Files
VoiceStudio/frontend/e2e/_helpers.ts
T
5c9b7ca313 chore(format): adopt oxfmt for JS/TS/JSX + CI format gate (#774)
Adds oxfmt (Rust formatter, Prettier-conformant) — the repo had no formatter, so
this is a one-time normalization of the JS/TS/JSX code (257 files; purely
cosmetic — full suite stays 638/638).

Scope is deliberately narrowed in .oxfmtrc.json to JS/TS/JSX only:
- singleQuote:true + jsxSingleQuote:false — preserve the project's existing
  style (single-quoted JS, double-quoted JSX attrs), not oxfmt's double-quote
  default. (Flipping quotes globally also broke a source-string-parsing test;
  preserving them keeps featureCoverage green.)
- Excludes **/*.css (the CSS→Tailwind migration will rewrite those — formatting
  them now is wasted churn), **/*.json (avoids reformatting 20 i18n locale
  files + config), **/*.toml, and src-tauri/** (Rust/Tauri config — out of scope
  for a frontend JS formatter; oxfmt was reformatting Cargo.toml/tauri.conf.json).

Tooling:
- `bun run format` (write) / `bun run format:check` (verify).
- ci.yml: new "Frontend format check (oxfmt)" gate after the oxlint gate.

Verified: format:check clean; oxlint 0 errors; vite build; full suite 638/638;
bun install --frozen-lockfile in sync.

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 15:18:01 +05:30

60 lines
1.8 KiB
TypeScript

import type { Page } from '@playwright/test';
/** Every routable view (the `mode` values in App.jsx). */
export const MODES = [
'launchpad',
'clone',
'design',
'gallery',
'dub',
'stories',
'projects',
'queue',
'tools',
'transcriptions',
'settings',
'donate',
] as const;
/**
* Fatal client errors that mean a view failed to LOAD — code-split chunk /
* dynamic-import failures (the "Use design → Importing a module script failed"
* regression) and uncaught exceptions. Deliberately NOT matching network/API
* noise (5xx, fetch failures) — backend health is covered elsewhere, and a
* flaky API shouldn't fail a UI-mount test.
*/
const FATAL = [
/Importing a module script failed/i,
/Failed to fetch dynamically imported module/i,
/error loading dynamically imported module/i,
/ChunkLoadError/i,
];
export type ErrorSink = { fatal: string[]; all: string[] };
/** Attach console/pageerror listeners; returns a sink you assert on later. */
export function collectErrors(page: Page): ErrorSink {
const sink: ErrorSink = { fatal: [], all: [] };
const record = (text: string) => {
sink.all.push(text);
if (FATAL.some((re) => re.test(text))) sink.fatal.push(text);
};
page.on('pageerror', (err) => record(`pageerror: ${err.message}`));
page.on('console', (msg) => {
if (msg.type() === 'error') record(`console.error: ${msg.text()}`);
});
return sink;
}
/**
* Land directly on a view by seeding the zustand-persist store (key
* `omnivoice.app`) before the app boots. A shallow merge over slice defaults,
* so only `mode` is forced.
*/
export async function gotoMode(page: Page, mode: string): Promise<void> {
await page.addInitScript((m) => {
localStorage.setItem('omnivoice.app', JSON.stringify({ state: { mode: m }, version: 4 }));
}, mode);
await page.goto('/');
}