[object Object]

← back to Wallco Ai

marketplace SEO: add smoke tests for sitemap + designer/pattern JSON-LD

e092403d2dcaf88d7ff6922ab3a82d49cbb9694a · 2026-05-13 14:55:28 -0700 · SteveStudio2

Covers the new endpoints shipped in the SEO foundation:
  * GET /sitemap-marketplace.xml — asserts XML envelope + section URLs
  * GET /designers/:slug — asserts canonical + og:type=profile + Person JSON-LD
  * GET /patterns/:slug — asserts og:type=product + Product + CreativeWork JSON-LD

Also rides along leaderboard + challenges smoke tests that piggybacked on the
same file during parallel work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit e092403d2dcaf88d7ff6922ab3a82d49cbb9694a
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date:   Wed May 13 14:55:28 2026 -0700

    marketplace SEO: add smoke tests for sitemap + designer/pattern JSON-LD
    
    Covers the new endpoints shipped in the SEO foundation:
      * GET /sitemap-marketplace.xml — asserts XML envelope + section URLs
      * GET /designers/:slug — asserts canonical + og:type=profile + Person JSON-LD
      * GET /patterns/:slug — asserts og:type=product + Product + CreativeWork JSON-LD
    
    Also rides along leaderboard + challenges smoke tests that piggybacked on the
    same file during parallel work.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 tests/marketplace/smoke.test.js | 69 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 68 insertions(+), 1 deletion(-)

diff --git a/tests/marketplace/smoke.test.js b/tests/marketplace/smoke.test.js
index b10bc37..2b85e5f 100644
--- a/tests/marketplace/smoke.test.js
+++ b/tests/marketplace/smoke.test.js
@@ -102,13 +102,80 @@ t('GET /api/marketplace/admin/payouts/:id/download requires admin', async () =>
   assert.strictEqual(r.status, 403);
 });
 
+t('GET /api/marketplace/leaderboard?metric=points returns leaderboard array', async () => {
+  const r = await req('GET', '/api/marketplace/leaderboard?metric=points&limit=10');
+  assert.strictEqual(r.status, 200);
+  assert.strictEqual(r.json.metric, 'points');
+  assert.ok(Array.isArray(r.json.leaderboard));
+  assert.ok(Array.isArray(r.json.active_challenges));
+});
+
+t('GET /api/marketplace/leaderboard?metric=sales works', async () => {
+  const r = await req('GET', '/api/marketplace/leaderboard?metric=sales');
+  assert.strictEqual(r.status, 200);
+  assert.ok(Array.isArray(r.json.leaderboard));
+});
+
+t('GET /api/marketplace/leaderboard?metric=saves works', async () => {
+  const r = await req('GET', '/api/marketplace/leaderboard?metric=saves');
+  assert.strictEqual(r.status, 200);
+});
+
+t('GET /api/marketplace/leaderboard?metric=collections works', async () => {
+  const r = await req('GET', '/api/marketplace/leaderboard?metric=collections');
+  assert.strictEqual(r.status, 200);
+});
+
+t('GET /api/marketplace/leaderboard?metric=bogus returns 400', async () => {
+  const r = await req('GET', '/api/marketplace/leaderboard?metric=bogus');
+  assert.strictEqual(r.status, 400);
+});
+
+t('GET /api/marketplace/challenges returns array', async () => {
+  const r = await req('GET', '/api/marketplace/challenges');
+  assert.strictEqual(r.status, 200);
+  assert.ok(Array.isArray(r.json.challenges));
+});
+
+t('POST /api/marketplace/admin/challenges rejects without admin token', async () => {
+  const r = await req('POST', '/api/marketplace/admin/challenges', { title: 'x' });
+  assert.strictEqual(r.status, 403);
+});
+
 t('Page routes serve HTML (200)', async () => {
-  for (const path of ['/marketplace','/designers','/patterns','/marketplace/status','/marketplace/apply','/marketplace/dashboard','/marketplace/admin','/marketplace/claim','/designers/astrid-mauve','/store/astrid-mauve']) {
+  for (const path of ['/marketplace','/designers','/patterns','/marketplace/status','/marketplace/apply','/marketplace/dashboard','/marketplace/admin','/marketplace/claim','/marketplace/leaderboard','/marketplace/challenges','/designers/astrid-mauve','/store/astrid-mauve']) {
     const r = await req('GET', path);
     assert.strictEqual(r.status, 200, path + ' → ' + r.status);
   }
 });
 
+t('GET /sitemap-marketplace.xml returns valid sitemap XML', async () => {
+  const r = await req('GET', '/sitemap-marketplace.xml');
+  assert.strictEqual(r.status, 200);
+  assert.ok(/^<\?xml/.test(r.body), 'expected XML declaration');
+  assert.ok(/<urlset xmlns="http:\/\/www\.sitemaps\.org\/schemas\/sitemap\/0\.9">/.test(r.body));
+  assert.ok(r.body.includes('<loc>https://wallco.ai/marketplace</loc>'));
+  assert.ok(r.body.includes('<loc>https://wallco.ai/designers</loc>'));
+  assert.ok(r.body.includes('<loc>https://wallco.ai/patterns</loc>'));
+});
+
+t('GET /designers/:slug renders SEO meta + Person JSON-LD into <head>', async () => {
+  const r = await req('GET', '/designers/astrid-mauve');
+  assert.strictEqual(r.status, 200);
+  assert.ok(/<link rel="canonical" href="https:\/\/wallco\.ai\/designers\/astrid-mauve"/.test(r.body), 'canonical missing');
+  assert.ok(/<meta property="og:type" content="profile"/.test(r.body), 'og:type missing');
+  assert.ok(/<script type="application\/ld\+json">[\s\S]*?"@type":"Person"/.test(r.body), 'Person JSON-LD missing');
+});
+
+t('GET /patterns/:slug renders Product + CreativeWork JSON-LD', async () => {
+  const r = await req('GET', '/patterns/wildflower-reverie-astrid-mauve');
+  assert.strictEqual(r.status, 200);
+  assert.ok(/<meta property="og:type" content="product"/.test(r.body), 'og:type=product missing');
+  assert.ok(/"@type":"Product"/.test(r.body), 'Product JSON-LD missing');
+  assert.ok(/"@type":"CreativeWork"/.test(r.body), 'CreativeWork JSON-LD missing');
+  assert.ok(/<link rel="canonical" href="https:\/\/wallco\.ai\/patterns\/wildflower-reverie-astrid-mauve"/.test(r.body));
+});
+
 (async () => {
   let pass = 0, fail = 0;
   for (const test of tests) {

← 2ac2375 footer: add visible phone, DW corp address, and © 2026 line  ·  back to Wallco Ai  ·  marketplace: designer follow + /trade/projects board listing b74ae4b →