fix(sidebar): Omdøb og Slet lå oven i hinanden i et gruppehoved

The "+" beside "Projekter" is a 20px square icon button, and the rule that
makes it one was written as `.group-head > button`. A group's heading is
also a `.group-head`, and it has two buttons in it that are words rather
than icons — so Omdøb and Slet were each squeezed into a 20px box, where
they overflowed and were drawn on top of each other.

They still worked. Every assertion in the smoke test clicks by accessible
name, which is unaffected by a button being the wrong size, so the whole
suite passed on a heading that read "0 Om…Slet". It took a screenshot from
somebody actually using it.

The selector now asks for the class instead of for "a button in a
heading", so the next text button added there is safe by default rather
than by remembering.

And the smoke test measures the row: each button must start at or after
the previous one's right edge. A layout assertion is unusual here on
purpose — the rest of the file deliberately tests behaviour — but this is
a failure mode behaviour cannot see.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kristian Wind
2026-08-17 20:53:14 +02:00
co-authored by Claude Opus 5
parent a2f4de02fc
commit 0259a1513d
2 changed files with 28 additions and 3 deletions
+19
View File
@@ -257,6 +257,25 @@ test('en projektgruppe kan foldes, fyldes og slettes uden at tage projekterne me
await expect(heading).toBeVisible();
await expect(sidebar.getByText('Træk et projekt herop')).toBeVisible();
// The words in the heading must not sit on top of each other.
//
// Everything else here clicks by accessible name, which is exactly why this
// needs saying out loud: "Omdøb" and "Slet" once got the 20px square meant for
// the "+" icon beside "Projekter", overflowed it, and were drawn overlapping.
// Both buttons still worked, so every assertion in this file passed.
const boxes = await sidebar.locator('.folder-head').evaluate((el) =>
[...el.querySelectorAll('button')].map((b) => {
const r = b.getBoundingClientRect();
return { text: b.textContent.trim(), left: r.left, right: r.right };
})
);
for (let i = 1; i < boxes.length; i++) {
expect(
boxes[i].left,
`"${boxes[i - 1].text}" og "${boxes[i].text}" overlapper i gruppehovedet`
).toBeGreaterThanOrEqual(boxes[i - 1].right);
}
// Dragged in, then dragged back out onto "Projekter" — which is the reason
// that heading is a drop target at all: with every project filed away there
// would otherwise be no loose row left to aim at.
+9 -3
View File
@@ -380,6 +380,7 @@
>
<h2>Projekter</h2>
<button
class="icon"
onclick={() => {
adding = !adding;
addingGroup = false;
@@ -387,7 +388,7 @@
aria-label="Nyt projekt">+</button
>
<button
class="new-group"
class="icon new-group"
onclick={() => {
addingGroup = !addingGroup;
adding = false;
@@ -705,7 +706,12 @@
color: var(--ink-faint);
}
.group-head > button {
/* Only the square icon buttons — "+" and the folder — and asked for by class
rather than by "a button in a heading". A group's heading also has Omdøb and
Slet in it, and they are words: a selector that reached them squeezed both
into a 20px box, where they overflowed and were drawn on top of each other.
The class is the boundary, so the next text button added here is safe. */
.group-head > button.icon {
width: 20px;
height: 20px;
display: grid;
@@ -717,7 +723,7 @@
flex: none;
}
.group-head > button:hover {
.group-head > button.icon:hover {
color: var(--ink);
background: var(--surface-raised);
}