Skip to content

Commit 62d8648

Browse files
committed
test(randomUUID): cover native and fallback paths; assert RFC4122 v4 shape
1 parent 58e8315 commit 62d8648

File tree

3 files changed

+133
-62
lines changed

3 files changed

+133
-62
lines changed

packages/agents-core/src/shims/shims-browser.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,19 @@ export class BrowserEventEmitter<
8383
export { BrowserEventEmitter as RuntimeEventEmitter };
8484

8585
export const randomUUID: () => `${string}-${string}-${string}-${string}-${string}` =
86-
(typeof crypto !== 'undefined' && crypto.randomUUID)
87-
? crypto.randomUUID.bind(crypto)
88-
: () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
89-
const r = Math.random() * 16 | 0;
90-
const v = c === 'x' ? r : (r & 0x3 | 0x8);
91-
return v.toString(16);
92-
}) as `${string}-${string}-${string}-${string}-${string}`;
86+
() => {
87+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
88+
return crypto.randomUUID();
89+
}
90+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
91+
/[xy]/g,
92+
function (c) {
93+
const r = (Math.random() * 16) | 0;
94+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
95+
return v.toString(16);
96+
},
97+
) as `${string}-${string}-${string}-${string}-${string}`;
98+
};
9399
export const Readable = class Readable {
94100
constructor() {}
95101
pipeTo(

packages/agents-core/test/shims/browser-event-emitter.test.ts

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { describe, expect, test, vi } from 'vitest';
2+
3+
import { BrowserEventEmitter, randomUUID } from '../../src/shims/shims-browser';
4+
5+
describe('BrowserEventEmitter', () => {
6+
test('off removes previously registered listener', () => {
7+
const emitter = new BrowserEventEmitter<{ foo: [string] }>();
8+
const calls: string[] = [];
9+
10+
const handler = (value: string) => {
11+
calls.push(value);
12+
};
13+
14+
emitter.on('foo', handler);
15+
emitter.emit('foo', 'first');
16+
emitter.off('foo', handler);
17+
emitter.emit('foo', 'second');
18+
19+
expect(calls).toEqual(['first']);
20+
});
21+
22+
test('once triggers listener only once', () => {
23+
const emitter = new BrowserEventEmitter<{ foo: [string] }>();
24+
let callCount = 0;
25+
26+
emitter.once('foo', () => {
27+
callCount += 1;
28+
});
29+
30+
emitter.emit('foo', 'first');
31+
emitter.emit('foo', 'second');
32+
33+
expect(callCount).toBe(1);
34+
});
35+
36+
test('multiple identical listeners fire for each registration and are removed by off', () => {
37+
const emitter = new BrowserEventEmitter<{ foo: [string] }>();
38+
const calls: string[] = [];
39+
40+
const handler = (value: string) => {
41+
calls.push(value);
42+
};
43+
44+
emitter.on('foo', handler);
45+
emitter.on('foo', handler);
46+
47+
emitter.emit('foo', 'first');
48+
expect(calls).toEqual(['first', 'first']);
49+
50+
emitter.off('foo', handler);
51+
emitter.emit('foo', 'second');
52+
53+
expect(calls).toEqual(['first', 'first']);
54+
});
55+
});
56+
57+
describe('randomUUID', () => {
58+
test('uses native crypto.randomUUID when available', () => {
59+
const mockUUID = '12345678-1234-1234-1234-123456789abc';
60+
const originalCrypto = global.crypto;
61+
62+
Object.defineProperty(global, 'crypto', {
63+
value: { randomUUID: vi.fn(() => mockUUID) },
64+
configurable: true,
65+
});
66+
67+
const result = randomUUID();
68+
expect(result).toBe(mockUUID);
69+
expect(global.crypto.randomUUID).toHaveBeenCalled();
70+
71+
Object.defineProperty(global, 'crypto', {
72+
value: originalCrypto,
73+
configurable: true,
74+
});
75+
});
76+
77+
test('uses fallback when crypto.randomUUID is unavailable', () => {
78+
const originalCrypto = global.crypto;
79+
80+
Object.defineProperty(global, 'crypto', {
81+
value: undefined,
82+
configurable: true,
83+
});
84+
85+
const result = randomUUID();
86+
expect(result).toMatch(
87+
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
88+
);
89+
90+
Object.defineProperty(global, 'crypto', {
91+
value: originalCrypto,
92+
configurable: true,
93+
});
94+
});
95+
96+
test('fallback generates valid UUID v4 format', () => {
97+
const originalCrypto = global.crypto;
98+
99+
Object.defineProperty(global, 'crypto', {
100+
value: undefined,
101+
configurable: true,
102+
});
103+
104+
const uuids = Array.from({ length: 10 }, () => randomUUID());
105+
106+
uuids.forEach((uuid) => {
107+
expect(uuid).toMatch(
108+
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
109+
);
110+
});
111+
112+
const uniqueUUIDs = new Set(uuids);
113+
expect(uniqueUUIDs.size).toBe(uuids.length);
114+
115+
Object.defineProperty(global, 'crypto', {
116+
value: originalCrypto,
117+
configurable: true,
118+
});
119+
});
120+
});

0 commit comments

Comments
 (0)