Skip to content

test(e2e): pin high-risk podcast journeys in Obsidian - #384

Merged
chhoumann merged 1 commit into
masterfrom
test/journey-e2e
Oct 11, 2026
Merged

chhoumann merged 1 commit into
masterfrom
test/journey-e2e

Conversation

@chhoumann

@chhoumann chhoumann commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

Add 18 real-Obsidian tests that cover all 15 highest-risk R5 journeys before the v3 rewrite. They exercise feed import, real playback, restart, Resume and timestamp links, local audio, offline downloads, transcription, sync conflicts, and mobile startup.

Five tests accept only the reproduced bug signatures in #357, #358, #375, #377, and #378. Other failures stay hard failures. A fixed bug makes its test request removal of the marker.

The harness restores cache, data, workspace files, recent-file history, mobile mode, and enabled plugins while it holds the vault lock. A temporary test plugin captures errors before PodNotes initializes. Runtime checks also cover the 21 baseline E2E tests.

Verification

  • npm run test:e2e passed three consecutive full runs, each with 39 tests. Complete command wall times are 91.64, 88.49, and 92.09 seconds.
  • npm run lint, npm run format:check, npm run typecheck, npm run build, npm run test, and npm run docs:build passed. The unit/component suite passed 1,263 tests in 81 files.
  • Obsidian 1.13.7 on headless Linux, isolated vault. Real RSS and range-capable WAV fixtures use http://127.0.0.1.nip.io:<port>. iTunes and OpenAI responses are stubbed only at the network boundary with a fake transcription secret. Source mutations proved one defect per new test file, plus startup-error detection. Workspace rollback passed after the save delay and another ordinary save.

Journey table and full QA report. Proof logs, mutations, probes, and independent reviews.

Historical real-media fixture playback

Mobile uses desktop emulation. The macOS restart branch has static review only. Earlier mutation experiments and the fixture screenshot are identified as historical evidence in the report.

Follow-ups

#380 tracks recorder recovery after interruption. #382 tracks late runtime errors cleared by final suite restoration. #383 tracks future Notice wording changes. Error-report cascades, macOS relaunch logging, shared-runner relaunch reuse, lifecycle imports, and Vitest stack hook ordering remain follow-ups. The sparse fixture drops an item without both title and description because it violates RSS 2.0.

Release impact

None. The change touches only tests/e2e. No product, dependency, schema, API, URI, or CI change.

Refs #357, #358, #375, #377, #378, #380, #382, #383.

Note

Add end-to-end journey test suite covering PodNotes feeds, playback, links, and resilience

Macroscope summarized 501663c.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying podnotes with  Cloudflare Pages  Cloudflare Pages

Latest commit: 501663c
Status: ✅  Deploy successful!
Preview URL: https://ec1fa5fa.podnotes.pages.dev
Branch Preview URL: https://test-journey-e2e.podnotes.pages.dev

View logs

Comment thread tests/e2e/harness.ts
await library.restoreJourneyWorkspace(suiteClient);
if (!wasEnabled) {
await suiteClient.dev.evalJsonAsync(
`(async () => { await app.plugins.disablePluginAndSave(${JSON.stringify(PLUGIN_ID)}); await app.plugins.saveConfig(); return true; })()`,

function byCss(name: string, selector: string, text?: string): UiTarget {
const filter =
text === undefined ? "" : `.filter((el) => el.textContent.trim() === ${q(text)})`;
playerTab: byCss("Player tab", `${PLAYER_VIEW} button[aria-label="Player"]`),
podcastCard: (title: string): UiTarget => ({
name: `podcast card ${title}`,
elements: `[...document.querySelectorAll(${q(`${PLAYER_VIEW} .podcast-grid button`)})].filter((button) => (button.getAttribute("aria-label") ?? button.querySelector("img")?.alt ?? button.textContent.trim()) === ${q(title)})`,
),
episode: (title: string): UiTarget => ({
name: `episode ${title}`,
elements: `[...document.querySelectorAll(${q(`${PLAYER_VIEW} .podcast-episode-item`)})].filter((el) => !el.closest(".episode-player") && el.querySelector(".episode-item-title")?.textContent.trim() === ${q(title)})`,
),
menuItem: (title: string): UiTarget => ({
name: `menu item ${title}`,
elements: `[...document.querySelectorAll(".menu .menu-item")].filter((el) => el.querySelector(".menu-item-title")?.textContent.trim() === ${q(title)})`,
byCss(`settings tab ${name}`, ".modal.mod-settings .vertical-tab-nav-item", name),
settingControl: (settingName: string, control: string): UiTarget => ({
name: `${control} of setting ${settingName}`,
elements: `[...document.querySelectorAll(".modal.mod-settings .setting-item")].filter((row) => row.querySelector(".setting-item-name")?.textContent.trim() === ${q(settingName)}).map((row) => row.querySelector(${q(control)})).filter(Boolean)`,
byCss(`settings tab ${name}`, ".modal.mod-settings .vertical-tab-nav-item", name),
settingControl: (settingName: string, control: string): UiTarget => ({
name: `${control} of setting ${settingName}`,
elements: `[...document.querySelectorAll(".modal.mod-settings .setting-item")].filter((row) => row.querySelector(".setting-item-name")?.textContent.trim() === ${q(settingName)}).map((row) => row.querySelector(${q(control)})).filter(Boolean)`,
@chhoumann
chhoumann merged commit 0d82581 into master Oct 11, 2026
12 checks passed
@chhoumann
chhoumann deleted the test/journey-e2e branch October 11, 2026 04:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants