Compare commits

...

2 Commits

Author SHA1 Message Date
Ilia Mashkov f79b24272c ci/cd: add e2e tests with playwright into gitea actions workflow 2026-05-28 13:20:25 +03:00
Ilia Mashkov a9229342e6 test: base playwrignt setup for firefox and chrome 2026-05-28 12:55:10 +03:00
7 changed files with 176 additions and 4 deletions
+49
View File
@@ -50,6 +50,55 @@ jobs:
timeout-minutes: 5
run: yarn test:component --reporter=verbose --logHeapUsage
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: svelte-static-dist
path: |
dist/
package.json
e2e:
needs: build
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.59.0-jammy
steps:
- uses: actions/checkout@v4
- name: Enable Corepack
run: |
corepack enable
corepack prepare yarn@stable --activate
- name: Persistent Yarn Cache
uses: actions/cache@v4
with:
path: .yarn/cache
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install --immutable
# Pull down the compiled dist folder so Vite can preview it
- name: Download Build Artifacts
uses: actions/download-artifact@v4
with:
name: svelte-static-dist
- name: E2E Tests
timeout-minutes: 15
run: yarn test:e2e
- name: Upload Playwright report
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
retention-days: 7
publish:
needs: build # Only runs if tests/lint pass
runs-on: ubuntu-latest
+3
View File
@@ -50,3 +50,6 @@ storybook-static
# Tests
coverage/
.aider*
playwright-report/
blob-report/
.playwright/
+16
View File
@@ -0,0 +1,16 @@
import type { Page } from '@playwright/test';
/**
* Shared base for all page objects. Subclasses extend this and expose
* domain-specific locators + actions — never raw selectors leaking into tests.
*/
export abstract class BasePage {
protected constructor(protected readonly page: Page) {}
/**
* Navigate to a path relative to baseURL.
*/
async goto(path = '/') {
await this.page.goto(path);
}
}
+36
View File
@@ -0,0 +1,36 @@
import type {
Locator,
Page,
} from '@playwright/test';
import { BasePage } from './base-page';
/**
* Page object for the root comparison view. Encapsulates locators for the
* primary controls so tests don't hardcode aria-labels or DOM structure.
*/
export class ComparisonPage extends BasePage {
readonly searchInput: Locator;
readonly previewInput: Locator;
constructor(page: Page) {
super(page);
this.searchInput = page.getByRole('textbox', { name: 'Search typefaces' });
this.previewInput = page.getByRole('textbox', { name: 'Preview text' });
}
/**
* Open the root page and wait for the main controls to be interactable.
*/
async open() {
await this.goto('/');
await this.searchInput.waitFor({ state: 'visible' });
}
async searchFor(query: string) {
await this.searchInput.fill(query);
}
async setPreviewText(text: string) {
await this.previewInput.fill(text);
}
}
+23
View File
@@ -0,0 +1,23 @@
import {
expect,
test,
} from '@playwright/test';
import { ComparisonPage } from './pages/comparison-page';
test.describe('smoke', () => {
test('loads the comparison view with its primary controls', async ({ page }) => {
const view = new ComparisonPage(page);
await view.open();
await expect(view.searchInput).toBeVisible();
await expect(view.previewInput).toBeVisible();
});
test('accepts a search query', async ({ page }) => {
const view = new ComparisonPage(page);
await view.open();
await view.searchFor('Inter');
await expect(view.searchInput).toHaveValue('Inter');
});
});
+47 -3
View File
@@ -1,10 +1,54 @@
import { defineConfig } from '@playwright/test';
import {
defineConfig,
devices,
} from '@playwright/test';
/**
* E2E config. Tests run against the production build via `vite preview` on port 4173.
* Locally: all three browser engines run in parallel.
* CI: chromium only, workers=1 — the runner has 6GB RAM and `yarn build` already
* spikes 12GB, so we keep the E2E peak bounded.
*/
const isCI = !!process.env.CI;
export default defineConfig({
testDir: 'e2e',
testMatch: /.*\.test\.ts$/,
fullyParallel: true,
forbidOnly: isCI,
retries: isCI ? 2 : 0,
workers: isCI ? 1 : undefined,
reporter: isCI
? [['html', { open: 'never' }], ['github']]
: [['html', { open: 'on-failure' }], ['list']],
use: {
baseURL: 'http://localhost:4173',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: isCI
? [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }]
: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
},
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
],
webServer: {
command: 'yarn build && yarn preview',
port: 4173,
reuseExistingServer: true,
reuseExistingServer: !isCI,
timeout: 120_000,
},
testDir: 'e2e',
});
+2 -1
View File
@@ -40,7 +40,8 @@
"src/**/*.d.ts",
"vitest.config*.ts",
"vitest.setup*.ts",
"vitest.types.d.ts"
"vitest.types.d.ts",
"playwright.config*.ts"
],
"exclude": [
"node_modules",