mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 16:59:43 +02:00
test(tiles): the grid harness finds a tile's element, and serves the pure helpers
Five tile-grid tests defined the same `tileEl(id)` lookup and three more inlined it; the harness (test/mocks/tile-grid-vm.ts) now exports it and they import it. tile-grid-open-set built a second vm context just to read constants.js, although the harness it already imports has loaded the same file: it reads windowStub.CodemanTileGrid instead. No assertion changed. Mutation-checked: tiles without their data-session-id fail 34 tests across the seven files, and a broken tileGridOpenSet fails the open-set cases. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -159,6 +159,8 @@ export const section = new FakeEl();
|
|||||||
section.id = 'tileGrid';
|
section.id = 'tileGrid';
|
||||||
section.className = 'tile-grid';
|
section.className = 'tile-grid';
|
||||||
main.appendChild(section);
|
main.appendChild(section);
|
||||||
|
/** The grid's element for one tiled session (its `.tile`), found by its data-session-id. */
|
||||||
|
export const tileEl = (id: string) => section.children.find((el) => el.dataset.sessionId === id) as FakeEl;
|
||||||
|
|
||||||
/** Extra elements `document.querySelector` finds, by exact selector (e.g. '.btn-split'). */
|
/** Extra elements `document.querySelector` finds, by exact selector (e.g. '.btn-split'). */
|
||||||
export const bySelector = new Map<string, FakeEl>();
|
export const bySelector = new Map<string, FakeEl>();
|
||||||
|
|||||||
@@ -18,18 +18,16 @@
|
|||||||
*/
|
*/
|
||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import {
|
import {
|
||||||
FakeEl,
|
|
||||||
FakeTile,
|
FakeTile,
|
||||||
fetchSpy,
|
fetchSpy,
|
||||||
makeGridApp,
|
makeGridApp,
|
||||||
resetGridHarness,
|
resetGridHarness,
|
||||||
section,
|
|
||||||
windowStub,
|
windowStub,
|
||||||
type GridApp,
|
type GridApp,
|
||||||
|
tileEl,
|
||||||
} from './mocks/tile-grid-vm.js';
|
} from './mocks/tile-grid-vm.js';
|
||||||
|
|
||||||
const IDS = ['s-a', 's-b', 's-c'];
|
const IDS = ['s-a', 's-b', 's-c'];
|
||||||
const tileEl = (id: string) => section.children.find((el) => el.dataset.sessionId === id) as FakeEl;
|
|
||||||
const overlayOf = (id: string) => tileEl(id).children[1].children.find((c) => c.className === 'tile-attach') ?? null;
|
const overlayOf = (id: string) => tileEl(id).children[1].children.find((c) => c.className === 'tile-attach') ?? null;
|
||||||
const visible = (id: string) => !!overlayOf(id) && !overlayOf(id)!.hidden;
|
const visible = (id: string) => !!overlayOf(id) && !overlayOf(id)!.hidden;
|
||||||
const textOf = (id: string) => overlayOf(id)!.children[0].textContent;
|
const textOf = (id: string) => overlayOf(id)!.children[0].textContent;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import { resolve } from 'node:path';
|
import { resolve } from 'node:path';
|
||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { FakeEl, FakeTile, makeGridApp, resetGridHarness, section, type GridApp } from './mocks/tile-grid-vm.js';
|
import { FakeTile, makeGridApp, resetGridHarness, section, type GridApp, tileEl } from './mocks/tile-grid-vm.js';
|
||||||
|
|
||||||
const IDS = ['s-a', 's-b'];
|
const IDS = ['s-a', 's-b'];
|
||||||
const addSession = (app: GridApp, id: string, workingDir = '/w') =>
|
const addSession = (app: GridApp, id: string, workingDir = '/w') =>
|
||||||
@@ -52,7 +52,7 @@ describe('Run from this tab', () => {
|
|||||||
app.openTileGrid(IDS);
|
app.openTileGrid(IDS);
|
||||||
addSession(app, 's-new');
|
addSession(app, 's-new');
|
||||||
app._joinTileGridFromRun('s-new');
|
app._joinTileGridFromRun('s-new');
|
||||||
const tile = section.children.find((el) => el.dataset.sessionId === 's-new') as FakeEl;
|
const tile = tileEl('s-new');
|
||||||
const overlay = tile.children[1].children.find((c) => c.className === 'tile-attach');
|
const overlay = tile.children[1].children.find((c) => c.className === 'tile-attach');
|
||||||
expect(!overlay || overlay.hidden).toBe(true);
|
expect(!overlay || overlay.hidden).toBe(true);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import { resolve } from 'node:path';
|
import { resolve } from 'node:path';
|
||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { FakeEl, FakeTile, makeGridApp, resetGridHarness, section, type GridApp } from './mocks/tile-grid-vm.js';
|
import { FakeEl, FakeTile, makeGridApp, resetGridHarness, type GridApp, tileEl } from './mocks/tile-grid-vm.js';
|
||||||
|
|
||||||
const IDS = ['s-a', 's-b', 's-c'];
|
const IDS = ['s-a', 's-b', 's-c'];
|
||||||
|
|
||||||
@@ -38,7 +38,6 @@ function openGrid(): GridApp {
|
|||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tileEl = (id: string) => section.children.find((el) => el.dataset.sessionId === id) as FakeEl;
|
|
||||||
const headerOf = (id: string) => tileEl(id).children[0];
|
const headerOf = (id: string) => tileEl(id).children[0];
|
||||||
const buttonOf = (id: string, cls: string) =>
|
const buttonOf = (id: string, cls: string) =>
|
||||||
headerOf(id).children[2].children.find((b) => b.className.includes(cls)) as FakeEl;
|
headerOf(id).children[2].children.find((b) => b.className.includes(cls)) as FakeEl;
|
||||||
@@ -99,7 +98,7 @@ describe('the header', () => {
|
|||||||
describe('header buttons', () => {
|
describe('header buttons', () => {
|
||||||
it('are ⋯ ⤢ × and nothing else: no + (owner decision 9)', () => {
|
it('are ⋯ ⤢ × and nothing else: no + (owner decision 9)', () => {
|
||||||
const app = openGrid();
|
const app = openGrid();
|
||||||
const tile = section.children.find((el) => el.dataset.sessionId === 's-a') as FakeEl;
|
const tile = tileEl('s-a');
|
||||||
const actions = tile.children[0].children.find((c) => c.className === 'tile-actions') as FakeEl;
|
const actions = tile.children[0].children.find((c) => c.className === 'tile-actions') as FakeEl;
|
||||||
expect(actions.children.map((b) => b.className)).toEqual([
|
expect(actions.children.map((b) => b.className)).toEqual([
|
||||||
'tile-btn tile-menu',
|
'tile-btn tile-menu',
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import {
|
|||||||
resetGridHarness,
|
resetGridHarness,
|
||||||
section,
|
section,
|
||||||
type GridApp,
|
type GridApp,
|
||||||
|
tileEl,
|
||||||
} from './mocks/tile-grid-vm.js';
|
} from './mocks/tile-grid-vm.js';
|
||||||
|
|
||||||
const SIX = ['s-a', 's-b', 's-c', 's-d', 's-e', 's-f'];
|
const SIX = ['s-a', 's-b', 's-c', 's-d', 's-e', 's-f'];
|
||||||
const tileEl = (id: string) => section.children.find((el) => el.dataset.sessionId === id) as FakeEl;
|
|
||||||
const divider = (app: GridApp, key: string) => app._tileGrid.dividers.get(key) as FakeEl;
|
const divider = (app: GridApp, key: string) => app._tileGrid.dividers.get(key) as FakeEl;
|
||||||
const tile = (id: string) => FakeTile.all.find((t) => t.sessionId === id) as FakeTile;
|
const tile = (id: string) => FakeTile.all.find((t) => t.sessionId === id) as FakeTile;
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ import {
|
|||||||
section,
|
section,
|
||||||
windowStub,
|
windowStub,
|
||||||
type GridApp,
|
type GridApp,
|
||||||
|
tileEl,
|
||||||
} from './mocks/tile-grid-vm.js';
|
} from './mocks/tile-grid-vm.js';
|
||||||
|
|
||||||
const IDS = ['s-a', 's-b', 's-c'];
|
const IDS = ['s-a', 's-b', 's-c'];
|
||||||
const tileEl = (id: string) => section.children.find((el) => el.dataset.sessionId === id) as FakeEl;
|
|
||||||
const slots = () => section.children.filter((el) => el.className === 'tile-slot');
|
const slots = () => section.children.filter((el) => el.className === 'tile-slot');
|
||||||
const dragEvent = () => ({ preventDefault: vi.fn(), stopPropagation: vi.fn(), dataTransfer: { dropEffect: '' } });
|
const dragEvent = () => ({ preventDefault: vi.fn(), stopPropagation: vi.fn(), dataTransfer: { dropEffect: '' } });
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,11 @@
|
|||||||
* (`toggleTileGrid`); right-click (contextmenu) opens the picker. With the
|
* (`toggleTileGrid`); right-click (contextmenu) opens the picker. With the
|
||||||
* grid open the picker shows the current tiles, and Open replaces them.
|
* grid open the picker shows the current tiles, and Open replaces them.
|
||||||
*
|
*
|
||||||
* Pure helper via `vm`, the app via the shared harness (test/mocks/tile-grid-vm.ts).
|
* The pure helper and the app both via the shared harness (test/mocks/tile-grid-vm.ts).
|
||||||
* Port: N/A.
|
* Port: N/A.
|
||||||
*/
|
*/
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import { resolve } from 'node:path';
|
import { resolve } from 'node:path';
|
||||||
import vm from 'node:vm';
|
|
||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import {
|
import {
|
||||||
FakeEl,
|
FakeEl,
|
||||||
@@ -25,17 +24,14 @@ import {
|
|||||||
documentAddEventListener,
|
documentAddEventListener,
|
||||||
makeGridApp,
|
makeGridApp,
|
||||||
resetGridHarness,
|
resetGridHarness,
|
||||||
|
windowStub,
|
||||||
} from './mocks/tile-grid-vm.js';
|
} from './mocks/tile-grid-vm.js';
|
||||||
|
|
||||||
type OpenSet = { source: string; ids: string[]; focusedId: string | null } | null;
|
type OpenSet = { source: string; ids: string[]; focusedId: string | null } | null;
|
||||||
type Helpers = { tileGridOpenSet(p: Record<string, unknown>): OpenSet; TILE_GRID_MAX: number };
|
type Helpers = { tileGridOpenSet(p: Record<string, unknown>): OpenSet; TILE_GRID_MAX: number };
|
||||||
|
|
||||||
function loadHelpers(): Helpers {
|
// constants.js as the harness loaded it (window.CodemanTileGrid).
|
||||||
const context = vm.createContext({ window: {}, globalThis: {} });
|
const T = windowStub.CodemanTileGrid as Helpers;
|
||||||
vm.runInContext(readFileSync(resolve(import.meta.dirname, '../src/web/public/constants.js'), 'utf8'), context);
|
|
||||||
return (context.window as { CodemanTileGrid: Helpers }).CodemanTileGrid;
|
|
||||||
}
|
|
||||||
const T = loadHelpers();
|
|
||||||
const INDEX_HTML = readFileSync(resolve(import.meta.dirname, '../src/web/public/index.html'), 'utf8');
|
const INDEX_HTML = readFileSync(resolve(import.meta.dirname, '../src/web/public/index.html'), 'utf8');
|
||||||
|
|
||||||
const order = Array.from({ length: 9 }, (_, i) => `t${i + 1}`);
|
const order = Array.from({ length: 9 }, (_, i) => `t${i + 1}`);
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import {
|
|||||||
localStore,
|
localStore,
|
||||||
makeGridApp,
|
makeGridApp,
|
||||||
resetGridHarness,
|
resetGridHarness,
|
||||||
section,
|
|
||||||
type GridApp,
|
type GridApp,
|
||||||
|
tileEl,
|
||||||
} from './mocks/tile-grid-vm.js';
|
} from './mocks/tile-grid-vm.js';
|
||||||
|
|
||||||
const IDS = ['s-a', 's-b', 's-c'];
|
const IDS = ['s-a', 's-b', 's-c'];
|
||||||
@@ -163,7 +163,7 @@ describe('moving focus between tiles', () => {
|
|||||||
it('pressing a tile is a human selection of its session', async () => {
|
it('pressing a tile is a human selection of its session', async () => {
|
||||||
const app = openGrid();
|
const app = openGrid();
|
||||||
app.selectSession = vi.fn();
|
app.selectSession = vi.fn();
|
||||||
const tileB = section.children.find((el) => el.dataset.sessionId === 's-b');
|
const tileB = tileEl('s-b');
|
||||||
tileB?.dispatch('pointerdown');
|
tileB?.dispatch('pointerdown');
|
||||||
expect(app.selectSession).toHaveBeenCalledWith('s-b');
|
expect(app.selectSession).toHaveBeenCalledWith('s-b');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,10 +16,17 @@
|
|||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import { resolve } from 'node:path';
|
import { resolve } from 'node:path';
|
||||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { FakeEl, FakeTile, makeGridApp, resetGridHarness, section, type GridApp } from './mocks/tile-grid-vm.js';
|
import {
|
||||||
|
FakeEl,
|
||||||
|
FakeTile,
|
||||||
|
makeGridApp,
|
||||||
|
resetGridHarness,
|
||||||
|
section,
|
||||||
|
type GridApp,
|
||||||
|
tileEl,
|
||||||
|
} from './mocks/tile-grid-vm.js';
|
||||||
|
|
||||||
const IDS = ['s-a', 's-b', 's-c', 's-d'];
|
const IDS = ['s-a', 's-b', 's-c', 's-d'];
|
||||||
const tileEl = (id: string) => section.children.find((el) => el.dataset.sessionId === id) as FakeEl;
|
|
||||||
const zoomButton = (id: string) =>
|
const zoomButton = (id: string) =>
|
||||||
tileEl(id).children[0].children[2].children.find((b) => b.className.includes('tile-zoom')) as FakeEl;
|
tileEl(id).children[0].children[2].children.find((b) => b.className.includes('tile-zoom')) as FakeEl;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user