Read Defuddle Markdown output from the content field

This commit is contained in:
murashit 2026-07-10 13:21:14 +09:00
parent 5f22d21dc7
commit 164c307bd1
2 changed files with 74 additions and 1 deletions

View file

@ -79,7 +79,7 @@ async function defuddleUrl(options: VaultWebClipperOptions, url: string): Promis
const result = new Defuddle(document, { url, markdown: true, useAsync: false }).parse();
return {
title: result.title,
content: result.contentMarkdown ?? result.content,
content: result.content,
site: result.site,
domain: result.domain,
};

View file

@ -0,0 +1,73 @@
// @vitest-environment jsdom
import type { Vault } from "obsidian";
import { describe, expect, it, vi } from "vitest";
import type { ComposerInputSnapshot } from "../../../../src/features/chat/application/composer/input-snapshot";
const mocks = vi.hoisted(() => ({
requestUrl: vi.fn(),
}));
vi.mock("obsidian", async (importOriginal) => {
const actual = await importOriginal<typeof import("obsidian")>();
return {
...actual,
requestUrl: mocks.requestUrl,
};
});
const { TFile } = await import("obsidian");
const { createVaultWebClipper } = await import("../../../../src/features/chat/host/obsidian/web-clipper.obsidian");
describe("vault web clipper parser integration", () => {
it("extracts article HTML with Defuddle and saves it as Markdown", async () => {
mocks.requestUrl.mockResolvedValue({
text: `<!doctype html>
<html>
<head><title>Integration Article</title></head>
<body>
<nav>Navigation that should not be clipped</nav>
<main>
<article>
<h1>Parser contract heading</h1>
<p>This readable paragraph exercises the real Defuddle full browser bundle.</p>
<p>A second paragraph makes the article content unambiguous.</p>
</article>
</main>
</body>
</html>`,
});
const { vault, createdContent } = memoryVault();
const result = await createVaultWebClipper({
vault,
settings: () => ({ clipFolder: "Clips", clipFilenameTemplate: "{{title}}.md", clipTags: "" }),
prepareInput: () => ({ text: "", input: [{ type: "text", text: "" }] }),
viewWindow: () => window,
now: () => new Date("2026-07-10T00:00:00.000Z"),
}).clipUrl("https://example.com/article", "", {} as ComposerInputSnapshot);
const markdown = createdContent.get("Clips/Integration Article.md");
expect(markdown).toContain("## Parser contract heading");
expect(markdown).toContain("This readable paragraph exercises the real Defuddle full browser bundle.");
expect(markdown).not.toContain("<article");
expect(markdown).not.toContain("Navigation that should not be clipped");
expect(result?.text).toBe("[[Clips/Integration Article.md]]");
});
});
function memoryVault(): { vault: Vault; createdContent: Map<string, string> } {
const files = new Map<string, InstanceType<typeof TFile>>();
const createdContent = new Map<string, string>();
const vault = {
getAbstractFileByPath: vi.fn((path: string) => files.get(path) ?? null),
createFolder: vi.fn().mockResolvedValue(undefined),
create: vi.fn().mockImplementation(async (path: string, content: string) => {
const File = TFile as unknown as new (path: string) => InstanceType<typeof TFile>;
files.set(path, new File(path));
createdContent.set(path, content);
}),
};
return { vault: vault as unknown as Vault, createdContent };
}