From 2c7215d30ede89c3f42ed01fef2868c418c49e8e Mon Sep 17 00:00:00 2001 From: frozenhelium Date: Fri, 26 Jun 2026 10:33:02 +0545 Subject: [PATCH] fix(tutorial): correct completeness tasks per screen to 6 - expect 6 tasks per screen for completeness scenario import, like find - rewrite completeness tests for the 6 tasks-per-screen rule - fix find error-message assertion to match instance(s) wording - align compare test with its single task-per-screen rule - update getValidReferenceValues tests to expect the [] empty-case return --- app/views/EditTutorial/utils.test.ts | 121 +++++++++++++++++++-------- app/views/EditTutorial/utils.ts | 2 +- 2 files changed, 85 insertions(+), 38 deletions(-) diff --git a/app/views/EditTutorial/utils.test.ts b/app/views/EditTutorial/utils.test.ts index 2e3b903..92039b9 100644 --- a/app/views/EditTutorial/utils.test.ts +++ b/app/views/EditTutorial/utils.test.ts @@ -52,13 +52,13 @@ describe('getValidReferenceValues', () => { it('skips options without a value along with their sub-options', () => { expect(getValidReferenceValues([ { subOptions: [{ value: 5 }] }, - ])).toBeUndefined(); + ])).toEqual([]); }); - it('returns undefined for missing or empty options', () => { - expect(getValidReferenceValues(undefined)).toBeUndefined(); - expect(getValidReferenceValues(null)).toBeUndefined(); - expect(getValidReferenceValues([])).toBeUndefined(); + it('returns an empty array for missing or empty options', () => { + expect(getValidReferenceValues(undefined)).toEqual([]); + expect(getValidReferenceValues(null)).toEqual([]); + expect(getValidReferenceValues([])).toEqual([]); }); }); @@ -236,7 +236,7 @@ describe('transformFindGeoJson', () => { return; } - expect(result.error).toContain('expected to have 6 instances'); + expect(result.error).toContain('expected to have 6 instance(s)'); }); it('rejects non-serial screens', () => { @@ -306,20 +306,20 @@ describe('transformStreetGeoJson', () => { }); describe('transformCompareGeoJson', () => { - it('accepts repeated screens and maps compare specifics', () => { + it('maps each feature to its own scenario page, sorted by screen', () => { const result = transformCompareGeoJson(createFeatureCollection([ { - screen: 1, - reference: 0, - tile_x: 1, - tile_y: 2, + screen: 2, + reference: 1, + tile_x: 3, + tile_y: 4, tile_z: 18, }, { screen: 1, - reference: 1, - tile_x: 3, - tile_y: 4, + reference: 0, + tile_x: 1, + tile_y: 2, tile_z: 18, }, ])); @@ -329,8 +329,11 @@ describe('transformCompareGeoJson', () => { return; } - expect(result.scenarioPages).toHaveLength(1); - expect(result.scenarioPages[0].tasks).toHaveLength(2); + expect(result.scenarioPages.map( + (page) => page.scenarioPageNumber, + )).toEqual([1, 2]); + expect(result.scenarioPages[0].tasks).toHaveLength(1); + expect(result.scenarioPages[1].tasks).toHaveLength(1); const [task] = result.scenarioPages[0].tasks ?? []; expect(task.projectTypeSpecifics?.compare).toEqual({ @@ -340,15 +343,22 @@ describe('transformCompareGeoJson', () => { }); }); - it('rejects non-serial screens', () => { + it('rejects screens with more than one feature', () => { const result = transformCompareGeoJson(createFeatureCollection([ { - screen: 2, + screen: 1, reference: 0, tile_x: 1, tile_y: 2, tile_z: 18, }, + { + screen: 1, + reference: 1, + tile_x: 3, + tile_y: 4, + tile_z: 18, + }, ])); expect(result.ok).toBe(false); @@ -356,27 +366,45 @@ describe('transformCompareGeoJson', () => { return; } - expect(result.error).toContain('screens must be serial'); + expect(result.error).toContain('expected to have 1 instance(s)'); }); -}); -describe('transformCompletenessGeoJson', () => { - it('accepts repeated screens and maps completeness specifics', () => { - const result = transformCompletenessGeoJson(createFeatureCollection([ + it('rejects non-serial screens', () => { + const result = transformCompareGeoJson(createFeatureCollection([ { - screen: 1, + screen: 2, reference: 0, tile_x: 1, tile_y: 2, tile_z: 18, }, - { - screen: 1, - reference: 1, - tile_x: 3, - tile_y: 4, - tile_z: 18, - }, + ])); + + expect(result.ok).toBe(false); + if (result.ok) { + return; + } + + expect(result.error).toContain('screens must be serial'); + }); +}); + +describe('transformCompletenessGeoJson', () => { + // tile_x encodes the screen so mis-grouped tasks are detectable + const makeScreen = (screen: number) => Array.from( + new Array(6).keys(), + ).map((i) => ({ + screen, + reference: i % 2, + tile_x: screen * 100 + i, + tile_y: 20 + i, + tile_z: 18, + })); + + it('groups features by screen into sorted scenario pages', () => { + const result = transformCompletenessGeoJson(createFeatureCollection([ + ...makeScreen(2), + ...makeScreen(1), ])); expect(result.ok).toBe(true); @@ -384,22 +412,26 @@ describe('transformCompletenessGeoJson', () => { return; } - expect(result.scenarioPages).toHaveLength(1); - expect(result.scenarioPages[0].tasks).toHaveLength(2); + expect(result.scenarioPages.map( + (page) => page.scenarioPageNumber, + )).toEqual([1, 2]); + + expect(result.scenarioPages[0].tasks).toHaveLength(6); + expect(result.scenarioPages[1].tasks).toHaveLength(6); const [task] = result.scenarioPages[0].tasks ?? []; expect(task.projectTypeSpecifics?.completeness).toEqual({ - tileX: 1, - tileY: 2, + tileX: 100, + tileY: 20, tileZ: 18, }); }); - it('rejects reference values outside the tile options', () => { + it('rejects screens without exactly 6 features', () => { const result = transformCompletenessGeoJson(createFeatureCollection([ { screen: 1, - reference: 9, + reference: 0, tile_x: 1, tile_y: 2, tile_z: 18, @@ -411,6 +443,21 @@ describe('transformCompletenessGeoJson', () => { return; } + expect(result.error).toContain('expected to have 6 instance(s)'); + }); + + it('rejects reference values outside the tile options', () => { + const [first, ...others] = makeScreen(1); + const result = transformCompletenessGeoJson(createFeatureCollection([ + { ...first, reference: 9 }, + ...others, + ])); + + expect(result.ok).toBe(false); + if (result.ok) { + return; + } + expect(result.error).toContain('invalid reference value(s): 9 for screen 1'); }); }); diff --git a/app/views/EditTutorial/utils.ts b/app/views/EditTutorial/utils.ts index 9629bf4..fd4f629 100644 --- a/app/views/EditTutorial/utils.ts +++ b/app/views/EditTutorial/utils.ts @@ -463,7 +463,7 @@ export function transformCompletenessGeoJson( return { ok: false, error: result.summary }; } - const problems = checkTileGroupedFeatures(result.features, 1); + const problems = checkTileGroupedFeatures(result.features, 6); if (problems.length > 0) { return { ok: false, error: problems.join('\n') }; }