Setup playwright e2e initial test

This commit is contained in:
Richard Roberson 2025-03-01 22:44:30 -07:00
parent 3568f3c8f9
commit 28a3804843
8 changed files with 252 additions and 3 deletions

31
.github/workflows/playwright.yml vendored Normal file
View file

@ -0,0 +1,31 @@
name: Playwright Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
env:
NEXT_PUBLIC_NODE_ENV: test
API_BASE: https://tts.richardr.dev/v1
API_KEY: not-needed
run: npx playwright test --reporter=list,github,html
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30

7
.gitignore vendored
View file

@ -43,3 +43,10 @@ next-env.d.ts
# documents
/docstore
# Playwright
node_modules/
/tests/results/
/playwright-report/
/blob-report/
/playwright/.cache/

68
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "openreader-webui",
"version": "0.1.3",
"version": "0.2.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openreader-webui",
"version": "0.1.3",
"version": "0.2.3",
"dependencies": {
"@headlessui/react": "^2.2.0",
"@types/howler": "^2.2.12",
@ -31,6 +31,7 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@playwright/test": "^1.50.1",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
@ -990,6 +991,22 @@
"node": ">=14"
}
},
"node_modules/@playwright/test": {
"version": "1.50.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz",
"integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.50.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@react-aria/focus": {
"version": "3.19.1",
"resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.19.1.tgz",
@ -5474,6 +5491,53 @@
"node": ">= 6"
}
},
"node_modules/playwright": {
"version": "1.50.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz",
"integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.50.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.50.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz",
"integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/playwright/node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",

View file

@ -3,7 +3,7 @@
"version": "0.2.3",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"dev": "next dev --turbopack -p 3003",
"build": "next build",
"start": "next start -p 3003",
"lint": "next lint"
@ -32,6 +32,7 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@playwright/test": "^1.50.1",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",

83
playwright.config.ts Normal file
View file

@ -0,0 +1,83 @@
import { defineConfig, devices } from '@playwright/test';
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// import path from 'path';
// dotenv.config({ path: path.resolve(__dirname, '.env') });
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './tests',
timeout: 30 * 1000,
outputDir: './tests/results',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 1 : 0,
/* Opt out of parallel tests on CI. */
workers: undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: 'http://localhost:3003',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],
/* Run your local dev server before starting the tests */
webServer: {
command: 'npm run build && npm run start',
url: 'http://localhost:3003',
reuseExistingServer: !process.env.CI,
timeout: 120 * 1000,
},
});

BIN
public/sample.epub Normal file

Binary file not shown.

View file

@ -71,6 +71,7 @@ export function EPUBViewer({ className = '' }: EPUBViewerProps) {
</div>
<div className="flex-1 -mt-16 pt-16">
<ReactReader
loadingView={<DocumentSkeleton />}
key={'epub-reader'}
location={locationRef.current}
locationChanged={handleLocationChanged}

62
tests/e2e.spec.ts Normal file
View file

@ -0,0 +1,62 @@
import { test, expect, Page } from '@playwright/test';
// Upload a sample epub or pdf
async function uploadFile(page: Page, filePath: string) {
const fileChooserPromise = page.waitForEvent('filechooser');
await page.getByText('Drop your file here, or click to select').click();
const fileChooser = await fileChooserPromise;
await fileChooser.setFiles(filePath);
}
test.describe('Document Upload and Display', () => {
test.beforeEach(async ({ page }) => {
// Navigate to the home page before each test
await page.goto('http://localhost:3003');
// Click the "done" button to dismiss the welcome message
await page.getByText('Done').click();
});
test.describe('PDF handling', () => {
test('should upload a PDF document', async ({ page }) => {
// Upload the file
await uploadFile(page, './public/sample.pdf');
// Verify upload success
await expect(page.getByText('sample.pdf')).toBeVisible();
});
test('should display a PDF document', async ({ page }) => {
// Upload the file
await uploadFile(page, './public/sample.pdf');
// Click on the uploaded document
await page.getByText('sample.pdf').click();
// Verify PDF viewer is displayed
await expect(page.locator('.react-pdf__Document')).toBeVisible();
await expect(page.locator('.react-pdf__Page')).toBeVisible();
});
});
test.describe('EPUB handling', () => {
test('should upload and display EPUB document', async ({ page }) => {
// Upload the file
await uploadFile(page, './public/sample.epub');
// Verify upload success
await expect(page.getByText('sample.epub')).toBeVisible();
});
test('should display an EPUB document', async ({ page }) => {
// Upload the file
await uploadFile(page, './public/sample.epub');
// Click on the uploaded document
await page.getByText('sample.epub').click();
// Verify EPUB viewer is displayed
await expect(page.locator('.epub-container')).toBeVisible();
});
});
});