From 92659f7c1b0ac0bd800a958c0aa42c86e6ccf870 Mon Sep 17 00:00:00 2001 From: Sue Tairaku Date: Thu, 25 Jun 2026 15:38:33 -0700 Subject: [PATCH 1/9] Research view automation --- .../components/common/ExpandableTextArea.tsx | 3 +- .../documentUpload/SelectedDocumentRow.tsx | 7 +- .../details/ResearchSummaryView.tsx | 12 ++- .../documents/document-upload-modal.page.ts | 6 +- .../pages/layout/layout.page.ts | 27 ++++++ .../pages/research/research-list.page.ts | 40 +++++++++ .../research-view-file-details.page.ts | 62 +++++++------ .../tests/e2e/research.spec.ts | 86 ++++++++++++++++++- 8 files changed, 210 insertions(+), 33 deletions(-) diff --git a/source/frontend/src/components/common/ExpandableTextArea.tsx b/source/frontend/src/components/common/ExpandableTextArea.tsx index 2f8db56c7c..bc9285def6 100644 --- a/source/frontend/src/components/common/ExpandableTextArea.tsx +++ b/source/frontend/src/components/common/ExpandableTextArea.tsx @@ -7,6 +7,7 @@ import { LinkButton } from './buttons'; export interface IExpandableTextCardProps { text: string; maxHeight?: number; + dataTestid?: string; } export const ExpandableTextCard: React.FunctionComponent< @@ -26,7 +27,7 @@ export const ExpandableTextCard: React.FunctionComponent< }, [max]); return ( - + diff --git a/source/frontend/src/features/documents/documentUpload/SelectedDocumentRow.tsx b/source/frontend/src/features/documents/documentUpload/SelectedDocumentRow.tsx index b03c1794d4..295fef69e3 100644 --- a/source/frontend/src/features/documents/documentUpload/SelectedDocumentRow.tsx +++ b/source/frontend/src/features/documents/documentUpload/SelectedDocumentRow.tsx @@ -111,7 +111,12 @@ export const SelectedDocumentRow: React.FunctionComponent - {fileError} + + {fileError} + } isCollapsable={false} diff --git a/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.tsx b/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.tsx index cc645761e0..084ce13af7 100644 --- a/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.tsx +++ b/source/frontend/src/features/mapSideBar/research/tabs/fileDetails/details/ResearchSummaryView.tsx @@ -126,7 +126,10 @@ const ResearchSummaryView: React.FunctionComponent = )} - +
@@ -135,12 +138,15 @@ const ResearchSummaryView: React.FunctionComponent = : 'not complete'} - +
{detail.isExpropriation ? 'Yes' : 'No'} - +
); diff --git a/testing/pims-integration/pages/documents/document-upload-modal.page.ts b/testing/pims-integration/pages/documents/document-upload-modal.page.ts index dee52bc9f3..2cffe7b998 100644 --- a/testing/pims-integration/pages/documents/document-upload-modal.page.ts +++ b/testing/pims-integration/pages/documents/document-upload-modal.page.ts @@ -36,10 +36,10 @@ export class DocumentUploadModalPage { } async getDocumentErrorLabel(index: number = 0): Promise { - const documentHeaderWrapper = this.page.locator( - `//div[@data-testid='document[${index}]-error']/parent::div/following-sibling::div` + const documentErrorLabel = this.page.getByTestId( + `document[${index}]-error-message` ); - return await documentHeaderWrapper.innerText(); + return await documentErrorLabel.innerText(); } async getDocumentErrorFilename(index: number = 0): Promise { diff --git a/testing/pims-integration/pages/layout/layout.page.ts b/testing/pims-integration/pages/layout/layout.page.ts index 03651eb290..0d7f5b5c9a 100644 --- a/testing/pims-integration/pages/layout/layout.page.ts +++ b/testing/pims-integration/pages/layout/layout.page.ts @@ -12,4 +12,31 @@ export class LayoutPage { async openHelpDeskForm() { await this.helpDeskButton.click(); } + + normalize(value: unknown): string { + return value == null ? '' : String(value).trim(); + } + + formatApiDate(apiDate: string | null | undefined): string { + if (!apiDate) { + return ''; + } + + const date = new Date(apiDate); + + return date.toLocaleDateString('en-CA', { + month: 'short', + day: 'numeric', + year: 'numeric', + timeZone: 'UTC', // avoids timezone surprises + }); + } + + formatApiBoolean(value: boolean | null | undefined): string { + if (value == null) { + return ''; + } + + return value ? 'Yes' : 'No'; + } } diff --git a/testing/pims-integration/pages/research/research-list.page.ts b/testing/pims-integration/pages/research/research-list.page.ts index b802d294ed..76e0063169 100644 --- a/testing/pims-integration/pages/research/research-list.page.ts +++ b/testing/pims-integration/pages/research/research-list.page.ts @@ -13,6 +13,7 @@ export class ResearchListPage extends LayoutPage { readonly researcSearchByLabel: Locator; readonly researchByRegionSelect: Locator; + readonly researchSearchNameInput: Locator; readonly researchByStatusSelect: Locator; readonly researchSearchBySelect: Locator; readonly researchSearchPidInput: Locator; @@ -74,6 +75,7 @@ export class ResearchListPage extends LayoutPage { this.researchByStatusSelect = page.locator('#input-researchFileStatusTypeCode'); this.researchSearchBySelect = page.locator('#input-researchSearchBy'); this.researchSearchPidInput = page.locator('#input-pid'); + this.researchSearchNameInput = page.locator('#input-name'); this.researchSearchRoadInput = page.locator('#input-roadOrAlias'); this.researchSearchDateSelect = page.locator('#input-createOrUpdateRange'); this.researchSearchDateToInput = page.locator('#datepicker-updatedOnStartDate'); @@ -134,4 +136,42 @@ export class ResearchListPage extends LayoutPage { async createNewResearchClick() { await this.researchNewButton.click(); } + + async openResearchFileInNewTab(index: number): Promise { + const selectedFile = this.page + .getByTestId('researchFilesTable') + .locator('.tbody .tr-wrapper') + .nth(index - 1) + .locator('a'); + const [newPage] = await Promise.all([ + this.page.context().waitForEvent('page'), + selectedFile.click(), + ]); + + await newPage.waitForLoadState('domcontentloaded'); + await newPage.waitForURL(/\/mapview\/sidebar\/research\/\d+/, { + timeout: 30000, + }); + // eslint-disable-next-line playwright/no-networkidle + await newPage.waitForLoadState('networkidle'); + await newPage.bringToFront(); + + return newPage; + } + + async searchByName(name: string) { + await this.researchSearchBySelect.selectOption('Research file name'); + await this.researchSearchNameInput.fill(name); + await this.researchSearchButton.click(); + } + + async clickResearchFileResult(index: number): Promise { + const link = this.page + .getByTestId('researchFilesTable') + .locator('.tbody .tr-wrapper') + .nth(index-1) + .locator('a'); + + await link.click(); + } } diff --git a/testing/pims-integration/pages/research/research-view-file-details.page.ts b/testing/pims-integration/pages/research/research-view-file-details.page.ts index 658198b9c1..39ff424b06 100644 --- a/testing/pims-integration/pages/research/research-view-file-details.page.ts +++ b/testing/pims-integration/pages/research/research-view-file-details.page.ts @@ -10,25 +10,20 @@ export class ResearchViewFileDetails extends LayoutPage { readonly researchProjectSubtitle: Locator; readonly researchProjectLabel: Locator; - readonly researchProjectContent: Locator; readonly reseachRoadTitle: Locator; readonly researchRoadNameLabel: Locator; - readonly researchRoadNameContent: Locator; readonly researchRoadAliasLabel: Locator; - readonly researchRoadAliasContent: Locator; readonly researchRequestTitle: Locator; readonly researchPurposeLabel: Locator; - readonly researchPurposeContent: Locator; readonly researchRequestDateLabel: Locator; readonly researchSourceRequestLabel: Locator; - readonly researchRequestDateContent: Locator; + readonly researchRequesterLabel: Locator; readonly researchSourceRequestContent: Locator; readonly researchRequesterContent: Locator; readonly researchDescriptionLabel: Locator; - readonly researchDescriptionContent: Locator; readonly researchResultTitle: Locator; readonly researchCompletedOnLabel: Locator; @@ -48,29 +43,17 @@ export class ResearchViewFileDetails extends LayoutPage { this.researchProjectSubtitle = page.locator('div').filter({ hasText: 'Project' }).first(); this.researchProjectLabel = page.getByText('Ministry project:', { exact: true }); - this.researchProjectContent = page.locator( - "//label[text()='Ministry project']/parent::div/following-sibling::div" - ); this.reseachRoadTitle = page.getByText('Roads', { exact: true }); this.researchRoadNameLabel = page.locator('label:has-text("Road name:")'); - this.researchRoadNameContent = page.locator( - "//label[text()='Road name:']/parent::div/following-sibling::div" - ); + this.researchRoadAliasLabel = page.locator('label:has-text("Road alias:")'); - this.researchRoadAliasContent = page.locator( - "//label[text()='Road alias:']/parent::div/following-sibling::div" - ); this.researchRequestTitle = page.getByText('Research Request', { exact: true }); this.researchPurposeLabel = page.getByText('Research purpose:', { exact: true }); - this.researchPurposeContent = page.locator( - "//label[text()='Research purpose:']/parent::div/following-sibling::div" - ); + this.researchRequestDateLabel = page.getByText('Request date:', { exact: true }); - this.researchRequestDateContent = page.locator( - "//label[text()='Request date:']/parent::div/following-sibling::div" - ); + this.researchSourceRequestLabel = page.getByText('Source of request:', { exact: true }); this.researchSourceRequestContent = page.locator( "//label[text()='Source of request:']/parent::div/following-sibling::div" @@ -80,9 +63,6 @@ export class ResearchViewFileDetails extends LayoutPage { "//label[text()='Source of request:']/parent::div/following-sibling::div" ); this.researchDescriptionLabel = page.locator('label:has-text("Requester:")'); - this.researchDescriptionContent = page.locator( - "//label[text()='Requester:']/parent::div/following-sibling::div" - ); this.researchResultTitle = page.locator(':text-is("Result")'); this.researchCompletedOnLabel = page.locator('label:has-text("Research completed on:")'); @@ -96,4 +76,38 @@ export class ResearchViewFileDetails extends LayoutPage { async navigateDocumentsTab() { await this.researchDocumentTab.click(); } + + async getFieldValueByLabel(label: string): Promise { + return await this.page + .locator(`//label[contains(normalize-space(), '${label}')]/parent::div/following-sibling::div`) + .innerText(); + } + + async getResearchDescription(): Promise { + return ( + await this.page + .getByTestId('request-description') + .locator('label') + .innerText() + ).trim(); + } + + async getResearchResult(): Promise { + return ( + await this.page + .getByTestId('research-result') + .locator('label') + .innerText() + ).trim(); + } + + async getResearchExpropriationNotes(): Promise { + return ( + await this.page + .getByTestId('expropriation-notes') + .locator('label') + .innerText() + ).trim(); + } + } diff --git a/testing/pims-integration/tests/e2e/research.spec.ts b/testing/pims-integration/tests/e2e/research.spec.ts index ed3de304ad..36b80bbefd 100644 --- a/testing/pims-integration/tests/e2e/research.spec.ts +++ b/testing/pims-integration/tests/e2e/research.spec.ts @@ -1,12 +1,14 @@ import test, { BrowserContext, expect, Page } from '@playwright/test'; import { ResearchCreatePage } from '../../pages/research/research-create.page'; import { DocumentsListPage } from '../../pages/documents/documents-list.page'; +import { ResearchListPage } from '../../pages/research/research-list.page'; import { ResearchViewFileDetails } from '../../pages/research/research-view-file-details.page'; import { DocumentUploadModalPage } from '../../pages/documents/document-upload-modal.page'; import path from 'path'; let context: BrowserContext; let page: Page; +let researchListPage: ResearchListPage; let researchCreatePage: ResearchCreatePage; let researchViewDetails: ResearchViewFileDetails; let documentsListPage: DocumentsListPage; @@ -16,6 +18,7 @@ test.describe('Research Files feature', () => { test.beforeAll(async ({ browser }) => { context = await browser.newContext(); page = await context.newPage(); + researchListPage = new ResearchListPage(page); researchCreatePage = new ResearchCreatePage(page); researchViewDetails = new ResearchViewFileDetails(page); documentsListPage = new DocumentsListPage(page); @@ -26,12 +29,93 @@ test.describe('Research Files feature', () => { await context.close(); }); - test('verify documents invalid types', async () => { + test('create new research file', async () => { //Navigate to new research file and create a minimum viable research await researchCreatePage.goto(); await researchCreatePage.setResearchNameValue('researchFile'); await researchCreatePage.confirmButtonClick(); await expect(researchViewDetails.researchDocumentTab).toBeVisible(); + }); + + test('verify research view form', async() => { + //Navigate to Research list view + await researchListPage.goto(); + + //Search researh file by name + await researchListPage.searchByName('Bubba BBQ Whirled'); + + const [newPage] = await Promise.all([ + context.waitForEvent('page'), + researchListPage.clickResearchFileResult(1), + ]); + + const responsePromise = newPage.waitForResponse((response: { url: () => string | string[]; status: () => number; }) => + response.url().includes('/api/researchFiles/') && + response.status() === 200 + ); + + await newPage.waitForLoadState('domcontentloaded'); + + const response = await responsePromise; + const apiResearchFile = await response.json(); + + const researchViewDetails = new ResearchViewFileDetails(newPage); + + console.log('############################'); + console.log('FOUND THE API RESPONSE'); + console.log(response.url()); + console.log(JSON.stringify(apiResearchFile, null, 2)); + console.log('############################'); + + await expect(researchViewDetails.researchDocumentTab).toBeVisible(); + const fieldsToCompare = [ + {label: 'Ministry project', apiValue: apiResearchFile.researchFileProjects[0]}, + {label: 'Road name', apiValue: apiResearchFile.roadName}, + {label: 'Road alias', apiValue: apiResearchFile.roadAlias }, + {label: 'Research purpose', apiValue: apiResearchFile.researchFilePurposes[0].researchPurposeTypeCode.description}, + {label: 'Source of request', apiValue: apiResearchFile.requestSourceType.description }, + {label: 'Requester', apiValue: apiResearchFile.requestorPerson }, + ]; + + const datesToCompare = [ + {label: 'Request date', apiValue: apiResearchFile.requestDate}, + {label: 'Research completed on', apiValue: apiResearchFile.researchCompletionDate }, + ] + + for (const field of fieldsToCompare) { + const uiValue = await researchViewDetails.getFieldValueByLabel(field.label); + expect(researchViewDetails.normalize(uiValue)).toBe(researchViewDetails.normalize(field.apiValue)); + } + + for(const date of datesToCompare) { + const uiValue = await researchViewDetails.getFieldValueByLabel(date.label); + const changedFormat = researchViewDetails.formatApiDate(date.apiValue); + expect(researchViewDetails.normalize(uiValue)).toBe(changedFormat); + } + + const isExpropriation = await researchViewDetails.getFieldValueByLabel('Expropriation?'); + const formatedBoolean = researchViewDetails.formatApiBoolean(apiResearchFile.isExpropriation); + expect(researchViewDetails.normalize(isExpropriation)).toBe(formatedBoolean); + + const description = await researchViewDetails.getResearchDescription(); + expect(description).toBe(apiResearchFile.requestDescription ?? ''); + + const result = await researchViewDetails.getResearchResult(); + expect(result).toBe(apiResearchFile.researchResult ?? ''); + + const exproNotes = await researchViewDetails.getResearchExpropriationNotes(); + expect(exproNotes).toBe(apiResearchFile.expropriationNotes ?? ''); + }); + + test('verify documents invalid types', async () => { + //Navigate to research list view and pick an existing research file + await researchListPage.goto(); + const newPage = await researchListPage.openResearchFileInNewTab(1); + researchViewDetails = new ResearchViewFileDetails(newPage); + documentsListPage = new DocumentsListPage(newPage); + documentUploadModalPage = new DocumentUploadModalPage(newPage); + + await expect(researchViewDetails.researchDocumentTab).toBeVisible(); //Navigate to the Document tab and create a new document await researchViewDetails.navigateDocumentsTab(); From b84ea048bde5f643b96b1429d4bdb7c6da091c2a Mon Sep 17 00:00:00 2001 From: Sue Tairaku Date: Thu, 25 Jun 2026 15:41:35 -0700 Subject: [PATCH 2/9] linting --- .../documents/document-upload-modal.page.ts | 4 +-- .../pages/research/research-list.page.ts | 10 +++--- .../research-view-file-details.page.ts | 26 ++++---------- .../tests/e2e/research.spec.ts | 35 +++++++++++-------- 4 files changed, 32 insertions(+), 43 deletions(-) diff --git a/testing/pims-integration/pages/documents/document-upload-modal.page.ts b/testing/pims-integration/pages/documents/document-upload-modal.page.ts index 2cffe7b998..0b04e841bd 100644 --- a/testing/pims-integration/pages/documents/document-upload-modal.page.ts +++ b/testing/pims-integration/pages/documents/document-upload-modal.page.ts @@ -36,9 +36,7 @@ export class DocumentUploadModalPage { } async getDocumentErrorLabel(index: number = 0): Promise { - const documentErrorLabel = this.page.getByTestId( - `document[${index}]-error-message` - ); + const documentErrorLabel = this.page.getByTestId(`document[${index}]-error-message`); return await documentErrorLabel.innerText(); } diff --git a/testing/pims-integration/pages/research/research-list.page.ts b/testing/pims-integration/pages/research/research-list.page.ts index 76e0063169..e878258c86 100644 --- a/testing/pims-integration/pages/research/research-list.page.ts +++ b/testing/pims-integration/pages/research/research-list.page.ts @@ -139,10 +139,10 @@ export class ResearchListPage extends LayoutPage { async openResearchFileInNewTab(index: number): Promise { const selectedFile = this.page - .getByTestId('researchFilesTable') - .locator('.tbody .tr-wrapper') - .nth(index - 1) - .locator('a'); + .getByTestId('researchFilesTable') + .locator('.tbody .tr-wrapper') + .nth(index - 1) + .locator('a'); const [newPage] = await Promise.all([ this.page.context().waitForEvent('page'), selectedFile.click(), @@ -169,7 +169,7 @@ export class ResearchListPage extends LayoutPage { const link = this.page .getByTestId('researchFilesTable') .locator('.tbody .tr-wrapper') - .nth(index-1) + .nth(index - 1) .locator('a'); await link.click(); diff --git a/testing/pims-integration/pages/research/research-view-file-details.page.ts b/testing/pims-integration/pages/research/research-view-file-details.page.ts index 39ff424b06..344170fdb4 100644 --- a/testing/pims-integration/pages/research/research-view-file-details.page.ts +++ b/testing/pims-integration/pages/research/research-view-file-details.page.ts @@ -79,35 +79,21 @@ export class ResearchViewFileDetails extends LayoutPage { async getFieldValueByLabel(label: string): Promise { return await this.page - .locator(`//label[contains(normalize-space(), '${label}')]/parent::div/following-sibling::div`) + .locator( + `//label[contains(normalize-space(), '${label}')]/parent::div/following-sibling::div` + ) .innerText(); } async getResearchDescription(): Promise { - return ( - await this.page - .getByTestId('request-description') - .locator('label') - .innerText() - ).trim(); + return (await this.page.getByTestId('request-description').locator('label').innerText()).trim(); } async getResearchResult(): Promise { - return ( - await this.page - .getByTestId('research-result') - .locator('label') - .innerText() - ).trim(); + return (await this.page.getByTestId('research-result').locator('label').innerText()).trim(); } async getResearchExpropriationNotes(): Promise { - return ( - await this.page - .getByTestId('expropriation-notes') - .locator('label') - .innerText() - ).trim(); + return (await this.page.getByTestId('expropriation-notes').locator('label').innerText()).trim(); } - } diff --git a/testing/pims-integration/tests/e2e/research.spec.ts b/testing/pims-integration/tests/e2e/research.spec.ts index 36b80bbefd..40a2885a81 100644 --- a/testing/pims-integration/tests/e2e/research.spec.ts +++ b/testing/pims-integration/tests/e2e/research.spec.ts @@ -37,7 +37,7 @@ test.describe('Research Files feature', () => { await expect(researchViewDetails.researchDocumentTab).toBeVisible(); }); - test('verify research view form', async() => { + test('verify research view form', async () => { //Navigate to Research list view await researchListPage.goto(); @@ -49,9 +49,9 @@ test.describe('Research Files feature', () => { researchListPage.clickResearchFileResult(1), ]); - const responsePromise = newPage.waitForResponse((response: { url: () => string | string[]; status: () => number; }) => - response.url().includes('/api/researchFiles/') && - response.status() === 200 + const responsePromise = newPage.waitForResponse( + (response: { url: () => string | string[]; status: () => number }) => + response.url().includes('/api/researchFiles/') && response.status() === 200 ); await newPage.waitForLoadState('domcontentloaded'); @@ -69,25 +69,30 @@ test.describe('Research Files feature', () => { await expect(researchViewDetails.researchDocumentTab).toBeVisible(); const fieldsToCompare = [ - {label: 'Ministry project', apiValue: apiResearchFile.researchFileProjects[0]}, - {label: 'Road name', apiValue: apiResearchFile.roadName}, - {label: 'Road alias', apiValue: apiResearchFile.roadAlias }, - {label: 'Research purpose', apiValue: apiResearchFile.researchFilePurposes[0].researchPurposeTypeCode.description}, - {label: 'Source of request', apiValue: apiResearchFile.requestSourceType.description }, - {label: 'Requester', apiValue: apiResearchFile.requestorPerson }, + { label: 'Ministry project', apiValue: apiResearchFile.researchFileProjects[0] }, + { label: 'Road name', apiValue: apiResearchFile.roadName }, + { label: 'Road alias', apiValue: apiResearchFile.roadAlias }, + { + label: 'Research purpose', + apiValue: apiResearchFile.researchFilePurposes[0].researchPurposeTypeCode.description, + }, + { label: 'Source of request', apiValue: apiResearchFile.requestSourceType.description }, + { label: 'Requester', apiValue: apiResearchFile.requestorPerson }, ]; const datesToCompare = [ - {label: 'Request date', apiValue: apiResearchFile.requestDate}, - {label: 'Research completed on', apiValue: apiResearchFile.researchCompletionDate }, - ] + { label: 'Request date', apiValue: apiResearchFile.requestDate }, + { label: 'Research completed on', apiValue: apiResearchFile.researchCompletionDate }, + ]; for (const field of fieldsToCompare) { const uiValue = await researchViewDetails.getFieldValueByLabel(field.label); - expect(researchViewDetails.normalize(uiValue)).toBe(researchViewDetails.normalize(field.apiValue)); + expect(researchViewDetails.normalize(uiValue)).toBe( + researchViewDetails.normalize(field.apiValue) + ); } - for(const date of datesToCompare) { + for (const date of datesToCompare) { const uiValue = await researchViewDetails.getFieldValueByLabel(date.label); const changedFormat = researchViewDetails.formatApiDate(date.apiValue); expect(researchViewDetails.normalize(uiValue)).toBe(changedFormat); From df1d3e546a9d222a08b5afa76c0b3df2a493f3c2 Mon Sep 17 00:00:00 2001 From: Sue Tairaku Date: Fri, 26 Jun 2026 15:30:11 -0700 Subject: [PATCH 3/9] Fix from comments --- .../pims-integration/models/research-file.ts | 30 ++++ .../pages/layout/layout.page.ts | 27 ---- .../tests/e2e/research.spec.ts | 144 ------------------ .../e2e/research/research-list-view.spec.ts | 23 +++ .../tests/e2e/research/research.spec.ts | 129 ++++++++++++++++ testing/pims-integration/utils/utils.ts | 27 ++++ 6 files changed, 209 insertions(+), 171 deletions(-) create mode 100644 testing/pims-integration/models/research-file.ts delete mode 100644 testing/pims-integration/tests/e2e/research.spec.ts create mode 100644 testing/pims-integration/tests/e2e/research/research-list-view.spec.ts create mode 100644 testing/pims-integration/tests/e2e/research/research.spec.ts create mode 100644 testing/pims-integration/utils/utils.ts diff --git a/testing/pims-integration/models/research-file.ts b/testing/pims-integration/models/research-file.ts new file mode 100644 index 0000000000..a7365628e7 --- /dev/null +++ b/testing/pims-integration/models/research-file.ts @@ -0,0 +1,30 @@ +export interface ApiGen_Concepts_ResearchFile { + id: number; + fileName: string | null; + fileNumber: string | null; + totalAllowableCompensation: number | null; + //fileStatusTypeCode: ApiGen_Base_CodeType | null; + //fileProperties: ApiGen_Concepts_FileProperty[] | null; + roadName: string | null; + roadAlias: string | null; + //fileProperties: ApiGen_Concepts_ResearchFileProperty[] | null; + //requestDate: UtcIsoDate | null; + requestDescription: string | null; + requestSourceDescription: string | null; + researchResult: string | null; + //researchCompletionDate: UtcIsoDate | null; + isExpropriation: boolean | null; + expropriationNotes: string | null; + //requestSourceType: ApiGen_Base_CodeType | null; + //requestorPerson: ApiGen_Concepts_Person | null; + //requestorOrganization: ApiGen_Concepts_Organization | null; + //researchFilePurposes: ApiGen_Concepts_ResearchFilePurpose[] | null; + //researchFileProjects: ApiGen_Concepts_ResearchFileProject[] | null; + //appCreateTimestamp: UtcIsoDateTime; + //appLastUpdateTimestamp: UtcIsoDateTime; + appLastUpdateUserid: string | null; + appCreateUserid: string | null; + appLastUpdateUserGuid: string | null; + appCreateUserGuid: string | null; + rowVersion: number | null; +} diff --git a/testing/pims-integration/pages/layout/layout.page.ts b/testing/pims-integration/pages/layout/layout.page.ts index 0d7f5b5c9a..03651eb290 100644 --- a/testing/pims-integration/pages/layout/layout.page.ts +++ b/testing/pims-integration/pages/layout/layout.page.ts @@ -12,31 +12,4 @@ export class LayoutPage { async openHelpDeskForm() { await this.helpDeskButton.click(); } - - normalize(value: unknown): string { - return value == null ? '' : String(value).trim(); - } - - formatApiDate(apiDate: string | null | undefined): string { - if (!apiDate) { - return ''; - } - - const date = new Date(apiDate); - - return date.toLocaleDateString('en-CA', { - month: 'short', - day: 'numeric', - year: 'numeric', - timeZone: 'UTC', // avoids timezone surprises - }); - } - - formatApiBoolean(value: boolean | null | undefined): string { - if (value == null) { - return ''; - } - - return value ? 'Yes' : 'No'; - } } diff --git a/testing/pims-integration/tests/e2e/research.spec.ts b/testing/pims-integration/tests/e2e/research.spec.ts deleted file mode 100644 index 40a2885a81..0000000000 --- a/testing/pims-integration/tests/e2e/research.spec.ts +++ /dev/null @@ -1,144 +0,0 @@ -import test, { BrowserContext, expect, Page } from '@playwright/test'; -import { ResearchCreatePage } from '../../pages/research/research-create.page'; -import { DocumentsListPage } from '../../pages/documents/documents-list.page'; -import { ResearchListPage } from '../../pages/research/research-list.page'; -import { ResearchViewFileDetails } from '../../pages/research/research-view-file-details.page'; -import { DocumentUploadModalPage } from '../../pages/documents/document-upload-modal.page'; -import path from 'path'; - -let context: BrowserContext; -let page: Page; -let researchListPage: ResearchListPage; -let researchCreatePage: ResearchCreatePage; -let researchViewDetails: ResearchViewFileDetails; -let documentsListPage: DocumentsListPage; -let documentUploadModalPage: DocumentUploadModalPage; - -test.describe('Research Files feature', () => { - test.beforeAll(async ({ browser }) => { - context = await browser.newContext(); - page = await context.newPage(); - researchListPage = new ResearchListPage(page); - researchCreatePage = new ResearchCreatePage(page); - researchViewDetails = new ResearchViewFileDetails(page); - documentsListPage = new DocumentsListPage(page); - documentUploadModalPage = new DocumentUploadModalPage(page); - }); - - test.afterAll(async () => { - await context.close(); - }); - - test('create new research file', async () => { - //Navigate to new research file and create a minimum viable research - await researchCreatePage.goto(); - await researchCreatePage.setResearchNameValue('researchFile'); - await researchCreatePage.confirmButtonClick(); - await expect(researchViewDetails.researchDocumentTab).toBeVisible(); - }); - - test('verify research view form', async () => { - //Navigate to Research list view - await researchListPage.goto(); - - //Search researh file by name - await researchListPage.searchByName('Bubba BBQ Whirled'); - - const [newPage] = await Promise.all([ - context.waitForEvent('page'), - researchListPage.clickResearchFileResult(1), - ]); - - const responsePromise = newPage.waitForResponse( - (response: { url: () => string | string[]; status: () => number }) => - response.url().includes('/api/researchFiles/') && response.status() === 200 - ); - - await newPage.waitForLoadState('domcontentloaded'); - - const response = await responsePromise; - const apiResearchFile = await response.json(); - - const researchViewDetails = new ResearchViewFileDetails(newPage); - - console.log('############################'); - console.log('FOUND THE API RESPONSE'); - console.log(response.url()); - console.log(JSON.stringify(apiResearchFile, null, 2)); - console.log('############################'); - - await expect(researchViewDetails.researchDocumentTab).toBeVisible(); - const fieldsToCompare = [ - { label: 'Ministry project', apiValue: apiResearchFile.researchFileProjects[0] }, - { label: 'Road name', apiValue: apiResearchFile.roadName }, - { label: 'Road alias', apiValue: apiResearchFile.roadAlias }, - { - label: 'Research purpose', - apiValue: apiResearchFile.researchFilePurposes[0].researchPurposeTypeCode.description, - }, - { label: 'Source of request', apiValue: apiResearchFile.requestSourceType.description }, - { label: 'Requester', apiValue: apiResearchFile.requestorPerson }, - ]; - - const datesToCompare = [ - { label: 'Request date', apiValue: apiResearchFile.requestDate }, - { label: 'Research completed on', apiValue: apiResearchFile.researchCompletionDate }, - ]; - - for (const field of fieldsToCompare) { - const uiValue = await researchViewDetails.getFieldValueByLabel(field.label); - expect(researchViewDetails.normalize(uiValue)).toBe( - researchViewDetails.normalize(field.apiValue) - ); - } - - for (const date of datesToCompare) { - const uiValue = await researchViewDetails.getFieldValueByLabel(date.label); - const changedFormat = researchViewDetails.formatApiDate(date.apiValue); - expect(researchViewDetails.normalize(uiValue)).toBe(changedFormat); - } - - const isExpropriation = await researchViewDetails.getFieldValueByLabel('Expropriation?'); - const formatedBoolean = researchViewDetails.formatApiBoolean(apiResearchFile.isExpropriation); - expect(researchViewDetails.normalize(isExpropriation)).toBe(formatedBoolean); - - const description = await researchViewDetails.getResearchDescription(); - expect(description).toBe(apiResearchFile.requestDescription ?? ''); - - const result = await researchViewDetails.getResearchResult(); - expect(result).toBe(apiResearchFile.researchResult ?? ''); - - const exproNotes = await researchViewDetails.getResearchExpropriationNotes(); - expect(exproNotes).toBe(apiResearchFile.expropriationNotes ?? ''); - }); - - test('verify documents invalid types', async () => { - //Navigate to research list view and pick an existing research file - await researchListPage.goto(); - const newPage = await researchListPage.openResearchFileInNewTab(1); - researchViewDetails = new ResearchViewFileDetails(newPage); - documentsListPage = new DocumentsListPage(newPage); - documentUploadModalPage = new DocumentUploadModalPage(newPage); - - await expect(researchViewDetails.researchDocumentTab).toBeVisible(); - - //Navigate to the Document tab and create a new document - await researchViewDetails.navigateDocumentsTab(); - await documentsListPage.addDocumentButtonClick(); - const documentTypes = await documentUploadModalPage.getSupportedFileExtensionsText(); - expect(documentTypes).toBe( - 'Supported file types include txt, pdf, docx, doc, xlsx, xls, html, odt, png, jpg, bmp, tif, tiff, jpeg, gif, shp, gml, kml, kmz, msg.' - ); - - //Insert an invalid document type - const filePath = path.resolve(process.cwd(), 'fixtures', 'react-icon.svg'); - await documentUploadModalPage.uploadDocument(filePath); - - //Verify warning message appears - const errorLabel = await documentUploadModalPage.getDocumentErrorLabel(); - expect(errorLabel).toBe('File type not supported!'); - - const fileName = await documentUploadModalPage.getDocumentErrorFilename(); - expect(fileName).toBe('react-icon.svg'); - }); -}); diff --git a/testing/pims-integration/tests/e2e/research/research-list-view.spec.ts b/testing/pims-integration/tests/e2e/research/research-list-view.spec.ts new file mode 100644 index 0000000000..706c747daf --- /dev/null +++ b/testing/pims-integration/tests/e2e/research/research-list-view.spec.ts @@ -0,0 +1,23 @@ +import test, { BrowserContext, Page } from '@playwright/test'; +import { ResearchListPage } from '../../../pages/research/research-list.page'; + +let context: BrowserContext; +let page: Page; +let researchListPage: ResearchListPage; + +test.describe('Research Files feature', () => { + test.beforeAll(async ({ browser }) => { + context = await browser.newContext(); + page = await context.newPage(); + researchListPage = new ResearchListPage(page); + }); + + test.afterAll(async () => { + await context.close(); + }); + + test('verify research list view', async () => { + //Navigate to research list view and pick an existing research file + await researchListPage.goto(); + }); +}); diff --git a/testing/pims-integration/tests/e2e/research/research.spec.ts b/testing/pims-integration/tests/e2e/research/research.spec.ts new file mode 100644 index 0000000000..909f419fb8 --- /dev/null +++ b/testing/pims-integration/tests/e2e/research/research.spec.ts @@ -0,0 +1,129 @@ +import test, { BrowserContext, expect, Page } from '@playwright/test'; +import { ResearchCreatePage } from '../../../pages/research/research-create.page'; +import { DocumentsListPage } from '../../../pages/documents/documents-list.page'; + +import { ResearchViewFileDetails } from '../../../pages/research/research-view-file-details.page'; +import { DocumentUploadModalPage } from '../../../pages/documents/document-upload-modal.page'; +import { normalize, formatApiDate, formatApiBoolean } from '../../../utils/utils'; +import path from 'path'; + +let context: BrowserContext; +let page: Page; + +let researchCreatePage: ResearchCreatePage; +let researchViewDetails: ResearchViewFileDetails; +let documentsListPage: DocumentsListPage; +let documentUploadModalPage: DocumentUploadModalPage; + +test.describe('Research Files feature', () => { + test.beforeAll(async ({ browser }) => { + context = await browser.newContext(); + page = await context.newPage(); + researchCreatePage = new ResearchCreatePage(page); + researchViewDetails = new ResearchViewFileDetails(page); + documentsListPage = new DocumentsListPage(page); + documentUploadModalPage = new DocumentUploadModalPage(page); + }); + + test.afterAll(async () => { + await context.close(); + }); + + test('new research file', async () => { + let apiFeatureFileJson: { + isExpropriation: boolean | null; + expropriationNotes: string; + researchResult: string; + requestDescription: string; + researchFileProjects: any[]; + roadName: any; + roadAlias: any; + researchFilePurposes: { researchPurposeTypeCode: { description: any } }[]; + requestSourceType: { description: any }; + requestorPerson: any; + requestDate: any; + researchCompletionDate: any; + }; + const responsePromise = page.waitForResponse( + (response: { url: () => string | string[]; status: () => number }) => + response.url().includes('/api/researchFiles/') && response.status() === 200 + ); + + await test.step('Create file', async () => { + //Navigate to new research file and create a minimum viable research + await researchCreatePage.goto(); + await researchCreatePage.setResearchNameValue('researchFile'); + await researchCreatePage.confirmButtonClick(); + + const response = await responsePromise; + apiFeatureFileJson = await response.json(); + + await expect(researchViewDetails.researchDocumentTab).toBeVisible(); + }); + + await test.step('Validate details', async () => { + await expect(researchViewDetails.researchDocumentTab).toBeVisible(); + const fieldsToCompare = [ + { label: 'Ministry project', apiValue: apiFeatureFileJson.researchFileProjects[0] }, + { label: 'Road name', apiValue: apiFeatureFileJson.roadName }, + { label: 'Road alias', apiValue: apiFeatureFileJson.roadAlias }, + { + label: 'Research purpose', + apiValue: apiFeatureFileJson.researchFilePurposes[0].researchPurposeTypeCode.description, + }, + { label: 'Source of request', apiValue: apiFeatureFileJson.requestSourceType.description }, + { label: 'Requester', apiValue: apiFeatureFileJson.requestorPerson }, + ]; + + const datesToCompare = [ + { label: 'Request date', apiValue: apiFeatureFileJson.requestDate }, + { label: 'Research completed on', apiValue: apiFeatureFileJson.researchCompletionDate }, + ]; + + for (const field of fieldsToCompare) { + const uiValue = await researchViewDetails.getFieldValueByLabel(field.label); + expect(normalize(uiValue)).toBe(normalize(field.apiValue)); + } + + for (const date of datesToCompare) { + const uiValue = await researchViewDetails.getFieldValueByLabel(date.label); + const changedFormat = formatApiDate(date.apiValue); + expect(normalize(uiValue)).toBe(changedFormat); + } + + const isExpropriation = await researchViewDetails.getFieldValueByLabel('Expropriation?'); + const formatedBoolean = formatApiBoolean(apiFeatureFileJson.isExpropriation); + expect(normalize(isExpropriation)).toBe(formatedBoolean); + + const description = await researchViewDetails.getResearchDescription(); + expect(description).toBe(apiFeatureFileJson.requestDescription ?? ''); + + const result = await researchViewDetails.getResearchResult(); + expect(result).toBe(apiFeatureFileJson.researchResult ?? ''); + + const exproNotes = await researchViewDetails.getResearchExpropriationNotes(); + expect(exproNotes).toBe(apiFeatureFileJson.expropriationNotes ?? ''); + }); + + await test.step('validate document upload', async () => { + //Navigate to the Document tab and create a new document + await researchViewDetails.navigateDocumentsTab(); + await documentsListPage.addDocumentButtonClick(); + const documentTypes = await documentUploadModalPage.getSupportedFileExtensionsText(); + expect(documentTypes).toBe( + 'Supported file types include txt, pdf, docx, doc, xlsx, xls, html, odt, png, jpg, bmp, tif, tiff, jpeg, gif, shp, gml, kml, kmz, msg.' + ); + + //Insert an invalid document type + const filePath = path.resolve(process.cwd(), 'fixtures', 'react-icon.svg'); + await documentUploadModalPage.uploadDocument(filePath); + + //Verify warning message appears + const errorLabel = await documentUploadModalPage.getDocumentErrorLabel(); + expect(errorLabel).toBe('File type not supported!'); + + const fileName = await documentUploadModalPage.getDocumentErrorFilename(); + expect(fileName).toBe('react-icon.svg'); + }); + }); +}); diff --git a/testing/pims-integration/utils/utils.ts b/testing/pims-integration/utils/utils.ts new file mode 100644 index 0000000000..51a5cb14f8 --- /dev/null +++ b/testing/pims-integration/utils/utils.ts @@ -0,0 +1,27 @@ + + export const normalize = (value: string | null): string =>{ + return value == null ? '' : String(value).trim(); + } + + export const formatApiDate = (apiDate: string | null | undefined): string => { + if (!apiDate) { + return ''; + } + + const date = new Date(apiDate); + + return date.toLocaleDateString('en-CA', { + month: 'short', + day: 'numeric', + year: 'numeric', + timeZone: 'UTC', // avoids timezone surprises + }); + } + + export const formatApiBoolean = (value: boolean | null | undefined): string => { + if (value == null) { + return ''; + } + + return value ? 'Yes' : 'No'; + } From 1c4bc9d0868af7c23144b56b12908ade74675e19 Mon Sep 17 00:00:00 2001 From: Sue Tairaku Date: Fri, 26 Jun 2026 15:30:30 -0700 Subject: [PATCH 4/9] linting --- testing/pims-integration/utils/utils.ts | 39 ++++++++++++------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/testing/pims-integration/utils/utils.ts b/testing/pims-integration/utils/utils.ts index 51a5cb14f8..fdab5681ae 100644 --- a/testing/pims-integration/utils/utils.ts +++ b/testing/pims-integration/utils/utils.ts @@ -1,27 +1,26 @@ +export const normalize = (value: string | null): string => { + return value == null ? '' : String(value).trim(); +}; - export const normalize = (value: string | null): string =>{ - return value == null ? '' : String(value).trim(); +export const formatApiDate = (apiDate: string | null | undefined): string => { + if (!apiDate) { + return ''; } - export const formatApiDate = (apiDate: string | null | undefined): string => { - if (!apiDate) { - return ''; - } + const date = new Date(apiDate); - const date = new Date(apiDate); + return date.toLocaleDateString('en-CA', { + month: 'short', + day: 'numeric', + year: 'numeric', + timeZone: 'UTC', // avoids timezone surprises + }); +}; - return date.toLocaleDateString('en-CA', { - month: 'short', - day: 'numeric', - year: 'numeric', - timeZone: 'UTC', // avoids timezone surprises - }); +export const formatApiBoolean = (value: boolean | null | undefined): string => { + if (value == null) { + return ''; } - export const formatApiBoolean = (value: boolean | null | undefined): string => { - if (value == null) { - return ''; - } - - return value ? 'Yes' : 'No'; - } + return value ? 'Yes' : 'No'; +}; From 6b81690ace2c8b62cc69d8e96ff6a8a9831e6360 Mon Sep 17 00:00:00 2001 From: Sue Tairaku Date: Fri, 26 Jun 2026 16:10:48 -0700 Subject: [PATCH 5/9] Fixing tests --- testing/pims-integration/tests/e2e/research/research.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/pims-integration/tests/e2e/research/research.spec.ts b/testing/pims-integration/tests/e2e/research/research.spec.ts index 909f419fb8..bd4d1bac3a 100644 --- a/testing/pims-integration/tests/e2e/research/research.spec.ts +++ b/testing/pims-integration/tests/e2e/research/research.spec.ts @@ -62,7 +62,7 @@ test.describe('Research Files feature', () => { }); await test.step('Validate details', async () => { - await expect(researchViewDetails.researchDocumentTab).toBeVisible(); + const fieldsToCompare = [ { label: 'Ministry project', apiValue: apiFeatureFileJson.researchFileProjects[0] }, { label: 'Road name', apiValue: apiFeatureFileJson.roadName }, From 86e33947740352d50e63711e9378681072e7eda6 Mon Sep 17 00:00:00 2001 From: Sue Tairaku Date: Fri, 26 Jun 2026 16:11:12 -0700 Subject: [PATCH 6/9] lint --- testing/pims-integration/tests/e2e/research/research.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/pims-integration/tests/e2e/research/research.spec.ts b/testing/pims-integration/tests/e2e/research/research.spec.ts index bd4d1bac3a..101dded453 100644 --- a/testing/pims-integration/tests/e2e/research/research.spec.ts +++ b/testing/pims-integration/tests/e2e/research/research.spec.ts @@ -62,7 +62,6 @@ test.describe('Research Files feature', () => { }); await test.step('Validate details', async () => { - const fieldsToCompare = [ { label: 'Ministry project', apiValue: apiFeatureFileJson.researchFileProjects[0] }, { label: 'Road name', apiValue: apiFeatureFileJson.roadName }, From 4ca3655d8d8ab980b057d2fe8ab2eb0d0a7bcaa3 Mon Sep 17 00:00:00 2001 From: Sue Tairaku Date: Fri, 3 Jul 2026 16:31:12 -0700 Subject: [PATCH 7/9] Correcting PR observations --- .../pages/research/research-create.page.ts | 16 ---------------- .../e2e/research/research-list-view.spec.ts | 3 ++- .../tests/e2e/research/research.spec.ts | 4 ++-- testing/pims-integration/utils/utils.ts | 15 +++++++++++++++ 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/testing/pims-integration/pages/research/research-create.page.ts b/testing/pims-integration/pages/research/research-create.page.ts index c59af2dadd..fd173caa4f 100644 --- a/testing/pims-integration/pages/research/research-create.page.ts +++ b/testing/pims-integration/pages/research/research-create.page.ts @@ -71,22 +71,6 @@ export class ResearchCreatePage extends LayoutPage { await this.page.goto('/mapview/sidebar/research/new', { waitUntil: 'domcontentloaded' }); } - async setResearchNameValue(researchName: string) { - const now = new Date(); - - const timestamp = - now.getFullYear().toString() + - String(now.getMonth() + 1).padStart(2, '0') + - String(now.getDate()).padStart(2, '0') + - String(now.getHours()).padStart(2, '0') + - String(now.getMinutes()).padStart(2, '0') + - String(now.getSeconds()).padStart(2, '0'); - - const fileName = `${researchName}-${timestamp}`; - - await this.researchNameInput.fill(fileName); - } - async cancelButtonClick() { await this.cancelButton.click(); } diff --git a/testing/pims-integration/tests/e2e/research/research-list-view.spec.ts b/testing/pims-integration/tests/e2e/research/research-list-view.spec.ts index 706c747daf..b23e5ad9f5 100644 --- a/testing/pims-integration/tests/e2e/research/research-list-view.spec.ts +++ b/testing/pims-integration/tests/e2e/research/research-list-view.spec.ts @@ -1,4 +1,4 @@ -import test, { BrowserContext, Page } from '@playwright/test'; +import test, { BrowserContext, expect, Page } from '@playwright/test'; import { ResearchListPage } from '../../../pages/research/research-list.page'; let context: BrowserContext; @@ -19,5 +19,6 @@ test.describe('Research Files feature', () => { test('verify research list view', async () => { //Navigate to research list view and pick an existing research file await researchListPage.goto(); + await expect(researchListPage.researchListTitle).toBeVisible(); }); }); diff --git a/testing/pims-integration/tests/e2e/research/research.spec.ts b/testing/pims-integration/tests/e2e/research/research.spec.ts index 101dded453..ebad39bfb6 100644 --- a/testing/pims-integration/tests/e2e/research/research.spec.ts +++ b/testing/pims-integration/tests/e2e/research/research.spec.ts @@ -4,7 +4,7 @@ import { DocumentsListPage } from '../../../pages/documents/documents-list.page' import { ResearchViewFileDetails } from '../../../pages/research/research-view-file-details.page'; import { DocumentUploadModalPage } from '../../../pages/documents/document-upload-modal.page'; -import { normalize, formatApiDate, formatApiBoolean } from '../../../utils/utils'; +import { generateFileName, normalize, formatApiDate, formatApiBoolean } from '../../../utils/utils'; import path from 'path'; let context: BrowserContext; @@ -52,7 +52,7 @@ test.describe('Research Files feature', () => { await test.step('Create file', async () => { //Navigate to new research file and create a minimum viable research await researchCreatePage.goto(); - await researchCreatePage.setResearchNameValue('researchFile'); + generateFileName('researchFile'); await researchCreatePage.confirmButtonClick(); const response = await responsePromise; diff --git a/testing/pims-integration/utils/utils.ts b/testing/pims-integration/utils/utils.ts index fdab5681ae..d42428d1dd 100644 --- a/testing/pims-integration/utils/utils.ts +++ b/testing/pims-integration/utils/utils.ts @@ -1,3 +1,18 @@ +export const generateFileName = (fileType: string): string => { + const now = new Date(); + + const timestamp = + now.getFullYear().toString() + + String(now.getMonth() + 1).padStart(2, '0') + + String(now.getDate()).padStart(2, '0') + + String(now.getHours()).padStart(2, '0') + + String(now.getMinutes()).padStart(2, '0') + + String(now.getSeconds()).padStart(2, '0'); + + return `${fileType}-${timestamp}`; +}; + + export const normalize = (value: string | null): string => { return value == null ? '' : String(value).trim(); }; From d15ab80e76f099d9eb1dea935c20e7f954c98810 Mon Sep 17 00:00:00 2001 From: Sue Tairaku Date: Fri, 3 Jul 2026 16:31:44 -0700 Subject: [PATCH 8/9] linting --- testing/pims-integration/utils/utils.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/testing/pims-integration/utils/utils.ts b/testing/pims-integration/utils/utils.ts index d42428d1dd..dfd5b15c75 100644 --- a/testing/pims-integration/utils/utils.ts +++ b/testing/pims-integration/utils/utils.ts @@ -1,18 +1,16 @@ export const generateFileName = (fileType: string): string => { const now = new Date(); - const timestamp = - now.getFullYear().toString() + - String(now.getMonth() + 1).padStart(2, '0') + - String(now.getDate()).padStart(2, '0') + - String(now.getHours()).padStart(2, '0') + - String(now.getMinutes()).padStart(2, '0') + - String(now.getSeconds()).padStart(2, '0'); - - return `${fileType}-${timestamp}`; + const timestamp = + now.getFullYear().toString() + + String(now.getMonth() + 1).padStart(2, '0') + + String(now.getDate()).padStart(2, '0') + + String(now.getHours()).padStart(2, '0') + + String(now.getMinutes()).padStart(2, '0') + + String(now.getSeconds()).padStart(2, '0'); + + return `${fileType}-${timestamp}`; }; - - export const normalize = (value: string | null): string => { return value == null ? '' : String(value).trim(); }; From 7eabbed6fd824bf6a7bd3f2b6df66548c62bd5df Mon Sep 17 00:00:00 2001 From: Sue Tairaku Date: Mon, 6 Jul 2026 13:04:48 -0700 Subject: [PATCH 9/9] Updating snapshots --- .../research/__snapshots__/ResearchContainer.test.tsx.snap | 3 +++ .../tabs/__snapshots__/ResearchTabsContainer.test.tsx.snap | 3 +++ .../details/__snapshots__/ResearchSummaryView.test.tsx.snap | 3 +++ 3 files changed, 9 insertions(+) diff --git a/source/frontend/src/features/mapSideBar/research/__snapshots__/ResearchContainer.test.tsx.snap b/source/frontend/src/features/mapSideBar/research/__snapshots__/ResearchContainer.test.tsx.snap index 9c4a5c7ef7..5de0001ba1 100644 --- a/source/frontend/src/features/mapSideBar/research/__snapshots__/ResearchContainer.test.tsx.snap +++ b/source/frontend/src/features/mapSideBar/research/__snapshots__/ResearchContainer.test.tsx.snap @@ -1379,6 +1379,7 @@ exports[`ResearchContainer component > renders as expected 1`] = `
renders as expected 1`] = `
renders as expected 1`] = `
matches snapshot 1`] = `
matches snapshot 1`] = `
matches snapshot 1`] = `
renders as expected 1`] = `
renders as expected 1`] = `
renders as expected 1`] = `