quake2ts 0.0.553 → 0.0.557

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.
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -22,18 +32,37 @@ var index_exports = {};
22
32
  __export(index_exports, {
23
33
  InputInjector: () => InputInjector,
24
34
  MockPointerLock: () => MockPointerLock,
35
+ captureAudioEvents: () => captureAudioEvents,
36
+ captureCanvasDrawCalls: () => captureCanvasDrawCalls,
37
+ captureGameScreenshot: () => captureGameScreenshot,
38
+ captureGameState: () => captureGameState,
39
+ compareScreenshots: () => compareScreenshots,
25
40
  createBinaryStreamMock: () => createBinaryStreamMock,
26
41
  createBinaryWriterMock: () => createBinaryWriterMock,
42
+ createCustomNetworkCondition: () => createCustomNetworkCondition,
27
43
  createEntity: () => createEntity,
28
44
  createEntityStateFactory: () => createEntityStateFactory,
29
45
  createGameStateSnapshotFactory: () => createGameStateSnapshotFactory,
46
+ createMockAudioContext: () => createMockAudioContext,
47
+ createMockCanvas: () => createMockCanvas,
48
+ createMockCanvasContext2D: () => createMockCanvasContext2D,
30
49
  createMockEngine: () => createMockEngine,
31
50
  createMockGame: () => createMockGame,
51
+ createMockImage: () => createMockImage,
52
+ createMockImageData: () => createMockImageData,
53
+ createMockIndexedDB: () => createMockIndexedDB,
54
+ createMockLocalStorage: () => createMockLocalStorage,
55
+ createMockPerformance: () => createMockPerformance,
56
+ createMockRAF: () => createMockRAF,
57
+ createMockSessionStorage: () => createMockSessionStorage,
32
58
  createMockWebGL2Context: () => createMockWebGL2Context,
33
59
  createNetChanMock: () => createNetChanMock,
34
60
  createPlayerStateFactory: () => createPlayerStateFactory,
61
+ createPlaywrightTestClient: () => createPlaywrightTestClient,
35
62
  createSpawnContext: () => createSpawnContext,
63
+ createStorageTestScenario: () => createStorageTestScenario,
36
64
  createTestContext: () => createTestContext,
65
+ createVisualTestScenario: () => createVisualTestScenario,
37
66
  intersects: () => import_shared3.intersects,
38
67
  ladderTrace: () => import_shared3.ladderTrace,
39
68
  makeAxisBrush: () => makeAxisBrush,
@@ -44,9 +73,16 @@ __export(index_exports, {
44
73
  makeNode: () => makeNode,
45
74
  makePlane: () => makePlane,
46
75
  setupBrowserEnvironment: () => setupBrowserEnvironment,
76
+ setupMockAudioContext: () => setupMockAudioContext,
47
77
  setupNodeEnvironment: () => setupNodeEnvironment,
78
+ simulateFrames: () => simulateFrames,
79
+ simulateFramesWithMock: () => simulateFramesWithMock,
80
+ simulateNetworkCondition: () => simulateNetworkCondition,
48
81
  stairTrace: () => import_shared3.stairTrace,
49
- teardownBrowserEnvironment: () => teardownBrowserEnvironment
82
+ teardownBrowserEnvironment: () => teardownBrowserEnvironment,
83
+ teardownMockAudioContext: () => teardownMockAudioContext,
84
+ throttleBandwidth: () => throttleBandwidth,
85
+ waitForGameReady: () => waitForGameReady
50
86
  });
51
87
  module.exports = __toCommonJS(index_exports);
52
88
 
@@ -444,123 +480,99 @@ function createEntity() {
444
480
  var import_jsdom = require("jsdom");
445
481
  var import_canvas = require("@napi-rs/canvas");
446
482
  var import_auto = require("fake-indexeddb/auto");
447
- function setupBrowserEnvironment(options = {}) {
448
- const { url = "http://localhost", pretendToBeVisual = true } = options;
449
- const dom = new import_jsdom.JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", {
450
- url,
451
- pretendToBeVisual
452
- });
453
- global.window = dom.window;
454
- global.document = dom.window.document;
455
- global.navigator = dom.window.navigator;
456
- global.location = dom.window.location;
457
- global.HTMLElement = dom.window.HTMLElement;
458
- global.Event = dom.window.Event;
459
- global.CustomEvent = dom.window.CustomEvent;
460
- global.DragEvent = dom.window.DragEvent;
461
- global.MouseEvent = dom.window.MouseEvent;
462
- global.KeyboardEvent = dom.window.KeyboardEvent;
463
- global.FocusEvent = dom.window.FocusEvent;
464
- global.WheelEvent = dom.window.WheelEvent;
465
- global.InputEvent = dom.window.InputEvent;
466
- global.UIEvent = dom.window.UIEvent;
467
- try {
468
- global.localStorage = dom.window.localStorage;
469
- } catch (e) {
470
- }
471
- if (!global.localStorage) {
472
- const storage = /* @__PURE__ */ new Map();
473
- global.localStorage = {
474
- getItem: (key) => storage.get(key) || null,
475
- setItem: (key, value) => storage.set(key, value),
476
- removeItem: (key) => storage.delete(key),
477
- clear: () => storage.clear(),
478
- key: (index) => Array.from(storage.keys())[index] || null,
479
- get length() {
480
- return storage.size;
483
+
484
+ // src/e2e/input.ts
485
+ var MockPointerLock = class {
486
+ static setup(doc) {
487
+ let _pointerLockElement = null;
488
+ Object.defineProperty(doc, "pointerLockElement", {
489
+ get: () => _pointerLockElement,
490
+ configurable: true
491
+ });
492
+ doc.exitPointerLock = () => {
493
+ if (_pointerLockElement) {
494
+ _pointerLockElement = null;
495
+ doc.dispatchEvent(new Event("pointerlockchange"));
481
496
  }
482
497
  };
483
- }
484
- const originalCreateElement = document.createElement.bind(document);
485
- document.createElement = function(tagName, options2) {
486
- if (tagName.toLowerCase() === "canvas") {
487
- const napiCanvas = new import_canvas.Canvas(300, 150);
488
- const domCanvas = originalCreateElement("canvas", options2);
489
- Object.defineProperty(domCanvas, "width", {
490
- get: () => napiCanvas.width,
491
- set: (value) => {
492
- napiCanvas.width = value;
493
- },
494
- enumerable: true,
495
- configurable: true
496
- });
497
- Object.defineProperty(domCanvas, "height", {
498
- get: () => napiCanvas.height,
499
- set: (value) => {
500
- napiCanvas.height = value;
501
- },
502
- enumerable: true,
503
- configurable: true
504
- });
505
- const originalGetContext = domCanvas.getContext.bind(domCanvas);
506
- domCanvas.getContext = function(contextId, options3) {
507
- if (contextId === "2d") {
508
- return napiCanvas.getContext("2d", options3);
509
- }
510
- if (contextId === "webgl" || contextId === "webgl2") {
511
- return originalGetContext(contextId, options3);
512
- }
513
- return napiCanvas.getContext(contextId, options3);
514
- };
515
- domCanvas.__napiCanvas = napiCanvas;
516
- return domCanvas;
517
- }
518
- return originalCreateElement(tagName, options2);
519
- };
520
- global.Image = import_canvas.Image;
521
- global.ImageData = import_canvas.ImageData;
522
- if (typeof global.createImageBitmap === "undefined") {
523
- global.createImageBitmap = async function(image, _options) {
524
- if (image && typeof image.width === "number" && typeof image.height === "number") {
525
- const canvas2 = new import_canvas.Canvas(image.width, image.height);
526
- const ctx = canvas2.getContext("2d");
527
- if (image.data) {
528
- ctx.putImageData(image, 0, 0);
529
- }
530
- return canvas2;
531
- }
532
- const canvas = new import_canvas.Canvas(100, 100);
533
- return canvas;
498
+ global.HTMLElement.prototype.requestPointerLock = function() {
499
+ _pointerLockElement = this;
500
+ doc.dispatchEvent(new Event("pointerlockchange"));
534
501
  };
535
502
  }
536
- if (typeof global.btoa === "undefined") {
537
- global.btoa = function(str) {
538
- return Buffer.from(str, "binary").toString("base64");
539
- };
503
+ };
504
+ var InputInjector = class {
505
+ constructor(doc, win) {
506
+ this.doc = doc;
507
+ this.win = win;
540
508
  }
541
- if (typeof global.atob === "undefined") {
542
- global.atob = function(str) {
543
- return Buffer.from(str, "base64").toString("binary");
544
- };
509
+ keyDown(key, code) {
510
+ const event = new this.win.KeyboardEvent("keydown", {
511
+ key,
512
+ code: code || key,
513
+ bubbles: true,
514
+ cancelable: true,
515
+ view: this.win
516
+ });
517
+ this.doc.dispatchEvent(event);
545
518
  }
546
- }
547
- function teardownBrowserEnvironment() {
548
- delete global.window;
549
- delete global.document;
550
- delete global.navigator;
551
- delete global.localStorage;
552
- delete global.location;
553
- delete global.HTMLElement;
554
- delete global.Image;
555
- delete global.ImageData;
556
- delete global.createImageBitmap;
557
- }
558
-
559
- // src/setup/node.ts
560
- function setupNodeEnvironment() {
561
- if (typeof global.fetch === "undefined") {
519
+ keyUp(key, code) {
520
+ const event = new this.win.KeyboardEvent("keyup", {
521
+ key,
522
+ code: code || key,
523
+ bubbles: true,
524
+ cancelable: true,
525
+ view: this.win
526
+ });
527
+ this.doc.dispatchEvent(event);
562
528
  }
563
- }
529
+ mouseMove(movementX, movementY, clientX = 0, clientY = 0) {
530
+ const event = new this.win.MouseEvent("mousemove", {
531
+ bubbles: true,
532
+ cancelable: true,
533
+ view: this.win,
534
+ clientX,
535
+ clientY,
536
+ movementX,
537
+ // Note: JSDOM might not support this standard property fully on event init
538
+ movementY
539
+ });
540
+ Object.defineProperty(event, "movementX", { value: movementX });
541
+ Object.defineProperty(event, "movementY", { value: movementY });
542
+ const target = this.doc.pointerLockElement || this.doc;
543
+ target.dispatchEvent(event);
544
+ }
545
+ mouseDown(button = 0) {
546
+ const event = new this.win.MouseEvent("mousedown", {
547
+ button,
548
+ bubbles: true,
549
+ cancelable: true,
550
+ view: this.win
551
+ });
552
+ const target = this.doc.pointerLockElement || this.doc;
553
+ target.dispatchEvent(event);
554
+ }
555
+ mouseUp(button = 0) {
556
+ const event = new this.win.MouseEvent("mouseup", {
557
+ button,
558
+ bubbles: true,
559
+ cancelable: true,
560
+ view: this.win
561
+ });
562
+ const target = this.doc.pointerLockElement || this.doc;
563
+ target.dispatchEvent(event);
564
+ }
565
+ wheel(deltaY) {
566
+ const event = new this.win.WheelEvent("wheel", {
567
+ deltaY,
568
+ bubbles: true,
569
+ cancelable: true,
570
+ view: this.win
571
+ });
572
+ const target = this.doc.pointerLockElement || this.doc;
573
+ target.dispatchEvent(event);
574
+ }
575
+ };
564
576
 
565
577
  // src/setup/webgl.ts
566
578
  function createMockWebGL2Context(canvas) {
@@ -686,114 +698,709 @@ function createMockWebGL2Context(canvas) {
686
698
  return gl;
687
699
  }
688
700
 
689
- // src/e2e/input.ts
690
- var MockPointerLock = class {
691
- static setup(doc) {
692
- let _pointerLockElement = null;
693
- Object.defineProperty(doc, "pointerLockElement", {
694
- get: () => _pointerLockElement,
695
- configurable: true
696
- });
697
- doc.exitPointerLock = () => {
698
- if (_pointerLockElement) {
699
- _pointerLockElement = null;
700
- doc.dispatchEvent(new Event("pointerlockchange"));
701
+ // src/setup/browser.ts
702
+ function setupBrowserEnvironment(options = {}) {
703
+ const {
704
+ url = "http://localhost",
705
+ pretendToBeVisual = true,
706
+ resources = void 0,
707
+ enableWebGL2 = false,
708
+ enablePointerLock = false
709
+ } = options;
710
+ const dom = new import_jsdom.JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", {
711
+ url,
712
+ pretendToBeVisual,
713
+ resources
714
+ });
715
+ global.window = dom.window;
716
+ global.document = dom.window.document;
717
+ try {
718
+ global.navigator = dom.window.navigator;
719
+ } catch (e) {
720
+ try {
721
+ Object.defineProperty(global, "navigator", {
722
+ value: dom.window.navigator,
723
+ writable: true,
724
+ configurable: true
725
+ });
726
+ } catch (e2) {
727
+ console.warn("Could not assign global.navigator, skipping.");
728
+ }
729
+ }
730
+ global.location = dom.window.location;
731
+ global.HTMLElement = dom.window.HTMLElement;
732
+ global.HTMLCanvasElement = dom.window.HTMLCanvasElement;
733
+ global.Event = dom.window.Event;
734
+ global.CustomEvent = dom.window.CustomEvent;
735
+ global.DragEvent = dom.window.DragEvent;
736
+ global.MouseEvent = dom.window.MouseEvent;
737
+ global.KeyboardEvent = dom.window.KeyboardEvent;
738
+ global.FocusEvent = dom.window.FocusEvent;
739
+ global.WheelEvent = dom.window.WheelEvent;
740
+ global.InputEvent = dom.window.InputEvent;
741
+ global.UIEvent = dom.window.UIEvent;
742
+ try {
743
+ global.localStorage = dom.window.localStorage;
744
+ } catch (e) {
745
+ }
746
+ if (!global.localStorage) {
747
+ const storage = /* @__PURE__ */ new Map();
748
+ global.localStorage = {
749
+ getItem: (key) => storage.get(key) || null,
750
+ setItem: (key, value) => storage.set(key, value),
751
+ removeItem: (key) => storage.delete(key),
752
+ clear: () => storage.clear(),
753
+ key: (index) => Array.from(storage.keys())[index] || null,
754
+ get length() {
755
+ return storage.size;
701
756
  }
702
757
  };
703
- global.HTMLElement.prototype.requestPointerLock = function() {
704
- _pointerLockElement = this;
705
- doc.dispatchEvent(new Event("pointerlockchange"));
706
- };
707
- }
708
- };
709
- var InputInjector = class {
710
- constructor(doc, win) {
711
- this.doc = doc;
712
- this.win = win;
713
758
  }
714
- keyDown(key, code) {
715
- const event = new this.win.KeyboardEvent("keydown", {
716
- key,
717
- code: code || key,
718
- bubbles: true,
719
- cancelable: true,
720
- view: this.win
721
- });
722
- this.doc.dispatchEvent(event);
759
+ const originalCreateElement = document.createElement.bind(document);
760
+ document.createElement = function(tagName, options2) {
761
+ if (tagName.toLowerCase() === "canvas") {
762
+ const napiCanvas = new import_canvas.Canvas(300, 150);
763
+ const domCanvas = originalCreateElement("canvas", options2);
764
+ Object.defineProperty(domCanvas, "width", {
765
+ get: () => napiCanvas.width,
766
+ set: (value) => {
767
+ napiCanvas.width = value;
768
+ },
769
+ enumerable: true,
770
+ configurable: true
771
+ });
772
+ Object.defineProperty(domCanvas, "height", {
773
+ get: () => napiCanvas.height,
774
+ set: (value) => {
775
+ napiCanvas.height = value;
776
+ },
777
+ enumerable: true,
778
+ configurable: true
779
+ });
780
+ const originalGetContext = domCanvas.getContext.bind(domCanvas);
781
+ domCanvas.getContext = function(contextId, options3) {
782
+ if (contextId === "2d") {
783
+ return napiCanvas.getContext("2d", options3);
784
+ }
785
+ if (enableWebGL2 && contextId === "webgl2") {
786
+ return createMockWebGL2Context(domCanvas);
787
+ }
788
+ if (contextId === "webgl" || contextId === "webgl2") {
789
+ return originalGetContext(contextId, options3);
790
+ }
791
+ return napiCanvas.getContext(contextId, options3);
792
+ };
793
+ domCanvas.__napiCanvas = napiCanvas;
794
+ return domCanvas;
795
+ }
796
+ return originalCreateElement(tagName, options2);
797
+ };
798
+ if (enableWebGL2) {
799
+ const originalProtoGetContext = global.HTMLCanvasElement.prototype.getContext;
800
+ global.HTMLCanvasElement.prototype.getContext = function(contextId, options2) {
801
+ if (contextId === "webgl2") {
802
+ return createMockWebGL2Context(this);
803
+ }
804
+ return originalProtoGetContext.call(this, contextId, options2);
805
+ };
723
806
  }
724
- keyUp(key, code) {
725
- const event = new this.win.KeyboardEvent("keyup", {
726
- key,
727
- code: code || key,
728
- bubbles: true,
729
- cancelable: true,
730
- view: this.win
731
- });
732
- this.doc.dispatchEvent(event);
807
+ global.Image = import_canvas.Image;
808
+ global.ImageData = import_canvas.ImageData;
809
+ if (typeof global.createImageBitmap === "undefined") {
810
+ global.createImageBitmap = async function(image, _options) {
811
+ if (image && typeof image.width === "number" && typeof image.height === "number") {
812
+ const canvas2 = new import_canvas.Canvas(image.width, image.height);
813
+ const ctx = canvas2.getContext("2d");
814
+ if (image.data) {
815
+ ctx.putImageData(image, 0, 0);
816
+ }
817
+ return canvas2;
818
+ }
819
+ const canvas = new import_canvas.Canvas(100, 100);
820
+ return canvas;
821
+ };
733
822
  }
734
- mouseMove(movementX, movementY, clientX = 0, clientY = 0) {
735
- const event = new this.win.MouseEvent("mousemove", {
736
- bubbles: true,
737
- cancelable: true,
738
- view: this.win,
739
- clientX,
740
- clientY,
741
- movementX,
742
- // Note: JSDOM might not support this standard property fully on event init
743
- movementY
744
- });
745
- Object.defineProperty(event, "movementX", { value: movementX });
746
- Object.defineProperty(event, "movementY", { value: movementY });
747
- const target = this.doc.pointerLockElement || this.doc;
748
- target.dispatchEvent(event);
823
+ if (typeof global.btoa === "undefined") {
824
+ global.btoa = function(str) {
825
+ return Buffer.from(str, "binary").toString("base64");
826
+ };
749
827
  }
750
- mouseDown(button = 0) {
751
- const event = new this.win.MouseEvent("mousedown", {
752
- button,
753
- bubbles: true,
754
- cancelable: true,
755
- view: this.win
756
- });
757
- const target = this.doc.pointerLockElement || this.doc;
758
- target.dispatchEvent(event);
828
+ if (typeof global.atob === "undefined") {
829
+ global.atob = function(str) {
830
+ return Buffer.from(str, "base64").toString("binary");
831
+ };
759
832
  }
760
- mouseUp(button = 0) {
761
- const event = new this.win.MouseEvent("mouseup", {
762
- button,
763
- bubbles: true,
764
- cancelable: true,
765
- view: this.win
766
- });
767
- const target = this.doc.pointerLockElement || this.doc;
768
- target.dispatchEvent(event);
833
+ if (enablePointerLock) {
834
+ MockPointerLock.setup(global.document);
769
835
  }
770
- wheel(deltaY) {
771
- const event = new this.win.WheelEvent("wheel", {
772
- deltaY,
773
- bubbles: true,
774
- cancelable: true,
775
- view: this.win
776
- });
777
- const target = this.doc.pointerLockElement || this.doc;
778
- target.dispatchEvent(event);
836
+ if (typeof global.requestAnimationFrame === "undefined") {
837
+ let lastTime = 0;
838
+ global.requestAnimationFrame = (callback) => {
839
+ const currTime = Date.now();
840
+ const timeToCall = Math.max(0, 16 - (currTime - lastTime));
841
+ const id = setTimeout(() => {
842
+ callback(currTime + timeToCall);
843
+ }, timeToCall);
844
+ lastTime = currTime + timeToCall;
845
+ return id;
846
+ };
847
+ global.cancelAnimationFrame = (id) => {
848
+ clearTimeout(id);
849
+ };
850
+ }
851
+ }
852
+ function teardownBrowserEnvironment() {
853
+ delete global.window;
854
+ delete global.document;
855
+ delete global.navigator;
856
+ delete global.localStorage;
857
+ delete global.location;
858
+ delete global.HTMLElement;
859
+ delete global.HTMLCanvasElement;
860
+ delete global.Image;
861
+ delete global.ImageData;
862
+ delete global.createImageBitmap;
863
+ delete global.Event;
864
+ delete global.CustomEvent;
865
+ delete global.DragEvent;
866
+ delete global.MouseEvent;
867
+ delete global.KeyboardEvent;
868
+ delete global.FocusEvent;
869
+ delete global.WheelEvent;
870
+ delete global.InputEvent;
871
+ delete global.UIEvent;
872
+ }
873
+
874
+ // src/setup/node.ts
875
+ function setupNodeEnvironment() {
876
+ if (typeof global.fetch === "undefined") {
877
+ }
878
+ }
879
+
880
+ // src/setup/canvas.ts
881
+ var import_canvas2 = require("@napi-rs/canvas");
882
+ function createMockCanvas(width = 300, height = 150) {
883
+ if (typeof document !== "undefined" && document.createElement) {
884
+ const canvas2 = document.createElement("canvas");
885
+ canvas2.width = width;
886
+ canvas2.height = height;
887
+ return canvas2;
888
+ }
889
+ const canvas = new import_canvas2.Canvas(width, height);
890
+ const originalGetContext = canvas.getContext.bind(canvas);
891
+ canvas.getContext = function(contextId, options) {
892
+ if (contextId === "webgl2") {
893
+ return createMockWebGL2Context(canvas);
894
+ }
895
+ if (contextId === "2d") {
896
+ return originalGetContext("2d", options);
897
+ }
898
+ return originalGetContext(contextId, options);
899
+ };
900
+ return canvas;
901
+ }
902
+ function createMockCanvasContext2D(canvas) {
903
+ if (!canvas) {
904
+ canvas = createMockCanvas();
905
+ }
906
+ return canvas.getContext("2d");
907
+ }
908
+ function captureCanvasDrawCalls(context) {
909
+ const drawCalls = [];
910
+ const methodsToSpy = [
911
+ "fillRect",
912
+ "strokeRect",
913
+ "clearRect",
914
+ "fillText",
915
+ "strokeText",
916
+ "drawImage",
917
+ "beginPath",
918
+ "closePath",
919
+ "moveTo",
920
+ "lineTo",
921
+ "arc",
922
+ "arcTo",
923
+ "bezierCurveTo",
924
+ "quadraticCurveTo",
925
+ "stroke",
926
+ "fill",
927
+ "putImageData"
928
+ ];
929
+ methodsToSpy.forEach((method) => {
930
+ const original = context[method];
931
+ if (typeof original === "function") {
932
+ context[method] = function(...args) {
933
+ drawCalls.push({ method, args });
934
+ return original.apply(this, args);
935
+ };
936
+ }
937
+ });
938
+ return drawCalls;
939
+ }
940
+ function createMockImageData(width, height, fillColor) {
941
+ const imageData = new import_canvas2.ImageData(width, height);
942
+ if (fillColor) {
943
+ const [r, g, b, a] = fillColor;
944
+ for (let i = 0; i < imageData.data.length; i += 4) {
945
+ imageData.data[i] = r;
946
+ imageData.data[i + 1] = g;
947
+ imageData.data[i + 2] = b;
948
+ imageData.data[i + 3] = a;
949
+ }
950
+ }
951
+ return imageData;
952
+ }
953
+ function createMockImage(width, height, src) {
954
+ const img = new import_canvas2.Image();
955
+ if (width) img.width = width;
956
+ if (height) img.height = height;
957
+ if (src) img.src = src;
958
+ return img;
959
+ }
960
+
961
+ // src/setup/timing.ts
962
+ function createMockRAF() {
963
+ let callbacks = [];
964
+ let nextId = 1;
965
+ let currentTime = 0;
966
+ const originalRAF = global.requestAnimationFrame;
967
+ const originalCancelRAF = global.cancelAnimationFrame;
968
+ const raf = (callback) => {
969
+ const id = nextId++;
970
+ callbacks.push({ id, callback });
971
+ return id;
972
+ };
973
+ const cancel = (id) => {
974
+ callbacks = callbacks.filter((cb) => cb.id !== id);
975
+ };
976
+ const mock = {
977
+ tick(timestamp) {
978
+ if (typeof timestamp !== "number") {
979
+ currentTime += 16.6;
980
+ } else {
981
+ currentTime = timestamp;
982
+ }
983
+ const currentCallbacks = [...callbacks];
984
+ callbacks = [];
985
+ currentCallbacks.forEach(({ callback }) => {
986
+ callback(currentTime);
987
+ });
988
+ },
989
+ advance(deltaMs = 16.6) {
990
+ this.tick(currentTime + deltaMs);
991
+ },
992
+ getCallbacks() {
993
+ return callbacks.map((c) => c.callback);
994
+ },
995
+ reset() {
996
+ callbacks = [];
997
+ nextId = 1;
998
+ currentTime = 0;
999
+ },
1000
+ enable() {
1001
+ global.requestAnimationFrame = raf;
1002
+ global.cancelAnimationFrame = cancel;
1003
+ },
1004
+ disable() {
1005
+ if (originalRAF) {
1006
+ global.requestAnimationFrame = originalRAF;
1007
+ } else {
1008
+ delete global.requestAnimationFrame;
1009
+ }
1010
+ if (originalCancelRAF) {
1011
+ global.cancelAnimationFrame = originalCancelRAF;
1012
+ } else {
1013
+ delete global.cancelAnimationFrame;
1014
+ }
1015
+ }
1016
+ };
1017
+ return mock;
1018
+ }
1019
+ function createMockPerformance(startTime = 0) {
1020
+ let currentTime = startTime;
1021
+ const mockPerf = {
1022
+ now: () => currentTime,
1023
+ timeOrigin: startTime,
1024
+ timing: {
1025
+ navigationStart: startTime
1026
+ },
1027
+ // Add minimal navigation/resource timing interfaces to satisfy types if needed
1028
+ clearMarks: () => {
1029
+ },
1030
+ clearMeasures: () => {
1031
+ },
1032
+ clearResourceTimings: () => {
1033
+ },
1034
+ getEntries: () => [],
1035
+ getEntriesByName: () => [],
1036
+ getEntriesByType: () => [],
1037
+ mark: () => {
1038
+ },
1039
+ measure: () => {
1040
+ },
1041
+ setResourceTimingBufferSize: () => {
1042
+ },
1043
+ toJSON: () => ({}),
1044
+ addEventListener: () => {
1045
+ },
1046
+ removeEventListener: () => {
1047
+ },
1048
+ dispatchEvent: () => true
1049
+ };
1050
+ mockPerf.advance = (deltaMs) => {
1051
+ currentTime += deltaMs;
1052
+ };
1053
+ mockPerf.setTime = (time) => {
1054
+ currentTime = time;
1055
+ };
1056
+ return mockPerf;
1057
+ }
1058
+ function simulateFrames(count, frameTimeMs = 16.6, callback) {
1059
+ const raf = global.requestAnimationFrame;
1060
+ if (!raf) return;
1061
+ }
1062
+ function simulateFramesWithMock(mock, count, frameTimeMs = 16.6, callback) {
1063
+ for (let i = 0; i < count; i++) {
1064
+ if (callback) callback(i);
1065
+ mock.advance(frameTimeMs);
1066
+ }
1067
+ }
1068
+
1069
+ // src/setup/storage.ts
1070
+ var import_auto2 = require("fake-indexeddb/auto");
1071
+ function createMockLocalStorage(initialData = {}) {
1072
+ const storage = new Map(Object.entries(initialData));
1073
+ return {
1074
+ getItem: (key) => storage.get(key) || null,
1075
+ setItem: (key, value) => storage.set(key, value),
1076
+ removeItem: (key) => storage.delete(key),
1077
+ clear: () => storage.clear(),
1078
+ key: (index) => Array.from(storage.keys())[index] || null,
1079
+ get length() {
1080
+ return storage.size;
1081
+ }
1082
+ };
1083
+ }
1084
+ function createMockSessionStorage(initialData = {}) {
1085
+ return createMockLocalStorage(initialData);
1086
+ }
1087
+ function createMockIndexedDB() {
1088
+ if (typeof indexedDB === "undefined") {
1089
+ throw new Error("IndexedDB mock not found. Ensure fake-indexeddb is loaded.");
1090
+ }
1091
+ return indexedDB;
1092
+ }
1093
+ function createStorageTestScenario(storageType = "local") {
1094
+ const storage = storageType === "local" ? createMockLocalStorage() : createMockSessionStorage();
1095
+ return {
1096
+ storage,
1097
+ populate(data) {
1098
+ Object.entries(data).forEach(([k, v]) => storage.setItem(k, v));
1099
+ },
1100
+ verify(key, value) {
1101
+ return storage.getItem(key) === value;
1102
+ }
1103
+ };
1104
+ }
1105
+
1106
+ // src/setup/audio.ts
1107
+ function createMockAudioContext() {
1108
+ return {
1109
+ createGain: () => ({
1110
+ connect: () => {
1111
+ },
1112
+ gain: { value: 1, setValueAtTime: () => {
1113
+ } }
1114
+ }),
1115
+ createOscillator: () => ({
1116
+ connect: () => {
1117
+ },
1118
+ start: () => {
1119
+ },
1120
+ stop: () => {
1121
+ },
1122
+ frequency: { value: 440 }
1123
+ }),
1124
+ createBufferSource: () => ({
1125
+ connect: () => {
1126
+ },
1127
+ start: () => {
1128
+ },
1129
+ stop: () => {
1130
+ },
1131
+ buffer: null,
1132
+ playbackRate: { value: 1 },
1133
+ loop: false
1134
+ }),
1135
+ destination: {},
1136
+ currentTime: 0,
1137
+ state: "running",
1138
+ resume: async () => {
1139
+ },
1140
+ suspend: async () => {
1141
+ },
1142
+ close: async () => {
1143
+ },
1144
+ decodeAudioData: async (buffer) => ({
1145
+ duration: 1,
1146
+ length: 44100,
1147
+ sampleRate: 44100,
1148
+ numberOfChannels: 2,
1149
+ getChannelData: () => new Float32Array(44100)
1150
+ }),
1151
+ createBuffer: (channels, length, sampleRate) => ({
1152
+ duration: length / sampleRate,
1153
+ length,
1154
+ sampleRate,
1155
+ numberOfChannels: channels,
1156
+ getChannelData: () => new Float32Array(length)
1157
+ })
1158
+ };
1159
+ }
1160
+ function setupMockAudioContext() {
1161
+ if (typeof global.AudioContext === "undefined" && typeof global.window !== "undefined") {
1162
+ global.AudioContext = class {
1163
+ constructor() {
1164
+ return createMockAudioContext();
1165
+ }
1166
+ };
1167
+ global.window.AudioContext = global.AudioContext;
1168
+ global.window.webkitAudioContext = global.AudioContext;
1169
+ }
1170
+ }
1171
+ function teardownMockAudioContext() {
1172
+ if (global.AudioContext && global.AudioContext.toString().includes("class")) {
1173
+ delete global.AudioContext;
1174
+ delete global.window.AudioContext;
1175
+ delete global.window.webkitAudioContext;
1176
+ }
1177
+ }
1178
+ function captureAudioEvents(context) {
1179
+ return [];
1180
+ }
1181
+
1182
+ // src/e2e/playwright.ts
1183
+ var import_playwright = require("playwright");
1184
+ async function createPlaywrightTestClient(options = {}) {
1185
+ const browser = await import_playwright.chromium.launch({
1186
+ headless: options.headless ?? true,
1187
+ args: options.args || [
1188
+ "--use-gl=egl",
1189
+ "--ignore-gpu-blocklist",
1190
+ "--no-sandbox",
1191
+ "--disable-setuid-sandbox"
1192
+ ]
1193
+ });
1194
+ const context = await browser.newContext({
1195
+ viewport: options.viewport || { width: 1280, height: 720 },
1196
+ recordVideo: options.recordVideo,
1197
+ deviceScaleFactor: 1
1198
+ });
1199
+ const page = await context.newPage();
1200
+ const waitForGame = async (timeout = 1e4) => {
1201
+ try {
1202
+ await page.waitForFunction(() => {
1203
+ return window.game || document.querySelector("canvas");
1204
+ }, null, { timeout });
1205
+ } catch (e) {
1206
+ throw new Error(`Game did not initialize within ${timeout}ms`);
1207
+ }
1208
+ };
1209
+ const client = {
1210
+ browser,
1211
+ context,
1212
+ page,
1213
+ async navigate(url) {
1214
+ await page.goto(url, { waitUntil: "domcontentloaded" });
1215
+ },
1216
+ async waitForGame(timeout) {
1217
+ await waitForGame(timeout);
1218
+ },
1219
+ async injectInput(type, key) {
1220
+ if (type === "keydown") {
1221
+ await page.keyboard.down(key);
1222
+ } else {
1223
+ await page.keyboard.up(key);
1224
+ }
1225
+ },
1226
+ async injectMouse(type, x = 0, y = 0, button = 0) {
1227
+ if (type === "move") {
1228
+ await page.mouse.move(x, y);
1229
+ } else if (type === "down") {
1230
+ await page.mouse.down({ button: button === 0 ? "left" : button === 2 ? "right" : "middle" });
1231
+ } else if (type === "up") {
1232
+ await page.mouse.up({ button: button === 0 ? "left" : button === 2 ? "right" : "middle" });
1233
+ }
1234
+ },
1235
+ async screenshot(path2) {
1236
+ await page.screenshot({ path: path2 });
1237
+ },
1238
+ async close() {
1239
+ await browser.close();
1240
+ }
1241
+ };
1242
+ return client;
1243
+ }
1244
+ async function waitForGameReady(page, timeout = 1e4) {
1245
+ await page.waitForFunction(() => {
1246
+ return window.game || document.querySelector("canvas");
1247
+ }, null, { timeout });
1248
+ }
1249
+ async function captureGameState(page) {
1250
+ return await page.evaluate(() => {
1251
+ const game = window.game;
1252
+ if (!game) return {};
1253
+ return {};
1254
+ });
1255
+ }
1256
+
1257
+ // src/e2e/network.ts
1258
+ var CONDITIONS = {
1259
+ "good": {
1260
+ offline: false,
1261
+ downloadThroughput: 10 * 1024 * 1024,
1262
+ // 10 Mbps
1263
+ uploadThroughput: 5 * 1024 * 1024,
1264
+ // 5 Mbps
1265
+ latency: 20
1266
+ },
1267
+ "slow": {
1268
+ offline: false,
1269
+ downloadThroughput: 500 * 1024,
1270
+ // 500 Kbps
1271
+ uploadThroughput: 500 * 1024,
1272
+ latency: 400
1273
+ },
1274
+ "unstable": {
1275
+ offline: false,
1276
+ downloadThroughput: 1 * 1024 * 1024,
1277
+ uploadThroughput: 1 * 1024 * 1024,
1278
+ latency: 100
1279
+ // Jitter needs logic not simple preset
1280
+ },
1281
+ "offline": {
1282
+ offline: true,
1283
+ downloadThroughput: 0,
1284
+ uploadThroughput: 0,
1285
+ latency: 0
779
1286
  }
780
1287
  };
1288
+ function simulateNetworkCondition(condition) {
1289
+ const config = CONDITIONS[condition];
1290
+ return createCustomNetworkCondition(config.latency, 0, 0, config);
1291
+ }
1292
+ function createCustomNetworkCondition(latency, jitter = 0, packetLoss = 0, baseConfig) {
1293
+ return {
1294
+ async apply(page) {
1295
+ const client = await page.context().newCDPSession(page);
1296
+ await client.send("Network.enable");
1297
+ await client.send("Network.emulateNetworkConditions", {
1298
+ offline: baseConfig?.offline || false,
1299
+ latency: latency + Math.random() * jitter,
1300
+ // Basic jitter application on setup (static)
1301
+ downloadThroughput: baseConfig?.downloadThroughput || -1,
1302
+ uploadThroughput: baseConfig?.uploadThroughput || -1
1303
+ });
1304
+ },
1305
+ async clear(page) {
1306
+ const client = await page.context().newCDPSession(page);
1307
+ await client.send("Network.emulateNetworkConditions", {
1308
+ offline: false,
1309
+ latency: 0,
1310
+ downloadThroughput: -1,
1311
+ uploadThroughput: -1
1312
+ });
1313
+ }
1314
+ };
1315
+ }
1316
+ async function throttleBandwidth(page, bytesPerSecond) {
1317
+ const simulator = createCustomNetworkCondition(0, 0, 0, {
1318
+ offline: false,
1319
+ latency: 0,
1320
+ downloadThroughput: bytesPerSecond,
1321
+ uploadThroughput: bytesPerSecond
1322
+ });
1323
+ await simulator.apply(page);
1324
+ }
1325
+
1326
+ // src/e2e/visual.ts
1327
+ var import_path = __toESM(require("path"), 1);
1328
+ var import_promises = __toESM(require("fs/promises"), 1);
1329
+ async function captureGameScreenshot(page, name, options = {}) {
1330
+ const dir = options.dir || "__screenshots__";
1331
+ const screenshotPath = import_path.default.join(dir, `${name}.png`);
1332
+ await import_promises.default.mkdir(dir, { recursive: true });
1333
+ return await page.screenshot({
1334
+ path: screenshotPath,
1335
+ fullPage: options.fullPage ?? false,
1336
+ animations: "disabled",
1337
+ // Try to freeze animations if possible
1338
+ caret: "hide"
1339
+ });
1340
+ }
1341
+ async function compareScreenshots(baseline, current, threshold = 0.1) {
1342
+ if (baseline.equals(current)) {
1343
+ return { pixelDiff: 0, matched: true };
1344
+ }
1345
+ return {
1346
+ pixelDiff: -1,
1347
+ // Unknown magnitude
1348
+ matched: false
1349
+ };
1350
+ }
1351
+ function createVisualTestScenario(page, sceneName) {
1352
+ return {
1353
+ async capture(snapshotName) {
1354
+ return await captureGameScreenshot(page, `${sceneName}-${snapshotName}`);
1355
+ },
1356
+ async compare(snapshotName, baselineDir) {
1357
+ const name = `${sceneName}-${snapshotName}`;
1358
+ const current = await captureGameScreenshot(page, name, { dir: "__screenshots__/current" });
1359
+ try {
1360
+ const baselinePath = import_path.default.join(baselineDir, `${name}.png`);
1361
+ const baseline = await import_promises.default.readFile(baselinePath);
1362
+ return await compareScreenshots(baseline, current);
1363
+ } catch (e) {
1364
+ return { pixelDiff: -1, matched: false };
1365
+ }
1366
+ }
1367
+ };
1368
+ }
781
1369
  // Annotate the CommonJS export names for ESM import in node:
782
1370
  0 && (module.exports = {
783
1371
  InputInjector,
784
1372
  MockPointerLock,
1373
+ captureAudioEvents,
1374
+ captureCanvasDrawCalls,
1375
+ captureGameScreenshot,
1376
+ captureGameState,
1377
+ compareScreenshots,
785
1378
  createBinaryStreamMock,
786
1379
  createBinaryWriterMock,
1380
+ createCustomNetworkCondition,
787
1381
  createEntity,
788
1382
  createEntityStateFactory,
789
1383
  createGameStateSnapshotFactory,
1384
+ createMockAudioContext,
1385
+ createMockCanvas,
1386
+ createMockCanvasContext2D,
790
1387
  createMockEngine,
791
1388
  createMockGame,
1389
+ createMockImage,
1390
+ createMockImageData,
1391
+ createMockIndexedDB,
1392
+ createMockLocalStorage,
1393
+ createMockPerformance,
1394
+ createMockRAF,
1395
+ createMockSessionStorage,
792
1396
  createMockWebGL2Context,
793
1397
  createNetChanMock,
794
1398
  createPlayerStateFactory,
1399
+ createPlaywrightTestClient,
795
1400
  createSpawnContext,
1401
+ createStorageTestScenario,
796
1402
  createTestContext,
1403
+ createVisualTestScenario,
797
1404
  intersects,
798
1405
  ladderTrace,
799
1406
  makeAxisBrush,
@@ -804,8 +1411,15 @@ var InputInjector = class {
804
1411
  makeNode,
805
1412
  makePlane,
806
1413
  setupBrowserEnvironment,
1414
+ setupMockAudioContext,
807
1415
  setupNodeEnvironment,
1416
+ simulateFrames,
1417
+ simulateFramesWithMock,
1418
+ simulateNetworkCondition,
808
1419
  stairTrace,
809
- teardownBrowserEnvironment
1420
+ teardownBrowserEnvironment,
1421
+ teardownMockAudioContext,
1422
+ throttleBandwidth,
1423
+ waitForGameReady
810
1424
  });
811
1425
  //# sourceMappingURL=index.cjs.map