Skip to content

Commit 5ed6ffa

Browse files
apognuChibiBlasphem
authored andcommitted
Add basic Playwright tests.
1 parent 2bd8022 commit 5ed6ffa

23 files changed

Lines changed: 811 additions & 827 deletions

.github/workflows/playground.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: E2E tests
2+
3+
on:
4+
push:
5+
branches: [poc/playwright]
6+
7+
jobs:
8+
e2e:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
- uses: actions/setup-node@v4
13+
- uses: pnpm/action-setup@v4
14+
- run: pnpm install --frozen-lockfile
15+
- run: pnpm --filter tests exec playwright install
16+
- run: pnpm --filter tests run test
17+
- uses: actions/upload-artifact@v4
18+
if: ${{ !cancelled() }}
19+
with:
20+
name: playwright-report
21+
path: |
22+
packages/tests/playwright-report/
23+
packages/tests/trace.zip
24+
retention-days: 1

packages/tests/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ node_modules/
33
/playwright-report/
44
/blob-report/
55
/playwright/.cache/
6+
/auth.json

packages/tests/common/utils.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { Locator, Page } from '@playwright/test';
2+
3+
export const waitForThen = async (
4+
page: Page,
5+
locator: Locator,
6+
callback: (locator: Locator) => Promise<void>,
7+
state: 'attached' | 'detached' | 'visible' | 'hidden' = 'visible',
8+
) => {
9+
await locator.waitFor({ state });
10+
await callback(locator);
11+
await page.waitForLoadState();
12+
};

packages/tests/e2e/001-user-signin-flow.test.ts

Lines changed: 0 additions & 63 deletions
This file was deleted.

packages/tests/e2e/002-custom-lists.test.ts

Lines changed: 0 additions & 51 deletions
This file was deleted.

packages/tests/e2e/003-scenario-publication.test.ts

Lines changed: 0 additions & 94 deletions
This file was deleted.

packages/tests/e2e/auth.spec.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { expect, test } from '@playwright/test';
2+
import path from 'path';
3+
import { fileURLToPath } from 'url';
4+
5+
test('Initial login page', async ({ page }) => {
6+
await page.goto('/');
7+
await page.waitForURL('/sign-in');
8+
9+
await expect(page).toHaveTitle('Marble');
10+
await expect(page.getByText('Great rules are built with the Right Tools')).toBeVisible();
11+
});
12+
13+
test('Invalid username', async ({ page }) => {
14+
await page.goto('/sign-in');
15+
16+
await page
17+
.getByRole('textbox')
18+
.and(page.locator('[name="credentials.email"]'))
19+
.fill('invalid@zorg.com');
20+
await page
21+
.getByRole('textbox')
22+
.and(page.locator('[name="credentials.password"]'))
23+
.fill('very-secret');
24+
await page.getByRole('button', { name: 'Sign in', exact: true }).click();
25+
26+
await expect(page.getByText('No user account found for this address.')).toBeVisible();
27+
});
28+
29+
test('Invalid password', async ({ page }) => {
30+
await page.goto('/sign-in');
31+
32+
await page
33+
.getByRole('textbox')
34+
.and(page.locator('[name="credentials.email"]'))
35+
.fill('jbe@zorg.com');
36+
await page
37+
.getByRole('textbox')
38+
.and(page.locator('[name="credentials.password"]'))
39+
.fill('invalid');
40+
await page.getByRole('button', { name: 'Sign in', exact: true }).click();
41+
42+
await expect(page.getByText('Wrong password.')).toBeVisible();
43+
});
44+
45+
const authState = path.join(path.dirname(fileURLToPath(import.meta.url)), '../auth.json');
46+
47+
test('Authentication', async ({ page }) => {
48+
await page.goto('/sign-in');
49+
50+
await page
51+
.getByRole('textbox')
52+
.and(page.locator('[name="credentials.email"]'))
53+
.fill('jbe@zorg.com');
54+
await page
55+
.getByRole('textbox')
56+
.and(page.locator('[name="credentials.password"]'))
57+
.fill('very-secret');
58+
await page.getByRole('button', { name: 'Sign in', exact: true }).click();
59+
60+
await page.waitForURL('/scenarios');
61+
62+
await expect(page.locator('nav').getByRole('link', { name: 'Scenarios ' })).toBeVisible();
63+
64+
await page.context().storageState({ path: authState, indexedDB: true });
65+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { expect, test } from '@playwright/test';
2+
import crypto from 'crypto';
3+
import { waitForThen } from 'tests/common/utils';
4+
5+
test('Create new list', async ({ page }) => {
6+
await page.goto('/lists');
7+
8+
const listName = crypto.randomUUID();
9+
const values = Array.from({ length: 5 }, () => crypto.randomUUID());
10+
11+
await page.getByRole('button', { name: 'New List' }).click();
12+
await page.getByRole('textbox', { name: 'Name' }).fill(listName);
13+
await page.getByRole('textbox', { name: 'Description' }).fill('Lorem ipsum dolor sit amet');
14+
15+
await waitForThen(
16+
page,
17+
page.getByRole('button', { name: 'Create new list' }),
18+
async (button) => await button.click(),
19+
);
20+
21+
await page.waitForURL('/lists/**');
22+
await page.waitForLoadState();
23+
24+
for (const value of values) {
25+
await waitForThen(page, page.getByRole('button', { name: 'New value' }), async (button) =>
26+
button.click(),
27+
);
28+
29+
await waitForThen(
30+
page,
31+
page.getByRole('textbox', { name: 'Value' }),
32+
async (field) => await field.fill(value),
33+
);
34+
35+
await page.getByRole('button', { name: 'Save' }).click();
36+
await page.getByRole('textbox', { name: 'Value' }).waitFor({ state: 'hidden' });
37+
}
38+
39+
await page.getByRole('listitem').filter({ hasText: 'Lists' }).getByRole('link').click();
40+
await page.waitForURL('/lists');
41+
await page.waitForLoadState();
42+
43+
await page.getByRole('cell', { name: listName }).click();
44+
await page.waitForURL('/lists/**');
45+
await page.waitForLoadState();
46+
47+
for (const value of values) {
48+
await expect(page.locator('table')).toContainText(value);
49+
}
50+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { expect, test } from '@playwright/test';
2+
import crypto from 'crypto';
3+
import { waitForThen } from 'tests/common/utils';
4+
5+
test('Create a user', async ({ page }) => {
6+
await page.goto('/settings');
7+
await page.waitForURL('/settings/users');
8+
9+
await waitForThen(
10+
page,
11+
page.getByRole('button', { name: 'New user' }),
12+
async (button) => await button.click(),
13+
);
14+
15+
const fn = crypto.randomUUID();
16+
const ln = crypto.randomUUID();
17+
const email = `${crypto.randomUUID()}@example.com`;
18+
19+
await page.getByRole('textbox').and(page.locator('[name="firstName"]')).fill(fn);
20+
await page.getByRole('textbox').and(page.locator('[name="lastName"]')).fill(ln);
21+
await page.getByRole('textbox').and(page.locator('[name="email"]')).fill(email);
22+
await page.getByRole('button', { name: 'Create new user' }).click();
23+
24+
await expect(page.locator('table')).toContainText(`${fn} ${ln}`);
25+
await expect(page.locator('table')).toContainText(email);
26+
});

0 commit comments

Comments
 (0)