@ampath/esm-laboratory-app 1.3.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +12 -0
- package/.eslintignore +2 -0
- package/.eslintrc +68 -0
- package/.husky/pre-commit +7 -0
- package/.husky/pre-push +6 -0
- package/.prettierignore +12 -0
- package/.prettierrc +8 -0
- package/.tx/config +11 -0
- package/.yarn/plugins/@yarnpkg/plugin-outdated.cjs +35 -0
- package/README.md +54 -0
- package/__mocks__/react-i18next.js +50 -0
- package/assets/screenshots/labs_enter_results.png +0 -0
- package/assets/screenshots/labs_general_dashboard.png +0 -0
- package/dist/1119.js +1 -0
- package/dist/1197.js +1 -0
- package/dist/1222.js +1 -0
- package/dist/1222.js.map +1 -0
- package/dist/1243.js +1 -0
- package/dist/1243.js.map +1 -0
- package/dist/2146.js +1 -0
- package/dist/2690.js +1 -0
- package/dist/3099.js +1 -0
- package/dist/3106.js +1 -0
- package/dist/3106.js.map +1 -0
- package/dist/312.js +1 -0
- package/dist/312.js.map +1 -0
- package/dist/3352.js +1 -0
- package/dist/3352.js.map +1 -0
- package/dist/3535.js +1 -0
- package/dist/3535.js.map +1 -0
- package/dist/3584.js +1 -0
- package/dist/4044.js +1 -0
- package/dist/4044.js.map +1 -0
- package/dist/4055.js +1 -0
- package/dist/4132.js +1 -0
- package/dist/4300.js +1 -0
- package/dist/4335.js +1 -0
- package/dist/439.js +1 -0
- package/dist/4535.js +1 -0
- package/dist/4535.js.map +1 -0
- package/dist/4618.js +1 -0
- package/dist/4652.js +1 -0
- package/dist/4748.js +2 -0
- package/dist/4748.js.LICENSE.txt +9 -0
- package/dist/4748.js.map +1 -0
- package/dist/4920.js +1 -0
- package/dist/4920.js.map +1 -0
- package/dist/4944.js +1 -0
- package/dist/5048.js +2 -0
- package/dist/5048.js.LICENSE.txt +29 -0
- package/dist/5048.js.map +1 -0
- package/dist/5088.js +1 -0
- package/dist/5088.js.map +1 -0
- package/dist/5173.js +1 -0
- package/dist/5241.js +1 -0
- package/dist/53.js +1 -0
- package/dist/53.js.map +1 -0
- package/dist/5339.js +1 -0
- package/dist/5339.js.map +1 -0
- package/dist/5348.js +1 -0
- package/dist/5348.js.map +1 -0
- package/dist/5380.js +1 -0
- package/dist/5380.js.map +1 -0
- package/dist/5442.js +1 -0
- package/dist/5661.js +1 -0
- package/dist/5780.js +2 -0
- package/dist/5780.js.LICENSE.txt +9 -0
- package/dist/5780.js.map +1 -0
- package/dist/6022.js +1 -0
- package/dist/6468.js +1 -0
- package/dist/6589.js +1 -0
- package/dist/6679.js +1 -0
- package/dist/6753.js +1 -0
- package/dist/6753.js.map +1 -0
- package/dist/6777.js +2 -0
- package/dist/6777.js.LICENSE.txt +19 -0
- package/dist/6777.js.map +1 -0
- package/dist/679.js +2 -0
- package/dist/679.js.LICENSE.txt +9 -0
- package/dist/679.js.map +1 -0
- package/dist/6840.js +1 -0
- package/dist/6859.js +1 -0
- package/dist/7097.js +1 -0
- package/dist/7129.js +1 -0
- package/dist/7129.js.map +1 -0
- package/dist/7159.js +1 -0
- package/dist/723.js +1 -0
- package/dist/7617.js +1 -0
- package/dist/791.js +1 -0
- package/dist/791.js.map +1 -0
- package/dist/795.js +1 -0
- package/dist/8163.js +1 -0
- package/dist/8349.js +1 -0
- package/dist/8371.js +1 -0
- package/dist/841.js +1 -0
- package/dist/841.js.map +1 -0
- package/dist/8618.js +1 -0
- package/dist/8627.js +2 -0
- package/dist/8627.js.LICENSE.txt +25 -0
- package/dist/8627.js.map +1 -0
- package/dist/8898.js +2 -0
- package/dist/8898.js.LICENSE.txt +32 -0
- package/dist/8898.js.map +1 -0
- package/dist/890.js +1 -0
- package/dist/9214.js +1 -0
- package/dist/9321.js +1 -0
- package/dist/9321.js.map +1 -0
- package/dist/9452.js +1 -0
- package/dist/9452.js.map +1 -0
- package/dist/9538.js +1 -0
- package/dist/9569.js +1 -0
- package/dist/9695.js +1 -0
- package/dist/9695.js.map +1 -0
- package/dist/986.js +1 -0
- package/dist/9879.js +1 -0
- package/dist/9895.js +1 -0
- package/dist/9900.js +1 -0
- package/dist/9910.js +1 -0
- package/dist/9910.js.map +1 -0
- package/dist/9913.js +1 -0
- package/dist/main.js +2 -0
- package/dist/main.js.LICENSE.txt +45 -0
- package/dist/main.js.map +1 -0
- package/dist/openmrs-esm-laboratory-app.js +1 -0
- package/dist/openmrs-esm-laboratory-app.js.buildmanifest.json +1744 -0
- package/dist/openmrs-esm-laboratory-app.js.map +1 -0
- package/dist/routes.json +1 -0
- package/e2e/README.md +117 -0
- package/e2e/commands/encounter-operations.ts +63 -0
- package/e2e/commands/index.ts +5 -0
- package/e2e/commands/patient-operations.ts +109 -0
- package/e2e/commands/provider-operations.ts +9 -0
- package/e2e/commands/test-order-operations.ts +46 -0
- package/e2e/commands/types/index.ts +157 -0
- package/e2e/commands/visit-operations.ts +38 -0
- package/e2e/core/global-setup.ts +32 -0
- package/e2e/core/index.ts +1 -0
- package/e2e/core/test.ts +31 -0
- package/e2e/fixtures/api.ts +27 -0
- package/e2e/fixtures/fhirApi.ts +28 -0
- package/e2e/fixtures/index.ts +2 -0
- package/e2e/pages/index.ts +1 -0
- package/e2e/pages/laboratory-page.ts +28 -0
- package/e2e/specs/add-lab-results.spec.ts +111 -0
- package/e2e/specs/reject-lab-request.spec.ts +88 -0
- package/e2e/specs/test-orders.spec.ts +69 -0
- package/e2e/support/github/Dockerfile +34 -0
- package/e2e/support/github/docker-compose.yml +24 -0
- package/e2e/support/github/run-e2e-docker-env.sh +58 -0
- package/example.env +7 -0
- package/jest.config.js +35 -0
- package/package.json +105 -0
- package/playwright.config.ts +42 -0
- package/src/components/create-dashboard-link.component.tsx +37 -0
- package/src/components/loader/loader.component.tsx +11 -0
- package/src/components/loader/loader.scss +9 -0
- package/src/components/orders-table/list-order-details.component.tsx +143 -0
- package/src/components/orders-table/list-order-details.scss +136 -0
- package/src/components/orders-table/order-detail.scss +18 -0
- package/src/components/orders-table/orders-data-table.component.tsx +349 -0
- package/src/components/orders-table/orders-data-table.scss +129 -0
- package/src/components/orders-table/orders-data-table.test.tsx +214 -0
- package/src/components/orders-table/orders-date-range-picker.component.tsx +32 -0
- package/src/components/orders-table/orders-date-range-picker.scss +7 -0
- package/src/components/summary-tile/lab-summary-tile.component.tsx +31 -0
- package/src/components/summary-tile/lab-summary-tile.scss +64 -0
- package/src/config-schema.ts +39 -0
- package/src/constants.ts +2 -0
- package/src/declarations.d.ts +2 -0
- package/src/index.ts +123 -0
- package/src/lab-tabs/actions/actions.scss +26 -0
- package/src/lab-tabs/actions/add-lab-request-results-action.component.tsx +46 -0
- package/src/lab-tabs/actions/amend-lab-results-action.component.tsx +40 -0
- package/src/lab-tabs/actions/approve-lab-results-action.component.tsx +36 -0
- package/src/lab-tabs/actions/pickup-lab-request-action.component.tsx +36 -0
- package/src/lab-tabs/actions/reject-lab-request-action.component.tsx +36 -0
- package/src/lab-tabs/data-table-extensions/completed-lab-requests-table.extension.tsx +8 -0
- package/src/lab-tabs/data-table-extensions/declined-lab-requests-table-extension.tsx +8 -0
- package/src/lab-tabs/data-table-extensions/in-progress-lab-requests-table.extension.tsx +8 -0
- package/src/lab-tabs/data-table-extensions/pending-review-lab-request-table.extension.tsx +8 -0
- package/src/lab-tabs/data-table-extensions/tests-ordered-table.extension.tsx +8 -0
- package/src/lab-tabs/laboratory-tabs.component.tsx +81 -0
- package/src/lab-tabs/laboratory-tabs.scss +38 -0
- package/src/lab-tabs/modals/approval-lab-results-modal.component.tsx +70 -0
- package/src/lab-tabs/modals/pickup-lab-request-modal.component.tsx +67 -0
- package/src/lab-tabs/modals/pickup-lab-request-modal.test.tsx +127 -0
- package/src/lab-tabs/modals/reject-lab-request-modal.component.tsx +86 -0
- package/src/lab-tabs/modals/reject-lab-request-modal.scss +13 -0
- package/src/lab-tabs/modals/reject-lab-request-modal.test.tsx +152 -0
- package/src/lab-tiles/all-lab-requests-tile.component.tsx +19 -0
- package/src/lab-tiles/completed-lab-requests-tile.component.tsx +19 -0
- package/src/lab-tiles/in-progress-lab-requests-tile.component.tsx +19 -0
- package/src/lab-tiles/laboratory-summary-tiles.component.tsx +52 -0
- package/src/lab-tiles/laboratory-summary-tiles.scss +16 -0
- package/src/lab-tiles/pending-review-lab-results-tile.component.tsx +22 -0
- package/src/laboratory-dashboard.component.tsx +30 -0
- package/src/laboratory-dashboard.scss +5 -0
- package/src/laboratory.resource.ts +108 -0
- package/src/root.component.tsx +15 -0
- package/src/routes.json +204 -0
- package/src/types.ts +39 -0
- package/tools/i18next-parser.config.js +93 -0
- package/tools/index.ts +1 -0
- package/tools/setup-tests.ts +8 -0
- package/tools/test-utils.ts +44 -0
- package/tools/update-openmrs-deps.mjs +42 -0
- package/translations/am.json +79 -0
- package/translations/ar.json +79 -0
- package/translations/ar_SY.json +79 -0
- package/translations/bn.json +79 -0
- package/translations/cs.json +79 -0
- package/translations/de.json +79 -0
- package/translations/en.json +79 -0
- package/translations/en_US.json +79 -0
- package/translations/es.json +79 -0
- package/translations/es_MX.json +79 -0
- package/translations/fr.json +79 -0
- package/translations/he.json +79 -0
- package/translations/hi.json +79 -0
- package/translations/hi_IN.json +79 -0
- package/translations/id.json +79 -0
- package/translations/it.json +79 -0
- package/translations/ka.json +79 -0
- package/translations/km.json +79 -0
- package/translations/ku.json +79 -0
- package/translations/ky.json +79 -0
- package/translations/lg.json +79 -0
- package/translations/ne.json +79 -0
- package/translations/pl.json +79 -0
- package/translations/pt.json +79 -0
- package/translations/pt_BR.json +79 -0
- package/translations/qu.json +79 -0
- package/translations/ro_RO.json +79 -0
- package/translations/ru_RU.json +79 -0
- package/translations/si.json +79 -0
- package/translations/sq.json +79 -0
- package/translations/sw.json +79 -0
- package/translations/sw_KE.json +79 -0
- package/translations/tr.json +79 -0
- package/translations/tr_TR.json +79 -0
- package/translations/uk.json +79 -0
- package/translations/uz.json +79 -0
- package/translations/uz@Latn.json +79 -0
- package/translations/uz_UZ.json +79 -0
- package/translations/vi.json +79 -0
- package/translations/zh.json +79 -0
- package/translations/zh_CN.json +79 -0
- package/translations/zh_TW.json +79 -0
- package/tsconfig.json +28 -0
- package/turbo.json +15 -0
- package/webpack.config.js +25 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
|
+
import { type APIRequestContext, type PlaywrightWorkerArgs, type WorkerFixture } from '@playwright/test';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A fixture which initializes an [`APIRequestContext`](https://playwright.dev/docs/api/class-apirequestcontext)
|
|
6
|
+
* that is bound to the configured OpenMRS API server. The context is automatically authenticated
|
|
7
|
+
* using the configured admin account.
|
|
8
|
+
*
|
|
9
|
+
* Use the request context like this:
|
|
10
|
+
* ```ts
|
|
11
|
+
* test('your test', async ({ api }) => {
|
|
12
|
+
* const res = await api.get('patient/1234');
|
|
13
|
+
* await expect(res.ok()).toBeTruthy();
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export const api: WorkerFixture<APIRequestContext, PlaywrightWorkerArgs> = async ({ playwright }, use) => {
|
|
18
|
+
const ctx = await playwright.request.newContext({
|
|
19
|
+
baseURL: `${process.env.E2E_BASE_URL}/ws/rest/v1/`,
|
|
20
|
+
httpCredentials: {
|
|
21
|
+
username: process.env.E2E_USER_ADMIN_USERNAME,
|
|
22
|
+
password: process.env.E2E_USER_ADMIN_PASSWORD,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
await use(ctx);
|
|
27
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type APIRequestContext, type PlaywrightWorkerArgs, type WorkerFixture } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A fixture which initializes an [`APIRequestContext`](https://playwright.dev/docs/api/class-apirequestcontext)
|
|
5
|
+
* that is bound to the configured OpenMRS API server. The context is automatically authenticated
|
|
6
|
+
* using the configured admin account.
|
|
7
|
+
*
|
|
8
|
+
* Use the request context like this:
|
|
9
|
+
* ```ts
|
|
10
|
+
* test('your test', async ({ api }) => {
|
|
11
|
+
* const res = await api.get('patient/1234');
|
|
12
|
+
* await expect(res.ok()).toBeTruthy();
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export const fhirApi: WorkerFixture<APIRequestContext, PlaywrightWorkerArgs> = async ({ playwright }, use) => {
|
|
18
|
+
const fhirctx = await playwright.request.newContext({
|
|
19
|
+
baseURL: `${process.env.E2E_BASE_URL}/ws/fhir2/R4/`,
|
|
20
|
+
httpCredentials: {
|
|
21
|
+
username: process.env.E2E_USER_ADMIN_USERNAME,
|
|
22
|
+
password: process.env.E2E_USER_ADMIN_PASSWORD,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
27
|
+
await use(fhirctx);
|
|
28
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './laboratory-page';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Page } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
export class LaboratoryPage {
|
|
4
|
+
constructor(readonly page: Page) {}
|
|
5
|
+
|
|
6
|
+
async goTo() {
|
|
7
|
+
await this.page.goto('/openmrs/spa/home/laboratory');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async navigateToTab(tabName: string) {
|
|
11
|
+
await this.page.getByRole('tab', { name: tabName }).click();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async expandPatientRow(patientName: string) {
|
|
15
|
+
await this.page
|
|
16
|
+
.getByRole('row', { name: new RegExp(`Expand current row ${patientName}`) })
|
|
17
|
+
.getByLabel('Expand current row')
|
|
18
|
+
.click();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async searchFor(text: string) {
|
|
22
|
+
await this.page.getByPlaceholder('Search this list').fill(text);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getPatientRow(patientName: string) {
|
|
26
|
+
return this.page.getByRole('row', { name: new RegExp(patientName) });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { expect } from '@playwright/test';
|
|
2
|
+
import { type Order, type Visit } from '@openmrs/esm-framework';
|
|
3
|
+
import {
|
|
4
|
+
generateRandomTestOrder,
|
|
5
|
+
deleteTestOrder,
|
|
6
|
+
createEncounter,
|
|
7
|
+
deleteEncounter,
|
|
8
|
+
getProvider,
|
|
9
|
+
startVisit,
|
|
10
|
+
endVisit,
|
|
11
|
+
} from '../commands';
|
|
12
|
+
import { test } from '../core';
|
|
13
|
+
import { type Encounter, type Provider } from '../commands/types';
|
|
14
|
+
import { LaboratoryPage } from '../pages';
|
|
15
|
+
|
|
16
|
+
let testOrder: Order;
|
|
17
|
+
let encounter: Encounter;
|
|
18
|
+
let orderer: Provider;
|
|
19
|
+
let fullName: string;
|
|
20
|
+
let visit: Visit;
|
|
21
|
+
|
|
22
|
+
test.beforeEach(async ({ api, patient }) => {
|
|
23
|
+
orderer = await getProvider(api);
|
|
24
|
+
visit = await startVisit(api, patient.uuid);
|
|
25
|
+
encounter = await createEncounter(api, patient.uuid, orderer.uuid, visit);
|
|
26
|
+
testOrder = await generateRandomTestOrder(api, patient.uuid, encounter, orderer.uuid);
|
|
27
|
+
fullName = patient.person?.display;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test.describe('Laboratory order workflow', () => {
|
|
31
|
+
test('Add lab results via the lab app', async ({ page }) => {
|
|
32
|
+
const laboratoryPage = new LaboratoryPage(page);
|
|
33
|
+
|
|
34
|
+
await test.step('Given I navigate to the laboratory page', async () => {
|
|
35
|
+
await laboratoryPage.goTo();
|
|
36
|
+
await expect(page).toHaveURL(process.env.E2E_BASE_URL + `/spa/home/laboratory`);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
await test.step('When I expand the patient row on the Tests ordered tab', async () => {
|
|
40
|
+
await expect(page.getByRole('tab', { name: 'Tests ordered' })).toBeVisible();
|
|
41
|
+
await laboratoryPage.expandPatientRow(fullName);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await test.step('Then I should see the order with status "not picked"', async () => {
|
|
45
|
+
await expect(page.getByText(/Status:Order not picked/i)).toBeVisible();
|
|
46
|
+
await expect(page.getByRole('cell', { name: 'serum glucose' })).toBeVisible();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await test.step('When I click Pick Lab Request and confirm', async () => {
|
|
50
|
+
await page.getByRole('button', { name: 'Pick Lab Request' }).first().click();
|
|
51
|
+
await page.getByRole('button', { name: 'Pick up lab request' }).click();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await test.step('Then I should see a success notification', async () => {
|
|
55
|
+
await expect(page.getByText(/You have successfully picked an order/i)).toBeVisible();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await test.step('When I navigate to the In progress tab', async () => {
|
|
59
|
+
await laboratoryPage.navigateToTab('In progress');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
await test.step('And I expand the patient row', async () => {
|
|
63
|
+
await laboratoryPage.expandPatientRow(fullName);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
await test.step('Then I should see the order with In progress status', async () => {
|
|
67
|
+
await expect(page.getByLabel('Structured list section').getByText('In progress')).toBeVisible();
|
|
68
|
+
await expect(page.getByRole('cell', { name: 'serum glucose' })).toBeVisible();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
await test.step('When I click Add lab results and enter a value', async () => {
|
|
72
|
+
await page.getByRole('button', { name: 'Add lab results' }).click();
|
|
73
|
+
await page.getByRole('spinbutton', { name: 'serum glucose (>= 0' }).fill('35');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await test.step('And I save the results', async () => {
|
|
77
|
+
await page.getByRole('button', { name: 'Save and close' }).click();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await test.step('Then I should see a success notification', async () => {
|
|
81
|
+
await expect(page.getByText(/Lab results for .* have been successfully updated/i)).toBeVisible();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await test.step('When I navigate to the Completed tab', async () => {
|
|
85
|
+
await laboratoryPage.navigateToTab('Completed');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await test.step('And I expand the patient row', async () => {
|
|
89
|
+
await laboratoryPage.expandPatientRow(fullName);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
await test.step('Then I should see the order with Completed status', async () => {
|
|
93
|
+
await expect(page.getByLabel('Structured list section').getByText('Completed')).toBeVisible();
|
|
94
|
+
await expect(
|
|
95
|
+
page.getByLabel('Structured list section').getByRole('cell', { name: 'serum glucose' }),
|
|
96
|
+
).toBeVisible();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test.afterEach(async ({ api }) => {
|
|
102
|
+
if (visit) {
|
|
103
|
+
await endVisit(api, visit);
|
|
104
|
+
}
|
|
105
|
+
if (encounter?.uuid) {
|
|
106
|
+
await deleteEncounter(api, encounter.uuid);
|
|
107
|
+
}
|
|
108
|
+
if (testOrder?.uuid) {
|
|
109
|
+
await deleteTestOrder(api, testOrder.uuid);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { expect } from '@playwright/test';
|
|
2
|
+
import { type Order, type Visit } from '@openmrs/esm-framework';
|
|
3
|
+
import {
|
|
4
|
+
generateRandomTestOrder,
|
|
5
|
+
deleteTestOrder,
|
|
6
|
+
createEncounter,
|
|
7
|
+
deleteEncounter,
|
|
8
|
+
getProvider,
|
|
9
|
+
startVisit,
|
|
10
|
+
endVisit,
|
|
11
|
+
} from '../commands';
|
|
12
|
+
import { test } from '../core';
|
|
13
|
+
import { type Encounter, type Provider } from '../commands/types';
|
|
14
|
+
import { LaboratoryPage } from '../pages';
|
|
15
|
+
|
|
16
|
+
let testOrder: Order;
|
|
17
|
+
let encounter: Encounter;
|
|
18
|
+
let orderer: Provider;
|
|
19
|
+
let fullName: string;
|
|
20
|
+
let visit: Visit;
|
|
21
|
+
|
|
22
|
+
test.beforeEach(async ({ api, patient }) => {
|
|
23
|
+
orderer = await getProvider(api);
|
|
24
|
+
visit = await startVisit(api, patient.uuid);
|
|
25
|
+
encounter = await createEncounter(api, patient.uuid, orderer.uuid, visit);
|
|
26
|
+
testOrder = await generateRandomTestOrder(api, patient.uuid, encounter, orderer.uuid);
|
|
27
|
+
fullName = patient.person?.display;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('Reject a lab request', async ({ page }) => {
|
|
31
|
+
const laboratoryPage = new LaboratoryPage(page);
|
|
32
|
+
|
|
33
|
+
await test.step('Given I navigate to the laboratory page', async () => {
|
|
34
|
+
await laboratoryPage.goTo();
|
|
35
|
+
await expect(page.getByRole('tab', { name: 'Tests ordered' })).toBeVisible();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await test.step('When I expand the patient row', async () => {
|
|
39
|
+
await laboratoryPage.expandPatientRow(fullName);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await test.step('Then I should see the test order', async () => {
|
|
43
|
+
await expect(page.getByRole('cell', { name: 'serum glucose' })).toBeVisible();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
await test.step('When I click the Reject Lab Request button', async () => {
|
|
47
|
+
await page.getByRole('button', { name: 'Reject Lab Request' }).first().click();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await test.step('Then I should see the rejection modal with the test type', async () => {
|
|
51
|
+
await expect(page.getByRole('heading', { name: /Reject lab request/ })).toBeVisible();
|
|
52
|
+
await expect(page.getByText(/Test type:/i)).toBeVisible();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await test.step('When I enter a rejection comment and confirm', async () => {
|
|
56
|
+
await page.getByRole('textbox', { name: 'Fulfiller comment' }).fill('Sample was contaminated');
|
|
57
|
+
await page.getByRole('button', { name: 'danger Reject', exact: true }).click();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
await test.step('Then I should see a success notification', async () => {
|
|
61
|
+
await expect(page.getByText(/Lab request rejected/i)).toBeVisible();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await test.step('When I navigate to the Declined tests tab', async () => {
|
|
65
|
+
await laboratoryPage.navigateToTab('Declined tests');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await test.step('And I expand the patient row', async () => {
|
|
69
|
+
await laboratoryPage.expandPatientRow(fullName);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await test.step('Then I should see the order with Declined status', async () => {
|
|
73
|
+
await expect(page.getByRole('cell', { name: 'serum glucose' })).toBeVisible();
|
|
74
|
+
await expect(page.getByRole('cell', { name: 'Declined' })).toBeVisible();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test.afterEach(async ({ api }) => {
|
|
79
|
+
if (visit) {
|
|
80
|
+
await endVisit(api, visit);
|
|
81
|
+
}
|
|
82
|
+
if (encounter?.uuid) {
|
|
83
|
+
await deleteEncounter(api, encounter.uuid);
|
|
84
|
+
}
|
|
85
|
+
if (testOrder?.uuid) {
|
|
86
|
+
await deleteTestOrder(api, testOrder.uuid);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { expect } from '@playwright/test';
|
|
2
|
+
import { type Order, type Visit } from '@openmrs/esm-framework';
|
|
3
|
+
import {
|
|
4
|
+
generateRandomTestOrder,
|
|
5
|
+
deleteTestOrder,
|
|
6
|
+
createEncounter,
|
|
7
|
+
deleteEncounter,
|
|
8
|
+
getProvider,
|
|
9
|
+
startVisit,
|
|
10
|
+
endVisit,
|
|
11
|
+
} from '../commands';
|
|
12
|
+
import { test } from '../core';
|
|
13
|
+
import { type Encounter, type Provider } from '../commands/types';
|
|
14
|
+
import { LaboratoryPage } from '../pages';
|
|
15
|
+
|
|
16
|
+
const url = process.env.E2E_BASE_URL;
|
|
17
|
+
|
|
18
|
+
let testOrder: Order;
|
|
19
|
+
let encounter: Encounter;
|
|
20
|
+
let orderer: Provider;
|
|
21
|
+
let fullName: string;
|
|
22
|
+
let visit: Visit;
|
|
23
|
+
|
|
24
|
+
test.beforeEach(async ({ api, patient }) => {
|
|
25
|
+
orderer = await getProvider(api);
|
|
26
|
+
visit = await startVisit(api, patient.uuid);
|
|
27
|
+
encounter = await createEncounter(api, patient.uuid, orderer.uuid, visit);
|
|
28
|
+
testOrder = await generateRandomTestOrder(api, patient.uuid, encounter, orderer.uuid);
|
|
29
|
+
fullName = patient.person?.display;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('View test orders', async ({ page }) => {
|
|
33
|
+
const laboratoryPage = new LaboratoryPage(page);
|
|
34
|
+
|
|
35
|
+
await test.step('Given I navigate to the laboratory page', async () => {
|
|
36
|
+
await laboratoryPage.goTo();
|
|
37
|
+
await expect(page).toHaveURL(url + `/spa/home/laboratory`);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await test.step('Then I should see the Tests ordered tab', async () => {
|
|
41
|
+
await expect(page.getByRole('tab', { name: 'Tests ordered' })).toBeVisible();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await test.step('And I should see the patient in the orders list', async () => {
|
|
45
|
+
await expect(laboratoryPage.getPatientRow(fullName)).toBeVisible();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
await test.step('When I expand the patient row', async () => {
|
|
49
|
+
await laboratoryPage.expandPatientRow(fullName);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
await test.step('Then I should see the order status, test name, and urgency', async () => {
|
|
53
|
+
await expect(page.getByText(/Status:Order not picked/i)).toBeVisible();
|
|
54
|
+
await expect(page.getByRole('cell', { name: 'serum glucose' })).toBeVisible();
|
|
55
|
+
await expect(page.getByText(/Routine/i)).toBeVisible();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test.afterEach(async ({ api }) => {
|
|
60
|
+
if (visit) {
|
|
61
|
+
await endVisit(api, visit);
|
|
62
|
+
}
|
|
63
|
+
if (encounter?.uuid) {
|
|
64
|
+
await deleteEncounter(api, encounter.uuid);
|
|
65
|
+
}
|
|
66
|
+
if (testOrder?.uuid) {
|
|
67
|
+
await deleteTestOrder(api, testOrder.uuid);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1.3
|
|
2
|
+
FROM --platform=$BUILDPLATFORM node:18-alpine as dev
|
|
3
|
+
|
|
4
|
+
ARG APP_SHELL_VERSION=next
|
|
5
|
+
|
|
6
|
+
RUN mkdir -p /app
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
|
|
9
|
+
COPY . .
|
|
10
|
+
|
|
11
|
+
RUN npm_config_legacy_peer_deps=true npm install -g openmrs@${APP_SHELL_VERSION:-next}
|
|
12
|
+
ARG CACHE_BUST
|
|
13
|
+
RUN npm_config_legacy_peer_deps=true openmrs assemble --manifest --mode config --config spa-assemble-config.json --target ./spa
|
|
14
|
+
|
|
15
|
+
FROM --platform=$BUILDPLATFORM openmrs/openmrs-reference-application-3-frontend:nightly as frontend
|
|
16
|
+
FROM nginx:1.23-alpine
|
|
17
|
+
|
|
18
|
+
RUN apk update && \
|
|
19
|
+
apk upgrade && \
|
|
20
|
+
# add more utils for sponge to support our startup script
|
|
21
|
+
apk add --no-cache moreutils
|
|
22
|
+
|
|
23
|
+
# clear any default files installed by nginx
|
|
24
|
+
RUN rm -rf /usr/share/nginx/html/*
|
|
25
|
+
|
|
26
|
+
COPY --from=frontend /etc/nginx/nginx.conf /etc/nginx/nginx.conf
|
|
27
|
+
# this assumes that NOTHING in the framework is in a subdirectory
|
|
28
|
+
COPY --from=frontend /usr/share/nginx/html/* /usr/share/nginx/html/
|
|
29
|
+
COPY --from=frontend /usr/local/bin/startup.sh /usr/local/bin/startup.sh
|
|
30
|
+
RUN chmod +x /usr/local/bin/startup.sh
|
|
31
|
+
|
|
32
|
+
COPY --from=dev /app/spa/ /usr/share/nginx/html/
|
|
33
|
+
|
|
34
|
+
CMD ["/usr/local/bin/startup.sh"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# This docker compose file is used to create a backend environment for the e2e.yml workflow.
|
|
2
|
+
# The images are pre-filled with data so that the backend environment can be started within a short time.
|
|
3
|
+
version: "3.7"
|
|
4
|
+
|
|
5
|
+
services:
|
|
6
|
+
gateway:
|
|
7
|
+
image: openmrs/openmrs-reference-application-3-gateway:${TAG:-nightly}
|
|
8
|
+
ports:
|
|
9
|
+
- "8080:80"
|
|
10
|
+
|
|
11
|
+
frontend:
|
|
12
|
+
build:
|
|
13
|
+
context: .
|
|
14
|
+
environment:
|
|
15
|
+
SPA_PATH: /openmrs/spa
|
|
16
|
+
API_URL: /openmrs
|
|
17
|
+
|
|
18
|
+
backend:
|
|
19
|
+
image: openmrs/openmrs-reference-application-3-backend:nightly-with-data
|
|
20
|
+
depends_on:
|
|
21
|
+
- db
|
|
22
|
+
|
|
23
|
+
db:
|
|
24
|
+
image: openmrs/openmrs-reference-application-3-db:nightly-with-data
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env bash -eu
|
|
2
|
+
|
|
3
|
+
# get the dir containing the script
|
|
4
|
+
script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
|
5
|
+
# create a temporary working directory
|
|
6
|
+
working_dir=$(mktemp -d "${TMPDIR:-/tmp/}openmrs-e2e-frontends.XXXXXXXXXX")
|
|
7
|
+
# get a list of all the apps in this workspace
|
|
8
|
+
apps=$(yarn workspaces list --json | jq -r 'select(.name | test("-app")) | .name')
|
|
9
|
+
# this array will hold all of the packed app names
|
|
10
|
+
app_names=()
|
|
11
|
+
|
|
12
|
+
echo "Creating packed archives of apps..."
|
|
13
|
+
# for each app
|
|
14
|
+
for app in $apps
|
|
15
|
+
do
|
|
16
|
+
# @openmrs/esm-whatever -> _openmrs_esm_whatever
|
|
17
|
+
app_name=$(echo "$app" | tr '[:punct:]' '_');
|
|
18
|
+
# add to our array
|
|
19
|
+
app_names+=("$app_name.tgz");
|
|
20
|
+
# run yarn pack for our app and add it to the working directory
|
|
21
|
+
# yarn workspace "$app" pack -o "$working_dir/$app_name.tgz" >/dev/null;
|
|
22
|
+
yarn pack -o "$working_dir/$app_name.tgz" >/dev/null
|
|
23
|
+
done;
|
|
24
|
+
echo "Created packed app archives"
|
|
25
|
+
|
|
26
|
+
echo "Creating dynamic spa-assemble-config.json..."
|
|
27
|
+
# dynamically assemble our list of frontend modules, prepending the login app and
|
|
28
|
+
# primary navigation apps; apps will all be in the /app directory of the Docker
|
|
29
|
+
# container
|
|
30
|
+
jq -n \
|
|
31
|
+
--arg apps "$apps" \
|
|
32
|
+
--arg app_names "$(echo ${app_names[@]})" \
|
|
33
|
+
'{
|
|
34
|
+
"@openmrs/esm-primary-navigation-app": "next",
|
|
35
|
+
"@openmrs/esm-home-app": "next",
|
|
36
|
+
"@openmrs/esm-patient-chart-app": "next",
|
|
37
|
+
"@openmrs/esm-patient-banner-app": "next",
|
|
38
|
+
"@openmrs/esm-patient-orders-app": "next",
|
|
39
|
+
"@openmrs/esm-patient-tests-app": "next"
|
|
40
|
+
} + (
|
|
41
|
+
($apps | split("\n")) as $apps | ($app_names | split(" ") | map("/app/" + .)) as $app_files
|
|
42
|
+
| [$apps, $app_files]
|
|
43
|
+
| transpose
|
|
44
|
+
| map({"key": .[0], "value": .[1]})
|
|
45
|
+
| from_entries
|
|
46
|
+
)' | jq '{"frontendModules": .}' > "$working_dir/spa-assemble-config.json"
|
|
47
|
+
echo "Created dynamic spa-assemble-config.json"
|
|
48
|
+
|
|
49
|
+
echo "Copying Docker configuration..."
|
|
50
|
+
cp "$script_dir/Dockerfile" "$working_dir/Dockerfile"
|
|
51
|
+
cp "$script_dir/docker-compose.yml" "$working_dir/docker-compose.yml"
|
|
52
|
+
|
|
53
|
+
cd $working_dir
|
|
54
|
+
echo "Starting Docker containers..."
|
|
55
|
+
# CACHE_BUST to ensure the assemble step is always run
|
|
56
|
+
docker compose build --build-arg CACHE_BUST=$(date +%s) frontend
|
|
57
|
+
docker compose up -d
|
|
58
|
+
|
package/example.env
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# This is an example environment file for configuring dynamic values.
|
|
2
|
+
E2E_BASE_URL=http://localhost:8080/openmrs
|
|
3
|
+
E2E_USER_ADMIN_USERNAME=admin
|
|
4
|
+
E2E_USER_ADMIN_PASSWORD=Admin123
|
|
5
|
+
E2E_LOGIN_DEFAULT_LOCATION_UUID=44c3efb0-2583-4c80-a79e-1f756a03c0a1
|
|
6
|
+
# The above location UUID is for the "Outpatient Clinic" location in the reference application
|
|
7
|
+
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** @type {import('jest').Config} */
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
clearMocks: true,
|
|
7
|
+
transform: {
|
|
8
|
+
'^.+\\.[jt]sx?$': ['@swc/jest'],
|
|
9
|
+
},
|
|
10
|
+
transformIgnorePatterns: ['/node_modules/(?!@openmrs|.+\\.pnp\\.[^\\/]+$)'],
|
|
11
|
+
moduleNameMapper: {
|
|
12
|
+
'^dexie$': require.resolve('dexie'),
|
|
13
|
+
'@openmrs/esm-framework': '@openmrs/esm-framework/mock',
|
|
14
|
+
'\\.(s?css)$': 'identity-obj-proxy',
|
|
15
|
+
'^lodash-es/(.*)$': 'lodash/$1',
|
|
16
|
+
'^lodash-es$': 'lodash',
|
|
17
|
+
'^@tools$': path.resolve(__dirname, 'tools'),
|
|
18
|
+
'^@tools/(.*)$': path.resolve(__dirname, 'tools', '$1'),
|
|
19
|
+
'^@mocks/(.*)$': path.resolve(__dirname, '__mocks__', '$1'),
|
|
20
|
+
'^uuid$': path.resolve(__dirname, 'node_modules', 'uuid', 'dist', 'index.js'),
|
|
21
|
+
},
|
|
22
|
+
collectCoverageFrom: [
|
|
23
|
+
'!**/node_modules/**',
|
|
24
|
+
'!**/e2e/**',
|
|
25
|
+
],
|
|
26
|
+
testPathIgnorePatterns: [
|
|
27
|
+
"/node_modules/",
|
|
28
|
+
"/e2e/" // Ignore the e2e directory containing Playwright tests
|
|
29
|
+
],
|
|
30
|
+
setupFilesAfterEnv: ['<rootDir>/tools/setup-tests.ts'],
|
|
31
|
+
testEnvironment: 'jsdom',
|
|
32
|
+
testEnvironmentOptions: {
|
|
33
|
+
url: 'http://localhost/',
|
|
34
|
+
},
|
|
35
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ampath/esm-laboratory-app",
|
|
3
|
+
"version": "1.3.0-next.2",
|
|
4
|
+
"license": "MPL-2.0",
|
|
5
|
+
"description": "An O3 frontend module for managing laboratory requests and queues",
|
|
6
|
+
"browser": "dist/openmrs-esm-laboratory-app.js",
|
|
7
|
+
"main": "src/index.ts",
|
|
8
|
+
"source": true,
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "openmrs develop",
|
|
11
|
+
"serve": "webpack serve --mode=development",
|
|
12
|
+
"build": "webpack --mode production",
|
|
13
|
+
"analyze": "webpack --mode=production --env analyze=true",
|
|
14
|
+
"lint": "eslint src --ext ts,tsx",
|
|
15
|
+
"prettier": "prettier --write \"src/**/*.{css,scss,ts,tsx}\" --list-different",
|
|
16
|
+
"typescript": "tsc",
|
|
17
|
+
"test": "jest --config jest.config.js --passWithNoTests --color",
|
|
18
|
+
"verify": "turbo lint typescript test --color",
|
|
19
|
+
"extract-translations": "i18next 'src/**/*.component.tsx' 'src/index.ts' --config ./tools/i18next-parser.config.js",
|
|
20
|
+
"coverage": "yarn test -- --coverage",
|
|
21
|
+
"postinstall": "husky install",
|
|
22
|
+
"test-e2e": "playwright test"
|
|
23
|
+
},
|
|
24
|
+
"browserslist": [
|
|
25
|
+
"extends browserslist-config-openmrs"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"openmrs",
|
|
29
|
+
"microfrontends",
|
|
30
|
+
"laboratory"
|
|
31
|
+
],
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/openmrs/openmrs-esm-laboratory.git"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/openmrs/openmrs-esm-laboratory#readme",
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/openmrs/openmrs-esm-laboratory/issues"
|
|
42
|
+
},
|
|
43
|
+
"lint-staged": {
|
|
44
|
+
"*.{ts,tsx}": "eslint --cache --fix --max-warnings 0",
|
|
45
|
+
"*.{css,scss,ts,tsx}": "prettier --write --list-different"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@carbon/react": "^1.83.0",
|
|
49
|
+
"lodash-es": "^4.17.21",
|
|
50
|
+
"react-hook-form": "^7.52.1"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@openmrs/esm-framework": "9.x",
|
|
54
|
+
"dayjs": "1.x",
|
|
55
|
+
"react": "18.x",
|
|
56
|
+
"react-i18next": "16.x",
|
|
57
|
+
"react-router-dom": "6.x"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@openmrs/esm-framework": "next",
|
|
61
|
+
"@playwright/test": "^1.52.0",
|
|
62
|
+
"@swc/cli": "^0.1.62",
|
|
63
|
+
"@swc/core": "^1.3.62",
|
|
64
|
+
"@swc/jest": "^0.2.26",
|
|
65
|
+
"@testing-library/dom": "^8.20.0",
|
|
66
|
+
"@testing-library/jest-dom": "^5.16.5",
|
|
67
|
+
"@testing-library/react": "^16.3.2",
|
|
68
|
+
"@testing-library/user-event": "^14.4.3",
|
|
69
|
+
"@types/dotenv": "^8.2.3",
|
|
70
|
+
"@types/jest": "^28.1.8",
|
|
71
|
+
"@types/react": "^18.3.21",
|
|
72
|
+
"@types/react-dom": "^18.3.0",
|
|
73
|
+
"@types/webpack-env": "^1.18.1",
|
|
74
|
+
"@typescript-eslint/eslint-plugin": "^8.45.0",
|
|
75
|
+
"@typescript-eslint/parser": "^8.45.0",
|
|
76
|
+
"css-loader": "^6.8.1",
|
|
77
|
+
"dayjs": "^1.11.11",
|
|
78
|
+
"eslint": "^8.57.0",
|
|
79
|
+
"eslint-plugin-import": "^2.31.0",
|
|
80
|
+
"eslint-plugin-react-hooks": "^5.0.0",
|
|
81
|
+
"file-saver": "^2.0.5",
|
|
82
|
+
"husky": "^8.0.0",
|
|
83
|
+
"i18next-parser": "^9.3.0",
|
|
84
|
+
"identity-obj-proxy": "^3.0.0",
|
|
85
|
+
"jest": "^28.1.3",
|
|
86
|
+
"jest-cli": "^28.1.3",
|
|
87
|
+
"jest-environment-jsdom": "^28.1.3",
|
|
88
|
+
"lint-staged": "^14.0.1",
|
|
89
|
+
"openmrs": "next",
|
|
90
|
+
"prettier": "^2.8.8",
|
|
91
|
+
"pretty-quick": "^3.1.3",
|
|
92
|
+
"raw-loader": "^4.0.2",
|
|
93
|
+
"react": "^18.3.1",
|
|
94
|
+
"react-dom": "^18.3.1",
|
|
95
|
+
"react-i18next": "^16.0.0",
|
|
96
|
+
"react-router-dom": "^6.11.2",
|
|
97
|
+
"swc-loader": "^0.2.3",
|
|
98
|
+
"turbo": "^2.5.2",
|
|
99
|
+
"typescript": "^5.0.0",
|
|
100
|
+
"webpack": "5.99.9",
|
|
101
|
+
"webpack-cli": "^6.0.1"
|
|
102
|
+
},
|
|
103
|
+
"packageManager": "yarn@4.10.3",
|
|
104
|
+
"stableVersion": "1.3.0"
|
|
105
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { devices, type PlaywrightTestConfig } from '@playwright/test';
|
|
3
|
+
import { config as dotenvConfig } from 'dotenv';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
|
|
6
|
+
// Suppress dotenv promotional messages
|
|
7
|
+
const originalLog = console.log;
|
|
8
|
+
console.log = () => {};
|
|
9
|
+
dotenvConfig({ path: resolve(process.cwd(), '.env') });
|
|
10
|
+
dotenvConfig();
|
|
11
|
+
console.log = originalLog;
|
|
12
|
+
|
|
13
|
+
// See https://playwright.dev/docs/test-configuration.
|
|
14
|
+
const config: PlaywrightTestConfig = {
|
|
15
|
+
testDir: './e2e/specs',
|
|
16
|
+
timeout: 3 * 60 * 1000,
|
|
17
|
+
expect: {
|
|
18
|
+
timeout: 40 * 1000,
|
|
19
|
+
},
|
|
20
|
+
fullyParallel: true,
|
|
21
|
+
forbidOnly: !!process.env.CI,
|
|
22
|
+
retries: 0,
|
|
23
|
+
reporter: process.env.CI ? [['junit', { outputFile: 'results.xml' }], ['html']] : [['html']],
|
|
24
|
+
globalSetup: require.resolve('./e2e/core/global-setup'),
|
|
25
|
+
use: {
|
|
26
|
+
baseURL: `${process.env.E2E_BASE_URL}/spa/`,
|
|
27
|
+
storageState: 'e2e/storageState.json',
|
|
28
|
+
video: 'retain-on-failure',
|
|
29
|
+
trace: 'retain-on-failure',
|
|
30
|
+
},
|
|
31
|
+
projects: [
|
|
32
|
+
{
|
|
33
|
+
name: 'chromium',
|
|
34
|
+
use: {
|
|
35
|
+
...devices['Desktop Chrome'],
|
|
36
|
+
channel: 'chromium',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default config;
|