Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion tests/e2e/dashboard-mobile.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@
<div class="dash-topbar">
<div id="shared-header"></div>
<div id="primary-toolbar" class="dash-toolbar dash-toolbar-primary"></div>
<div class="dash-toolbar dash-toolbar-variables has-variables">
<!-- #473: the real `ui/dashboard.ts` toolbar carries only these two classes,
always — it never adds a visibility class. The show/hide contract is an
inline `style.display`, applied only in the hidden case (an omitted
style, as here, means "no ordinary variables to hide"). This harness's
scenario always has ordinary variables, so no inline style is present,
matching the app's own undefined-style branch. -->
<div class="dash-toolbar dash-toolbar-variables">
<div class="dash-variable-host dash-variables" role="group" aria-label="Dashboard variables"><div class="dash-variable-ordinary"></div></div>
<button class="dash-clear-variables">Clear all</button>
</div>
Expand Down
17 changes: 14 additions & 3 deletions tests/e2e/dashboard-mobile.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,17 +200,24 @@ test.describe('Dashboard mobile layout', () => {
await expect(list).toBeVisible();
const popover = await list.evaluate((node) => {
const input = document.querySelector('[aria-label="region"]');
const toolbar = document.querySelector('.dash-toolbar.has-variables');
// #473: `.dash-toolbar-variables` is the real class the app always builds;
// `ui/dashboard.ts` never sets a `has-variables`/`has-filters` class. The
// show/hide contract is its inline `style.display`, which the app leaves
// unset (not `'none'`) whenever ordinary variables are present, as here.
const toolbar = document.querySelector('.dash-toolbar-variables');
const listRect = node.getBoundingClientRect();
const inputRect = input.getBoundingClientRect();
return {
position: getComputedStyle(node).position,
anchored: Math.abs(listRect.left - inputRect.left) < 2 && listRect.top >= inputRect.bottom,
escapesToolbar: listRect.bottom > toolbar.getBoundingClientRect().bottom,
toolbarDisplay: toolbar.style.display,
pageOverflow: document.documentElement.scrollWidth - innerWidth,
};
});
expect(popover).toEqual({ position: 'fixed', anchored: true, escapesToolbar: true, pageOverflow: 0 });
expect(popover).toEqual({
position: 'fixed', anchored: true, escapesToolbar: true, toolbarDisplay: '', pageOverflow: 0,
});
await first.press('Enter');
await expect(first).toHaveValue('alpha');
});
Expand Down Expand Up @@ -290,7 +297,11 @@ test.describe('Dashboard mobile layout', () => {
await expect(page.locator('.dash-filter-count')).toHaveCount(0);
await expect(page.locator('.dash-filter-count-host')).toHaveCount(0);

const toolbar = page.locator('.dash-toolbar.has-variables');
// #473: real class (never `has-variables`/`has-filters` — the app doesn't set
// one); the actual show/hide contract is the inline `style.display` the app
// sets only to hide the toolbar, asserted here directly.
const toolbar = page.locator('.dash-toolbar-variables');
expect(await toolbar.evaluate((node) => node.style.display)).toBe('');
const before = await toolbar.evaluate((node) => node.getBoundingClientRect().height);

const layout = await page.evaluate(() => {
Expand Down
18 changes: 18 additions & 0 deletions tests/unit/dashboard.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3280,6 +3280,24 @@ describe('renderDashboard — compound time-range control (#335)', () => {
expect(ordinaryToolbar.contains(liveRegion)).toBe(false);
});

// #473: the counterpart to the test above — the "shown" half of the same
// ternary (`src/ui/dashboard.ts`'s `hasOrdinaryVariables ? undefined : {
// display: 'none' }`) was asserted nowhere against a real `createApp`
// render; only the e2e fixture's hand-written markup modeled it. An ordinary
// (non-time-range) variable — `region` here — must leave the toolbar with NO
// inline display override at all, not merely "not none".
it('shows the ordinary-variable toolbar with no inline display override when an ordinary variable is present', async () => {
const { app } = dashApp({
workspace: wsWith({
queries: [paired(PAIR + ' AND r = {region:String}')],
tiles: [{ id: 't1', queryId: 'q1' }],
}),
});
await render(app);
const ordinaryToolbar = qs(app.root, '.dash-toolbar-variables');
expect(ordinaryToolbar.style.display).toBe('');
});

it('Apply commits BOTH bounds through session.applyVariables in one wave and announces the range', async () => {
const { app, calls } = dashApp({
workspace: wsWith({ queries: [paired()], tiles: [{ id: 't1', queryId: 'q1' }] }),
Expand Down