← back to Dw Domain Fleet

scripts/boot-test.js

59 lines

#!/usr/bin/env node
/**
 * boot-test.js — load every site config, build its niche pool, render its
 * home + catalog + about pages in-process. Catches per-site render failures
 * WITHOUT needing 65 ports. No HTTP — direct function calls.
 */
const fs = require('fs');
const path = require('path');
const catalog = require('../shared/catalog');
const { sortProducts } = require('../shared/sort');
const render = require('../shared/render');

const sites = fs.readdirSync(path.join(__dirname, '..', 'sites')).filter(f => f.endsWith('.json'));
let pass = 0, fail = 0;
const thin = [];

for (const f of sites) {
  const cfg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'sites', f), 'utf8'));
  try {
    const niche = catalog.nicheSlice({
      pos: cfg.niche.pos || [], neg: cfg.niche.neg || [], types: cfg.niche.types || [], limit: 6000
    });
    const pool = niche.length >= 24 ? niche
      : catalog.nicheSlice({ pos: [], neg: cfg.niche.neg || [], types: ['Wallcovering'], limit: 6000 });
    const heroImgs = sortProducts(pool, 'newest').slice(0, 14).map(p => p.image_url).filter(Boolean);
    const featured = sortProducts(pool, 'newest').slice(0, 20);
    const home = render.homePage(cfg, heroImgs, featured);
    const cat = render.catalogPage(cfg, pool.slice(0, 60), '', 'newest', 1, 5, pool.length);
    const about = render.aboutPage(cfg);
    // sanity assertions
    if (!/<!doctype html>/i.test(home)) throw new Error('home: no doctype');
    // Banned-word check: "wallpaper" must NOT appear in EDITORIAL copy
    // (tagline / about / meta-desc / hero-sub). It IS allowed in the brand
    // wordmark + <title> when the registered domain stem itself contains it
    // (e.g. wallpaperny.com) — the domain is the SEO asset, per Steve's rule.
    for (const [k, v] of Object.entries({ tagline: cfg.tagline, heroSub: cfg.heroSub,
      metaDesc: cfg.metaDesc, aboutCopy: cfg.aboutCopy })) {
      if (/wallpaper/i.test(render.clean(String(v)))) {
        throw new Error(`banned word "wallpaper" in editorial field ${k}`);
      }
    }
    if (!/id="sortSel"/.test(cat)) throw new Error('catalog: no sort select');
    if (!/id="densSel"/.test(cat)) throw new Error('catalog: no density slider');
    if (!/gucci-menu/.test(home)) throw new Error('home: no gucci menu');
    pass++;
    if (niche.length < 60) thin.push(`${cfg.slug}: niche=${niche.length} (using ${pool.length})`);
    process.stdout.write(`. `);
  } catch (e) {
    fail++;
    console.log(`\nFAIL ${cfg.slug}: ${e.message}`);
  }
}
console.log(`\n\n${pass} pass · ${fail} fail · ${sites.length} total`);
if (thin.length) {
  console.log(`\nThin niches (fell back to broad wallcovering pool):`);
  thin.forEach(t => console.log('  ' + t));
}
process.exit(fail ? 1 : 0);