Files
orca/mobile/scripts/build-terminal-document-script.test.ts
T

85 lines
3.3 KiB
TypeScript

import { mkdtemp, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { emitTerminalDocumentModule } from './build-terminal-document-script.mjs'
import { terminalBackgroundFallback } from '../src/terminal/document/document-constants'
/**
* What the generator drops, what it keeps, and how it puts a module back into the document.
*
* The per-group tests compare a real module against the string the document carries, which says
* the two agree; these say why, on inputs small enough to read. The import and export cases are
* the ones that bit: esbuild wraps a long list across lines, and skipping only the first line
* leaves the rest of the names loose in the document.
*/
let directory: string
async function emit(source: string): Promise<string> {
const path = join(directory, `module-${Math.random().toString(36).slice(2)}.ts`)
await writeFile(path, source)
return emitTerminalDocumentModule(path)
}
beforeAll(async () => {
directory = await mkdtemp(join(tmpdir(), 'orca-terminal-document-'))
})
afterAll(async () => {
await rm(directory, { recursive: true, force: true })
})
describe('emitting one terminal document module', () => {
it('unmarks an export and indents it into the document scope', async () => {
expect(await emit('export function f() {\n return 1\n}\n')).toBe(
' function f() {\n return 1;\n }'
)
})
it('drops an import that fits on one line', async () => {
expect(await emit("import { a } from './x'\nexport const b = 1\n")).toBe(' const b = 1;')
})
it('drops an import esbuild wrapped across lines', async () => {
// The case that produced an unparseable document: the names after the first line stayed.
const source =
"import { alpha, beta, gamma, delta, epsilon, zeta, eta, theta } from './document-externals'\n" +
'export const b = alpha\n'
expect(await emit(source)).toBe(' const b = alpha;')
})
it('drops the trailing export block esbuild prints, not just its keyword', async () => {
// Left behind it is a bare block statement, which parses and does nothing.
const emitted = await emit('function f() {}\nfunction g() {}\nexport { f, g }\n')
expect(emitted).not.toContain('{ f, g }')
expect(emitted).toBe(' function f() {\n }\n function g() {\n }')
})
it('erases types without touching the program', async () => {
expect(
await emit(
'export type T = { a: number }\nexport function f(v: T): number {\n return v.a\n}\n'
)
).toBe(' function f(v) {\n return v.a;\n }')
})
it('substitutes a build-time constant the document carries as a literal', async () => {
const emitted = await emit(
"import { terminalBackgroundFallback } from '../src/terminal/document/document-constants'\n" +
'export function paint() {\n' +
' return terminalBackgroundFallback\n' +
'}\n'
)
expect(emitted).toContain(JSON.stringify(terminalBackgroundFallback))
expect(emitted).not.toContain('terminalBackgroundFallback')
})
it('drops a lint directive rather than let it parenthesise the expression it guards', async () => {
expect(
await emit(
'export const R =\n' + ' // oxlint-disable-next-line no-useless-escape\n' + ' /a/g\n'
)
).toBe(' const R = /a/g;')
})
})