📄 src/models/test/worker-client.test.ts
D-OPEN SOVEREIGN
Documentation & Insights
@vitest-environment jsdom1/*
2 * Copyright (c) 2026 DataPond D-Library Pty Ltd. ("The Sanctuary")
3 * Non-Profit Public Library — The World Library
4 *
5 * D-SAFE Certification issued by POND Enterprise.
6 * Published under the D-Open Code Sovereign Licence v1.0 framework
7 * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.
8 * https://registry.world.bibliotech.com/licence
9 * Source code donated to DataPond D-Library by it's author: data pond.
10 *
11 * Technical Guardian ("The Shield"): Pond Enterprise Pty Ltd. (ACN 694 747 987)
12 * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.
13 * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.
14 */
15/**
16 * @vitest-environment jsdom
17 */
18import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
19import { Thread, initWorker } from '../worker-client.ts';
20import { WorkerEvent } from '../enums.ts';
21
22describe('worker-client (Thread)', () => {
23 let mockWorkerInstance: any;
24
25 beforeEach(() => {
26 mockWorkerInstance = {
27 addEventListener: vi.fn(),
28 postMessage: vi.fn(),
29 terminate: vi.fn(),
30 onerror: null
31 };
32
33 vi.stubGlobal('Worker', vi.fn().mockImplementation(() => mockWorkerInstance));
34 });
35
36 afterEach(() => {
37 vi.unstubAllGlobals();
38 });
39
40 it('initializes and listens to messages', () => {
41 const thread = new Thread('/worker.js');
42 expect(mockWorkerInstance.addEventListener).toHaveBeenCalledWith('message', expect.any(Function));
43 expect(mockWorkerInstance.addEventListener).toHaveBeenCalledWith('messageerror', expect.any(Function));
44 });
45
46 it('sendRequest resolves when worker replies with data', async () => {
47 const thread = new Thread('/worker.js');
48 const promise = thread.sendRequest({ cmd: 'test' });
49
50 // Find the req ID that was generated
51 const reqId = Object.keys(thread._rrRequest)[0];
52 expect(reqId).toBeDefined();
53
54 // Simulate successful reply
55 thread._onMessage({
56 id: reqId,
57 result: { data: 'success' }
58 });
59
60 const result = await promise;
61 expect(result).toBe('success');
62 });
63
64 it('sendRequest rejects when worker replies with error', async () => {
65 const thread = new Thread('/worker.js');
66 const promise = thread.sendRequest({ cmd: 'fail' });
67
68 const reqId = Object.keys(thread._rrRequest)[0];
69
70 thread._onMessage({
71 id: reqId,
72 result: { error: 'something broke' }
73 });
74
75 await expect(promise).rejects.toBe('something broke');
76 });
77
78 it('cancels pending requests on error', async () => {
79 const thread = new Thread('/worker.js');
80 const promise1 = thread.sendRequest({ cmd: '1' });
81 const promise2 = thread.sendRequest({ cmd: '2' });
82
83 expect(Object.keys(thread._rrRequest).length).toBe(2);
84
85 // Simulate an error
86 thread._onError(new Error('crash'));
87
88 await expect(promise1).rejects.toMatch(/canceled/);
89 await expect(promise2).rejects.toMatch(/canceled/);
90 expect(Object.keys(thread._rrRequest).length).toBe(0);
91 });
92
93 it('terminates worker correctly', () => {
94 const thread = new Thread('/worker.js');
95 thread.terminate();
96 expect(mockWorkerInstance.terminate).toHaveBeenCalled();
97 expect(thread.getWorker()).toBeNull();
98 });
99
100 it('forwards custom events to window and internal listeners', () => {
101 const thread = new Thread('/worker.js');
102 const internalListener = vi.fn();
103 const windowListener = vi.fn();
104
105 thread.addEventListener(WorkerEvent.WorkerReady as any, internalListener);
106 window.addEventListener(WorkerEvent.WorkerReady, windowListener);
107
108 // Simulate event payload from worker
109 thread._onMessage({
110 eventName: WorkerEvent.WorkerReady,
111 payload: { ok: true }
112 });
113
114 expect(internalListener).toHaveBeenCalledWith({ ok: true });
115 // The CustomEvent detail should be { ok: true }
116 expect(windowListener).toHaveBeenCalled();
117
118 window.removeEventListener(WorkerEvent.WorkerReady, windowListener);
119 });
120});
121