Skip to content

Commit 6e17528

Browse files
committed
WIP: Add Playwright end-to-end tests
1 parent dafd31b commit 6e17528

File tree

9 files changed

+774
-8
lines changed

9 files changed

+774
-8
lines changed

.github/workflows/playwright.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Playwright Tests
2+
on:
3+
push:
4+
branches:
5+
- main
6+
- playwright
7+
pull_request:
8+
branches:
9+
- main
10+
jobs:
11+
test:
12+
timeout-minutes: 60
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: actions/setup-node@v4
17+
with:
18+
node-version: 20
19+
cache: 'npm'
20+
- name: Install dependencies
21+
run: npm ci
22+
- name: Install Playwright Browsers
23+
run: npx playwright install --with-deps chromium
24+
- name: Run Playwright tests
25+
run: npx playwright test
26+
- uses: actions/upload-artifact@v4
27+
if: always()
28+
with:
29+
name: playwright-report
30+
path: playwright-report/
31+
retention-days: 7

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@
44
/src/treetop/generated/*.css
55
/web-ext-artifacts/
66
/.vscode/
7+
/test-results/
8+
/playwright-report/
9+
/blob-report/
10+
/playwright/.cache/

e2e/bookmarks.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { test, expect } from './fixtures';
2+
3+
test.beforeEach(async ({ page, extensionId }, _testInfo) => {
4+
await page.goto(`chrome-extension://${extensionId}/treetop.html`);
5+
6+
await page.evaluate(async () => {
7+
await chrome.bookmarks.create({
8+
parentId: '1',
9+
url: 'https://github.com',
10+
title: 'GitHub',
11+
});
12+
await chrome.bookmarks.create({
13+
parentId: '2',
14+
url: 'https://gitlab.com',
15+
title: 'GitLab',
16+
});
17+
});
18+
});
19+
20+
test('existing bookmarks', async ({ page }) => {
21+
const rootFolder = page.locator('.folder').first();
22+
const bookmarksBarContents = rootFolder.locator('.folder > .contents').nth(0);
23+
await expect(bookmarksBarContents).toHaveCount(1);
24+
expect(
25+
bookmarksBarContents.getByRole('link', { name: 'GitHub' }),
26+
).toBeVisible();
27+
28+
const otherBookmarksContents = rootFolder
29+
.locator('.folder > .contents')
30+
.nth(1);
31+
await expect(otherBookmarksContents).toHaveCount(1);
32+
expect(
33+
otherBookmarksContents.getByRole('link', { name: 'GitLab' }),
34+
).toBeVisible();
35+
});

e2e/default.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { test, expect } from './fixtures';
2+
3+
test.beforeEach(async ({ page, extensionId }, _testInfo) => {
4+
await page.goto(`chrome-extension://${extensionId}/treetop.html`);
5+
});
6+
7+
test('page header', async ({ page }) => {
8+
const banner = page.getByRole('banner');
9+
await expect(banner.locator('.treetop')).toHaveText('Treetop');
10+
await expect(banner.getByRole('textbox')).toBeVisible();
11+
await expect(banner.getByRole('textbox')).toHaveText('');
12+
await expect(banner.getByRole('button')).toHaveText(/settings/i);
13+
});
14+
15+
test('default bookmarks', async ({ page }) => {
16+
// Root folder
17+
const rootFolder = page.locator('.folder').first();
18+
await expect(rootFolder.locator('.heading').first()).toHaveText('Bookmarks');
19+
20+
// Bookmarks bar
21+
const bookmarksBar = rootFolder.locator('.folder > .heading').nth(0);
22+
const bookmarksBarContents = rootFolder.locator('.folder > .contents').nth(0);
23+
24+
await expect(bookmarksBar).toHaveText('Bookmarks bar');
25+
await expect(bookmarksBarContents).toHaveText('Empty folder');
26+
27+
// Other bookmarks
28+
const otherBookmarks = rootFolder.locator('.folder > .heading').nth(1);
29+
const otherBookmarksContents = rootFolder
30+
.locator('.folder > .contents')
31+
.nth(1);
32+
33+
await expect(otherBookmarks).toHaveText('Other bookmarks');
34+
await expect(otherBookmarksContents).toHaveText('Empty folder');
35+
});

e2e/fixtures.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { test as base, chromium, type BrowserContext } from '@playwright/test';
2+
import path from 'path';
3+
4+
export const test = base.extend<{
5+
context: BrowserContext;
6+
extensionId: string;
7+
}>({
8+
context: async ({}, use) => {
9+
const pathToExtension = './dist/chrome';
10+
const context = await chromium.launchPersistentContext('', {
11+
headless: false,
12+
args: [
13+
`--headless=new`,
14+
`--disable-extensions-except=${pathToExtension}`,
15+
`--load-extension=${pathToExtension}`,
16+
],
17+
});
18+
await use(context);
19+
await context.close();
20+
},
21+
extensionId: async ({ context }, use) => {
22+
let [background] = context.serviceWorkers();
23+
if (!background) {
24+
background = await context.waitForEvent('serviceworker');
25+
}
26+
27+
const extensionId = background.url().split('/')[2];
28+
await use(extensionId);
29+
},
30+
});
31+
32+
export const expect = test.expect;

package-lock.json

Lines changed: 121 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"@fontsource/inter": "~5.0.16",
3535
"@fontsource/material-icons": "~5.0.11",
3636
"@fontsource/news-cycle": "~5.0.18",
37+
"@playwright/test": "~1.40.1",
3738
"@smui/button": "~7.0.0-beta.16",
3839
"@smui/dialog": "~7.0.0-beta.16",
3940
"@smui/icon-button": "~7.0.0-beta.16",
@@ -47,6 +48,7 @@
4748
"@tsconfig/svelte": "~5.0.2",
4849
"@types/faker": "5.5.9",
4950
"@types/lodash-es": "~4.17.12",
51+
"@types/node": "~20.10.5",
5052
"@typescript-eslint/eslint-plugin": "~6.16.0",
5153
"@typescript-eslint/parser": "~6.16.0",
5254
"chrome-types": "~0.1.246",

0 commit comments

Comments
 (0)