Skip to content

Commit 94fa81a

Browse files
authored
Merge branch 'develop' into PW-DSM-Tissue-request-flow
2 parents 5abdecf + d5ac523 commit 94fa81a

File tree

3 files changed

+63
-93
lines changed

3 files changed

+63
-93
lines changed

playwright-e2e/dsm/pages/participant-list-page.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,54 @@ export default class ParticipantListPage {
294294
}
295295
throw new Error(`Failed to find a suitable participant for Kit Upload within max waiting time 90 seconds.`);
296296
}
297+
298+
async findParticipantFor(columnGroup: string, columnName: string, opts: {value?: string, nth?: number} = {}): Promise<number> {
299+
const { value, nth = 1 } = opts;
300+
301+
const compareForMatch = async (index: number): Promise<number> => {
302+
const columnText = await participantListTable.getTextAt(index, columnName);
303+
if (value) {
304+
return columnText.some(text => text.indexOf(value) !== -1) ? index : -1;
305+
}
306+
return columnText.length === 1 && columnText[0].trim().length === 0 ? index : -1;
307+
};
308+
309+
const searchPanel = this.filters.searchPanel;
310+
await searchPanel.open();
311+
await searchPanel.checkboxes('Status', { checkboxValues: ['Enrolled'] });
312+
await searchPanel.search();
313+
314+
const participantListTable = this.participantListTable;
315+
await expect(participantListTable.rowLocator().first()).toBeVisible();
316+
317+
const customizeViewPanel = this.filters.customizeViewPanel;
318+
await customizeViewPanel.open();
319+
await customizeViewPanel.selectColumns(columnGroup, [columnName], {nth});
320+
await customizeViewPanel.close();
321+
322+
let participantsCount = await participantListTable.rowsCount;
323+
expect(participantsCount).toBeGreaterThanOrEqual(1);
324+
325+
const endTime = Date.now() + 90 * 1000;
326+
while (participantsCount > 0 && Date.now() < endTime) {
327+
let rowIndex = -1;
328+
// Iterate rows in random order
329+
const array = shuffle([...Array(participantsCount).keys()]);
330+
for (const index of array) {
331+
rowIndex = await compareForMatch(index);
332+
if (rowIndex !== -1) {
333+
return rowIndex;
334+
}
335+
}
336+
// Next page in table
337+
const hasNextPage = await participantListTable.paginator.hasNext();
338+
if (hasNextPage) {
339+
await participantListTable.nextPage();
340+
participantsCount = await participantListTable.rowsCount;
341+
} else {
342+
participantsCount = 0;
343+
}
344+
}
345+
throw new Error(`Failed to find a suitable participant for ${columnGroup}: ${columnName} = "${value}" within max waiting time 90 seconds.`);
346+
}
297347
}

playwright-e2e/dsm/pages/samples/search-page.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { expect, Page } from '@playwright/test';
22
import DatePicker from 'dsm/component/date-picker';
33
import Select from 'dss/component/select';
44
import Table from 'dss/component/table';
5-
import { waitForNoSpinner } from 'utils/test-utils';
5+
import { waitForNoSpinner, waitForResponse } from 'utils/test-utils';
66

77
export enum SearchByField {
88
SHORT_ID = 'Short ID',
@@ -23,6 +23,7 @@ export default class SearchPage {
2323
const locator = this.page.locator('//div[button[normalize-space()="Search Kit"]]');
2424
await locator.locator('//input').fill(value);
2525
await locator.locator('//button').click();
26+
await waitForResponse(this.page, {uri: '/ui/searchKit'});
2627
await waitForNoSpinner(this.page);
2728

2829
const table = new Table(this.page);

playwright-e2e/tests/dsm/atcp/atcp-receive-kit.spec.ts

Lines changed: 11 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect } from '@playwright/test';
2-
import { AdditionalFilter } from 'dsm/component/filters/sections/search/search-enums';
2+
import { test } from 'fixtures/dsm-fixture';
33
import { SamplesNavEnum } from 'dsm/component/navigation/enums/samplesNav-enum';
44
import { StudyEnum } from 'dsm/component/navigation/enums/selectStudyNav-enum';
55
import { StudyNavEnum } from 'dsm/component/navigation/enums/studyNav-enum';
@@ -11,129 +11,47 @@ import ParticipantPage from 'dsm/pages/participant-page/participant-page';
1111
import AtcpSearchPage, { SearchByField } from 'dsm/pages/samples/search-page';
1212
import { WelcomePage } from 'dsm/pages/welcome-page';
1313
import Radiobutton from 'dss/component/radiobutton';
14-
import { test } from 'fixtures/dsm-fixture';
1514
import { getUtcDate } from 'utils/date-utils';
1615
import { generateAlphaNumeric } from 'utils/faker-utils';
17-
import { logError, logGenomeStudySampleKitReceived, logInfo } from 'utils/log-utils';
1816
import { studyShortName, waitForNoSpinner, waitForResponse } from 'utils/test-utils';
17+
import { logInfo } from 'utils/log-utils';
1918

2019
test.describe('Receive Genome Study Kit', () => {
2120
const studies = [StudyEnum.AT];
2221
for (const study of studies) {
2322
let newBarcode = generateAlphaNumeric().toUpperCase();
2423

2524
let shortId: string;
26-
let guid: string;
2725

2826
let participantPage: ParticipantPage;
2927
let participantListPage: ParticipantListPage;
3028
let navigation: Navigation;
3129

32-
// Fallback to use non-e2e participant if all e2e participants have kit received before
33-
const nonE2EParticipants: string[] = [];
34-
3530
test.beforeEach(async ({page, request}) => {
3631
navigation = new Navigation(page, request);
3732
const welcomePage = new WelcomePage(page);
3833
await welcomePage.selectStudy(study);
3934
});
4035

4136
test(`Receive genome sample kit for ${study} @dsm @${study} @functional`, async ({page}) => {
42-
// 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.
43-
// Find a Playwright test user that does not have GENOME_STUDY_SPIT_KIT_BARCODE.
44-
await page.route('**/*', async (route, request): Promise<void> => {
45-
const regex = new RegExp(/applyFilter\?realm=.*&userId=.*&parent=participantList/i);
46-
if (!shortId && request && request.url().match(regex)) {
47-
logInfo(`Intercepting API request ${request.url()} to search for a E2E participant`);
48-
const response = await route.fetch();
49-
const json = JSON.parse(await response.text());
50-
for (const i in json.participants) {
51-
const participant = json.participants[i];
52-
const profile = participant.esData.profile;
53-
const participantData = participant.esData.dsm.participantData;
54-
let hruId = profile.hruid;
55-
expect(hruId).toBeTruthy(); // hruid must exists
56-
try {
57-
let existField = false;
58-
for (const dataId in participantData) {
59-
if ((participantData[dataId].fieldTypeId as string) === 'AT_GROUP_GENOME_STUDY') {
60-
existField = true;
61-
if ((participantData[dataId].data as string).indexOf('GENOME_STUDY_SPIT_KIT_BARCODE') !== -1) {
62-
hruId = null; // discard this participant because person has received genome study kit before
63-
}
64-
break;
65-
}
66-
}
67-
expect(existField).toBe(true); // AT_GROUP_GENOME_STUDY must exists in participantData
68-
if (hruId && profile.firstName) {
69-
if (profile.firstName.includes('E2E')) {
70-
shortId = hruId;
71-
break; // finish searching for a participant who is Playwright automation test created and does not have genome study kit barcode
72-
} else {
73-
// save non-e2e participant short id then check next participant
74-
nonE2EParticipants.push(hruId);
75-
}
76-
}
77-
} catch (err) {
78-
logError(`Failed to read response json.\n${err}`);
79-
logError(JSON.stringify(participant));
80-
}
81-
}
82-
}
83-
return route.continue();
84-
});
85-
8637
await test.step('Search for the right participant on Participant List page', async () => {
8738
participantListPage = await navigation.selectFromStudy<ParticipantListPage>(StudyNavEnum.PARTICIPANT_LIST);
8839
await participantListPage.waitForReady();
8940

90-
// Search for a participant that meets the search criteria
91-
const customizeViewPanel = participantListPage.filters.customizeViewPanel;
92-
await customizeViewPanel.open();
93-
await customizeViewPanel.selectColumns('Participant Columns', ['Registration Date']);
94-
await customizeViewPanel.selectColumns('Genome Study Columns', ['Sample kit barcode for genome study'], { nth: 1 });
95-
await customizeViewPanel.close();
96-
97-
const searchPanel = participantListPage.filters.searchPanel;
98-
await searchPanel.open();
99-
await searchPanel.checkboxes('Status', { checkboxValues: ['Registered', 'Enrolled'] });
100-
await searchPanel.text('Sample kit barcode for genome study', { additionalFilters: [AdditionalFilter.EMPTY] });
101-
await searchPanel.search();
102-
});
103-
104-
await test.step('Verify participant detail on Participant page', async () => {
105-
const searchPanel = participantListPage.filters.searchPanel;
106-
await searchPanel.clear();
107-
108-
if (!shortId) {
109-
// Attempt to find a non-e2e test participant
110-
const [firstParticipant] = nonE2EParticipants;
111-
shortId = firstParticipant;
112-
}
113-
114-
await participantListPage.filterListByShortId(shortId);
115-
logGenomeStudySampleKitReceived(shortId);
41+
const rowIndex = await participantListPage.findParticipantFor('Genome Study Columns', 'Sample kit barcode for genome study', {nth: 1});
11642

117-
const row = 0;
118-
const participantsTable = participantListPage.participantListTable;
119-
const status = await participantsTable.getParticipantDataAt(row, 'Status');
120-
expect(status).toMatch(/Enrolled|Registered/);
121-
const rowShortId = await participantsTable.getParticipantDataAt(row, 'Short ID');
122-
expect(rowShortId).toBe(shortId);
123-
const registrationDate = await participantsTable.getParticipantDataAt(row, 'Registration Date', { exactMatch: false });
124-
125-
// Open the Participant page
126-
participantPage = await participantsTable.openParticipantPageAt(row);
127-
128-
expect(await participantPage.getStatus()).toBe(status);
129-
expect(await participantPage.getShortId()).toBe(shortId);
130-
expect(await participantPage.getRegistrationDate()).toBe(registrationDate);
131-
guid = await participantPage.getGuid();
43+
const participantListTable = participantListPage.participantListTable;
44+
shortId = await participantListTable.getParticipantDataAt(rowIndex, 'Short ID');
45+
participantPage = await participantListTable.openParticipantPageAt(rowIndex);
46+
logInfo(`Participant Short ID: ${shortId}`);
13247
});
13348

13449
await test.step('Set new sample kit barcode', async () => {
13550
newBarcode = `${shortId}-${newBarcode}`;
13651
const genomeStudyTab = await participantPage.clickTab<GenomeStudyTab>(TabEnum.GENOME_STUDY);
52+
const value = await genomeStudyTab.getField('Sample kit barcode for genome study').locator('input').inputValue();
53+
expect(value).toBe(''); // Sample Kit Barcode input should be empty
54+
13755
await Promise.all([
13856
genomeStudyTab.setValue('Sample kit barcode for genome study', newBarcode),
13957
page.waitForResponse(resp => {
@@ -157,6 +75,7 @@ test.describe('Receive Genome Study Kit', () => {
15775
expect(await table.getRowText(row, 'Short ID')).toBe(shortId);
15876

15977
const button = table.findButtonInCell(table.rowLocator(), { label: 'Mark Received' });
78+
await expect(button.toLocator()).toBeVisible();
16079
await Promise.all([
16180
waitForResponse(page, { uri: `ui/receivedKits?realm=${studyShortName(study).realm}&userId=` }),
16281
button.click()

0 commit comments

Comments
 (0)