Skip to content

Commit 9660f24

Browse files
author
Your Name
committed
Standardize header styles for test panel
The test panel drawer headers display inconsistent typography and toggle indicators between the case creation form and test execution status. This change aligns font properties and stateful indicator styles across both sections to establish visual continuity in the interview view. Add a browser test under tests/browser/ to verify that both headers share the same marker and typography styles, and that each marker rotates when its section opens.
1 parent 6b6cdfe commit 9660f24

3 files changed

Lines changed: 189 additions & 5 deletions

File tree

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Run with: node --test tests/browser/test-drawer-headers.test.js
2+
3+
import { after, before, test } from "node:test";
4+
import assert from "node:assert/strict";
5+
6+
import {
7+
DEFAULT_RUNTIME_CONFIG,
8+
launchChromium,
9+
startStaticServer,
10+
} from "./source.js";
11+
12+
let browser = null;
13+
let server = null;
14+
let base = "";
15+
16+
before(async () => {
17+
browser = await launchChromium();
18+
if (!browser) return;
19+
({ server, base } = await startStaticServer({
20+
runtimeConfig: DEFAULT_RUNTIME_CONFIG,
21+
}));
22+
});
23+
24+
after(async () => {
25+
await browser?.close();
26+
await new Promise((closed) => (server ? server.close(closed) : closed()));
27+
});
28+
29+
async function waitForTransformTransition(marker, action) {
30+
const transitionFinished = marker.evaluate(
31+
(el) =>
32+
new Promise((resolve) => {
33+
const onTransitionEnd = (event) => {
34+
if (event.propertyName !== "transform") return;
35+
el.removeEventListener("transitionend", onTransitionEnd);
36+
resolve();
37+
};
38+
39+
el.addEventListener("transitionend", onTransitionEnd);
40+
}),
41+
);
42+
43+
await action();
44+
await transitionFinished;
45+
}
46+
47+
test("drawer headers share typography and toggle their chevrons", async (t) => {
48+
if (!browser) return t.skip("playwright chromium unavailable");
49+
50+
const page = await browser.newPage();
51+
try {
52+
await page.goto(`${base}/interview.html`, {
53+
waitUntil: "domcontentloaded",
54+
});
55+
56+
const headers = [
57+
{
58+
selector: "#candidate-case > summary",
59+
open: async () =>
60+
page.locator("#candidate-case").evaluate((el) => {
61+
el.open = true;
62+
}),
63+
close: async () =>
64+
page.locator("#candidate-case").evaluate((el) => {
65+
el.open = false;
66+
}),
67+
},
68+
{
69+
selector: "#results-toggle",
70+
open: async () =>
71+
page.locator("#results-toggle").evaluate((el) => {
72+
el.classList.add("open");
73+
}),
74+
close: async () =>
75+
page.locator("#results-toggle").evaluate((el) => {
76+
el.classList.remove("open");
77+
}),
78+
},
79+
];
80+
81+
const styles = await Promise.all(
82+
headers.map(({ selector }) =>
83+
page.locator(selector).evaluate((header) => {
84+
const style = getComputedStyle(header);
85+
const marker = header.querySelector(".drawer-chevron");
86+
const markerStyle = getComputedStyle(marker);
87+
return {
88+
fontFamily: style.fontFamily,
89+
fontSize: style.fontSize,
90+
fontWeight: style.fontWeight,
91+
lineHeight: style.lineHeight,
92+
markerTransform: markerStyle.transform,
93+
markerTransition: markerStyle.transition,
94+
};
95+
}),
96+
),
97+
);
98+
99+
assert.deepEqual(
100+
styles[0],
101+
styles[1],
102+
"both headers should share typography and chevron styles",
103+
);
104+
105+
for (const header of headers) {
106+
const marker = page.locator(`${header.selector} .drawer-chevron`);
107+
108+
assert.equal(await marker.count(), 1);
109+
110+
const closedTransform = await marker.evaluate(
111+
(el) => getComputedStyle(el).transform,
112+
);
113+
114+
await waitForTransformTransition(marker, header.open);
115+
116+
const openTransform = await marker.evaluate(
117+
(el) => getComputedStyle(el).transform,
118+
);
119+
120+
const openRotation = await marker.evaluate((el) => {
121+
const { a, b } = new DOMMatrixReadOnly(getComputedStyle(el).transform);
122+
return Math.round(Math.atan2(b, a) * (180 / Math.PI));
123+
});
124+
125+
assert.equal(
126+
openRotation,
127+
90,
128+
`${header.selector} chevron should rotate 90 degrees when opened`,
129+
);
130+
131+
assert.notEqual(
132+
openTransform,
133+
closedTransform,
134+
`${header.selector} chevron should change when opened`,
135+
);
136+
137+
await waitForTransformTransition(marker, header.close);
138+
139+
const restoredTransform = await marker.evaluate(
140+
(el) => getComputedStyle(el).transform,
141+
);
142+
143+
assert.equal(
144+
restoredTransform,
145+
closedTransform,
146+
`${header.selector} chevron should return when closed`,
147+
);
148+
}
149+
} finally {
150+
await page.close();
151+
}
152+
});

‎web/interview.html‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,10 @@ <h1 id="problem-title">Loading interview...</h1>
264264
></div>
265265
<section id="test-drawer" class="test-drawer">
266266
<details id="candidate-case">
267-
<summary>Add a case</summary>
267+
<summary>
268+
<span class="drawer-chevron" aria-hidden="true"></span>
269+
<span>Add a case</span>
270+
</summary>
268271
<label
269272
>Input JSON
270273
<textarea
@@ -284,8 +287,12 @@ <h1 id="problem-title">Loading interview...</h1>
284287
<ol id="candidate-case-list" class="small"></ol>
285288
</details>
286289
<button id="results-toggle" type="button">
290+
<span
291+
id="results-chevron"
292+
class="drawer-chevron"
293+
aria-hidden="true"
294+
></span>
287295
<span id="results-label">Test results</span>
288-
<span id="results-chevron">v</span>
289296
</button>
290297
<div id="results-body" class="results-body">
291298
<p class="muted small">

‎web/styles.css‎

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,16 +1425,41 @@ p {
14251425
flex-basis: auto;
14261426
}
14271427

1428+
.test-drawer summary::-webkit-details-marker,
1429+
.test-drawer summary::marker {
1430+
display: none;
1431+
}
1432+
1433+
.test-drawer summary,
14281434
#results-toggle {
14291435
display: flex;
1436+
align-items: center;
1437+
gap: 0.5rem;
14301438
width: 100%;
1431-
justify-content: space-between;
1439+
padding: 0.5rem 1rem;
14321440
border: 0;
14331441
background: transparent;
14341442
color: var(--sub);
1435-
padding: 0.5rem 1rem;
1436-
cursor: pointer;
1443+
font-family: inherit;
1444+
font-size: 0.875rem;
14371445
font-weight: 700;
1446+
cursor: pointer;
1447+
text-align: left;
1448+
}
1449+
1450+
.drawer-chevron {
1451+
display: inline-block;
1452+
width: 0;
1453+
height: 0;
1454+
border-top: 4px solid transparent;
1455+
border-bottom: 4px solid transparent;
1456+
border-left: 6px solid var(--sub);
1457+
transition: transform 120ms ease;
1458+
}
1459+
1460+
.test-drawer details[open] .drawer-chevron,
1461+
#results-toggle.open .drawer-chevron {
1462+
transform: rotate(90deg);
14381463
}
14391464

14401465
.results-body {

0 commit comments

Comments
 (0)