Files
chore/frontend/playwright.config.ts
Ryan Kegel 8774e85529
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 2m19s
feat: add workflow for promoting master to production with testing and deployment steps
2026-04-26 19:08:08 -04:00

264 lines
9.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { defineConfig, devices } from '@playwright/test'
import {
STORAGE_STATE,
STORAGE_STATE_NO_PIN,
STORAGE_STATE_DELETE,
STORAGE_STATE_CC,
} from './e2e/e2e-constants'
/**
* 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.
*/
const frontendBaseUrl = process.env.PLAYWRIGHT_BASE_URL || 'https://localhost:5173'
export default defineConfig({
testDir: './e2e',
/* 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 ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : 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: frontendBaseUrl,
ignoreHTTPSErrors: true,
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},
/* Configure projects for major browsers */
projects: [
{ name: 'setup', testMatch: /auth\.setup\.ts/ },
{ name: 'setup-no-pin', testMatch: /auth-no-pin\.setup\.ts/ },
// Depends on 'setup' because e2e-seed (run in setup) truncates all users first.
{ name: 'setup-delete', testMatch: /auth-delete\.setup\.ts/, dependencies: ['setup'] },
{ name: 'setup-cc', testMatch: /auth-cc\.setup\.ts/, dependencies: ['setup'] },
{
// Bucket A: child-options tests — run before create-child so that
// deleteAllChildren() in happy-path.spec.ts cannot delete children
// that these tests are actively using.
name: 'chromium-child-options',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/child-options\/.+\.spec\.ts/],
},
{
// Bucket B: create-child tests — uses its own isolated user (e2e-cc@test.com)
// so deleteAllChildren() only affects that user's children and never interferes
// with concurrent buckets using the main E2E user.
name: 'chromium-create-child',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE_CC },
dependencies: ['setup-cc'],
testMatch: [/mode_parent\/create-child\/.+\.spec\.ts/],
},
{
// Bucket: tests that mutate shared system-default items (chores/kindness/penalties).
// fullyParallel:false prevents files from being split across workers;
// the merged kindness-default and penalty-default files use mode:'serial'
// internally to guarantee the convert and delete tests never run in parallel.
// API-based beforeEach cleanup in each spec makes these tests resilient to
// concurrent SSE activity from other buckets.
name: 'chromium-default-tasks',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/tasks\/.*default\.spec\.ts/],
fullyParallel: false,
},
{
// Bucket: task and reward assignment tests for individual children.
// Serial mode within each file ensures assign → verify → unassign → cancel flow order.
name: 'chromium-task-assignment',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/task-assignment\/.+\.spec\.ts/],
},
{
// Bucket: task activation and reward redemption tests — each spec creates its own
// isolated child so the 4 files can safely run in parallel within this bucket.
name: 'chromium-task-activation',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/task-activation\/.+\.spec\.ts/],
},
{
// Bucket: task modification tests — each spec creates its own isolated child
// so the 6 files can safely run in parallel within this bucket.
name: 'chromium-task-modification',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/task-modification\/.+\.spec\.ts/],
},
{
// Bucket: chore scheduler tests — each spec creates isolated child+chores.
name: 'chromium-chore-scheduler',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/chore-scheduler\/.+\.spec\.ts/],
},
{
// Bucket: parent notifications tests — push subscription, chore/reward
// notification approval/denial, deep-link navigation, digest tokens, and
// user profile notification settings. Each spec creates its own isolated child.
name: 'chromium-parent-notifications',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/notifications\/.+\.spec\.ts/],
},
{
// Bucket: parent profile button tests (permanent parent mode).
name: 'chromium-profile-button',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/profile-button\/.+\.spec\.ts/],
},
{
// Bucket: user profile editing tests (name, image, save/cancel, change password).
name: 'chromium-user-profile',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/user-profile\/profile-editing\.spec\.ts/],
},
{
// Bucket: change PIN flow tests — restores the original PIN in afterAll.
name: 'chromium-user-profile-pin',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/user-profile\/change-pin\.spec\.ts/],
},
{
// Bucket: delete account tests — uses its own isolated user (e2e-delete@test.com)
// so the shared E2E session is never affected and no cross-project dependencies needed.
name: 'chromium-user-profile-delete',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE_DELETE },
dependencies: ['setup-delete'],
testMatch: [/mode_parent\/user-profile\/delete-account\.spec\.ts/],
},
{
name: 'chromium-tasks-rewards',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testIgnore: [
/\/mode_child\//,
/mode_parent\/(create-child|child-options)\//,
/mode_parent\/tasks\/.*default\.spec\.ts/,
/mode_parent\/task-assignment\//,
/mode_parent\/task-activation\//,
/mode_parent\/task-modification\//,
/mode_parent\/profile-button\//,
/mode_parent\/user-profile\//,
/mode_parent\/chore-scheduler\//,
/mode_parent\/notifications\//,
],
},
{
name: 'chromium-no-pin',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE_NO_PIN },
dependencies: ['setup-no-pin'],
// never run the large task suite or the SSE crosstab tests when the parent
// pin is removed they are slow and rely on longlived connections.
testIgnore: [/\/mode_parent\//],
},
// {
// 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 tests */
webServer: [
{
command: 'npm run dev',
url: frontendBaseUrl,
reuseExistingServer: !process.env.CI,
stdout: 'pipe',
stderr: 'pipe',
ignoreHTTPSErrors: true,
},
{
command:
process.platform === 'win32'
? 'echo Platform: %PROCESS_PLATFORM% && .venv\\Scripts\\python.exe -m flask run --host=0.0.0.0 --port=5000 --no-debugger --no-reload'
: 'echo Platform: $PROCESS_PLATFORM && .venv/bin/python -m flask run --host=0.0.0.0 --port=5000 --no-debugger --no-reload',
url: 'http://localhost:5000/version',
reuseExistingServer: !process.env.CI,
stdout: 'pipe',
stderr: 'pipe',
cwd: '../backend',
env: {
FLASK_APP: 'main.py',
FLASK_DEBUG: '1',
DB_ENV: 'e2e',
DATA_ENV: 'e2e',
SECRET_KEY: 'dev-secret-key-change-in-production',
ACCESS_TOKEN_EXPIRY_MINUTES: process.env.E2E_ACCESS_TOKEN_EXPIRY_MINUTES || '180',
REFRESH_TOKEN_EXPIRY_DAYS: '90',
DIGEST_TOKEN_SECRET: 'dev-digest-token',
VAPID_PUBLIC_KEY:
'BNKkHdq45uLigohSG7c1TwlAo7ETncoRVLQK02LxHgu2P1DgSJD9njRMfbbzUsaTQGllvLBz7An1WiWsNYQhvKE',
VAPID_PRIVATE_KEY: 'jNiZJT0UO4H861KmnCt874Fg6p5jDAyYKS4V2MZf8bQ',
PROCESS_PLATFORM: process.platform,
},
},
],
/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// url: 'http://localhost:3000',
// reuseExistingServer: !process.env.CI,
// },
})