Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/main.activateView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,8 +650,10 @@ describe("PodNotes onload wiring (#55)", () => {
vi.spyOn(HTMLMediaElement.prototype, "pause").mockImplementation(() => {});
const { plugin } = await loadPlugin(savedData);
plugin.api.start();
// jsdom loads no media; the browser would hold its metadata by now.
// jsdom loads no media and play() is stubbed; the browser would hold its metadata
// and be playing by now.
Object.defineProperty(media(), "readyState", { value: HTMLMediaElement.HAVE_METADATA });
Object.defineProperty(media(), "paused", { value: false });
media().dispatchEvent(new Event("loadedmetadata"));
media().currentTime = 1300;

Expand Down
88 changes: 87 additions & 1 deletion src/main.persistence.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @vitest-environment jsdom
import { get } from "svelte/store";
import { afterEach, describe, expect, it, vi } from "vitest";
import { afterEach, describe, expect, it, onTestFinished, vi } from "vitest";
import { Notice, type SecretStorage } from "obsidian";
import * as obsidian from "obsidian";
import { DEFAULT_SETTINGS } from "./constants";
Expand Down Expand Up @@ -870,6 +870,92 @@ describe("PodNotes persistence integration", () => {
});
});

describe("while the loaded episode is paused at 17 s", () => {
async function paused() {
const plugin = makePlugin();
const episode = {
title: "A",
streamUrl: "https://pod.example.com/a.mp3",
url: "",
description: "",
content: "",
podcastName: "Pod",
};
let disk: unknown = JSON.parse(JSON.stringify(encodePodNotesData(plugin.settings)));
Object.assign(plugin, {
loadData: vi.fn(async () => structuredClone(disk)),
saveData: vi.fn(async (next: unknown) => {
disk = JSON.parse(JSON.stringify(next));
}),
});
Object.assign(plugin.app.vault.adapter, {
read: vi.fn(async () => dataFileText(disk)),
});
attachDataFileWriter(plugin);
(plugin as unknown as { setCollectionStores(): void }).setCollectionStores();
onTestFinished(bindStoresToSettings(plugin));
const doc = new FakeDocument();
plugin.player = new PlayerController(doc.asPlayerDocument(), plugin);
onTestFinished(() => plugin.player.dispose());
plugin.player.play(episode);
doc.media.duration = 3600;
doc.media.emit("loadedmetadata");
doc.media.currentTime = 17;
plugin.player.pause();
await plugin.flushSaves();
const saved = () =>
(disk as { playedEpisodes: Record<string, { time: number; finished: boolean }> })
.playedEpisodes["Pod::A"];
expect(saved()).toMatchObject({ time: 17, finished: false });
return {
plugin,
doc,
saved,
sync: async (time: number) => {
saved().time = time;
await plugin.onExternalSettingsChange();
},
};
}

it("shows the progress a sync brings and keeps it in data.json through a save", async () => {
const { plugin, doc, saved, sync } = await paused();

await sync(45);
plugin.player.save();
await plugin.flushSaves();

expect(saved()).toMatchObject({ time: 45, finished: false });
expect(get(plugin.player.state)).toMatchObject({ status: "paused", currentTime: 45 });
expect(doc.media.currentTime).toBe(45);
});

it("saves a seek made after the sync", async () => {
const { plugin, doc, saved, sync } = await paused();

await sync(45);
plugin.player.seek(25);
plugin.player.save();
await plugin.flushSaves();

expect(saved()).toMatchObject({ time: 25, finished: false });
expect(doc.media.currentTime).toBe(25);
});

it("saves a seek from the browser's own controls made after the sync", async () => {
const { plugin, doc, saved, sync } = await paused();

await sync(45);
doc.media.currentTime = 42;
for (const type of ["seeking", "timeupdate", "seeked"]) doc.media.emit(type);
plugin.player.save();
await plugin.flushSaves();

expect(saved()).toMatchObject({ time: 42, finished: false });
expect(get(plugin.player.state)).toMatchObject({ status: "paused", currentTime: 42 });
});
});

describe("once a data.json it could not read at startup becomes readable", () => {
async function startUnreadable(saveData: (data: unknown) => Promise<void>) {
const plugin = makePlugin(saveData, { dataFileExists: true });
Expand Down
2 changes: 0 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -616,8 +616,6 @@ export default class PodNotes extends Plugin implements IPodNotes {
Object.assign(settings, decoded.settings);
this.persistenceUnknownFields = decoded.unknownFields;
this.setCollectionStores();
// A sync can land after startup, before anything loads. The restored episode
// follows it, and loaded media stays as it is.
this.player?.restore(this.settings.currentEpisode);
}

Expand Down
Loading
Loading