browser tests run only by hand: the suites that launch Chrome / Chromium move to tests/browser/*.browser.ts (bun test, ci, ci:quick and the Forgejo workflows never pick them up; bun run test:browser runs them); the desktop boot check leaves bun run ci (it stays in desktop-release.ts mac at release time); CI=full is gone: Forgejo's ci runs the Rust steps when the push changed a Rust input (STOREBOUND_CI_BASE=HEAD~1), no Playwright install; CONTRIBUTING
This commit is contained in:
parent
4c7ff89950
commit
cd1e13c1e2
20 changed files with 116 additions and 133 deletions
|
|
@ -7,11 +7,11 @@ import { spawnSync } from 'node:child_process';
|
|||
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import type { ShipConfig, ShotsCapture } from '../cli/lib/config';
|
||||
import { type CaptureReport, defaultConcurrency, planWeb, pool, progressLine, selectJobs, timingSummary } from '../cli/shots/capture-web';
|
||||
import { BASE } from './helpers/store-mock';
|
||||
import type { ShipConfig, ShotsCapture } from '../../cli/lib/config';
|
||||
import { type CaptureReport, defaultConcurrency, planWeb, pool, progressLine, selectJobs, timingSummary } from '../../cli/shots/capture-web';
|
||||
import { BASE } from '../helpers/store-mock';
|
||||
|
||||
const CLI = join(import.meta.dir, '..', 'cli', 'index.ts');
|
||||
const CLI = join(import.meta.dir, '..', '..', 'cli', 'index.ts');
|
||||
|
||||
describe('capture helpers', () => {
|
||||
test('default concurrency: render min(4, cores/2), capture (GPU-heavy) min(3, cores/4), at least 1', () => {
|
||||
|
|
@ -85,7 +85,7 @@ afterAll(() => server.stop(true));
|
|||
|
||||
// launch only: exiting closes the browser's pipe and it quits on its own (a graceful close of Google Chrome, the
|
||||
// fallback without playwright's Chromium, can take 30 s)
|
||||
const canLaunch = spawnSync('bun', ['-e', `const { launch } = await import(${JSON.stringify(join(import.meta.dir, '..', 'cli', 'shots', 'browser.ts'))}); await launch(${JSON.stringify(join(import.meta.dir, '..'))}, { headless: true }); process.exit(0);`], { timeout: 60_000 }).status === 0;
|
||||
const canLaunch = spawnSync('bun', ['-e', `const { launch } = await import(${JSON.stringify(join(import.meta.dir, '..', '..', 'cli', 'shots', 'browser.ts'))}); await launch(${JSON.stringify(join(import.meta.dir, '..', '..'))}, { headless: true }); process.exit(0);`], { timeout: 60_000 }).status === 0;
|
||||
if (!canLaunch) console.warn('capture-web browser tests skipped: no Chromium could launch (bunx playwright install chromium)');
|
||||
|
||||
/** A temp project with this config; cli() runs `storebound shots capture <args>` in it. */
|
||||
|
|
@ -6,19 +6,19 @@
|
|||
// Speed: the browser tests run BROWSER_CONCURRENCY at a time (scope.concurrent, each with its own contexts) and the
|
||||
// engine's waits are the test ones (TEST_WAITS / TEST_TICK_MS: 20 ms rounds, a missing step ends once its page is
|
||||
// loaded and quiet). SLOW tests still wait out some "not here" timeouts of the engine (navMs, scaled down). The relaunch of storebound's own profile
|
||||
// (session cookies kept) needs a real Chrome: tests/console-persist.test.ts.
|
||||
// (session cookies kept) needs a real Chrome: tests/browser/console-persist.browser.ts.
|
||||
import { afterAll, afterEach, beforeAll, describe, expect, test } from 'bun:test';
|
||||
import { mkdtempSync, readdirSync, rmSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { matchAccount, openAcross, readAccounts, rememberApple, rememberPlay, withAccountIds } from '../cli/console/accounts';
|
||||
import { createAppHere, engineWaits, fillPage, fillSession, navClick, navigate, resumeAt, run, safeClick, signInPage, signInReason } from '../cli/console/fill';
|
||||
import type { ConsoleBrowser } from '../cli/console/session';
|
||||
import { parseArgs } from '../cli/lib/args';
|
||||
import { type ShipConfig, validateExtras } from '../cli/lib/config';
|
||||
import { AGE_RATING_API, consoleAnswers, consoleResult, fillValue, FORM_IDS, type FormId, formMeta } from '../cli/lib/console-answers';
|
||||
import { consoleReached, CREATE_APP_OPENERS, createAppAllowed, formDef, FORM_OPENERS, forbiddenControl, hasToken, isSignInText, isSignInUrl, navAllowed, navPlan, playDeveloperId, switchAllowed } from '../cli/lib/console-forms';
|
||||
import { AFTER_ALL_MS, AFTER_EACH_MS, launchTestBrowser, logLines, scaled, TEST_TICK_MS, TEST_WAITS, testScope, WaitTimeout } from './helpers/browser';
|
||||
import { matchAccount, openAcross, readAccounts, rememberApple, rememberPlay, withAccountIds } from '../../cli/console/accounts';
|
||||
import { createAppHere, engineWaits, fillPage, fillSession, navClick, navigate, resumeAt, run, safeClick, signInPage, signInReason } from '../../cli/console/fill';
|
||||
import type { ConsoleBrowser } from '../../cli/console/session';
|
||||
import { parseArgs } from '../../cli/lib/args';
|
||||
import { type ShipConfig, validateExtras } from '../../cli/lib/config';
|
||||
import { AGE_RATING_API, consoleAnswers, consoleResult, fillValue, FORM_IDS, type FormId, formMeta } from '../../cli/lib/console-answers';
|
||||
import { consoleReached, CREATE_APP_OPENERS, createAppAllowed, formDef, FORM_OPENERS, forbiddenControl, hasToken, isSignInText, isSignInUrl, navAllowed, navPlan, playDeveloperId, switchAllowed } from '../../cli/lib/console-forms';
|
||||
import { AFTER_ALL_MS, AFTER_EACH_MS, launchTestBrowser, logLines, scaled, TEST_TICK_MS, TEST_WAITS, testScope, WaitTimeout } from '../helpers/browser';
|
||||
|
||||
const config: ShipConfig = {
|
||||
app: { name: 'Example Game', profile: 'game', privacyPolicyUrl: 'https://example.com/privacy', supportUrl: 'https://example.com/support', website: 'https://example.com', contactEmail: 'support@example.com' },
|
||||
|
|
@ -181,7 +181,7 @@ const SLOW_TEST_MS = scaled(90_000);
|
|||
/** Engine waits that are expected to SUCCEED: they return as soon as the element is there, so a long cap costs nothing. */
|
||||
const FOUND_MS = scaled(15_000);
|
||||
|
||||
const FIX = join(import.meta.dir, 'fixtures', 'console');
|
||||
const FIX = join(import.meta.dir, '..', 'fixtures', 'console');
|
||||
/** Console URLs of the navigation plans -> modeled pages (bases: asc = <base>asc, play = <base>play). */
|
||||
const ROUTES: Record<string, string> = {
|
||||
'/asc/apps': 'asc-apps.html', '/asc-tr/apps': 'asc-apps-tr.html', '/asc-noplus/apps': 'asc-apps-noplus.html', '/asc-dup/apps': 'asc-apps-dup.html', '/asc-card/apps': 'asc-apps-card.html',
|
||||
|
|
@ -613,7 +613,7 @@ describe.skipIf(!browser)('sign-in and watching (headless, modeled pages on the
|
|||
expect(await resumeAt(page, plan)).toBeNull();
|
||||
await page.close();
|
||||
}, BROWSER_TEST_MS);
|
||||
// the session-cookie persistence of storebound's own profile: tests/console-persist.test.ts (real Chrome, own shard)
|
||||
// the session-cookie persistence of storebound's own profile: tests/browser/console-persist.browser.ts (real Chrome, own shard)
|
||||
});
|
||||
|
||||
// ---- one login, several developer accounts / teams ----
|
||||
|
|
@ -987,7 +987,7 @@ describe.skipIf(!browser)('play-app-record (headless, modeled pages)', () => {
|
|||
});
|
||||
|
||||
test('ticks are gated on agreements only: help text with "saved" is fine, Developer Program Policies is not; buttons keep the full gate', async () => {
|
||||
const { forbiddenTick, forbiddenControl } = await import('../cli/lib/console-forms');
|
||||
const { forbiddenTick, forbiddenControl } = await import('../../cli/lib/console-forms');
|
||||
const productInteraction = 'Product InteractionSuch as app launches, taps, clicks, scrolling information, music listening data, video views, saved place in a game, video, or song, or other information about how the user interacts with the app';
|
||||
expect(forbiddenTick(productInteraction)).toBe(false);
|
||||
expect(forbiddenTick('NameIncluding first or last name')).toBe(false);
|
||||
|
|
@ -7,15 +7,15 @@ import { afterAll, afterEach, beforeAll, describe, expect, test } from 'bun:test
|
|||
import { mkdtempSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { engineWaits, fillSession } from '../cli/console/fill';
|
||||
import type { ConsoleBrowser } from '../cli/console/session';
|
||||
import { APPLE_DATA_TYPE_IDS, type AppleDataTypeId, type AppleTypeAnswer } from '../cli/lib/app-privacy';
|
||||
import type { ShipConfig } from '../cli/lib/config';
|
||||
import { type FlowWhere, flowAllowed, flowClass, FORM_BUTTONS, labelNames, setUpAllowed, setUpTexts, TYPE_ALIASES } from '../cli/lib/console-forms';
|
||||
import { APPLE_PRIVACY_TYPES } from '../cli/lib/app-privacy';
|
||||
import { AFTER_ALL_MS, AFTER_EACH_MS, launchTestBrowser, logLines, scaled, TEST_TICK_MS, TEST_WAITS, testScope } from './helpers/browser';
|
||||
import { engineWaits, fillSession } from '../../cli/console/fill';
|
||||
import type { ConsoleBrowser } from '../../cli/console/session';
|
||||
import { APPLE_DATA_TYPE_IDS, type AppleDataTypeId, type AppleTypeAnswer } from '../../cli/lib/app-privacy';
|
||||
import type { ShipConfig } from '../../cli/lib/config';
|
||||
import { type FlowWhere, flowAllowed, flowClass, FORM_BUTTONS, labelNames, setUpAllowed, setUpTexts, TYPE_ALIASES } from '../../cli/lib/console-forms';
|
||||
import { APPLE_PRIVACY_TYPES } from '../../cli/lib/app-privacy';
|
||||
import { AFTER_ALL_MS, AFTER_EACH_MS, launchTestBrowser, logLines, scaled, TEST_TICK_MS, TEST_WAITS, testScope } from '../helpers/browser';
|
||||
|
||||
const FIX = join(import.meta.dir, 'fixtures', 'console');
|
||||
const FIX = join(import.meta.dir, '..', 'fixtures', 'console');
|
||||
const base0: ShipConfig = {
|
||||
app: { name: 'Example Game', profile: 'game', privacyPolicyUrl: 'https://example.com/privacy', supportUrl: 'https://example.com/support', website: 'https://example.com', contactEmail: 'support@example.com' },
|
||||
languages: [{ id: 'en', play: 'en-US', apple: 'en-US' }],
|
||||
|
|
@ -473,7 +473,7 @@ describe.skipIf(!browser)('watchdog: an unknown page after a click never means a
|
|||
});
|
||||
|
||||
describe('every wait of the console engine is bounded (code scan)', () => {
|
||||
const SRC = join(import.meta.dir, '..', 'cli', 'console');
|
||||
const SRC = join(import.meta.dir, '..', '..', 'cli', 'console');
|
||||
const files = readdirSync(SRC).filter(f => f.endsWith('.ts'));
|
||||
/** The text from `open` to its matching `close` (brackets balanced). */
|
||||
const span = (s: string, at: number, open: string, close: string): string => {
|
||||
|
|
@ -8,9 +8,9 @@ import { afterAll, beforeAll, describe, expect, test } from 'bun:test';
|
|||
import { mkdtempSync, rmSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { type ConsoleBrowser, openConsoleBrowser } from '../cli/console/session';
|
||||
import { installedBrowsers } from '../cli/shots/browser';
|
||||
import { capped, CLOSE_TIMEOUT_MS, LAUNCH_TIMEOUT_MS, persistentBrowser } from './helpers/browser';
|
||||
import { type ConsoleBrowser, openConsoleBrowser } from '../../cli/console/session';
|
||||
import { installedBrowsers } from '../../cli/shots/browser';
|
||||
import { capped, CLOSE_TIMEOUT_MS, LAUNCH_TIMEOUT_MS, persistentBrowser } from '../helpers/browser';
|
||||
|
||||
const real = await persistentBrowser();
|
||||
if (!real.label) console.warn(`console-persist tests skipped: ${real.skipWhy}`);
|
||||
|
|
@ -33,7 +33,7 @@ describe.skipIf(!real.label)(`storebound's own profile (${real.label ?? 'no real
|
|||
for (const store of ['apple', 'play'] as const) {
|
||||
test.concurrent(`${store}: a session cookie survives closing and relaunching storebound's own profile`, async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), `storebound-profile-${store}-`));
|
||||
const root = join(import.meta.dir, '..');
|
||||
const root = join(import.meta.dir, '..', '..');
|
||||
const { chromium } = await import('playwright');
|
||||
// the resolver's own choice, without a STOREBOUND_CHROME from the environment
|
||||
const installed = installedBrowsers(chromium, { ...process.env, STOREBOUND_CHROME: undefined });
|
||||
|
|
@ -10,9 +10,9 @@ import { afterAll, describe, expect, test } from 'bun:test';
|
|||
import { existsSync, mkdirSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { APPLE_COPY_NOTE, AUTOMATION_SWITCHES, browserPlan, chromeDataDir, consoleChromeArgs, CONSOLE_HOSTS, cookieApplies, copySession, devToolsEndpoint, filterCookies, GOOGLE_COPY_WARNING, GOOGLE_REJECTED, googleRejected, NEVER_COPY, openConsoleBrowser, parseUseChromeSession, pickProfile, PROVIDER_HOSTS, sessionFiles } from '../cli/console/session';
|
||||
import { sandboxArgs } from '../cli/shots/browser';
|
||||
import { capped, CLOSE_TIMEOUT_MS, LAUNCH_TIMEOUT_MS } from './helpers/browser';
|
||||
import { APPLE_COPY_NOTE, AUTOMATION_SWITCHES, browserPlan, chromeDataDir, consoleChromeArgs, CONSOLE_HOSTS, cookieApplies, copySession, devToolsEndpoint, filterCookies, GOOGLE_COPY_WARNING, GOOGLE_REJECTED, googleRejected, NEVER_COPY, openConsoleBrowser, parseUseChromeSession, pickProfile, PROVIDER_HOSTS, sessionFiles } from '../../cli/console/session';
|
||||
import { sandboxArgs } from '../../cli/shots/browser';
|
||||
import { capped, CLOSE_TIMEOUT_MS, LAUNCH_TIMEOUT_MS } from '../helpers/browser';
|
||||
|
||||
const scratch = mkdtempSync(join(tmpdir(), 'sb-session-test-'));
|
||||
afterAll(() => rmSync(scratch, { recursive: true, force: true }));
|
||||
|
|
@ -226,7 +226,7 @@ describe.skipIf(!hasChrome)('copy mode with real Chrome (throwaway profile, loca
|
|||
await seed.close();
|
||||
seed = null;
|
||||
const said: string[] = [];
|
||||
b = await openConsoleBrowser(join(import.meta.dir, '..'), {
|
||||
b = await openConsoleBrowser(join(import.meta.dir, '..', '..'), {
|
||||
store: 'apple', useChromeSession: ['apple'], profileDir: tmp('own-profile'), say: m => said.push(m), chromeDir: src, hosts: ['127.0.0.1'], headless: true, platform: 'darwin', launchTimeoutMs: LAUNCH_TIMEOUT_MS,
|
||||
});
|
||||
expect(b.mode).toBe('copy');
|
||||
|
|
@ -256,7 +256,7 @@ describe.skipIf(!hasChrome)('the console window has no automation markers (real
|
|||
{ headers: { 'content-type': 'text/html' } }) });
|
||||
let b: any = null;
|
||||
try {
|
||||
b = await openConsoleBrowser(join(import.meta.dir, '..'), {
|
||||
b = await openConsoleBrowser(join(import.meta.dir, '..', '..'), {
|
||||
store: 'play', profileDir: tmp('own-webdriver'), say: () => {}, headless: true, platform: 'darwin', chromeDir: tmp('no-chrome-here'), launchTimeoutMs: LAUNCH_TIMEOUT_MS,
|
||||
});
|
||||
expect(b.mode).toBe('profile');
|
||||
|
|
@ -5,10 +5,10 @@
|
|||
import { afterAll, describe, expect, test } from 'bun:test';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { boxOutside, DEFAULT_PHONE, FEATURE_CANVAS, featureLayout, rotatedBox } from '../cli/shots/lib';
|
||||
import { deviceIssues } from '../cli/shots/report';
|
||||
import { validateConfig } from '../cli/lib/config';
|
||||
import { AFTER_ALL_MS, launchTestBrowser, scaled } from './helpers/browser';
|
||||
import { boxOutside, DEFAULT_PHONE, FEATURE_CANVAS, featureLayout, rotatedBox } from '../../cli/shots/lib';
|
||||
import { deviceIssues } from '../../cli/shots/report';
|
||||
import { validateConfig } from '../../cli/lib/config';
|
||||
import { AFTER_ALL_MS, launchTestBrowser, scaled } from '../helpers/browser';
|
||||
|
||||
const close = (a: number, b: number) => expect(Math.abs(a - b)).toBeLessThan(0.01);
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ describe.skipIf(!browser)('feature graphic templates at 1024 x 500 (DOM layout b
|
|||
for (const style of ['game', 'app'] as const) for (const fit of ['contain', 'bleed'] as const) test(`${style}, fit ${fit}`, async () => {
|
||||
const page = await browser.newPage({ viewport: { width: 1024, height: 500 } });
|
||||
try {
|
||||
const html = readFileSync(join(import.meta.dir, '..', 'cli', 'shots', style === 'app' ? 'feature-app.html' : 'feature.html'), 'utf8');
|
||||
const html = readFileSync(join(import.meta.dir, '..', '..', 'cli', 'shots', style === 'app' ? 'feature-app.html' : 'feature.html'), 'utf8');
|
||||
const job = { style, phone: DEFAULT_PHONE, logo: false, appName: 'Demo', fonts: { title: 'X' }, frame: 'a.png',
|
||||
device: featureLayout(style, DEFAULT_PHONE, { fit }),
|
||||
palette: { bg: ['#123456', '#345678', '#567890'], glow: '#ffffff', ink: '#000000', shadow: 'rgba(0,0,0,.4)' } };
|
||||
|
|
@ -6,8 +6,8 @@
|
|||
import { afterAll, describe, expect, test } from 'bun:test';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { measureFonts } from '../cli/shots/glyphs';
|
||||
import { AFTER_ALL_MS, launchTestBrowser, scaled } from './helpers/browser';
|
||||
import { measureFonts } from '../../cli/shots/glyphs';
|
||||
import { AFTER_ALL_MS, launchTestBrowser, scaled } from '../helpers/browser';
|
||||
|
||||
// one browser for the file, launched and killed by the shared helper (bounded, load-aware timeouts); tools/ci-plan.ts
|
||||
// lists this file as HEAVY (the browser shard)
|
||||
|
|
@ -17,7 +17,7 @@ if (!browser) console.warn(`glyph ligature test skipped: no Chromium installed (
|
|||
|
||||
afterAll(() => shared.close(), AFTER_ALL_MS);
|
||||
|
||||
const font = readFileSync(join(import.meta.dir, 'fixtures', 'fonts', 'montserrat-text-subset.woff2')).toString('base64');
|
||||
const font = readFileSync(join(import.meta.dir, '..', 'fixtures', 'fonts', 'montserrat-text-subset.woff2')).toString('base64');
|
||||
const TEXT = 'Outfits, fit, office, affine';
|
||||
|
||||
describe.skipIf(!browser)('shots font usage: ligatures', () => {
|
||||
|
|
@ -5,11 +5,11 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { brotliCompressSync, deflateSync } from 'node:zlib';
|
||||
import { cmapTable, fontCodepoints, missingChars } from '../cli/shots/cmap';
|
||||
import { attribute, type FaceJob, type MeasuredText, fontIssues, fontsCss, fontUsage, GlyphError, planFonts, roleTexts, uncoveredChars } from '../cli/shots/glyphs';
|
||||
import { langTexts } from '../cli/shots/fonts';
|
||||
import { allIssues, scanRenders } from '../cli/shots/report';
|
||||
import { shotFonts } from '../cli/shots/lib';
|
||||
import { cmapTable, fontCodepoints, missingChars } from '../../cli/shots/cmap';
|
||||
import { attribute, type FaceJob, type MeasuredText, fontIssues, fontsCss, fontUsage, GlyphError, planFonts, roleTexts, uncoveredChars } from '../../cli/shots/glyphs';
|
||||
import { langTexts } from '../../cli/shots/fonts';
|
||||
import { allIssues, scanRenders } from '../../cli/shots/report';
|
||||
import { shotFonts } from '../../cli/shots/lib';
|
||||
|
||||
// ---- tiny font builders (only a cmap table: enough for the reader) ----
|
||||
function cmapBytes(cps: number[]): Uint8Array {
|
||||
|
|
@ -6,12 +6,12 @@ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'nod
|
|||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { brotliCompressSync } from 'node:zlib';
|
||||
import { fontCodepoints, fontFamilyName } from '../cli/shots/cmap';
|
||||
import { type FaceJob, fontIssues, fontsCss, fontUsage, type FontManifest, GlyphError, planFonts } from '../cli/shots/glyphs';
|
||||
import { langTexts } from '../cli/shots/fonts';
|
||||
import { faceFilePath, fontsRoute, loadLocalFont, localByFamily, localFontIssues, resolveShotFonts, staleLocalFonts } from '../cli/shots/local-fonts';
|
||||
import { planWeb } from '../cli/shots/capture-web';
|
||||
import { validateConfig } from '../cli/lib/config';
|
||||
import { fontCodepoints, fontFamilyName } from '../../cli/shots/cmap';
|
||||
import { type FaceJob, fontIssues, fontsCss, fontUsage, type FontManifest, GlyphError, planFonts } from '../../cli/shots/glyphs';
|
||||
import { langTexts } from '../../cli/shots/fonts';
|
||||
import { faceFilePath, fontsRoute, loadLocalFont, localByFamily, localFontIssues, resolveShotFonts, staleLocalFonts } from '../../cli/shots/local-fonts';
|
||||
import { planWeb } from '../../cli/shots/capture-web';
|
||||
import { validateConfig } from '../../cli/lib/config';
|
||||
|
||||
// ---- minimal font writer: an sfnt (or WOFF2) with a format 12 cmap and a name table ----
|
||||
function cmapBytes(cps: number[]): Uint8Array {
|
||||
|
|
@ -6,9 +6,9 @@
|
|||
// (tests/helpers/browser.ts). SLOW on purpose: 113 widths x 2 themes, each a resize and a layout read.
|
||||
import { afterAll, afterEach, describe, expect, test } from 'bun:test';
|
||||
import { join } from 'node:path';
|
||||
import { AFTER_ALL_MS, AFTER_EACH_MS, launchTestBrowser, testScope } from './helpers/browser';
|
||||
import { AFTER_ALL_MS, AFTER_EACH_MS, launchTestBrowser, testScope } from '../helpers/browser';
|
||||
|
||||
const page = 'file://' + join(import.meta.dir, '..', 'site', 'index.html');
|
||||
const page = 'file://' + join(import.meta.dir, '..', '..', 'site', 'index.html');
|
||||
|
||||
const shared = await launchTestBrowser('playwright-core');
|
||||
const { browser, skipWhy } = shared;
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
import { describe, expect, test } from 'bun:test';
|
||||
import { balance, deferBrowser, depsOf, GLOBAL, HEAVY, junitTimes, listTests, mergeTimings, relatedTests, rustNeeded, shardCount } from '../tools/ci-plan';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { balance, deferBrowser, depsOf, GLOBAL, HEAVY, junitTimes, listTests, mergeTimings, relatedTests, ROOT, rustNeeded, shardCount } from '../tools/ci-plan';
|
||||
|
||||
describe('tools/ci-plan: browser suites deferred on a busy machine', () => {
|
||||
test('deferred only when the 1-minute load is above 2x the cores, never with CI=full', () => {
|
||||
|
|
@ -48,9 +50,10 @@ describe('tools/ci-plan: test shards', () => {
|
|||
expect(t).toEqual({ 'a.test.ts': 20, 'b.test.ts': 20, 'keep.test.ts': 3, 'new.test.ts': 5 });
|
||||
});
|
||||
|
||||
test('every heavy suite exists and every test file is found', () => {
|
||||
test('the browser suites exist but are never in the CI test list (bun run test:browser only)', () => {
|
||||
const all = listTests();
|
||||
for (const h of HEAVY) expect(all).toContain(h);
|
||||
for (const h of HEAVY) { expect(existsSync(join(ROOT, h))).toBe(true); expect(all).not.toContain(h); }
|
||||
expect(all.some(f => f.startsWith('tests/browser/'))).toBe(false);
|
||||
expect(all).toContain('tests/ci-plan.test.ts');
|
||||
expect(all).toContain('apps/desktop/tests/webview.test.ts');
|
||||
expect(all.some(f => f.includes('node_modules') || f.includes('/fixtures/'))).toBe(false);
|
||||
|
|
@ -73,11 +76,8 @@ describe('tools/ci-plan: related tests (ci:quick)', () => {
|
|||
expect(GLOBAL.test('bunfig.toml')).toBe(true);
|
||||
expect(relatedTests([['docs/nobody', 'reads.md'].join('-')], all)).toEqual([]);
|
||||
});
|
||||
test('a browser suite runs for its own module and its near imports, not for every shared core module', () => {
|
||||
expect(relatedTests(['cli/lib/upsert.ts'], all, undefined, HEAVY)).not.toContain('tests/console-fill.test.ts');
|
||||
expect(relatedTests(['cli/lib/upsert.ts'], all)).toContain('tests/console-fill.test.ts');
|
||||
expect(relatedTests(['cli/console/fill.ts'], all, undefined, HEAVY)).toContain('tests/console-fill.test.ts');
|
||||
expect(relatedTests(['tests/capture-web.test.ts'], all, undefined, HEAVY)).toEqual(['tests/capture-web.test.ts']);
|
||||
test('ci:quick never picks a browser suite, whatever changed', () => {
|
||||
for (const f of ['cli/lib/upsert.ts', 'cli/console/fill.ts', 'package.json']) expect(relatedTests([f], all).some(t => t.startsWith('tests/browser/'))).toBe(false);
|
||||
});
|
||||
test('Rust steps only for the Tauri crate or the sidecar build, or with CI=full / unknown diff', () => {
|
||||
expect(rustNeeded(['cli/index.ts'], {})).toBe(false);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Shared plumbing of the headless browser tests (tests/console-fill.test.ts, tests/site-overflow.test.ts,
|
||||
// tests/console-session.test.ts). They used to time out now and then, mostly when the machine was busy:
|
||||
// Shared plumbing of the headless browser tests (tests/browser/console-fill.browser.ts, tests/browser/site-overflow.browser.ts,
|
||||
// tests/browser/console-session.browser.ts). They used to time out now and then, mostly when the machine was busy:
|
||||
// - the afterAll browser close (30 s, "(unnamed)" hook timeout). Cause: Google Chrome (the fallback when
|
||||
// playwright's own Chromium is not downloaded) often hangs in its own shutdown after loading http pages and only
|
||||
// exits when its 10 s teardown watchdog fires ("Teardown watchdog expired" in DEBUG=pw:browser); under load that
|
||||
|
|
@ -89,7 +89,7 @@ const firstLine = (e: unknown) => (e as Error).message.split('\n')[0]!;
|
|||
const notInstalled = (e: unknown) => /Executable doesn't exist|distribution '[^']+' is not found|Failed to launch .* because executable/i.test((e as Error).message);
|
||||
|
||||
/**
|
||||
* The browser the persistent-profile tests (tests/console-persist.test.ts) launch: the same kind `console fill` uses
|
||||
* The browser the persistent-profile tests (tests/browser/console-persist.browser.ts) launch: the same kind `console fill` uses
|
||||
* for storebound's own profile (cli/shots/browser.ts, kind "visible"): real Google Chrome (channel "chrome"), else
|
||||
* Playwright's FULL Chromium (channel "chromium"). Never the fast headless shell launchTestBrowser uses: it ignores
|
||||
* --restore-last-session, so session cookies are dropped on relaunch. `label` is null when neither is installed.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue