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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quake2ts",
3
- "version": "0.0.562",
3
+ "version": "0.0.563",
4
4
  "description": "Quake II re-release port to TypeScript with WebGL renderer - A complete game engine with physics, networking, and BSP rendering",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -35,10 +35,13 @@ __export(index_exports, {
35
35
  MockTransport: () => MockTransport,
36
36
  captureAudioEvents: () => captureAudioEvents,
37
37
  captureCanvasDrawCalls: () => captureCanvasDrawCalls,
38
+ captureGameScreenshot: () => captureGameScreenshot,
38
39
  captureGameState: () => captureGameState,
40
+ compareScreenshots: () => compareScreenshots,
39
41
  createBinaryStreamMock: () => createBinaryStreamMock,
40
42
  createBinaryWriterMock: () => createBinaryWriterMock,
41
43
  createControlledTimer: () => createControlledTimer,
44
+ createCustomNetworkCondition: () => createCustomNetworkCondition,
42
45
  createEntity: () => createEntity,
43
46
  createEntityStateFactory: () => createEntityStateFactory,
44
47
  createGameStateSnapshotFactory: () => createGameStateSnapshotFactory,
@@ -69,6 +72,7 @@ __export(index_exports, {
69
72
  createSpawnContext: () => createSpawnContext,
70
73
  createStorageTestScenario: () => createStorageTestScenario,
71
74
  createTestContext: () => createTestContext,
75
+ createVisualTestScenario: () => createVisualTestScenario,
72
76
  intersects: () => import_shared3.intersects,
73
77
  ladderTrace: () => import_shared3.ladderTrace,
74
78
  makeAxisBrush: () => makeAxisBrush,
@@ -83,9 +87,11 @@ __export(index_exports, {
83
87
  setupNodeEnvironment: () => setupNodeEnvironment,
84
88
  simulateFrames: () => simulateFrames,
85
89
  simulateFramesWithMock: () => simulateFramesWithMock,
90
+ simulateNetworkCondition: () => simulateNetworkCondition,
86
91
  stairTrace: () => import_shared3.stairTrace,
87
92
  teardownBrowserEnvironment: () => teardownBrowserEnvironment,
88
93
  teardownMockAudioContext: () => teardownMockAudioContext,
94
+ throttleBandwidth: () => throttleBandwidth,
89
95
  waitForGameReady: () => waitForGameReady
90
96
  });
91
97
  module.exports = __toCommonJS(index_exports);
@@ -1169,8 +1175,8 @@ function createMockImage(width, height, src) {
1169
1175
  }
1170
1176
 
1171
1177
  // src/setup/node.ts
1172
- function setupNodeEnvironment() {
1173
- if (typeof global.fetch === "undefined") {
1178
+ function setupNodeEnvironment(options = {}) {
1179
+ if (options.polyfillFetch && typeof global.fetch === "undefined") {
1174
1180
  }
1175
1181
  }
1176
1182
 
@@ -1199,6 +1205,61 @@ function createMockIndexedDB() {
1199
1205
  return indexedDB;
1200
1206
  }
1201
1207
  function createStorageTestScenario(storageType = "local") {
1208
+ if (storageType === "indexed") {
1209
+ const dbName = `test-db-${Math.random().toString(36).substring(7)}`;
1210
+ const storeName = "test-store";
1211
+ const storage2 = createMockIndexedDB();
1212
+ return {
1213
+ storage: storage2,
1214
+ populate: async (data) => {
1215
+ return new Promise((resolve, reject) => {
1216
+ const req = storage2.open(dbName, 1);
1217
+ req.onupgradeneeded = (e) => {
1218
+ const db = e.target.result;
1219
+ db.createObjectStore(storeName);
1220
+ };
1221
+ req.onsuccess = (e) => {
1222
+ const db = e.target.result;
1223
+ const tx = db.transaction(storeName, "readwrite");
1224
+ const store = tx.objectStore(storeName);
1225
+ Object.entries(data).forEach(([k, v]) => store.put(v, k));
1226
+ tx.oncomplete = () => {
1227
+ db.close();
1228
+ resolve();
1229
+ };
1230
+ tx.onerror = () => reject(tx.error);
1231
+ };
1232
+ req.onerror = () => reject(req.error);
1233
+ });
1234
+ },
1235
+ verify: async (key, value) => {
1236
+ return new Promise((resolve, reject) => {
1237
+ const req = storage2.open(dbName, 1);
1238
+ req.onsuccess = (e) => {
1239
+ const db = e.target.result;
1240
+ if (!db.objectStoreNames.contains(storeName)) {
1241
+ db.close();
1242
+ resolve(false);
1243
+ return;
1244
+ }
1245
+ const tx = db.transaction(storeName, "readonly");
1246
+ const store = tx.objectStore(storeName);
1247
+ const getReq = store.get(key);
1248
+ getReq.onsuccess = () => {
1249
+ const result = getReq.result === value;
1250
+ db.close();
1251
+ resolve(result);
1252
+ };
1253
+ getReq.onerror = () => {
1254
+ db.close();
1255
+ resolve(false);
1256
+ };
1257
+ };
1258
+ req.onerror = () => reject(req.error);
1259
+ });
1260
+ }
1261
+ };
1262
+ }
1202
1263
  const storage = storageType === "local" ? createMockLocalStorage() : createMockSessionStorage();
1203
1264
  return {
1204
1265
  storage,
@@ -1213,7 +1274,7 @@ function createStorageTestScenario(storageType = "local") {
1213
1274
 
1214
1275
  // src/setup/audio.ts
1215
1276
  function createMockAudioContext() {
1216
- return {
1277
+ const context = {
1217
1278
  createGain: () => ({
1218
1279
  connect: () => {
1219
1280
  },
@@ -1262,8 +1323,23 @@ function createMockAudioContext() {
1262
1323
  sampleRate,
1263
1324
  numberOfChannels: channels,
1264
1325
  getChannelData: () => new Float32Array(length)
1265
- })
1326
+ }),
1327
+ // Helper to track events if needed
1328
+ _events: []
1266
1329
  };
1330
+ return new Proxy(context, {
1331
+ get(target, prop, receiver) {
1332
+ if (prop === "_events") return target._events;
1333
+ const value = Reflect.get(target, prop, receiver);
1334
+ if (typeof value === "function") {
1335
+ return (...args) => {
1336
+ target._events.push({ type: String(prop), args });
1337
+ return Reflect.apply(value, target, args);
1338
+ };
1339
+ }
1340
+ return value;
1341
+ }
1342
+ });
1267
1343
  }
1268
1344
  function setupMockAudioContext() {
1269
1345
  if (typeof global.AudioContext === "undefined" && typeof global.window !== "undefined") {
@@ -1284,7 +1360,7 @@ function teardownMockAudioContext() {
1284
1360
  }
1285
1361
  }
1286
1362
  function captureAudioEvents(context) {
1287
- return [];
1363
+ return context._events || [];
1288
1364
  }
1289
1365
 
1290
1366
  // src/setup/timing.ts
@@ -1576,6 +1652,116 @@ async function captureGameState(page) {
1576
1652
  return {};
1577
1653
  });
1578
1654
  }
1655
+
1656
+ // src/e2e/network.ts
1657
+ var CONDITIONS = {
1658
+ "good": {
1659
+ offline: false,
1660
+ downloadThroughput: 10 * 1024 * 1024,
1661
+ // 10 Mbps
1662
+ uploadThroughput: 5 * 1024 * 1024,
1663
+ // 5 Mbps
1664
+ latency: 20
1665
+ },
1666
+ "slow": {
1667
+ offline: false,
1668
+ downloadThroughput: 500 * 1024,
1669
+ // 500 Kbps
1670
+ uploadThroughput: 500 * 1024,
1671
+ latency: 400
1672
+ },
1673
+ "unstable": {
1674
+ offline: false,
1675
+ downloadThroughput: 1 * 1024 * 1024,
1676
+ uploadThroughput: 1 * 1024 * 1024,
1677
+ latency: 100
1678
+ },
1679
+ "offline": {
1680
+ offline: true,
1681
+ downloadThroughput: 0,
1682
+ uploadThroughput: 0,
1683
+ latency: 0
1684
+ }
1685
+ };
1686
+ function simulateNetworkCondition(condition) {
1687
+ const config = CONDITIONS[condition];
1688
+ return createCustomNetworkCondition(config.latency, 0, 0, config);
1689
+ }
1690
+ function createCustomNetworkCondition(latency, jitter = 0, packetLoss = 0, baseConfig) {
1691
+ return {
1692
+ async apply(page) {
1693
+ const client = await page.context().newCDPSession(page);
1694
+ await client.send("Network.enable");
1695
+ await client.send("Network.emulateNetworkConditions", {
1696
+ offline: baseConfig?.offline || false,
1697
+ latency: latency + Math.random() * jitter,
1698
+ downloadThroughput: baseConfig?.downloadThroughput || -1,
1699
+ uploadThroughput: baseConfig?.uploadThroughput || -1
1700
+ });
1701
+ },
1702
+ async clear(page) {
1703
+ const client = await page.context().newCDPSession(page);
1704
+ await client.send("Network.emulateNetworkConditions", {
1705
+ offline: false,
1706
+ latency: 0,
1707
+ downloadThroughput: -1,
1708
+ uploadThroughput: -1
1709
+ });
1710
+ }
1711
+ };
1712
+ }
1713
+ async function throttleBandwidth(page, bytesPerSecond) {
1714
+ const simulator = createCustomNetworkCondition(0, 0, 0, {
1715
+ offline: false,
1716
+ latency: 0,
1717
+ downloadThroughput: bytesPerSecond,
1718
+ uploadThroughput: bytesPerSecond
1719
+ });
1720
+ await simulator.apply(page);
1721
+ }
1722
+
1723
+ // src/e2e/visual.ts
1724
+ var import_path = __toESM(require("path"), 1);
1725
+ var import_promises = __toESM(require("fs/promises"), 1);
1726
+ async function captureGameScreenshot(page, name, options = {}) {
1727
+ const dir = options.dir || "__screenshots__";
1728
+ const screenshotPath = import_path.default.join(dir, `${name}.png`);
1729
+ await import_promises.default.mkdir(dir, { recursive: true });
1730
+ return await page.screenshot({
1731
+ path: screenshotPath,
1732
+ fullPage: options.fullPage ?? false,
1733
+ animations: "disabled",
1734
+ caret: "hide"
1735
+ });
1736
+ }
1737
+ async function compareScreenshots(baseline, current, threshold = 0.1) {
1738
+ if (baseline.equals(current)) {
1739
+ return { pixelDiff: 0, matched: true };
1740
+ }
1741
+ return {
1742
+ pixelDiff: -1,
1743
+ // Unknown magnitude
1744
+ matched: false
1745
+ };
1746
+ }
1747
+ function createVisualTestScenario(page, sceneName) {
1748
+ return {
1749
+ async capture(snapshotName) {
1750
+ return await captureGameScreenshot(page, `${sceneName}-${snapshotName}`);
1751
+ },
1752
+ async compare(snapshotName, baselineDir) {
1753
+ const name = `${sceneName}-${snapshotName}`;
1754
+ const current = await captureGameScreenshot(page, name, { dir: "__screenshots__/current" });
1755
+ try {
1756
+ const baselinePath = import_path.default.join(baselineDir, `${name}.png`);
1757
+ const baseline = await import_promises.default.readFile(baselinePath);
1758
+ return await compareScreenshots(baseline, current);
1759
+ } catch (e) {
1760
+ return { pixelDiff: -1, matched: false };
1761
+ }
1762
+ }
1763
+ };
1764
+ }
1579
1765
  // Annotate the CommonJS export names for ESM import in node:
1580
1766
  0 && (module.exports = {
1581
1767
  InputInjector,
@@ -1583,10 +1769,13 @@ async function captureGameState(page) {
1583
1769
  MockTransport,
1584
1770
  captureAudioEvents,
1585
1771
  captureCanvasDrawCalls,
1772
+ captureGameScreenshot,
1586
1773
  captureGameState,
1774
+ compareScreenshots,
1587
1775
  createBinaryStreamMock,
1588
1776
  createBinaryWriterMock,
1589
1777
  createControlledTimer,
1778
+ createCustomNetworkCondition,
1590
1779
  createEntity,
1591
1780
  createEntityStateFactory,
1592
1781
  createGameStateSnapshotFactory,
@@ -1617,6 +1806,7 @@ async function captureGameState(page) {
1617
1806
  createSpawnContext,
1618
1807
  createStorageTestScenario,
1619
1808
  createTestContext,
1809
+ createVisualTestScenario,
1620
1810
  intersects,
1621
1811
  ladderTrace,
1622
1812
  makeAxisBrush,
@@ -1631,9 +1821,11 @@ async function captureGameState(page) {
1631
1821
  setupNodeEnvironment,
1632
1822
  simulateFrames,
1633
1823
  simulateFramesWithMock,
1824
+ simulateNetworkCondition,
1634
1825
  stairTrace,
1635
1826
  teardownBrowserEnvironment,
1636
1827
  teardownMockAudioContext,
1828
+ throttleBandwidth,
1637
1829
  waitForGameReady
1638
1830
  });
1639
1831
  //# sourceMappingURL=index.cjs.map