test: improve tests execution time

This commit is contained in:
Jakub P.
2024-12-06 09:17:21 +01:00
parent b8da721e39
commit f83deac469
19 changed files with 591 additions and 506 deletions

View File

@@ -3,13 +3,12 @@ on:
push: push:
branches: branches:
- main - main
# TODO: Add pull request after optimizing the total excecution time of the test suite. pull_request:
# pull_request: paths:
# paths: - 'packages/backend/**'
# - 'packages/backend/**' - 'packages/e2e-tests/**'
# - 'packages/e2e-tests/**' - 'packages/web/**'
# - 'packages/web/**' - '!packages/backend/src/apps/**'
# - '!packages/backend/src/apps/**'
workflow_dispatch: workflow_dispatch:
env: env:
@@ -56,27 +55,44 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v4
with: with:
node-version: 18 node-version: '18'
- name: Install web dependencies cache: 'yarn'
run: yarn cache-dependency-path: |
working-directory: ./packages/web packages/backend/yarn.lock
packages/web/yarn.lock
packages/e2e-tests/yarn.lock
- name: Install backend dependencies - name: Install backend dependencies
run: yarn run: yarn --frozen-lockfile
working-directory: ./packages/backend working-directory: ./packages/backend
- name: Install web dependencies
run: yarn --frozen-lockfile
working-directory: ./packages/web
- name: Install e2e-tests dependencies - name: Install e2e-tests dependencies
run: yarn run: yarn --frozen-lockfile
working-directory: ./packages/e2e-tests 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 - name: Install Playwright Browsers
run: yarn playwright install --with-deps run: yarn playwright install --with-deps
working-directory: ./packages/e2e-tests working-directory: ./packages/e2e-tests
if: steps.playwright-cache.outputs.cache-hit != 'true'
- name: Build Automatisch web - name: Build Automatisch web
run: yarn build run: yarn build
working-directory: ./packages/web
env: env:
# Keep this until we clean up warnings in build processes # Keep this until we clean up warnings in build processes
CI: false CI: false
working-directory: ./packages/web
- name: Migrate database - name: Migrate database
working-directory: ./packages/backend working-directory: ./packages/backend
run: yarn db:migrate run: yarn db:migrate
@@ -116,6 +132,7 @@ jobs:
env: env:
LOGIN_EMAIL: user@automatisch.io LOGIN_EMAIL: user@automatisch.io
LOGIN_PASSWORD: sample LOGIN_PASSWORD: sample
BACKEND_APP_URL: http://localhost:3000
BASE_URL: http://localhost:3000 BASE_URL: http://localhost:3000
GITHUB_CLIENT_ID: 1c0417daf898adfbd99a GITHUB_CLIENT_ID: 1c0417daf898adfbd99a
GITHUB_CLIENT_SECRET: 3328fa814dd582ccd03dbe785cfd683fb8da92b3 GITHUB_CLIENT_SECRET: 3328fa814dd582ccd03dbe785cfd683fb8da92b3

View File

@@ -3,3 +3,4 @@ POSTGRES_USER=automatisch_user
POSTGRES_PASSWORD=automatisch_password POSTGRES_PASSWORD=automatisch_password
POSTGRES_PORT=5432 POSTGRES_PORT=5432
POSTGRES_HOST=localhost POSTGRES_HOST=localhost
BACKEND_APP_URL=http://localhost:3000

View File

@@ -56,8 +56,10 @@ export class AdminApplicationSettingsPage extends AuthenticatedPage {
} }
async expectSuccessSnackbarToBeVisible() { async expectSuccessSnackbarToBeVisible() {
await expect(this.successSnackbar).toHaveCount(1); const snackbars = await this.successSnackbar.all();
await this.successSnackbar.click(); for (const snackbar of snackbars) {
await expect(this.successSnackbar).toHaveCount(0); await expect(await snackbar.getAttribute('data-snackbar-variant')).toBe('success');
await snackbar.click();
}
} }
} }

View File

@@ -1,3 +1,5 @@
import { expect } from '@playwright/test';
const { AuthenticatedPage } = require('../authenticated-page'); const { AuthenticatedPage } = require('../authenticated-page');
const { RoleConditionsModal } = require('./role-conditions-modal'); const { RoleConditionsModal } = require('./role-conditions-modal');
@@ -16,6 +18,7 @@ export class AdminCreateRolePage extends AuthenticatedPage {
this.executionRow = page.getByTestId('Execution-permission-row'); this.executionRow = page.getByTestId('Execution-permission-row');
this.flowRow = page.getByTestId('Flow-permission-row'); this.flowRow = page.getByTestId('Flow-permission-row');
this.pageTitle = page.getByTestId('create-role-title'); 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}`); throw new Error(`${subject} does not have action ${action}`);
} }
} }
async waitForPermissionsCatalogToVisible() {
await expect(this.permissionsCatalog).toBeVisible();
}
} }

View File

@@ -14,8 +14,12 @@ export class AdminCreateUserPage extends AuthenticatedPage {
this.roleInput = page.getByTestId('role.id-autocomplete'); this.roleInput = page.getByTestId('role.id-autocomplete');
this.createButton = page.getByTestId('create-button'); this.createButton = page.getByTestId('create-button');
this.pageTitle = page.getByTestId('create-user-title'); this.pageTitle = page.getByTestId('create-user-title');
this.invitationEmailInfoAlert = page.getByTestId('invitation-email-info-alert'); this.invitationEmailInfoAlert = page.getByTestId(
this.acceptInvitationLink = page.getByTestId('invitation-email-info-alert').getByRole('link'); 'invitation-email-info-alert'
);
this.acceptInvitationLink = page
.getByTestId('invitation-email-info-alert')
.getByRole('link');
} }
seed(seed) { seed(seed) {

View File

@@ -95,7 +95,6 @@ export class AdminUsersPage extends AuthenticatedPage {
}); });
} }
const rowLocator = await this.getUserRowByEmail(email); const rowLocator = await this.getUserRowByEmail(email);
console.log('rowLocator.count', email, await rowLocator.count());
if ((await rowLocator.count()) === 1) { if ((await rowLocator.count()) === 1) {
return rowLocator; return rowLocator;
} }

View File

@@ -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 * Closes all snackbars, should be replaced later
*/ */
async closeSnackbar() { async closeAllSnackbars() {
const snackbars = await this.snackbar.all(); const snackbars = await this.snackbar.all();
for (const snackbar of snackbars) { for (const snackbar of snackbars) {
await snackbar.click(); await snackbar.click();

View File

@@ -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();
};

View File

@@ -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);
};

View File

@@ -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);
};

View File

@@ -26,7 +26,7 @@
}, },
"devDependencies": { "devDependencies": {
"@faker-js/faker": "^8.2.0", "@faker-js/faker": "^8.2.0",
"@playwright/test": "^1.45.1" "@playwright/test": "1.49.0"
}, },
"dependencies": { "dependencies": {
"axios": "^1.6.0", "axios": "^1.6.0",

View File

@@ -15,9 +15,9 @@ module.exports = defineConfig({
fullyParallel: true, fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */ /* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI, forbidOnly: !!process.env.CI,
retries: 0, retries: process.env.CI ? 1 : 0,
/* Opt out of parallel tests on CI. */ /* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined, workers: undefined,
/* Timeout threshold for each test */ /* Timeout threshold for each test */
timeout: 30000, timeout: 30000,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */ /* 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', baseURL: process.env.BASE_URL || 'http://localhost:3001',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ /* 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', testIdAttribute: 'data-test',
viewport: { width: 1280, height: 720 }, viewport: { width: 1280, height: 720 },
}, },

View File

@@ -5,16 +5,18 @@ test.describe('Admin Applications', () => {
test.beforeAll(async () => { test.beforeAll(async () => {
const deleteAppAuthClients = { const deleteAppAuthClients = {
text: 'DELETE FROM app_auth_clients WHERE app_key in ($1, $2, $3, $4, $5)', 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 = { const deleteAppConfigs = {
text: 'DELETE FROM app_configs WHERE key in ($1, $2, $3, $4, $5)', 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 { try {
const deleteAppAuthClientsResult = await pgPool.query(deleteAppAuthClients); const deleteAppAuthClientsResult = await pgPool.query(
deleteAppAuthClients
);
expect(deleteAppAuthClientsResult.command).toBe('DELETE'); expect(deleteAppAuthClientsResult.command).toBe('DELETE');
const deleteAppConfigsResult = await pgPool.query(deleteAppConfigs); const deleteAppConfigsResult = await pgPool.query(deleteAppConfigs);
expect(deleteAppConfigsResult.command).toBe('DELETE'); expect(deleteAppConfigsResult.command).toBe('DELETE');
@@ -31,7 +33,7 @@ test.describe('Admin Applications', () => {
test('Admin should be able to toggle Application settings', async ({ test('Admin should be able to toggle Application settings', async ({
adminApplicationsPage, adminApplicationsPage,
adminApplicationSettingsPage, adminApplicationSettingsPage,
page page,
}) => { }) => {
await adminApplicationsPage.openApplication('Carbone'); await adminApplicationsPage.openApplication('Carbone');
await expect(page.url()).toContain('/admin-settings/apps/carbone/settings'); await expect(page.url()).toContain('/admin-settings/apps/carbone/settings');
@@ -57,7 +59,7 @@ test.describe('Admin Applications', () => {
adminApplicationsPage, adminApplicationsPage,
adminApplicationSettingsPage, adminApplicationSettingsPage,
flowEditorPage, flowEditorPage,
page page,
}) => { }) => {
await adminApplicationsPage.openApplication('Spotify'); await adminApplicationsPage.openApplication('Spotify');
await expect(page.url()).toContain('/admin-settings/apps/spotify/settings'); await expect(page.url()).toContain('/admin-settings/apps/spotify/settings');
@@ -75,11 +77,15 @@ test.describe('Admin Applications', () => {
const triggerStep = flowEditorPage.flowStep.last(); const triggerStep = flowEditorPage.flowStep.last();
await triggerStep.click(); await triggerStep.click();
await flowEditorPage.chooseAppAndEvent("Spotify", "Create Playlist"); await flowEditorPage.chooseAppAndEvent('Spotify', 'Create Playlist');
await flowEditorPage.connectionAutocomplete.click(); await flowEditorPage.connectionAutocomplete.click();
const newConnectionOption = page.getByRole('option').filter({ hasText: 'Add new connection' }); const newConnectionOption = page
const newSharedConnectionOption = page.getByRole('option').filter({ hasText: 'Add new shared connection' }); .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).toBeEnabled();
await expect(newConnectionOption).toHaveCount(1); await expect(newConnectionOption).toHaveCount(1);
@@ -91,7 +97,7 @@ test.describe('Admin Applications', () => {
adminApplicationSettingsPage, adminApplicationSettingsPage,
adminApplicationAuthClientsPage, adminApplicationAuthClientsPage,
flowEditorPage, flowEditorPage,
page page,
}) => { }) => {
await adminApplicationsPage.openApplication('Reddit'); await adminApplicationsPage.openApplication('Reddit');
await expect(page.url()).toContain('/admin-settings/apps/reddit/settings'); await expect(page.url()).toContain('/admin-settings/apps/reddit/settings');
@@ -101,13 +107,21 @@ test.describe('Admin Applications', () => {
await adminApplicationAuthClientsPage.openAuthClientsTab(); await adminApplicationAuthClientsPage.openAuthClientsTab();
await adminApplicationAuthClientsPage.openFirstAuthClientCreateForm(); 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.getByTestId('switch')).check();
await authClientForm.locator(page.locator('[name="name"]')).fill('redditAuthClient'); await authClientForm
await authClientForm.locator(page.locator('[name="clientId"]')).fill('redditClientId'); .locator(page.locator('[name="name"]'))
await authClientForm.locator(page.locator('[name="clientSecret"]')).fill('redditClientSecret'); .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.submitAuthClientForm();
await adminApplicationAuthClientsPage.authClientShouldBeVisible('redditAuthClient'); await adminApplicationAuthClientsPage.authClientShouldBeVisible(
'redditAuthClient'
);
await page.goto('/'); await page.goto('/');
await page.getByTestId('create-flow-button').click(); await page.getByTestId('create-flow-button').click();
@@ -119,11 +133,15 @@ test.describe('Admin Applications', () => {
const triggerStep = flowEditorPage.flowStep.last(); const triggerStep = flowEditorPage.flowStep.last();
await triggerStep.click(); await triggerStep.click();
await flowEditorPage.chooseAppAndEvent("Reddit", "Create link post"); await flowEditorPage.chooseAppAndEvent('Reddit', 'Create link post');
await flowEditorPage.connectionAutocomplete.click(); await flowEditorPage.connectionAutocomplete.click();
const newConnectionOption = page.getByRole('option').filter({ hasText: 'Add new connection' }); const newConnectionOption = page
const newSharedConnectionOption = page.getByRole('option').filter({ hasText: 'Add new shared connection' }); .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(newConnectionOption).toHaveCount(0);
await expect(newSharedConnectionOption).toBeEnabled(); await expect(newSharedConnectionOption).toBeEnabled();
@@ -134,7 +152,7 @@ test.describe('Admin Applications', () => {
adminApplicationsPage, adminApplicationsPage,
adminApplicationSettingsPage, adminApplicationSettingsPage,
flowEditorPage, flowEditorPage,
page page,
}) => { }) => {
await adminApplicationsPage.openApplication('DeepL'); await adminApplicationsPage.openApplication('DeepL');
await expect(page.url()).toContain('/admin-settings/apps/deepl/settings'); await expect(page.url()).toContain('/admin-settings/apps/deepl/settings');
@@ -152,12 +170,18 @@ test.describe('Admin Applications', () => {
const triggerStep = flowEditorPage.flowStep.last(); const triggerStep = flowEditorPage.flowStep.last();
await triggerStep.click(); await triggerStep.click();
await flowEditorPage.chooseAppAndEvent("DeepL", "Translate text"); await flowEditorPage.chooseAppAndEvent('DeepL', 'Translate text');
await flowEditorPage.connectionAutocomplete.click(); await flowEditorPage.connectionAutocomplete.click();
const newConnectionOption = page.getByRole('option').filter({ hasText: 'Add new connection' }); const newConnectionOption = page
const newSharedConnectionOption = page.getByRole('option').filter({ hasText: 'Add new shared connection' }); .getByRole('option')
const noConnectionsOption = page.locator('.MuiAutocomplete-noOptions').filter({ hasText: 'No options' }); .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(noConnectionsOption).toHaveCount(1);
await expect(newConnectionOption).toHaveCount(0); await expect(newConnectionOption).toHaveCount(0);
@@ -168,11 +192,11 @@ test.describe('Admin Applications', () => {
adminApplicationsPage, adminApplicationsPage,
adminApplicationSettingsPage, adminApplicationSettingsPage,
flowEditorPage, flowEditorPage,
page page,
}) => { }) => {
const queryUser = { const queryUser = {
text: 'SELECT * FROM users WHERE email = $1', text: 'SELECT * FROM users WHERE email = $1',
values: [process.env.LOGIN_EMAIL] values: [process.env.LOGIN_EMAIL],
}; };
try { 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)', text: 'INSERT INTO connections (key, data, user_id, verified, draft) VALUES ($1, $2, $3, $4, $5)',
values: [ values: [
'mailchimp', '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, queryUserResult.rows[0].id,
'true', 'true',
'false' 'false',
], ],
}; };
const createMailchimpConnectionResult = await pgPool.query(createMailchimpConnection); const createMailchimpConnectionResult = await pgPool.query(
createMailchimpConnection
);
expect(createMailchimpConnectionResult.rowCount).toBe(1); expect(createMailchimpConnectionResult.rowCount).toBe(1);
expect(createMailchimpConnectionResult.command).toBe('INSERT'); expect(createMailchimpConnectionResult.command).toBe('INSERT');
} catch (err) { } catch (err) {
@@ -199,7 +225,9 @@ test.describe('Admin Applications', () => {
} }
await adminApplicationsPage.openApplication('Mailchimp'); 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.disallowConnections();
await adminApplicationSettingsPage.expectSuccessSnackbarToBeVisible(); await adminApplicationSettingsPage.expectSuccessSnackbarToBeVisible();
@@ -214,14 +242,22 @@ test.describe('Admin Applications', () => {
const triggerStep = flowEditorPage.flowStep.last(); const triggerStep = flowEditorPage.flowStep.last();
await triggerStep.click(); await triggerStep.click();
await flowEditorPage.chooseAppAndEvent("Mailchimp", "Create campaign"); await flowEditorPage.chooseAppAndEvent('Mailchimp', 'Create campaign');
await flowEditorPage.connectionAutocomplete.click(); await flowEditorPage.connectionAutocomplete.click();
await expect(page.getByRole('option').first()).toHaveText('Unnamed'); await expect(page.getByRole('option').first()).toHaveText('Unnamed');
const existingConnection = page.getByRole('option').filter({ hasText: 'Unnamed' }); const existingConnection = page
const newConnectionOption = page.getByRole('option').filter({ hasText: 'Add new connection' }); .getByRole('option')
const newSharedConnectionOption = page.getByRole('option').filter({ hasText: 'Add new shared connection' }); .filter({ hasText: 'Unnamed' });
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(await existingConnection.count()).toBeGreaterThan(0); await expect(await existingConnection.count()).toBeGreaterThan(0);
await expect(noConnectionsOption).toHaveCount(0); await expect(noConnectionsOption).toHaveCount(0);

View File

@@ -22,22 +22,18 @@ test.describe('Role management page', () => {
await adminRolesPage.navigateTo(); await adminRolesPage.navigateTo();
await adminRolesPage.createRoleButton.click(); await adminRolesPage.createRoleButton.click();
await adminCreateRolePage.isMounted(); await adminCreateRolePage.isMounted();
await adminCreateRolePage.waitForPermissionsCatalogToVisible();
await adminCreateRolePage.nameInput.fill('Create Edit Test'); await adminCreateRolePage.nameInput.fill('Create Edit Test');
await adminCreateRolePage.descriptionInput.fill('Test description'); await adminCreateRolePage.descriptionInput.fill('Test description');
await adminCreateRolePage.createButton.click(); await adminCreateRolePage.createButton.click();
await adminCreateRolePage.snackbar.waitFor({
state: 'attached',
});
const snackbar = await adminCreateRolePage.getSnackbarData( const snackbar = await adminCreateRolePage.getSnackbarData(
'snackbar-create-role-success' 'snackbar-create-role-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminCreateRolePage.closeSnackbar();
}); });
let roleRow = await test.step( let roleRow =
'Make sure role data is correct', await test.step('Make sure role data is correct', async () => {
async () => {
const roleRow = await adminRolesPage.getRoleRowByName( const roleRow = await adminRolesPage.getRoleRowByName(
'Create Edit Test' 'Create Edit Test'
); );
@@ -48,8 +44,7 @@ test.describe('Role management page', () => {
await expect(roleData.canEdit).toBe(true); await expect(roleData.canEdit).toBe(true);
await expect(roleData.canDelete).toBe(true); await expect(roleData.canDelete).toBe(true);
return roleRow; return roleRow;
} });
);
await test.step('Edit the role', async () => { await test.step('Edit the role', async () => {
await adminRolesPage.clickEditRole(roleRow); await adminRolesPage.clickEditRole(roleRow);
@@ -57,19 +52,14 @@ test.describe('Role management page', () => {
await adminEditRolePage.nameInput.fill('Create Update Test'); await adminEditRolePage.nameInput.fill('Create Update Test');
await adminEditRolePage.descriptionInput.fill('Update test description'); await adminEditRolePage.descriptionInput.fill('Update test description');
await adminEditRolePage.updateButton.click(); await adminEditRolePage.updateButton.click();
await adminEditRolePage.snackbar.waitFor({
state: 'attached',
});
const snackbar = await adminEditRolePage.getSnackbarData( const snackbar = await adminEditRolePage.getSnackbarData(
'snackbar-edit-role-success' 'snackbar-edit-role-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminEditRolePage.closeSnackbar();
}); });
roleRow = await test.step( roleRow =
'Make sure changes reflected on roles page', await test.step('Make sure changes reflected on roles page', async () => {
async () => {
await adminRolesPage.isMounted(); await adminRolesPage.isMounted();
const roleRow = await adminRolesPage.getRoleRowByName( const roleRow = await adminRolesPage.getRoleRowByName(
'Create Update Test' 'Create Update Test'
@@ -81,8 +71,7 @@ test.describe('Role management page', () => {
await expect(roleData.canEdit).toBe(true); await expect(roleData.canEdit).toBe(true);
await expect(roleData.canDelete).toBe(true); await expect(roleData.canDelete).toBe(true);
return roleRow; return roleRow;
} });
);
await test.step('Delete the role', async () => { await test.step('Delete the role', async () => {
await adminRolesPage.clickDeleteRole(roleRow); await adminRolesPage.clickDeleteRole(roleRow);
@@ -91,14 +80,10 @@ test.describe('Role management page', () => {
state: 'attached', state: 'attached',
}); });
await deleteModal.deleteButton.click(); await deleteModal.deleteButton.click();
await adminRolesPage.snackbar.waitFor({
state: 'attached',
});
const snackbar = await adminRolesPage.getSnackbarData( const snackbar = await adminRolesPage.getSnackbarData(
'snackbar-delete-role-success' 'snackbar-delete-role-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminRolesPage.closeSnackbar();
await deleteModal.modal.waitFor({ await deleteModal.modal.waitFor({
state: 'detached', state: 'detached',
}); });
@@ -173,20 +158,15 @@ test.describe('Role management page', () => {
await test.step('Create a new role', async () => { await test.step('Create a new role', async () => {
await adminRolesPage.createRoleButton.click(); await adminRolesPage.createRoleButton.click();
await adminCreateRolePage.isMounted(); await adminCreateRolePage.isMounted();
await adminCreateRolePage.waitForPermissionsCatalogToVisible();
await adminCreateRolePage.nameInput.fill('Delete Role'); await adminCreateRolePage.nameInput.fill('Delete Role');
await adminCreateRolePage.createButton.click(); await adminCreateRolePage.createButton.click();
await adminCreateRolePage.snackbar.waitFor({
state: 'attached',
});
const snackbar = await adminCreateRolePage.getSnackbarData( const snackbar = await adminCreateRolePage.getSnackbarData(
'snackbar-create-role-success' 'snackbar-create-role-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminCreateRolePage.closeSnackbar();
}); });
await test.step( await test.step('Create a new user with the "Delete Role" role', async () => {
'Create a new user with the "Delete Role" role',
async () => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
await adminUsersPage.createUserButton.click(); await adminUsersPage.createUserButton.click();
await adminCreateUserPage.fullNameInput.fill('User Role Test'); await adminCreateUserPage.fullNameInput.fill('User Role Test');
@@ -198,9 +178,6 @@ test.describe('Role management page', () => {
.getByRole('option', { name: 'Delete Role', exact: true }) .getByRole('option', { name: 'Delete Role', exact: true })
.click(); .click();
await adminCreateUserPage.createButton.click(); await adminCreateUserPage.createButton.click();
await adminCreateUserPage.snackbar.waitFor({
state: 'attached',
});
await adminCreateUserPage.invitationEmailInfoAlert.waitFor({ await adminCreateUserPage.invitationEmailInfoAlert.waitFor({
state: 'attached', state: 'attached',
}); });
@@ -208,25 +185,18 @@ test.describe('Role management page', () => {
'snackbar-create-user-success' 'snackbar-create-user-success'
); );
await expect(snackbar.variant).toBe('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 test.step(
'Try to delete "Delete Role" role when new user has it',
async () => {
await adminRolesPage.navigateTo(); await adminRolesPage.navigateTo();
const row = await adminRolesPage.getRoleRowByName('Delete Role'); const row = await adminRolesPage.getRoleRowByName('Delete Role');
const modal = await adminRolesPage.clickDeleteRole(row); const modal = await adminRolesPage.clickDeleteRole(row);
await modal.deleteButton.click(); await modal.deleteButton.click();
await adminRolesPage.snackbar.waitFor({ const snackbar = await adminRolesPage.getSnackbarData(
state: 'attached', 'snackbar-delete-role-error'
});
const snackbar = await adminRolesPage.getSnackbarData('snackbar-delete-role-error');
await expect(snackbar.variant).toBe('error');
await adminRolesPage.closeSnackbar();
await modal.close();
}
); );
await expect(snackbar.variant).toBe('error');
await modal.close();
});
await test.step('Change the role the user has', async () => { await test.step('Change the role the user has', async () => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
await adminUsersPage.usersLoader.waitFor({ await adminUsersPage.usersLoader.waitFor({
@@ -241,14 +211,10 @@ test.describe('Role management page', () => {
.getByRole('option', { name: 'Admin' }) .getByRole('option', { name: 'Admin' })
.click(); .click();
await adminEditUserPage.updateButton.click(); await adminEditUserPage.updateButton.click();
await adminEditUserPage.snackbar.waitFor({
state: 'attached',
});
const snackbar = await adminEditUserPage.getSnackbarData( const snackbar = await adminEditUserPage.getSnackbarData(
'snackbar-edit-user-success' 'snackbar-edit-user-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminEditUserPage.closeSnackbar();
}); });
await test.step('Delete the original role', async () => { await test.step('Delete the original role', async () => {
await adminRolesPage.navigateTo(); await adminRolesPage.navigateTo();
@@ -256,14 +222,10 @@ test.describe('Role management page', () => {
const modal = await adminRolesPage.clickDeleteRole(row); const modal = await adminRolesPage.clickDeleteRole(row);
await expect(modal.modal).toBeVisible(); await expect(modal.modal).toBeVisible();
await modal.deleteButton.click(); await modal.deleteButton.click();
await adminRolesPage.snackbar.waitFor({
state: 'attached',
});
const snackbar = await adminRolesPage.getSnackbarData( const snackbar = await adminRolesPage.getSnackbarData(
'snackbar-delete-role-success' 'snackbar-delete-role-success'
); );
await expect(snackbar.variant).toBe('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 test.step('Create a new role', async () => {
await adminRolesPage.createRoleButton.click(); await adminRolesPage.createRoleButton.click();
await adminCreateRolePage.isMounted(); await adminCreateRolePage.isMounted();
await adminCreateRolePage.waitForPermissionsCatalogToVisible();
await adminCreateRolePage.nameInput.fill('Cannot Delete Role'); await adminCreateRolePage.nameInput.fill('Cannot Delete Role');
await adminCreateRolePage.createButton.click(); await adminCreateRolePage.createButton.click();
await adminCreateRolePage.snackbar.waitFor({
state: 'attached',
});
const snackbar = await adminCreateRolePage.getSnackbarData( const snackbar = await adminCreateRolePage.getSnackbarData(
'snackbar-create-role-success' 'snackbar-create-role-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminCreateRolePage.closeSnackbar();
}); });
await test.step('Create a new user with this role', async () => { await test.step('Create a new user with this role', async () => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
@@ -301,9 +260,6 @@ test.describe('Role management page', () => {
.getByRole('option', { name: 'Cannot Delete Role' }) .getByRole('option', { name: 'Cannot Delete Role' })
.click(); .click();
await adminCreateUserPage.createButton.click(); await adminCreateUserPage.createButton.click();
await adminCreateUserPage.snackbar.waitFor({
state: 'attached',
});
await adminCreateUserPage.invitationEmailInfoAlert.waitFor({ await adminCreateUserPage.invitationEmailInfoAlert.waitFor({
state: 'attached', state: 'attached',
}); });
@@ -311,40 +267,34 @@ test.describe('Role management page', () => {
'snackbar-create-user-success' 'snackbar-create-user-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminCreateUserPage.closeSnackbar();
}); });
await test.step('Delete this user', async () => { await test.step('Delete this user', async () => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
const row = await adminUsersPage.findUserPageWithEmail( const row = await adminUsersPage.findUserPageWithEmail(
'user-delete-role-test@automatisch.io' 'user-delete-role-test@automatisch.io'
); );
// await test.waitForTimeout(10000);
const modal = await adminUsersPage.clickDeleteUser(row); const modal = await adminUsersPage.clickDeleteUser(row);
await modal.deleteButton.click(); await modal.deleteButton.click();
await adminUsersPage.snackbar.waitFor({
state: 'attached',
});
const snackbar = await adminUsersPage.getSnackbarData( const snackbar = await adminUsersPage.getSnackbarData(
'snackbar-delete-user-success' 'snackbar-delete-user-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminUsersPage.closeSnackbar();
}); });
await test.step('Try deleting this role', async () => { await test.step('Try deleting this role', async () => {
await adminRolesPage.navigateTo(); await adminRolesPage.navigateTo();
const row = await adminRolesPage.getRoleRowByName('Cannot Delete Role'); const row = await adminRolesPage.getRoleRowByName('Cannot Delete Role');
const modal = await adminRolesPage.clickDeleteRole(row); const modal = await adminRolesPage.clickDeleteRole(row);
await modal.deleteButton.click(); await modal.deleteButton.click();
await adminRolesPage.snackbar.waitFor({ const snackbar = await adminRolesPage.getSnackbarData(
state: 'attached', 'snackbar-delete-role-error'
}); );
await expect(snackbar.variant).toBe('error');
/* /*
* TODO: await snackbar - make assertions based on product * TODO: await snackbar - make assertions based on product
* decisions * decisions
const snackbar = await adminRolesPage.getSnackbarData(); const snackbar = await adminRolesPage.getSnackbarData();
await expect(snackbar.variant).toBe('...'); await expect(snackbar.variant).toBe('...');
*/ */
await adminRolesPage.closeSnackbar();
}); });
}); });
}); });
@@ -362,16 +312,13 @@ test('Accessibility of role management page', async ({
await adminRolesPage.navigateTo(); await adminRolesPage.navigateTo();
await adminRolesPage.createRoleButton.click(); await adminRolesPage.createRoleButton.click();
await adminCreateRolePage.isMounted(); await adminCreateRolePage.isMounted();
await adminCreateRolePage.waitForPermissionsCatalogToVisible();
await adminCreateRolePage.nameInput.fill('Basic Test'); await adminCreateRolePage.nameInput.fill('Basic Test');
await adminCreateRolePage.createButton.click(); await adminCreateRolePage.createButton.click();
await adminCreateRolePage.snackbar.waitFor({
state: 'attached',
});
const snackbar = await adminCreateRolePage.getSnackbarData( const snackbar = await adminCreateRolePage.getSnackbarData(
'snackbar-create-role-success' 'snackbar-create-role-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminCreateRolePage.closeSnackbar();
}); });
await test.step('Create a new user with the basic role', async () => { 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' }) .getByRole('option', { name: 'Basic Test' })
.click(); .click();
await adminCreateUserPage.createButton.click(); await adminCreateUserPage.createButton.click();
await adminCreateUserPage.snackbar.waitFor({
state: 'attached',
});
await adminCreateUserPage.invitationEmailInfoAlert.waitFor({ await adminCreateUserPage.invitationEmailInfoAlert.waitFor({
state: 'attached', state: 'attached',
}); });
@@ -395,36 +339,27 @@ test('Accessibility of role management page', async ({
'snackbar-create-user-success' 'snackbar-create-user-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminCreateUserPage.closeSnackbar();
}); });
await test.step('Logout and login to the basic role user', async () => { await test.step('Logout and login to the basic role user', async () => {
const acceptInvitationLink = await adminCreateUserPage.acceptInvitationLink; const acceptInvitationLink = await adminCreateUserPage.acceptInvitationLink;
console.log(acceptInvitationLink);
const acceptInvitationUrl = await acceptInvitationLink.textContent(); const acceptInvitationUrl = await acceptInvitationLink.textContent();
console.log(acceptInvitationUrl);
const acceptInvitatonToken = acceptInvitationUrl.split('?token=')[1]; const acceptInvitatonToken = acceptInvitationUrl.split('?token=')[1];
await page.getByTestId('profile-menu-button').click(); await page.getByTestId('profile-menu-button').click();
await page.getByTestId('logout-item').click(); await page.getByTestId('logout-item').click();
const acceptInvitationPage = new AcceptInvitation(page); const acceptInvitationPage = new AcceptInvitation(page);
await acceptInvitationPage.open(acceptInvitatonToken); await acceptInvitationPage.open(acceptInvitatonToken);
await acceptInvitationPage.acceptInvitation('sample'); await acceptInvitationPage.acceptInvitation('sample');
const loginPage = new LoginPage(page); const loginPage = new LoginPage(page);
// await loginPage.isMounted();
await loginPage.login('basic-role-test@automatisch.io', 'sample'); await loginPage.login('basic-role-test@automatisch.io', 'sample');
await expect(loginPage.loginButton).not.toBeVisible(); await expect(loginPage.loginButton).not.toBeVisible();
await expect(page).toHaveURL('/flows'); await expect(page).toHaveURL('/flows');
}); });
await test.step( await test.step('Navigate to the admin settings page and make sure it is blank', async () => {
'Navigate to the admin settings page and make sure it is blank',
async () => {
const pageUrl = new URL(page.url()); const pageUrl = new URL(page.url());
const url = `${pageUrl.origin}/admin-settings/users`; const url = `${pageUrl.origin}/admin-settings/users`;
await page.goto(url); await page.goto(url);
@@ -443,8 +378,7 @@ test('Accessibility of role management page', async ({
return false; return false;
}); });
await expect(isUnmounted).toBe(true); await expect(isUnmounted).toBe(true);
} });
);
await test.step('Log back into the admin account', async () => { await test.step('Log back into the admin account', async () => {
await page.goto('/'); await page.goto('/');
@@ -465,10 +399,10 @@ test('Accessibility of role management page', async ({
await adminEditUserPage.roleInput.click(); await adminEditUserPage.roleInput.click();
await adminEditUserPage.page.getByRole('option', { name: 'Admin' }).click(); await adminEditUserPage.page.getByRole('option', { name: 'Admin' }).click();
await adminEditUserPage.updateButton.click(); await adminEditUserPage.updateButton.click();
await adminEditUserPage.snackbar.waitFor({ const snackbar = await adminEditUserPage.getSnackbarData(
state: 'attached', 'snackbar-edit-user-success'
}); );
await adminEditUserPage.closeSnackbar(); await expect(snackbar.variant).toBe('success');
}); });
await test.step('Delete the role', async () => { await test.step('Delete the role', async () => {
@@ -480,14 +414,10 @@ test('Accessibility of role management page', async ({
state: 'attached', state: 'attached',
}); });
await deleteModal.deleteButton.click(); await deleteModal.deleteButton.click();
await adminRolesPage.snackbar.waitFor({
state: 'attached',
});
const snackbar = await adminRolesPage.getSnackbarData( const snackbar = await adminRolesPage.getSnackbarData(
'snackbar-delete-role-success' 'snackbar-delete-role-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminRolesPage.closeSnackbar();
await deleteModal.modal.waitFor({ await deleteModal.modal.waitFor({
state: 'detached', state: 'detached',
}); });

View File

@@ -5,15 +5,16 @@ const { test, expect } = require('../../fixtures/index');
* otherwise tests will fail since users are only *soft*-deleted * otherwise tests will fail since users are only *soft*-deleted
*/ */
test.describe('User management page', () => { test.describe('User management page', () => {
test.beforeEach(async ({ adminUsersPage }) => { test.beforeEach(async ({ adminUsersPage }) => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
await adminUsersPage.closeSnackbar(); await adminUsersPage.closeAllSnackbars();
}); });
test( test('User creation and deletion process', async ({
'User creation and deletion process', adminCreateUserPage,
async ({ adminCreateUserPage, adminEditUserPage, adminUsersPage }) => { adminEditUserPage,
adminUsersPage,
}) => {
adminCreateUserPage.seed(9000); adminCreateUserPage.seed(9000);
const user = adminCreateUserPage.generateUser(); const user = adminCreateUserPage.generateUser();
await adminUsersPage.usersLoader.waitFor({ await adminUsersPage.usersLoader.waitFor({
@@ -21,21 +22,19 @@ test.describe('User management page', () => {
because visibility: hidden is used as part of the state transition in because visibility: hidden is used as part of the state transition in
notistack, see notistack, see
https://github.com/iamhosseindhv/notistack/blob/122f47057eb7ce5a1abfe923316cf8475303e99a/src/transitions/Collapse/Collapse.tsx#L110 https://github.com/iamhosseindhv/notistack/blob/122f47057eb7ce5a1abfe923316cf8475303e99a/src/transitions/Collapse/Collapse.tsx#L110
*/ */,
}); });
await test.step( await test.step('Create a user', async () => {
'Create a user',
async () => {
await adminUsersPage.createUserButton.click(); await adminUsersPage.createUserButton.click();
await adminCreateUserPage.fullNameInput.fill(user.fullName); await adminCreateUserPage.fullNameInput.fill(user.fullName);
await adminCreateUserPage.emailInput.fill(user.email); await adminCreateUserPage.emailInput.fill(user.email);
await adminCreateUserPage.roleInput.click(); await adminCreateUserPage.roleInput.click();
await adminCreateUserPage.page.getByRole( await adminCreateUserPage.page
'option', { name: 'Admin' } .getByRole('option', { name: 'Admin' })
).click(); .click();
await adminCreateUserPage.createButton.click(); await adminCreateUserPage.createButton.click();
await adminCreateUserPage.invitationEmailInfoAlert.waitFor({ await adminCreateUserPage.invitationEmailInfoAlert.waitFor({
state: 'attached' state: 'attached',
}); });
const snackbar = await adminUsersPage.getSnackbarData( const snackbar = await adminUsersPage.getSnackbarData(
@@ -43,23 +42,16 @@ test.describe('User management page', () => {
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
await adminUsersPage.closeSnackbar(); });
} await test.step('Check the user exists with the expected properties', async () => {
);
await test.step(
'Check the user exists with the expected properties',
async () => {
await adminUsersPage.findUserPageWithEmail(user.email); await adminUsersPage.findUserPageWithEmail(user.email);
const userRow = await adminUsersPage.getUserRowByEmail(user.email); const userRow = await adminUsersPage.getUserRowByEmail(user.email);
const data = await adminUsersPage.getRowData(userRow); const data = await adminUsersPage.getRowData(userRow);
await expect(data.email).toBe(user.email); await expect(data.email).toBe(user.email);
await expect(data.fullName).toBe(user.fullName); await expect(data.fullName).toBe(user.fullName);
await expect(data.role).toBe('Admin'); await expect(data.role).toBe('Admin');
} });
); await test.step('Edit user info and make sure the edit works correctly', async () => {
await test.step(
'Edit user info and make sure the edit works correctly',
async () => {
await adminUsersPage.findUserPageWithEmail(user.email); await adminUsersPage.findUserPageWithEmail(user.email);
let userRow = await adminUsersPage.getUserRowByEmail(user.email); let userRow = await adminUsersPage.getUserRowByEmail(user.email);
@@ -73,17 +65,13 @@ test.describe('User management page', () => {
'snackbar-edit-user-success' 'snackbar-edit-user-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminUsersPage.closeSnackbar();
await adminUsersPage.findUserPageWithEmail(user.email); await adminUsersPage.findUserPageWithEmail(user.email);
userRow = await adminUsersPage.getUserRowByEmail(user.email); userRow = await adminUsersPage.getUserRowByEmail(user.email);
const rowData = await adminUsersPage.getRowData(userRow); const rowData = await adminUsersPage.getRowData(userRow);
await expect(rowData.fullName).toBe(newUserInfo.fullName); await expect(rowData.fullName).toBe(newUserInfo.fullName);
} });
); await test.step('Delete user and check the page confirms this deletion', async () => {
await test.step(
'Delete user and check the page confirms this deletion',
async () => {
await adminUsersPage.findUserPageWithEmail(user.email); await adminUsersPage.findUserPageWithEmail(user.email);
const userRow = await adminUsersPage.getUserRowByEmail(user.email); const userRow = await adminUsersPage.getUserRowByEmail(user.email);
await adminUsersPage.clickDeleteUser(userRow); await adminUsersPage.clickDeleteUser(userRow);
@@ -94,41 +82,34 @@ test.describe('User management page', () => {
'snackbar-delete-user-success' 'snackbar-delete-user-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminUsersPage.closeSnackbar();
await expect(userRow).not.toBeVisible(false); await expect(userRow).not.toBeVisible(false);
} });
);
}); });
test( test('Creating a user which has been deleted', async ({
'Creating a user which has been deleted', adminCreateUserPage,
async ({ adminCreateUserPage, adminUsersPage }) => { adminUsersPage,
}) => {
adminCreateUserPage.seed(9100); adminCreateUserPage.seed(9100);
const testUser = adminCreateUserPage.generateUser(); const testUser = adminCreateUserPage.generateUser();
await test.step( await test.step('Create the test user', async () => {
'Create the test user',
async () => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
await adminUsersPage.createUserButton.click(); await adminUsersPage.createUserButton.click();
await adminCreateUserPage.fullNameInput.fill(testUser.fullName); await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
await adminCreateUserPage.emailInput.fill(testUser.email); await adminCreateUserPage.emailInput.fill(testUser.email);
await adminCreateUserPage.roleInput.click(); await adminCreateUserPage.roleInput.click();
await adminCreateUserPage.page.getByRole( await adminCreateUserPage.page
'option', { name: 'Admin' } .getByRole('option', { name: 'Admin' })
).click(); .click();
await adminCreateUserPage.createButton.click(); await adminCreateUserPage.createButton.click();
const snackbar = await adminUsersPage.getSnackbarData( const snackbar = await adminUsersPage.getSnackbarData(
'snackbar-create-user-success' 'snackbar-create-user-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminUsersPage.closeSnackbar(); });
}
);
await test.step( await test.step('Delete the created user', async () => {
'Delete the created user',
async () => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
await adminUsersPage.findUserPageWithEmail(testUser.email); await adminUsersPage.findUserPageWithEmail(testUser.email);
const userRow = await adminUsersPage.getUserRowByEmail(testUser.email); const userRow = await adminUsersPage.getUserRowByEmail(testUser.email);
@@ -140,129 +121,107 @@ test.describe('User management page', () => {
); );
await expect(snackbar).not.toBeNull(); await expect(snackbar).not.toBeNull();
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminUsersPage.closeSnackbar();
await expect(userRow).not.toBeVisible(false); await expect(userRow).not.toBeVisible(false);
} });
);
await test.step( await test.step('Create the user again', async () => {
'Create the user again',
async () => {
await adminUsersPage.createUserButton.click(); await adminUsersPage.createUserButton.click();
await adminCreateUserPage.fullNameInput.fill(testUser.fullName); await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
await adminCreateUserPage.emailInput.fill(testUser.email); await adminCreateUserPage.emailInput.fill(testUser.email);
await adminCreateUserPage.roleInput.click(); await adminCreateUserPage.roleInput.click();
await adminCreateUserPage.page.getByRole( await adminCreateUserPage.page
'option', { name: 'Admin' } .getByRole('option', { name: 'Admin' })
).click(); .click();
await adminCreateUserPage.createButton.click(); await adminCreateUserPage.createButton.click();
const snackbar = await adminUsersPage.getSnackbarData('snackbar-error'); const snackbar = await adminUsersPage.getSnackbarData('snackbar-error');
await expect(snackbar.variant).toBe('error'); await expect(snackbar.variant).toBe('error');
await adminUsersPage.closeSnackbar(); });
} });
);
}
);
test( test('Creating a user which already exists', async ({
'Creating a user which already exists', adminCreateUserPage,
async ({ adminCreateUserPage, adminUsersPage, page }) => { adminUsersPage,
page,
}) => {
adminCreateUserPage.seed(9200); adminCreateUserPage.seed(9200);
const testUser = adminCreateUserPage.generateUser(); const testUser = adminCreateUserPage.generateUser();
await test.step( await test.step('Create the test user', async () => {
'Create the test user',
async () => {
await adminUsersPage.createUserButton.click(); await adminUsersPage.createUserButton.click();
await adminCreateUserPage.fullNameInput.fill(testUser.fullName); await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
await adminCreateUserPage.emailInput.fill(testUser.email); await adminCreateUserPage.emailInput.fill(testUser.email);
await adminCreateUserPage.roleInput.click(); await adminCreateUserPage.roleInput.click();
await adminCreateUserPage.page.getByRole( await adminCreateUserPage.page
'option', { name: 'Admin' } .getByRole('option', { name: 'Admin' })
).click(); .click();
await adminCreateUserPage.createButton.click(); await adminCreateUserPage.createButton.click();
const snackbar = await adminUsersPage.getSnackbarData( const snackbar = await adminUsersPage.getSnackbarData(
'snackbar-create-user-success' 'snackbar-create-user-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminUsersPage.closeSnackbar(); });
}
);
await test.step( await test.step('Create the user again', async () => {
'Create the user again',
async () => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
await adminUsersPage.createUserButton.click(); await adminUsersPage.createUserButton.click();
await adminCreateUserPage.fullNameInput.fill(testUser.fullName); await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
await adminCreateUserPage.emailInput.fill(testUser.email); await adminCreateUserPage.emailInput.fill(testUser.email);
const createUserPageUrl = page.url(); const createUserPageUrl = page.url();
await adminCreateUserPage.roleInput.click(); await adminCreateUserPage.roleInput.click();
await adminCreateUserPage.page.getByRole( await adminCreateUserPage.page
'option', { name: 'Admin' } .getByRole('option', { name: 'Admin' })
).click(); .click();
await adminCreateUserPage.createButton.click(); await adminCreateUserPage.createButton.click();
await expect(page.url()).toBe(createUserPageUrl); await expect(page.url()).toBe(createUserPageUrl);
const snackbar = await adminUsersPage.getSnackbarData('snackbar-error'); const snackbar = await adminUsersPage.getSnackbarData('snackbar-error');
await expect(snackbar.variant).toBe('error'); await expect(snackbar.variant).toBe('error');
await adminUsersPage.closeSnackbar(); });
} });
);
}
);
test( test('Editing a user to have the same email as another user should not be allowed', async ({
'Editing a user to have the same email as another user should not be allowed', adminCreateUserPage,
async ({ adminEditUserPage,
adminCreateUserPage, adminEditUserPage, adminUsersPage, page adminUsersPage,
page,
}) => { }) => {
adminCreateUserPage.seed(9300); adminCreateUserPage.seed(9300);
const user1 = adminCreateUserPage.generateUser(); const user1 = adminCreateUserPage.generateUser();
const user2 = adminCreateUserPage.generateUser(); const user2 = adminCreateUserPage.generateUser();
await test.step( await test.step('Create the first user', async () => {
'Create the first user',
async () => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
await adminUsersPage.createUserButton.click(); await adminUsersPage.createUserButton.click();
await adminCreateUserPage.fullNameInput.fill(user1.fullName); await adminCreateUserPage.fullNameInput.fill(user1.fullName);
await adminCreateUserPage.emailInput.fill(user1.email); await adminCreateUserPage.emailInput.fill(user1.email);
await adminCreateUserPage.roleInput.click(); await adminCreateUserPage.roleInput.click();
await adminCreateUserPage.page.getByRole( await adminCreateUserPage.page
'option', { name: 'Admin' } .getByRole('option', { name: 'Admin' })
).click(); .click();
await adminCreateUserPage.createButton.click(); await adminCreateUserPage.createButton.click();
const snackbar = await adminUsersPage.getSnackbarData( const snackbar = await adminUsersPage.getSnackbarData(
'snackbar-create-user-success' 'snackbar-create-user-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminUsersPage.closeSnackbar(); await adminUsersPage.closeAllSnackbars();
} });
);
await test.step( await test.step('Create the second user', async () => {
'Create the second user',
async () => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
await adminUsersPage.createUserButton.click(); await adminUsersPage.createUserButton.click();
await adminCreateUserPage.fullNameInput.fill(user2.fullName); await adminCreateUserPage.fullNameInput.fill(user2.fullName);
await adminCreateUserPage.emailInput.fill(user2.email); await adminCreateUserPage.emailInput.fill(user2.email);
await adminCreateUserPage.roleInput.click(); await adminCreateUserPage.roleInput.click();
await adminCreateUserPage.page.getByRole( await adminCreateUserPage.page
'option', { name: 'Admin' } .getByRole('option', { name: 'Admin' })
).click(); .click();
await adminCreateUserPage.createButton.click(); await adminCreateUserPage.createButton.click();
const snackbar = await adminUsersPage.getSnackbarData( const snackbar = await adminUsersPage.getSnackbarData(
'snackbar-create-user-success' 'snackbar-create-user-success'
); );
await expect(snackbar.variant).toBe('success'); await expect(snackbar.variant).toBe('success');
await adminUsersPage.closeSnackbar(); });
}
);
await test.step( await test.step('Try editing the second user to have the email of the first user', async () => {
'Try editing the second user to have the email of the first user',
async () => {
await adminUsersPage.navigateTo(); await adminUsersPage.navigateTo();
await adminUsersPage.findUserPageWithEmail(user2.email); await adminUsersPage.findUserPageWithEmail(user2.email);
let userRow = await adminUsersPage.getUserRowByEmail(user2.email); let userRow = await adminUsersPage.getUserRowByEmail(user2.email);
@@ -272,14 +231,9 @@ test.describe('User management page', () => {
const editPageUrl = page.url(); const editPageUrl = page.url();
await adminEditUserPage.updateButton.click(); await adminEditUserPage.updateButton.click();
const snackbar = await adminUsersPage.getSnackbarData( const snackbar = await adminUsersPage.getSnackbarData('snackbar-error');
'snackbar-error'
);
await expect(snackbar.variant).toBe('error'); await expect(snackbar.variant).toBe('error');
await adminUsersPage.closeSnackbar();
await expect(page.url()).toBe(editPageUrl); await expect(page.url()).toBe(editPageUrl);
} });
); });
}
);
}); });

View File

@@ -1,24 +1,55 @@
const { request } = require('@playwright/test');
const { test, expect } = require('../../fixtures/index'); 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.describe('Pop-up message on connections', () => {
test.beforeEach(async ({ flowEditorPage, page }) => { test.beforeEach(async ({ flowEditorPage, page }) => {
await page.getByTestId('create-flow-button').click(); const apiRequest = await request.newContext();
await page.waitForURL( const tokenJsonResponse = await getToken(apiRequest);
/\/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}/ const token = tokenJsonResponse.data.token;
);
await expect(page.getByTestId('flow-step')).toHaveCount(2);
await flowEditorPage.flowName.click(); let flow = await createFlow(apiRequest, token);
await flowEditorPage.flowNameInput.fill('PopupFlow'); const flowId = flow.data.id;
await flowEditorPage.createWebhookTrigger(true); 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'); const triggerStepId = flowSteps.find((step) => step.type === 'trigger').id;
await expect(flowEditorPage.continueButton).toHaveCount(1); const actionStepId = flowSteps.find((step) => step.type === 'action').id;
await expect(flowEditorPage.continueButton).not.toBeEnabled();
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.connectionAutocomplete.click();
await flowEditorPage.addNewConnectionItem.click(); }); await flowEditorPage.addNewConnectionItem.click();
});
test('should show error to remind to enable pop-up on connection create', async ({ test('should show error to remind to enable pop-up on connection create', async ({
page, page,
@@ -37,8 +68,10 @@ test.describe('Pop-up message on connections', () => {
await addMattermostConnectionModal.fillConnectionForm(); await addMattermostConnectionModal.fillConnectionForm();
await addMattermostConnectionModal.submitConnectionForm(); await addMattermostConnectionModal.submitConnectionForm();
await expect(page.getByTestId("add-connection-error")).toHaveCount(1); 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')).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 ({ 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(); await addMattermostConnectionModal.submitConnectionForm();
const popup = await popupPromise; const popup = await popupPromise;
await expect(popup.url()).toContain("mattermost"); await expect(popup.url()).toContain('mattermost');
await expect(page.getByTestId("add-connection-error")).toHaveCount(0); await expect(page.getByTestId('add-connection-error')).toHaveCount(0);
await test.step('Should show error on failed credentials verification', async () => { await test.step('Should show error on failed credentials verification', async () => {
await popup.close(); await popup.close();
await expect(page.getByTestId("add-connection-error")).toHaveCount(1); 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')).toHaveText(
'Error occured while verifying credentials!'
);
}); });
}); });
}); });

View File

@@ -1,57 +1,38 @@
const { request } = require('@playwright/test');
const { publicTest, expect } = require('../../fixtures/index'); const { publicTest, expect } = require('../../fixtures/index');
const { AdminUsersPage } = require('../../fixtures/admin/users-page');
const { MyProfilePage } = require('../../fixtures/my-profile-page'); const { MyProfilePage } = require('../../fixtures/my-profile-page');
const { LoginPage } = require('../../fixtures/login-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', () => { publicTest.describe('My Profile', () => {
let testUser; let testUser;
publicTest.beforeEach( publicTest.beforeEach(
async ({ acceptInvitationPage, adminCreateUserPage, loginPage, page }) => { async ({ adminCreateUserPage, loginPage, page }) => {
let acceptInvitationLink; let addUserResponse;
const apiRequest = await request.newContext();
adminCreateUserPage.seed( adminCreateUserPage.seed(
Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER) Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER)
); );
testUser = adminCreateUserPage.generateUser(); 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 publicTest.step('create new user', async () => {
await adminUsersPage.navigateTo(); const tokenJsonResponse = await getToken(apiRequest);
await adminUsersPage.createUserButton.click(); addUserResponse = await addUser(
await adminCreateUserPage.fullNameInput.fill(testUser.fullName); apiRequest,
await adminCreateUserPage.emailInput.fill(testUser.email); tokenJsonResponse.data.token,
await adminCreateUserPage.roleInput.click(); {
await adminCreateUserPage.page fullName: testUser.fullName,
.getByRole('option', { name: 'Admin' }) email: testUser.email,
.click(); }
await adminCreateUserPage.createButton.click();
const snackbar = await adminUsersPage.getSnackbarData(
'snackbar-create-user-success'
); );
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 publicTest.step('accept invitation', async () => {
await page.goto(acceptInvitationLink); let acceptToken = addUserResponse.data.acceptInvitationUrl.split('=')[1];
await acceptInvitationPage.acceptInvitation(LoginPage.defaultPassword); await acceptInvitation(apiRequest, {token:acceptToken, password:LoginPage.defaultPassword});
}); });
await publicTest.step('login as new Admin', async () => { await publicTest.step('login as new Admin', async () => {

View File

@@ -79,7 +79,7 @@
"@nodelib/fs.scandir" "2.1.5" "@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0" fastq "^1.6.0"
"@playwright/test@^1.45.1": "@playwright/test@1.49.0":
version "1.49.0" version "1.49.0"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.49.0.tgz#74227385b58317ee076b86b56d0e1e1b25cff01e" resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.49.0.tgz#74227385b58317ee076b86b56d0e1e1b25cff01e"
integrity sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw== integrity sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==

View File

@@ -30,7 +30,7 @@ const PermissionCatalogField = ({
if (isPermissionCatalogLoading) return <PermissionCatalogFieldLoader />; if (isPermissionCatalogLoading) return <PermissionCatalogFieldLoader />;
return ( return (
<TableContainer component={Paper}> <TableContainer data-test="permissions-catalog" component={Paper}>
<Table> <Table>
<TableHead> <TableHead>
<TableRow> <TableRow>