2026-09-20 11:55:23 +02:00

100 lines
2.8 KiB
TypeScript

import { expect } from '../framework/expect';
import { describe, test } from '../framework/registry';
import { waitFor } from './wait';
// Events.
// Listeners are registered with `on`, triggered by mutating state, and removed
// with `off`. Callbacks are debounced (~10ms), so the tests wait before asserting.
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
describe('Events', () => {
test('selectionchange fires with the selected ids', async (ctx) => {
const rect = ctx.penpot.createRectangle();
ctx.board.appendChild(rect);
let received: string[] | null = null;
const listenerId = ctx.penpot.on('selectionchange', (ids) => {
received = ids;
});
ctx.penpot.selection = [rect];
await waitFor(() => received !== null);
ctx.penpot.off(listenerId);
expect(received).not.toBeNull();
if (received) {
expect((received as string[]).includes(rect.id)).toBe(true);
}
});
test('shapechange fires when the observed shape changes', async (ctx) => {
const rect = ctx.penpot.createRectangle();
ctx.board.appendChild(rect);
let fired = false;
const listenerId = ctx.penpot.on(
'shapechange',
() => {
fired = true;
},
{ shapeId: rect.id },
);
rect.name = 'changed-name';
await waitFor(() => fired);
ctx.penpot.off(listenerId);
expect(fired).toBe(true);
});
test('off stops further notifications', async (ctx) => {
const rect = ctx.penpot.createRectangle();
ctx.board.appendChild(rect);
let count = 0;
const listenerId = ctx.penpot.on('selectionchange', () => {
count += 1;
});
ctx.penpot.off(listenerId);
ctx.penpot.selection = [rect];
// Asserting a non-event: there is no positive condition to poll for, so
// give the debounce a fixed window to (not) fire.
await sleep(150);
expect(count).toBe(0);
});
test('a blank shapeId leaves the other listeners working', async (ctx) => {
const rect = ctx.penpot.createRectangle();
ctx.board.appendChild(rect);
// Listeners are store watches notified by a plain iteration, so one that
// raises aborts the loop and the listeners after it miss the change.
const blankListenerId = ctx.penpot.on('shapechange', () => {}, {
shapeId: '',
});
let received: string[] | null = null;
const listenerId = ctx.penpot.on('selectionchange', (ids) => {
received = ids;
});
ctx.penpot.selection = [rect];
await waitFor(() => received !== null);
ctx.penpot.off(listenerId);
ctx.penpot.off(blankListenerId);
expect(received).not.toBeNull();
});
test('a malformed shapeId is rejected when the listener is registered', (ctx) => {
expect(() =>
ctx.penpot.on('shapechange', () => {}, { shapeId: 'not-a-uuid' }),
).toThrow();
});
});