test: [ENG-08] add verified TS coverage and paired performance reports

This commit is contained in:
Harvey Zhao committed 2026-09-11 22:01:48 +08:00
1 parent 8ed0a5228c
commit 4a9a26d4fc
38 files changed
+24335 -61

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
# Paired performance and cleanup
Run `yarn test:package` first. Set `ARTPLAYER_BROWSER_ARTIFACTS` to the resulting
`refactor/.cache/packages/run-*/browser-artifacts.json`, then run
`yarn test:performance`. The command starts its own local server; do not run it
alongside other browser tests or CPU-heavy builds. All three engines run with one
worker, no trace/video recording and the same media and viewport within a pair.
Each engine runs three alternating published/candidate pairs. Each side retains
one warm-up and five timed samples for both core and core + chapter, followed by
separate instrumented resource probes. `scripts/performance-fixture.mjs` adapts
only the frozen BASE-06 fixture's script URLs and report transport. Its original
files remain unchanged and their existing baseline tests still run.
The candidate must come from an isolated package installation. Artifact hashes,
source snapshots, package inputs and build tools are checked before measurement;
an old candidate cannot silently stand in for changed source. Raw, gzip 9 and
Brotli 6 compare matching modern, legacy and ESM files from the same installation.
Timing uses the exact JS files selected by the artifact map.
Reports are in `refactor/.cache/performance/run-<engine>-*/report.json` and
`summary.md`. Playwright evidence is in `refactor/.cache/performance/browser/`.
CI uploads both and appends summaries to the workflow run. Failed or incomplete
runs remain recorded and are not promoted to a passing baseline.
A successful test proves the measurement contract and candidate resource cleanup.
`review-required` means size or timing thresholds were exceeded; it is not release
approval. CORE-22 and release reviews must resolve the corresponding risks before
publishing. These counters do not measure native heap/GPU memory, real mobile
hardware or screen-reader behavior. See `refactor/coverage-performance.md`.
+72
View File
@@ -0,0 +1,72 @@
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'
import { compareArtifactSizes, verifyPerformanceArtifacts } from '../../scripts/performance-artifacts.mjs'
import { validatePairedPerformance } from '../../scripts/performance-report.mjs'
import { performanceSummary } from '../../scripts/performance-summary.mjs'
import { expect, test } from '../browser/fixtures.js'
const root = fileURLToPath(new URL('../../', import.meta.url))
test('installed core and chapter: three paired timing groups with strict candidate cleanup', async ({ page, browser, browserName, request, diagnostics }, testInfo) => {
const artifacts = verifyPerformanceArtifacts(root, process.env.ARTPLAYER_BROWSER_ARTIFACTS)
const manifest = await (await request.get('/test/manifest.json')).json()
for (const input of artifacts.inputs) {
const resource = manifest.resources[`/candidate/${input.name}.js`]
expect(resource.source.kind).toBe('artifact')
expect(resource.sha256).toBe(input.sha256)
}
const output = path.join(root, 'refactor/.cache/performance')
fs.mkdirSync(output, { recursive: true })
const directory = fs.mkdtempSync(path.join(output, `run-${browserName}-`))
const report = {
schemaVersion: 1,
task: 'ENG-08',
capturedAt: new Date().toISOString(),
environment: { browser: browserName, version: browser.version(), platform: process.platform, node: process.version },
inputs: artifacts.inputs,
toolchain: artifacts.toolchain,
manifest,
sizes: await compareArtifactSizes(root, artifacts),
runs: [],
status: 'incomplete',
}
const file = path.join(directory, 'report.json')
const save = () => fs.writeFileSync(file, `${JSON.stringify(report, null, 2)}\n`)
save()
try {
for (let group = 0; group < 3; group++) {
for (const variant of group % 2 ? ['candidate', 'published'] : ['published', 'candidate']) {
await page.goto(`/test/performance.html?variant=${variant}`)
await page.bringToFront()
await page.locator('#run').click()
await page.waitForFunction(() => window.artplayerPerformanceReport, null, { timeout: 25000 })
const measurements = await page.evaluate(() => window.artplayerPerformanceReport)
report.runs.push({ group, variant, measurements })
save()
}
}
Object.assign(report, validatePairedPerformance(report))
report.reviewRequired ||= report.sizes.some(item => item.reviewSignals.length > 0)
expect(diagnostics.errors).toEqual([])
expect(diagnostics.consoleErrors).toEqual([])
report.status = report.reviewRequired ? 'review-required' : 'passed'
save()
const summary = performanceSummary(report)
fs.writeFileSync(path.join(directory, 'summary.md'), summary)
await testInfo.attach('performance-summary', { body: summary, contentType: 'text/markdown' })
if (process.env.GITHUB_STEP_SUMMARY)
fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, summary)
}
catch (error) {
report.status = 'failed'
report.failure = error.message
save()
throw error
}
finally {
await testInfo.attach('paired-performance', { path: file, contentType: 'application/json' })
process.stdout.write(`Paired performance (${browserName}): ${path.relative(root, file)}; ${report.status}\n`)
}
})