Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Playwright E2E test - sign up with invite link via email #9332

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci-e2e.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
name: CI E2E Tests
name: CI E2E Playwright Tests
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, labeled]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down
2 changes: 0 additions & 2 deletions packages/twenty-e2e-testing/.env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# Note that provide always without trailing forward slash to have expected behaviour
FRONTEND_BASE_URL=http://localhost:3001
[email protected]
[email protected]
[email protected]
DEFAULT_PASSWORD=Applecar2025
BOHEUS marked this conversation as resolved.
Show resolved Hide resolved
WEBSITE_URL=https://twenty.com

Expand Down
21 changes: 6 additions & 15 deletions packages/twenty-e2e-testing/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ if (envResult.error) {
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: '.',
testDir: './tests',
outputDir: 'run_results/', // directory for screenshots and videos
snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}', // just in case, do not delete it
fullyParallel: true, // false only for specific tests, overwritten in specific projects or global setups of projects
fullyParallel: false, // parallelization of tests will be done later in the future
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: 1, // 1 worker = 1 test at the time, tests can't be parallelized
Expand Down Expand Up @@ -49,25 +49,16 @@ export default defineConfig({
use: {
...devices['Desktop Chrome'],
},
testMatch: /demo\/demo_basic\.spec\.ts/,
testMatch: /demo\/demo_basic\.e2e-spec\.ts/,
},
{
name: 'chromium',
name: 'Authentication',
use: {
...devices['Desktop Chrome'],
permissions: ['clipboard-read', 'clipboard-write'],
storageState: path.resolve(__dirname, '.auth', 'user.json'), // takes saved cookies from directory
},
dependencies: ['Login setup'], // forces to run login setup before running tests from this project - CASE SENSITIVE
testMatch: /all\/.+\.e2e-spec\.ts/,
},
{
name: 'firefox',
use: {
...devices['Desktop Firefox'],
storageState: path.resolve(__dirname, '.auth', 'user.json'),
},
dependencies: ['Login setup'],
testMatch: /all\/.+\.e2e-spec\.ts/,
testMatch: /authentication\/.+\.e2e-spec\.ts/, // forces to run login setup before running tests from this project - CASE SENSITIVE
},

//{
Expand Down
16 changes: 0 additions & 16 deletions packages/twenty-e2e-testing/tests/all/companies.e2e-spec.ts

This file was deleted.

40 changes: 0 additions & 40 deletions packages/twenty-e2e-testing/tests/all/workspaces.e2e-spec.ts

This file was deleted.

45 changes: 45 additions & 0 deletions packages/twenty-e2e-testing/tests/authentication/fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { test as base } from '../../lib/fixtures/screenshot';
import { LoginPage } from '../../lib/pom/loginPage';
import { LeftMenu } from '../../lib/pom/leftMenu';
import { SettingsPage } from '../../lib/pom/settingsPage';
import { MembersSection } from '../../lib/pom/settings/membersSection';
import { ProfileSection } from '../../lib/pom/settings/profileSection';
import { ConfirmationModal } from '../../lib/pom/helper/confirmationModal';

type Fixtures = {
confirmationModal: ConfirmationModal;
loginPage: LoginPage;
leftMenu: LeftMenu;
settingsPage: SettingsPage;
membersSection: MembersSection;
profileSection: ProfileSection;
};

export const test = base.extend<Fixtures>({
confirmationModal: async ({ page }, use) => {
const confirmationModal = new ConfirmationModal(page);
await use(confirmationModal);
},
loginPage: async ({ page }, use) => {
const loginPage = new LoginPage(page);
await use(loginPage);
},
leftMenu: async ({ page }, use) => {
const leftMenu = new LeftMenu(page);
await use(leftMenu);
},
settingsPage: async ({ page }, use) => {
const settingsPage = new SettingsPage(page);
await use(settingsPage);
},
membersSection: async ({ page }, use) => {
const membersSection = new MembersSection(page);
await use(membersSection);
},
profileSection: async ({ page }, use) => {
const profileSection = new ProfileSection(page);
await use(profileSection);
},
});

export { expect } from '@playwright/test';
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { expect, test } from './fixture';

test.describe('Authentication test', () => {
const email = '[email protected]';
const firstName = 'John';
const lastName = 'Doe';
let testCompleted = false;

test('Sign up with invite link via email', async ({
page,
loginPage,
leftMenu,
membersSection,
settingsPage,
}) => {
await page.goto(process.env.LINK); // skip login page (and redirect) when running on environments with multi-workspace enabled
await leftMenu.goToSettings();
await settingsPage.goToMembersSection();
await membersSection.copyInviteLink();
const inviteLink: string = await page.evaluate(
'navigator.clipboard.readText()',
);
BOHEUS marked this conversation as resolved.
Show resolved Hide resolved
await settingsPage.logout();
await page.goto(inviteLink);
await loginPage.clickLoginWithEmail();
await loginPage.typeEmail(email);
await loginPage.clickContinueButton();
await loginPage.typePassword(process.env.DEFAULT_PASSWORD);
await loginPage.clickSignInButton();
await loginPage.typeFirstName(firstName);
await loginPage.typeLastName(lastName);
await loginPage.clickContinueButton();
await loginPage.noSyncWithGoogle();
testCompleted = true;
});

test.afterEach(
async ({
page,
confirmationModal,
leftMenu,
profileSection,
settingsPage,
}) => {
if (testCompleted) {
// security measurement to clean up only after test is completed,
// otherwise default account used for tests may be deleted and resetting database will be necessary
await leftMenu.goToSettings();
await settingsPage.goToProfileSection();
await profileSection.deleteAccount();
await confirmationModal.typePlaceholderToInput();
await confirmationModal.clickConfirmButton();
expect(page.url()).toContain('/welcome');
BOHEUS marked this conversation as resolved.
Show resolved Hide resolved
}
},
);
});
32 changes: 21 additions & 11 deletions packages/twenty-e2e-testing/tests/login.setup.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
import { expect, test as setup } from '@playwright/test';
import { expect, test as base } from '@playwright/test';
import { LoginPage } from '../lib/pom/loginPage';
import path from 'path';

setup('Login test', async ({ page }) => {
// fixture
const test = base.extend<{ loginPage: LoginPage }>({
loginPage: async ({ page }, use) => {
const loginPage = new LoginPage(page);
await use(loginPage);
},
});

test('Login test', async ({ loginPage, page }) => {
console.log('Starting login test');

await page.goto('/');
console.log('Navigated to homepage');

await page.getByRole('button', { name: 'Continue With Email' }).click();
console.log('Clicked email login button');
await page.waitForLoadState('networkidle'); // wait as a precaution for environments with multi-workspace enabled
if (page.url().includes('demo.twenty.com') || !page.url().includes('app.localhost:3001')) {
await loginPage.clickLoginWithEmail();
}

console.log('Default login', process.env.DEFAULT_LOGIN);
await page.getByPlaceholder('Email').fill(process.env.DEFAULT_LOGIN ?? '');
await loginPage.typeEmail(process.env.DEFAULT_LOGIN);
console.log('Filled email field');
BOHEUS marked this conversation as resolved.
Show resolved Hide resolved

await page.getByRole('button', { name: 'Continue', exact: true }).click();
await loginPage.clickContinueButton();
console.log('Clicked continue button');

await page
.getByPlaceholder('Password')
.fill(process.env.DEFAULT_PASSWORD ?? '');
await loginPage.typePassword(process.env.DEFAULT_PASSWORD);
console.log('Filled password field');

await page.getByRole('button', { name: 'Sign in' }).click();
await loginPage.clickSignInButton();
console.log('Clicked sign in button');

await page.waitForLoadState('networkidle');
Expand All @@ -35,4 +43,6 @@ setup('Login test', async ({ page }) => {
path: path.resolve(__dirname, '..', '.auth', 'user.json'),
});
console.log('Saved auth state');

process.env.LINK = page.url();
});
BOHEUS marked this conversation as resolved.
Show resolved Hide resolved
Loading