openvibers/openvibe.reviews Commits
Reviews: the advertised Atom feed is a valid empty feed before anything is published (was 404) (#45)
Changes
@@@ -78,8 +78,11 @@ function createMachine({ svc, config, releaseLastmod }) {router.get('/feed.atom', async (_req, res) => {const items = await feedItems();-- if (!items.some((i) => i.decision.listable)) return res.status(404).set('Cache-Control', cache.htmlHeaders({ maxAge: 60 })).type('text/plain').send('No summary has been published yet.');-- setCache(res).type('application/atom+xml').send(seo.atomFeed({ title: 'OpenVibe.Reviews: published summaries', link: `${origin}/`, feedUrl: `${origin}/feed.atom`, id: `${origin}/feed.atom` }, items));++ // Every page names this feed, so an empty one is still a valid feed (as News, Trade and Coupons serve): its++ // <updated> is the release's commit time, a real time. Only without one does it answer 404.++ const empty = !items.some((i) => i.decision.listable);++ if (empty && !releaseLastmod) return res.status(404).set('Cache-Control', cache.htmlHeaders({ maxAge: 60 })).type('text/plain').send('No summary has been published yet.');++ setCache(res).type('application/atom+xml').send(seo.atomFeed({ title: 'OpenVibe.Reviews: published summaries', link: `${origin}/`, feedUrl: `${origin}/feed.atom`, id: `${origin}/feed.atom`, ...(empty ? { updated: releaseLastmod } : {}) }, items));});router.get('/feed.json', async (_req, res) => {setCache(res).type('application/feed+json').send(JSON.stringify(seo.jsonFeed({ title: 'OpenVibe.Reviews: published summaries', link: `${origin}/`, feedUrl: `${origin}/feed.json`, description: 'Editor-reviewed summaries, by the time their current revision was published.' }, await feedItems())));@@@ -26,6 +26,17 @@ const noScripts = (html) => html.replace(/<script[\s\S]*?<\/script>/g, '');const jsonLd = (html) => [...html.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)].map((m) => JSON.parse(m[1]));const robots = (html) => (html.match(/<meta name="robots" content="([^"]+)"/) || [])[1];++t('the Atom feed every page names is a valid, empty feed before anything is published', async () => {++ const h = await boot();++ try {++ const atom = await req(h, 'GET', '/feed.atom');++ assert.strictEqual(atom.status, 200, atom.text);++ assert.match(atom.text, /<feed xmlns="http:\/\/www\.w3\.org\/2005\/Atom"/);++ assert.match(atom.text, /<updated>\d{4}-\d{2}-\d{2}T[^<]+<\/updated>/, 'a real <updated>: the release commit time');++ assert.ok(!/<entry>/.test(atom.text), 'no entries');++ } finally { await h.stop(); }++});++t('AggregateRating JSON-LD is absent without signals, present only while signals back it', async () => {const h = await boot();try {
@@ -78,8 +78,11 @@ function createMachine({ svc, config, releaseLastmod }) {
@@ -78,8 +78,11 @@ function createMachine({ svc, config, releaseLastmod }) {
router.get('/feed.atom', async (_req, res) => {
router.get('/feed.atom', async (_req, res) => {
const items = await feedItems();
const items = await feedItems();
- if (!items.some((i) => i.decision.listable)) return res.status(404).set('Cache-Control', cache.htmlHeaders({ maxAge: 60 })).type('text/plain').send('No summary has been published yet.');
- setCache(res).type('application/atom+xml').send(seo.atomFeed({ title: 'OpenVibe.Reviews: published summaries', link: `${origin}/`, feedUrl: `${origin}/feed.atom`, id: `${origin}/feed.atom` }, items));
+ // Every page names this feed, so an empty one is still a valid feed (as News, Trade and Coupons serve): its
+ // <updated> is the release's commit time, a real time. Only without one does it answer 404.
+ const empty = !items.some((i) => i.decision.listable);
+ if (empty && !releaseLastmod) return res.status(404).set('Cache-Control', cache.htmlHeaders({ maxAge: 60 })).type('text/plain').send('No summary has been published yet.');
+ setCache(res).type('application/atom+xml').send(seo.atomFeed({ title: 'OpenVibe.Reviews: published summaries', link: `${origin}/`, feedUrl: `${origin}/feed.atom`, id: `${origin}/feed.atom`, ...(empty ? { updated: releaseLastmod } : {}) }, items));
});
});
router.get('/feed.json', async (_req, res) => {
router.get('/feed.json', async (_req, res) => {
setCache(res).type('application/feed+json').send(JSON.stringify(seo.jsonFeed({ title: 'OpenVibe.Reviews: published summaries', link: `${origin}/`, feedUrl: `${origin}/feed.json`, description: 'Editor-reviewed summaries, by the time their current revision was published.' }, await feedItems())));
setCache(res).type('application/feed+json').send(JSON.stringify(seo.jsonFeed({ title: 'OpenVibe.Reviews: published summaries', link: `${origin}/`, feedUrl: `${origin}/feed.json`, description: 'Editor-reviewed summaries, by the time their current revision was published.' }, await feedItems())));
@@ -26,6 +26,17 @@ const noScripts = (html) => html.replace(/<script[\s\S]*?<\/script>/g, '');
@@ -26,6 +26,17 @@ const noScripts = (html) => html.replace(/<script[\s\S]*?<\/script>/g, '');
const jsonLd = (html) => [...html.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)].map((m) => JSON.parse(m[1]));
const jsonLd = (html) => [...html.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)].map((m) => JSON.parse(m[1]));
const robots = (html) => (html.match(/<meta name="robots" content="([^"]+)"/) || [])[1];
const robots = (html) => (html.match(/<meta name="robots" content="([^"]+)"/) || [])[1];
+t('the Atom feed every page names is a valid, empty feed before anything is published', async () => {
+ const h = await boot();
+ try {
+ const atom = await req(h, 'GET', '/feed.atom');
+ assert.strictEqual(atom.status, 200, atom.text);
+ assert.match(atom.text, /<feed xmlns="http:\/\/www\.w3\.org\/2005\/Atom"/);
+ assert.match(atom.text, /<updated>\d{4}-\d{2}-\d{2}T[^<]+<\/updated>/, 'a real <updated>: the release commit time');
+ assert.ok(!/<entry>/.test(atom.text), 'no entries');
+ } finally { await h.stop(); }
+});
+
t('AggregateRating JSON-LD is absent without signals, present only while signals back it', async () => {
t('AggregateRating JSON-LD is absent without signals, present only while signals back it', async () => {
const h = await boot();
const h = await boot();
try {
try {