import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as domtools from '../ts/index.js'; const cleanupGlobalDomTools = () => { try { domtools.DomTools.getGlobalDomToolsSync().dispose(); } catch { // No global domtools instance exists yet. } }; const getStyleCount = () => document.head.querySelectorAll('style').length; tap.test('setupDomTools reuses the global singleton', async () => { cleanupGlobalDomTools(); const firstInstance = await domtools.DomTools.setupDomTools(); const secondInstance = await domtools.DomTools.setupDomTools(); expect(firstInstance).toBeInstanceOf(domtools.DomTools); expect(firstInstance === secondInstance).toBeTrue(); expect(domtools.DomTools.getGlobalDomToolsSync() === firstInstance).toBeTrue(); cleanupGlobalDomTools(); }); tap.test('ignoreGlobal creates an isolated instance without replacing the global one', async () => { cleanupGlobalDomTools(); const globalInstance = await domtools.DomTools.setupDomTools(); const isolatedInstance = await domtools.DomTools.setupDomTools({ ignoreGlobal: true, }); await globalInstance.domToolsReady.promise; await globalInstance.domReady.promise; await isolatedInstance.domToolsReady.promise; await isolatedInstance.domReady.promise; expect(globalInstance === isolatedInstance).toBeFalse(); expect(domtools.DomTools.getGlobalDomToolsSync() === globalInstance).toBeTrue(); expect(Boolean(isolatedInstance.keyboard)).toBeTrue(); isolatedInstance.dispose(); cleanupGlobalDomTools(); }); tap.test('runOnce shares the first result across concurrent callers', async () => { cleanupGlobalDomTools(); const domtoolsInstance = await domtools.DomTools.setupDomTools({ ignoreGlobal: true, }); let runCount = 0; const [firstResult, secondResult] = await Promise.all([ domtoolsInstance.runOnce('test-run-once', async () => { runCount += 1; await new Promise((resolve) => window.setTimeout(resolve, 10)); return 'shared-result'; }), domtoolsInstance.runOnce('test-run-once', async () => { runCount += 1; return 'unexpected-result'; }), ]); expect(runCount).toEqual(1); expect(firstResult).toEqual('shared-result'); expect(secondResult).toEqual('shared-result'); domtoolsInstance.dispose(); }); tap.test('elementBasic setup waits for global styles and keeps injection idempotent', async () => { cleanupGlobalDomTools(); const styleCountBefore = getStyleCount(); const firstInstance = await domtools.elementBasic.setup(); const secondInstance = await domtools.elementBasic.setup(); await firstInstance.globalStylesReady.promise; expect(firstInstance === secondInstance).toBeTrue(); expect(getStyleCount() - styleCountBefore).toEqual(1); firstInstance.dispose(); expect(getStyleCount()).toEqual(styleCountBefore); expect(() => domtools.DomTools.getGlobalDomToolsSync()).toThrow(); }); tap.test('keyboard combos still emit through the public key enum API', async () => { const domtoolsInstance = await domtools.DomTools.setupDomTools({ ignoreGlobal: true, }); await domtoolsInstance.domReady.promise; const keyboard = domtoolsInstance.keyboard!; const events: KeyboardEvent[] = []; const subscription = keyboard.on([keyboard.keyEnum.Ctrl, keyboard.keyEnum.S]).subscribe((event) => { events.push(event); }); keyboard.triggerKeyPress([keyboard.keyEnum.Ctrl, keyboard.keyEnum.S]); expect(events).toHaveLength(1); expect(events[0].key).toEqual('s'); expect(events[0].ctrlKey).toBeTrue(); subscription.unsubscribe(); domtoolsInstance.dispose(); }); tap.test('plugin namespace exports remain available for downstream consumers', async () => { expect(domtools.plugins.smartdelay.delayFor).toBeDefined(); expect(domtools.plugins.smartstate.Smartstate).toBeDefined(); expect(domtools.plugins.smartpromise.defer).toBeDefined(); expect(domtools.plugins.smartrouter.SmartRouter).toBeDefined(); expect(domtools.plugins.smartrx.rxjs.Subject).toBeDefined(); expect(domtools.plugins.smarturl.Smarturl).toBeDefined(); }); export default tap.start();