update test
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { signal } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ActivatedRoute, convertToParamMap, Router } from '@angular/router';
|
||||
import { provideRouter } from '@angular/router';
|
||||
@@ -23,6 +24,63 @@ const makeIssue = (overrides: Partial<IssueEntity> = {}): IssueEntity => ({
|
||||
...overrides,
|
||||
});
|
||||
|
||||
class FakeIssuesStore {
|
||||
private _data = signal<IssueEntity[]>([
|
||||
makeIssue({ id: 1, name: 'Issue 1' }),
|
||||
makeIssue({ id: 2, name: 'Issue 2' }),
|
||||
makeIssue({ id: 3, name: 'Issue 3' }),
|
||||
]);
|
||||
|
||||
readonly issues = this._data.asReadonly();
|
||||
readonly loading = signal(false);
|
||||
readonly loaded = signal(true);
|
||||
|
||||
getById(id: number): IssueEntity | undefined {
|
||||
return this._data().find((i) => i.id === id);
|
||||
}
|
||||
|
||||
getNextId(): number {
|
||||
const ids = this._data().map((i) => i.id);
|
||||
return ids.length === 0 ? 1 : Math.max(...ids) + 1;
|
||||
}
|
||||
|
||||
load(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
upsert(issue: any): Promise<IssueEntity> {
|
||||
const { comments: c, estimatedTime: et, dependsOnIds: deps, dependsOnId: legacy, ...rest } = issue;
|
||||
const normalized: IssueEntity = {
|
||||
...makeIssue(),
|
||||
...rest,
|
||||
dependsOnIds: Array.isArray(deps)
|
||||
? deps.filter((v: unknown) => typeof v === 'number')
|
||||
: typeof legacy === 'number'
|
||||
? [legacy]
|
||||
: [],
|
||||
comments: Array.isArray(c) ? c : [],
|
||||
estimatedTime: et ?? null,
|
||||
};
|
||||
this._data.update((issues) => {
|
||||
const idx = issues.findIndex((i) => i.id === normalized.id);
|
||||
if (idx === -1) return [...issues, normalized];
|
||||
const copy = [...issues];
|
||||
copy[idx] = normalized;
|
||||
return copy;
|
||||
});
|
||||
return Promise.resolve(normalized);
|
||||
}
|
||||
|
||||
deleteById(id: number): Promise<void> {
|
||||
this._data.update((issues) =>
|
||||
issues
|
||||
.filter((i) => i.id !== id)
|
||||
.map((i) => ({ ...i, dependsOnIds: i.dependsOnIds.filter((d) => d !== id) })),
|
||||
);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
function makeRoute(id = '1', path = 'issues/:id') {
|
||||
return {
|
||||
snapshot: {
|
||||
@@ -37,30 +95,26 @@ function makeRoute(id = '1', path = 'issues/:id') {
|
||||
describe('IssueDetail — existing issue', () => {
|
||||
let component: IssueDetail;
|
||||
let fixture: ComponentFixture<IssueDetail>;
|
||||
let store: IssuesStore;
|
||||
let store: FakeIssuesStore;
|
||||
let router: Router;
|
||||
|
||||
beforeEach(async () => {
|
||||
localStorage.clear();
|
||||
store = new FakeIssuesStore();
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [IssueDetail],
|
||||
providers: [
|
||||
provideRouter([]),
|
||||
{ provide: ActivatedRoute, useValue: makeRoute('1') },
|
||||
{ provide: IssuesStore, useValue: store },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
store = TestBed.inject(IssuesStore);
|
||||
router = TestBed.inject(Router);
|
||||
fixture = TestBed.createComponent(IssueDetail);
|
||||
component = fixture.componentInstance;
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
@@ -115,7 +169,7 @@ describe('IssueDetail — existing issue', () => {
|
||||
describe('deleteIssue', () => {
|
||||
it('removes the issue and navigates to /issues', async () => {
|
||||
const spy = vi.spyOn(router, 'navigate').mockResolvedValue(true);
|
||||
(component as any).deleteIssue();
|
||||
await (component as any).deleteIssue();
|
||||
expect(store.getById(1)).toBeUndefined();
|
||||
expect(spy).toHaveBeenCalledWith(['/issues']);
|
||||
});
|
||||
@@ -169,9 +223,9 @@ describe('IssueDetail — existing issue', () => {
|
||||
expect((component as any).selectedCandidateId).toBeNull();
|
||||
});
|
||||
|
||||
it('confirmAddDependency adds the selected id and saves', () => {
|
||||
it('confirmAddDependency adds the selected id and saves', async () => {
|
||||
(component as any).selectedCandidateId = 2;
|
||||
(component as any).confirmAddDependency();
|
||||
await (component as any).confirmAddDependency();
|
||||
expect((component as any).issue.dependsOnIds).toContain(2);
|
||||
expect(store.getById(1)?.dependsOnIds).toContain(2);
|
||||
expect((component as any).showAddDependency).toBe(false);
|
||||
@@ -370,9 +424,9 @@ describe('IssueDetail — existing issue', () => {
|
||||
expect(created?.type).toBe('Story');
|
||||
});
|
||||
|
||||
it('confirmCreateInEpic resets the form', () => {
|
||||
it('confirmCreateInEpic resets the form', async () => {
|
||||
(component as any).newIssueName = 'Child Issue';
|
||||
(component as any).confirmCreateInEpic();
|
||||
await (component as any).confirmCreateInEpic();
|
||||
expect((component as any).showCreateInEpic).toBe(false);
|
||||
expect((component as any).newIssueName).toBe('');
|
||||
});
|
||||
@@ -405,9 +459,9 @@ describe('IssueDetail — existing issue', () => {
|
||||
expect((component as any).selectedEpicCandidateId).toBeNull();
|
||||
});
|
||||
|
||||
it('confirmAddToEpic assigns the epic name to the selected issue', () => {
|
||||
it('confirmAddToEpic assigns the epic name to the selected issue', async () => {
|
||||
(component as any).selectedEpicCandidateId = 2;
|
||||
(component as any).confirmAddToEpic();
|
||||
await (component as any).confirmAddToEpic();
|
||||
expect(store.getById(2)?.epic).toBe('My Epic');
|
||||
expect((component as any).showAddToEpic).toBe(false);
|
||||
});
|
||||
@@ -436,11 +490,11 @@ describe('IssueDetail — existing issue', () => {
|
||||
describe('IssueDetail — new issue route', () => {
|
||||
let component: IssueDetail;
|
||||
let fixture: ComponentFixture<IssueDetail>;
|
||||
let store: IssuesStore;
|
||||
let store: FakeIssuesStore;
|
||||
let router: Router;
|
||||
|
||||
beforeEach(async () => {
|
||||
localStorage.clear();
|
||||
store = new FakeIssuesStore();
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [IssueDetail],
|
||||
providers: [
|
||||
@@ -456,20 +510,16 @@ describe('IssueDetail — new issue route', () => {
|
||||
paramMap: of(convertToParamMap({})),
|
||||
},
|
||||
},
|
||||
{ provide: IssuesStore, useValue: store },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
store = TestBed.inject(IssuesStore);
|
||||
router = TestBed.inject(Router);
|
||||
fixture = TestBed.createComponent(IssueDetail);
|
||||
component = fixture.componentInstance;
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
@@ -486,14 +536,14 @@ describe('IssueDetail — new issue route', () => {
|
||||
it('saveIssue without explicit flag does nothing for new route', () => {
|
||||
(component as any).issue.name = 'Draft Name';
|
||||
const countBefore = store.issues().length;
|
||||
(component as any).saveIssue(); // explicit = false
|
||||
(component as any).saveIssue();
|
||||
expect(store.issues().length).toBe(countBefore);
|
||||
});
|
||||
|
||||
it('saveIssue with explicit=true creates the issue and navigates', async () => {
|
||||
const spy = vi.spyOn(router, 'navigate').mockResolvedValue(true);
|
||||
(component as any).issue.name = 'Brand New Issue';
|
||||
(component as any).saveIssue(true);
|
||||
await (component as any).saveIssue(true);
|
||||
expect(store.issues().some((i) => i.name === 'Brand New Issue')).toBe(true);
|
||||
expect(spy).toHaveBeenCalledWith(['/issues', 10]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user