diff --git a/src/frontend/e2e/createproject.spec.ts b/src/frontend/e2e/01-create-new-project.spec.ts similarity index 93% rename from src/frontend/e2e/createproject.spec.ts rename to src/frontend/e2e/01-create-new-project.spec.ts index 6220ff881..212a236ac 100644 --- a/src/frontend/e2e/createproject.spec.ts +++ b/src/frontend/e2e/01-create-new-project.spec.ts @@ -3,7 +3,7 @@ import { test, expect } from '@playwright/test'; -test('Project Creation', async ({ browserName, page }) => { +test('create new project', async ({ browserName, page }) => { // Specific for this large test, only run in one browser // Run other tests in all browsers test.skip(browserName !== 'chromium', 'Test only for chromium!'); @@ -83,5 +83,8 @@ test('Project Creation', async ({ browserName, page }) => { await page.getByRole('spinbutton').fill('3'); await page.getByRole('button', { name: 'Click to generate task' }).click(); await page.getByRole('button', { name: 'SUBMIT' }).click(); - await expect(page.getByText('Project Generation Completed. Redirecting...')).toBeVisible(); + + const projectCreationSuccessToast = page.getByText('Project Generation Completed. Redirecting...'); + await projectCreationSuccessToast.waitFor({ state: 'visible' }); + await expect(projectCreationSuccessToast).toBeVisible(); }); diff --git a/src/frontend/e2e/02-mapper-flow.spec.ts b/src/frontend/e2e/02-mapper-flow.spec.ts new file mode 100644 index 000000000..bc66a7709 --- /dev/null +++ b/src/frontend/e2e/02-mapper-flow.spec.ts @@ -0,0 +1,152 @@ +import { test, expect } from '@playwright/test'; + +test.describe('mapper flow', () => { + test('mapper flow', async ({ page }) => { + await page.goto('/'); + // await page.goto('http://fmtm.localhost:7050/'); + await page.getByRole('button', { name: 'Sign in' }).click(); + await page + .getByLabel('', { exact: true }) + .locator('div') + .filter({ hasText: "Temporary AccountIf you're" }) + .nth(3) + .click(); + + // click first project card on the home page + await page.locator('.MuiCardContent-root').first().click(); + + // click on task + await page.waitForTimeout(4000); + await page.locator('canvas').click({ + position: { + x: 445, + y: 95, + }, + }); + await expect(page.getByText('Status: READY')).toBeVisible(); + await page.getByRole('alert').waitFor({ state: 'hidden' }); + await page.getByTitle('Close').getByTestId('CloseIcon').click(); + expect(await page.locator('canvas').screenshot()).toMatchSnapshot('ready.png'); + + await page.locator('canvas').click({ + position: { + x: 445, + y: 95, + }, + }); + // STATUS: READY + await page.getByRole('button', { name: 'START MAPPING' }).waitFor({ state: 'visible' }); + await page.getByRole('button', { name: 'START MAPPING' }).click(); + await page.waitForSelector('div:has-text("updated status to LOCKED_FOR_MAPPING"):nth-of-type(1)'); + await expect( + page + .locator('div') + .filter({ hasText: /updated status to LOCKED_FOR_MAPPING/ }) + .first(), + ).toBeVisible(); + await page.getByRole('alert').waitFor({ state: 'hidden' }); + await page.getByTitle('Close').getByTestId('CloseIcon').click(); + expect(await page.locator('canvas').screenshot()).toMatchSnapshot('locked-for-mapping.png'); + + await page.locator('canvas').click({ + position: { + x: 445, + y: 95, + }, + }); + //STATUS: LOCKED_FOR_MAPPING + await page.getByRole('button', { name: 'MARK AS FULLY MAPPED' }).click(); + await page.getByRole('button', { name: 'MARK AS FULLY MAPPED' }).click(); + await page.waitForSelector('div:has-text("updated status to MAPPED"):nth-of-type(1)'); + await expect( + page + .locator('div') + .filter({ hasText: /updated status to MAPPED/ }) + .first(), + ).toBeVisible(); + await page.getByRole('alert').waitFor({ state: 'hidden' }); + await page.getByTitle('Close').getByTestId('CloseIcon').click(); + expect(await page.locator('canvas').screenshot()).toMatchSnapshot('mapped.png'); + + await page.locator('canvas').click({ + position: { + x: 445, + y: 95, + }, + }); + // STATUS: MAPPED + await page.getByRole('button', { name: 'START VALIDATION' }).click(); + await page.getByRole('button', { name: 'FULLY MAPPED' }).click(); + + await page.getByText('has been updated to VALIDATED').waitFor({ state: 'visible' }); + await expect(page.getByText('has been updated to VALIDATED')).toBeVisible(); + + // click on validated task after map renders + await page.waitForTimeout(4000); + expect(await page.locator('canvas').screenshot()).toMatchSnapshot('validated.png'); + await page.locator('canvas').click({ + position: { + x: 445, + y: 95, + }, + }); + await expect(page.getByText('Status: VALIDATED')).toBeVisible(); + }); + + test('comment section', async ({ page }) => { + await page.goto('/'); + // await page.goto('http://fmtm.localhost:7050/'); + await page.getByRole('button', { name: 'Sign in' }).click(); + await page + .getByLabel('', { exact: true }) + .locator('div') + .filter({ hasText: "Temporary AccountIf you're" }) + .nth(3) + .click(); + + // click first project card on the home page + await page.locator('.MuiCardContent-root').first().click(); + + await page.waitForTimeout(4000); + await page.locator('canvas').click({ + position: { + x: 475, + y: 127, + }, + }); + + // Assert no comment is visible + await page.getByRole('button', { name: 'Comments' }).click(); + await expect(page.getByText('No Comments!')).toBeVisible(); + + // Add comment + await page.getByTestId('FormatBoldIcon').click(); + await page.locator('.fmtm-min-h-\\[150px\\] > .tiptap > p').click(); + await page.locator('.fmtm-min-h-\\[150px\\] > .tiptap').fill('Test playwright'); + await page.getByRole('button', { name: 'SAVE COMMENT' }).click(); + await expect( + page + .locator('div') + .filter({ hasText: /Test playwright/ }) + .first(), + ).toBeVisible(); + + // Add comment + await page.locator('.fmtm-min-h-\\[150px\\] > .tiptap > p').click(); + await page.locator('.fmtm-min-h-\\[150px\\] > .tiptap > p').click(); + await page.locator('.fmtm-min-h-\\[150px\\] > .tiptap').fill('map features accurately'); + await page.getByRole('button', { name: 'SAVE COMMENT' }).click(); + await expect( + page + .locator('div') + .filter({ hasText: /map features accurately/ }) + .first(), + ).toBeVisible(); + + // Save empty comment + await page.locator('.fmtm-min-h-\\[150px\\] > .tiptap > p').click(); + await page.getByRole('button', { name: 'SAVE COMMENT' }).click(); + await page.getByRole('heading', { name: 'Empty comment field.' }).click(); + await page.getByRole('alert').click(); + }); +}); diff --git a/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/locked-for-mapping-chromium-linux.png b/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/locked-for-mapping-chromium-linux.png new file mode 100644 index 000000000..375967820 Binary files /dev/null and b/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/locked-for-mapping-chromium-linux.png differ diff --git a/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/mapped-chromium-linux.png b/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/mapped-chromium-linux.png new file mode 100644 index 000000000..efc3c3fe1 Binary files /dev/null and b/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/mapped-chromium-linux.png differ diff --git a/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/ready-chromium-linux.png b/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/ready-chromium-linux.png new file mode 100644 index 000000000..ca2b52148 Binary files /dev/null and b/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/ready-chromium-linux.png differ diff --git a/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/validated-chromium-linux.png b/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/validated-chromium-linux.png new file mode 100644 index 000000000..69e0d63b6 Binary files /dev/null and b/src/frontend/e2e/02-mapper-flow.spec.ts-snapshots/validated-chromium-linux.png differ diff --git a/src/frontend/e2e/03-entity-update.spec.ts b/src/frontend/e2e/03-entity-update.spec.ts new file mode 100644 index 000000000..f5548c374 --- /dev/null +++ b/src/frontend/e2e/03-entity-update.spec.ts @@ -0,0 +1,71 @@ +import { test, expect } from '@playwright/test'; + +test('entity update', async ({ page }) => { + await page.goto('/'); + await page.getByRole('button', { name: 'Sign in' }).click(); + await page + .getByLabel('', { exact: true }) + .locator('div') + .filter({ hasText: "Temporary AccountIf you're" }) + .nth(3) + .click(); + + // click first project card on the home page + await page.locator('.MuiCardContent-root').first().click(); + + // click on task & assert task popup visibility + await page.waitForTimeout(4000); + await page.locator('canvas').click({ + position: { + x: 388, + y: 220, + }, + }); + await expect(page.getByText('Status: READY')).toBeVisible(); + await expect(page.getByRole('button', { name: 'START MAPPING' })).toBeVisible(); + + // click on entity within task & assert feature popup visibility + await page.waitForTimeout(4000); + await page.locator('canvas').click({ + position: { + x: 387, + y: 211, + }, + }); + await expect(page.getByRole('heading', { name: 'Feature:' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'MAP FEATURE IN ODK' })).toBeEnabled(); + await page.getByRole('button', { name: 'MAP FEATURE IN ODK' }).click(); + await expect( + page.getByRole('alert').locator('div').filter({ hasText: 'Requires a mobile phone with ODK collect' }), + ).toBeVisible(); + + // check if task status is updated to locked_for_mapping on entity map + await page.waitForSelector('div:has-text("updated status to LOCKED_FOR_MAPPING"):nth-of-type(1)'); + await expect( + page + .locator('div') + .filter({ hasText: /updated status to LOCKED_FOR_MAPPING/ }) + .first(), + ).toBeVisible(); + + // click on task to check if task popup has been updated + await page.waitForTimeout(4000); + await page.locator('canvas').click({ + position: { + x: 411, + y: 171, + }, + }); + + // await page.getByText('Status: LOCKED_FOR_MAPPING').click(); + await expect(page.getByText('Status: LOCKED_FOR_MAPPING')).toBeVisible(); + + // click entity to confirm task is locked + await page.locator('canvas').click({ + position: { + x: 387, + y: 211, + }, + }); + await expect(page.getByRole('button', { name: 'MAP FEATURE IN ODK' })).toBeDisabled(); +}); diff --git a/src/frontend/src/environment.ts b/src/frontend/src/environment.ts index 2268422ed..de786b5b3 100755 --- a/src/frontend/src/environment.ts +++ b/src/frontend/src/environment.ts @@ -36,6 +36,7 @@ export default { { key: 'Mapping Needed', value: 'INVALIDATED', btnBG: 'transparent' }, ], }, + { label: 'VALIDATED', action: [] }, // { label: 'VALIDATED', action: [{ key: 'Merge data with OSM', value: 'MERGE_WITH_OSM', btnBG: 'gray' }] }, { label: 'INVALIDATED', action: [{ key: 'Map Again', value: 'LOCKED_FOR_MAPPING', btnBG: 'gray' }] }, { label: 'BAD', action: [] }, diff --git a/src/frontend/src/store/slices/ProjectSlice.ts b/src/frontend/src/store/slices/ProjectSlice.ts index ed3c93497..c6cc54a3b 100755 --- a/src/frontend/src/store/slices/ProjectSlice.ts +++ b/src/frontend/src/store/slices/ProjectSlice.ts @@ -159,7 +159,7 @@ const ProjectSlice = createSlice({ const updatedProjectTaskBoundries = state.projectTaskBoundries?.map((boundary) => { if (boundary.id == action.payload.projectId) { const updatedBoundary = boundary?.taskBoundries?.map((taskBoundary) => { - if (taskBoundary?.index === action.payload.taskId) { + if (taskBoundary?.index === +action.payload.taskId) { return { ...taskBoundary, task_status: action.payload.task_status,