quake2ts 0.0.562 → 0.0.563
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/test-utils/dist/index.cjs +197 -5
- package/packages/test-utils/dist/index.cjs.map +1 -1
- package/packages/test-utils/dist/index.d.cts +65 -8
- package/packages/test-utils/dist/index.d.ts +65 -8
- package/packages/test-utils/dist/index.js +191 -5
- package/packages/test-utils/dist/index.js.map +1 -1
|
@@ -310,11 +310,14 @@ declare function createMockImageData(width: number, height: number, fillColor?:
|
|
|
310
310
|
*/
|
|
311
311
|
declare function createMockImage(width?: number, height?: number, src?: string): HTMLImageElement;
|
|
312
312
|
|
|
313
|
+
interface NodeSetupOptions {
|
|
314
|
+
polyfillFetch?: boolean;
|
|
315
|
+
}
|
|
313
316
|
/**
|
|
314
317
|
* Sets up a Node.js environment for testing.
|
|
315
318
|
* This is primarily for backend or shared logic that doesn't rely on browser APIs.
|
|
316
319
|
*/
|
|
317
|
-
declare function setupNodeEnvironment(): void;
|
|
320
|
+
declare function setupNodeEnvironment(options?: NodeSetupOptions): void;
|
|
318
321
|
|
|
319
322
|
declare function createMockWebGL2Context(canvas: HTMLCanvasElement): WebGL2RenderingContext;
|
|
320
323
|
|
|
@@ -334,14 +337,14 @@ declare function createMockSessionStorage(initialData?: Record<string, string>):
|
|
|
334
337
|
*/
|
|
335
338
|
declare function createMockIndexedDB(): IDBFactory;
|
|
336
339
|
interface StorageScenario {
|
|
337
|
-
storage: Storage;
|
|
338
|
-
populate(data: Record<string,
|
|
339
|
-
verify(key: string, value:
|
|
340
|
+
storage: Storage | IDBFactory;
|
|
341
|
+
populate(data: Record<string, any>): Promise<void> | void;
|
|
342
|
+
verify(key: string, value: any): Promise<boolean> | boolean;
|
|
340
343
|
}
|
|
341
344
|
/**
|
|
342
345
|
* Helper to setup a storage test scenario.
|
|
343
346
|
*/
|
|
344
|
-
declare function createStorageTestScenario(storageType?: 'local' | 'session'): StorageScenario;
|
|
347
|
+
declare function createStorageTestScenario(storageType?: 'local' | 'session' | 'indexed'): StorageScenario;
|
|
345
348
|
|
|
346
349
|
declare function createMockAudioContext(): AudioContext;
|
|
347
350
|
/**
|
|
@@ -358,8 +361,7 @@ interface AudioEvent {
|
|
|
358
361
|
}
|
|
359
362
|
/**
|
|
360
363
|
* Captures audio operations for verification.
|
|
361
|
-
*
|
|
362
|
-
* This is a placeholder for future implementation.
|
|
364
|
+
* Note: Only works if the context was created via createMockAudioContext which proxies calls.
|
|
363
365
|
*/
|
|
364
366
|
declare function captureAudioEvents(context: AudioContext): AudioEvent[];
|
|
365
367
|
|
|
@@ -452,4 +454,59 @@ declare class InputInjector {
|
|
|
452
454
|
wheel(deltaY: number): void;
|
|
453
455
|
}
|
|
454
456
|
|
|
455
|
-
|
|
457
|
+
interface NetworkSimulator {
|
|
458
|
+
apply(page: any): Promise<void>;
|
|
459
|
+
clear(page: any): Promise<void>;
|
|
460
|
+
}
|
|
461
|
+
type NetworkCondition = 'good' | 'slow' | 'unstable' | 'offline';
|
|
462
|
+
interface NetworkConfig {
|
|
463
|
+
offline: boolean;
|
|
464
|
+
downloadThroughput: number;
|
|
465
|
+
uploadThroughput: number;
|
|
466
|
+
latency: number;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Simulates network conditions using Chrome DevTools Protocol (CDP) via Playwright.
|
|
470
|
+
*/
|
|
471
|
+
declare function simulateNetworkCondition(condition: NetworkCondition): NetworkSimulator;
|
|
472
|
+
/**
|
|
473
|
+
* Creates a custom network condition simulator.
|
|
474
|
+
*
|
|
475
|
+
* @param latency Latency in milliseconds
|
|
476
|
+
* @param jitter Approximate jitter (variation in latency) - Note: CDP doesn't support jitter natively.
|
|
477
|
+
* @param packetLoss Packet loss percentage (0-100) - Ignored for basic CDP emulation.
|
|
478
|
+
*/
|
|
479
|
+
declare function createCustomNetworkCondition(latency: number, jitter?: number, packetLoss?: number, baseConfig?: NetworkConfig): NetworkSimulator;
|
|
480
|
+
/**
|
|
481
|
+
* Throttles bandwidth for the given page.
|
|
482
|
+
*/
|
|
483
|
+
declare function throttleBandwidth(page: any, bytesPerSecond: number): Promise<void>;
|
|
484
|
+
|
|
485
|
+
interface VisualDiff {
|
|
486
|
+
pixelDiff: number;
|
|
487
|
+
diffPath?: string;
|
|
488
|
+
matched: boolean;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Captures a screenshot of the current game state.
|
|
492
|
+
*/
|
|
493
|
+
declare function captureGameScreenshot(page: Page, name: string, options?: {
|
|
494
|
+
dir?: string;
|
|
495
|
+
fullPage?: boolean;
|
|
496
|
+
}): Promise<Buffer>;
|
|
497
|
+
/**
|
|
498
|
+
* Compares two image buffers pixel-by-pixel.
|
|
499
|
+
* Note: A robust implementation would use a library like 'pixelmatch' or 'looks-same'.
|
|
500
|
+
* For now, we provide a basic placeholder or rely on simple buffer comparison.
|
|
501
|
+
*/
|
|
502
|
+
declare function compareScreenshots(baseline: Buffer, current: Buffer, threshold?: number): Promise<VisualDiff>;
|
|
503
|
+
interface VisualScenario {
|
|
504
|
+
capture(name: string): Promise<Buffer>;
|
|
505
|
+
compare(name: string, baselineDir: string): Promise<VisualDiff>;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Creates a helper for visual regression testing scenarios.
|
|
509
|
+
*/
|
|
510
|
+
declare function createVisualTestScenario(page: Page, sceneName: string): VisualScenario;
|
|
511
|
+
|
|
512
|
+
export { type AudioEvent, type BinaryStreamMock, type BinaryWriterMock, type BrowserSetupOptions, type ControlledTimer, type DrawCall, type GameState, type GameStateCapture, InputInjector, type MockEngine, type MockGame, MockPointerLock, type MockRAF, type MockServer, MockTransport, type MockUDPSocket, type NetworkAddress, type NetworkCondition, type NetworkConfig, type NetworkSimulator, type NodeSetupOptions, type PlaywrightOptions, type PlaywrightTestClient, type StorageScenario, type TestContext, type VisualDiff, type VisualScenario, captureAudioEvents, captureCanvasDrawCalls, captureGameScreenshot, captureGameState, compareScreenshots, createBinaryStreamMock, createBinaryWriterMock, createControlledTimer, createCustomNetworkCondition, createEntity, createEntityStateFactory, createGameStateSnapshotFactory, createMockAudioContext, createMockCanvas, createMockCanvasContext2D, createMockEngine, createMockGame, createMockGameState, createMockImage, createMockImageData, createMockIndexedDB, createMockLocalStorage, createMockNetworkAddress, createMockPerformance, createMockRAF, createMockServer, createMockServerClient, createMockServerState, createMockServerStatic, createMockSessionStorage, createMockTransport, createMockUDPSocket, createMockWebGL2Context, createNetChanMock, createPlayerStateFactory, createPlaywrightTestClient, createSpawnContext, createStorageTestScenario, createTestContext, createVisualTestScenario, makeAxisBrush, makeBrushFromMinsMaxs, makeBspModel, makeLeaf, makeLeafModel, makeNode, makePlane, setupBrowserEnvironment, setupMockAudioContext, setupNodeEnvironment, simulateFrames, simulateFramesWithMock, simulateNetworkCondition, teardownBrowserEnvironment, teardownMockAudioContext, throttleBandwidth, waitForGameReady };
|
|
@@ -1080,8 +1080,8 @@ function createMockImage(width, height, src) {
|
|
|
1080
1080
|
}
|
|
1081
1081
|
|
|
1082
1082
|
// src/setup/node.ts
|
|
1083
|
-
function setupNodeEnvironment() {
|
|
1084
|
-
if (typeof global.fetch === "undefined") {
|
|
1083
|
+
function setupNodeEnvironment(options = {}) {
|
|
1084
|
+
if (options.polyfillFetch && typeof global.fetch === "undefined") {
|
|
1085
1085
|
}
|
|
1086
1086
|
}
|
|
1087
1087
|
|
|
@@ -1110,6 +1110,61 @@ function createMockIndexedDB() {
|
|
|
1110
1110
|
return indexedDB;
|
|
1111
1111
|
}
|
|
1112
1112
|
function createStorageTestScenario(storageType = "local") {
|
|
1113
|
+
if (storageType === "indexed") {
|
|
1114
|
+
const dbName = `test-db-${Math.random().toString(36).substring(7)}`;
|
|
1115
|
+
const storeName = "test-store";
|
|
1116
|
+
const storage2 = createMockIndexedDB();
|
|
1117
|
+
return {
|
|
1118
|
+
storage: storage2,
|
|
1119
|
+
populate: async (data) => {
|
|
1120
|
+
return new Promise((resolve, reject) => {
|
|
1121
|
+
const req = storage2.open(dbName, 1);
|
|
1122
|
+
req.onupgradeneeded = (e) => {
|
|
1123
|
+
const db = e.target.result;
|
|
1124
|
+
db.createObjectStore(storeName);
|
|
1125
|
+
};
|
|
1126
|
+
req.onsuccess = (e) => {
|
|
1127
|
+
const db = e.target.result;
|
|
1128
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
1129
|
+
const store = tx.objectStore(storeName);
|
|
1130
|
+
Object.entries(data).forEach(([k, v]) => store.put(v, k));
|
|
1131
|
+
tx.oncomplete = () => {
|
|
1132
|
+
db.close();
|
|
1133
|
+
resolve();
|
|
1134
|
+
};
|
|
1135
|
+
tx.onerror = () => reject(tx.error);
|
|
1136
|
+
};
|
|
1137
|
+
req.onerror = () => reject(req.error);
|
|
1138
|
+
});
|
|
1139
|
+
},
|
|
1140
|
+
verify: async (key, value) => {
|
|
1141
|
+
return new Promise((resolve, reject) => {
|
|
1142
|
+
const req = storage2.open(dbName, 1);
|
|
1143
|
+
req.onsuccess = (e) => {
|
|
1144
|
+
const db = e.target.result;
|
|
1145
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
1146
|
+
db.close();
|
|
1147
|
+
resolve(false);
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
const tx = db.transaction(storeName, "readonly");
|
|
1151
|
+
const store = tx.objectStore(storeName);
|
|
1152
|
+
const getReq = store.get(key);
|
|
1153
|
+
getReq.onsuccess = () => {
|
|
1154
|
+
const result = getReq.result === value;
|
|
1155
|
+
db.close();
|
|
1156
|
+
resolve(result);
|
|
1157
|
+
};
|
|
1158
|
+
getReq.onerror = () => {
|
|
1159
|
+
db.close();
|
|
1160
|
+
resolve(false);
|
|
1161
|
+
};
|
|
1162
|
+
};
|
|
1163
|
+
req.onerror = () => reject(req.error);
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1113
1168
|
const storage = storageType === "local" ? createMockLocalStorage() : createMockSessionStorage();
|
|
1114
1169
|
return {
|
|
1115
1170
|
storage,
|
|
@@ -1124,7 +1179,7 @@ function createStorageTestScenario(storageType = "local") {
|
|
|
1124
1179
|
|
|
1125
1180
|
// src/setup/audio.ts
|
|
1126
1181
|
function createMockAudioContext() {
|
|
1127
|
-
|
|
1182
|
+
const context = {
|
|
1128
1183
|
createGain: () => ({
|
|
1129
1184
|
connect: () => {
|
|
1130
1185
|
},
|
|
@@ -1173,8 +1228,23 @@ function createMockAudioContext() {
|
|
|
1173
1228
|
sampleRate,
|
|
1174
1229
|
numberOfChannels: channels,
|
|
1175
1230
|
getChannelData: () => new Float32Array(length)
|
|
1176
|
-
})
|
|
1231
|
+
}),
|
|
1232
|
+
// Helper to track events if needed
|
|
1233
|
+
_events: []
|
|
1177
1234
|
};
|
|
1235
|
+
return new Proxy(context, {
|
|
1236
|
+
get(target, prop, receiver) {
|
|
1237
|
+
if (prop === "_events") return target._events;
|
|
1238
|
+
const value = Reflect.get(target, prop, receiver);
|
|
1239
|
+
if (typeof value === "function") {
|
|
1240
|
+
return (...args) => {
|
|
1241
|
+
target._events.push({ type: String(prop), args });
|
|
1242
|
+
return Reflect.apply(value, target, args);
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
return value;
|
|
1246
|
+
}
|
|
1247
|
+
});
|
|
1178
1248
|
}
|
|
1179
1249
|
function setupMockAudioContext() {
|
|
1180
1250
|
if (typeof global.AudioContext === "undefined" && typeof global.window !== "undefined") {
|
|
@@ -1195,7 +1265,7 @@ function teardownMockAudioContext() {
|
|
|
1195
1265
|
}
|
|
1196
1266
|
}
|
|
1197
1267
|
function captureAudioEvents(context) {
|
|
1198
|
-
return [];
|
|
1268
|
+
return context._events || [];
|
|
1199
1269
|
}
|
|
1200
1270
|
|
|
1201
1271
|
// src/setup/timing.ts
|
|
@@ -1487,16 +1557,129 @@ async function captureGameState(page) {
|
|
|
1487
1557
|
return {};
|
|
1488
1558
|
});
|
|
1489
1559
|
}
|
|
1560
|
+
|
|
1561
|
+
// src/e2e/network.ts
|
|
1562
|
+
var CONDITIONS = {
|
|
1563
|
+
"good": {
|
|
1564
|
+
offline: false,
|
|
1565
|
+
downloadThroughput: 10 * 1024 * 1024,
|
|
1566
|
+
// 10 Mbps
|
|
1567
|
+
uploadThroughput: 5 * 1024 * 1024,
|
|
1568
|
+
// 5 Mbps
|
|
1569
|
+
latency: 20
|
|
1570
|
+
},
|
|
1571
|
+
"slow": {
|
|
1572
|
+
offline: false,
|
|
1573
|
+
downloadThroughput: 500 * 1024,
|
|
1574
|
+
// 500 Kbps
|
|
1575
|
+
uploadThroughput: 500 * 1024,
|
|
1576
|
+
latency: 400
|
|
1577
|
+
},
|
|
1578
|
+
"unstable": {
|
|
1579
|
+
offline: false,
|
|
1580
|
+
downloadThroughput: 1 * 1024 * 1024,
|
|
1581
|
+
uploadThroughput: 1 * 1024 * 1024,
|
|
1582
|
+
latency: 100
|
|
1583
|
+
},
|
|
1584
|
+
"offline": {
|
|
1585
|
+
offline: true,
|
|
1586
|
+
downloadThroughput: 0,
|
|
1587
|
+
uploadThroughput: 0,
|
|
1588
|
+
latency: 0
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
function simulateNetworkCondition(condition) {
|
|
1592
|
+
const config = CONDITIONS[condition];
|
|
1593
|
+
return createCustomNetworkCondition(config.latency, 0, 0, config);
|
|
1594
|
+
}
|
|
1595
|
+
function createCustomNetworkCondition(latency, jitter = 0, packetLoss = 0, baseConfig) {
|
|
1596
|
+
return {
|
|
1597
|
+
async apply(page) {
|
|
1598
|
+
const client = await page.context().newCDPSession(page);
|
|
1599
|
+
await client.send("Network.enable");
|
|
1600
|
+
await client.send("Network.emulateNetworkConditions", {
|
|
1601
|
+
offline: baseConfig?.offline || false,
|
|
1602
|
+
latency: latency + Math.random() * jitter,
|
|
1603
|
+
downloadThroughput: baseConfig?.downloadThroughput || -1,
|
|
1604
|
+
uploadThroughput: baseConfig?.uploadThroughput || -1
|
|
1605
|
+
});
|
|
1606
|
+
},
|
|
1607
|
+
async clear(page) {
|
|
1608
|
+
const client = await page.context().newCDPSession(page);
|
|
1609
|
+
await client.send("Network.emulateNetworkConditions", {
|
|
1610
|
+
offline: false,
|
|
1611
|
+
latency: 0,
|
|
1612
|
+
downloadThroughput: -1,
|
|
1613
|
+
uploadThroughput: -1
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
async function throttleBandwidth(page, bytesPerSecond) {
|
|
1619
|
+
const simulator = createCustomNetworkCondition(0, 0, 0, {
|
|
1620
|
+
offline: false,
|
|
1621
|
+
latency: 0,
|
|
1622
|
+
downloadThroughput: bytesPerSecond,
|
|
1623
|
+
uploadThroughput: bytesPerSecond
|
|
1624
|
+
});
|
|
1625
|
+
await simulator.apply(page);
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
// src/e2e/visual.ts
|
|
1629
|
+
import path from "path";
|
|
1630
|
+
import fs from "fs/promises";
|
|
1631
|
+
async function captureGameScreenshot(page, name, options = {}) {
|
|
1632
|
+
const dir = options.dir || "__screenshots__";
|
|
1633
|
+
const screenshotPath = path.join(dir, `${name}.png`);
|
|
1634
|
+
await fs.mkdir(dir, { recursive: true });
|
|
1635
|
+
return await page.screenshot({
|
|
1636
|
+
path: screenshotPath,
|
|
1637
|
+
fullPage: options.fullPage ?? false,
|
|
1638
|
+
animations: "disabled",
|
|
1639
|
+
caret: "hide"
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
async function compareScreenshots(baseline, current, threshold = 0.1) {
|
|
1643
|
+
if (baseline.equals(current)) {
|
|
1644
|
+
return { pixelDiff: 0, matched: true };
|
|
1645
|
+
}
|
|
1646
|
+
return {
|
|
1647
|
+
pixelDiff: -1,
|
|
1648
|
+
// Unknown magnitude
|
|
1649
|
+
matched: false
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
function createVisualTestScenario(page, sceneName) {
|
|
1653
|
+
return {
|
|
1654
|
+
async capture(snapshotName) {
|
|
1655
|
+
return await captureGameScreenshot(page, `${sceneName}-${snapshotName}`);
|
|
1656
|
+
},
|
|
1657
|
+
async compare(snapshotName, baselineDir) {
|
|
1658
|
+
const name = `${sceneName}-${snapshotName}`;
|
|
1659
|
+
const current = await captureGameScreenshot(page, name, { dir: "__screenshots__/current" });
|
|
1660
|
+
try {
|
|
1661
|
+
const baselinePath = path.join(baselineDir, `${name}.png`);
|
|
1662
|
+
const baseline = await fs.readFile(baselinePath);
|
|
1663
|
+
return await compareScreenshots(baseline, current);
|
|
1664
|
+
} catch (e) {
|
|
1665
|
+
return { pixelDiff: -1, matched: false };
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1490
1670
|
export {
|
|
1491
1671
|
InputInjector,
|
|
1492
1672
|
MockPointerLock,
|
|
1493
1673
|
MockTransport,
|
|
1494
1674
|
captureAudioEvents,
|
|
1495
1675
|
captureCanvasDrawCalls,
|
|
1676
|
+
captureGameScreenshot,
|
|
1496
1677
|
captureGameState,
|
|
1678
|
+
compareScreenshots,
|
|
1497
1679
|
createBinaryStreamMock,
|
|
1498
1680
|
createBinaryWriterMock,
|
|
1499
1681
|
createControlledTimer,
|
|
1682
|
+
createCustomNetworkCondition,
|
|
1500
1683
|
createEntity,
|
|
1501
1684
|
createEntityStateFactory,
|
|
1502
1685
|
createGameStateSnapshotFactory,
|
|
@@ -1527,6 +1710,7 @@ export {
|
|
|
1527
1710
|
createSpawnContext,
|
|
1528
1711
|
createStorageTestScenario,
|
|
1529
1712
|
createTestContext,
|
|
1713
|
+
createVisualTestScenario,
|
|
1530
1714
|
intersects,
|
|
1531
1715
|
ladderTrace,
|
|
1532
1716
|
makeAxisBrush,
|
|
@@ -1541,9 +1725,11 @@ export {
|
|
|
1541
1725
|
setupNodeEnvironment,
|
|
1542
1726
|
simulateFrames,
|
|
1543
1727
|
simulateFramesWithMock,
|
|
1728
|
+
simulateNetworkCondition,
|
|
1544
1729
|
stairTrace,
|
|
1545
1730
|
teardownBrowserEnvironment,
|
|
1546
1731
|
teardownMockAudioContext,
|
|
1732
|
+
throttleBandwidth,
|
|
1547
1733
|
waitForGameReady
|
|
1548
1734
|
};
|
|
1549
1735
|
//# sourceMappingURL=index.js.map
|