#301: stop /settings scrolling horizontally at 320px #309
@ -120,37 +120,66 @@ async function expectNoHorizontalScroll(page: Page, label: string): Promise<void
|
|||||||
const report = await page.evaluate(() => {
|
const report = await page.evaluate(() => {
|
||||||
const doc = document.documentElement;
|
const doc = document.documentElement;
|
||||||
const limit = doc.clientWidth;
|
const limit = doc.clientWidth;
|
||||||
/** Content inside its own scroll container is allowed to be wider than
|
const describe = (el: HTMLElement): string => {
|
||||||
* the viewport — that is the prescribed remedy, not the defect. Only
|
const cls =
|
||||||
* what pushes the PAGE is a finding. */
|
el.className && typeof el.className === 'string'
|
||||||
const insideScroller = (el: HTMLElement): boolean => {
|
? `.${el.className.trim().split(/\s+/).join('.')}`
|
||||||
|
: '';
|
||||||
|
return `${el.tagName.toLowerCase()}${cls}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content inside a scroll container may exceed the viewport — that is the
|
||||||
|
* remedy, not the defect. But only if the CONTAINER itself fits: a
|
||||||
|
* scroller that is wider than the viewport still pushes the page, and its
|
||||||
|
* children are then symptoms, not causes.
|
||||||
|
*/
|
||||||
|
const containedByFittingScroller = (el: HTMLElement): boolean => {
|
||||||
for (let node = el.parentElement; node && node !== doc; node = node.parentElement) {
|
for (let node = el.parentElement; node && node !== doc; node = node.parentElement) {
|
||||||
const overflowX = getComputedStyle(node).overflowX;
|
const overflowX = getComputedStyle(node).overflowX;
|
||||||
if (overflowX === 'auto' || overflowX === 'scroll' || overflowX === 'hidden') return true;
|
if (overflowX === 'auto' || overflowX === 'scroll' || overflowX === 'hidden') {
|
||||||
|
return node.getBoundingClientRect().right <= limit + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const offenders: string[] = [];
|
const offenders: string[] = [];
|
||||||
|
let widest: HTMLElement | null = null;
|
||||||
for (const el of Array.from(document.querySelectorAll<HTMLElement>('body *'))) {
|
for (const el of Array.from(document.querySelectorAll<HTMLElement>('body *'))) {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
// 1 px Toleranz gegen Subpixel-Rundung.
|
// 1 px Toleranz gegen Subpixel-Rundung.
|
||||||
if (rect.width > 0 && rect.right > limit + 1 && !insideScroller(el)) {
|
if (rect.width > 0 && rect.right > limit + 1 && !containedByFittingScroller(el)) {
|
||||||
const cls =
|
|
||||||
el.className && typeof el.className === 'string'
|
|
||||||
? `.${el.className.trim().split(/\s+/).join('.')}`
|
|
||||||
: '';
|
|
||||||
offenders.push(
|
offenders.push(
|
||||||
`${el.tagName.toLowerCase()}${cls} (right=${Math.round(rect.right)}, width=${Math.round(rect.width)})`,
|
`${describe(el)} (right=${Math.round(rect.right)}, width=${Math.round(rect.width)})`,
|
||||||
);
|
);
|
||||||
|
if (!widest || rect.width > widest.getBoundingClientRect().width) widest = el;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { scrollWidth: doc.scrollWidth, clientWidth: limit, offenders: offenders.slice(0, 20) };
|
|
||||||
|
// Where does the inflation start? The chain from body down to the widest
|
||||||
|
// offender, with each box's width — the first entry wider than the
|
||||||
|
// viewport is the element that actually needs constraining.
|
||||||
|
const chain: string[] = [];
|
||||||
|
for (let node: HTMLElement | null = widest; node && node !== doc; node = node.parentElement) {
|
||||||
|
chain.unshift(`${describe(node)} w=${Math.round(node.getBoundingClientRect().width)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
scrollWidth: doc.scrollWidth,
|
||||||
|
clientWidth: limit,
|
||||||
|
offenders: offenders.slice(0, 20),
|
||||||
|
chain,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
expect(
|
expect(
|
||||||
{ overflowBy: report.scrollWidth - report.clientWidth, offenders: report.offenders },
|
{
|
||||||
|
overflowBy: report.scrollWidth - report.clientWidth,
|
||||||
|
offenders: report.offenders,
|
||||||
|
chain: report.chain,
|
||||||
|
},
|
||||||
`${label}: horizontaler Überlauf bei 320 px`,
|
`${label}: horizontaler Überlauf bei 320 px`,
|
||||||
).toEqual({ overflowBy: 0, offenders: [] });
|
).toEqual({ overflowBy: 0, offenders: [], chain: [] });
|
||||||
}
|
}
|
||||||
|
|
||||||
test.describe('reflow at 320px', () => {
|
test.describe('reflow at 320px', () => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user