Skip to content

Commit aac72bd

Browse files
committed
ci: dump vitest stdout/stderr for content-api debug suites
Add SUMMARY_DEBUG/SUMMARY_DEBUG_SUITES support to runTestsWithSummary plus a pre-flight diagnostics block (env vars, figma plugin resolution, Content API /health and /dev/jwt pings) so the next CI run surfaces the real failure reason instead of just "0/N".
1 parent 79a9b2d commit aac72bd

2 files changed

Lines changed: 130 additions & 9 deletions

File tree

.github/workflows/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,9 @@ jobs:
599599
env:
600600
NODE_OPTIONS: --max-old-space-size=8096
601601
PAYLOAD_DATABASE: content-api
602+
# Debug: dump raw vitest stdout/stderr for these suites so we can
603+
# see the underlying failure. Remove once resolved.
604+
SUMMARY_DEBUG_SUITES: _community,access-control
602605

603606
- name: Dump Content API logs on failure
604607
if: failure()

test/runTestsWithSummary.ts

Lines changed: 127 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { execSync } from 'child_process'
22
import fs from 'fs'
3+
import { createRequire } from 'module'
34
import path from 'path'
45
import ts from 'typescript'
56
import { fileURLToPath } from 'url'
@@ -79,6 +80,42 @@ const isContentAPIMode = process.env.PAYLOAD_DATABASE === 'content-api'
7980
const contentAPISuiteTimeout = 120000
8081
const vitestBinary = './node_modules/.bin/vitest'
8182

83+
// Debug dump config (temporary diagnostic for content-api CI).
84+
// - SUMMARY_DEBUG=1: dump every suite that produced 0 passes or errored.
85+
// - SUMMARY_DEBUG_SUITES="a,b": dump only those suites (when they fail).
86+
const debugDumpEnabled = process.env.SUMMARY_DEBUG === '1' || process.env.SUMMARY_DEBUG === 'true'
87+
const debugDumpSuites = new Set(
88+
(process.env.SUMMARY_DEBUG_SUITES || '')
89+
.split(',')
90+
.map((s) => s.trim())
91+
.filter(Boolean),
92+
)
93+
const debugDumpMaxLines = Number(process.env.SUMMARY_DEBUG_MAX_LINES || 400)
94+
95+
function dumpSuiteOutput(suiteName: string, stdout: string, stderr: string): void {
96+
const tail = (s: string): string => {
97+
if (!s) {
98+
return '(empty)'
99+
}
100+
const lines = s.split('\n')
101+
if (lines.length <= debugDumpMaxLines) {
102+
return s
103+
}
104+
return (
105+
`... (${lines.length - debugDumpMaxLines} earlier lines omitted) ...\n` +
106+
lines.slice(-debugDumpMaxLines).join('\n')
107+
)
108+
}
109+
console.log(`\n${'='.repeat(80)}`)
110+
console.log(`🔬 DEBUG DUMP for suite: ${suiteName}`)
111+
console.log(`${'='.repeat(80)}`)
112+
console.log('--- stdout (tail) ---')
113+
console.log(tail(stdout))
114+
console.log('--- stderr (tail) ---')
115+
console.log(tail(stderr))
116+
console.log(`${'='.repeat(80)}\n`)
117+
}
118+
82119
function getVitestEnv(options?: { unsetPayloadDatabase?: boolean }): NodeJS.ProcessEnv {
83120
const env = {
84121
...process.env,
@@ -362,6 +399,10 @@ function runTestSuite(suiteName: string): SuiteResult {
362399
duration: 0,
363400
}
364401

402+
let capturedStdout = ''
403+
let capturedStderr = ''
404+
let sawError = false
405+
365406
try {
366407
const testPath = path.join(dirname, suiteName, 'int.spec.ts')
367408
const command = `${vitestBinary} run --project int ${testPath} --reporter=json`
@@ -374,7 +415,7 @@ function runTestSuite(suiteName: string): SuiteResult {
374415
...(isContentAPIMode ? { timeout: contentAPISuiteTimeout } : {}),
375416
})
376417

377-
// Parse Jest output to extract test counts
418+
capturedStdout = output
378419
const parsed = parseTestResults(output)
379420
result.passed = parsed.passed
380421
result.total = parsed.total
@@ -386,23 +427,29 @@ function runTestSuite(suiteName: string): SuiteResult {
386427
result.total = getStaticTestCount(suiteName)
387428
}
388429
} catch (error: unknown) {
389-
// Try to parse failure output from both stdout and stderr
430+
sawError = true
390431
let errorOutput = ''
391432
if (error && typeof error === 'object') {
392433
if ('stdout' in error) {
393434
const stdout = (error as { stdout?: unknown }).stdout
394435
if (typeof stdout === 'string') {
395436
errorOutput += stdout
437+
capturedStdout = stdout
396438
} else if (stdout && Buffer.isBuffer(stdout)) {
397-
errorOutput += stdout.toString('utf8')
439+
const s = stdout.toString('utf8')
440+
errorOutput += s
441+
capturedStdout = s
398442
}
399443
}
400444
if ('stderr' in error) {
401445
const stderr = (error as { stderr?: unknown }).stderr
402446
if (typeof stderr === 'string') {
403447
errorOutput += '\n' + stderr
448+
capturedStderr = stderr
404449
} else if (stderr && Buffer.isBuffer(stderr)) {
405-
errorOutput += '\n' + stderr.toString('utf8')
450+
const s = stderr.toString('utf8')
451+
errorOutput += '\n' + s
452+
capturedStderr = s
406453
}
407454
}
408455
}
@@ -422,6 +469,13 @@ function runTestSuite(suiteName: string): SuiteResult {
422469
result.total = Math.max(0, result.total - getExplicitSkippedTestCount(suiteName))
423470
result.failed = result.passed < result.total
424471
result.duration = Date.now() - startTime
472+
473+
const shouldDump =
474+
(debugDumpEnabled || debugDumpSuites.has(suiteName)) && (result.passed === 0 || sawError)
475+
if (shouldDump) {
476+
dumpSuiteOutput(suiteName, capturedStdout, capturedStderr)
477+
}
478+
425479
return result
426480
}
427481

@@ -435,9 +489,75 @@ function formatDuration(ms: number): string {
435489
return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`
436490
}
437491

438-
function main() {
492+
async function printDiagnostics(): Promise<void> {
493+
console.log('=== Content API Diagnostics ===')
494+
const envKeys = [
495+
'PAYLOAD_DATABASE',
496+
'NODE_ENV',
497+
'CONTENT_API_URL',
498+
'CONTENT_SYSTEM_ID',
499+
'SUMMARY_DEBUG',
500+
'SUMMARY_DEBUG_SUITES',
501+
]
502+
for (const k of envKeys) {
503+
console.log(` env.${k} = ${process.env[k] ?? '(unset)'}`)
504+
}
505+
506+
// Resolve @payloadcms/figma to understand which source vitest will use.
507+
const figmaSrcAlias = path.resolve(
508+
process.cwd(),
509+
'../enterprise-plugins/packages/figma/src/index.ts',
510+
)
511+
const hasFigmaSrc = fs.existsSync(figmaSrcAlias)
512+
console.log(` enterprise-plugins sibling exists: ${hasFigmaSrc} (${figmaSrcAlias})`)
513+
try {
514+
const req = createRequire(path.join(process.cwd(), 'test/package.json'))
515+
const resolved = req.resolve('@payloadcms/figma')
516+
console.log(` @payloadcms/figma resolves to: ${resolved}`)
517+
const pkgPath = path.join(path.dirname(resolved), 'package.json')
518+
if (fs.existsSync(pkgPath)) {
519+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
520+
console.log(` @payloadcms/figma version: ${pkg.version}`)
521+
}
522+
} catch (e) {
523+
console.log(` @payloadcms/figma resolve FAILED: ${(e as Error).message}`)
524+
}
525+
526+
// Ping Content API if we're targeting it, so we know it is reachable from the
527+
// node process that runs the tests (not just the docker healthcheck).
528+
if (isContentAPIMode) {
529+
const url = process.env.CONTENT_API_URL || 'http://localhost:8080'
530+
for (const endpoint of ['/health', '/dev/jwt']) {
531+
try {
532+
const init: RequestInit =
533+
endpoint === '/dev/jwt'
534+
? {
535+
method: 'POST',
536+
headers: { 'content-type': 'application/json' },
537+
body: JSON.stringify({
538+
contentSystemId:
539+
process.env.CONTENT_SYSTEM_ID || '00000000-0000-4000-8000-000000000001',
540+
}),
541+
}
542+
: {}
543+
const res = await fetch(`${url}${endpoint}`, init)
544+
const text = await res.text()
545+
console.log(
546+
` GET ${url}${endpoint} -> ${res.status} ${res.statusText}; body: ${text.slice(0, 200)}`,
547+
)
548+
} catch (e) {
549+
console.log(` GET ${url}${endpoint} -> ERROR ${(e as Error).message}`)
550+
}
551+
}
552+
}
553+
console.log('================================\n')
554+
}
555+
556+
async function main() {
439557
console.log('🧪 Running integration tests suite by suite...\n')
440558

559+
await printDiagnostics()
560+
441561
const testDirs = getTestDirectories()
442562
console.log(`Found ${testDirs.length} test suites\n`)
443563

@@ -520,9 +640,7 @@ function main() {
520640
}
521641
}
522642

523-
try {
524-
main()
525-
} catch (error) {
643+
main().catch((error) => {
526644
console.error('Error running tests:', error)
527645
process.exit(1)
528-
}
646+
})

0 commit comments

Comments
 (0)