Files
chore/frontend/playwright.config.ts
T
ryan cc1189cd9b
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 2m56s
feat(tutorial): enhance help button visibility and add dialog tests
- Introduced a mechanism to hide the help button when modal dialogs are open by adding `helpButtonHidden` state in the tutorial controller.
- Updated various components to set the help button visibility based on dialog states.
- Added tests to verify help button visibility during reward and task confirmation dialogs.
- Created new E2E tests for dialog help button functionality across different assignment views.
- Refactored existing dialog components to utilize the new help button visibility logic.
- Added unit tests for `RewardConfirmDialog` and `TaskConfirmDialog` to ensure correct titles are rendered based on task type.
- Enhanced `HelpButton` component tests to validate visibility based on tutorial state.
2026-07-23 01:02:21 -04:00

301 lines
11 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,
STORAGE_STATE_TUTORIAL,
} 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'] },
{
name: 'setup-tutorial',
testMatch: /auth-tutorial\.setup\.ts/,
// Depends on setup because e2e-seed truncates all users first.
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: routine tests — child-mode overlay flow (confirm + cancel) and
// parent notification appearance. Each spec creates its own isolated child.
name: 'chromium-routines',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
dependencies: ['setup'],
testMatch: [/mode_parent\/routines\/.+\.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/],
},
{
// Bucket: tutorial system tests — uses an isolated user so tutorial
// enabled/progress state never interferes with other buckets.
name: 'chromium-tutorial',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE_TUTORIAL },
dependencies: ['setup-tutorial'],
testMatch: [/mode_parent\/tutorial\/.+\.spec\.ts/],
testIgnore: [/mode_parent\/tutorial\/dialog-help-button\.spec\.ts/],
},
{
// Bucket: dialog help-button/title tests — depends on the tutorial bucket
// so it reuses the isolated tutorial user without running concurrently.
name: 'chromium-dialog',
use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE_TUTORIAL },
dependencies: ['chromium-tutorial'],
testMatch: [/mode_parent\/tutorial\/dialog-help-button\.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\//,
/mode_parent\/routines\//,
/mode_parent\/tutorial\//,
],
},
{
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,
// },
})