diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index de9d4e5e..30d36c76 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -3,13 +3,12 @@ on:
push:
branches:
- main
- # TODO: Add pull request after optimizing the total excecution time of the test suite.
- # pull_request:
- # paths:
- # - 'packages/backend/**'
- # - 'packages/e2e-tests/**'
- # - 'packages/web/**'
- # - '!packages/backend/src/apps/**'
+ pull_request:
+ paths:
+ - 'packages/backend/**'
+ - 'packages/e2e-tests/**'
+ - 'packages/web/**'
+ - '!packages/backend/src/apps/**'
workflow_dispatch:
env:
@@ -56,27 +55,44 @@ jobs:
steps:
- uses: actions/checkout@v3
- - uses: actions/setup-node@v3
+ - uses: actions/setup-node@v4
with:
- node-version: 18
- - name: Install web dependencies
- run: yarn
- working-directory: ./packages/web
+ node-version: '18'
+ cache: 'yarn'
+ cache-dependency-path: |
+ packages/backend/yarn.lock
+ packages/web/yarn.lock
+ packages/e2e-tests/yarn.lock
- name: Install backend dependencies
- run: yarn
+ run: yarn --frozen-lockfile
working-directory: ./packages/backend
+ - name: Install web dependencies
+ run: yarn --frozen-lockfile
+ working-directory: ./packages/web
- name: Install e2e-tests dependencies
- run: yarn
+ run: yarn --frozen-lockfile
working-directory: ./packages/e2e-tests
+ - name: Get installed Playwright version
+ id: playwright-version
+ run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package.json').devDependencies['@playwright/test'])")" >> $GITHUB_ENV
+ working-directory: ./packages/e2e-tests
+ - name: Cache playwright binaries
+ uses: actions/cache@v3
+ id: playwright-cache
+ with:
+ path: |
+ ~/.cache/ms-playwright
+ key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Install Playwright Browsers
run: yarn playwright install --with-deps
working-directory: ./packages/e2e-tests
+ if: steps.playwright-cache.outputs.cache-hit != 'true'
- name: Build Automatisch web
run: yarn build
- working-directory: ./packages/web
env:
# Keep this until we clean up warnings in build processes
CI: false
+ working-directory: ./packages/web
- name: Migrate database
working-directory: ./packages/backend
run: yarn db:migrate
@@ -116,6 +132,7 @@ jobs:
env:
LOGIN_EMAIL: user@automatisch.io
LOGIN_PASSWORD: sample
+ BACKEND_APP_URL: http://localhost:3000
BASE_URL: http://localhost:3000
GITHUB_CLIENT_ID: 1c0417daf898adfbd99a
GITHUB_CLIENT_SECRET: 3328fa814dd582ccd03dbe785cfd683fb8da92b3
diff --git a/packages/e2e-tests/.env-example b/packages/e2e-tests/.env-example
index b7a2b62f..0cf8775e 100644
--- a/packages/e2e-tests/.env-example
+++ b/packages/e2e-tests/.env-example
@@ -2,4 +2,5 @@ POSTGRES_DB=automatisch
POSTGRES_USER=automatisch_user
POSTGRES_PASSWORD=automatisch_password
POSTGRES_PORT=5432
-POSTGRES_HOST=localhost
\ No newline at end of file
+POSTGRES_HOST=localhost
+BACKEND_APP_URL=http://localhost:3000
\ No newline at end of file
diff --git a/packages/e2e-tests/fixtures/admin/application-settings-page.js b/packages/e2e-tests/fixtures/admin/application-settings-page.js
index 57858ccb..da421b24 100644
--- a/packages/e2e-tests/fixtures/admin/application-settings-page.js
+++ b/packages/e2e-tests/fixtures/admin/application-settings-page.js
@@ -56,8 +56,10 @@ export class AdminApplicationSettingsPage extends AuthenticatedPage {
}
async expectSuccessSnackbarToBeVisible() {
- await expect(this.successSnackbar).toHaveCount(1);
- await this.successSnackbar.click();
- await expect(this.successSnackbar).toHaveCount(0);
+ const snackbars = await this.successSnackbar.all();
+ for (const snackbar of snackbars) {
+ await expect(await snackbar.getAttribute('data-snackbar-variant')).toBe('success');
+ await snackbar.click();
+ }
}
}
diff --git a/packages/e2e-tests/fixtures/admin/create-role-page.js b/packages/e2e-tests/fixtures/admin/create-role-page.js
index 3426e520..fe0ecde0 100644
--- a/packages/e2e-tests/fixtures/admin/create-role-page.js
+++ b/packages/e2e-tests/fixtures/admin/create-role-page.js
@@ -1,3 +1,5 @@
+import { expect } from '@playwright/test';
+
const { AuthenticatedPage } = require('../authenticated-page');
const { RoleConditionsModal } = require('./role-conditions-modal');
@@ -16,6 +18,7 @@ export class AdminCreateRolePage extends AuthenticatedPage {
this.executionRow = page.getByTestId('Execution-permission-row');
this.flowRow = page.getByTestId('Flow-permission-row');
this.pageTitle = page.getByTestId('create-role-title');
+ this.permissionsCatalog = page.getByTestId('permissions-catalog');
}
/**
@@ -104,4 +107,8 @@ export class AdminCreateRolePage extends AuthenticatedPage {
throw new Error(`${subject} does not have action ${action}`);
}
}
+
+ async waitForPermissionsCatalogToVisible() {
+ await expect(this.permissionsCatalog).toBeVisible();
+ }
}
diff --git a/packages/e2e-tests/fixtures/admin/create-user-page.js b/packages/e2e-tests/fixtures/admin/create-user-page.js
index 135b38fb..e59ba2c5 100644
--- a/packages/e2e-tests/fixtures/admin/create-user-page.js
+++ b/packages/e2e-tests/fixtures/admin/create-user-page.js
@@ -14,8 +14,12 @@ export class AdminCreateUserPage extends AuthenticatedPage {
this.roleInput = page.getByTestId('role.id-autocomplete');
this.createButton = page.getByTestId('create-button');
this.pageTitle = page.getByTestId('create-user-title');
- this.invitationEmailInfoAlert = page.getByTestId('invitation-email-info-alert');
- this.acceptInvitationLink = page.getByTestId('invitation-email-info-alert').getByRole('link');
+ this.invitationEmailInfoAlert = page.getByTestId(
+ 'invitation-email-info-alert'
+ );
+ this.acceptInvitationLink = page
+ .getByTestId('invitation-email-info-alert')
+ .getByRole('link');
}
seed(seed) {
diff --git a/packages/e2e-tests/fixtures/admin/users-page.js b/packages/e2e-tests/fixtures/admin/users-page.js
index af6dbac3..6b7f6263 100644
--- a/packages/e2e-tests/fixtures/admin/users-page.js
+++ b/packages/e2e-tests/fixtures/admin/users-page.js
@@ -95,7 +95,6 @@ export class AdminUsersPage extends AuthenticatedPage {
});
}
const rowLocator = await this.getUserRowByEmail(email);
- console.log('rowLocator.count', email, await rowLocator.count());
if ((await rowLocator.count()) === 1) {
return rowLocator;
}
diff --git a/packages/e2e-tests/fixtures/base-page.js b/packages/e2e-tests/fixtures/base-page.js
index 1b057899..ade03437 100644
--- a/packages/e2e-tests/fixtures/base-page.js
+++ b/packages/e2e-tests/fixtures/base-page.js
@@ -51,10 +51,20 @@ export class BasePage {
};
}
+ async closeSnackbar() {
+ await this.snackbar.click();
+ }
+
+ async closeSnackbarAndWaitUntilDetached() {
+ const snackbar = await this.snackbar;
+ await snackbar.click();
+ await snackbar.waitFor({ state: 'detached' });
+ }
+
/**
* Closes all snackbars, should be replaced later
*/
- async closeSnackbar() {
+ async closeAllSnackbars() {
const snackbars = await this.snackbar.all();
for (const snackbar of snackbars) {
await snackbar.click();
diff --git a/packages/e2e-tests/helpers/auth-api-helper.js b/packages/e2e-tests/helpers/auth-api-helper.js
new file mode 100644
index 00000000..f8067ede
--- /dev/null
+++ b/packages/e2e-tests/helpers/auth-api-helper.js
@@ -0,0 +1,16 @@
+const { expect } = require('../fixtures/index');
+
+export const getToken = async (apiRequest) => {
+ const tokenResponse = await apiRequest.post(
+ `${process.env.BACKEND_APP_URL}/api/v1/access-tokens`,
+ {
+ data: {
+ email: process.env.LOGIN_EMAIL,
+ password: process.env.LOGIN_PASSWORD,
+ },
+ }
+ );
+ await expect(tokenResponse.status()).toBe(200);
+
+ return await tokenResponse.json();
+};
diff --git a/packages/e2e-tests/helpers/flow-api-helper.js b/packages/e2e-tests/helpers/flow-api-helper.js
new file mode 100644
index 00000000..525274a8
--- /dev/null
+++ b/packages/e2e-tests/helpers/flow-api-helper.js
@@ -0,0 +1,69 @@
+const { expect } = require('../fixtures/index');
+
+export const createFlow = async (request, token) => {
+ const response = await request.post(
+ `${process.env.BACKEND_APP_URL}/api/v1/flows`,
+ { headers: { Authorization: token } }
+ );
+ await expect(response.status()).toBe(201);
+ return await response.json();
+};
+
+export const getFlow = async (request, token, flowId) => {
+ const response = await request.get(
+ `${process.env.BACKEND_APP_URL}/api/v1/flows/${flowId}`,
+ { headers: { Authorization: token } }
+ );
+ await expect(response.status()).toBe(200);
+ return await response.json();
+};
+
+export const updateFlowName = async (request, token, flowId) => {
+ const updateFlowNameResponse = await request.patch(
+ `${process.env.BACKEND_APP_URL}/api/v1/flows/${flowId}`,
+ {
+ headers: { Authorization: token },
+ data: { name: flowId },
+ }
+ );
+ await expect(updateFlowNameResponse.status()).toBe(200);
+};
+
+export const updateFlowStep = async (request, token, stepId, requestBody) => {
+ const updateTriggerStepResponse = await request.patch(
+ `${process.env.BACKEND_APP_URL}/api/v1/steps/${stepId}`,
+ {
+ headers: { Authorization: token },
+ data: requestBody,
+ }
+ );
+ await expect(updateTriggerStepResponse.status()).toBe(200);
+ return await updateTriggerStepResponse.json();
+};
+
+export const testStep = async (request, token, stepId) => {
+ const testTriggerStepResponse = await request.post(
+ `${process.env.BACKEND_APP_URL}/api/v1/steps/${stepId}/test`,
+ {
+ headers: { Authorization: token },
+ }
+ );
+ await expect(testTriggerStepResponse.status()).toBe(200);
+};
+
+export const publishFlow = async (request, token, flowId) => {
+ const publishFlowResponse = await request.patch(
+ `${process.env.BACKEND_APP_URL}/api/v1/flows/${flowId}/status`,
+ {
+ headers: { Authorization: token },
+ data: { active: true },
+ }
+ );
+ await expect(publishFlowResponse.status()).toBe(200);
+ return publishFlowResponse.json();
+};
+
+export const triggerFlow = async (request, url) => {
+ const triggerFlowResponse = await request.get(url);
+ await expect(triggerFlowResponse.status()).toBe(204);
+};
diff --git a/packages/e2e-tests/helpers/user-api-helper.js b/packages/e2e-tests/helpers/user-api-helper.js
new file mode 100644
index 00000000..57d96e75
--- /dev/null
+++ b/packages/e2e-tests/helpers/user-api-helper.js
@@ -0,0 +1,24 @@
+const { expect } = require('../fixtures/index');
+
+export const addUser = async (apiRequest, token, request) => {
+ const addUserResponse = await apiRequest.post(
+ `${process.env.BACKEND_APP_URL}/api/v1/admin/users`,
+ {
+ headers: { Authorization: token },
+ data: request,
+ }
+ );
+ await expect(addUserResponse.status()).toBe(201);
+
+ return await addUserResponse.json();
+};
+
+export const acceptInvitation = async (apiRequest, request) => {
+ const acceptInvitationResponse = await apiRequest.post(
+ `${process.env.BACKEND_APP_URL}/api/v1/users/invitation`,
+ {
+ data: request,
+ }
+ );
+ await expect(acceptInvitationResponse.status()).toBe(204);
+};
diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json
index ddb5979d..4ad6bd10 100644
--- a/packages/e2e-tests/package.json
+++ b/packages/e2e-tests/package.json
@@ -26,7 +26,7 @@
},
"devDependencies": {
"@faker-js/faker": "^8.2.0",
- "@playwright/test": "^1.45.1"
+ "@playwright/test": "1.49.0"
},
"dependencies": {
"axios": "^1.6.0",
@@ -40,4 +40,4 @@
"pg": "^8.12.0",
"prettier": "^2.5.1"
}
-}
+}
\ No newline at end of file
diff --git a/packages/e2e-tests/playwright.config.js b/packages/e2e-tests/playwright.config.js
index ec034c39..6ba4656c 100644
--- a/packages/e2e-tests/playwright.config.js
+++ b/packages/e2e-tests/playwright.config.js
@@ -15,9 +15,9 @@ module.exports = defineConfig({
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
- retries: 0,
+ retries: process.env.CI ? 1 : 0,
/* Opt out of parallel tests on CI. */
- workers: process.env.CI ? 1 : undefined,
+ workers: undefined,
/* Timeout threshold for each test */
timeout: 30000,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
@@ -30,7 +30,7 @@ module.exports = defineConfig({
baseURL: process.env.BASE_URL || 'http://localhost:3001',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
- trace: 'retain-on-failure',
+ trace: 'on-first-retry',
testIdAttribute: 'data-test',
viewport: { width: 1280, height: 720 },
},
diff --git a/packages/e2e-tests/tests/admin/applications.spec.js b/packages/e2e-tests/tests/admin/applications.spec.js
index 2fad49b9..94a2d3a1 100644
--- a/packages/e2e-tests/tests/admin/applications.spec.js
+++ b/packages/e2e-tests/tests/admin/applications.spec.js
@@ -5,16 +5,18 @@ test.describe('Admin Applications', () => {
test.beforeAll(async () => {
const deleteAppAuthClients = {
text: 'DELETE FROM app_auth_clients WHERE app_key in ($1, $2, $3, $4, $5)',
- values: ['carbone', 'spotify', 'deepl', 'mailchimp', 'reddit']
+ values: ['carbone', 'spotify', 'deepl', 'mailchimp', 'reddit'],
};
const deleteAppConfigs = {
text: 'DELETE FROM app_configs WHERE key in ($1, $2, $3, $4, $5)',
- values: ['carbone', 'spotify', 'deepl', 'mailchimp', 'reddit']
+ values: ['carbone', 'spotify', 'deepl', 'mailchimp', 'reddit'],
};
try {
- const deleteAppAuthClientsResult = await pgPool.query(deleteAppAuthClients);
+ const deleteAppAuthClientsResult = await pgPool.query(
+ deleteAppAuthClients
+ );
expect(deleteAppAuthClientsResult.command).toBe('DELETE');
const deleteAppConfigsResult = await pgPool.query(deleteAppConfigs);
expect(deleteAppConfigsResult.command).toBe('DELETE');
@@ -31,7 +33,7 @@ test.describe('Admin Applications', () => {
test('Admin should be able to toggle Application settings', async ({
adminApplicationsPage,
adminApplicationSettingsPage,
- page
+ page,
}) => {
await adminApplicationsPage.openApplication('Carbone');
await expect(page.url()).toContain('/admin-settings/apps/carbone/settings');
@@ -57,7 +59,7 @@ test.describe('Admin Applications', () => {
adminApplicationsPage,
adminApplicationSettingsPage,
flowEditorPage,
- page
+ page,
}) => {
await adminApplicationsPage.openApplication('Spotify');
await expect(page.url()).toContain('/admin-settings/apps/spotify/settings');
@@ -75,11 +77,15 @@ test.describe('Admin Applications', () => {
const triggerStep = flowEditorPage.flowStep.last();
await triggerStep.click();
- await flowEditorPage.chooseAppAndEvent("Spotify", "Create Playlist");
+ await flowEditorPage.chooseAppAndEvent('Spotify', 'Create Playlist');
await flowEditorPage.connectionAutocomplete.click();
- const newConnectionOption = page.getByRole('option').filter({ hasText: 'Add new connection' });
- const newSharedConnectionOption = page.getByRole('option').filter({ hasText: 'Add new shared connection' });
+ const newConnectionOption = page
+ .getByRole('option')
+ .filter({ hasText: 'Add new connection' });
+ const newSharedConnectionOption = page
+ .getByRole('option')
+ .filter({ hasText: 'Add new shared connection' });
await expect(newConnectionOption).toBeEnabled();
await expect(newConnectionOption).toHaveCount(1);
@@ -91,7 +97,7 @@ test.describe('Admin Applications', () => {
adminApplicationSettingsPage,
adminApplicationAuthClientsPage,
flowEditorPage,
- page
+ page,
}) => {
await adminApplicationsPage.openApplication('Reddit');
await expect(page.url()).toContain('/admin-settings/apps/reddit/settings');
@@ -101,13 +107,21 @@ test.describe('Admin Applications', () => {
await adminApplicationAuthClientsPage.openAuthClientsTab();
await adminApplicationAuthClientsPage.openFirstAuthClientCreateForm();
- const authClientForm = page.getByTestId("auth-client-form");
+ const authClientForm = page.getByTestId('auth-client-form');
await authClientForm.locator(page.getByTestId('switch')).check();
- await authClientForm.locator(page.locator('[name="name"]')).fill('redditAuthClient');
- await authClientForm.locator(page.locator('[name="clientId"]')).fill('redditClientId');
- await authClientForm.locator(page.locator('[name="clientSecret"]')).fill('redditClientSecret');
+ await authClientForm
+ .locator(page.locator('[name="name"]'))
+ .fill('redditAuthClient');
+ await authClientForm
+ .locator(page.locator('[name="clientId"]'))
+ .fill('redditClientId');
+ await authClientForm
+ .locator(page.locator('[name="clientSecret"]'))
+ .fill('redditClientSecret');
await adminApplicationAuthClientsPage.submitAuthClientForm();
- await adminApplicationAuthClientsPage.authClientShouldBeVisible('redditAuthClient');
+ await adminApplicationAuthClientsPage.authClientShouldBeVisible(
+ 'redditAuthClient'
+ );
await page.goto('/');
await page.getByTestId('create-flow-button').click();
@@ -119,11 +133,15 @@ test.describe('Admin Applications', () => {
const triggerStep = flowEditorPage.flowStep.last();
await triggerStep.click();
- await flowEditorPage.chooseAppAndEvent("Reddit", "Create link post");
+ await flowEditorPage.chooseAppAndEvent('Reddit', 'Create link post');
await flowEditorPage.connectionAutocomplete.click();
- const newConnectionOption = page.getByRole('option').filter({ hasText: 'Add new connection' });
- const newSharedConnectionOption = page.getByRole('option').filter({ hasText: 'Add new shared connection' });
+ const newConnectionOption = page
+ .getByRole('option')
+ .filter({ hasText: 'Add new connection' });
+ const newSharedConnectionOption = page
+ .getByRole('option')
+ .filter({ hasText: 'Add new shared connection' });
await expect(newConnectionOption).toHaveCount(0);
await expect(newSharedConnectionOption).toBeEnabled();
@@ -134,7 +152,7 @@ test.describe('Admin Applications', () => {
adminApplicationsPage,
adminApplicationSettingsPage,
flowEditorPage,
- page
+ page,
}) => {
await adminApplicationsPage.openApplication('DeepL');
await expect(page.url()).toContain('/admin-settings/apps/deepl/settings');
@@ -152,12 +170,18 @@ test.describe('Admin Applications', () => {
const triggerStep = flowEditorPage.flowStep.last();
await triggerStep.click();
- await flowEditorPage.chooseAppAndEvent("DeepL", "Translate text");
+ await flowEditorPage.chooseAppAndEvent('DeepL', 'Translate text');
await flowEditorPage.connectionAutocomplete.click();
- const newConnectionOption = page.getByRole('option').filter({ hasText: 'Add new connection' });
- const newSharedConnectionOption = page.getByRole('option').filter({ hasText: 'Add new shared connection' });
- const noConnectionsOption = page.locator('.MuiAutocomplete-noOptions').filter({ hasText: 'No options' });
+ const newConnectionOption = page
+ .getByRole('option')
+ .filter({ hasText: 'Add new connection' });
+ const newSharedConnectionOption = page
+ .getByRole('option')
+ .filter({ hasText: 'Add new shared connection' });
+ const noConnectionsOption = page
+ .locator('.MuiAutocomplete-noOptions')
+ .filter({ hasText: 'No options' });
await expect(noConnectionsOption).toHaveCount(1);
await expect(newConnectionOption).toHaveCount(0);
@@ -168,11 +192,11 @@ test.describe('Admin Applications', () => {
adminApplicationsPage,
adminApplicationSettingsPage,
flowEditorPage,
- page
+ page,
}) => {
const queryUser = {
text: 'SELECT * FROM users WHERE email = $1',
- values: [process.env.LOGIN_EMAIL]
+ values: [process.env.LOGIN_EMAIL],
};
try {
@@ -183,14 +207,16 @@ test.describe('Admin Applications', () => {
text: 'INSERT INTO connections (key, data, user_id, verified, draft) VALUES ($1, $2, $3, $4, $5)',
values: [
'mailchimp',
- "U2FsdGVkX1+cAtdHwLiuRL4DaK/T1aljeeKyPMmtWK0AmAIsKhYwQiuyQCYJO3mdZ31z73hqF2Y+yj2Kn2/IIpLRqCxB2sC0rCDCZyolzOZ290YcBXSzYRzRUxhoOcZEtwYDKsy8AHygKK/tkj9uv9k6wOe1LjipNik4VmRhKjEYizzjLrJpbeU1oY+qW0GBpPYomFTeNf+MejSSmsUYyYJ8+E/4GeEfaonvsTSwMT7AId98Lck6Vy4wrfgpm7sZZ8xU15/HqXZNc8UCo2iTdw45xj/Oov9+brX4WUASFPG8aYrK8dl/EdaOvr89P8uIofbSNZ25GjJvVF5ymarrPkTZ7djjJXchzpwBY+7GTJfs3funR/vIk0Hq95jgOFFP1liZyqTXSa49ojG3hzojRQ==",
+ 'U2FsdGVkX1+cAtdHwLiuRL4DaK/T1aljeeKyPMmtWK0AmAIsKhYwQiuyQCYJO3mdZ31z73hqF2Y+yj2Kn2/IIpLRqCxB2sC0rCDCZyolzOZ290YcBXSzYRzRUxhoOcZEtwYDKsy8AHygKK/tkj9uv9k6wOe1LjipNik4VmRhKjEYizzjLrJpbeU1oY+qW0GBpPYomFTeNf+MejSSmsUYyYJ8+E/4GeEfaonvsTSwMT7AId98Lck6Vy4wrfgpm7sZZ8xU15/HqXZNc8UCo2iTdw45xj/Oov9+brX4WUASFPG8aYrK8dl/EdaOvr89P8uIofbSNZ25GjJvVF5ymarrPkTZ7djjJXchzpwBY+7GTJfs3funR/vIk0Hq95jgOFFP1liZyqTXSa49ojG3hzojRQ==',
queryUserResult.rows[0].id,
'true',
- 'false'
+ 'false',
],
};
- const createMailchimpConnectionResult = await pgPool.query(createMailchimpConnection);
+ const createMailchimpConnectionResult = await pgPool.query(
+ createMailchimpConnection
+ );
expect(createMailchimpConnectionResult.rowCount).toBe(1);
expect(createMailchimpConnectionResult.command).toBe('INSERT');
} catch (err) {
@@ -199,7 +225,9 @@ test.describe('Admin Applications', () => {
}
await adminApplicationsPage.openApplication('Mailchimp');
- await expect(page.url()).toContain('/admin-settings/apps/mailchimp/settings');
+ await expect(page.url()).toContain(
+ '/admin-settings/apps/mailchimp/settings'
+ );
await adminApplicationSettingsPage.disallowConnections();
await adminApplicationSettingsPage.expectSuccessSnackbarToBeVisible();
@@ -214,14 +242,22 @@ test.describe('Admin Applications', () => {
const triggerStep = flowEditorPage.flowStep.last();
await triggerStep.click();
- await flowEditorPage.chooseAppAndEvent("Mailchimp", "Create campaign");
+ await flowEditorPage.chooseAppAndEvent('Mailchimp', 'Create campaign');
await flowEditorPage.connectionAutocomplete.click();
await expect(page.getByRole('option').first()).toHaveText('Unnamed');
- const existingConnection = page.getByRole('option').filter({ hasText: 'Unnamed' });
- const newConnectionOption = page.getByRole('option').filter({ hasText: 'Add new connection' });
- const newSharedConnectionOption = page.getByRole('option').filter({ hasText: 'Add new shared connection' });
- const noConnectionsOption = page.locator('.MuiAutocomplete-noOptions').filter({ hasText: 'No options' });
+ const existingConnection = page
+ .getByRole('option')
+ .filter({ hasText: 'Unnamed' });
+ const newConnectionOption = page
+ .getByRole('option')
+ .filter({ hasText: 'Add new connection' });
+ const newSharedConnectionOption = page
+ .getByRole('option')
+ .filter({ hasText: 'Add new shared connection' });
+ const noConnectionsOption = page
+ .locator('.MuiAutocomplete-noOptions')
+ .filter({ hasText: 'No options' });
await expect(await existingConnection.count()).toBeGreaterThan(0);
await expect(noConnectionsOption).toHaveCount(0);
diff --git a/packages/e2e-tests/tests/admin/manage-roles.spec.js b/packages/e2e-tests/tests/admin/manage-roles.spec.js
index 00299c5d..fd6b9385 100644
--- a/packages/e2e-tests/tests/admin/manage-roles.spec.js
+++ b/packages/e2e-tests/tests/admin/manage-roles.spec.js
@@ -22,22 +22,18 @@ test.describe('Role management page', () => {
await adminRolesPage.navigateTo();
await adminRolesPage.createRoleButton.click();
await adminCreateRolePage.isMounted();
+ await adminCreateRolePage.waitForPermissionsCatalogToVisible();
await adminCreateRolePage.nameInput.fill('Create Edit Test');
await adminCreateRolePage.descriptionInput.fill('Test description');
await adminCreateRolePage.createButton.click();
- await adminCreateRolePage.snackbar.waitFor({
- state: 'attached',
- });
const snackbar = await adminCreateRolePage.getSnackbarData(
'snackbar-create-role-success'
);
await expect(snackbar.variant).toBe('success');
- await adminCreateRolePage.closeSnackbar();
});
- let roleRow = await test.step(
- 'Make sure role data is correct',
- async () => {
+ let roleRow =
+ await test.step('Make sure role data is correct', async () => {
const roleRow = await adminRolesPage.getRoleRowByName(
'Create Edit Test'
);
@@ -48,8 +44,7 @@ test.describe('Role management page', () => {
await expect(roleData.canEdit).toBe(true);
await expect(roleData.canDelete).toBe(true);
return roleRow;
- }
- );
+ });
await test.step('Edit the role', async () => {
await adminRolesPage.clickEditRole(roleRow);
@@ -57,19 +52,14 @@ test.describe('Role management page', () => {
await adminEditRolePage.nameInput.fill('Create Update Test');
await adminEditRolePage.descriptionInput.fill('Update test description');
await adminEditRolePage.updateButton.click();
- await adminEditRolePage.snackbar.waitFor({
- state: 'attached',
- });
const snackbar = await adminEditRolePage.getSnackbarData(
'snackbar-edit-role-success'
);
await expect(snackbar.variant).toBe('success');
- await adminEditRolePage.closeSnackbar();
});
- roleRow = await test.step(
- 'Make sure changes reflected on roles page',
- async () => {
+ roleRow =
+ await test.step('Make sure changes reflected on roles page', async () => {
await adminRolesPage.isMounted();
const roleRow = await adminRolesPage.getRoleRowByName(
'Create Update Test'
@@ -81,8 +71,7 @@ test.describe('Role management page', () => {
await expect(roleData.canEdit).toBe(true);
await expect(roleData.canDelete).toBe(true);
return roleRow;
- }
- );
+ });
await test.step('Delete the role', async () => {
await adminRolesPage.clickDeleteRole(roleRow);
@@ -91,14 +80,10 @@ test.describe('Role management page', () => {
state: 'attached',
});
await deleteModal.deleteButton.click();
- await adminRolesPage.snackbar.waitFor({
- state: 'attached',
- });
const snackbar = await adminRolesPage.getSnackbarData(
'snackbar-delete-role-success'
);
await expect(snackbar.variant).toBe('success');
- await adminRolesPage.closeSnackbar();
await deleteModal.modal.waitFor({
state: 'detached',
});
@@ -173,60 +158,45 @@ test.describe('Role management page', () => {
await test.step('Create a new role', async () => {
await adminRolesPage.createRoleButton.click();
await adminCreateRolePage.isMounted();
+ await adminCreateRolePage.waitForPermissionsCatalogToVisible();
await adminCreateRolePage.nameInput.fill('Delete Role');
await adminCreateRolePage.createButton.click();
- await adminCreateRolePage.snackbar.waitFor({
- state: 'attached',
- });
const snackbar = await adminCreateRolePage.getSnackbarData(
'snackbar-create-role-success'
);
await expect(snackbar.variant).toBe('success');
- await adminCreateRolePage.closeSnackbar();
});
- await test.step(
- 'Create a new user with the "Delete Role" role',
- async () => {
- await adminUsersPage.navigateTo();
- await adminUsersPage.createUserButton.click();
- await adminCreateUserPage.fullNameInput.fill('User Role Test');
- await adminCreateUserPage.emailInput.fill(
- 'user-role-test@automatisch.io'
- );
- await adminCreateUserPage.roleInput.click();
- await adminCreateUserPage.page
- .getByRole('option', { name: 'Delete Role', exact: true })
- .click();
- await adminCreateUserPage.createButton.click();
- await adminCreateUserPage.snackbar.waitFor({
- state: 'attached',
- });
- await adminCreateUserPage.invitationEmailInfoAlert.waitFor({
- state: 'attached',
- });
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-create-user-success'
- );
- await expect(snackbar.variant).toBe('success');
- await adminUsersPage.closeSnackbar();
- }
- );
- await test.step(
- 'Try to delete "Delete Role" role when new user has it',
- async () => {
- await adminRolesPage.navigateTo();
- const row = await adminRolesPage.getRoleRowByName('Delete Role');
- const modal = await adminRolesPage.clickDeleteRole(row);
- await modal.deleteButton.click();
- await adminRolesPage.snackbar.waitFor({
- state: 'attached',
- });
- const snackbar = await adminRolesPage.getSnackbarData('snackbar-delete-role-error');
- await expect(snackbar.variant).toBe('error');
- await adminRolesPage.closeSnackbar();
- await modal.close();
- }
- );
+ await test.step('Create a new user with the "Delete Role" role', async () => {
+ await adminUsersPage.navigateTo();
+ await adminUsersPage.createUserButton.click();
+ await adminCreateUserPage.fullNameInput.fill('User Role Test');
+ await adminCreateUserPage.emailInput.fill(
+ 'user-role-test@automatisch.io'
+ );
+ await adminCreateUserPage.roleInput.click();
+ await adminCreateUserPage.page
+ .getByRole('option', { name: 'Delete Role', exact: true })
+ .click();
+ await adminCreateUserPage.createButton.click();
+ await adminCreateUserPage.invitationEmailInfoAlert.waitFor({
+ state: 'attached',
+ });
+ const snackbar = await adminUsersPage.getSnackbarData(
+ 'snackbar-create-user-success'
+ );
+ await expect(snackbar.variant).toBe('success');
+ });
+ await test.step('Try to delete "Delete Role" role when new user has it', async () => {
+ await adminRolesPage.navigateTo();
+ const row = await adminRolesPage.getRoleRowByName('Delete Role');
+ const modal = await adminRolesPage.clickDeleteRole(row);
+ await modal.deleteButton.click();
+ const snackbar = await adminRolesPage.getSnackbarData(
+ 'snackbar-delete-role-error'
+ );
+ await expect(snackbar.variant).toBe('error');
+ await modal.close();
+ });
await test.step('Change the role the user has', async () => {
await adminUsersPage.navigateTo();
await adminUsersPage.usersLoader.waitFor({
@@ -241,14 +211,10 @@ test.describe('Role management page', () => {
.getByRole('option', { name: 'Admin' })
.click();
await adminEditUserPage.updateButton.click();
- await adminEditUserPage.snackbar.waitFor({
- state: 'attached',
- });
const snackbar = await adminEditUserPage.getSnackbarData(
'snackbar-edit-user-success'
);
await expect(snackbar.variant).toBe('success');
- await adminEditUserPage.closeSnackbar();
});
await test.step('Delete the original role', async () => {
await adminRolesPage.navigateTo();
@@ -256,14 +222,10 @@ test.describe('Role management page', () => {
const modal = await adminRolesPage.clickDeleteRole(row);
await expect(modal.modal).toBeVisible();
await modal.deleteButton.click();
- await adminRolesPage.snackbar.waitFor({
- state: 'attached',
- });
const snackbar = await adminRolesPage.getSnackbarData(
'snackbar-delete-role-success'
);
await expect(snackbar.variant).toBe('success');
- await adminRolesPage.closeSnackbar();
});
});
@@ -277,16 +239,13 @@ test.describe('Role management page', () => {
await test.step('Create a new role', async () => {
await adminRolesPage.createRoleButton.click();
await adminCreateRolePage.isMounted();
+ await adminCreateRolePage.waitForPermissionsCatalogToVisible();
await adminCreateRolePage.nameInput.fill('Cannot Delete Role');
await adminCreateRolePage.createButton.click();
- await adminCreateRolePage.snackbar.waitFor({
- state: 'attached',
- });
const snackbar = await adminCreateRolePage.getSnackbarData(
'snackbar-create-role-success'
);
await expect(snackbar.variant).toBe('success');
- await adminCreateRolePage.closeSnackbar();
});
await test.step('Create a new user with this role', async () => {
await adminUsersPage.navigateTo();
@@ -301,9 +260,6 @@ test.describe('Role management page', () => {
.getByRole('option', { name: 'Cannot Delete Role' })
.click();
await adminCreateUserPage.createButton.click();
- await adminCreateUserPage.snackbar.waitFor({
- state: 'attached',
- });
await adminCreateUserPage.invitationEmailInfoAlert.waitFor({
state: 'attached',
});
@@ -311,40 +267,34 @@ test.describe('Role management page', () => {
'snackbar-create-user-success'
);
await expect(snackbar.variant).toBe('success');
- await adminCreateUserPage.closeSnackbar();
});
await test.step('Delete this user', async () => {
await adminUsersPage.navigateTo();
const row = await adminUsersPage.findUserPageWithEmail(
'user-delete-role-test@automatisch.io'
);
- // await test.waitForTimeout(10000);
const modal = await adminUsersPage.clickDeleteUser(row);
await modal.deleteButton.click();
- await adminUsersPage.snackbar.waitFor({
- state: 'attached',
- });
const snackbar = await adminUsersPage.getSnackbarData(
'snackbar-delete-user-success'
);
await expect(snackbar.variant).toBe('success');
- await adminUsersPage.closeSnackbar();
});
await test.step('Try deleting this role', async () => {
await adminRolesPage.navigateTo();
const row = await adminRolesPage.getRoleRowByName('Cannot Delete Role');
const modal = await adminRolesPage.clickDeleteRole(row);
await modal.deleteButton.click();
- await adminRolesPage.snackbar.waitFor({
- state: 'attached',
- });
+ const snackbar = await adminRolesPage.getSnackbarData(
+ 'snackbar-delete-role-error'
+ );
+ await expect(snackbar.variant).toBe('error');
/*
* TODO: await snackbar - make assertions based on product
* decisions
const snackbar = await adminRolesPage.getSnackbarData();
await expect(snackbar.variant).toBe('...');
*/
- await adminRolesPage.closeSnackbar();
});
});
});
@@ -362,16 +312,13 @@ test('Accessibility of role management page', async ({
await adminRolesPage.navigateTo();
await adminRolesPage.createRoleButton.click();
await adminCreateRolePage.isMounted();
+ await adminCreateRolePage.waitForPermissionsCatalogToVisible();
await adminCreateRolePage.nameInput.fill('Basic Test');
await adminCreateRolePage.createButton.click();
- await adminCreateRolePage.snackbar.waitFor({
- state: 'attached',
- });
const snackbar = await adminCreateRolePage.getSnackbarData(
'snackbar-create-role-success'
);
await expect(snackbar.variant).toBe('success');
- await adminCreateRolePage.closeSnackbar();
});
await test.step('Create a new user with the basic role', async () => {
@@ -385,9 +332,6 @@ test('Accessibility of role management page', async ({
.getByRole('option', { name: 'Basic Test' })
.click();
await adminCreateUserPage.createButton.click();
- await adminCreateUserPage.snackbar.waitFor({
- state: 'attached',
- });
await adminCreateUserPage.invitationEmailInfoAlert.waitFor({
state: 'attached',
});
@@ -395,56 +339,46 @@ test('Accessibility of role management page', async ({
'snackbar-create-user-success'
);
await expect(snackbar.variant).toBe('success');
- await adminCreateUserPage.closeSnackbar();
});
await test.step('Logout and login to the basic role user', async () => {
const acceptInvitationLink = await adminCreateUserPage.acceptInvitationLink;
- console.log(acceptInvitationLink);
const acceptInvitationUrl = await acceptInvitationLink.textContent();
- console.log(acceptInvitationUrl);
const acceptInvitatonToken = acceptInvitationUrl.split('?token=')[1];
await page.getByTestId('profile-menu-button').click();
await page.getByTestId('logout-item').click();
const acceptInvitationPage = new AcceptInvitation(page);
-
await acceptInvitationPage.open(acceptInvitatonToken);
-
await acceptInvitationPage.acceptInvitation('sample');
const loginPage = new LoginPage(page);
-
- // await loginPage.isMounted();
await loginPage.login('basic-role-test@automatisch.io', 'sample');
await expect(loginPage.loginButton).not.toBeVisible();
await expect(page).toHaveURL('/flows');
});
- await test.step(
- 'Navigate to the admin settings page and make sure it is blank',
- async () => {
- const pageUrl = new URL(page.url());
- const url = `${pageUrl.origin}/admin-settings/users`;
- await page.goto(url);
- await page.waitForTimeout(750);
- const isUnmounted = await page.evaluate(() => {
- // eslint-disable-next-line no-undef
- const root = document.querySelector('#root');
+ await test.step('Navigate to the admin settings page and make sure it is blank', async () => {
+ const pageUrl = new URL(page.url());
+ const url = `${pageUrl.origin}/admin-settings/users`;
+ await page.goto(url);
+ await page.waitForTimeout(750);
+ const isUnmounted = await page.evaluate(() => {
+ // eslint-disable-next-line no-undef
+ const root = document.querySelector('#root');
- if (root) {
- // We have react query devtools only in dev env.
- // In production, there is nothing in root.
- // That's why `<= 1`.
- return root.children.length <= 1;
- }
+ if (root) {
+ // We have react query devtools only in dev env.
+ // In production, there is nothing in root.
+ // That's why `<= 1`.
+ return root.children.length <= 1;
+ }
- return false;
- });
- await expect(isUnmounted).toBe(true);
- }
- );
+ return false;
+ });
+ await expect(isUnmounted).toBe(true);
+ });
await test.step('Log back into the admin account', async () => {
await page.goto('/');
@@ -465,10 +399,10 @@ test('Accessibility of role management page', async ({
await adminEditUserPage.roleInput.click();
await adminEditUserPage.page.getByRole('option', { name: 'Admin' }).click();
await adminEditUserPage.updateButton.click();
- await adminEditUserPage.snackbar.waitFor({
- state: 'attached',
- });
- await adminEditUserPage.closeSnackbar();
+ const snackbar = await adminEditUserPage.getSnackbarData(
+ 'snackbar-edit-user-success'
+ );
+ await expect(snackbar.variant).toBe('success');
});
await test.step('Delete the role', async () => {
@@ -480,14 +414,10 @@ test('Accessibility of role management page', async ({
state: 'attached',
});
await deleteModal.deleteButton.click();
- await adminRolesPage.snackbar.waitFor({
- state: 'attached',
- });
const snackbar = await adminRolesPage.getSnackbarData(
'snackbar-delete-role-success'
);
await expect(snackbar.variant).toBe('success');
- await adminRolesPage.closeSnackbar();
await deleteModal.modal.waitFor({
state: 'detached',
});
diff --git a/packages/e2e-tests/tests/admin/manage-users.spec.js b/packages/e2e-tests/tests/admin/manage-users.spec.js
index d6fc1507..7c3ab62d 100644
--- a/packages/e2e-tests/tests/admin/manage-users.spec.js
+++ b/packages/e2e-tests/tests/admin/manage-users.spec.js
@@ -5,281 +5,235 @@ const { test, expect } = require('../../fixtures/index');
* otherwise tests will fail since users are only *soft*-deleted
*/
test.describe('User management page', () => {
-
test.beforeEach(async ({ adminUsersPage }) => {
await adminUsersPage.navigateTo();
- await adminUsersPage.closeSnackbar();
+ await adminUsersPage.closeAllSnackbars();
});
- test(
- 'User creation and deletion process',
- async ({ adminCreateUserPage, adminEditUserPage, adminUsersPage }) => {
- adminCreateUserPage.seed(9000);
- const user = adminCreateUserPage.generateUser();
- await adminUsersPage.usersLoader.waitFor({
- state: 'detached' /* Note: state: 'visible' introduces flakiness
+ test('User creation and deletion process', async ({
+ adminCreateUserPage,
+ adminEditUserPage,
+ adminUsersPage,
+ }) => {
+ adminCreateUserPage.seed(9000);
+ const user = adminCreateUserPage.generateUser();
+ await adminUsersPage.usersLoader.waitFor({
+ state: 'detached' /* Note: state: 'visible' introduces flakiness
because visibility: hidden is used as part of the state transition in
notistack, see
https://github.com/iamhosseindhv/notistack/blob/122f47057eb7ce5a1abfe923316cf8475303e99a/src/transitions/Collapse/Collapse.tsx#L110
- */
+ */,
+ });
+ await test.step('Create a user', async () => {
+ await adminUsersPage.createUserButton.click();
+ await adminCreateUserPage.fullNameInput.fill(user.fullName);
+ await adminCreateUserPage.emailInput.fill(user.email);
+ await adminCreateUserPage.roleInput.click();
+ await adminCreateUserPage.page
+ .getByRole('option', { name: 'Admin' })
+ .click();
+ await adminCreateUserPage.createButton.click();
+ await adminCreateUserPage.invitationEmailInfoAlert.waitFor({
+ state: 'attached',
});
- await test.step(
- 'Create a user',
- async () => {
- await adminUsersPage.createUserButton.click();
- await adminCreateUserPage.fullNameInput.fill(user.fullName);
- await adminCreateUserPage.emailInput.fill(user.email);
- await adminCreateUserPage.roleInput.click();
- await adminCreateUserPage.page.getByRole(
- 'option', { name: 'Admin' }
- ).click();
- await adminCreateUserPage.createButton.click();
- await adminCreateUserPage.invitationEmailInfoAlert.waitFor({
- state: 'attached'
- });
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-create-user-success'
- );
- await expect(snackbar.variant).toBe('success');
- await adminUsersPage.navigateTo();
- await adminUsersPage.closeSnackbar();
- }
+ const snackbar = await adminUsersPage.getSnackbarData(
+ 'snackbar-create-user-success'
);
- await test.step(
- 'Check the user exists with the expected properties',
- async () => {
- await adminUsersPage.findUserPageWithEmail(user.email);
- const userRow = await adminUsersPage.getUserRowByEmail(user.email);
- const data = await adminUsersPage.getRowData(userRow);
- await expect(data.email).toBe(user.email);
- await expect(data.fullName).toBe(user.fullName);
- await expect(data.role).toBe('Admin');
- }
+ await expect(snackbar.variant).toBe('success');
+ await adminUsersPage.navigateTo();
+ });
+ await test.step('Check the user exists with the expected properties', async () => {
+ await adminUsersPage.findUserPageWithEmail(user.email);
+ const userRow = await adminUsersPage.getUserRowByEmail(user.email);
+ const data = await adminUsersPage.getRowData(userRow);
+ await expect(data.email).toBe(user.email);
+ await expect(data.fullName).toBe(user.fullName);
+ await expect(data.role).toBe('Admin');
+ });
+ await test.step('Edit user info and make sure the edit works correctly', async () => {
+ await adminUsersPage.findUserPageWithEmail(user.email);
+
+ let userRow = await adminUsersPage.getUserRowByEmail(user.email);
+ await adminUsersPage.clickEditUser(userRow);
+ await adminEditUserPage.waitForLoad(user.fullName);
+ const newUserInfo = adminEditUserPage.generateUser();
+ await adminEditUserPage.fullNameInput.fill(newUserInfo.fullName);
+ await adminEditUserPage.updateButton.click();
+
+ const snackbar = await adminUsersPage.getSnackbarData(
+ 'snackbar-edit-user-success'
);
- await test.step(
- 'Edit user info and make sure the edit works correctly',
- async () => {
- await adminUsersPage.findUserPageWithEmail(user.email);
+ await expect(snackbar.variant).toBe('success');
- let userRow = await adminUsersPage.getUserRowByEmail(user.email);
- await adminUsersPage.clickEditUser(userRow);
- await adminEditUserPage.waitForLoad(user.fullName);
- const newUserInfo = adminEditUserPage.generateUser();
- await adminEditUserPage.fullNameInput.fill(newUserInfo.fullName);
- await adminEditUserPage.updateButton.click();
+ await adminUsersPage.findUserPageWithEmail(user.email);
+ userRow = await adminUsersPage.getUserRowByEmail(user.email);
+ const rowData = await adminUsersPage.getRowData(userRow);
+ await expect(rowData.fullName).toBe(newUserInfo.fullName);
+ });
+ await test.step('Delete user and check the page confirms this deletion', async () => {
+ await adminUsersPage.findUserPageWithEmail(user.email);
+ const userRow = await adminUsersPage.getUserRowByEmail(user.email);
+ await adminUsersPage.clickDeleteUser(userRow);
+ const modal = adminUsersPage.deleteUserModal;
+ await modal.deleteButton.click();
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-edit-user-success'
- );
- await expect(snackbar.variant).toBe('success');
- await adminUsersPage.closeSnackbar();
-
- await adminUsersPage.findUserPageWithEmail(user.email);
- userRow = await adminUsersPage.getUserRowByEmail(user.email);
- const rowData = await adminUsersPage.getRowData(userRow);
- await expect(rowData.fullName).toBe(newUserInfo.fullName);
- }
+ const snackbar = await adminUsersPage.getSnackbarData(
+ 'snackbar-delete-user-success'
);
- await test.step(
- 'Delete user and check the page confirms this deletion',
- async () => {
- await adminUsersPage.findUserPageWithEmail(user.email);
- const userRow = await adminUsersPage.getUserRowByEmail(user.email);
- await adminUsersPage.clickDeleteUser(userRow);
- const modal = adminUsersPage.deleteUserModal;
- await modal.deleteButton.click();
+ await expect(snackbar.variant).toBe('success');
+ await expect(userRow).not.toBeVisible(false);
+ });
+ });
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-delete-user-success'
- );
- await expect(snackbar.variant).toBe('success');
- await adminUsersPage.closeSnackbar();
- await expect(userRow).not.toBeVisible(false);
- }
+ test('Creating a user which has been deleted', async ({
+ adminCreateUserPage,
+ adminUsersPage,
+ }) => {
+ adminCreateUserPage.seed(9100);
+ const testUser = adminCreateUserPage.generateUser();
+
+ await test.step('Create the test user', async () => {
+ await adminUsersPage.navigateTo();
+ await adminUsersPage.createUserButton.click();
+ await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
+ await adminCreateUserPage.emailInput.fill(testUser.email);
+ await adminCreateUserPage.roleInput.click();
+ await adminCreateUserPage.page
+ .getByRole('option', { name: 'Admin' })
+ .click();
+ await adminCreateUserPage.createButton.click();
+ const snackbar = await adminUsersPage.getSnackbarData(
+ 'snackbar-create-user-success'
);
+ await expect(snackbar.variant).toBe('success');
});
- test(
- 'Creating a user which has been deleted',
- async ({ adminCreateUserPage, adminUsersPage }) => {
- adminCreateUserPage.seed(9100);
- const testUser = adminCreateUserPage.generateUser();
-
- await test.step(
- 'Create the test user',
- async () => {
- await adminUsersPage.navigateTo();
- await adminUsersPage.createUserButton.click();
- await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
- await adminCreateUserPage.emailInput.fill(testUser.email);
- await adminCreateUserPage.roleInput.click();
- await adminCreateUserPage.page.getByRole(
- 'option', { name: 'Admin' }
- ).click();
- await adminCreateUserPage.createButton.click();
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-create-user-success'
- );
- await expect(snackbar.variant).toBe('success');
- await adminUsersPage.closeSnackbar();
- }
+ await test.step('Delete the created user', async () => {
+ await adminUsersPage.navigateTo();
+ await adminUsersPage.findUserPageWithEmail(testUser.email);
+ const userRow = await adminUsersPage.getUserRowByEmail(testUser.email);
+ await adminUsersPage.clickDeleteUser(userRow);
+ const modal = adminUsersPage.deleteUserModal;
+ await modal.deleteButton.click();
+ const snackbar = await adminUsersPage.getSnackbarData(
+ 'snackbar-delete-user-success'
);
+ await expect(snackbar).not.toBeNull();
+ await expect(snackbar.variant).toBe('success');
+ await expect(userRow).not.toBeVisible(false);
+ });
- await test.step(
- 'Delete the created user',
- async () => {
- await adminUsersPage.navigateTo();
- await adminUsersPage.findUserPageWithEmail(testUser.email);
- const userRow = await adminUsersPage.getUserRowByEmail(testUser.email);
- await adminUsersPage.clickDeleteUser(userRow);
- const modal = adminUsersPage.deleteUserModal;
- await modal.deleteButton.click();
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-delete-user-success'
- );
- await expect(snackbar).not.toBeNull();
- await expect(snackbar.variant).toBe('success');
- await adminUsersPage.closeSnackbar();
- await expect(userRow).not.toBeVisible(false);
- }
+ await test.step('Create the user again', async () => {
+ await adminUsersPage.createUserButton.click();
+ await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
+ await adminCreateUserPage.emailInput.fill(testUser.email);
+ await adminCreateUserPage.roleInput.click();
+ await adminCreateUserPage.page
+ .getByRole('option', { name: 'Admin' })
+ .click();
+ await adminCreateUserPage.createButton.click();
+ const snackbar = await adminUsersPage.getSnackbarData('snackbar-error');
+ await expect(snackbar.variant).toBe('error');
+ });
+ });
+
+ test('Creating a user which already exists', async ({
+ adminCreateUserPage,
+ adminUsersPage,
+ page,
+ }) => {
+ adminCreateUserPage.seed(9200);
+ const testUser = adminCreateUserPage.generateUser();
+
+ await test.step('Create the test user', async () => {
+ await adminUsersPage.createUserButton.click();
+ await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
+ await adminCreateUserPage.emailInput.fill(testUser.email);
+ await adminCreateUserPage.roleInput.click();
+ await adminCreateUserPage.page
+ .getByRole('option', { name: 'Admin' })
+ .click();
+ await adminCreateUserPage.createButton.click();
+ const snackbar = await adminUsersPage.getSnackbarData(
+ 'snackbar-create-user-success'
);
+ await expect(snackbar.variant).toBe('success');
+ });
- await test.step(
- 'Create the user again',
- async () => {
- await adminUsersPage.createUserButton.click();
- await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
- await adminCreateUserPage.emailInput.fill(testUser.email);
- await adminCreateUserPage.roleInput.click();
- await adminCreateUserPage.page.getByRole(
- 'option', { name: 'Admin' }
- ).click();
- await adminCreateUserPage.createButton.click();
- const snackbar = await adminUsersPage.getSnackbarData('snackbar-error');
- await expect(snackbar.variant).toBe('error');
- await adminUsersPage.closeSnackbar();
- }
+ await test.step('Create the user again', async () => {
+ await adminUsersPage.navigateTo();
+ await adminUsersPage.createUserButton.click();
+ await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
+ await adminCreateUserPage.emailInput.fill(testUser.email);
+ const createUserPageUrl = page.url();
+ await adminCreateUserPage.roleInput.click();
+ await adminCreateUserPage.page
+ .getByRole('option', { name: 'Admin' })
+ .click();
+ await adminCreateUserPage.createButton.click();
+
+ await expect(page.url()).toBe(createUserPageUrl);
+ const snackbar = await adminUsersPage.getSnackbarData('snackbar-error');
+ await expect(snackbar.variant).toBe('error');
+ });
+ });
+
+ test('Editing a user to have the same email as another user should not be allowed', async ({
+ adminCreateUserPage,
+ adminEditUserPage,
+ adminUsersPage,
+ page,
+ }) => {
+ adminCreateUserPage.seed(9300);
+ const user1 = adminCreateUserPage.generateUser();
+ const user2 = adminCreateUserPage.generateUser();
+ await test.step('Create the first user', async () => {
+ await adminUsersPage.navigateTo();
+ await adminUsersPage.createUserButton.click();
+ await adminCreateUserPage.fullNameInput.fill(user1.fullName);
+ await adminCreateUserPage.emailInput.fill(user1.email);
+ await adminCreateUserPage.roleInput.click();
+ await adminCreateUserPage.page
+ .getByRole('option', { name: 'Admin' })
+ .click();
+ await adminCreateUserPage.createButton.click();
+ const snackbar = await adminUsersPage.getSnackbarData(
+ 'snackbar-create-user-success'
);
- }
- );
+ await expect(snackbar.variant).toBe('success');
+ await adminUsersPage.closeAllSnackbars();
+ });
- test(
- 'Creating a user which already exists',
- async ({ adminCreateUserPage, adminUsersPage, page }) => {
- adminCreateUserPage.seed(9200);
- const testUser = adminCreateUserPage.generateUser();
-
- await test.step(
- 'Create the test user',
- async () => {
- await adminUsersPage.createUserButton.click();
- await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
- await adminCreateUserPage.emailInput.fill(testUser.email);
- await adminCreateUserPage.roleInput.click();
- await adminCreateUserPage.page.getByRole(
- 'option', { name: 'Admin' }
- ).click();
- await adminCreateUserPage.createButton.click();
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-create-user-success'
- );
- await expect(snackbar.variant).toBe('success');
- await adminUsersPage.closeSnackbar();
- }
+ await test.step('Create the second user', async () => {
+ await adminUsersPage.navigateTo();
+ await adminUsersPage.createUserButton.click();
+ await adminCreateUserPage.fullNameInput.fill(user2.fullName);
+ await adminCreateUserPage.emailInput.fill(user2.email);
+ await adminCreateUserPage.roleInput.click();
+ await adminCreateUserPage.page
+ .getByRole('option', { name: 'Admin' })
+ .click();
+ await adminCreateUserPage.createButton.click();
+ const snackbar = await adminUsersPage.getSnackbarData(
+ 'snackbar-create-user-success'
);
+ await expect(snackbar.variant).toBe('success');
+ });
- await test.step(
- 'Create the user again',
- async () => {
- await adminUsersPage.navigateTo();
- await adminUsersPage.createUserButton.click();
- await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
- await adminCreateUserPage.emailInput.fill(testUser.email);
- const createUserPageUrl = page.url();
- await adminCreateUserPage.roleInput.click();
- await adminCreateUserPage.page.getByRole(
- 'option', { name: 'Admin' }
- ).click();
- await adminCreateUserPage.createButton.click();
+ await test.step('Try editing the second user to have the email of the first user', async () => {
+ await adminUsersPage.navigateTo();
+ await adminUsersPage.findUserPageWithEmail(user2.email);
+ let userRow = await adminUsersPage.getUserRowByEmail(user2.email);
+ await adminUsersPage.clickEditUser(userRow);
+ await adminEditUserPage.waitForLoad(user2.fullName);
+ await adminEditUserPage.emailInput.fill(user1.email);
+ const editPageUrl = page.url();
+ await adminEditUserPage.updateButton.click();
- await expect(page.url()).toBe(createUserPageUrl);
- const snackbar = await adminUsersPage.getSnackbarData('snackbar-error');
- await expect(snackbar.variant).toBe('error');
- await adminUsersPage.closeSnackbar();
- }
- );
- }
- );
-
- test(
- 'Editing a user to have the same email as another user should not be allowed',
- async ({
- adminCreateUserPage, adminEditUserPage, adminUsersPage, page
- }) => {
- adminCreateUserPage.seed(9300);
- const user1 = adminCreateUserPage.generateUser();
- const user2 = adminCreateUserPage.generateUser();
- await test.step(
- 'Create the first user',
- async () => {
- await adminUsersPage.navigateTo();
- await adminUsersPage.createUserButton.click();
- await adminCreateUserPage.fullNameInput.fill(user1.fullName);
- await adminCreateUserPage.emailInput.fill(user1.email);
- await adminCreateUserPage.roleInput.click();
- await adminCreateUserPage.page.getByRole(
- 'option', { name: 'Admin' }
- ).click();
- await adminCreateUserPage.createButton.click();
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-create-user-success'
- );
- await expect(snackbar.variant).toBe('success');
- await adminUsersPage.closeSnackbar();
- }
- );
-
- await test.step(
- 'Create the second user',
- async () => {
- await adminUsersPage.navigateTo();
- await adminUsersPage.createUserButton.click();
- await adminCreateUserPage.fullNameInput.fill(user2.fullName);
- await adminCreateUserPage.emailInput.fill(user2.email);
- await adminCreateUserPage.roleInput.click();
- await adminCreateUserPage.page.getByRole(
- 'option', { name: 'Admin' }
- ).click();
- await adminCreateUserPage.createButton.click();
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-create-user-success'
- );
- await expect(snackbar.variant).toBe('success');
- await adminUsersPage.closeSnackbar();
- }
- );
-
- await test.step(
- 'Try editing the second user to have the email of the first user',
- async () => {
- await adminUsersPage.navigateTo();
- await adminUsersPage.findUserPageWithEmail(user2.email);
- let userRow = await adminUsersPage.getUserRowByEmail(user2.email);
- await adminUsersPage.clickEditUser(userRow);
- await adminEditUserPage.waitForLoad(user2.fullName);
- await adminEditUserPage.emailInput.fill(user1.email);
- const editPageUrl = page.url();
- await adminEditUserPage.updateButton.click();
-
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-error'
- );
- await expect(snackbar.variant).toBe('error');
- await adminUsersPage.closeSnackbar();
- await expect(page.url()).toBe(editPageUrl);
- }
- );
- }
- );
+ const snackbar = await adminUsersPage.getSnackbarData('snackbar-error');
+ await expect(snackbar.variant).toBe('error');
+ await expect(page.url()).toBe(editPageUrl);
+ });
+ });
});
diff --git a/packages/e2e-tests/tests/connections/enabled-pop-up-reminder.spec.js b/packages/e2e-tests/tests/connections/enabled-pop-up-reminder.spec.js
index 32d30525..3b599a56 100644
--- a/packages/e2e-tests/tests/connections/enabled-pop-up-reminder.spec.js
+++ b/packages/e2e-tests/tests/connections/enabled-pop-up-reminder.spec.js
@@ -1,24 +1,55 @@
+const { request } = require('@playwright/test');
const { test, expect } = require('../../fixtures/index');
-const {AddMattermostConnectionModal} = require('../../fixtures/apps/mattermost/add-mattermost-connection-modal');
+const {
+ AddMattermostConnectionModal,
+} = require('../../fixtures/apps/mattermost/add-mattermost-connection-modal');
+const { createFlow, updateFlowName, getFlow, updateFlowStep, testStep } = require('../../helpers/flow-api-helper');
+const { getToken } = require('../../helpers/auth-api-helper');
test.describe('Pop-up message on connections', () => {
test.beforeEach(async ({ flowEditorPage, page }) => {
- await page.getByTestId('create-flow-button').click();
- await page.waitForURL(
- /\/editor\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}/
- );
- await expect(page.getByTestId('flow-step')).toHaveCount(2);
+ const apiRequest = await request.newContext();
+ const tokenJsonResponse = await getToken(apiRequest);
+ const token = tokenJsonResponse.data.token;
- await flowEditorPage.flowName.click();
- await flowEditorPage.flowNameInput.fill('PopupFlow');
- await flowEditorPage.createWebhookTrigger(true);
+ let flow = await createFlow(apiRequest, token);
+ const flowId = flow.data.id;
+ await updateFlowName(apiRequest, token, flowId);
+ flow = await getFlow(apiRequest, token, flowId);
+ const flowSteps = flow.data.steps;
- await flowEditorPage.chooseAppAndEvent('Mattermost', 'Send a message to channel');
- await expect(flowEditorPage.continueButton).toHaveCount(1);
- await expect(flowEditorPage.continueButton).not.toBeEnabled();
+ const triggerStepId = flowSteps.find((step) => step.type === 'trigger').id;
+ const actionStepId = flowSteps.find((step) => step.type === 'action').id;
+
+ const triggerStep = await updateFlowStep(apiRequest, token, triggerStepId, {
+ appKey: 'webhook',
+ key: 'catchRawWebhook',
+ parameters: {
+ workSynchronously: false,
+ },
+ });
+ await apiRequest.get(triggerStep.data.webhookUrl);
+ await testStep(apiRequest, token, triggerStepId);
+
+ await updateFlowStep(apiRequest, token, actionStepId, {
+ appKey: 'mattermost',
+ key: 'sendMessageToChannel',
+ });
+ await testStep(apiRequest, token, actionStepId);
+
+ await page.reload();
+
+ const flowRow = await page.getByTestId('flow-row').filter({
+ hasText: flowId,
+ });
+ await flowRow.click();
+ const flowTriggerStep = await page.getByTestId('flow-step').nth(1);
+ await flowTriggerStep.click();
+ await page.getByText('Choose connection').click();
await flowEditorPage.connectionAutocomplete.click();
- await flowEditorPage.addNewConnectionItem.click(); });
+ await flowEditorPage.addNewConnectionItem.click();
+ });
test('should show error to remind to enable pop-up on connection create', async ({
page,
@@ -28,7 +59,7 @@ test.describe('Pop-up message on connections', () => {
// Inject script to override window.open
await page.evaluate(() => {
// eslint-disable-next-line no-undef
- window.open = function() {
+ window.open = function () {
console.log('Popup blocked!');
return null;
};
@@ -37,8 +68,10 @@ test.describe('Pop-up message on connections', () => {
await addMattermostConnectionModal.fillConnectionForm();
await addMattermostConnectionModal.submitConnectionForm();
- await expect(page.getByTestId("add-connection-error")).toHaveCount(1);
- await expect(page.getByTestId("add-connection-error")).toHaveText('Make sure pop-ups are enabled in your browser.');
+ await expect(page.getByTestId('add-connection-error')).toHaveCount(1);
+ await expect(page.getByTestId('add-connection-error')).toHaveText(
+ 'Make sure pop-ups are enabled in your browser.'
+ );
});
test('should not show pop-up error if pop-ups are enabled on connection create', async ({
@@ -51,13 +84,15 @@ test.describe('Pop-up message on connections', () => {
await addMattermostConnectionModal.submitConnectionForm();
const popup = await popupPromise;
- await expect(popup.url()).toContain("mattermost");
- await expect(page.getByTestId("add-connection-error")).toHaveCount(0);
+ await expect(popup.url()).toContain('mattermost');
+ await expect(page.getByTestId('add-connection-error')).toHaveCount(0);
await test.step('Should show error on failed credentials verification', async () => {
await popup.close();
- await expect(page.getByTestId("add-connection-error")).toHaveCount(1);
- await expect(page.getByTestId("add-connection-error")).toHaveText('Error occured while verifying credentials!');
+ await expect(page.getByTestId('add-connection-error')).toHaveCount(1);
+ await expect(page.getByTestId('add-connection-error')).toHaveText(
+ 'Error occured while verifying credentials!'
+ );
});
});
-});
\ No newline at end of file
+});
diff --git a/packages/e2e-tests/tests/my-profile/profile-updates.spec.js b/packages/e2e-tests/tests/my-profile/profile-updates.spec.js
index d77962e4..d53c3a08 100644
--- a/packages/e2e-tests/tests/my-profile/profile-updates.spec.js
+++ b/packages/e2e-tests/tests/my-profile/profile-updates.spec.js
@@ -1,57 +1,38 @@
+const { request } = require('@playwright/test');
const { publicTest, expect } = require('../../fixtures/index');
-const { AdminUsersPage } = require('../../fixtures/admin/users-page');
const { MyProfilePage } = require('../../fixtures/my-profile-page');
const { LoginPage } = require('../../fixtures/login-page');
+const { addUser, acceptInvitation } = require('../../helpers/user-api-helper');
+const { getToken } = require('../../helpers/auth-api-helper');
publicTest.describe('My Profile', () => {
let testUser;
publicTest.beforeEach(
- async ({ acceptInvitationPage, adminCreateUserPage, loginPage, page }) => {
- let acceptInvitationLink;
+ async ({ adminCreateUserPage, loginPage, page }) => {
+ let addUserResponse;
+ const apiRequest = await request.newContext();
adminCreateUserPage.seed(
Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER)
);
testUser = adminCreateUserPage.generateUser();
- const adminUsersPage = new AdminUsersPage(page);
- const myProfilePage = new MyProfilePage(page);
-
- await publicTest.step('login as Admin', async () => {
- await loginPage.login();
- await expect(loginPage.page).toHaveURL('/flows');
- });
-
await publicTest.step('create new user', async () => {
- await adminUsersPage.navigateTo();
- await adminUsersPage.createUserButton.click();
- await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
- await adminCreateUserPage.emailInput.fill(testUser.email);
- await adminCreateUserPage.roleInput.click();
- await adminCreateUserPage.page
- .getByRole('option', { name: 'Admin' })
- .click();
- await adminCreateUserPage.createButton.click();
- const snackbar = await adminUsersPage.getSnackbarData(
- 'snackbar-create-user-success'
+ const tokenJsonResponse = await getToken(apiRequest);
+ addUserResponse = await addUser(
+ apiRequest,
+ tokenJsonResponse.data.token,
+ {
+ fullName: testUser.fullName,
+ email: testUser.email,
+ }
);
- await expect(snackbar.variant).toBe('success');
- });
-
- await publicTest.step('copy invitation link', async () => {
- const invitationMessage =
- await adminCreateUserPage.acceptInvitationLink;
- acceptInvitationLink = await invitationMessage.getAttribute('href');
- });
-
- await publicTest.step('logout', async () => {
- await myProfilePage.logout();
});
await publicTest.step('accept invitation', async () => {
- await page.goto(acceptInvitationLink);
- await acceptInvitationPage.acceptInvitation(LoginPage.defaultPassword);
+ let acceptToken = addUserResponse.data.acceptInvitationUrl.split('=')[1];
+ await acceptInvitation(apiRequest, {token:acceptToken, password:LoginPage.defaultPassword});
});
await publicTest.step('login as new Admin', async () => {
diff --git a/packages/e2e-tests/yarn.lock b/packages/e2e-tests/yarn.lock
index 4953ecb7..f86c39e7 100644
--- a/packages/e2e-tests/yarn.lock
+++ b/packages/e2e-tests/yarn.lock
@@ -79,7 +79,7 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
-"@playwright/test@^1.45.1":
+"@playwright/test@1.49.0":
version "1.49.0"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.49.0.tgz#74227385b58317ee076b86b56d0e1e1b25cff01e"
integrity sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==
diff --git a/packages/web/src/components/PermissionCatalogField/index.ee.jsx b/packages/web/src/components/PermissionCatalogField/index.ee.jsx
index 5f2bf909..24a86d38 100644
--- a/packages/web/src/components/PermissionCatalogField/index.ee.jsx
+++ b/packages/web/src/components/PermissionCatalogField/index.ee.jsx
@@ -30,7 +30,7 @@ const PermissionCatalogField = ({
if (isPermissionCatalogLoading) return ;
return (
-
+