diff --git a/package.json b/package.json index 57d3fa2d..1cff6256 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "test:e2e:obsidian:discover": "tsx test/e2e-obsidian/scripts/discover.ts", "test:e2e:obsidian:cli-help": "tsx test/e2e-obsidian/scripts/cli-help.ts", "test:e2e:obsidian:debug-ui": "tsx test/e2e-obsidian/scripts/debug-ui.ts", + "test:e2e:obsidian:focused": "tsx test/e2e-obsidian/scripts/run-focused.ts", "test:e2e:obsidian:smoke": "tsx test/e2e-obsidian/scripts/smoke.ts", "test:e2e:obsidian:onboarding-invitation": "tsx test/e2e-obsidian/scripts/onboarding-invitation.ts", "test:e2e:obsidian:dialog-mounts": "tsx test/e2e-obsidian/scripts/dialog-mounts.ts", diff --git a/test/e2e-obsidian/README.md b/test/e2e-obsidian/README.md index 82d0c23d..56daa68b 100644 --- a/test/e2e-obsidian/README.md +++ b/test/e2e-obsidian/README.md @@ -50,6 +50,17 @@ These tests are intended for local verification, not the default CI gate. Reuse ## Commands +After changing plug-in source, use the focused wrapper rather than invoking a scenario directly. It always rebuilds `main.js` before launching real Obsidian, and it builds the local CLI too when the CLI-to-Obsidian scenario needs it: + +```bash +npm run test:e2e:obsidian:focused -- settings-ui +npm run test:e2e:obsidian:focused -- two-vault-sync +``` + +The wrapper accepts only maintained real-Obsidian scenario names; run it with `--help` for the current list. It deliberately does not manage CouchDB or Object Storage. Start the required fixtures first, or use the complete service-managed suite. + +The principal entry points are: + ```bash npm run test:contract:contexts npm run test:contract:context:webapp @@ -59,26 +70,12 @@ npm run test:e2e:obsidian:runner npm run test:e2e:obsidian:install-appimage npm run test:e2e:obsidian:discover npm run test:e2e:obsidian:cli-help -- vaults verbose -npm run test:e2e:obsidian:smoke -npm run test:e2e:obsidian:onboarding-invitation -npm run test:e2e:obsidian:dialog-mounts -npm run test:e2e:obsidian:settings-ui -npm run test:e2e:obsidian:review-harness -npm run test:e2e:obsidian:p2p-pane -npm run test:e2e:obsidian:vault-reflection -npm run test:e2e:obsidian:couchdb-upload -npm run test:e2e:obsidian:cli-to-obsidian-sync -npm run test:e2e:obsidian:minio-upload -npm run test:e2e:obsidian:startup-scan -npm run test:e2e:obsidian:setup-uri-workflow -npm run test:e2e:obsidian:two-vault-sync -npm run test:e2e:obsidian:hidden-file-snippet-sync -npm run test:e2e:obsidian:customisation-sync -npm run test:e2e:obsidian:setting-markdown-export npm run test:e2e:obsidian:local-suite npm run test:e2e:obsidian:local-suite:services ``` +The underlying `test:e2e:obsidian:` scripts remain available for an immediate rerun against an already built, unchanged bundle. They do not build `main.js`; do not use them as the first verification after a source change. The complete local suite performs its own build. + `test:contract:contexts` runs the directly observable host contract against the Obsidian, CLI, and Webapp compositions. It verifies event and translation results, host-specific capabilities, and that the CLI and Webapp Service Hubs pass one exact Context to all exposed services. `test:contract:context:webapp` runs only the Webapp part. `test:contract:context:cli` builds the Node CLI and runs its existing Deno setup, put, read, list, information, remove, conflict-resolution, and revision workflow. `test:contract:context:obsidian` builds the plug-in and runs the real-Obsidian smoke test, including the Context inspection. These runtime scripts are local validation entry points and are not added to the default CI gate by this change. diff --git a/test/e2e-obsidian/scripts/run-focused.ts b/test/e2e-obsidian/scripts/run-focused.ts new file mode 100644 index 00000000..d3d9d10d --- /dev/null +++ b/test/e2e-obsidian/scripts/run-focused.ts @@ -0,0 +1,82 @@ +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +// Keep the public wrapper deliberately narrower than package.json. Discovery, +// installation, runner contracts, and the complete suite have different setup +// requirements and remain separate entry points. +const focusedScenarios = new Set([ + "smoke", + "onboarding-invitation", + "dialog-mounts", + "settings-ui", + "review-harness", + "p2p-pane", + "vault-reflection", + "couchdb-upload", + "cli-to-obsidian-sync", + "minio-upload", + "startup-scan", + "setup-uri-workflow", + "two-vault-sync", + "hidden-file-snippet-sync", + "customisation-sync", + "setting-markdown-export", +]); + +function usage(): string { + return `Usage: npm run test:e2e:obsidian:focused -- [scenario arguments] + +Builds the current Self-hosted LiveSync plug-in before running one maintained +real-Obsidian scenario. Supported scenarios: + +${[...focusedScenarios].map((scenario) => ` ${scenario}`).join("\n")} + +This wrapper does not start CouchDB or Object Storage. Use the documented +service commands or the complete local-suite:services wrapper when required.`; +} + +// npm receives each argument directly. In particular, environment values and +// scenario arguments never pass through a shell for re-interpretation. +function runNpm(args: string[]): void { + const npm = process.platform === "win32" ? "npm.cmd" : "npm"; + const result = spawnSync(npm, args, { + cwd: fileURLToPath(new URL("../../..", import.meta.url)), + stdio: "inherit", + }); + if (result.error) throw result.error; + if (result.status !== 0) { + throw new Error(`npm ${args.join(" ")} failed with exit code ${result.status ?? "unknown"}.`); + } +} + +function main(): void { + const [scenario, ...scenarioArguments] = process.argv.slice(2); + if (!scenario || scenario === "-h" || scenario === "--help") { + process.stdout.write(`${usage()}\n`); + return; + } + if (!focusedScenarios.has(scenario)) { + throw new Error(`Unsupported focused real-Obsidian scenario: ${scenario}\n\n${usage()}`); + } + + // Individual scenario scripts intentionally remain fast, raw entry points. + // The wrapper owns the freshness guarantee which was previously easy to + // miss after changing TypeScript source. + runNpm(["run", "build"]); + + // The compatibility scenario defaults to the repository CLI. Build it only + // when the caller has not selected an external CLI distribution. + if (scenario === "cli-to-obsidian-sync" && !process.env.LIVESYNC_CLI_COMMAND) { + runNpm(["run", "build", "--workspace", "self-hosted-livesync-cli"]); + } + + const script = `test:e2e:obsidian:${scenario}`; + runNpm(["run", script, ...(scenarioArguments.length > 0 ? ["--", ...scenarioArguments] : [])]); +} + +try { + main(); +} catch (error) { + console.error(error instanceof Error ? error.message : error); + process.exitCode = 1; +}