From dc8ad3e2b7ca0932d9ec69eec7e91680b8437254 Mon Sep 17 00:00:00 2001 From: aweng98 Date: Wed, 20 Sep 2023 16:14:45 -0400 Subject: [PATCH] fix atcp-recieve-kit.spec playwright test --- .../dsm/pages/participant-list-page.ts | 50 +++++++++ .../dsm/pages/samples/search-page.ts | 3 +- .../tests/dsm/atcp/atcp-receive-kit.spec.ts | 103 ++---------------- 3 files changed, 63 insertions(+), 93 deletions(-) diff --git a/playwright-e2e/dsm/pages/participant-list-page.ts b/playwright-e2e/dsm/pages/participant-list-page.ts index a47ec18238..786b7de268 100644 --- a/playwright-e2e/dsm/pages/participant-list-page.ts +++ b/playwright-e2e/dsm/pages/participant-list-page.ts @@ -294,4 +294,54 @@ export default class ParticipantListPage { } throw new Error(`Failed to find a suitable participant for Kit Upload within max waiting time 90 seconds.`); } + + async findParticipantFor(columnGroup: string, columnName: string, opts: {value?: string, nth?: number} = {}): Promise { + const { value, nth = 1 } = opts; + + const compareForMatch = async (index: number): Promise => { + const columnText = await participantListTable.getTextAt(index, columnName); + if (value) { + return columnText.some(text => text.indexOf(value) !== -1) ? index : -1; + } + return columnText.length === 1 && columnText[0].trim().length === 0 ? index : -1; + }; + + const searchPanel = this.filters.searchPanel; + await searchPanel.open(); + await searchPanel.checkboxes('Status', { checkboxValues: ['Enrolled'] }); + await searchPanel.search(); + + const participantListTable = this.participantListTable; + await expect(participantListTable.rowLocator().first()).toBeVisible(); + + const customizeViewPanel = this.filters.customizeViewPanel; + await customizeViewPanel.open(); + await customizeViewPanel.selectColumns(columnGroup, [columnName], {nth}); + await customizeViewPanel.close(); + + let participantsCount = await participantListTable.rowsCount; + expect(participantsCount).toBeGreaterThanOrEqual(1); + + const endTime = Date.now() + 90 * 1000; + while (participantsCount > 0 && Date.now() < endTime) { + let rowIndex = -1; + // Iterate rows in random order + const array = shuffle([...Array(participantsCount).keys()]); + for (const index of array) { + rowIndex = await compareForMatch(index); + if (rowIndex !== -1) { + return rowIndex; + } + } + // Next page in table + const hasNextPage = await participantListTable.paginator.hasNext(); + if (hasNextPage) { + await participantListTable.nextPage(); + participantsCount = await participantListTable.rowsCount; + } else { + participantsCount = 0; + } + } + throw new Error(`Failed to find a suitable participant for ${columnGroup}: ${columnName} = "${value}" within max waiting time 90 seconds.`); + } } diff --git a/playwright-e2e/dsm/pages/samples/search-page.ts b/playwright-e2e/dsm/pages/samples/search-page.ts index cbb3add1f8..fbb0d9b763 100644 --- a/playwright-e2e/dsm/pages/samples/search-page.ts +++ b/playwright-e2e/dsm/pages/samples/search-page.ts @@ -2,7 +2,7 @@ import { expect, Page } from '@playwright/test'; import DatePicker from 'dsm/component/date-picker'; import Select from 'dss/component/select'; import Table from 'dss/component/table'; -import { waitForNoSpinner } from 'utils/test-utils'; +import { waitForNoSpinner, waitForResponse } from 'utils/test-utils'; export enum SearchByField { SHORT_ID = 'Short ID', @@ -23,6 +23,7 @@ export default class SearchPage { const locator = this.page.locator('//div[button[normalize-space()="Search Kit"]]'); await locator.locator('//input').fill(value); await locator.locator('//button').click(); + await waitForResponse(this.page, {uri: '/ui/searchKit'}); await waitForNoSpinner(this.page); const table = new Table(this.page); diff --git a/playwright-e2e/tests/dsm/atcp/atcp-receive-kit.spec.ts b/playwright-e2e/tests/dsm/atcp/atcp-receive-kit.spec.ts index 19d47aeb07..069fbd7033 100644 --- a/playwright-e2e/tests/dsm/atcp/atcp-receive-kit.spec.ts +++ b/playwright-e2e/tests/dsm/atcp/atcp-receive-kit.spec.ts @@ -1,5 +1,5 @@ import { expect } from '@playwright/test'; -import { AdditionalFilter } from 'dsm/component/filters/sections/search/search-enums'; +import { test } from 'fixtures/dsm-fixture'; import { SamplesNavEnum } from 'dsm/component/navigation/enums/samplesNav-enum'; import { StudyEnum } from 'dsm/component/navigation/enums/selectStudyNav-enum'; import { StudyNavEnum } from 'dsm/component/navigation/enums/studyNav-enum'; @@ -11,11 +11,10 @@ import ParticipantPage from 'dsm/pages/participant-page/participant-page'; import AtcpSearchPage, { SearchByField } from 'dsm/pages/samples/search-page'; import { WelcomePage } from 'dsm/pages/welcome-page'; import Radiobutton from 'dss/component/radiobutton'; -import { test } from 'fixtures/dsm-fixture'; import { getUtcDate } from 'utils/date-utils'; import { generateAlphaNumeric } from 'utils/faker-utils'; -import { logError, logGenomeStudySampleKitReceived, logInfo } from 'utils/log-utils'; import { studyShortName, waitForNoSpinner, waitForResponse } from 'utils/test-utils'; +import { logInfo } from 'utils/log-utils'; test.describe('Receive Genome Study Kit', () => { const studies = [StudyEnum.AT]; @@ -23,15 +22,11 @@ test.describe('Receive Genome Study Kit', () => { let newBarcode = generateAlphaNumeric().toUpperCase(); let shortId: string; - let guid: string; let participantPage: ParticipantPage; let participantListPage: ParticipantListPage; let navigation: Navigation; - // Fallback to use non-e2e participant if all e2e participants have kit received before - const nonE2EParticipants: string[] = []; - test.beforeEach(async ({page, request}) => { navigation = new Navigation(page, request); const welcomePage = new WelcomePage(page); @@ -39,101 +34,24 @@ test.describe('Receive Genome Study Kit', () => { }); test(`Receive genome sample kit for ${study} @dsm @${study} @functional`, async ({page}) => { - // Instead using UI table filter and search, it is much quicker and more accurate to intercept DSM API request to find the right participant to use. - // Find a Playwright test user that does not have GENOME_STUDY_SPIT_KIT_BARCODE. - await page.route('**/*', async (route, request): Promise => { - const regex = new RegExp(/applyFilter\?realm=.*&userId=.*&parent=participantList/i); - if (!shortId && request && request.url().match(regex)) { - logInfo(`Intercepting API request ${request.url()} to search for a E2E participant`); - const response = await route.fetch(); - const json = JSON.parse(await response.text()); - for (const i in json.participants) { - const participant = json.participants[i]; - const profile = participant.esData.profile; - const participantData = participant.esData.dsm.participantData; - let hruId = profile.hruid; - expect(hruId).toBeTruthy(); // hruid must exists - try { - let existField = false; - for (const dataId in participantData) { - if ((participantData[dataId].fieldTypeId as string) === 'AT_GROUP_GENOME_STUDY') { - existField = true; - if ((participantData[dataId].data as string).indexOf('GENOME_STUDY_SPIT_KIT_BARCODE') !== -1) { - hruId = null; // discard this participant because person has received genome study kit before - } - break; - } - } - expect(existField).toBe(true); // AT_GROUP_GENOME_STUDY must exists in participantData - if (hruId && profile.firstName) { - if (profile.firstName.includes('E2E')) { - shortId = hruId; - break; // finish searching for a participant who is Playwright automation test created and does not have genome study kit barcode - } else { - // save non-e2e participant short id then check next participant - nonE2EParticipants.push(hruId); - } - } - } catch (err) { - logError(`Failed to read response json.\n${err}`); - logError(JSON.stringify(participant)); - } - } - } - return route.continue(); - }); - await test.step('Search for the right participant on Participant List page', async () => { participantListPage = await navigation.selectFromStudy(StudyNavEnum.PARTICIPANT_LIST); await participantListPage.waitForReady(); - // Search for a participant that meets the search criteria - const customizeViewPanel = participantListPage.filters.customizeViewPanel; - await customizeViewPanel.open(); - await customizeViewPanel.selectColumns('Participant Columns', ['Registration Date']); - await customizeViewPanel.selectColumns('Genome Study Columns', ['Sample kit barcode for genome study'], { nth: 1 }); - await customizeViewPanel.close(); - - const searchPanel = participantListPage.filters.searchPanel; - await searchPanel.open(); - await searchPanel.checkboxes('Status', { checkboxValues: ['Registered', 'Enrolled'] }); - await searchPanel.text('Sample kit barcode for genome study', { additionalFilters: [AdditionalFilter.EMPTY] }); - await searchPanel.search(); - }); - - await test.step('Verify participant detail on Participant page', async () => { - const searchPanel = participantListPage.filters.searchPanel; - await searchPanel.clear(); - - if (!shortId) { - // Attempt to find a non-e2e test participant - const [firstParticipant] = nonE2EParticipants; - shortId = firstParticipant; - } - - await participantListPage.filterListByShortId(shortId); - logGenomeStudySampleKitReceived(shortId); + const rowIndex = await participantListPage.findParticipantFor('Genome Study Columns', 'Sample kit barcode for genome study', {nth: 1}); - const row = 0; - const participantsTable = participantListPage.participantListTable; - const status = await participantsTable.getParticipantDataAt(row, 'Status'); - expect(status).toMatch(/Enrolled|Registered/); - const rowShortId = await participantsTable.getParticipantDataAt(row, 'Short ID'); - expect(rowShortId).toBe(shortId); - const registrationDate = await participantsTable.getParticipantDataAt(row, 'Registration Date', { exactMatch: false }); - - // Open the Participant page - participantPage = await participantsTable.openParticipantPageAt(row); - - expect(await participantPage.getStatus()).toBe(status); - expect(await participantPage.getShortId()).toBe(shortId); - expect(await participantPage.getRegistrationDate()).toBe(registrationDate); - guid = await participantPage.getGuid(); + const participantListTable = participantListPage.participantListTable; + shortId = await participantListTable.getParticipantDataAt(rowIndex, 'Short ID'); + participantPage = await participantListTable.openParticipantPageAt(rowIndex); + logInfo(`Participant Short ID: ${shortId}`); }); await test.step('Set new sample kit barcode', async () => { newBarcode = `${shortId}-${newBarcode}`; const genomeStudyTab = await participantPage.clickTab(TabEnum.GENOME_STUDY); + const value = await genomeStudyTab.getField('Sample kit barcode for genome study').locator('input').inputValue(); + expect(value).toBe(''); // Sample Kit Barcode input should be empty + await Promise.all([ genomeStudyTab.setValue('Sample kit barcode for genome study', newBarcode), page.waitForResponse(resp => { @@ -157,6 +75,7 @@ test.describe('Receive Genome Study Kit', () => { expect(await table.getRowText(row, 'Short ID')).toBe(shortId); const button = table.findButtonInCell(table.rowLocator(), { label: 'Mark Received' }); + await expect(button.toLocator()).toBeVisible(); await Promise.all([ waitForResponse(page, { uri: `ui/receivedKits?realm=${studyShortName(study).realm}&userId=` }), button.click()