|
- import { defineConfig, devices } from '@playwright/test'
- import fs from 'node:fs'
- import path from 'node:path'
-
- const loadLocalEnvironment = () => {
- const filename = process.env.E2E_ENV_FILE?.trim() || path.resolve('.env')
- if (!fs.existsSync(filename)) return
- for (const line of fs.readFileSync(filename, 'utf8').split(/\r?\n/)) {
- const match = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/)
- if (!match || match[1]!.startsWith('#') || process.env[match[1]!]) continue
- const raw = match[2]!
- process.env[match[1]!] = raw.length >= 2 && ((raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'")))
- ? raw.slice(1, -1)
- : raw
- }
- }
-
- loadLocalEnvironment()
-
- const rawApplicationBaseUrl = process.env.BASE_URL?.trim() || 'http://127.0.0.1:6180'
- let applicationUrl: URL
- try {
- applicationUrl = new URL(rawApplicationBaseUrl)
- } catch {
- throw new Error('BASE_URL must be an absolute HTTP(S) URL')
- }
- if (!['http:', 'https:'].includes(applicationUrl.protocol) || applicationUrl.username || applicationUrl.password) {
- throw new Error('BASE_URL must be an HTTP(S) URL without embedded credentials')
- }
- const applicationLoopbackHosts = new Set(['127.0.0.1', 'localhost', '::1', '[::1]'])
- if (
- !applicationLoopbackHosts.has(applicationUrl.hostname.toLowerCase())
- && applicationUrl.protocol !== 'https:'
- && process.env.E2E_ALLOW_INSECURE_REMOTE !== '1'
- ) {
- throw new Error('Remote BASE_URL must use HTTPS unless E2E_ALLOW_INSECURE_REMOTE=1 explicitly accepts the risk')
- }
-
- const baseURL = applicationUrl.toString().replace(/\/$/, '')
-
- export default defineConfig({
- testDir: './tests',
- outputDir: './artifacts/test-results',
- fullyParallel: false,
- workers: 1,
- retries: process.env.CI ? 1 : 0,
- timeout: 60_000,
- expect: {
- timeout: 10_000,
- },
- reporter: [
- ['list'],
- ['html', { outputFolder: 'artifacts/html-report', open: 'never' }],
- ['json', { outputFile: 'artifacts/results.json' }],
- ],
- use: {
- baseURL,
- locale: 'zh-CN',
- timezoneId: 'Asia/Shanghai',
- actionTimeout: 10_000,
- navigationTimeout: 20_000,
- screenshot: 'off',
- // Auth traces contain request bodies and bearer tokens. Keep them disabled
- // by default; an operator may opt in only in a protected local/CI workspace.
- trace: process.env.E2E_TRACE === '1' ? 'retain-on-failure' : 'off',
- video: 'retain-on-failure',
- },
- projects: [
- {
- name: 'chromium',
- use: { ...devices['Desktop Chrome'] },
- },
- ],
- })
|