@openmrs/esm-dispensing-app 1.11.2-pre.1811 → 1.11.2-pre.1814
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/.turbo/cache/b639f8894500c9f3-meta.json +1 -0
- package/.turbo/cache/{3728e9c2a4a6b6ce.tar.zst → b639f8894500c9f3.tar.zst} +0 -0
- package/.turbo/turbo-build.log +1 -1
- package/dist/routes.json +1 -1
- package/e2e/commands/index.ts +1 -0
- package/e2e/commands/medication-dispense-operations.ts +98 -0
- package/e2e/core/test.ts +3 -1
- package/e2e/fixtures/fhirApi.ts +27 -0
- package/e2e/fixtures/index.ts +1 -0
- package/e2e/specs/edit-medication-dispense.spec.ts +111 -0
- package/package.json +1 -1
- package/.turbo/cache/3728e9c2a4a6b6ce-meta.json +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"hash":"b639f8894500c9f3","duration":11866}
|
|
Binary file
|
package/.turbo/turbo-build.log
CHANGED
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":">=2.2.0 <4.0.0"},"optionalBackendDependencies":{"emrapi":{"version":">=3.3.0 <4.0.0","feature":{"flagName":"emrapi-module","label":"EMR API Module","description":"Required if the locationBehavior.restrictToVisitLocationDescendants config is set to true."}}},"pages":[{"component":"dispensing","route":"dispensing","online":true,"offline":true}],"extensions":[{"name":"dispensing-link","slot":"app-menu-slot","component":"dispensingLink","online":true,"offline":true},{"name":"patient-diagnoses","component":"patientDiagnoses","slot":"dispensing-condition-and-diagnoses","online":true,"offline":true},{"name":"patient-conditions","component":"patientConditions","slot":"dispensing-condition-and-diagnoses","online":true,"offline":true},{"name":"dispensing-dashboard","slot":"dispensing-dashboard-slot","component":"dispensingDashboard","online":true,"offline":true},{"name":"dispensing-dashboard-link","component":"dispensingDashboardLink","meta":{"name":"dispensing","slot":"dispensing-dashboard-slot","title":"Dispensing"}},{"name":"dispense-action-button","slot":"prescription-action-button-slot","component":"dispenseActionButton"},{"name":"pause-action-button","slot":"prescription-action-button-slot","component":"pauseActionButton"},{"name":"close-action-button","slot":"prescription-action-button-slot","component":"closeActionButton"}],"workspaces2":[{"name":"close-dispense-workspace","component":"closeDispenseWorkspace","window":"dispensing-window"},{"name":"pause-dispense-workspace","component":"pauseDispenseWorkspace","window":"dispensing-window"},{"name":"dispense-workspace","component":"dispenseWorkspace","window":"dispensing-window"},{"name":"dispensing-patient-search-workspace","component":"@openmrs/esm-patient-search-app#patientSearchWorkspace2","window":"fill-prescription-window"},{"name":"dispensing-start-visit-workspace","component":"@openmrs/esm-patient-chart-app#exportedVisitForm","window":"fill-prescription-window"},{"name":"dispensing-order-basket-workspace","component":"@openmrs/esm-patient-orders-app#exportedOrderBasketWorkspace","window":"fill-prescription-window"},{"name":"dispensing-order-basket-add-drug-order-workspace","component":"@openmrs/esm-patient-medications-app#exportedAddDrugOrderWorkspace","window":"fill-prescription-window"},{"name":"dispensing-order-basket-add-allergy-workspace","component":"@openmrs/esm-patient-allergies-app#exportedAllergyFormWorkspace","window":"fill-prescription-window"}],"workspaceWindows2":[{"name":"dispensing-window","group":"dispensing-group"},{"name":"fill-prescription-window","group":"dispensing-group"}],"workspaceGroups2":[{"name":"dispensing-group","overlay":true}],"modals":[{"name":"prescription-print-preview-modal","component":"printPrescriptionPreviewModal"},{"name":"delete-confirm-modal","component":"deleteConfirmModal"},{"name":"duplicate-dispense-modal","component":"duplicateDispenseModal"},{"name":"on-prescription-filled-modal","component":"onPrescriptionFilledModal"}],"version":"1.11.2-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":">=2.2.0 <4.0.0"},"optionalBackendDependencies":{"emrapi":{"version":">=3.3.0 <4.0.0","feature":{"flagName":"emrapi-module","label":"EMR API Module","description":"Required if the locationBehavior.restrictToVisitLocationDescendants config is set to true."}}},"pages":[{"component":"dispensing","route":"dispensing","online":true,"offline":true}],"extensions":[{"name":"dispensing-link","slot":"app-menu-slot","component":"dispensingLink","online":true,"offline":true},{"name":"patient-diagnoses","component":"patientDiagnoses","slot":"dispensing-condition-and-diagnoses","online":true,"offline":true},{"name":"patient-conditions","component":"patientConditions","slot":"dispensing-condition-and-diagnoses","online":true,"offline":true},{"name":"dispensing-dashboard","slot":"dispensing-dashboard-slot","component":"dispensingDashboard","online":true,"offline":true},{"name":"dispensing-dashboard-link","component":"dispensingDashboardLink","meta":{"name":"dispensing","slot":"dispensing-dashboard-slot","title":"Dispensing"}},{"name":"dispense-action-button","slot":"prescription-action-button-slot","component":"dispenseActionButton"},{"name":"pause-action-button","slot":"prescription-action-button-slot","component":"pauseActionButton"},{"name":"close-action-button","slot":"prescription-action-button-slot","component":"closeActionButton"}],"workspaces2":[{"name":"close-dispense-workspace","component":"closeDispenseWorkspace","window":"dispensing-window"},{"name":"pause-dispense-workspace","component":"pauseDispenseWorkspace","window":"dispensing-window"},{"name":"dispense-workspace","component":"dispenseWorkspace","window":"dispensing-window"},{"name":"dispensing-patient-search-workspace","component":"@openmrs/esm-patient-search-app#patientSearchWorkspace2","window":"fill-prescription-window"},{"name":"dispensing-start-visit-workspace","component":"@openmrs/esm-patient-chart-app#exportedVisitForm","window":"fill-prescription-window"},{"name":"dispensing-order-basket-workspace","component":"@openmrs/esm-patient-orders-app#exportedOrderBasketWorkspace","window":"fill-prescription-window"},{"name":"dispensing-order-basket-add-drug-order-workspace","component":"@openmrs/esm-patient-medications-app#exportedAddDrugOrderWorkspace","window":"fill-prescription-window"},{"name":"dispensing-order-basket-add-allergy-workspace","component":"@openmrs/esm-patient-allergies-app#exportedAllergyFormWorkspace","window":"fill-prescription-window"}],"workspaceWindows2":[{"name":"dispensing-window","group":"dispensing-group"},{"name":"fill-prescription-window","group":"dispensing-group"}],"workspaceGroups2":[{"name":"dispensing-group","overlay":true}],"modals":[{"name":"prescription-print-preview-modal","component":"printPrescriptionPreviewModal"},{"name":"delete-confirm-modal","component":"deleteConfirmModal"},{"name":"duplicate-dispense-modal","component":"duplicateDispenseModal"},{"name":"on-prescription-filled-modal","component":"onPrescriptionFilledModal"}],"version":"1.11.2-pre.1814"}
|
package/e2e/commands/index.ts
CHANGED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import { type APIRequestContext, expect } from '@playwright/test';
|
|
3
|
+
import { type Patient } from './patient-operations';
|
|
4
|
+
import { type Provider } from './types';
|
|
5
|
+
import { type MedicationDispense, MedicationDispenseStatus } from '../../src/types';
|
|
6
|
+
|
|
7
|
+
export const generateMedicationDispense = async (
|
|
8
|
+
fhirApi: APIRequestContext,
|
|
9
|
+
patient: Patient,
|
|
10
|
+
provider: Provider,
|
|
11
|
+
medicationRequestUuid: string,
|
|
12
|
+
): Promise<MedicationDispense> => {
|
|
13
|
+
const dispense = await fhirApi.post('MedicationDispense', {
|
|
14
|
+
data: {
|
|
15
|
+
resourceType: 'MedicationDispense',
|
|
16
|
+
status: MedicationDispenseStatus.completed,
|
|
17
|
+
authorizingPrescription: [
|
|
18
|
+
{
|
|
19
|
+
reference: `MedicationRequest/${medicationRequestUuid}`,
|
|
20
|
+
type: 'MedicationRequest',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
medicationReference: {
|
|
24
|
+
reference: 'Medication/09e58895-e7f0-4649-b7c0-e665c5c08e93',
|
|
25
|
+
type: 'Medication',
|
|
26
|
+
display: 'Aspirin 81mg',
|
|
27
|
+
},
|
|
28
|
+
subject: {
|
|
29
|
+
reference: `Patient/${patient.uuid}`,
|
|
30
|
+
},
|
|
31
|
+
performer: [
|
|
32
|
+
{
|
|
33
|
+
actor: {
|
|
34
|
+
reference: `Practitioner/${provider.uuid}`,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
location: {
|
|
39
|
+
reference: `Location/${process.env.E2E_LOGIN_DEFAULT_LOCATION_UUID}`,
|
|
40
|
+
},
|
|
41
|
+
substitution: {
|
|
42
|
+
wasSubstituted: false,
|
|
43
|
+
reason: [],
|
|
44
|
+
type: null,
|
|
45
|
+
},
|
|
46
|
+
whenHandedOver: dayjs().format(),
|
|
47
|
+
quantity: {
|
|
48
|
+
value: 5,
|
|
49
|
+
code: '1513AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
50
|
+
unit: 'Tablet',
|
|
51
|
+
},
|
|
52
|
+
dosageInstruction: [
|
|
53
|
+
{
|
|
54
|
+
timing: {
|
|
55
|
+
repeat: {
|
|
56
|
+
durationUnit: 'd',
|
|
57
|
+
},
|
|
58
|
+
code: {
|
|
59
|
+
coding: [
|
|
60
|
+
{
|
|
61
|
+
code: '160862AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
62
|
+
display: 'Once daily',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
text: 'Once daily',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
asNeededBoolean: false,
|
|
69
|
+
route: {
|
|
70
|
+
coding: [
|
|
71
|
+
{
|
|
72
|
+
code: '160240AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
73
|
+
display: 'Oral',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
text: 'Oral',
|
|
77
|
+
},
|
|
78
|
+
doseAndRate: [
|
|
79
|
+
{
|
|
80
|
+
doseQuantity: {
|
|
81
|
+
value: 1,
|
|
82
|
+
unit: 'Milligram',
|
|
83
|
+
code: '161553AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(dispense.ok()).toBeTruthy();
|
|
93
|
+
return await dispense.json();
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const deleteMedicationDispense = async (fhirApi: APIRequestContext, uuid: string) => {
|
|
97
|
+
await fhirApi.delete(`MedicationDispense/${uuid}`);
|
|
98
|
+
};
|
package/e2e/core/test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type APIRequestContext, type Page, test as base } from '@playwright/test';
|
|
2
|
-
import { api } from '../fixtures';
|
|
2
|
+
import { api, fhirApi } from '../fixtures';
|
|
3
3
|
import { type Patient } from '../types';
|
|
4
4
|
import { generateRandomPatient, deletePatient } from '../commands';
|
|
5
5
|
|
|
@@ -16,10 +16,12 @@ export interface CustomTestFixtures {
|
|
|
16
16
|
|
|
17
17
|
export interface CustomWorkerFixtures {
|
|
18
18
|
api: APIRequestContext;
|
|
19
|
+
fhirApi: APIRequestContext;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export const test = base.extend<CustomTestFixtures, CustomWorkerFixtures>({
|
|
22
23
|
api: [api, { scope: 'worker' }],
|
|
24
|
+
fhirApi: [fhirApi, { scope: 'worker' }],
|
|
23
25
|
patient: [
|
|
24
26
|
async ({ api }, use) => {
|
|
25
27
|
const patient = await generateRandomPatient(api);
|
|
@@ -0,0 +1,27 @@
|
|
|
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 FHIR R4 API server. The context is automatically
|
|
6
|
+
* authenticated using the configured admin account.
|
|
7
|
+
*
|
|
8
|
+
* Use the request context like this:
|
|
9
|
+
* ```ts
|
|
10
|
+
* test('your test', async ({ fhirApi }) => {
|
|
11
|
+
* const res = await fhirApi.get('MedicationDispense/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
|
+
use(fhirctx);
|
|
27
|
+
};
|
package/e2e/fixtures/index.ts
CHANGED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { expect } from '@playwright/test';
|
|
2
|
+
import { type Order, type Visit } from '@openmrs/esm-framework';
|
|
3
|
+
import {
|
|
4
|
+
createEncounter,
|
|
5
|
+
deleteDrugOrder,
|
|
6
|
+
deleteEncounter,
|
|
7
|
+
deleteMedicationDispense,
|
|
8
|
+
endVisit,
|
|
9
|
+
generateMedicationDispense,
|
|
10
|
+
generateRandomDrugOrder,
|
|
11
|
+
getProvider,
|
|
12
|
+
startVisit,
|
|
13
|
+
} from '../commands';
|
|
14
|
+
import { DispensingPage } from '../pages';
|
|
15
|
+
import { test } from '../core';
|
|
16
|
+
import { type Encounter, type Provider } from '../commands/types';
|
|
17
|
+
import { type MedicationDispense } from '../../src/types';
|
|
18
|
+
|
|
19
|
+
let visit: Visit;
|
|
20
|
+
let drugOrder: Order;
|
|
21
|
+
let encounter: Encounter;
|
|
22
|
+
let orderer: Provider;
|
|
23
|
+
let medicationDispense: MedicationDispense;
|
|
24
|
+
|
|
25
|
+
test.beforeEach(async ({ api, fhirApi, patient }) => {
|
|
26
|
+
visit = await startVisit(api, patient.uuid);
|
|
27
|
+
orderer = await getProvider(api);
|
|
28
|
+
encounter = await createEncounter(api, patient.uuid, orderer.uuid, visit);
|
|
29
|
+
drugOrder = await generateRandomDrugOrder(api, patient.uuid, encounter, orderer.uuid);
|
|
30
|
+
medicationDispense = await generateMedicationDispense(fhirApi, patient, orderer, drugOrder.uuid);
|
|
31
|
+
|
|
32
|
+
// Wait until the dispense is returned by the same FHIR search the prescription
|
|
33
|
+
// details view issues, so the UI is guaranteed to see it once the test starts
|
|
34
|
+
await expect
|
|
35
|
+
.poll(
|
|
36
|
+
async () => {
|
|
37
|
+
const response = await fhirApi.get(
|
|
38
|
+
`MedicationRequest?encounter=${encounter.uuid}&_revinclude=MedicationDispense:prescription`,
|
|
39
|
+
);
|
|
40
|
+
if (!response.ok()) {
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
const bundle = await response.json();
|
|
44
|
+
return (
|
|
45
|
+
bundle.entry?.filter(
|
|
46
|
+
(entry: { resource?: { resourceType?: string } }) => entry.resource?.resourceType === 'MedicationDispense',
|
|
47
|
+
).length ?? 0
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
{ timeout: 30000 },
|
|
51
|
+
)
|
|
52
|
+
.toBeGreaterThan(0);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('Edit medication dispense', async ({ page, patient }) => {
|
|
56
|
+
const dispensingPage = new DispensingPage(page);
|
|
57
|
+
const patientRow = page.getByRole('row', { name: new RegExp(patient.person.display) });
|
|
58
|
+
const historyTabPanel = page.getByRole('tabpanel', { name: 'History and comments' });
|
|
59
|
+
|
|
60
|
+
await test.step('When I navigate to the dispensing app', async () => {
|
|
61
|
+
await dispensingPage.goTo();
|
|
62
|
+
await expect(page).toHaveURL(`${process.env.E2E_BASE_URL}/spa/dispensing`);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await test.step('And I click on the "All prescriptions" tab', async () => {
|
|
66
|
+
await page.getByRole('tab', { name: 'All prescriptions' }).click();
|
|
67
|
+
await expect(page.getByRole('tab', { name: 'All prescriptions' })).toHaveAttribute('aria-selected', 'true');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await test.step("Then I should see the patient's prescription in the table", async () => {
|
|
71
|
+
await expect(patientRow).toBeVisible({ timeout: 15000 });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await test.step('And I expand the prescription row', async () => {
|
|
75
|
+
await patientRow.getByLabel('Expand current row').click();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
await test.step('And I navigate to the History and comments tab', async () => {
|
|
79
|
+
await page.getByRole('tab', { name: 'History and comments' }).click();
|
|
80
|
+
await expect(historyTabPanel.getByText('QUANTITY 5 Tablet')).toBeVisible();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await test.step('And I edit the dispense record', async () => {
|
|
84
|
+
await historyTabPanel.getByRole('button', { name: 'Options' }).click();
|
|
85
|
+
await page.getByRole('menuitem', { name: 'Edit Record' }).click();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await test.step('And I update the quantity to 9', async () => {
|
|
89
|
+
await page.getByRole('spinbutton', { name: 'Quantity' }).click();
|
|
90
|
+
await page.getByRole('spinbutton', { name: 'Quantity' }).fill('9');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
await test.step('And I save the changes', async () => {
|
|
94
|
+
await page.getByRole('button', { name: 'Save changes' }).click();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
await test.step('Then I should see a success notification confirming the update', async () => {
|
|
98
|
+
await expect(page.getByText(/medication dispense list has been updated/i)).toBeVisible();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await test.step('And the quantity should be updated to 9', async () => {
|
|
102
|
+
await expect(historyTabPanel.getByText('QUANTITY 9 Tablet')).toBeVisible();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test.afterEach(async ({ api, fhirApi }) => {
|
|
107
|
+
await deleteMedicationDispense(fhirApi, medicationDispense.id);
|
|
108
|
+
await deleteEncounter(api, encounter.uuid);
|
|
109
|
+
await deleteDrugOrder(api, drugOrder.uuid);
|
|
110
|
+
await endVisit(api, visit);
|
|
111
|
+
});
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"hash":"3728e9c2a4a6b6ce","duration":11666}
|