Tests, tooling and the served scripts are TypeScript (#392)
The page and the service worker were strict TypeScript; the tests, the build, the home page's generator, the load tests, boot.js and the directory's site.js were plain JavaScript that nothing checked. All of it is TypeScript now, in five programs, each with its own globals, all checked by npm run typecheck: the page (tsconfig.json, with boot.ts and the directory's site.ts), the worker, Node's (tsconfig.tools.json: the Node tests, the browser suite, the build, the site generator, the load harness), and k6's (tsconfig.k6.json, with @types/k6). Node 24 runs the .ts files by stripping their types, so they hold only TypeScript that erases (erasableSyntaxOnly) and import each other by .ts name; package.json says "type": "module" for it, and Dockerfile.web moves to Node 24 to run build.mts. k6 2.3 strips its scripts' types itself. The browser suite's page.evaluate calls reach the page's globals; the page's tsc run now also writes its declarations to target/page-types, which the suite's program includes, so those calls are typed by the page's own code rather than by hand-written copies. boot.ts is compiled by build.mts with swc, as the worker is, and named by the hash of what is served. The directory's build has no Node, so site.js is compiled from site.ts and committed (node web/build.mts --directory-script), and tests/directory-script.ts fails if they drift. Checked: the site generator's 139 pages are byte for byte what the JavaScript made; the page build's app.js is identical and only boot.js (now minified) and its hash differ; contrast, page-smoke, page-unit, native-bridge, the browser suite (96 passed, 2 skipped) and the directory's and ipx's Rust tests pass; k6 parses each load script. The load tests themselves did not run: they build a release binary outside the capped builder. .agents/skills/security-audit is an installed skill's, not ours, and is left as it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
91
tests/ui/global-setup.ts
Normal file
91
tests/ui/global-setup.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
// Builds a scratch config and data dir so the browser tests drive a real daemon with
|
||||
// known feeds, rather than whatever happens to be on the machine.
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import crypto from 'node:crypto';
|
||||
|
||||
const root = path.join(os.tmpdir(), 'ipx-ui-test');
|
||||
const TOKEN = 'testtokentesttokentesttoken12345'; // fixed, so tests need not scrape a log
|
||||
// The suite's own directory service (#205), and this daemon's token for it, which may do anything.
|
||||
const DIRECTORY = 'http://127.0.0.1:8795';
|
||||
const DIRECTORY_TOKEN = 'ipxd_testdirectorytoken';
|
||||
|
||||
// Called from playwright.config.ts at load time, NOT as globalSetup: Playwright starts
|
||||
// webServer *before* globalSetup, so a config written there does not exist yet when the
|
||||
// daemon launches -- it would fall back to the real config and fight the live daemon.
|
||||
// Playwright imports this config again in every worker process, so prepare() runs more
|
||||
// than once per suite. Wiping on the second call deleted the data directory out from under
|
||||
// the running daemon: it kept serving from the unlinked inode, while anything else opening
|
||||
// that path -- the CLI, a query -- got a brand new empty database and disagreed with it.
|
||||
function prepare() {
|
||||
// Only the process that launches the run may wipe. A worker gets TEST_WORKER_INDEX.
|
||||
if (process.env.TEST_WORKER_INDEX !== undefined || process.env.PW_WORKER_INDEX !== undefined) {
|
||||
return;
|
||||
}
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
for (const d of ['config', 'data', 'downloads']) {
|
||||
fs.mkdirSync(path.join(root, d), { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(path.join(root, 'config', 'config.toml'), `
|
||||
[general]
|
||||
download_dir = "${path.join(root, 'downloads')}"
|
||||
socket = "${path.join(root, 'ipx.sock')}"
|
||||
schedule = "every 60m"
|
||||
max_new_per_check = 1
|
||||
# The fixture feeds are on loopback, which ipx refuses otherwise (#320).
|
||||
fetch_internal = ["127.0.0.1"]
|
||||
directory_url = "${DIRECTORY}"
|
||||
directory_token = "${DIRECTORY_TOKEN}"
|
||||
directory_share = true
|
||||
|
||||
[torrent]
|
||||
enabled = false
|
||||
|
||||
[web]
|
||||
enabled = true
|
||||
# Behind Caddy, which serves the pages on 8791 and passes the API here (#203).
|
||||
bind = "127.0.0.1:8796"
|
||||
token = "${TOKEN}"
|
||||
# The proxy path, for tests that send the header themselves: the daemon sees them at 127.0.0.1.
|
||||
trusted_header = "X-Test-User"
|
||||
trusted_proxies = ["127.0.0.1"]
|
||||
sign_out_url = "/signed-out-by-the-proxy"
|
||||
|
||||
[feeds.test-show]
|
||||
url = "http://127.0.0.1:8792/show.xml"
|
||||
auto_download = true
|
||||
|
||||
# Downloads its image, so the UI has a file that is not playable to deal with.
|
||||
[feeds.picture-blog]
|
||||
url = "http://127.0.0.1:8792/pics.xml"
|
||||
auto_download = true
|
||||
media_types = ["image"]
|
||||
|
||||
[feeds.multi-show]
|
||||
url = "http://127.0.0.1:8792/multi.xml"
|
||||
auto_download = true
|
||||
|
||||
[feeds.test-subscriptions]
|
||||
url = "http://127.0.0.1:8792/subs.opml"
|
||||
auto_download = false
|
||||
|
||||
# A key in its URL, like a Patreon feed: someone's paid subscription, never offered to others.
|
||||
[feeds.paid-show]
|
||||
url = "http://127.0.0.1:8792/paid.xml?auth=secret123"
|
||||
auto_download = false
|
||||
`);
|
||||
fs.writeFileSync(path.join(root, 'directory.toml'), `
|
||||
bind = "127.0.0.1:8795"
|
||||
database_url_env = "DIRECTORY_DATABASE_URL"
|
||||
# The fixture feeds are on loopback, which the refresher refuses otherwise (#329).
|
||||
fetch_internal = ["127.0.0.1"]
|
||||
|
||||
[[tokens]]
|
||||
name = "test"
|
||||
access = "rwa"
|
||||
token_sha256 = "${crypto.createHash('sha256').update(DIRECTORY_TOKEN).digest('hex')}"
|
||||
`);
|
||||
}
|
||||
|
||||
export { prepare, root, TOKEN, DIRECTORY, DIRECTORY_TOKEN };
|
||||
Reference in New Issue
Block a user