diff --git a/app/package.json b/app/package.json index 333d25c..8926bef 100644 --- a/app/package.json +++ b/app/package.json @@ -23,7 +23,8 @@ "test:electron:images": "electron-vite build && electron --no-sandbox tests/electron-session-images.mjs", "test:electron:timeline": "electron-vite build && electron --no-sandbox tests/electron-session-virtualization.mjs", "test:electron:reader-state": "electron-vite build && electron --no-sandbox tests/electron-session-reader-state.mjs", - "test:electron:file-refs": "electron-vite build && electron --no-sandbox tests/electron-file-references.mjs" + "test:electron:file-refs": "electron-vite build && electron --no-sandbox tests/electron-file-references.mjs", + "test:electron:all": "electron-vite build && node tests/run-electron-suites.mjs" }, "build": { "appId": "com.obelisk.app", diff --git a/app/tests/electron-session-images.mjs b/app/tests/electron-session-images.mjs index 514c2ec..e342edf 100644 --- a/app/tests/electron-session-images.mjs +++ b/app/tests/electron-session-images.mjs @@ -300,6 +300,16 @@ async function run() { const smallImageRect = smallImage.getBoundingClientRect(); const wideRowRect = wideRow.getBoundingClientRect(); const nextRowRect = nextRow.getBoundingClientRect(); + // Row spacing is applied by the virtualizer, not by CSS on the row, so + // calibrate against the spacing the rest of this timeline is using rather + // than hard-coding the current value. + const mountedRows = [...document.querySelectorAll('.virtual-timeline-row')] + .map(row => ({ index: Number(row.dataset.index), rect: row.getBoundingClientRect() })) + .sort((left, right) => left.index - right.index); + const gaps = mountedRows + .slice(1) + .map((row, offset) => row.rect.top - mountedRows[offset].rect.bottom) + .sort((left, right) => left - right); return { wrapClientWidth: wrap.clientWidth, wrapScrollWidth: wrap.scrollWidth, @@ -312,6 +322,7 @@ async function run() { smallNaturalWidth: smallImage.naturalWidth, rowHeight: wideRowRect.height, rowGap: nextRowRect.top - wideRowRect.bottom, + typicalRowGap: gaps[Math.floor(gaps.length / 2)] ?? null, brokenText: brokenHost.shadowRoot.querySelector('figcaption')?.textContent || '', }; })()`, true); @@ -337,7 +348,9 @@ async function run() { `small images keep their intrinsic width (${JSON.stringify(layout)})`, ); assert( - layout.rowHeight > layout.wideImageHeight && layout.rowGap >= 13, + layout.rowHeight > layout.wideImageHeight + && layout.typicalRowGap !== null + && Math.abs(layout.rowGap - layout.typicalRowGap) <= 1, `measured image rows do not overlap the following row (${JSON.stringify(layout)})`, ); assert( diff --git a/app/tests/run-electron-suites.mjs b/app/tests/run-electron-suites.mjs new file mode 100644 index 0000000..2e1ac61 --- /dev/null +++ b/app/tests/run-electron-suites.mjs @@ -0,0 +1,32 @@ +// Runs every Electron regression suite against one build and reports a single +// summary. Each suite already prints its own PASS/FAIL lines; this exists so a +// new suite is covered by one command instead of only being run by whoever +// remembers it is there. + +import { spawnSync } from 'node:child_process' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import electron from 'electron' + +const appRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') +const suites = [ + 'electron-concurrency.mjs', + 'electron-session-images.mjs', + 'electron-session-virtualization.mjs', + 'electron-session-reader-state.mjs', + 'electron-file-references.mjs', +] + +const failed = [] +for (const suite of suites) { + console.log(`\n=== ${suite} ===`) + const result = spawnSync(electron, ['--no-sandbox', path.join('tests', suite)], { + cwd: appRoot, + stdio: 'inherit', + }) + if (result.status !== 0) failed.push(`${suite} (exit ${result.status ?? 'signal'})`) +} + +console.log(`\n${suites.length - failed.length}/${suites.length} Electron suites passed`) +for (const failure of failed) console.error(`FAILED: ${failure}`) +process.exit(failed.length ? 1 : 0)