/**
* The browser pane's two text inputs, read the way C4.2's census reads them.
*
* The pane is not in any page route today, so no route closure reaches it and the census that
* enforces the seam is not run against it: it walks the source-control hub and the review route,
* and the pane is in neither. C6 raises both inputs anyway, because the failure is not cosmetic —
* an input under 16px makes an iOS browser zoom the page on focus, and `keyboard-occlusion.web.ts`
* reads a visual viewport scale other than 1 as "no keyboard" for the rest of the typing session.
*
* This file is the census run by hand over the pane's own modules, so the raise is checked by the
* rule that will judge it once a route lists the pane.
*/
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
import {
modulesDeclaringTextInput,
textInputFontSizeOffenders,
unresolvedTextInputStyles
} from './mobile-web-app-text-input-font-size-seam.mjs'
const mobileDir = join(fileURLToPath(new URL('../..', import.meta.url)), 'mobile')
/**
* The pane's text-input modules, named as the bundler resolves them: a `.web.ts` where one exists,
* which is what `mobileWebAppRouteClosure` reports for a real route.
*/
const PANE_CLOSURE = {
local: [
'src/browser/MobileBrowserPaneView.tsx',
'src/browser/MobileBrowserAddressField.tsx',
'src/browser/mobile-browser-pane-styles.ts',
'src/browser/browser-address-field-styles.web.ts',
'src/platform/text-input-font-size.web.ts'
]
}
const KEY_ROW_STYLES = 'src/browser/mobile-browser-pane-styles.ts'
/** The modules in `PANE_CLOSURE` that render an input, which is what the rule below judges. */
const PANE_INPUT_MODULES = [
'src/browser/MobileBrowserAddressField.tsx',
'src/browser/MobileBrowserPaneView.tsx'
]
function offendingFiles() {
return textInputFontSizeOffenders(mobileDir, PANE_CLOSURE).map((entry) =>
entry.slice(0, entry.lastIndexOf(':'))
)
}
describe('the browser pane text inputs under the C4.2 census', () => {
/**
* The precondition the rest of this file rests on.
*
* `PANE_CLOSURE` is written by hand, because the pane is in no page route and there is no
* closure to derive it from. So "no unresolved styles" says the walk read the files listed, not
* that those files are the pane's inputs — a third input module added under `src/browser/` would
* leave every assertion below green and unchecked. This scans for it instead.
*/
it('lists every module under src/browser that renders an input', () => {
expect(modulesDeclaringTextInput(mobileDir, 'src/browser')).toEqual(PANE_INPUT_MODULES)
expect(PANE_CLOSURE.local).toEqual(expect.arrayContaining(PANE_INPUT_MODULES))
})
it('reads every input the pane declares, so the verdicts below are complete', () => {
// The completeness half: an empty offender list means nothing if the walk found no input.
expect(unresolvedTextInputStyles(mobileDir, PANE_CLOSURE)).toEqual([])
expect(PANE_CLOSURE.local).toContain('src/platform/text-input-font-size.web.ts')
})
// A scan that happens to find two things is not a scan that would find a third. Planted in a
// scratch tree rather than in src/browser, so no other census ever walks the plant.
it('would report a third input module, and ignores tests and non-JSX mentions', () => {
const scratch = mkdtempSync(join(tmpdir(), 'orca-browser-pane-inputs-'))
try {
mkdirSync(join(scratch, 'src/browser'), { recursive: true })
for (const [name, source] of Object.entries({
'Planted.tsx': 'export const P = () => ',
'Planted.test.tsx': 'it("x", () => )',
'mentions-only.ts': "import { TextInput } from 'react-native' // TextInput, named twice"
})) {
writeFileSync(join(scratch, 'src/browser', name), source)
}
expect(modulesDeclaringTextInput(scratch, 'src/browser')).toEqual(['src/browser/Planted.tsx'])
} finally {
rmSync(scratch, { recursive: true, force: true })
}
})
it('takes the key row input through the seam', () => {
expect(offendingFiles()).not.toContain(KEY_ROW_STYLES)
})
/**
* The address field is split, and the split is what the census now reads.
*
* Native keeps the 12px the toolbar has always rendered, because no phone has a page to zoom;
* the browser gets the seam. `resolveLocal` follows the `.web.ts` the builder would have
* resolved, so the size judged here is the size the page runs rather than the one it does not.
*/
it('takes the address field through the seam, through its .web sibling', () => {
expect(offendingFiles()).toEqual([])
})
})