validate: removed-from-sale IAPs are no blockers; shots capture --device landscape (Mac / Chromebook frames from a web build); playwright lookup says why each place failed

This commit is contained in:
CRTkafa 2026-11-03 23:14:34 +07:00
parent cdd9321794
commit d0f568ebc2
13 changed files with 230 additions and 48 deletions

View file

@ -43,7 +43,7 @@ export function validateCapture(c: ShotsCapture | undefined): string[] {
if (s.click !== undefined) for (const [i, c] of (Array.isArray(s.click) && s.click.some(x => typeof x !== 'string') ? s.click : [s.click]).entries()) e.push(...validateSelector(`shots.capture.shots.${name}.click[${i}]`, c));
} else if (s.waitSelector !== undefined || s.click !== undefined) e.push(`shots.capture.shots.${name}: waitSelector / click only apply to source web`);
if (s.navigate && !['spa', 'reload'].includes(s.navigate)) e.push(`shots.capture.shots.${name}.navigate: spa | reload`);
if (s.device && !['phone', 'tablet', 'both'].includes(s.device)) e.push(`shots.capture.shots.${name}.device: phone | tablet | both`);
if (s.device && !['phone', 'tablet', 'both', 'landscape'].includes(s.device)) e.push(`shots.capture.shots.${name}.device: phone | tablet | both | landscape`);
if (src === 'web' && s.path === undefined) e.push(`shots.capture.shots.${name}.path: URL path (source web)`);
if ((src === 'web' || src === 'folder') && (s.args || s.extras)) e.push(`shots.capture.shots.${name}: args / extras only apply to ios-sim / android-emu`);
for (const [k, v] of Object.entries(s.extras ?? {})) {
@ -96,9 +96,20 @@ export function adbTarget(and: NonNullable<ShotsCapture['android']>, device: 'ph
return device === 'tablet' ? and.serials?.tablet : and.serials?.phone ?? and.serial;
}
/** Which shots run on which device class. */
export function shotsFor(c: ShotsCapture, device: 'phone' | 'tablet', only: string[] = []): [string, ShotSpec][] {
return Object.entries(c.shots ?? {}).filter(([name, s]) => (!only.length || only.includes(name)) && ((s.device ?? 'phone') === 'both' || (s.device ?? 'phone') === device));
/** Capture device classes: phone / tablet frames (status bar cut) and desktop landscape frames (Mac, Chromebook). */
export type CaptureDevice = 'phone' | 'tablet' | 'landscape';
export const CAPTURE_DEVICES: readonly CaptureDevice[] = ['phone', 'tablet', 'landscape'];
/** Which shots run on which device class. phone / tablet: device unset = phone, 'both' = phone + tablet (unchanged).
* landscape: the shots with device 'landscape'; with `allLandscape` (the project renders a landscape size, or
* --device landscape was asked for) also every shot with no device or 'both', because render needs a landscape frame
* for each scene. A shot that says 'phone' or 'tablet' explicitly stays off the landscape list. */
export function shotsFor(c: ShotsCapture, device: CaptureDevice, only: string[] = [], allLandscape = false): [string, ShotSpec][] {
return Object.entries(c.shots ?? {}).filter(([name, s]) => {
if (only.length && !only.includes(name)) return false;
if (device === 'landscape') return s.device === 'landscape' || (allLandscape && (s.device === undefined || s.device === 'both'));
return s.device !== 'landscape' && ((s.device ?? 'phone') === 'both' || (s.device ?? 'phone') === device);
});
}
// ---- iOS Simulator (xcrun simctl) ----