feat: release meme protocol v1.1.0
Add one-click meme copying, complete viewer actions, fixed-footer pagination, protocol lore, and the Homo Reseticus download chooser. Install dedicated social and favicon assets, expand local demo data, and synchronize the changelog, documentation, package, and OpenAPI release metadata.
This commit is contained in:
+50
-1
@@ -1,6 +1,7 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { feedJson, renderIndex, sitemapXml } from '../src/seo.js';
|
||||
import fs from 'node:fs';
|
||||
import { feedJson, manifest, renderIndex, sitemapXml } from '../src/seo.js';
|
||||
|
||||
const id = 'a'.repeat(64);
|
||||
const meme = {
|
||||
@@ -8,6 +9,7 @@ const meme = {
|
||||
createdAt: '2026-07-24T12:00:00.000Z',
|
||||
width: 1200,
|
||||
height: 900,
|
||||
mime: 'image/webp',
|
||||
moderationScore: 92
|
||||
};
|
||||
const template = [
|
||||
@@ -34,10 +36,57 @@ test('renders a meme permalink with meme-specific share metadata', () => {
|
||||
assert.match(html, /nonce="test-nonce"/);
|
||||
});
|
||||
|
||||
test('renders the homepage with the dedicated social preview image', () => {
|
||||
const html = renderIndex({
|
||||
template,
|
||||
baseUrl: 'https://memes.example',
|
||||
nonce: 'home-nonce',
|
||||
approvedCount: 12
|
||||
});
|
||||
|
||||
assert.match(html, /og:image" content="https:\/\/memes\.example\/assets\/social-preview-v1\.png"/);
|
||||
assert.doesNotMatch(html, /yoonect-logo\.png/);
|
||||
});
|
||||
|
||||
test('uses the supplied favicon suite in the page and web app manifest', () => {
|
||||
const index = fs.readFileSync(new URL('../public/index.html', import.meta.url), 'utf8');
|
||||
const appManifest = manifest('https://memes.example');
|
||||
|
||||
assert.match(index, /\/assets\/favicon\/favicon\.svg\?v=20260814/);
|
||||
assert.match(index, /\/assets\/favicon\/favicon-96x96\.png\?v=20260814/);
|
||||
assert.match(index, /\/favicon\.ico\?v=20260814/);
|
||||
assert.match(index, /\/assets\/favicon\/apple-touch-icon\.png\?v=20260814/);
|
||||
assert.doesNotMatch(index, /rel="icon"[^>]+yoonect-logo\.png/);
|
||||
assert.deepEqual(appManifest.icons.map(({ sizes, purpose }) => ({ sizes, purpose })), [
|
||||
{ sizes: '192x192', purpose: 'maskable' },
|
||||
{ sizes: '512x512', purpose: 'maskable' }
|
||||
]);
|
||||
assert.match(appManifest.icons[0].src, /web-app-manifest-192x192\.png\?v=20260814$/);
|
||||
assert.match(appManifest.icons[1].src, /web-app-manifest-512x512\.png\?v=20260814$/);
|
||||
});
|
||||
|
||||
test('renders a shareable lore page with text-file metadata', () => {
|
||||
const html = renderIndex({
|
||||
template,
|
||||
baseUrl: 'https://memes.example',
|
||||
nonce: 'lore-nonce',
|
||||
approvedCount: 1,
|
||||
lore: true
|
||||
});
|
||||
|
||||
assert.match(html, /<title>Lore \| The Meme Protocol<\/title>/);
|
||||
assert.match(html, /canonical" href="https:\/\/memes\.example\/lore"/);
|
||||
assert.match(html, /og:image" content="https:\/\/memes\.example\/assets\/social-preview-v1\.png"/);
|
||||
assert.match(html, /"@type":"CreativeWork"/);
|
||||
assert.match(html, /https:\/\/memes\.example\/assets\/meme-protocol-lore\.txt/);
|
||||
});
|
||||
|
||||
test('discovery feeds point readers to viewer permalinks', () => {
|
||||
const feed = feedJson('https://memes.example', [meme]);
|
||||
const sitemap = sitemapXml('https://memes.example', [meme]);
|
||||
|
||||
assert.match(sitemap, /https:\/\/memes\.example\/lore/);
|
||||
|
||||
assert.equal(feed.items[0].url, `https://memes.example/meme/${id}`);
|
||||
assert.equal(feed.items[0].image, `https://memes.example/media/${id}`);
|
||||
assert.match(sitemap, new RegExp(`https://memes\\.example/meme/${id}`));
|
||||
|
||||
Reference in New Issue
Block a user