test: check-sizes measures text and control heights per size mode (T8)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
// Checks the size modes (Compact / Normal / Large): body text and the heights of a table row, a
|
||||
// text field, the submit button and (on phones) a mobile menu link. Sets the size on the admin
|
||||
// account, so it needs the redmine_tonalmine plugin (dev/docker-compose.yml); resets it when done.
|
||||
// Usage: node check-sizes.mjs (exits 1 on any failure)
|
||||
import { chromium } from 'playwright';
|
||||
import { setSize } from './size.mjs';
|
||||
|
||||
const BASE = process.env.REDMINE_URL ?? 'http://127.0.0.1:3070';
|
||||
// size → [body text, fields / buttons / phone table rows, mobile menu links]
|
||||
const SIZES = { compact: ['13px', 32, 40], normal: ['14px', 40, 48], large: ['16px', 48, 56] };
|
||||
const browser = await chromium.launch();
|
||||
let failures = 0;
|
||||
|
||||
function check(name, got, want) {
|
||||
const ok = got === want;
|
||||
if (!ok) failures++;
|
||||
console.log(`${ok ? 'ok ' : 'FAIL'} ${name}${ok ? '' : `\n expected ${want}, got ${got}`}`);
|
||||
}
|
||||
|
||||
const height = (page, selector) => page.$eval(selector, (el) => Math.round(el.getBoundingClientRect().height));
|
||||
|
||||
for (const [width, mobile] of [[1440, false], [390, true]]) {
|
||||
const page = await browser.newPage({ viewport: { width, height: 900 } });
|
||||
await page.goto(`${BASE}/login`);
|
||||
await page.fill('#username', 'admin');
|
||||
await page.fill('#password', 'admin');
|
||||
await page.click('#login-submit');
|
||||
await page.waitForURL((url) => !url.pathname.startsWith('/login'));
|
||||
|
||||
for (const [size, [text, control, menuLink]] of Object.entries(SIZES)) {
|
||||
await setSize(page, size);
|
||||
const at = `${size} ${width}`;
|
||||
await page.goto(`${BASE}/projects/apollo/issues`, { waitUntil: 'networkidle' });
|
||||
check(`${at} body text`, await page.$eval('body', (el) => getComputedStyle(el).fontSize), text);
|
||||
// On desktop the cells' 4px padding comes on top of their block-size
|
||||
check(`${at} issue row`, await height(page, 'table.list.issues tbody tr:first-child'), control + (mobile ? 0 : 8));
|
||||
if (mobile) {
|
||||
await page.click('.mobile-toggle-button');
|
||||
await page.waitForSelector('.flyout-menu .js-project-menu a.overview', { state: 'visible' });
|
||||
check(`${at} mobile menu link`, await height(page, '.flyout-menu .js-project-menu a.overview'), menuLink);
|
||||
}
|
||||
await page.goto(`${BASE}/projects/apollo/issues/new`, { waitUntil: 'networkidle' });
|
||||
check(`${at} text field`, await height(page, '#issue_subject'), control);
|
||||
check(`${at} submit button`, await height(page, 'input[name="commit"]'), control);
|
||||
}
|
||||
await setSize(page);
|
||||
await page.close();
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
process.exit(failures ? 1 : 0);
|
||||
@@ -0,0 +1,10 @@
|
||||
// Saves a size mode on the logged-in user's account (needs the redmine_tonalmine plugin).
|
||||
// No size resets the account to the default appearance.
|
||||
export async function setSize(page, size) {
|
||||
const status = await page.evaluate(async (body) => {
|
||||
const headers = { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest',
|
||||
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content };
|
||||
return (await fetch('/tonalmine/appearance', { method: 'PUT', headers, body: JSON.stringify(body) })).status;
|
||||
}, size ? { size } : {});
|
||||
if (status !== 204) throw new Error(`could not save size ${size ?? 'default'} (HTTP ${status})`);
|
||||
}
|
||||
Reference in New Issue
Block a user