Ajout des dates calculés

This commit is contained in:
2026-05-30 07:38:08 +02:00
parent b1a114aaa8
commit fb0e853122
13 changed files with 386 additions and 15 deletions
+118
View File
@@ -11,6 +11,7 @@ const makeIssue = (overrides: Partial<IssueEntity> = {}): IssueEntity => ({
epic: '',
name: 'Test Issue',
startDate: '',
startDateMode: 'forced',
endDate: '',
dueDate: '',
description: '',
@@ -183,6 +184,123 @@ describe('IssuesStore', () => {
expect(store.getById(991)?.startDate).toBe('2026-01-01');
expect(store.getById(991)?.endDate).toBe('2026-01-31');
});
it('restores startDateMode when the API response omits it', async () => {
const issue = makeIssue({ id: 1, startDateMode: 'calculated' });
const p = store.upsert(issue);
const apiResponse = { ...makeIssue({ id: 1 }), startDateMode: undefined };
httpMock.expectOne({ method: 'PUT', url: `${API_BASE_URL}/issues/1` }).flush(apiResponse);
await p;
expect(store.getById(1)?.startDateMode).toBe('calculated');
});
it('restores linkedIssueIds in comments when API response omits them', async () => {
const issueWithComment = makeIssue({ id: 1, comments: [{ id: 10, text: 'hello', createdAt: '', updatedAt: null, linkedIssueIds: [2, 3] }] });
const apiResponse = makeIssue({ id: 1, comments: [{ id: 10, text: 'hello', createdAt: '', updatedAt: null, linkedIssueIds: undefined as any }] });
const p = store.upsert(issueWithComment);
httpMock.expectOne({ method: 'PUT', url: `${API_BASE_URL}/issues/1` }).flush(apiResponse);
await p;
expect(store.getById(1)?.comments[0].linkedIssueIds).toEqual([2, 3]);
});
it('keeps existing linkedIssueIds in comments when already present in API response', async () => {
const issue = makeIssue({ id: 1, comments: [{ id: 10, text: 'hello', createdAt: '', updatedAt: null, linkedIssueIds: [5] }] });
const apiResponse = makeIssue({ id: 1, comments: [{ id: 10, text: 'hello', createdAt: '', updatedAt: null, linkedIssueIds: [5] }] });
const p = store.upsert(issue);
httpMock.expectOne({ method: 'PUT', url: `${API_BASE_URL}/issues/1` }).flush(apiResponse);
await p;
expect(store.getById(1)?.comments[0].linkedIssueIds).toEqual([5]);
});
});
describe('cascade recalculation of calculated-mode issues', () => {
it('updates startDate of a calculated-mode dependent when its dependency endDate changes', async () => {
await loadWith([
makeIssue({ id: 1, endDate: '2026-06-01' }),
makeIssue({ id: 2, startDateMode: 'calculated', dependsOnIds: [1], startDate: '2026-06-01', endDate: '' }),
]);
const p = store.upsert(makeIssue({ id: 1, endDate: '2026-06-10' }));
httpMock.expectOne({ method: 'PUT', url: `${API_BASE_URL}/issues/1` }).flush(makeIssue({ id: 1, endDate: '2026-06-10' }));
await p;
expect(store.getById(2)?.startDate).toBe('2026-06-10');
});
it('recalculates endDate of a calculated-mode dependent based on estimatedTime', async () => {
await loadWith([
makeIssue({ id: 1, endDate: '2026-06-01' }),
makeIssue({ id: 2, startDateMode: 'calculated', dependsOnIds: [1], startDate: '2026-06-01', estimatedTime: 16, endDate: '2026-06-02' }),
]);
const p = store.upsert(makeIssue({ id: 1, endDate: '2026-06-10' }));
httpMock.expectOne({ method: 'PUT', url: `${API_BASE_URL}/issues/1` }).flush(makeIssue({ id: 1, endDate: '2026-06-10' }));
await p;
expect(store.getById(2)?.startDate).toBe('2026-06-10');
expect(store.getById(2)?.endDate).toBe('2026-06-11');
});
it('clears endDate when dependency loses its endDate', async () => {
await loadWith([
makeIssue({ id: 1, endDate: '2026-06-10' }),
makeIssue({ id: 2, startDateMode: 'calculated', dependsOnIds: [1], startDate: '2026-06-10', estimatedTime: 8, endDate: '2026-06-10' }),
]);
const p = store.upsert(makeIssue({ id: 1, endDate: '' }));
httpMock.expectOne({ method: 'PUT', url: `${API_BASE_URL}/issues/1` }).flush(makeIssue({ id: 1, endDate: '' }));
await p;
expect(store.getById(2)?.startDate).toBe('');
expect(store.getById(2)?.endDate).toBe('');
});
it('cascades through a chain A → B → C', async () => {
await loadWith([
makeIssue({ id: 1, endDate: '2026-06-01' }),
makeIssue({ id: 2, startDateMode: 'calculated', dependsOnIds: [1], startDate: '2026-06-01', estimatedTime: 8, endDate: '2026-06-01' }),
makeIssue({ id: 3, startDateMode: 'calculated', dependsOnIds: [2], startDate: '2026-06-01', estimatedTime: 16, endDate: '2026-06-02' }),
]);
const p = store.upsert(makeIssue({ id: 1, endDate: '2026-06-10' }));
httpMock.expectOne({ method: 'PUT', url: `${API_BASE_URL}/issues/1` }).flush(makeIssue({ id: 1, endDate: '2026-06-10' }));
await p;
expect(store.getById(2)?.startDate).toBe('2026-06-10');
expect(store.getById(2)?.endDate).toBe('2026-06-10');
expect(store.getById(3)?.startDate).toBe('2026-06-10');
expect(store.getById(3)?.endDate).toBe('2026-06-11');
});
it('does not affect forced-mode issues', async () => {
await loadWith([
makeIssue({ id: 1, endDate: '2026-06-01' }),
makeIssue({ id: 2, startDateMode: 'forced', dependsOnIds: [1], startDate: '2026-05-01', endDate: '2026-05-15' }),
]);
const p = store.upsert(makeIssue({ id: 1, endDate: '2026-06-10' }));
httpMock.expectOne({ method: 'PUT', url: `${API_BASE_URL}/issues/1` }).flush(makeIssue({ id: 1, endDate: '2026-06-10' }));
await p;
expect(store.getById(2)?.startDate).toBe('2026-05-01');
expect(store.getById(2)?.endDate).toBe('2026-05-15');
});
it('uses the latest endDate among multiple dependencies', async () => {
await loadWith([
makeIssue({ id: 1, endDate: '2026-06-01' }),
makeIssue({ id: 2, endDate: '2026-06-05' }),
makeIssue({ id: 3, startDateMode: 'calculated', dependsOnIds: [1, 2], startDate: '', estimatedTime: 8, endDate: '' }),
]);
const p = store.upsert(makeIssue({ id: 1, endDate: '2026-06-10' }));
httpMock.expectOne({ method: 'PUT', url: `${API_BASE_URL}/issues/1` }).flush(makeIssue({ id: 1, endDate: '2026-06-10' }));
await p;
expect(store.getById(3)?.startDate).toBe('2026-06-10');
expect(store.getById(3)?.endDate).toBe('2026-06-10');
});
it('recalculates after deleteById removes a dependency', async () => {
await loadWith([
makeIssue({ id: 1, endDate: '2026-06-10' }),
makeIssue({ id: 2, endDate: '2026-06-05' }),
makeIssue({ id: 3, startDateMode: 'calculated', dependsOnIds: [1, 2], startDate: '2026-06-10', estimatedTime: 8, endDate: '2026-06-10' }),
]);
const p = store.deleteById(1);
httpMock.expectOne({ method: 'DELETE', url: `${API_BASE_URL}/issues/1` }).flush(null);
await p;
expect(store.getById(3)?.startDate).toBe('2026-06-05');
expect(store.getById(3)?.endDate).toBe('2026-06-05');
});
});
describe('deleteById', () => {