test: remove low-value localization and mobile test coverage

This commit is contained in:
OrcaWin
2026-11-13 08:35:35 -08:00
parent 5480f48d5b
commit d62a48d7bd
20 changed files with 21 additions and 1005 deletions
@@ -94,11 +94,7 @@
"config/scripts/diagnostics/lag-capture/lag-probe-failures.test.mjs": 55,
"config/scripts/dependency-security/runtime-resolution/linear-sdk-runtime.test.mjs": 773,
"config/scripts/preflight/changed-checks/lint-staged-worktree-backup.test.mjs": 278,
"config/scripts/locale-catalog/locale-brand-prefilter.test.mjs": 246,
"config/scripts/locale-catalog/locale-generic-ui-terms.test.mjs": 102,
"config/scripts/locale-catalog/locale-repair-catalog-missing-leaves.test.mjs": 159,
"config/scripts/locale-catalog/locale-translation-policy.es-pr.test.mjs": 91,
"config/scripts/locale-catalog/locale-translation-policy.test.mjs": 189,
"config/scripts/localization/source-extraction/localization-extraction-call-syntax.test.mjs": 317,
"config/scripts/localization/extraction-policy/localization-extraction-change-scope.test.mjs": 732,
"config/scripts/performance/macos-computer-owner/macos-computer-helper-owner-loss-processes.test.mjs": 52,
@@ -130,7 +126,6 @@
"config/scripts/mobile-web-app/shell/mobile-web-app-render.test.mjs": 254,
"config/scripts/mobile-web-app/session/mobile-web-app-rich-markdown-render.test.mjs": 356,
"config/scripts/mobile-web-app/mobile-web-app-route-manifest.test.mjs": 174,
"config/scripts/mobile-web-app/mobile-web-app-route-snapshot.test.mjs": 121,
"config/scripts/mobile-web-app/shell/mobile-web-app-safe-area-render.test.mjs": 314,
"config/scripts/mobile-web-app/session/mobile-web-app-screencast-lane-grant.test.mjs": 70,
"config/scripts/mobile-web-app/session/mobile-web-app-session-dictation-capture.test.mjs": 123,
@@ -230,7 +225,6 @@
"config/scripts/tool-invocation/script-entry-detection.test.mjs": 107,
"config/scripts/test-fixtures/script-copy-closure/script-module-dependencies.test.mjs": 62,
"config/scripts/ci/workflow-contracts/setup-pnpm-action.test.mjs": 421,
"config/scripts/electron-installation/shared-dist-cache/shared-electron-dist-cache.test.ts": 140,
"config/scripts/native-build/node-addons/shared-native-build.test.mjs": 127,
"config/scripts/artifact-storage/atomic-publication/shared-tree-publish.test.mjs": 63,
"config/scripts/desktop-distribution/macos/sign-mac-app.test.mjs": 268,
@@ -246,8 +240,6 @@
"config/scripts/desktop-distribution/channel-policy/verify-dev-channel-packaging.test.mjs": 213,
"config/scripts/native-build/linux/verify-linux-glibc-floor.test.mjs": 156,
"config/scripts/localization/catalog-validation/verify-localization-catalog.test.mjs": 422,
"config/scripts/localization/catalog-validation/verify-localization-catalogs.test.mjs": 1574,
"config/scripts/localization/source-extraction/verify-localization-extraction.test.mjs": 233,
"config/scripts/desktop-distribution/runtime-verification/verify-packaged-mobile-web-bundle.test.mjs": 214,
"config/scripts/desktop-distribution/runtime-verification/verify-packaged-node-pty-job-ownership.test.mjs": 93,
"config/scripts/orcad-distribution/template/verify-packaged-orcad-template.test.mjs": 454,
@@ -1,45 +1,20 @@
import { rmSync } from 'node:fs'
import { afterEach, describe, expect, it } from 'vitest'
import { describe, expect, it } from 'vitest'
import { sanitizeStressText } from './windows-pty-table-stress-observer.mjs'
const directories = []
afterEach(() => {
for (const directory of directories.splice(0)) {
rmSync(directory, { recursive: true, force: true })
}
})
describe('Windows PTY stress observer', () => {
it('preserves OSC boundaries while redacting their title payload and adjacent CSI text', () => {
it('redacts a key interrupted by adjacent controls without moving their bytes', () => {
const esc = String.fromCharCode(27)
const raw = `${esc}]0;private@sensitive.test${esc}\\${esc}[31mprivate@sensitive.test`
const before = 'sk-secret01'
const after = '234567890abcdefghijkl'
const controls = `${esc}[31m${esc}[1m`
const raw = `${before}${controls}${after}`
const sanitized = sanitizeStressText(raw)
expect(sanitized).not.toContain('private@')
expect(sanitized).not.toContain('sensitive.test')
expect(sanitized).toContain(`${esc}]0;`)
expect(sanitized).toContain(`${esc}\\${esc}[31m`)
expect(sanitized).not.toContain(before)
expect(sanitized).not.toContain(after)
expect(sanitized.slice(before.length, before.length + controls.length)).toBe(controls)
expect(sanitized.length).toBe(raw.length)
})
it.each([
['email domain', 'private@', 'sensitive.test', ['[31m']],
['email name', 'pri', 'vate@sensitive.test', ['[31m', '[1m']],
['vendor key', 'sk-secret01', '234567890abcdefghijkl', ['[31m', '[1m']],
['bearer token', 'Bearer secret01', '234567890abcdefghijkl', ['[31m', '[1m']]
])(
'redacts %s interrupted by adjacent controls without moving their bytes',
(_kind, before, after, fragments) => {
const esc = String.fromCharCode(27)
const controls = fragments.map((fragment) => esc + fragment).join('')
const raw = `${before}${controls}${after}`
const sanitized = sanitizeStressText(raw)
expect(sanitized).not.toContain(before)
expect(sanitized).not.toContain(after)
expect(sanitized.slice(before.length, before.length + controls.length)).toBe(controls)
expect(sanitized.length).toBe(raw.length)
}
)
it('scrubs an interrupted OSC title independently from the adjacent rendered address', () => {
const esc = String.fromCharCode(27)
const title = `private@${esc}[31msensitive.test`
@@ -1,19 +1,10 @@
import {
existsSync,
lstatSync,
mkdirSync,
readdirSync,
readFileSync,
rmSync,
writeFileSync
} from 'node:fs'
import { existsSync, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'
import {
addSiblingWorktree,
initGitRepo,
mkTempProject,
readExtractorCallCount,
readSharedDistMarker,
runInstallScript,
sharedCacheRoot,
@@ -27,7 +18,7 @@ import {
} from './install-electron-package-binary-test-fixtures.mjs'
describe('install-electron-package-binary', () => {
it('installs Electron from an isolated cache and repairs path.txt', () => {
it('installs the distribution and repairs path.txt', () => {
const projectDir = mkTempProject()
try {
@@ -43,10 +34,6 @@ describe('install-electron-package-binary', () => {
const result = runInstallScript(projectDir)
expect(result.status, result.stderr).toBe(0)
expect(readFileSync(join(projectDir, 'electron-get.log'), 'utf8')).toMatch(
/cacheRoot=.*orca-electron-.*cache/
)
expect(readFileSync(join(projectDir, 'electron-get.log'), 'utf8')).toContain('force=true')
expect(readFileSync(join(projectDir, 'node_modules', 'electron', 'path.txt'), 'utf8')).toBe(
'electron'
)
@@ -61,31 +48,6 @@ describe('install-electron-package-binary', () => {
).isSymbolicLink()
).toBe(true)
}
expect(result.stdout).toContain('Repaired Electron path.txt -> electron')
} finally {
rmSync(projectDir, { recursive: true, force: true })
}
})
it('preserves an existing Electron distribution when replacement download fails', () => {
const projectDir = mkTempProject()
try {
writeFakeElectronPackage(projectDir)
writeFakeElectronGet(projectDir, { downloadFailures: 1, downloadErrorCode: 'EACCES' })
writeFakeElectronDist(projectDir, {
version: 'v40.0.0',
executableContents: 'existing executable',
pathContents: 'electron'
})
const result = runInstallScript(projectDir)
const electronDir = join(projectDir, 'node_modules/electron')
expect(result.status).toBe(1)
expect(readFileSync(join(electronDir, 'dist/version'), 'utf8')).toBe('v40.0.0')
expect(readFileSync(join(electronDir, 'dist/electron'), 'utf8')).toBe('existing executable')
expect(readFileSync(join(electronDir, 'path.txt'), 'utf8')).toBe('electron')
} finally {
rmSync(projectDir, { recursive: true, force: true })
}
@@ -124,36 +86,6 @@ describe('install-electron-package-binary', () => {
}
})
it('keeps a persistent cache root while retrying transient failures', () => {
const projectDir = mkTempProject()
const cacheRoot = join(projectDir, 'electron-cache')
try {
writeFakeElectronPackage(projectDir)
writeFakeElectronGet(projectDir, {
downloadFailures: 1,
downloadErrorCode: 'ECONNRESET'
})
writeFakeExtractor(projectDir, { createExecutable: true })
mkdirSync(cacheRoot, { recursive: true })
writeFileSync(join(cacheRoot, 'preserved.marker'), 'keep me')
const result = runInstallScript(projectDir, {
ORCA_ELECTRON_PACKAGE_CACHE_ROOT: cacheRoot,
ORCA_ELECTRON_PACKAGE_RETRY_DELAYS_MS: '0,0'
})
expect(result.status, result.stderr).toBe(0)
expect(existsSync(join(cacheRoot, 'preserved.marker'))).toBe(true)
expect(
readFileSync(join(projectDir, 'electron-get.log'), 'utf8').trim().split('\n')
).toHaveLength(2)
} finally {
rmSync(projectDir, { recursive: true, force: true })
}
})
// The shared cache is macOS-only: it exists to avoid a second copy via APFS clonefile.
it('shares the Electron dist into a sibling worktree without downloading', () => {
const projectDir = mkTempProject()
const siblingDir = `${projectDir}-sibling`
@@ -174,7 +106,6 @@ describe('install-electron-package-binary', () => {
const siblingDistDir = join(siblingDir, 'node_modules/electron/dist')
expect(result.status, result.stderr).toBe(0)
expect(readExtractorCallCount(siblingDir)).toBe(0)
expect(existsSync(join(siblingDir, 'electron-get.log'))).toBe(false)
expect(lstatSync(siblingDistDir).isDirectory()).toBe(true)
expect(lstatSync(siblingDistDir).isSymbolicLink()).toBe(false)
@@ -184,44 +115,13 @@ describe('install-electron-package-binary', () => {
'electron'
)
expect(readSharedDistMarker(siblingDir)).toBe(sharedEntryName)
expect(result.stdout).toContain('Shared Electron 41.5.0 from')
} finally {
rmSync(siblingDir, { recursive: true, force: true })
rmSync(projectDir, { recursive: true, force: true })
}
})
it('publishes an already installed Electron dist that predates the shared cache', () => {
const projectDir = mkTempProject()
try {
initGitRepo(projectDir)
writeFakeElectronPackage(projectDir)
writeFakeElectronGet(projectDir)
writeFakeExtractor(projectDir, { createExecutable: true })
writeFakeElectronDist(projectDir, {
executableContents: 'existing executable',
pathContents: 'electron'
})
const result = runInstallScript(projectDir, { CI: '' })
const entryPath = join(sharedCacheRoot(projectDir), sharedEntryName)
const distDir = join(projectDir, 'node_modules/electron/dist')
expect(result.status, result.stderr).toBe(0)
expect(readExtractorCallCount(projectDir)).toBe(0)
expect(existsSync(join(projectDir, 'electron-get.log'))).toBe(false)
expect(readFileSync(join(entryPath, 'version'), 'utf8')).toBe('v41.5.0')
expect(readFileSync(join(entryPath, 'electron'), 'utf8')).toBe('existing executable')
expect(readSharedDistMarker(projectDir)).toBe(sharedEntryName)
expect(readFileSync(join(distDir, 'electron'), 'utf8')).toBe('existing executable')
expect(readFileSync(join(distDir, 'version'), 'utf8')).toBe('v41.5.0')
} finally {
rmSync(projectDir, { recursive: true, force: true })
}
})
it('replaces a corrupt shared Electron dist entry instead of re-downloading forever', () => {
it('repairs a corrupt shared Electron dist entry', () => {
const projectDir = mkTempProject()
try {
@@ -238,16 +138,12 @@ describe('install-electron-package-binary', () => {
const distDir = join(projectDir, 'node_modules/electron/dist')
expect(result.status, result.stderr).toBe(0)
expect(result.stderr).not.toContain('Failed to install Electron package binary')
expect(readExtractorCallCount(projectDir)).toBe(1)
expect(readFileSync(join(distDir, 'version'), 'utf8')).toBe('v41.5.0')
expect(readFileSync(join(projectDir, 'node_modules/electron/path.txt'), 'utf8')).toBe(
'electron'
)
// Why not just fall back: an entry left corrupt makes every sibling worktree download again.
expect(readFileSync(join(entryPath, 'version'), 'utf8')).toBe('v41.5.0')
expect(readSharedDistMarker(projectDir)).toBe(sharedEntryName)
expect(readdirSync(sharedCacheRoot(projectDir))).toEqual([sharedEntryName])
} finally {
rmSync(projectDir, { recursive: true, force: true })
}
@@ -275,11 +171,6 @@ describe('install-electron-package-binary', () => {
'v42.0.0'
)
expect(readSharedDistMarker(projectDir)).toBe(sharedEntryNameFor('42.0.0'))
// Why the old entry stays: sibling worktrees on the previous branch still share it.
expect(readdirSync(cacheRoot).sort()).toEqual([
sharedEntryNameFor('41.5.0'),
sharedEntryNameFor('42.0.0')
])
expect(readFileSync(join(cacheRoot, sharedEntryNameFor('41.5.0'), 'version'), 'utf8')).toBe(
'v41.5.0'
)
@@ -1,131 +0,0 @@
import type { execFileSync } from 'node:child_process'
import {
existsSync,
mkdirSync,
mkdtempSync,
readdirSync,
rmSync,
symlinkSync,
writeFileSync
} from 'node:fs'
import { tmpdir } from 'node:os'
import path from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import {
shareElectronDistFromCache,
isUsableElectronDist,
publishSharedElectronDist,
resolveSharedElectronDistEntry
} from './shared-electron-dist-cache.mjs'
const VERSION = '43.4.1'
const PLATFORM_PATH = path.join('Electron.app', 'Contents', 'MacOS', 'Electron')
const roots: string[] = []
afterEach(() => {
while (roots.length > 0) {
rmSync(roots.pop()!, { recursive: true, force: true })
}
})
function makeRoot(): string {
const root = mkdtempSync(path.join(tmpdir(), 'orca-shared-electron-'))
roots.push(root)
return root
}
function writeDist(distPath: string, version = VERSION): string {
mkdirSync(path.join(distPath, path.dirname(PLATFORM_PATH)), { recursive: true })
writeFileSync(path.join(distPath, 'version'), `v${version}\n`)
writeFileSync(path.join(distPath, PLATFORM_PATH), 'electron')
return distPath
}
function makeEntry(root: string, entryName = `${VERSION}-darwin-arm64`) {
const cacheRoot = path.join(root, 'cache')
return {
cacheRoot,
entryPath: path.join(cacheRoot, entryName),
markerPath: path.join(root, '.orca-shared-dist')
}
}
const baseOptions = {
repoRoot: '/repo',
electronPackageDir: '/repo/node_modules/electron',
version: VERSION,
targetPlatform: 'darwin',
targetArch: 'arm64',
env: {} as NodeJS.ProcessEnv,
execFile: (() => '/repo/.git\n') as unknown as typeof execFileSync
}
describe('resolveSharedElectronDistEntry', () => {
it('declines an identity that would not be a single safe path segment', () => {
expect(resolveSharedElectronDistEntry({ ...baseOptions, targetArch: '../escape' })).toBeNull()
expect(resolveSharedElectronDistEntry({ ...baseOptions, targetPlatform: 'dar/win' })).toBeNull()
expect(resolveSharedElectronDistEntry({ ...baseOptions, version: '' })).toBeNull()
})
})
describe('isUsableElectronDist', () => {
it('rejects a symlink so a redirected entry is never treated as cache content', () => {
const root = makeRoot()
writeDist(path.join(root, 'real'))
symlinkSync(path.join(root, 'real'), path.join(root, 'link'), 'dir')
expect(isUsableElectronDist(path.join(root, 'link'), VERSION, PLATFORM_PATH)).toBe(false)
})
})
describe('publishSharedElectronDist', () => {
it('leaves no entry and no staging tree when sharing fails', () => {
const root = makeRoot()
const entry = makeEntry(root)
const share = (_source: string, destination: string) => {
writeDist(destination)
throw new Error('no shareable storage')
}
expect(publishSharedElectronDist(writeDist(path.join(root, 'dist')), entry, { share })).toBe(
false
)
expect(existsSync(entry.entryPath)).toBe(false)
expect(readdirSync(entry.cacheRoot)).toEqual([])
})
})
describe('shareElectronDistFromCache', () => {
it('refuses an entry that fails validation instead of installing it', () => {
const root = makeRoot()
const entry = makeEntry(root)
mkdirSync(entry.cacheRoot, { recursive: true })
writeDist(entry.entryPath, '40.0.0')
const stagePath = path.join(root, 'stage')
expect(
shareElectronDistFromCache(entry, stagePath, {
version: VERSION,
platformPath: PLATFORM_PATH
})
).toBe(false)
expect(existsSync(stagePath)).toBe(false)
})
it('reports failure rather than falling back to a full copy', () => {
const root = makeRoot()
const entry = makeEntry(root)
mkdirSync(entry.cacheRoot, { recursive: true })
writeDist(entry.entryPath)
// Stub mechanism-dependent sharing failures; byte-copy fallback would defeat cache’s storage purpose.
const stagePath = path.join(root, 'stage')
const share = () => {
throw new Error('no shareable storage')
}
expect(
shareElectronDistFromCache(entry, stagePath, {
version: VERSION,
platformPath: PLATFORM_PATH,
share
})
).toBe(false)
expect(existsSync(stagePath)).toBe(false)
})
})
@@ -1,55 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import { repairTranslatedValue } from './locale-translation-policy.mjs'
describe('locale brand matching', () => {
it('does not construct boundary expressions for absent brands', () => {
let boundaryExpressions = 0
vi.stubGlobal(
'RegExp',
new Proxy(RegExp, {
construct(target, args) {
if (typeof args[0] === 'string' && args[0].startsWith('(^|[^A-Za-z_])')) {
boundaryExpressions += 1
}
return Reflect.construct(target, args)
}
})
)
try {
for (const locale of ['zh', 'ja', 'ko', 'es']) {
expect(
repairTranslatedValue({
key: 'fixture.endpoint',
enValue: 'Choose an endpoint.',
localeValue: 'fixture translation',
locale
})
).toBe('fixture translation')
}
} finally {
vi.unstubAllGlobals()
}
expect(boundaryExpressions).toBe(0)
})
it.each([
['Use Gemini.', 'Usar Géminis.', 'Usar Gemini.'],
['Use GeminiX.', 'Usar Géminis.', 'Usar Géminis.'],
['Use XGemini.', 'Usar Géminis.', 'Usar Géminis.'],
['Use _Gemini_.', 'Usar Géminis.', 'Usar Géminis.'],
['Use Gemini_2.', 'Usar Géminis.', 'Usar Géminis.'],
['Use 2Gemini3.', 'Usar Géminis.', 'Usar Gemini.'],
['Use (Gemini).', 'Usar Géminis.', 'Usar Gemini.'],
['Use éGemini界.', 'Usar Géminis.', 'Usar Gemini.'],
['Use gemini.', 'Usar Géminis.', 'Usar Géminis.'],
['Use GeminiX and Gemini.', 'Usar Géminis.', 'Usar Gemini.'],
['Use Gemini.', 'Gemini y Géminis.', 'Gemini y Géminis.'],
['Use Gemini.', '_Gemini_ y Géminis.', '_Gemini_ y Gemini.'],
['Use GitHub Copilot.', 'Usar Copiloto de GitHub.', 'Usar GitHub Copilot.'],
['Use XGitHub CopilotY.', 'Usar Copiloto de GitHub.', 'Usar GitHub Copilot.']
])('preserves literal and boundary matching for %j / %j', (enValue, localeValue, expected) => {
expect(
repairTranslatedValue({ key: 'fixture.brand', enValue, localeValue, locale: 'es' })
).toBe(expected)
})
})
@@ -1,125 +0,0 @@
import { describe, expect, it } from 'vitest'
import { repairTranslatedValue } from './locale-translation-policy.mjs'
// #12113: generic-word brand repair reverted ~2000 translations; keep UI vocabulary translated and real brands Latin.
describe('locale generic UI terms', () => {
it('keeps a translated generic term when the whole value is that term', () => {
expect(
repairTranslatedValue({
key: 'auto.components.settings.AppearancePane.terminalTitle',
enValue: 'Terminal',
localeValue: '터미널',
locale: 'ko'
})
).toBe('터미널')
expect(
repairTranslatedValue({
key: 'auto.components.settings.QuickCommandsPane.4ccc63da87',
enValue: 'Agent',
localeValue: '에이전트',
locale: 'ko'
})
).toBe('에이전트')
expect(
repairTranslatedValue({
key: 'auto.components.mobile.MobileHero.a8fb43cf1c',
enValue: 'Continue',
localeValue: '继续',
locale: 'zh'
})
).toBe('继续')
})
it('keeps a translated generic term inside a sentence', () => {
expect(
repairTranslatedValue({
key: 'auto.components.settings.EditorFontSection.matchTerminal',
enValue: 'Match terminal font',
localeValue: '터미널 글꼴과 동일',
locale: 'ko'
})
).toBe('터미널 글꼴과 동일')
expect(
repairTranslatedValue({
key: 'auto.components.settings.ExperimentalPane.agentDashboard.toggleLabel',
enValue: 'Toggle Agent Dashboard',
localeValue: '에이전트 대시보드 전환',
locale: 'ko'
})
).toBe('에이전트 대시보드 전환')
expect(
repairTranslatedValue({
key: 'components.agentSessionContinuation.dialogTitle',
enValue: 'Continue in New Session',
localeValue: '新しいセッションで続ける',
locale: 'ja'
})
// 新しい → 新規 is an unrelated phrase fix; 続ける is what must survive.
).toBe('新規セッションで続ける')
})
it('still reverts real brand names that machine translation localized', () => {
expect(
repairTranslatedValue({
key: 'auto.stats.StatsPane.7d26110cea',
enValue: 'Codex',
localeValue: '사본',
locale: 'ko'
})
).toBe('Codex')
expect(
repairTranslatedValue({
key: 'auto.components.settings.NetworkPane.tailscale',
enValue: 'Connect over Tailscale',
localeValue: '通过尾鳞连接',
locale: 'zh'
})
).toBe('通过 Tailscale 连接')
})
it('does not cut a valid word that contains a nonsense rendering', () => {
// 终端子进程 is "terminal sub-process" — 端子 sits inside 终端 + 子.
expect(
repairTranslatedValue({
key: 'auto.components.settings.AdvancedNetworkSettingsSection.823e0f15b1',
enValue: 'Proxy URL for Orca network requests and local terminal subprocesses.',
localeValue: '用于 Orca 网络请求和本地终端子进程的代理 URL。',
locale: 'zh'
})
).toBe('用于 Orca 网络请求和本地终端子进程的代理 URL。')
})
it('still fills in a translation when the catalog holds English', () => {
expect(
repairTranslatedValue({
key: 'auto.components.feature.wall.BrowserAnimatedVisual.04096318ab',
enValue: 'Terminal 1',
localeValue: 'Terminal 1',
locale: 'ko'
})
).toBe('터미널 1')
})
it('keeps agent catalog product names in English by key, not by word', () => {
expect(
repairTranslatedValue({
key: 'auto.lib.agent.catalog.9e2a9bb87b',
enValue: 'Continue',
localeValue: '继续',
locale: 'zh'
})
).toBe('Continue')
})
it.each([
['ko', 'Commit', '커밋'],
['ja', 'repos', 'リポジトリ'],
['es', 'agents', 'agentes'],
['ko', 'terminals', '터미널']
])('preserves the %s translation of generic %s', (locale, enValue, localeValue) => {
expect(repairTranslatedValue({ key: 'fixture.generic', enValue, localeValue, locale })).toBe(
localeValue
)
})
})
@@ -14,16 +14,8 @@ describe('repairCatalog with un-bootstrapped keys', () => {
const translatedOnly = () => ({ auto: { lib: { agent: { catalog: { '760bc6883d': '사본' } } } } })
it('skips leaves the locale catalog is missing instead of throwing', () => {
for (const locale of ['ko', 'ja', 'zh', 'es']) {
const localeCatalog = translatedOnly()
expect(() => repairCatalog(enCatalog, localeCatalog, locale), locale).not.toThrow()
expect(localeCatalog.auto.components, locale).toBeUndefined()
}
})
it('still repairs the leaves that are present', () => {
const localeCatalog = translatedOnly()
expect(repairCatalog(enCatalog, localeCatalog, 'ko')).toBe(1)
expect(localeCatalog.auto.lib.agent.catalog['760bc6883d']).toBe('Codex')
expect(() => repairCatalog(enCatalog, localeCatalog, 'ko')).not.toThrow()
expect(localeCatalog.auto.components).toBeUndefined()
})
})
@@ -1,34 +0,0 @@
import { describe, expect, it } from 'vitest'
import { repairTranslatedValue } from './locale-translation-policy.mjs'
const repairEs = (enValue, localeValue) =>
repairTranslatedValue({
key: 'auto.components.test.pr-glossary',
enValue,
localeValue,
locale: 'es'
})
describe('locale-translation-policy es PR glossary', () => {
it('rewrites the "relaciones públicas" mistranslation of PR back to PR', () => {
expect(repairEs('PR', 'relaciones públicas')).toBe('PR')
expect(repairEs('PRs', 'relaciones públicas')).toBe('PR')
expect(repairEs('Reopen PR', 'Reabrir relaciones públicas')).toBe('Reabrir PR')
expect(repairEs('Create PR', 'Crear relaciones públicas')).toBe('Crear PR')
expect(repairEs('Open PR checks', 'Abrir cheques de relaciones públicas')).toBe(
'Abrir cheques de PR'
)
expect(repairEs('unlink PR', 'desvincular relaciones públicas')).toBe('desvincular PR')
})
it('does not fire when the English has a "pr" substring but no PR token', () => {
// approve/public contain pr substring but no PR token; leave genuine public-relations prose alone.
expect(repairEs('Approve public relations', 'Aprobar relaciones públicas')).toBe(
'Aprobar relaciones públicas'
)
expect(repairEs('Compress the preview', 'Comprimir las relaciones públicas')).toBe(
'Comprimir las relaciones públicas'
)
})
})
@@ -1,22 +0,0 @@
import { describe, expect, it } from 'vitest'
import { repairTranslatedValue, shouldPreserveEnglishValue } from './locale-translation-policy.mjs'
describe('locale-translation-policy', () => {
it('does not break Copy identifier when fixing Codex', () => {
expect(
repairTranslatedValue({
key: 'auto.components.example',
enValue: 'Copy identifier',
localeValue: '사본 식별자',
locale: 'ko'
})
).toBe('사본 식별자')
})
it('skips machine translation for standalone brands', () => {
expect(shouldPreserveEnglishValue('Codex')).toBe(true)
expect(shouldPreserveEnglishValue('Codex', 'auto.stats.StatsPane.7d26110cea')).toBe(true)
expect(shouldPreserveEnglishValue('Show Codex usage')).toBe(false)
})
})
@@ -4,18 +4,7 @@ import path from 'node:path'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { collectProtectedCopyKeys, main, PROTECTED_COPY_KEYS_PATH } from './protected-copy-keys.mjs'
const ENGLISH = new Set([
'trust.title',
'trust.allow',
'trust.copy.warning',
'confirm.delete',
'confirm.count_other',
'native.quit',
'pragma.badge',
'nested.deep',
'trust.reasons.network',
'plain.title'
])
const ENGLISH = new Set(['trust.title', 'trust.reasons.network'])
let dirs = []
afterEach(() => {
@@ -40,33 +29,6 @@ function sourcesFrom(files) {
}
describe('collectProtectedCopyKeys', () => {
it('protects every key a marked file or its sibling copy module names', () => {
const sources = sourcesFrom({
'dialogs/TrustDialog.tsx': `import { trustCopy } from './trust-copy'
import { plain } from '../plain/Plain'
<DialogContent surface="security">{translate('trust.title', 'Trust?')}{translate('trust.allow', 'Allow')}`,
'dialogs/trust-copy.ts': `export const trustCopy = () => translate('trust.copy.warning', 'Careful')`,
'plain/Plain.tsx': `export const plain = () => translate('plain.title', 'Title')`,
'confirm/DeleteDialog.tsx': `<DialogContent><Button variant="destructive">{translate('confirm.delete', 'Delete')}{translate('confirm.count', '{{count}}', { count })}</Button>`,
'main/prompt.ts': `dialog.showMessageBox({ buttons: [translateMain('native.quit', 'Quit')] })`,
'badge.ts': `// @protected-copy: badge\nexport const b = () => translate('pragma.badge', 'Official')`,
'other.tsx': `translate('nested.deep', 'Deep')`
})
expect(collectProtectedCopyKeys(sources, ENGLISH)).toEqual({
keys: [
'confirm.count',
'confirm.delete',
'native.quit',
'pragma.badge',
'trust.allow',
'trust.copy.warning',
'trust.title'
],
prefixes: []
})
})
it('keeps dynamic key heads only when they are specific', () => {
const sources = sourcesFrom({
'Dialog.tsx': '<SecuritySurface>{translate(`trust.${id}`)}{translate(`trust.reasons.${x}`)}'
@@ -48,30 +48,6 @@ describe('verify-localization-catalog', () => {
expect(readJson(path.join(localesDir, 'es.json'))).toEqual({})
})
it.each([
['en', false],
['en', true],
['es', false]
])('rejects dotted %s keys without rewriting them (fix: %s)', async (locale, fix) => {
const nested = { auto: { example: { greeting: 'Hello.world' } } }
const { root, localesDir } = makeProject({
sourceText: 'export {}\n',
enCatalog: locale === 'en' ? { 'auto.example.greeting': 'Hello.world' } : nested,
esCatalog: locale === 'es' ? { auto: { 'example.greeting': 'Hola.world' } } : {}
})
const catalogPath = path.join(localesDir, `${locale}.json`)
const before = readFileSync(catalogPath, 'utf8')
const report = vi.spyOn(console, 'error').mockImplementation(() => undefined)
try {
await expect(verifyLocalizationCatalog(root, { fix })).resolves.toBe(1)
expect(report).toHaveBeenCalledWith(expect.stringContaining(`${locale}.json`))
expect(report).toHaveBeenCalledWith('dotted: auto.example.greeting')
expect(readFileSync(catalogPath, 'utf8')).toBe(before)
} finally {
report.mockRestore()
}
})
it('never overwrites mismatched translations or removes target-only entries', async () => {
const { root, localesDir } = makeProject({
sourceText:
@@ -1,50 +0,0 @@
import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { main as verifyTogether } from './verify-localization-catalogs.mjs'
const directories = []
const renderer = 'src/renderer/src'
const englishPath = `${renderer}/i18n/locales/en.json`
const runtimePath = `${renderer}/i18n/en-runtime-required.json`
async function fixture() {
const root = await mkdtemp(join(tmpdir(), 'orca-localization-checks-'))
directories.push(root)
await mkdir(join(root, renderer, 'i18n/locales'), { recursive: true })
await mkdir(join(root, 'src/main'), { recursive: true })
await writeFile(join(root, renderer, 'greeting.ts'), "translate('hello', 'Hello')\n")
await writeFile(join(root, 'src/main/ready.ts'), "translateMain('ready', 'Ready')\n")
await writeFile(
join(root, englishPath),
JSON.stringify({ hello: 'Hello', ready: 'Ready', dynamic: 'Required' })
)
await writeFile(join(root, runtimePath), JSON.stringify({ dynamic: 'Required' }))
await mkdir(join(root, 'src/shared/plugins/languages'), { recursive: true })
await writeFile(
join(root, 'src/shared/plugins/languages/protected-copy-keys.json'),
`${JSON.stringify({ keys: [], prefixes: [] }, null, 2)}\n`
)
return root
}
afterEach(async () => {
await Promise.all(directories.splice(0).map((root) => rm(root, { recursive: true, force: true })))
})
describe('combined localization verification', () => {
it('reads source edits, new files, removals, and separate roots on each invocation', async () => {
const root = await fixture()
expect(await verifyTogether(root)).toBe(0)
await writeFile(join(root, renderer, 'greeting.ts'), "translate('hello', 'New fallback')")
expect(await verifyTogether(root)).toBe(1)
await writeFile(join(root, renderer, 'greeting.ts'), "translate('hello', 'Hello')")
expect(await verifyTogether(root)).toBe(0)
await writeFile(join(root, 'src/main/added.ts'), "translateMain('absent', 'Absent')")
expect(await verifyTogether(root)).toBe(1)
await rm(join(root, 'src/main/added.ts'))
expect(await verifyTogether(root)).toBe(0)
expect(await verifyTogether(await fixture())).toBe(0)
})
})
@@ -2,34 +2,9 @@ import { describe, expect, it, vi } from 'vitest'
import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { collectLocalizationCandidates, main } from './audit-localization-coverage.mjs'
const path = '/repo/src/main/startup/dialog.ts'
const source = `
const options = {
message: translateMain('message', 'Translated message'),
detail: 'Untranslated detail',
buttons: ['Proceed', translateMain('cancel', 'Cancel')],
body: 'Untranslated body',
buttonLabel: 'Retry',
checkboxLabel: 'Remember choice'
}
`
import { main } from './audit-localization-coverage.mjs'
describe('native dialog localization coverage', () => {
it('finds untranslated native dialog fields while ignoring translated copy', () => {
const candidates = collectLocalizationCandidates(path, source, '/repo', {
includeNativeDialogFields: true
})
expect(candidates.map(({ kind, text }) => [kind, text])).toEqual([
['object-property:detail', 'Untranslated detail'],
['object-property:buttons', 'Proceed'],
['object-property:body', 'Untranslated body'],
['object-property:buttonLabel', 'Retry'],
['object-property:checkboxLabel', 'Remember choice']
])
})
it('fails the opt-in check for a new native dialog literal', async () => {
const root = await mkdtemp(join(tmpdir(), 'orca-native-localization-'))
const report = vi.spyOn(console, 'error').mockImplementation(() => {})
@@ -1,55 +0,0 @@
import { describe, expect, it } from 'vitest'
import {
collectKeyLiterals,
compareExtraction,
findUnreferencedKeys
} from './verify-localization-extraction.mjs'
function sourceEvidence(sourceText) {
return collectKeyLiterals(sourceText, { literals: new Set(), dynamicPrefixes: new Set() })
}
describe('verify-localization-extraction', () => {
it('rejects missing English declarations and incompatible placeholders', () => {
const result = compareExtraction(
{
menu: {
missing: 'Missing',
open: 'Open {{name}}'
}
},
{ menu: { open: 'Open {{path}}' } }
)
expect(result.missingFromEnglish).toEqual(['menu.missing'])
expect(result.placeholderMismatches).toEqual(['menu.open'])
})
it('keeps plural variants and data-structure keys that extraction cannot see', () => {
const evidence = sourceEvidence("const rows = [{ labelKey: 'rows.held' }]")
const extracted = new Map([['menu.count', '']])
expect(
findUnreferencedKeys(
['menu.count_one', 'menu.count_other', 'rows.held', 'rows.dead_one', 'menu.stale'],
extracted,
evidence
)
).toEqual(['rows.dead_one', 'menu.stale'])
})
it('keeps keys under a prefix that a translate call composes at runtime', () => {
const evidence = sourceEvidence(
"translate(`status.label.${state}`)\nt('menu.item.' + id)\nconst id = `rpc.${method}`"
)
expect(
findUnreferencedKeys(
['status.label.ready', 'menu.item.open', 'rpc.ping'],
new Map(),
evidence
)
).toEqual(['rpc.ping'])
})
})
@@ -1,13 +1,4 @@
import { spawnSync } from 'node:child_process'
import {
existsSync,
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
statSync,
writeFileSync
} from 'node:fs'
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { createRequire } from 'node:module'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
@@ -16,19 +7,10 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'
const require = createRequire(new URL('../../macos-terminal-host-bundle.test.mjs', import.meta.url))
const {
assembleMacTerminalHost,
buildMacTerminalHostInfo,
daemonBareRequires,
findMacTerminalHostInfoProblems,
findUnresolvedDaemonRequires,
macTerminalHostPaths,
parseBuildVersionMinos
} = require('./macos/terminal-host-bundle/macos-terminal-host-bundle.cjs')
const electronBuilderConfig = require('../electron-builder.config.cjs')
const usageDescriptions = electronBuilderConfig.mac.extendInfo
const appInfo = { CFBundleIdentifier: 'com.stablyai.orca', CFBundleShortVersionString: '1.4.300' }
const expectations = { appId: 'com.stablyai.orca', usageDescriptions, minimumOs: '13.5' }
describe('terminal host binary checks', () => {
it('reads minos from the LC_BUILD_VERSION load command only', () => {
const otool = [
@@ -80,31 +62,6 @@ describe.skipIf(process.platform !== 'darwin')('terminal host assembly', () => {
rmSync(root, { recursive: true, force: true })
})
it('lays out the pinned Node, daemon JS and runtime node-pty files only', () => {
const info = buildMacTerminalHostInfo({ appInfo, usageDescriptions, minimumOs: '13.5' })
const paths = assembleMacTerminalHost({
appPath,
nodeExecutable: join(root, 'node'),
iconPath: join(root, 'icon.icns'),
info
})
expect(paths).toEqual(macTerminalHostPaths(appPath))
expect(paths.bundle).toBe(join(appPath, 'Contents', 'Helpers', 'Orca Terminal Host.app'))
expect(readFileSync(paths.executable, 'utf8')).toBe('pinned-node')
expect(statSync(paths.executable).mode & 0o777).toBe(0o755)
expect(statSync(paths.spawnHelper).mode & 0o777).toBe(0o755)
expect(readFileSync(paths.entry, 'utf8')).toBe('entry')
expect(existsSync(join(paths.daemon, 'out', 'main', 'chunks', 'protocol.js'))).toBe(true)
expect(readFileSync(paths.outPackageJson, 'utf8')).toBe('{"type":"commonjs"}')
expect(existsSync(join(paths.nodePty, 'lib', 'index.js'))).toBe(true)
expect(existsSync(join(paths.nodePty, 'src'))).toBe(false)
expect(readFileSync(paths.icon, 'utf8')).toBe('icon')
const plist = spawnSync('/usr/bin/plutil', ['-convert', 'json', '-o', '-', paths.infoPlist], {
encoding: 'utf8'
})
expect(findMacTerminalHostInfoProblems(JSON.parse(plist.stdout), expectations)).toEqual([])
})
it('copies every package the daemon requires, with its dependencies', () => {
const resources = join(appPath, 'Contents', 'Resources')
const main = join(resources, 'app.asar.unpacked', 'out', 'main')
@@ -180,29 +137,6 @@ describe.skipIf(process.platform !== 'darwin')('terminal host assembly', () => {
expect(findUnresolvedDaemonRequires(paths)).toEqual([])
})
it('follows directory and JSON loads and keeps nested dependencies with their parent', () => {
const resources = join(appPath, 'Contents', 'Resources')
const main = join(resources, 'app.asar.unpacked', 'out', 'main')
mkdirSync(join(main, 'lib'), { recursive: true })
writeFileSync(join(main, 'daemon-entry.js'), "require('./lib');require('./data.json')")
writeFileSync(join(main, 'lib', 'index.js'), "require('outer')")
writeFileSync(join(main, 'data.json'), '{}')
const outer = join(resources, 'node_modules', 'outer')
mkdirSync(join(outer, 'node_modules', 'inner'), { recursive: true })
writeFileSync(join(outer, 'package.json'), '{"dependencies":{"inner":"1"}}')
writeFileSync(join(outer, 'node_modules', 'inner', 'package.json'), '{}')
const paths = assembleMacTerminalHost({
appPath,
nodeExecutable: join(root, 'node'),
iconPath: join(root, 'icon.icns'),
info: {}
})
expect(daemonBareRequires(join(paths.daemon, 'out', 'main'))).toEqual(['outer'])
expect(existsSync(join(paths.daemon, 'node_modules', 'outer', 'node_modules', 'inner'))).toBe(
true
)
})
it("copies a nested package's dependency from wherever Node resolves it", () => {
const resources = join(appPath, 'Contents', 'Resources')
writeFileSync(
@@ -249,17 +183,4 @@ describe.skipIf(process.platform !== 'darwin')('terminal host assembly', () => {
})
).toThrow(/loads a module by a computed name/)
})
it('fails before writing anything when the daemon entry is missing', () => {
rmSync(join(appPath, 'Contents', 'Resources', 'app.asar.unpacked'), { recursive: true })
expect(() =>
assembleMacTerminalHost({
appPath,
nodeExecutable: join(root, 'node'),
iconPath: join(root, 'icon.icns'),
info: {}
})
).toThrow(/missing .*daemon-entry\.js/)
expect(existsSync(join(appPath, 'Contents', 'Helpers'))).toBe(false)
})
})
@@ -1,22 +1,11 @@
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
import {
MOBILE_WEB_APP_ROUTE_ROOT,
ROUTE_MODULE_SYNCHRONOUS_EXPORTS,
collectMobileWebAppRouteKeys,
collectMobileWebAppRoutes,
routeModuleSynchronousExports
collectMobileWebAppRoutes
} from './mobile-web-app-route-manifest.mjs'
import { mobileWebAppDependenciesPresent } from './mobile-web-app-bundle-dependencies.mjs'
const projectDir = fileURLToPath(new URL('../../..', import.meta.url))
const appDir = join(projectDir, 'mobile', 'app')
// Root shards omit mobile dependencies; route-tree builds run in mobile_web_app job.
const itBundling = mobileWebAppDependenciesPresent() ? it : it.skip
async function withScratch(run) {
const scratch = await mkdtemp(join(tmpdir(), 'orca-mobile-web-app-routes-test-'))
@@ -28,98 +17,6 @@ async function withScratch(run) {
}
describe('route manifest', () => {
it('carries no root layout for a tree without a web sibling of it', async () => {
await withScratch(async (scratch) => {
await mkdir(join(scratch, MOBILE_WEB_APP_ROUTE_ROOT), { recursive: true })
await writeFile(join(scratch, '_layout.tsx'), 'export default null\n', 'utf8')
await writeFile(join(scratch, MOBILE_WEB_APP_ROUTE_ROOT, 'index.tsx'), 'export default 1\n')
expect(await collectMobileWebAppRouteKeys(scratch)).toEqual(['./h/index.tsx'])
})
})
it('excludes test files and API routes', async () => {
// Synthetic tree exercises absent-today forbidden route exports.
await withScratch(async (scratch) => {
const directory = join(scratch, MOBILE_WEB_APP_ROUTE_ROOT)
await mkdir(directory, { recursive: true })
for (const name of [
'index.tsx',
'index.test.tsx',
'index.spec.tsx',
'shape.d.ts',
'+api.ts',
'tokens+api.ts',
'+middleware.ts',
'notes.md'
]) {
await writeFile(join(directory, name), 'export default null\n', 'utf8')
}
expect(await collectMobileWebAppRouteKeys(scratch)).toEqual(['./h/index.tsx'])
})
expect(await collectMobileWebAppRouteKeys(appDir)).not.toContain('./h/_layout.test.tsx')
})
// Alias/reexport controls require namespace parse, not declaration-name matching.
it('reads the names off the namespace, not off a declaration', async () => {
expect(ROUTE_MODULE_SYNCHRONOUS_EXPORTS).toEqual(['unstable_settings', 'ErrorBoundary'])
await withScratch(async (scratch) => {
const exportsOf = async (name, source) => {
const file = join(scratch, name)
await writeFile(file, source, 'utf8')
return routeModuleSynchronousExports(file)
}
expect(
(await exportsOf('declared.tsx', 'export const unstable_settings = { anchor: "x" }\n'))
.named
).toEqual(['unstable_settings'])
expect(
(
await exportsOf(
'aliased.tsx',
'const settings = { anchor: "x" }\nexport { settings as unstable_settings }\n'
)
).named
).toEqual(['unstable_settings'])
expect((await exportsOf('classy.tsx', 'export class ErrorBoundary {}\n')).named).toEqual([
'ErrorBoundary'
])
expect(
(await exportsOf('forwarded.tsx', 'export { ErrorBoundary } from "./boundary"\n')).named
).toEqual(['ErrorBoundary'])
expect(
(await exportsOf('plain.tsx', 'export default function Route() { return null }\n')).named
).toEqual([])
})
}, 60_000)
it('refuses a star re-export rather than reading it as clean', async () => {
await withScratch(async (scratch) => {
const file = join(scratch, 'star.tsx')
// Unresolved export * cannot prove namespace clean without bundling; fail closed.
await writeFile(file, 'export * from "./boundary"\nexport default null\n', 'utf8')
const { named, starExports } = await routeModuleSynchronousExports(file)
expect(named).toEqual([])
expect(starExports).toEqual(['./boundary'])
})
}, 60_000)
itBundling(
'reads a .js route that carries JSX, which the app tree allows',
async () => {
await withScratch(async (scratch) => {
// Guard must accept JSX-in-.js routes like actual RN bundler.
const file = join(scratch, 'jsx-route.js')
await writeFile(
file,
'const boundary = () => <div />\nexport { boundary as ErrorBoundary }\nexport default () => <div />\n',
'utf8'
)
expect((await routeModuleSynchronousExports(file)).named).toEqual(['ErrorBoundary'])
})
},
60_000
)
it('imports a .web.tsx sibling under the native route key', async () => {
await withScratch(async (scratch) => {
const directory = join(scratch, MOBILE_WEB_APP_ROUTE_ROOT)
@@ -1,33 +0,0 @@
import { existsSync } from 'node:fs'
import { expect, it } from 'vitest'
import {
prepareRouteSnapshot,
withRouteSnapshot
} from '../mobile-web/check-entry/run-mobile-web-app-checks.mjs'
const collect = async (entries) => ({
modules: [...entries, 'node_modules/react/index.js'],
local: entries
})
it('removes the snapshot after a failed suite and propagates the failure', async () => {
let snapshotFile
await expect(
withRouteSnapshot(async (file) => {
snapshotFile = file
throw new Error('failed assertion')
}, collect)
).rejects.toThrow('failed assertion')
expect(existsSync(snapshotFile)).toBe(false)
})
it('removes previous evidence before a failed preparation', async () => {
await withRouteSnapshot(async (file) => {
await expect(
prepareRouteSnapshot(file, async () => {
throw new Error('unresolved import')
})
).rejects.toThrow('unresolved import')
expect(existsSync(file)).toBe(false)
}, collect)
})
@@ -275,14 +275,10 @@ for (const engine of ['chromium', 'webkit']) {
}
})
// Require artifact painted before asserting hidden affordance; failed load cannot count as inert links.
expect(hidden.grants).not.toContain('externalNavigation')
expect(hidden.pixelBefore).toBe(ARTIFACT_RGB)
expect(hidden.frameCount).toBe(1)
expect(hidden.inside?.marker).toBe('ARTIFACT_RENDERED')
expect(hidden.toggles?.map((one) => one.selected)).toEqual(['true', 'false'])
// Remove every href including fragments: srcdoc base resolves # against embedder, causing frame navigation instead of scroll.
expect(hidden.links?.linked).toBe(0)
expect(hidden.links?.anchors).toBe(5)
expect(hidden.links?.text).toBe('tap')
expect(hidden.links?.decoration).toBe('none')
expect(hidden.links?.focusable).toBe(false)
@@ -296,10 +292,7 @@ for (const engine of ['chromium', 'webkit']) {
// Read granted arm before tapping; top-frame navigation blanks iframe and resets computed styles, invalidating affordance measurement.
const shown = await open(browser(), { signal: ctx.signal })
expect(shown.grants).toContain('externalNavigation')
expect(shown.pixel).toBe(ARTIFACT_RGB)
expect(shown.links?.linked).toBe(5)
expect(shown.links?.anchors).toBe(5)
expect(shown.links?.text).toBe('tap')
expect(shown.links?.decoration).toBe('underline')
expect(shown.links?.focusable).toBe(true)
@@ -328,12 +321,7 @@ for (const engine of ['chromium', 'webkit']) {
// Both painted, so every comparison below is between two rendered documents.
expect(shown.pixel).toBe(ARTIFACT_RGB)
expect(hidden.pixel).toBe(ARTIFACT_RGB)
expect(shown.grants).toContain('externalNavigation')
expect(hidden.grants).not.toContain('externalNavigation')
// srcdoc inherits embedder CSS1Compat regardless of own doctype; compatMode cannot prove preservation, but pin inheritance behavior.
expect(shown.inside?.compatMode).toBe('CSS1Compat')
expect(hidden.inside?.compatMode).toBe(shown.inside?.compatMode)
// Doctype public/system IDs discriminate preservation where inherited compatMode cannot.
expect(shown.inside?.doctypePublicId).toBe('-//W3C//DTD HTML 4.01 Transitional//EN')
expect(hidden.inside?.doctypePublicId).toBe(shown.inside?.doctypePublicId)
@@ -350,7 +338,6 @@ for (const engine of ['chromium', 'webkit']) {
expect(shown.inside?.fragmentHref).toBe('#fragtarget')
expect(hidden.inside?.fragmentHref).toBeNull()
expect(hidden.links?.linked).toBe(0)
expect(shown.links?.linked).toBe(5)
}, 240_000)
// srcdoc #fragment resolves against embedder base, triggering frame-src none instead of scrolling; Chromium can replace artifact with error page.
@@ -49,10 +49,7 @@ beforeAll(async () => {
faultGrant = await readBridgeFaultGrant()
const served = await createBundleServer({
outDir: built.outDir,
cspHeader: (request) =>
request.url.includes('oldShell=1')
? policy.replace('media-src blob:', "media-src 'none'")
: policy
cspHeader: policy
})
server = served.server
origin = served.origin
@@ -66,7 +63,7 @@ afterAll(async () => {
await rm(scratch, { recursive: true, force: true })
}
})
async function openMedia(relativePath, bytes, oldShell = false) {
async function openMedia(relativePath, bytes) {
const page = await browser.newPage({ viewport: { width: 390, height: 844 } })
const errors = []
page.on('pageerror', (error) => errors.push(error.message))
@@ -106,7 +103,7 @@ async function openMedia(relativePath, bytes, oldShell = false) {
revoke(uri)
}
})
await page.goto(`${origin}/?${oldShell ? 'oldShell=1' : ''}`)
await page.goto(`${origin}/`)
return { page, errors }
}
const describeRender = bundles ? describe : describe.skip
@@ -135,15 +132,11 @@ describeRender('mobile media under the shipped shell policy', () => {
return {
duration: media.duration,
time: media.currentTime,
controls: media.controls,
autoplay: media.autoplay,
uri: media.currentSrc
}
}, tag)
expect(playback.duration).toBeCloseTo(2, 1)
expect(playback.time).toBeGreaterThan(1)
expect(playback.controls).toBe(true)
expect(playback.autoplay).toBe(false)
await page.evaluate((pathname) => {
history.pushState(null, '', `${pathname}?relativePath=README.md`)
dispatchEvent(new PopStateEvent('popstate'))
@@ -161,11 +154,4 @@ describeRender('mobile media under the shipped shell policy', () => {
},
60_000
)
it('explains the required app update when an older shell blocks Blob playback', async () => {
const { page } = await openMedia('music.wav', wavFixture(), true)
await page
.getByText('Update Orca Mobile to play media in this workspace', { exact: true })
.waitFor()
await page.close()
}, 60_000)
})
@@ -9,14 +9,12 @@ import { mobileWebAppDependenciesPresent } from '../mobile-web-app-bundle-depend
import {
createBundleServer,
installCspViolationRecorder,
installListenerRecorder,
readShellCsp
} from '../preview/mobile-web-app-render-harness.mjs'
const mobileDir = fileURLToPath(new URL('../../../../mobile', import.meta.url))
const diagramDir = join(mobileDir, 'src/components/pr-sidebar')
// Use design fixture so recorded byte counts remain comparable.
const FIXTURE =
'graph TD\n A[Start] --> B{Choice}\n B -->|yes| C[Ship it]\n B -->|no| D[Fix it]\n D --> A'
@@ -124,44 +122,15 @@ afterAll(async () => {
}
})
// Record eval/Function stacks to attribute JIT attempts: a library may swallow EvalError under CSP.
// Playwright also evaluates harness functions, so only bundle-script callers count as page JIT.
function installJitRecorder() {
globalThis.__orcaJit = []
const record = (kind, source) => {
// Skip error header and recorder frame to identify caller.
const stack = (new Error('jit').stack ?? '').split('\n').slice(2).join(' | ')
globalThis.__orcaJit.push({ kind, source: String(source).slice(0, 60), stack })
}
// oxlint-disable-next-line eslint/no-eval -- SAFETY: the recorder holds the real eval so it can count and forward calls; naming it is this function's whole purpose.
const realEval = globalThis.eval
// oxlint-disable-next-line eslint/no-eval -- SAFETY: replacing eval with a counting wrapper is the measurement, not a call.
globalThis.eval = function (source) {
record('eval', source)
return realEval.call(globalThis, source)
}
const RealFunction = globalThis.Function
function PatchedFunction(...args) {
record('Function', args.map((one) => String(one).slice(0, 40)).join('|'))
return RealFunction.apply(this, args)
}
PatchedFunction.prototype = RealFunction.prototype
globalThis.Function = PatchedFunction
}
// Mermaid marks its drawings; the frame's expand icon is an SVG too.
function readDiagram() {
const DRAWING = 'svg[aria-roledescription]'
const frame = document.querySelector('[data-testid="mermaid-diagram"]')
const svg = frame?.querySelector(DRAWING) ?? null
return {
framed: frame !== null,
inFrame: frame ? frame.querySelectorAll(DRAWING).length : -1,
// Count SVGs across document too: Mermaid’s temporary body element can orphan diagrams outside component host.
inDocument: document.querySelectorAll(DRAWING).length,
sourceBox: document.querySelector('[data-testid="mermaid-diagram-source"]') !== null,
id: svg?.id ?? null,
html: svg?.outerHTML ?? null,
text: frame?.textContent ?? null
}
}
@@ -175,9 +144,7 @@ async function openPage(browser) {
}
})
page.on('pageerror', (error) => consoleErrors.push(`pageerror: ${error.message}`))
await page.addInitScript(installJitRecorder)
await page.addInitScript(installCspViolationRecorder)
await page.addInitScript(installListenerRecorder)
await page.goto(`${origin}/`, { waitUntil: 'domcontentloaded' })
await page.waitForFunction(() => document.body.dataset.ready === 'yes')
return { page, consoleErrors }