platform.bible-extension has no automated tests today. interlinearizer-extension (a sibling extension) has a working Playwright + Electron e2e smoke tier at e2e-tests/. Port just enough of that infrastructure to run one adapted smoke test — not the full CDP/feature tier.
Scope
Only what tests/smoke/extension-launch.spec.ts needs: fixtures/app.fixture.ts → fixtures/helpers.ts → process-utils.ts, driven by playwright.config.ts + global-setup.ts + global-teardown.ts. Skip everything CDP/feature-tier only (cdp.fixture.ts, global-setup-cdp.ts, global-teardown-cdp.ts, playwright-cdp.config.ts, tests/features/**, tests/_example/**) — none of it is a dependency of the smoke spec.
Files to add under platform.bible-extension/e2e-tests/
playwright.config.ts — copy as-is from interlinearizer-extension (already scoped to a single smoke project)
global-setup.ts, global-teardown.ts — copy, fix path depth (see below)
process-utils.ts — copy verbatim; fully generic, no interlinearizer-specific content
fixtures/app.fixture.ts — copy near-verbatim; already generic, no "Interlinearizer" references
fixtures/helpers.ts — trimmed copy. Keep: settings backup/seed, launchElectronWithExtension/teardownElectronApp, the PAPI rpc.discover polling primitives, waitForServiceHostsRegistered, waitForDockTabTitlesResolved, withFatalStartupTripwire, waitForAppReady. Drop the Interlinearizer-only helpers not reachable from the smoke spec: waitForInterlinearizerReady, openInterlinearizerFromScriptureEditor, closeSelectProjectPickers, getInterlinearizerFrame, interlinearizerTabLocator, dismissLeftoverModals.
tests/smoke/extension-launch.spec.ts — same 4 tests (window created, React root rendered, dock loads, extension PAPI commands registered), describe title and last test renamed from "Interlinearizer" to "Lexicon"
.eslintrc.json, tsconfig.json — copy verbatim (generic lint/tsconfig config, not extension-specific)
README.md is documentation-only — optional for "the test runs," cheap to include.
Adaptations required (not a straight copy)
1. Path depth. interlinearizer-extension sits directly under paranext/, so its e2e helpers reach the sibling paranext-core checkout via ../../paranext-core (from e2e-tests/) or ../../../paranext-core (from e2e-tests/fixtures/). platform.bible-extension sits one level deeper (under paranext/languageforge-lexbox/), confirmed by its own package.json ("core:start": "npm --prefix ../../paranext-core start"). Every paranext-core-pointing path needs one extra ../:
global-setup.ts / global-teardown.ts: ../../paranext-core → ../../../paranext-core
fixtures/helpers.ts (coreDir, DEV_APPDATA_SETTINGS_PATH): ../../../paranext-core → ../../../../paranext-core
- Paths pointing at the extension's own
dist (extensionRoot, extensionDist) are unaffected — same repo, same depth. Webpack outputs to dist/src/main.js for both extensions, so the dist-exists check in global-setup.ts needs no change.
2. Extension-specific readiness check. The 4th smoke test calls waitForAppAndInterlinearizerReady, which polls for command:interlinearizer.openForWebView. Replace with a lexicon-specific equivalent (e.g. waitForAppAndLexiconReady polling command:lexicon.lexicons, or another command registered in src/main.ts: lexicon.addEntry, lexicon.selectLexicon, etc.).
package.json changes
devDependencies: add @playwright/test, ws, @types/ws (versions matching interlinearizer-extension's: ^1.49.0, ^8.18.0, ^8.5.14). escape-string-regexp is already present.
scripts: add "test:e2e:smoke": "playwright test --config e2e-tests/playwright.config.ts --project=smoke". No change needed to core:start/core:stop — the e2e harness calls paranext-core's scripts directly via execSync/spawn, not through this package's own script aliases.
Open item to verify during implementation
launchFwLite() in src/main.ts is synchronous — it calls spawn() and returns a URL string immediately without awaiting FW Lite startup, and command registration proceeds regardless. That suggests task build-fw-lite is not required just to pass this smoke test (dock load + PAPI command registration shouldn't depend on FW Lite actually responding), but that should be confirmed with a real run rather than assumed — a spawn() on a missing binary could still surface as a startup-path error that hasn't been traced fully.
Drafted by Claude Sonnet 5 (claude-sonnet-5) via Claude Code.
platform.bible-extensionhas no automated tests today.interlinearizer-extension(a sibling extension) has a working Playwright + Electron e2e smoke tier ate2e-tests/. Port just enough of that infrastructure to run one adapted smoke test — not the full CDP/feature tier.Scope
Only what
tests/smoke/extension-launch.spec.tsneeds:fixtures/app.fixture.ts→fixtures/helpers.ts→process-utils.ts, driven byplaywright.config.ts+global-setup.ts+global-teardown.ts. Skip everything CDP/feature-tier only (cdp.fixture.ts,global-setup-cdp.ts,global-teardown-cdp.ts,playwright-cdp.config.ts,tests/features/**,tests/_example/**) — none of it is a dependency of the smoke spec.Files to add under
platform.bible-extension/e2e-tests/playwright.config.ts— copy as-is from interlinearizer-extension (already scoped to a singlesmokeproject)global-setup.ts,global-teardown.ts— copy, fix path depth (see below)process-utils.ts— copy verbatim; fully generic, no interlinearizer-specific contentfixtures/app.fixture.ts— copy near-verbatim; already generic, no "Interlinearizer" referencesfixtures/helpers.ts— trimmed copy. Keep: settings backup/seed,launchElectronWithExtension/teardownElectronApp, the PAPIrpc.discoverpolling primitives,waitForServiceHostsRegistered,waitForDockTabTitlesResolved,withFatalStartupTripwire,waitForAppReady. Drop the Interlinearizer-only helpers not reachable from the smoke spec:waitForInterlinearizerReady,openInterlinearizerFromScriptureEditor,closeSelectProjectPickers,getInterlinearizerFrame,interlinearizerTabLocator,dismissLeftoverModals.tests/smoke/extension-launch.spec.ts— same 4 tests (window created, React root rendered, dock loads, extension PAPI commands registered),describetitle and last test renamed from "Interlinearizer" to "Lexicon".eslintrc.json,tsconfig.json— copy verbatim (generic lint/tsconfig config, not extension-specific)README.mdis documentation-only — optional for "the test runs," cheap to include.Adaptations required (not a straight copy)
1. Path depth.
interlinearizer-extensionsits directly underparanext/, so its e2e helpers reach the siblingparanext-corecheckout via../../paranext-core(frome2e-tests/) or../../../paranext-core(frome2e-tests/fixtures/).platform.bible-extensionsits one level deeper (underparanext/languageforge-lexbox/), confirmed by its ownpackage.json("core:start": "npm --prefix ../../paranext-core start"). Everyparanext-core-pointing path needs one extra../:global-setup.ts/global-teardown.ts:../../paranext-core→../../../paranext-corefixtures/helpers.ts(coreDir,DEV_APPDATA_SETTINGS_PATH):../../../paranext-core→../../../../paranext-coredist(extensionRoot,extensionDist) are unaffected — same repo, same depth. Webpack outputs todist/src/main.jsfor both extensions, so the dist-exists check inglobal-setup.tsneeds no change.2. Extension-specific readiness check. The 4th smoke test calls
waitForAppAndInterlinearizerReady, which polls forcommand:interlinearizer.openForWebView. Replace with a lexicon-specific equivalent (e.g.waitForAppAndLexiconReadypollingcommand:lexicon.lexicons, or another command registered insrc/main.ts:lexicon.addEntry,lexicon.selectLexicon, etc.).package.jsonchangesdevDependencies: add@playwright/test,ws,@types/ws(versions matching interlinearizer-extension's:^1.49.0,^8.18.0,^8.5.14).escape-string-regexpis already present.scripts: add"test:e2e:smoke": "playwright test --config e2e-tests/playwright.config.ts --project=smoke". No change needed tocore:start/core:stop— the e2e harness calls paranext-core's scripts directly viaexecSync/spawn, not through this package's own script aliases.Open item to verify during implementation
launchFwLite()insrc/main.tsis synchronous — it callsspawn()and returns a URL string immediately without awaiting FW Lite startup, and command registration proceeds regardless. That suggeststask build-fw-liteis not required just to pass this smoke test (dock load + PAPI command registration shouldn't depend on FW Lite actually responding), but that should be confirmed with a real run rather than assumed — aspawn()on a missing binary could still surface as a startup-path error that hasn't been traced fully.Drafted by Claude Sonnet 5 (
claude-sonnet-5) via Claude Code.