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
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,8 +81,8 @@ describe('real Electron window smoke gate (PR-DESKTOP-SMOKE-0)', () => {
);
assert.match(
src,
/maka-search-modal-input/,
'programmatic focus check must accept the actual search input focus target, not only the close button',
/activeElementInSearchModal/,
'programmatic focus check must verify focus is trapped structurally inside the search modal (any interactive control), not by a brittle class on the focused element',
);
assert.match(src, /Window diagnostics/, 'real-window smoke report must include BrowserWindow/renderer diagnostics when available');
assert.match(src, /PROGRAMMATIC_SMOKE_CHECKS/, 'real-window smoke must include an accessibility-independent programmatic BrowserWindow/renderer layer');
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
/**
* Contract between the real-window smoke diagnostic (main.ts, injected into
* the renderer) and the live modal DOM.
*
* The diagnostic detects the search modal's backdrop and focus state by
* querying the renderer. Those selectors silently drifted once the modal
* migrated to the Base UI `Dialog` primitives: the backdrop stopped carrying
* `.maka-search-modal-backdrop`, and the focused input lost the
* `maka-search-modal-input` class to InputGroup's own utility classes — so
* the `programmatic-search-modal-open` and `programmatic-focus-target` smoke
* checks failed on a clean tree (reproduced identically on `main`).
*
* This gate binds the diagnostic to a STABLE hook so it can't drift again:
* - the shared DialogBackdrop carries `maka-dialog-backdrop` (style-free),
* - the diagnostic queries that hook (not the dead search-modal-backdrop),
* - focus-trap is detected structurally via closest('.maka-search-modal'),
* not via a brittle class on the focused element.
*/

import { strict as assert } from 'node:assert';
import { readFile } from 'node:fs/promises';
import { describe, it } from 'node:test';
import { join } from 'node:path';

const MAIN_PATH = join(process.cwd(), 'src', 'main', 'main.ts');
const UI_PATH = join(process.cwd(), '..', '..', 'packages', 'ui', 'src', 'ui.tsx');

describe('real-window smoke diagnostic ↔ modal DOM contract', () => {
it('the shared dialog backdrop carries the stable maka-dialog-backdrop hook', async () => {
const ui = await readFile(UI_PATH, 'utf8');
assert.match(
ui,
/maka-dialog-backdrop/,
'DialogBackdrop must carry the style-free `maka-dialog-backdrop` hook so the smoke diagnostic can select the backdrop. Base UI otherwise renders only drifting Tailwind utility classes.',
);
});

it('the diagnostic queries the live backdrop hook, not the dead search-modal-backdrop class', async () => {
const main = await readFile(MAIN_PATH, 'utf8');
assert.match(
main,
/querySelector\('\.maka-dialog-backdrop'\)/,
'the smoke diagnostic must detect the modal backdrop via `.maka-dialog-backdrop`',
);
assert.doesNotMatch(
main,
/maka-search-modal-backdrop/,
'the dead `.maka-search-modal-backdrop` selector (no element carries it) must be gone',
);
});

it('the diagnostic reports whether focus is trapped inside the search modal', async () => {
const main = await readFile(MAIN_PATH, 'utf8');
assert.match(
main,
/activeElementInSearchModal/,
'the diagnostic must expose `activeElementInSearchModal` so focus-target is checked structurally',
);
assert.match(
main,
/closest\('\.maka-search-modal'\)/,
'focus-trap detection must use closest(.maka-search-modal), not a class on the focused element',
);
});
});
3 changes: 2 additions & 1 deletion apps/desktop/src/main/main.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -1562,8 +1562,9 @@ function emitRealWindowSmokeDiagnostic(stage: string): void {
title: document.title,
appFramePresent: Boolean(document.querySelector('.appFrame')),
searchModalPresent: Boolean(document.querySelector('.maka-search-modal')),
searchModalBackdropPresent: Boolean(document.querySelector('.maka-search-modal-backdrop')),
searchModalBackdropPresent: Boolean(document.querySelector('.maka-dialog-backdrop')),
errorBoundaryPresent: Boolean(document.querySelector('.maka-error-surface')),
activeElementInSearchModal: Boolean(document.activeElement && document.activeElement.closest && document.activeElement.closest('.maka-search-modal')),
activeElement: document.activeElement ? {
tagName: document.activeElement.tagName,
className: typeof document.activeElement.className === 'string' ? document.activeElement.className : '',
Expand Down
9 changes: 3 additions & 6 deletions apps/desktop/src/renderer/styles.css
Original file line numberDiff line numberDiff line change
Expand Up@@ -418,12 +418,9 @@ button:active {
}

/* Search modal: input + local thread-search results, backed by
* `window.maka.search.thread()` through the renderer shell. */
.maka-search-modal-backdrop {
/* Reuse the existing modal backdrop tokens. The presentational
* `.maka-modal-backdrop` class above this block handles dimming
* and centering. */
}
* `window.maka.search.thread()` through the renderer shell. The dialog
* backdrop is rendered by the shared Dialog primitive (.maka-dialog-backdrop
* + .maka-modal-backdrop tokens), not a search-modal-specific element. */
.maka-search-modal {
width: min(560px, 92vw);
max-height: 64vh;
Expand Down
6 changes: 5 additions & 1 deletion packages/ui/src/ui.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -221,7 +221,11 @@ export const DialogBackdrop = forwardRef<HTMLDivElement, React.ComponentPropsWit
return (
<BaseDialog.Backdrop
ref={ref}
className={cn('fixed inset-0 z-40 bg-foreground/20 backdrop-blur-sm', className)}
// `maka-dialog-backdrop` is a stable, style-free hook so tests and the
// real-window smoke diagnostic can select the dialog backdrop; Base UI
// renders only utility classes otherwise, which drift and aren't
// reliably selectable.
className={cn('maka-dialog-backdrop fixed inset-0 z-40 bg-foreground/20 backdrop-blur-sm', className)}
{...props}
/>
);
Expand Down
16 changes: 7 additions & 9 deletions scripts/desktop-real-window-smoke.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -382,16 +382,14 @@ function buildProgrammaticResults(args, diagnostics) {
},
{
check: PROGRAMMATIC_SMOKE_CHECKS[4],
// Focus must land on a control trapped inside the search modal. Check
// this structurally (activeElement is inside `.maka-search-modal`) rather
// than by a class on the focused element — the search input's class is
// owned by InputGroup's utility classes and isn't stable.
ok:
(
renderer.activeElement?.tagName === 'INPUT' &&
renderer.activeElement?.className?.includes('maka-search-modal-input')
) ||
(
renderer.activeElement?.tagName === 'BUTTON' &&
renderer.activeElement?.className?.includes('maka-search-modal-close')
),
note: `activeElement=${JSON.stringify(renderer.activeElement ?? null)}`,
renderer.activeElementInSearchModal === true &&
(renderer.activeElement?.tagName === 'INPUT' || renderer.activeElement?.tagName === 'BUTTON'),
note: `activeElementInSearchModal=${renderer.activeElementInSearchModal ?? 'unknown'} activeElement=${JSON.stringify(renderer.activeElement ?? null)}`,
},
{
check: PROGRAMMATIC_SMOKE_CHECKS[5],
Expand Down