From 481c80bea9a8a8e51493999fcb8fda2cf415a9c4 Mon Sep 17 00:00:00 2001 From: Gabriel Cozma Date: Tue, 18 Aug 2026 12:39:41 +0300 Subject: [PATCH 1/2] feat: add tests for sitemap and feed generation with root/index page handling --- test.ts | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/test.ts b/test.ts index 4eb828d..c1b4796 100644 --- a/test.ts +++ b/test.ts @@ -111,6 +111,132 @@ Deno.test({ }, }); +Deno.test({ + name: + "seo: includes root/index pages in the sitemap but excludes them from RSS/Atom, and sorts by date descending", + fn: async () => { + const plugin = seoPlugin({ siteUrl: "https://myblog.com/" }); + + const writtenFiles: Record = {}; + const originalWriteTextFile = Deno.writeTextFile; + + Deno.writeTextFile = ( + path: string | URL, + data: string | ReadableStream, + ): Promise => { + writtenFiles[String(path)] = typeof data === "string" ? data : "[Stream]"; + return Promise.resolve(); + }; + + try { + const mockConfig = { + output: "dist", + title: "Test Blog", + description: "Test description", + author: "Tester", + pages: [ + { + slug: "", + title: "Home", + description: "Homepage", + date: "2026-01-01T00:00:00Z", + }, + { + slug: "index.html", + title: "Index", + description: "Index page", + date: "2026-01-02T00:00:00Z", + }, + { + slug: "posts/older-post", + title: "Older Post", + description: "An older post", + date: "2026-01-01T00:00:00Z", + }, + { + slug: "posts/newer-post", + title: "Newer Post", + description: "A newer post", + date: "2026-02-01T00:00:00Z", + }, + ], + }; + + await plugin.afterBuild!(mockConfig); + + const sitemap = writtenFiles["dist/sitemap.xml"]; + const rss = writtenFiles["dist/feed.xml"]; + const atom = writtenFiles["dist/atom.xml"]; + + // Root and index.html pages appear in the sitemap... + assertStringIncludes(sitemap, "https://myblog.com/"); + assertStringIncludes(sitemap, "https://myblog.com/index.html"); + + // ...but are excluded from RSS/Atom item lists. + assert( + !rss.includes("Home") && + !rss.includes("Index"), + "root/index pages should not appear as RSS items", + ); + assert( + !atom.includes("Home") && + !atom.includes("Index"), + "root/index pages should not appear as Atom items", + ); + + // Non-root pages are included, ordered newest-first. + const rssNewerIdx = rss.indexOf("Newer Post"); + const rssOlderIdx = rss.indexOf("Older Post"); + assert(rssNewerIdx !== -1 && rssOlderIdx !== -1); + assert( + rssNewerIdx < rssOlderIdx, + "expected newer post to appear before older post in RSS feed", + ); + } finally { + Deno.writeTextFile = originalWriteTextFile; + } + }, +}); + +Deno.test({ + name: "seo: defaults pages to [] and output to 'dist' when omitted", + fn: async () => { + const plugin = seoPlugin({ siteUrl: "https://myblog.com/" }); + + const writtenFiles: Record = {}; + const originalWriteTextFile = Deno.writeTextFile; + + Deno.writeTextFile = ( + path: string | URL, + data: string | ReadableStream, + ): Promise => { + writtenFiles[String(path)] = typeof data === "string" ? data : "[Stream]"; + return Promise.resolve(); + }; + + try { + // Neither `pages` nor `output` provided. + const mockConfig = { + title: "Test Blog", + description: "Test description", + author: "Tester", + }; + + await plugin.afterBuild!(mockConfig); + + assert(writtenFiles["dist/sitemap.xml"] !== undefined); + assert(writtenFiles["dist/feed.xml"] !== undefined); + assert(writtenFiles["dist/atom.xml"] !== undefined); + assertStringIncludes( + writtenFiles["dist/sitemap.xml"], + '\n', + ); + } finally { + Deno.writeTextFile = originalWriteTextFile; + } + }, +}); + Deno.test({ name: "seo: generates a default robots.txt allowing all crawling", fn: async () => { From 594751ff56816de2a9d2399e0e67f3e06ef7699b Mon Sep 17 00:00:00 2001 From: Gabriel Cozma Date: Tue, 18 Aug 2026 12:39:59 +0300 Subject: [PATCH 2/2] chore: bump to 1.0.0 --- deno.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deno.json b/deno.json index 0fe6a1a..6a394de 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@steno/plugin-seo", - "version": "0.7.3", + "version": "1.0.0", "exports": "./mod.ts", "imports": { "steno": "jsr:@steno/steno@^0.12.0",