From 912f54043a36984ca1967efcff79f1cd652f2ab6 Mon Sep 17 00:00:00 2001 From: Travis Harris Date: Mon, 29 Apr 2024 12:00:06 -0700 Subject: [PATCH] test(e2e): Clean up and fix up some mock e2e test using newer playwright apis (#4723) * test(e2e): Fix up E2E tests a bit * test(e2e): fix up e2e tests * fix some tests * fix(Designer): Copy Paste Fixes (#4725) * fixScopePaste * remove logs * fix test * fix tests * i forgot to update the original one * readd tests * readd tests --------- Co-authored-by: Eric Wu <95886809+Eric-B-Wu@users.noreply.github.com> --- .github/workflows/real-e2e.yml | 3 +- e2e/designer/app.spec.ts | 6 +- e2e/designer/dragAndDrop.spec.ts | 23 +- e2e/designer/ensureInitializeVariable.spec.ts | 24 +- e2e/designer/mock-copypastescope.spec.ts | 16 +- e2e/designer/real-api/copypastescope.spec.ts | 303 ++++++++---------- e2e/designer/real-api/custom-code.spec.ts | 4 +- e2e/designer/real-api/sanity-test.spec.ts | 8 +- .../real-api/statelessvariables.spec.ts | 136 ++++---- e2e/designer/serialization.spec.ts | 91 ++---- e2e/designer/utils/GoToWorkflow.ts | 10 +- e2e/designer/utils/designerFunctions.ts | 8 + playwright.config.ts | 16 +- 13 files changed, 293 insertions(+), 355 deletions(-) create mode 100644 e2e/designer/utils/designerFunctions.ts diff --git a/.github/workflows/real-e2e.yml b/.github/workflows/real-e2e.yml index 0897ee97086..b4a0f40980c 100644 --- a/.github/workflows/real-e2e.yml +++ b/.github/workflows/real-e2e.yml @@ -13,7 +13,7 @@ jobs: id-token: write strategy: matrix: - browser: [chromium, firefox, webkit] + browser: [chromium, firefox] steps: - uses: actions/checkout@v4 @@ -101,7 +101,6 @@ jobs: run: | az group delete -n lauxtest2chromium --yes --no-wait az group delete -n lauxtest2firefox --yes --no-wait - az group delete -n lauxtest2webkit --yes --no-wait - name: "Upload Playwright Report to Azure Blob Storage for static site access" shell: bash diff --git a/e2e/designer/app.spec.ts b/e2e/designer/app.spec.ts index 5b1252ea862..05c7ccffb29 100644 --- a/e2e/designer/app.spec.ts +++ b/e2e/designer/app.spec.ts @@ -1,4 +1,5 @@ import { expect, test } from '@playwright/test'; +import { GoToMockWorkflow } from './utils/GoToWorkflow'; test( 'Sanity Check', @@ -8,9 +9,8 @@ test( async ({ page }) => { await page.goto('/'); - await page.getByText('Select an option').click(); - await page.getByRole('option', { name: 'Simple Big Workflow' }).click(); - await page.getByRole('button', { name: 'Toolbox' }).click(); + await GoToMockWorkflow(page, 'Simple Big Workflow'); + await page.getByTestId('card-Increment variable').getByRole('button').click(); await page.getByLabel('Value').getByRole('paragraph').click(); await page.getByLabel('Value').press('Escape'); diff --git a/e2e/designer/dragAndDrop.spec.ts b/e2e/designer/dragAndDrop.spec.ts index aceed1161e6..8060b4cf7ba 100644 --- a/e2e/designer/dragAndDrop.spec.ts +++ b/e2e/designer/dragAndDrop.spec.ts @@ -1,4 +1,5 @@ -import { test } from '@playwright/test'; +import { test, expect } from '@playwright/test'; +import { GoToMockWorkflow } from './utils/GoToWorkflow'; test( 'Should be able to drag and drop operations', @@ -8,21 +9,9 @@ test( async ({ page }) => { await page.goto('/'); - await page.locator('text=Select an option').click(); - await page.locator('button[role="option"]:has-text("Simple Big Workflow")').click(); - await page.locator('div[role="button"]:has-text("🧰")').click(); - - const originElement = await page.waitForSelector('div[role="button"]:has-text("Increment variable55")'); - const destinationElement = await page.waitForSelector( - 'g:nth-child(51) > .edgebutton-foreignobject > div > div > .msla-drop-zone-viewmanager2' - ); - - await originElement.hover(); - await page.mouse.down(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const box = (await destinationElement.boundingBox())!; - await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2); - await destinationElement.hover(); - await page.mouse.up(); + await GoToMockWorkflow(page, 'Panel'); + await page + .getByLabel('HTTP operation, HTTP connector') + .dragTo(page.getByTestId('rf__edge-manual-Initialize_ArrayVariable').getByLabel('Insert a new step between')); } ); diff --git a/e2e/designer/ensureInitializeVariable.spec.ts b/e2e/designer/ensureInitializeVariable.spec.ts index b2f901dde6f..43797a57bc6 100644 --- a/e2e/designer/ensureInitializeVariable.spec.ts +++ b/e2e/designer/ensureInitializeVariable.spec.ts @@ -1,4 +1,6 @@ import { test, expect } from '@playwright/test'; +import { GoToMockWorkflow } from './utils/GoToWorkflow'; +import { getSerializedWorkflowFromState } from './utils/designerFunctions'; test( 'Should be able to switch between Initialize Variable types', @@ -7,9 +9,7 @@ test( }, async ({ page }) => { await page.goto('/'); - await page.getByText('Select an option').click(); - await page.getByRole('option', { name: 'Recurrence' }).click(); - await page.getByRole('button', { name: 'Toolbox' }).click(); + await GoToMockWorkflow(page, 'Recurrence'); await page.getByLabel('Insert a new step after').click(); await page.getByText('Add an action').click(); await page.getByPlaceholder('Search').click(); @@ -37,14 +37,7 @@ test( .first() .click(); - const serialized: any = await page.evaluate(() => { - return new Promise((resolve) => { - setTimeout(() => { - const state = (window as any).DesignerStore.getState(); - resolve((window as any).DesignerModule.serializeBJSWorkflow(state)); - }, 5000); - }); - }); + const serialized: any = await getSerializedWorkflowFromState(page); expect(serialized.definition.actions.Initialize_variable.inputs.variables[0].type).toBe('integer'); expect(serialized.definition.actions.Initialize_variable.inputs.variables[0].value).toEqual(12); @@ -52,14 +45,7 @@ test( await page.getByRole('option', { name: 'Boolean' }).click(); await page.getByPlaceholder('Enter initial value').click(); await page.getByRole('option', { name: 'true' }).click(); - const serialized2: any = await page.evaluate(() => { - return new Promise((resolve) => { - setTimeout(() => { - const state = (window as any).DesignerStore.getState(); - resolve((window as any).DesignerModule.serializeBJSWorkflow(state)); - }, 5000); - }); - }); + const serialized2: any = await getSerializedWorkflowFromState(page); expect(serialized2.definition.actions.Initialize_variable.inputs.variables[0].type).toBe('boolean'); expect(serialized2.definition.actions.Initialize_variable.inputs.variables[0].value).toEqual(true); } diff --git a/e2e/designer/mock-copypastescope.spec.ts b/e2e/designer/mock-copypastescope.spec.ts index 1b1a11e9db6..27358595fba 100644 --- a/e2e/designer/mock-copypastescope.spec.ts +++ b/e2e/designer/mock-copypastescope.spec.ts @@ -1,15 +1,12 @@ import { test, expect } from '@playwright/test'; +import { getSerializedWorkflowFromState } from './utils/designerFunctions'; test( 'Mock: Expect Copy and Paste of Scopes to work on single workflow', { tag: '@mock', }, - async ({ page, browserName, context }) => { - test.skip(browserName === 'webkit'); - if (browserName === 'webkit') { - context.grantPermissions(['clipboard-read'], { origin: 'http://localhost:4200' }); - } + async ({ page }) => { await page.goto('/'); await page.getByText('Select an option').click(); await page.getByRole('option', { name: 'Conditionals', exact: true }).click(); @@ -20,14 +17,7 @@ test( await page.getByTestId('rf__edge-Initialize_variable-Condition').getByLabel('Insert a new step between').focus(); await page.keyboard.press('Control+V'); await page.waitForTimeout(1000); - const serialized: any = await page.evaluate(() => { - return new Promise((resolve) => { - setTimeout(() => { - const state = (window as any).DesignerStore.getState(); - resolve((window as any).DesignerModule.serializeBJSWorkflow(state)); - }, 5000); - }); - }); + const serialized: any = await getSerializedWorkflowFromState(page); expect(serialized.definition).toEqual(verificationWorkflow); } ); diff --git a/e2e/designer/real-api/copypastescope.spec.ts b/e2e/designer/real-api/copypastescope.spec.ts index 0b4d2ed10ff..7aed4311033 100644 --- a/e2e/designer/real-api/copypastescope.spec.ts +++ b/e2e/designer/real-api/copypastescope.spec.ts @@ -1,5 +1,6 @@ import { expect, test } from '@playwright/test'; -import { GoToWorkflow } from '../utils/GoToWorkflow'; +import { GoToRealWorkflow } from '../utils/GoToWorkflow'; +import { getSerializedWorkflowFromState } from '../utils/designerFunctions'; test.describe( 'Copy and Paste of Scopes', @@ -8,208 +9,178 @@ test.describe( }, () => { - test.beforeEach(async ({ browserName }) => { - test.skip(browserName === 'webkit'); - }); - test('Expect Copy and Paste of Scopes to work on single workflow', async ({ page, context, browserName }) => { - if (browserName === 'webkit') { - context.grantPermissions(['clipboard-read'], { origin: 'http://localhost:4200' }); - } + test('Expect Copy and Paste of Scopes to work on single workflow', async ({ page, browserName }) => { + await page.goto('/'); - await GoToWorkflow(page, `wapp-lauxtest2${browserName}`, 'CopyPaste'); + await GoToRealWorkflow(page, `wapp-lauxtest2${browserName}`, 'CopyPaste'); await page.waitForLoadState('networkidle'); await page.getByTestId('rf__node-For_each-#scope').getByRole('button', { name: 'For each' }).focus(); await page.keyboard.press('Control+C'); await page.getByTestId('rf__edge-For_each-Filter_array').getByLabel('Insert a new step between For').focus(); await page.keyboard.press('Control+V'); - const serialized: any = await page.evaluate(() => { - return new Promise((resolve) => { - setTimeout(() => { - const state = (window as any).DesignerStore.getState(); - resolve((window as any).DesignerModule.serializeBJSWorkflow(state)); - }, 500); - }); - }); + const serialized: any = await getSerializedWorkflowFromState(page); expect(serialized.definition).toEqual(verificationWorkflow); }); } ); const verificationWorkflow = { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "actions": { - "Initialize_ArrayVariable": { - "type": "InitializeVariable", - "inputs": { - "variables": [ + $schema: 'https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#', + actions: { + Initialize_ArrayVariable: { + type: 'InitializeVariable', + inputs: { + variables: [ { - "name": "ArrayVariable", - "type": "array", - "value": [ + name: 'ArrayVariable', + type: 'array', + value: [ { - "document": "A", - "min": 7500001, - "policy": "X" + document: 'A', + min: 7500001, + policy: 'X', }, { - "document": "B", - "min": 7500001, - "policy": "Y" + document: 'B', + min: 7500001, + policy: 'Y', }, { - "document": "C", - "min": 7500001, - "policy": "Z" - } - ] - } - ] + document: 'C', + min: 7500001, + policy: 'Z', + }, + ], + }, + ], }, - "runAfter": {} + runAfter: {}, }, - "Filter_array": { - "type": "Query", - "inputs": { - "from": "@body('Parse_JSON')", - "where": "@not(contains(length(split(item(), '|')?[0]),length(split(item(), '|')?[0])))" + Filter_array: { + type: 'Query', + inputs: { + from: "@body('Parse_JSON')", + where: "@not(contains(length(split(item(), '|')?[0]),length(split(item(), '|')?[0])))", + }, + runAfter: { + 'For_each-copy': ['SUCCEEDED'], }, - "runAfter": { - "For_each-copy": [ - "SUCCEEDED" - ] - } }, - "HTTP": { - "type": "Http", - "inputs": { - "uri": "http://test.com", - "method": "GET", - "body": "@variables('ArrayVariable')" + HTTP: { + type: 'Http', + inputs: { + uri: 'http://test.com', + method: 'GET', + body: "@variables('ArrayVariable')", + }, + runAfter: { + Filter_array: ['SUCCEEDED'], }, - "runAfter": { - "Filter_array": [ - "SUCCEEDED" - ] + runtimeConfiguration: { + contentTransfer: { + transferMode: 'Chunked', + }, }, - "runtimeConfiguration": { - "contentTransfer": { - "transferMode": "Chunked" - } - } }, - "For_each": { - "type": "foreach", - "foreach": "@triggerOutputs()?['body']?['array']", - "actions": { - "Parse_JSON": { - "type": "ParseJson", - "inputs": { - "content": "@{triggerBody()?['string']}@{variables('ArrayVariable')}@{item()?['item1']}", - "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "document": { - "type": "string" + For_each: { + type: 'foreach', + foreach: "@triggerOutputs()?['body']?['array']", + actions: { + Parse_JSON: { + type: 'ParseJson', + inputs: { + content: "@{triggerBody()?['string']}@{variables('ArrayVariable')}@{item()?['item1']}", + schema: { + type: 'array', + items: { + type: 'object', + properties: { + document: { + type: 'string', + }, + min: { + type: 'integer', }, - "min": { - "type": "integer" + policy: { + type: 'string', }, - "policy": { - "type": "string" - } }, - "required": [ - "document", - "min", - "policy" - ] - } - } - } - } + required: ['document', 'min', 'policy'], + }, + }, + }, + }, + }, + runAfter: { + Initialize_ArrayVariable: ['SUCCEEDED'], }, - "runAfter": { - "Initialize_ArrayVariable": [ - "SUCCEEDED" - ] - } }, - "For_each-copy": { - "type": "foreach", - "foreach": "@triggerOutputs()?['body']?['array']", - "actions": { - "Parse_JSON_1": { - "type": "ParseJson", - "inputs": { - "content": "@{triggerBody()?['string']}@{variables('ArrayVariable')}@{item()?['item1']}", - "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "document": { - "type": "string" + 'For_each-copy': { + type: 'foreach', + foreach: "@triggerOutputs()?['body']?['array']", + actions: { + Parse_JSON_1: { + type: 'ParseJson', + inputs: { + content: "@{triggerBody()?['string']}@{variables('ArrayVariable')}@{item()?['item1']}", + schema: { + type: 'array', + items: { + type: 'object', + properties: { + document: { + type: 'string', }, - "min": { - "type": "integer" + min: { + type: 'integer', + }, + policy: { + type: 'string', }, - "policy": { - "type": "string" - } }, - "required": [ - "document", - "min", - "policy" - ] - } - } - } - } + required: ['document', 'min', 'policy'], + }, + }, + }, + }, + }, + runAfter: { + For_each: ['SUCCEEDED'], }, - "runAfter": { - "For_each": [ - "SUCCEEDED" - ] - } - } + }, }, - "contentVersion": "1.0.0.0", - "outputs": {}, - "triggers": { - "manual": { - "type": "Request", - "kind": "Http", - "inputs": { - "schema": { - "type": "object", - "properties": { - "array": { - "type": "array", - "items": { - "type": "object", - "properties": { - "item1": { - "type": "string" - } + contentVersion: '1.0.0.0', + outputs: {}, + triggers: { + manual: { + type: 'Request', + kind: 'Http', + inputs: { + schema: { + type: 'object', + properties: { + array: { + type: 'array', + items: { + type: 'object', + properties: { + item1: { + type: 'string', + }, }, - "required": [ - "item1" - ] - } + required: ['item1'], + }, }, - "string": { - "type": "string" + string: { + type: 'string', }, - "number": { - "type": "integer" - } - } - } - } - } - } + number: { + type: 'integer', + }, + }, + }, + }, + }, + }, }; diff --git a/e2e/designer/real-api/custom-code.spec.ts b/e2e/designer/real-api/custom-code.spec.ts index 5b6223226d8..4fc7c0484f9 100644 --- a/e2e/designer/real-api/custom-code.spec.ts +++ b/e2e/designer/real-api/custom-code.spec.ts @@ -1,5 +1,5 @@ import { test } from '@playwright/test'; -import { GoToWorkflow } from '../utils/GoToWorkflow'; +import { GoToRealWorkflow } from '../utils/GoToWorkflow'; test.describe( 'Custom Code', @@ -9,7 +9,7 @@ test.describe( () => { test('Inline Javascript', async ({ page, request, browserName }) => { await page.goto('/'); - await GoToWorkflow(page, `wapp-lauxtest2${browserName}`, 'inlineJS'); + await GoToRealWorkflow(page, `wapp-lauxtest2${browserName}`, 'inlineJS'); await page.getByRole('button', { name: 'Insert a new step between' }).first().click(); await page.getByText('Add an action').click(); diff --git a/e2e/designer/real-api/sanity-test.spec.ts b/e2e/designer/real-api/sanity-test.spec.ts index 85cbd4389cd..5ac7eb8cd9a 100644 --- a/e2e/designer/real-api/sanity-test.spec.ts +++ b/e2e/designer/real-api/sanity-test.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from '@playwright/test'; -import { GoToWorkflow } from '../utils/GoToWorkflow'; +import { GoToRealWorkflow } from '../utils/GoToWorkflow'; test.describe( 'Sanity Check', @@ -9,16 +9,16 @@ test.describe( () => { test('Sanity Check', async ({ page, request, browserName }) => { await page.goto('/'); - await GoToWorkflow(page, `wapp-lauxtest2${browserName}`, 'testWorkflow1'); + await GoToRealWorkflow(page, `wapp-lauxtest2${browserName}`, 'testWorkflow1'); await page.getByTestId('card-When a HTTP request is received').getByLabel('When a HTTP request is').click(); await page.getByRole('combobox', { name: 'Method' }).click(); await page.getByRole('option', { name: 'GET' }).click(); await page.getByLabel('Insert a new step after When').click(); await page.getByRole('menuitem', { name: 'Add an action' }).click(); - await page.getByPlaceholder('Search').fill('response',); + await page.getByPlaceholder('Search').fill('response'); await page.getByLabel('Response This is an incoming').click(); await page.getByLabel('Body').getByRole('paragraph').click(); - await page.getByLabel('Body').fill('Test Body',); + await page.getByLabel('Body').fill('Test Body'); await page.getByRole('menuitem', { name: 'Save Save' }).click(); await page.waitForResponse((resp) => resp.url().includes('/deployWorkflowArtifacts') && resp.status() === 200); diff --git a/e2e/designer/real-api/statelessvariables.spec.ts b/e2e/designer/real-api/statelessvariables.spec.ts index 98d8177641b..7dd433f2818 100644 --- a/e2e/designer/real-api/statelessvariables.spec.ts +++ b/e2e/designer/real-api/statelessvariables.spec.ts @@ -1,71 +1,79 @@ import { test } from '@playwright/test'; -import { GoToWorkflow } from '../utils/GoToWorkflow'; +import { GoToRealWorkflow } from '../utils/GoToWorkflow'; test.describe( - 'Stateless Variables', - { - tag: '@real', - }, - () => { - test('Variable Functionality works', async ({ page, request, browserName }) => { - await page.goto('/'); - await GoToWorkflow(page, `wapp-lauxtest2${browserName}`, 'statelessVariables'); - await page.getByRole('button', { name: 'Insert a new step between' }).first().click(); - await page.getByRole('menuitem', { name: 'Add an action' }).click(); - await page.getByPlaceholder('Search').click(); - await page.getByPlaceholder('Search').fill('init'); - await page.getByLabel('Initialize variable').click(); - await page.getByRole('paragraph').click(); + 'Stateless Variables', + { + tag: '@real', + }, + () => { + test('Variable Functionality works', async ({ page, request, browserName }) => { + await page.goto('/'); + await GoToRealWorkflow(page, `wapp-lauxtest2${browserName}`, 'statelessVariables'); + await page.getByRole('button', { name: 'Insert a new step between' }).first().click(); + await page.getByRole('menuitem', { name: 'Add an action' }).click(); + await page.getByPlaceholder('Search').click(); + await page.getByPlaceholder('Search').fill('init'); + await page.getByLabel('Initialize variable').click(); + await page.getByRole('paragraph').click(); - await page.getByLabel('Name').fill('v1'); - await page.getByText('Boolean').click(); - await page.getByRole('option', { name: 'Array' }).click(); - await page.getByLabel('Value').getByRole('paragraph').click(); - await page.getByLabel('Value').fill('[1,2]'); + await page.getByLabel('Name').fill('v1'); + await page.getByText('Boolean').click(); + await page.getByRole('option', { name: 'Array' }).click(); + await page.getByLabel('Value').getByRole('paragraph').click(); + await page.getByLabel('Value').fill('[1,2]'); - await page.locator('#msla-node-details-panel-Initialize_variable div').filter({ hasText: 'Namev1Add dynamic data or' }).first().click(); - await page.getByTestId('rf__edge-Initialize_variable-Response').getByLabel('Insert a new step between').click(); - await page.getByRole('menuitem', { name: 'Add an action' }).click(); - await page.getByPlaceholder('Search').fill('Append to array variable'); - await page.getByLabel('Append to array variable').click(); - await page.getByLabel('Name').locator('span').first().click(); - await page.getByRole('option', { name: 'v1' }).click(); - await page.getByRole('paragraph').click(); - await page.getByLabel('Value').fill('3'); - await page.getByTestId('rf__edge-Append_to_array_variable-Response').getByRole('button', { name: 'Insert a new step between' }).first().click(); - await page.getByText('Add an action').click(); - await page.getByPlaceholder('Search').fill('initalize'); - await page.getByLabel('Initialize variable Initializes a variable.').click(); - await page.getByRole('paragraph').click(); - await page.getByLabel('Name').fill('v2'); - await page.getByText('Boolean').click(); - await page.getByRole('option', { name: 'String' }).click(); - await page.getByLabel('Value').getByRole('paragraph').click(); - await page.getByLabel('Value').fill('foo'); - await page.getByTestId('rf__edge-Initialize_variable_1-Response').getByLabel('Insert a new step between').click(); - await page.getByRole('menuitem', { name: 'Add an action' }).click(); - await page.getByPlaceholder('Search').fill('append string'); - await page.getByLabel('Append to string variable').click(); - await page.getByLabel('Name').locator('span').first().click(); - await page.getByRole('option', { name: 'v2' }).click(); - await page.getByRole('paragraph').click(); - await page.getByLabel('Value').fill(browserName); - await page.getByLabel('Response operation, Request').click(); - await page.getByLabel('Body').getByRole('paragraph').click(); - await page.locator('button').filter({ hasText: '' }).click(); - await page.getByRole('button', { name: 'v1' }).click(); - await page.locator('button').filter({ hasText: '' }).click(); - await page.getByRole('button', { name: 'v2' }).click(); - await page.getByText('Advanced parametersShowing 0').click(); - await page.getByLabel('fit view').click(); - await page.getByRole('menuitem', { name: 'Save' }).click(); + await page + .locator('#msla-node-details-panel-Initialize_variable div') + .filter({ hasText: 'Namev1Add dynamic data or' }) + .first() + .click(); + await page.getByTestId('rf__edge-Initialize_variable-Response').getByLabel('Insert a new step between').click(); + await page.getByRole('menuitem', { name: 'Add an action' }).click(); + await page.getByPlaceholder('Search').fill('Append to array variable'); + await page.getByLabel('Append to array variable').click(); + await page.getByLabel('Name').locator('span').first().click(); + await page.getByRole('option', { name: 'v1' }).click(); + await page.getByRole('paragraph').click(); + await page.getByLabel('Value').fill('3'); + await page + .getByTestId('rf__edge-Append_to_array_variable-Response') + .getByRole('button', { name: 'Insert a new step between' }) + .first() + .click(); + await page.getByText('Add an action').click(); + await page.getByPlaceholder('Search').fill('initalize'); + await page.getByLabel('Initialize variable Initializes a variable.').click(); + await page.getByRole('paragraph').click(); + await page.getByLabel('Name').fill('v2'); + await page.getByText('Boolean').click(); + await page.getByRole('option', { name: 'String' }).click(); + await page.getByLabel('Value').getByRole('paragraph').click(); + await page.getByLabel('Value').fill('foo'); + await page.getByTestId('rf__edge-Initialize_variable_1-Response').getByLabel('Insert a new step between').click(); + await page.getByRole('menuitem', { name: 'Add an action' }).click(); + await page.getByPlaceholder('Search').fill('append string'); + await page.getByLabel('Append to string variable').click(); + await page.getByLabel('Name').locator('span').first().click(); + await page.getByRole('option', { name: 'v2' }).click(); + await page.getByRole('paragraph').click(); + await page.getByLabel('Value').fill(browserName); + await page.getByLabel('Response operation, Request').click(); + await page.getByLabel('Body').getByRole('paragraph').click(); + await page.locator('button').filter({ hasText: '' }).click(); + await page.getByRole('button', { name: 'v1' }).click(); + await page.locator('button').filter({ hasText: '' }).click(); + await page.getByRole('button', { name: 'v2' }).click(); + await page.getByText('Advanced parametersShowing 0').click(); + await page.getByLabel('fit view').click(); + await page.getByRole('menuitem', { name: 'Save' }).click(); - await page.waitForResponse((resp) => resp.url().includes('/deployWorkflowArtifacts') && resp.status() === 200); - await page.getByTestId('card-When a HTTP request is received').getByLabel('When a HTTP request is').click({ timeout: 20000 }); - const value = await page.getByRole('textbox', { name: 'URL will be generated after' }).inputValue(); - const LAResult = await request.get(value); - test.expect(LAResult.status()).toBe(200); - test.expect(await LAResult.text()).toBe(`[1,2,3]foo${browserName}`); - }); - } + await page.waitForResponse((resp) => resp.url().includes('/deployWorkflowArtifacts') && resp.status() === 200); + await page.getByTestId('card-When a HTTP request is received').getByLabel('When a HTTP request is').click({ timeout: 20000 }); + const value = await page.getByRole('textbox', { name: 'URL will be generated after' }).inputValue(); + const LAResult = await request.get(value); + test.expect(LAResult.status()).toBe(200); + test.expect(await LAResult.text()).toBe(`[1,2,3]foo${browserName}`); + }); + } ); diff --git a/e2e/designer/serialization.spec.ts b/e2e/designer/serialization.spec.ts index 47cd68a21b6..9bc36246704 100644 --- a/e2e/designer/serialization.spec.ts +++ b/e2e/designer/serialization.spec.ts @@ -1,78 +1,53 @@ import { test, expect } from '@playwright/test'; - -test( - 'Should serialize the workflow after deserializing it and match', +import { GoToMockWorkflow } from './utils/GoToWorkflow'; +import { getSerializedWorkflowFromState } from './utils/designerFunctions'; +test.describe( + 'Serialization Tests', { tag: '@mock', }, - async ({ page }) => { - await page.goto('/'); + () => { + test('Should serialize the workflow after deserializing it and match', async ({ page }) => { + await page.goto('/'); + + await GoToMockWorkflow(page, 'Panel'); - await page.locator('text=Select an option').click(); - await page.locator('button[role="option"]:has-text("Panel")').click(); - await page.locator('div[role="button"]:has-text("🧰")').click(); + const serialized: any = await getSerializedWorkflowFromState(page); - const serialized: any = await page.evaluate(() => { - return new Promise((resolve) => { - setTimeout(() => { - const state = (window as any).DesignerStore.getState(); - resolve((window as any).DesignerModule.serializeBJSWorkflow(state)); - }, 5000); + const mock = await import('../../__mocks__/workflows/Panel.json', { + assert: { type: 'json' }, }); - }); - const mock = await import('../../__mocks__/workflows/Panel.json', { - assert: { type: 'json' }, + expect({ connectionReferences: {}, parameters: {}, definition: mock.default.definition }).toEqual(serialized as any); }); - expect({ connectionReferences: {}, parameters: {}, definition: mock.default.definition }).toEqual(serialized as any); - } -); + test('Should serialize the workflow after deserializing it and match with a switch statement', async ({ page }) => { + await page.goto('/'); + await GoToMockWorkflow(page, 'Switch'); -test('Should serialize the workflow after deserializing it and match with a switch statement', async ({ page }) => { - await page.goto('/'); + const serialized: any = await getSerializedWorkflowFromState(page); - await page.locator('text=Select an option').click(); - await page.locator('button[role="option"]:has-text("Switch")').click(); - await page.locator('div[role="button"]:has-text("🧰")').click(); + const mock = await import('../../__mocks__/workflows/Switch.json', { + assert: { type: 'json' }, + }); - const serialized: any = await page.evaluate(() => { - return new Promise((resolve) => { - setTimeout(() => { - const state = (window as any).DesignerStore.getState(); - resolve((window as any).DesignerModule.serializeBJSWorkflow(state)); - }, 5000); + expect({ connectionReferences: {}, parameters: {}, definition: mock.default.definition }).toEqual(serialized as any); }); - }); - const mock = await import('../../__mocks__/workflows/Switch.json', { - assert: { type: 'json' }, - }); + test('Should serialize the workflow after deserializing it and match with some strings and keys containing unicode characters', async ({ + page, + }) => { + await page.goto('/'); - expect({ connectionReferences: {}, parameters: {}, definition: mock.default.definition }).toEqual(serialized as any); -}); + await GoToMockWorkflow(page, 'Unicode Keys'); -test('Should serialize the workflow after deserializing it and match with some strings and keys containing unicode characters', async ({ - page, -}) => { - await page.goto('/'); + const serialized: any = await getSerializedWorkflowFromState(page); - await page.locator('text=Select an option').click(); - await page.locator('button[role="option"]:has-text("Unicode Keys")').click(); - await page.locator('div[role="button"]:has-text("🧰")').click(); + const mock = await import('../../__mocks__/workflows/UnicodeKeys.json', { + assert: { type: 'json' }, + }); - const serialized: any = await page.evaluate(() => { - return new Promise((resolve) => { - setTimeout(() => { - const state = (window as any).DesignerStore.getState(); - resolve((window as any).DesignerModule.serializeBJSWorkflow(state)); - }, 5000); + expect({ connectionReferences: {}, parameters: {}, definition: mock.default.definition }).toEqual(serialized as any); }); - }); - - const mock = await import('../../__mocks__/workflows/UnicodeKeys.json', { - assert: { type: 'json' }, - }); - - expect({ connectionReferences: {}, parameters: {}, definition: mock.default.definition }).toEqual(serialized as any); -}); + } +); diff --git a/e2e/designer/utils/GoToWorkflow.ts b/e2e/designer/utils/GoToWorkflow.ts index df740d1dacb..04ca26606ec 100644 --- a/e2e/designer/utils/GoToWorkflow.ts +++ b/e2e/designer/utils/GoToWorkflow.ts @@ -1,10 +1,18 @@ import type { Page } from '@playwright/test'; -export const GoToWorkflow = async (page: Page, appName: string, workflowName) => { +export const GoToRealWorkflow = async (page: Page, appName: string, workflowName: string) => { await page.getByPlaceholder('Select an App').click(); await page.getByPlaceholder('Select an App').fill(appName); await page.getByPlaceholder('Select an App').press('Enter'); await page.getByLabel('Workflow').locator('span').filter({ hasText: '' }).click(); await page.getByRole('option', { name: workflowName }).click(); await page.getByRole('button', { name: 'Toolbox' }).click(); + await page.getByLabel('fit view').click({ force: true }); +}; + +export const GoToMockWorkflow = async (page: Page, workflowName: string) => { + await page.getByText('Select an option').click(); + await page.getByRole('option', { name: workflowName }).click(); + await page.getByRole('button', { name: 'Toolbox' }).click(); + await page.getByLabel('fit view').click({ force: true }); }; diff --git a/e2e/designer/utils/designerFunctions.ts b/e2e/designer/utils/designerFunctions.ts new file mode 100644 index 00000000000..cc73b877aa7 --- /dev/null +++ b/e2e/designer/utils/designerFunctions.ts @@ -0,0 +1,8 @@ +import type { Page } from '@playwright/test'; + +export const getSerializedWorkflowFromState = (page: Page) => { + return page.evaluate(async () => { + const state = (window as any).DesignerStore.getState(); + return await (window as any).DesignerModule.serializeBJSWorkflow(state); + }); +}; diff --git a/playwright.config.ts b/playwright.config.ts index b5c24f4b877..7483260c80d 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -24,7 +24,11 @@ export default defineConfig({ timeout: 5 * 60 * 1_000, expect: { // expect timeout set to 20 seconds - timeout: 20 * 1000 + timeout: 20 * 1000, + }, + reportSlowTests: { + threshold: 60 * 1_000, + max: 10, }, /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { @@ -51,14 +55,14 @@ export default defineConfig({ 'dom.events.asyncClipboard.readText': true, 'dom.events.testing.asyncClipboard': true, }, - } + }, }, }, - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] }, + // }, /* Test against mobile viewports. */ // {