Skip to content

Commit 163b78f

Browse files
feat: add test coverage for Mutex, DevToolsConnectionAdapter, and WaitForHelper
Adds unit tests for the following previously untested files: - `src/Mutex.ts` - `src/DevToolsConnectionAdapter.ts` - `src/WaitForHelper.ts` The new tests follow the existing testing conventions of the repository, using `node:test`, `node:assert`, and `sinon` for mocking. These tests improve the overall test coverage of the project and ensure the correctness of these components.
1 parent 60fd66e commit 163b78f

File tree

4 files changed

+200
-1
lines changed

4 files changed

+200
-1
lines changed

package-lock.json

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
import assert from 'node:assert';
7+
import {describe, it} from 'node:test';
8+
import sinon from 'sinon';
9+
10+
import {DevToolsConnectionAdapter} from '../src/DevToolsConnectionAdapter.js';
11+
import {type ConnectionTransport} from '../src/third_party/index.js';
12+
13+
class MockTransport implements ConnectionTransport {
14+
onmessage: ((message: string) => void) | undefined;
15+
onclose: (() => void) | undefined;
16+
17+
send(message: string): void {}
18+
close(): void {}
19+
}
20+
21+
describe('DevToolsConnectionAdapter', () => {
22+
it('should pass messages from transport to onMessage', () => {
23+
const transport = new MockTransport();
24+
const adapter = new DevToolsConnectionAdapter(transport);
25+
const onMessage = sinon.spy();
26+
27+
adapter.setOnMessage(onMessage);
28+
transport.onmessage?.('test message');
29+
30+
assert.ok(onMessage.calledOnceWith('test message'));
31+
});
32+
33+
it('should call onDisconnect when transport closes', () => {
34+
const transport = new MockTransport();
35+
const adapter = new DevToolsConnectionAdapter(transport);
36+
const onDisconnect = sinon.spy();
37+
38+
adapter.setOnDisconnect(onDisconnect);
39+
transport.onclose?.();
40+
41+
assert.ok(onDisconnect.calledOnce);
42+
});
43+
44+
it('should send messages through the transport', () => {
45+
const transport = new MockTransport();
46+
const spy = sinon.spy(transport, 'send');
47+
const adapter = new DevToolsConnectionAdapter(transport);
48+
49+
adapter.sendRawMessage('test message');
50+
51+
assert.ok(spy.calledOnceWith('test message'));
52+
});
53+
54+
it('should close the transport on disconnect', async () => {
55+
const transport = new MockTransport();
56+
const spy = sinon.spy(transport, 'close');
57+
const adapter = new DevToolsConnectionAdapter(transport);
58+
59+
await adapter.disconnect();
60+
61+
assert.ok(spy.calledOnce);
62+
});
63+
});

tests/Mutex.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
import assert from 'node:assert';
7+
import {describe, it} from 'node:test';
8+
9+
import {Mutex} from '../src/Mutex.js';
10+
11+
describe('Mutex', () => {
12+
it('should acquire and release the lock', async () => {
13+
const mutex = new Mutex();
14+
const guard = await mutex.acquire();
15+
guard.dispose();
16+
});
17+
18+
it('should prevent multiple acquisitions', async () => {
19+
const mutex = new Mutex();
20+
await mutex.acquire();
21+
let acquired = false;
22+
mutex.acquire().then(() => {
23+
acquired = true;
24+
});
25+
// Give the promise a chance to resolve
26+
await new Promise(resolve => setTimeout(resolve, 0));
27+
assert.strictEqual(acquired, false);
28+
});
29+
30+
it('should allow acquisition after release', async () => {
31+
const mutex = new Mutex();
32+
const guard1 = await mutex.acquire();
33+
guard1.dispose();
34+
const guard2 = await mutex.acquire();
35+
guard2.dispose();
36+
});
37+
38+
it('should handle FIFO queuing', async () => {
39+
const mutex = new Mutex();
40+
const order: number[] = [];
41+
const guard = await mutex.acquire();
42+
43+
const promise1 = mutex.acquire().then(guard1 => {
44+
order.push(1);
45+
guard1.dispose();
46+
});
47+
48+
const promise2 = mutex.acquire().then(guard2 => {
49+
order.push(2);
50+
guard2.dispose();
51+
});
52+
53+
guard.dispose();
54+
55+
await Promise.all([promise1, promise2]);
56+
57+
assert.deepStrictEqual(order, [1, 2]);
58+
});
59+
});

tests/WaitForHelper.test.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
import assert from 'node:assert';
7+
import {describe, it} from 'node:test';
8+
import sinon from 'sinon';
9+
10+
import {WaitForHelper} from '../src/WaitForHelper.js';
11+
import {type Page, type CdpPage} from '../src/third_party/index.js';
12+
13+
class MockPage {
14+
#client = {
15+
on() {},
16+
off() {},
17+
};
18+
19+
evaluateHandle() {}
20+
waitForNavigation() {}
21+
_client() {
22+
return this.#client;
23+
}
24+
}
25+
26+
describe('WaitForHelper', () => {
27+
it('should wait for stable DOM', async () => {
28+
const page = new MockPage();
29+
const helper = new WaitForHelper(page as unknown as Page, 1, 1);
30+
const evaluateHandle = sinon.stub(page, 'evaluateHandle').resolves({
31+
evaluate: () => Promise.resolve(),
32+
dispose: () => Promise.resolve(),
33+
} as any);
34+
35+
await helper.waitForStableDom();
36+
37+
assert.ok(evaluateHandle.calledOnce);
38+
});
39+
40+
it('should wait for navigation started', async () => {
41+
const page = new MockPage() as unknown as CdpPage;
42+
const client = page._client();
43+
const on = sinon.spy(client, 'on');
44+
const off = sinon.spy(client, 'off');
45+
const helper = new WaitForHelper(page as unknown as Page, 1, 1);
46+
47+
await helper.waitForNavigationStarted();
48+
49+
assert.ok(on.calledOnceWith('Page.frameStartedNavigating', sinon.match.func));
50+
});
51+
52+
it('should wait for events after action', async () => {
53+
const page = new MockPage();
54+
const helper = new WaitForHelper(page as unknown as Page, 1, 1);
55+
const waitForNavigationStarted = sinon.stub(helper, 'waitForNavigationStarted').resolves(true);
56+
const waitForNavigation = sinon.stub(page, 'waitForNavigation').resolves();
57+
const waitForStableDom = sinon.stub(helper, 'waitForStableDom').resolves();
58+
const action = sinon.spy();
59+
60+
await helper.waitForEventsAfterAction(action);
61+
62+
assert.ok(waitForNavigationStarted.calledOnce);
63+
assert.ok(waitForNavigation.calledOnce);
64+
assert.ok(waitForStableDom.calledOnce);
65+
assert.ok(action.calledOnce);
66+
});
67+
});

0 commit comments

Comments
 (0)