Skip to content

Commit

Permalink
test: add process instance e2e tests (#5140)
Browse files Browse the repository at this point in the history
  • Loading branch information
huygur committed Aug 15, 2023
1 parent b396cfd commit af8f5f5
Show file tree
Hide file tree
Showing 8 changed files with 444 additions and 1 deletion.
20 changes: 20 additions & 0 deletions client/e2e-playwright/pages/ProcessInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,39 @@ export class ProcessInstance {
private page: Page;
readonly instanceHeader: Locator;
readonly instanceHistory: Locator;
readonly variablesList: Locator;
readonly incidentsTable: Locator;
readonly incidentsBanner: Locator;
readonly diagram: Locator;
readonly popover: Locator;
readonly variablePanelEmptyText: Locator;
readonly addVariableButton: Locator;
readonly saveVariableButton: Locator;
readonly newVariableNameField: Locator;
readonly newVariableValueField: Locator;
readonly editVariableValueField: Locator;
readonly variableSpinner: Locator;
readonly operationSpinner: Locator;

constructor(page: Page) {
this.page = page;
this.instanceHeader = page.getByTestId('instance-header');
this.instanceHistory = page.getByTestId('instance-history');
this.variablesList = page.getByTestId('variables-list');
this.incidentsTable = page.getByTestId('data-list');
this.incidentsBanner = page.getByTestId('incidents-banner');
this.diagram = page.getByTestId('diagram');
this.popover = page.getByTestId('popover');
this.variablePanelEmptyText = page.getByText(
/to view the variables, select a single flow node instance in the instance history./i,
);
this.addVariableButton = page.getByRole('button', {name: 'Add variable'});
this.saveVariableButton = page.getByRole('button', {name: 'Save variable'});
this.newVariableNameField = page.getByRole('textbox', {name: 'Name'});
this.newVariableValueField = page.getByRole('textbox', {name: 'Value'});
this.editVariableValueField = page.getByRole('textbox', {name: 'Value'});
this.variableSpinner = page.getByTestId('variable-operation-spinner');
this.operationSpinner = page.getByTestId('operation-spinner');
}

getEditVariableFieldSelector(variableName: string) {
Expand Down
3 changes: 2 additions & 1 deletion client/e2e-playwright/tests/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@

const SETUP_WAITING_TIME = 20000;
const DATE_REGEX = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
const DEFAULT_TEST_TIMEOUT = 30 * 1000;

export {SETUP_WAITING_TIME, DATE_REGEX};
export {SETUP_WAITING_TIME, DATE_REGEX, DEFAULT_TEST_TIMEOUT};
31 changes: 31 additions & 0 deletions client/e2e-playwright/tests/processInstance.mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/

import {deployProcess, createSingleInstance} from '../setup-utils';

export async function setup() {
await deployProcess([
'processWithAnIncident.bpmn',
'processWithMultiIncidents.bpmn',
]);

const instanceWithIncidentToCancel = await createSingleInstance(
'processWithAnIncident',
1,
);

const instanceWithIncidentToResolve = await createSingleInstance(
'processWithMultiIncidents',
1,
{goUp: 3},
);

return {
instanceWithIncidentToCancel,
instanceWithIncidentToResolve,
};
}
236 changes: 236 additions & 0 deletions client/e2e-playwright/tests/processInstance.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/

import {setup} from './processInstance.mocks';
import {test} from '../test-fixtures';
import {expect} from '@playwright/test';
import {
DATE_REGEX,
DEFAULT_TEST_TIMEOUT,
SETUP_WAITING_TIME,
} from './constants';
import {config} from '../config';

let initialData: Awaited<ReturnType<typeof setup>>;

test.beforeAll(async ({request}) => {
initialData = await setup();
test.setTimeout(SETUP_WAITING_TIME);

await Promise.all([
expect
.poll(
async () => {
const response = await request.get(
`${config.endpoint}/v1/process-instances/${initialData.instanceWithIncidentToResolve.processInstanceKey}`,
);

return response.status();
},
{timeout: SETUP_WAITING_TIME},
)
.toBe(200),
expect
.poll(
async () => {
const response = await request.get(
`${config.endpoint}/v1/process-instances/${initialData.instanceWithIncidentToCancel.processInstanceKey}`,
);

return response.status();
},
{timeout: SETUP_WAITING_TIME},
)
.toBe(200),
expect
.poll(
async () => {
const response = await request.post(
`${config.endpoint}/v1/incidents/search`,
{
data: {
filter: {
processInstanceKey: parseInt(
initialData.instanceWithIncidentToResolve
.processInstanceKey,
),
},
},
},
);

const incidents: {items: [{state: string}]; total: number} =
await response.json();

return (
incidents.total > 0 &&
incidents.items.filter(({state}) => state === 'PENDING').length ===
0
);
},
{timeout: SETUP_WAITING_TIME},
)
.toBeTruthy(),
]);
});

test.describe('Process Instance', () => {
test('Resolve an incident', async ({page, processInstancePage}) => {
test.setTimeout(DEFAULT_TEST_TIMEOUT + 3 * 15000); // 15 seconds for each applied operation in this test

await processInstancePage.navigateToProcessInstance(
initialData.instanceWithIncidentToResolve.processInstanceKey,
);

// click and expand incident bar
await expect(
page.getByRole('button', {
name: /view 2 incidents in instance/i,
}),
).toBeVisible();

await page
.getByRole('button', {
name: /view 2 incidents in instance/i,
})
.click();

await expect(
page.getByRole('button', {name: /filter by incident type/i}),
).toBeVisible();
await expect(
page.getByRole('button', {name: /filter by flow node/i}),
).toBeVisible();

// edit goUp variable
await processInstancePage.variablesList
.getByRole('button', {
name: /edit variable/i,
})
.click();

await processInstancePage.editVariableValueField.clear();
await processInstancePage.editVariableValueField.type('20');

await expect(processInstancePage.saveVariableButton).toBeEnabled();
await processInstancePage.saveVariableButton.click();

await expect(processInstancePage.variableSpinner).toBeVisible();
await expect(processInstancePage.variableSpinner).not.toBeVisible();

// retry one incident to resolve it
await processInstancePage.incidentsTable
.getByRole('row', {name: /Condition error/i})
.getByRole('button', {name: 'Retry Incident'})
.click();

await expect(
processInstancePage.incidentsTable
.getByRole('row', {name: /Condition error/i})
.getByTestId('operation-spinner'),
).toBeVisible();

await expect(
processInstancePage.incidentsTable.getByTestId('operation-spinner'),
).not.toBeVisible();

await expect(
processInstancePage.incidentsTable.getByRole('row'),
).toHaveCount(1);

await expect(
processInstancePage.incidentsTable.getByText(/is cool\?/i),
).toBeVisible();
await expect(
processInstancePage.incidentsTable.getByText(/where to go\?/i),
).not.toBeVisible();

// add variable isCool

await processInstancePage.addVariableButton.click();

await processInstancePage.newVariableNameField.type('isCool');
await processInstancePage.newVariableValueField.type('true');

await expect(processInstancePage.saveVariableButton).toBeEnabled();

await processInstancePage.saveVariableButton.click();
await expect(processInstancePage.variableSpinner).toBeVisible();
await expect(processInstancePage.variableSpinner).not.toBeVisible();

// retry second incident to resolve it
await processInstancePage.incidentsTable
.getByRole('row', {
name: /Extract value error/i,
})
.getByRole('button', {name: 'Retry Incident'})
.click();

await expect(
processInstancePage.incidentsTable
.getByRole('row', {
name: /Extract value error/i,
})
.getByTestId('operation-spinner'),
).toBeVisible();

// expect all incidents resolved
await expect(processInstancePage.incidentsBanner).not.toBeVisible();
await expect(processInstancePage.incidentsTable).not.toBeVisible();
await expect(
processInstancePage.instanceHeader.getByTestId('COMPLETED-icon'),
).toBeVisible();
});

test('Cancel an instance', async ({page, processInstancePage}) => {
test.setTimeout(DEFAULT_TEST_TIMEOUT + 1 * 15000); // 15 seconds for each applied operation in this test

const instanceId =
initialData.instanceWithIncidentToCancel.processInstanceKey;

await processInstancePage.navigateToProcessInstance(
initialData.instanceWithIncidentToCancel.processInstanceKey,
);

await expect(
page.getByRole('button', {
name: /view 3 incidents in instance/i,
}),
).toBeVisible();

await page
.getByRole('button', {
name: `Cancel Instance ${instanceId}`,
})
.click();

await page
.getByRole('button', {
name: 'Apply',
})
.click();

await expect(processInstancePage.operationSpinner).toBeVisible();
await expect(processInstancePage.operationSpinner).not.toBeVisible();

await expect(
page.getByRole('button', {
name: /view 3 incidents in instance/i,
}),
).not.toBeVisible();

await expect(
processInstancePage.instanceHeader.getByTestId('CANCELED-icon'),
).toBeVisible();

await expect(
await processInstancePage.instanceHeader
.getByTestId('end-date')
.innerText(),
).toMatch(DATE_REGEX);
});
});
Loading

0 comments on commit af8f5f5

Please sign in to comment.