test: base playwrignt setup for firefox and chrome
This commit is contained in:
@@ -50,3 +50,6 @@ storybook-static
|
|||||||
# Tests
|
# Tests
|
||||||
coverage/
|
coverage/
|
||||||
.aider*
|
.aider*
|
||||||
|
playwright-report/
|
||||||
|
blob-report/
|
||||||
|
.playwright/
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
@@ -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 1–2GB, so we keep the E2E peak bounded.
|
||||||
|
*/
|
||||||
|
const isCI = !!process.env.CI;
|
||||||
|
|
||||||
export default defineConfig({
|
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: {
|
webServer: {
|
||||||
command: 'yarn build && yarn preview',
|
command: 'yarn build && yarn preview',
|
||||||
port: 4173,
|
port: 4173,
|
||||||
reuseExistingServer: true,
|
reuseExistingServer: !isCI,
|
||||||
|
timeout: 120_000,
|
||||||
},
|
},
|
||||||
testDir: 'e2e',
|
|
||||||
});
|
});
|
||||||
|
|||||||
+2
-1
@@ -40,7 +40,8 @@
|
|||||||
"src/**/*.d.ts",
|
"src/**/*.d.ts",
|
||||||
"vitest.config*.ts",
|
"vitest.config*.ts",
|
||||||
"vitest.setup*.ts",
|
"vitest.setup*.ts",
|
||||||
"vitest.types.d.ts"
|
"vitest.types.d.ts",
|
||||||
|
"playwright.config*.ts"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
|||||||
Reference in New Issue
Block a user