mirror of
https://github.com/ThatGuySam/doesitarm.git
synced 2026-05-15 06:35:20 -07:00
test(playwright): lock browser coverage before scanner refactors
Add a typed Playwright harness for Pagefind and the Apple Silicon app-test flow so scanner work has browser-level protection. Keep the rollout plan in the same stack so the TypeScript conversion stays staged and reviewable. Constraint: Must not change production runtime behavior in this commit Rejected: Leave the old JS browser test and add a second harness | duplicates setup and leaves the targeted browser script broken Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep browser-only helpers under test/playwright/support until the runtime scanner surface is fully typed Tested: pnpm run typecheck; pnpm run test:browser; pnpm run test:browser:pagefind Not-tested: Live browser checks against doesitarm.com
This commit is contained in:
parent
c5ec942de0
commit
0480c47bbb
8 changed files with 633 additions and 276 deletions
77
test/playwright/support/app-archive-fixture.ts
Normal file
77
test/playwright/support/app-archive-fixture.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
|
||||
import { Zip } from 'zip-lib'
|
||||
|
||||
const machoObjectBase64 =
|
||||
'z/rt/gwAAAEAAAAAAQAAAAQAAABoAQAAACAAAAAAAAAZAAAA6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAiAEAAAAAAAA4AAAAAAAAAAcAAAAHAAAAAgAAAAAAAABfX3RleHQAAAAAAAAAAAAAX19URVhUAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAACIAQAAAgAAAAAAAAAAAAAAAAQAgAAAAAAAAAAAAAAAAF9fY29tcGFjdF91bndpbmRfX0xEAAAAAAAAAAAAAAAAGAAAAAAAAAAgAAAAAAAAAKABAAADAAAAwAEAAAEAAAAAAAACAAAAAAAAAAAAAAAAMgAAABgAAAABAAAAAAALAAACGgAAAAAAAgAAABgAAADIAQAAAwAAAPgBAAAYAAAACwAAAFAAAAAAAAAAAgAAAAIAAAABAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/QwDRAACAUv8PALn/QwCRwANf1gAAAAAAAAAAAAAAABQAAAAAEAACAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAGDQAAAA4BAAAAAAAAAAAAAAcAAAAOAgAAGAAAAAAAAAABAAAADwEAAAAAAAAAAAAAAF9tYWluAGx0bXAxAGx0bXAwAAAAAAAA'
|
||||
|
||||
export interface PlaywrightUploadFile {
|
||||
arrayBuffer: ArrayBuffer
|
||||
buffer: Buffer
|
||||
mimeType: string
|
||||
name: string
|
||||
type: string
|
||||
}
|
||||
|
||||
function makeInfoPlist ( appName: string ) {
|
||||
return [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
||||
'<plist version="1.0">',
|
||||
'<dict>',
|
||||
' <key>CFBundleDisplayName</key>',
|
||||
` <string>${ appName }</string>`,
|
||||
' <key>CFBundleExecutable</key>',
|
||||
` <string>${ appName }</string>`,
|
||||
' <key>CFBundleIdentifier</key>',
|
||||
` <string>com.doesitarm.${ appName.toLowerCase().replaceAll( ' ', '-' ) }</string>`,
|
||||
' <key>CFBundleName</key>',
|
||||
` <string>${ appName }</string>`,
|
||||
' <key>CFBundleShortVersionString</key>',
|
||||
' <string>1.0.0</string>',
|
||||
'</dict>',
|
||||
'</plist>',
|
||||
''
|
||||
].join( '\n' )
|
||||
}
|
||||
|
||||
export async function createNativeAppArchive ( appName = 'Playwright Native App' ): Promise<PlaywrightUploadFile> {
|
||||
const tempRoot = await mkdtemp( join( tmpdir(), 'doesitarm-playwright-' ) )
|
||||
const appBundlePath = join( tempRoot, `${ appName }.app` )
|
||||
const contentsPath = join( appBundlePath, 'Contents' )
|
||||
const executablePath = join( contentsPath, 'MacOS', appName )
|
||||
const archivePath = join( tempRoot, `${ appName }.app.zip` )
|
||||
|
||||
try {
|
||||
const executableBytes = new Uint8Array( Buffer.from( machoObjectBase64, 'base64' ) )
|
||||
|
||||
await mkdir( join( contentsPath, 'MacOS' ), { recursive: true } )
|
||||
await writeFile( join( contentsPath, 'Info.plist' ), makeInfoPlist( appName ) )
|
||||
await writeFile( executablePath, executableBytes, { mode: 0o755 } )
|
||||
|
||||
const zip = new Zip()
|
||||
|
||||
zip.addFolder( appBundlePath, `${ appName }.app` )
|
||||
await zip.archive( archivePath )
|
||||
|
||||
const archiveBuffer = await readFile( archivePath )
|
||||
|
||||
return {
|
||||
arrayBuffer: archiveBuffer.buffer.slice(
|
||||
archiveBuffer.byteOffset,
|
||||
archiveBuffer.byteOffset + archiveBuffer.byteLength
|
||||
),
|
||||
buffer: archiveBuffer,
|
||||
mimeType: 'application/zip',
|
||||
name: `${ appName }.app.zip`,
|
||||
type: 'application/zip'
|
||||
}
|
||||
} finally {
|
||||
await rm( tempRoot, {
|
||||
force: true,
|
||||
recursive: true
|
||||
} )
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue