Files
automatisch/packages/e2e-tests/tests/import-export-flow/import-export-flow.spec.js
2025-03-10 22:40:28 +01:00

400 lines
13 KiB
JavaScript

const { test, expect } = require('../../fixtures/index');
const axios = require('axios');
const {
createFlow,
updateFlowName,
getFlow,
updateFlowStep,
testStep,
createConnection,
verifyConnection,
} = require('../../helpers/flow-api-helper');
const { getToken } = require('../../helpers/auth-api-helper');
const { ImportFlowDialog } = require('../../fixtures/import-flow-dialog');
test.describe('Import/Export flow', () => {
test('export flow from the details with variables, step names', async ({
page,
request,
flowEditorPage,
flowsPage,
}) => {
let flowId;
const importFlowDialog = new ImportFlowDialog(page);
await test.step('create flow', async () => {
const tokenJsonResponse = await getToken(request);
const token = tokenJsonResponse.data.token;
let flow = await createFlow(request, token);
flowId = flow.data.id;
await updateFlowName(request, token, flowId);
flow = await getFlow(request, token, flowId);
const flowSteps = flow.data.steps;
const triggerStepId = flowSteps.find(
(step) => step.type === 'trigger'
).id;
const actionStepId = flowSteps.find((step) => step.type === 'action').id;
const triggerStep = await updateFlowStep(request, token, triggerStepId, {
appKey: 'webhook',
key: 'catchRawWebhook',
name: 'triggerStep',
parameters: {
workSynchronously: true,
},
});
await request.get(triggerStep.data.webhookUrl);
await testStep(request, token, triggerStepId);
await updateFlowStep(request, token, actionStepId, {
appKey: 'webhook',
key: 'respondWith',
name: 'actionStep',
parameters: {
statusCode: '200',
body: `{{step.${triggerStepId}.headers.host}}`,
headers: [
{
key: '',
value: '',
},
],
},
});
await testStep(request, token, actionStepId);
});
await test.step('open added flow', async () => {
await page.goto(`/editor/${flowId}`);
});
await test.step('export and import flow', async () => {
const downloadPromise = page.waitForEvent('download');
await flowEditorPage.exportFlowButton.click();
const download = await downloadPromise;
await download.saveAs(download.suggestedFilename());
await flowEditorPage.goBackButton.click();
await flowsPage.importFlowButton.click();
await importFlowDialog.fileInput.setInputFiles(
download.suggestedFilename()
);
await expect(importFlowDialog.fileNameWrapper).toHaveText(
`Selected file:${flowId}.json`
);
await importFlowDialog.importButton.click();
await expect(importFlowDialog.successAlert).toHaveText(
'The flow has been successfully imported. You can view it here.'
);
await importFlowDialog.successAlertLink.click();
});
await test.step('verify imported flow', async () => {
await expect(flowEditorPage.stepName.first()).toHaveText(
'1. triggerStep'
);
await flowEditorPage.continueButton.click();
await expect(
page
.getByTestId('parameters.workSynchronously-autocomplete')
.first()
.getByRole('combobox')
).toHaveValue('Yes');
await flowEditorPage.continueButton.last().click();
const webhookUrl = await page.locator('input[name="webhookUrl"]');
await axios.get(await webhookUrl.inputValue());
await flowEditorPage.testAndContinueButton.click();
await expect(flowEditorPage.stepName.nth(1)).toHaveText('2. actionStep');
await flowEditorPage.continueButton.last().click();
await expect(flowEditorPage.appAutocompleteInput).toHaveValue('Webhook');
await flowEditorPage.continueButton.last().click();
await expect(
page
.getByTestId('parameters.body-power-input')
.locator('[contenteditable="true"]')
).toContainText('step1.headers.host: localhost:3000');
});
});
test('export flow from the Flow List', async ({
page,
request,
flowsPage,
}) => {
const tokenJsonResponse = await getToken(request);
const token = tokenJsonResponse.data.token;
let flow = await createFlow(request, token);
const flowId = flow.data.id;
await updateFlowName(request, token, flowId);
await page.goto('/flows');
await expect(page).toHaveURL('/flows');
await expect(
flowsPage.flowRow.filter({
hasText: flowId,
})
).toHaveCount(1);
await flowsPage.flowRow
.filter({
hasText: flowId,
})
.getByRole('button')
.click();
const downloadPromise = page.waitForEvent('download');
await page.getByRole('menuitem', { name: 'Export' }).click();
const download = await downloadPromise;
await download.saveAs(download.suggestedFilename());
});
test('import flow and check if flow is not in status to publish', async ({
page,
flowEditorPage,
flowsPage,
}) => {
const importFlowDialog = new ImportFlowDialog(page);
await flowsPage.importFlowButton.click();
await importFlowDialog.fileInput.setInputFiles({
name: 'flow.json',
mimeType: 'application/json',
buffer: Buffer.from(`
{
"id": "b85d6ceb-4220-4afa-965a-c43fa01e96e0",
"name": "Name your flow",
"steps": [
{
"id": "3987bcb5-b33c-4f1c-964a-eff5a54d1fd4",
"key": "catchRawWebhook",
"name": "Catch raw webhook",
"appKey": "webhook",
"type": "trigger",
"parameters": {
"workSynchronously": false
},
"position": 1,
"webhookPath": "/webhooks/flows/b85d6ceb-4220-4afa-965a-c43fa01e96e0"
},
{
"id": "49ba3181-d7b0-462b-b62f-005d50689f87",
"key": "respondWith",
"name": "Respond with",
"appKey": "webhook",
"type": "action",
"parameters": {
"body": "{{step.3987bcb5-b33c-4f1c-964a-eff5a54d1fd4.headers.host}}",
"headers": [
{
"key": "abc",
"__id": "21a0bfa9-7928-4e42-9e56-f4d68b8ff7aa",
"value": "{{step.3da3f847-efda-42b7-adbe-f0203a3491b8.headers.host}}"
}
],
"statusCode": "200"
},
"position": 2
}
]
}`),
});
await expect(importFlowDialog.fileNameWrapper).toHaveText(
'Selected file:flow.json'
);
await importFlowDialog.importButton.click();
await expect(importFlowDialog.successAlert).toHaveText(
'The flow has been successfully imported. You can view it here.'
);
await importFlowDialog.successAlertLink.click();
await flowEditorPage.publishFlowButton.click();
const snackbar = await page.getByTestId('snackbar-error');
await expect(snackbar).toHaveText(
'All steps should be completed before updating flow status!'
);
});
test('connection should not be exported', async ({
page,
request,
flowEditorPage,
flowsPage,
}) => {
let flowId;
const importFlowDialog = new ImportFlowDialog(page);
await test.step('create flow', async () => {
const tokenJsonResponse = await getToken(request);
const token = tokenJsonResponse.data.token;
let flow = await createFlow(request, token);
flowId = flow.data.id;
await updateFlowName(request, token, flowId);
flow = await getFlow(request, token, flowId);
const flowSteps = flow.data.steps;
const triggerStepId = flowSteps.find(
(step) => step.type === 'trigger'
).id;
const actionStepId = flowSteps.find((step) => step.type === 'action').id;
const triggerStep = await updateFlowStep(request, token, triggerStepId, {
appKey: 'webhook',
key: 'catchRawWebhook',
name: 'triggerStep',
parameters: {
workSynchronously: true,
},
});
await request.get(triggerStep.data.webhookUrl);
await testStep(request, token, triggerStepId);
const connection = await createConnection(request, token, 'postgresql', {
formattedData: {
version: '14.5',
host: process.env.POSTGRES_HOST,
port: '5432',
enableSsl: 'false',
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USERNAME,
password: process.env.POSTGRES_PASSWORD,
},
});
await verifyConnection(request, token, connection.data.id);
await updateFlowStep(request, token, actionStepId, {
appKey: 'postgresql',
key: 'SQLQuery',
name: 'SQLQuery',
connectionId: connection.data.id,
parameters: {
queryStatement: 'select * from users;',
params: [
{
parameter: '',
value: '',
},
],
},
});
await testStep(request, token, actionStepId);
});
await test.step('open added flow', async () => {
await page.goto(`/editor/${flowId}`);
});
await test.step('export and import flow', async () => {
const downloadPromise = page.waitForEvent('download');
await flowEditorPage.exportFlowButton.click();
const download = await downloadPromise;
await download.saveAs(download.suggestedFilename());
await expect(page.getByTestId('snackbar')).toHaveText(
'The flow export has been successfully generated.'
);
await page.getByTestId('snackbar').click();
await flowEditorPage.goBackButton.click();
await flowsPage.importFlowButton.click();
await importFlowDialog.fileInput.setInputFiles(
download.suggestedFilename()
);
await expect(importFlowDialog.fileNameWrapper).toHaveText(
`Selected file:${flowId}.json`
);
await importFlowDialog.importButton.click();
await expect(importFlowDialog.successAlert).toHaveText(
'The flow has been successfully imported. You can view it here.'
);
await importFlowDialog.successAlertLink.click();
});
await test.step('verify imported flow', async () => {
await flowEditorPage.flowStep.last().click();
await expect(flowEditorPage.appAutocompleteInput).toHaveCount(1);
await expect(flowEditorPage.appAutocompleteInput).toHaveValue(
'PostgreSQL'
);
await expect(flowEditorPage.eventAutocompleteInput).toHaveValue(
'SQL query'
);
await flowEditorPage.continueButton.click();
await expect(flowEditorPage.connectionAutocompleteInput).toHaveValue('');
await page.getByText('Set up action').click();
await expect(
page
.getByTestId('parameters.queryStatement-power-input')
.locator('[contenteditable]')
).toHaveText('select * from users;');
});
});
// ellipsis if not verified properly
test.skip('handle long file names', async ({ flowsPage, page }) => {
const importFlowDialog = new ImportFlowDialog(page);
await flowsPage.importFlowButton.click();
await importFlowDialog.fileInput.setInputFiles({
name: 'very_long_file_name_with_some_additional_remarks_that_should_not_be_visible.txt',
mimeType: 'text/plain',
buffer: Buffer.from('this is test'),
});
await expect(importFlowDialog.fileName).toHaveText(
'very_long_file_name_with_some_additional_remark...'
);
});
test('should fail on import different file than json', async ({
flowsPage,
page,
}) => {
const importFlowDialog = new ImportFlowDialog(page);
await flowsPage.importFlowButton.click();
await importFlowDialog.fileInput.setInputFiles({
name: 'abc.txt',
mimeType: 'text/plain',
buffer: Buffer.from('this is test'),
});
await expect(importFlowDialog.fileNameWrapper).toHaveText(
'Selected file:abc.txt'
);
await importFlowDialog.importButton.click();
await expect(importFlowDialog.importParsingError).toHaveText(
'Something has gone wrong with parsing the selected file.'
);
});
test('import invalid nonflow json', async ({ flowsPage, page }) => {
const importFlowDialog = new ImportFlowDialog(page);
await flowsPage.importFlowButton.click();
await importFlowDialog.fileInput.setInputFiles({
name: 'abcd.json',
mimeType: 'application/json',
buffer: Buffer.from('{"this": "is test"}'),
});
await expect(importFlowDialog.fileNameWrapper).toHaveText(
'Selected file:abcd.json'
);
await importFlowDialog.importButton.click();
await expect(importFlowDialog.genericImportError).toHaveText(
'Something went wrong. Please try again.'
);
});
});