Files
meshcore-analyzer/tests/e2e/test-customize-export-e2e.js
T
Alex B 893773338e chore(tests): move root test-*.js into tests/unit and tests/e2e (#2036)
Moves 290 root test-*.js into tests/unit (177, listed in test-all.sh) and tests/e2e (113, classified in scripts/non-unit-tests.json), per #1981 and PR-D of #1385. Root goes from 348 entries to 48. test-all.sh and test-fixtures/ stay put. The inventory guard now fails if a test reappears in the root or sits in the wrong folder.

Verified independently of the diff: the invoked sets are unchanged (test-all.sh 177 before and after, deploy.yml 96 before and after, both identical as sets), and a full local run of test-all.sh on master and on the branch produced 4702 output lines each whose only differences are absolute paths, stack-trace line numbers shifted by the REPO_ROOT line, the inventory wording and two perf ratios. The guard was mutation-checked: a test back in the root, a unit suite in tests/e2e, and a suite dropped from test-all.sh each make it exit 1. CI run 35246304316 ran 97 suites from tests/e2e and is green.

Follow-up 9335c51d finished the instruction files: no bare root test command is left in AGENTS.md, the squad charters, .github or docs, and every tests/ path they name resolves.

Merged by the interim maintainer without a second human reviewer: CI and the local runs above are the independent checks.

Known and deliberately out of scope: 18 of the 113 files in tests/e2e are invoked by no runner at all, and one of them cannot run anywhere because it requires jsdom, which is not a declared dependency. Tracked separately.
2026-09-17 19:06:07 +02:00

103 lines
4.6 KiB
JavaScript

/**
* E2E (#1297 B4): Customizer V2 — Export / Import / Reset
*
* Exercises export tab + raw JSON area + reset-all button in public/customize-v2.js:
* - Write an override → switch to export tab → raw JSON textarea reflects it
* - Copy button populates the clipboard via document.execCommand or navigator.clipboard
* - Reset All clears cs-theme-overrides and CSS variables revert
*
* Usage: BASE_URL=http://localhost:13581 node test-customize-export-e2e.js
*/
'use strict';
const { chromium } = require('playwright');
const BASE = process.env.BASE_URL || 'http://localhost:3000';
let passed = 0, failed = 0;
async function step(name, fn) {
try { await fn(); passed++; console.log(' \u2713 ' + name); }
catch (e) { failed++; console.error(' \u2717 ' + name + ': ' + e.message); }
}
function assert(c, m) { if (!c) throw new Error(m || 'assertion failed'); }
(async () => {
const browser = await chromium.launch({
headless: true,
executablePath: process.env.CHROMIUM_PATH || undefined,
args: ['--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'],
});
const ctx = await browser.newContext();
const page = await ctx.newPage();
page.setDefaultTimeout(8000);
page.on('dialog', async (d) => { await d.accept(); }); // confirm() for reset
page.on('pageerror', (e) => console.error('[pageerror]', e.message));
console.log(`\n=== #1297 B4 customize-export E2E against ${BASE} ===`);
await step('setup: seed an override before loading', async () => {
await page.goto(BASE + '/', { waitUntil: 'domcontentloaded' });
await page.evaluate(() => {
localStorage.setItem('cs-theme-overrides',
JSON.stringify({ theme: { accent: '#ff00aa' }, distanceUnit: 'mi' }));
});
await page.reload({ waitUntil: 'load' });
await page.waitForFunction(() => window._customizerV2 && window._customizerV2.initDone, null, { timeout: 8000 });
});
await step('open customizer + switch to export tab', async () => {
await page.click('#customizeToggle');
await page.waitForSelector('.cust-overlay:not(.hidden)');
const tab = await page.$('.cust-tab[data-tab="export"]');
assert(tab, 'export tab missing');
await tab.click();
await page.waitForSelector('#cv2ExportJson', { state: 'attached', timeout: 4000 });
});
await step('raw JSON textarea reflects current overrides', async () => {
// Open <details> to reveal textarea
await page.evaluate(() => {
document.querySelectorAll('.cust-overlay details').forEach(d => d.open = true);
});
const json = await page.$eval('#cv2ExportJson', el => el.value);
const parsed = JSON.parse(json);
assert(parsed.distanceUnit === 'mi', 'export JSON should include distanceUnit, got: ' + json);
assert(parsed.theme && parsed.theme.accent === '#ff00aa',
'export JSON should include theme.accent, got: ' + json);
});
await step('Download button exists and is wired', async () => {
const btn = await page.$('#cv2Download');
assert(btn, '#cv2Download missing');
});
await step('Reset All clears overrides + reverts CSS variable', async () => {
const resetBtn = await page.$('#cv2ResetAll');
assert(resetBtn, '#cv2ResetAll missing (should appear when there are overrides)');
await resetBtn.click();
await page.waitForTimeout(500);
const raw = await page.evaluate(() => localStorage.getItem('cs-theme-overrides'));
assert(raw === null || raw === '{}' || (raw && Object.keys(JSON.parse(raw)).length === 0),
'cs-theme-overrides should be cleared after Reset All, got: ' + raw);
// After reset, the inline --accent override on documentElement.style should be gone
// (server default may still set computed style; we check the inline override)
const inlineAccent = await page.evaluate(() =>
document.documentElement.style.getPropertyValue('--accent').trim()
);
// Either empty (truly reset) or replaced by server default (not the user's pink #ff00aa)
assert(inlineAccent !== '#ff00aa',
'inline --accent should no longer be #ff00aa after reset, got: ' + inlineAccent);
});
await step('reset persists across reload', async () => {
await page.reload({ waitUntil: 'load' });
await page.waitForFunction(() => window._customizerV2 && window._customizerV2.initDone, null, { timeout: 8000 });
const raw = await page.evaluate(() => localStorage.getItem('cs-theme-overrides'));
assert(raw === null || raw === '{}' || (raw && Object.keys(JSON.parse(raw)).length === 0),
'overrides should remain cleared after reload, got: ' + raw);
});
await browser.close();
console.log('\n' + passed + '/' + (passed + failed) + ' tests passed');
process.exit(failed > 0 ? 1 : 0);
})();