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.
@@ -395,123 +395,99 @@ function createEntity() {
395
395
  import { JSDOM } from "jsdom";
396
396
  import { Canvas, Image, ImageData } from "@napi-rs/canvas";
397
397
  import "fake-indexeddb/auto";
398
- function setupBrowserEnvironment(options = {}) {
399
- const { url = "http://localhost", pretendToBeVisual = true } = options;
400
- const dom = new JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", {
401
- url,
402
- pretendToBeVisual
403
- });
404
- global.window = dom.window;
405
- global.document = dom.window.document;
406
- global.navigator = dom.window.navigator;
407
- global.location = dom.window.location;
408
- global.HTMLElement = dom.window.HTMLElement;
409
- global.Event = dom.window.Event;
410
- global.CustomEvent = dom.window.CustomEvent;
411
- global.DragEvent = dom.window.DragEvent;
412
- global.MouseEvent = dom.window.MouseEvent;
413
- global.KeyboardEvent = dom.window.KeyboardEvent;
414
- global.FocusEvent = dom.window.FocusEvent;
415
- global.WheelEvent = dom.window.WheelEvent;
416
- global.InputEvent = dom.window.InputEvent;
417
- global.UIEvent = dom.window.UIEvent;
418
- try {
419
- global.localStorage = dom.window.localStorage;
420
- } catch (e) {
421
- }
422
- if (!global.localStorage) {
423
- const storage = /* @__PURE__ */ new Map();
424
- global.localStorage = {
425
- getItem: (key) => storage.get(key) || null,
426
- setItem: (key, value) => storage.set(key, value),
427
- removeItem: (key) => storage.delete(key),
428
- clear: () => storage.clear(),
429
- key: (index) => Array.from(storage.keys())[index] || null,
430
- get length() {
431
- return storage.size;
398
+
399
+ // src/e2e/input.ts
400
+ var MockPointerLock = class {
401
+ static setup(doc) {
402
+ let _pointerLockElement = null;
403
+ Object.defineProperty(doc, "pointerLockElement", {
404
+ get: () => _pointerLockElement,
405
+ configurable: true
406
+ });
407
+ doc.exitPointerLock = () => {
408
+ if (_pointerLockElement) {
409
+ _pointerLockElement = null;
410
+ doc.dispatchEvent(new Event("pointerlockchange"));
432
411
  }
433
412
  };
434
- }
435
- const originalCreateElement = document.createElement.bind(document);
436
- document.createElement = function(tagName, options2) {
437
- if (tagName.toLowerCase() === "canvas") {
438
- const napiCanvas = new Canvas(300, 150);
439
- const domCanvas = originalCreateElement("canvas", options2);
440
- Object.defineProperty(domCanvas, "width", {
441
- get: () => napiCanvas.width,
442
- set: (value) => {
443
- napiCanvas.width = value;
444
- },
445
- enumerable: true,
446
- configurable: true
447
- });
448
- Object.defineProperty(domCanvas, "height", {
449
- get: () => napiCanvas.height,
450
- set: (value) => {
451
- napiCanvas.height = value;
452
- },
453
- enumerable: true,
454
- configurable: true
455
- });
456
- const originalGetContext = domCanvas.getContext.bind(domCanvas);
457
- domCanvas.getContext = function(contextId, options3) {
458
- if (contextId === "2d") {
459
- return napiCanvas.getContext("2d", options3);
460
- }
461
- if (contextId === "webgl" || contextId === "webgl2") {
462
- return originalGetContext(contextId, options3);
463
- }
464
- return napiCanvas.getContext(contextId, options3);
465
- };
466
- domCanvas.__napiCanvas = napiCanvas;
467
- return domCanvas;
468
- }
469
- return originalCreateElement(tagName, options2);
470
- };
471
- global.Image = Image;
472
- global.ImageData = ImageData;
473
- if (typeof global.createImageBitmap === "undefined") {
474
- global.createImageBitmap = async function(image, _options) {
475
- if (image && typeof image.width === "number" && typeof image.height === "number") {
476
- const canvas2 = new Canvas(image.width, image.height);
477
- const ctx = canvas2.getContext("2d");
478
- if (image.data) {
479
- ctx.putImageData(image, 0, 0);
480
- }
481
- return canvas2;
482
- }
483
- const canvas = new Canvas(100, 100);
484
- return canvas;
413
+ global.HTMLElement.prototype.requestPointerLock = function() {
414
+ _pointerLockElement = this;
415
+ doc.dispatchEvent(new Event("pointerlockchange"));
485
416
  };
486
417
  }
487
- if (typeof global.btoa === "undefined") {
488
- global.btoa = function(str) {
489
- return Buffer.from(str, "binary").toString("base64");
490
- };
418
+ };
419
+ var InputInjector = class {
420
+ constructor(doc, win) {
421
+ this.doc = doc;
422
+ this.win = win;
491
423
  }
492
- if (typeof global.atob === "undefined") {
493
- global.atob = function(str) {
494
- return Buffer.from(str, "base64").toString("binary");
495
- };
424
+ keyDown(key, code) {
425
+ const event = new this.win.KeyboardEvent("keydown", {
426
+ key,
427
+ code: code || key,
428
+ bubbles: true,
429
+ cancelable: true,
430
+ view: this.win
431
+ });
432
+ this.doc.dispatchEvent(event);
496
433
  }
497
- }
498
- function teardownBrowserEnvironment() {
499
- delete global.window;
500
- delete global.document;
501
- delete global.navigator;
502
- delete global.localStorage;
503
- delete global.location;
504
- delete global.HTMLElement;
505
- delete global.Image;
506
- delete global.ImageData;
507
- delete global.createImageBitmap;
508
- }
509
-
510
- // src/setup/node.ts
511
- function setupNodeEnvironment() {
512
- if (typeof global.fetch === "undefined") {
434
+ keyUp(key, code) {
435
+ const event = new this.win.KeyboardEvent("keyup", {
436
+ key,
437
+ code: code || key,
438
+ bubbles: true,
439
+ cancelable: true,
440
+ view: this.win
441
+ });
442
+ this.doc.dispatchEvent(event);
513
443
  }
514
- }
444
+ mouseMove(movementX, movementY, clientX = 0, clientY = 0) {
445
+ const event = new this.win.MouseEvent("mousemove", {
446
+ bubbles: true,
447
+ cancelable: true,
448
+ view: this.win,
449
+ clientX,
450
+ clientY,
451
+ movementX,
452
+ // Note: JSDOM might not support this standard property fully on event init
453
+ movementY
454
+ });
455
+ Object.defineProperty(event, "movementX", { value: movementX });
456
+ Object.defineProperty(event, "movementY", { value: movementY });
457
+ const target = this.doc.pointerLockElement || this.doc;
458
+ target.dispatchEvent(event);
459
+ }
460
+ mouseDown(button = 0) {
461
+ const event = new this.win.MouseEvent("mousedown", {
462
+ button,
463
+ bubbles: true,
464
+ cancelable: true,
465
+ view: this.win
466
+ });
467
+ const target = this.doc.pointerLockElement || this.doc;
468
+ target.dispatchEvent(event);
469
+ }
470
+ mouseUp(button = 0) {
471
+ const event = new this.win.MouseEvent("mouseup", {
472
+ button,
473
+ bubbles: true,
474
+ cancelable: true,
475
+ view: this.win
476
+ });
477
+ const target = this.doc.pointerLockElement || this.doc;
478
+ target.dispatchEvent(event);
479
+ }
480
+ wheel(deltaY) {
481
+ const event = new this.win.WheelEvent("wheel", {
482
+ deltaY,
483
+ bubbles: true,
484
+ cancelable: true,
485
+ view: this.win
486
+ });
487
+ const target = this.doc.pointerLockElement || this.doc;
488
+ target.dispatchEvent(event);
489
+ }
490
+ };
515
491
 
516
492
  // src/setup/webgl.ts
517
493
  function createMockWebGL2Context(canvas) {
@@ -637,113 +613,708 @@ function createMockWebGL2Context(canvas) {
637
613
  return gl;
638
614
  }
639
615
 
640
- // src/e2e/input.ts
641
- var MockPointerLock = class {
642
- static setup(doc) {
643
- let _pointerLockElement = null;
644
- Object.defineProperty(doc, "pointerLockElement", {
645
- get: () => _pointerLockElement,
646
- configurable: true
647
- });
648
- doc.exitPointerLock = () => {
649
- if (_pointerLockElement) {
650
- _pointerLockElement = null;
651
- doc.dispatchEvent(new Event("pointerlockchange"));
616
+ // src/setup/browser.ts
617
+ function setupBrowserEnvironment(options = {}) {
618
+ const {
619
+ url = "http://localhost",
620
+ pretendToBeVisual = true,
621
+ resources = void 0,
622
+ enableWebGL2 = false,
623
+ enablePointerLock = false
624
+ } = options;
625
+ const dom = new JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", {
626
+ url,
627
+ pretendToBeVisual,
628
+ resources
629
+ });
630
+ global.window = dom.window;
631
+ global.document = dom.window.document;
632
+ try {
633
+ global.navigator = dom.window.navigator;
634
+ } catch (e) {
635
+ try {
636
+ Object.defineProperty(global, "navigator", {
637
+ value: dom.window.navigator,
638
+ writable: true,
639
+ configurable: true
640
+ });
641
+ } catch (e2) {
642
+ console.warn("Could not assign global.navigator, skipping.");
643
+ }
644
+ }
645
+ global.location = dom.window.location;
646
+ global.HTMLElement = dom.window.HTMLElement;
647
+ global.HTMLCanvasElement = dom.window.HTMLCanvasElement;
648
+ global.Event = dom.window.Event;
649
+ global.CustomEvent = dom.window.CustomEvent;
650
+ global.DragEvent = dom.window.DragEvent;
651
+ global.MouseEvent = dom.window.MouseEvent;
652
+ global.KeyboardEvent = dom.window.KeyboardEvent;
653
+ global.FocusEvent = dom.window.FocusEvent;
654
+ global.WheelEvent = dom.window.WheelEvent;
655
+ global.InputEvent = dom.window.InputEvent;
656
+ global.UIEvent = dom.window.UIEvent;
657
+ try {
658
+ global.localStorage = dom.window.localStorage;
659
+ } catch (e) {
660
+ }
661
+ if (!global.localStorage) {
662
+ const storage = /* @__PURE__ */ new Map();
663
+ global.localStorage = {
664
+ getItem: (key) => storage.get(key) || null,
665
+ setItem: (key, value) => storage.set(key, value),
666
+ removeItem: (key) => storage.delete(key),
667
+ clear: () => storage.clear(),
668
+ key: (index) => Array.from(storage.keys())[index] || null,
669
+ get length() {
670
+ return storage.size;
652
671
  }
653
672
  };
654
- global.HTMLElement.prototype.requestPointerLock = function() {
655
- _pointerLockElement = this;
656
- doc.dispatchEvent(new Event("pointerlockchange"));
657
- };
658
- }
659
- };
660
- var InputInjector = class {
661
- constructor(doc, win) {
662
- this.doc = doc;
663
- this.win = win;
664
673
  }
665
- keyDown(key, code) {
666
- const event = new this.win.KeyboardEvent("keydown", {
667
- key,
668
- code: code || key,
669
- bubbles: true,
670
- cancelable: true,
671
- view: this.win
672
- });
673
- this.doc.dispatchEvent(event);
674
+ const originalCreateElement = document.createElement.bind(document);
675
+ document.createElement = function(tagName, options2) {
676
+ if (tagName.toLowerCase() === "canvas") {
677
+ const napiCanvas = new Canvas(300, 150);
678
+ const domCanvas = originalCreateElement("canvas", options2);
679
+ Object.defineProperty(domCanvas, "width", {
680
+ get: () => napiCanvas.width,
681
+ set: (value) => {
682
+ napiCanvas.width = value;
683
+ },
684
+ enumerable: true,
685
+ configurable: true
686
+ });
687
+ Object.defineProperty(domCanvas, "height", {
688
+ get: () => napiCanvas.height,
689
+ set: (value) => {
690
+ napiCanvas.height = value;
691
+ },
692
+ enumerable: true,
693
+ configurable: true
694
+ });
695
+ const originalGetContext = domCanvas.getContext.bind(domCanvas);
696
+ domCanvas.getContext = function(contextId, options3) {
697
+ if (contextId === "2d") {
698
+ return napiCanvas.getContext("2d", options3);
699
+ }
700
+ if (enableWebGL2 && contextId === "webgl2") {
701
+ return createMockWebGL2Context(domCanvas);
702
+ }
703
+ if (contextId === "webgl" || contextId === "webgl2") {
704
+ return originalGetContext(contextId, options3);
705
+ }
706
+ return napiCanvas.getContext(contextId, options3);
707
+ };
708
+ domCanvas.__napiCanvas = napiCanvas;
709
+ return domCanvas;
710
+ }
711
+ return originalCreateElement(tagName, options2);
712
+ };
713
+ if (enableWebGL2) {
714
+ const originalProtoGetContext = global.HTMLCanvasElement.prototype.getContext;
715
+ global.HTMLCanvasElement.prototype.getContext = function(contextId, options2) {
716
+ if (contextId === "webgl2") {
717
+ return createMockWebGL2Context(this);
718
+ }
719
+ return originalProtoGetContext.call(this, contextId, options2);
720
+ };
674
721
  }
675
- keyUp(key, code) {
676
- const event = new this.win.KeyboardEvent("keyup", {
677
- key,
678
- code: code || key,
679
- bubbles: true,
680
- cancelable: true,
681
- view: this.win
682
- });
683
- this.doc.dispatchEvent(event);
722
+ global.Image = Image;
723
+ global.ImageData = ImageData;
724
+ if (typeof global.createImageBitmap === "undefined") {
725
+ global.createImageBitmap = async function(image, _options) {
726
+ if (image && typeof image.width === "number" && typeof image.height === "number") {
727
+ const canvas2 = new Canvas(image.width, image.height);
728
+ const ctx = canvas2.getContext("2d");
729
+ if (image.data) {
730
+ ctx.putImageData(image, 0, 0);
731
+ }
732
+ return canvas2;
733
+ }
734
+ const canvas = new Canvas(100, 100);
735
+ return canvas;
736
+ };
684
737
  }
685
- mouseMove(movementX, movementY, clientX = 0, clientY = 0) {
686
- const event = new this.win.MouseEvent("mousemove", {
687
- bubbles: true,
688
- cancelable: true,
689
- view: this.win,
690
- clientX,
691
- clientY,
692
- movementX,
693
- // Note: JSDOM might not support this standard property fully on event init
694
- movementY
695
- });
696
- Object.defineProperty(event, "movementX", { value: movementX });
697
- Object.defineProperty(event, "movementY", { value: movementY });
698
- const target = this.doc.pointerLockElement || this.doc;
699
- target.dispatchEvent(event);
738
+ if (typeof global.btoa === "undefined") {
739
+ global.btoa = function(str) {
740
+ return Buffer.from(str, "binary").toString("base64");
741
+ };
700
742
  }
701
- mouseDown(button = 0) {
702
- const event = new this.win.MouseEvent("mousedown", {
703
- button,
704
- bubbles: true,
705
- cancelable: true,
706
- view: this.win
707
- });
708
- const target = this.doc.pointerLockElement || this.doc;
709
- target.dispatchEvent(event);
743
+ if (typeof global.atob === "undefined") {
744
+ global.atob = function(str) {
745
+ return Buffer.from(str, "base64").toString("binary");
746
+ };
710
747
  }
711
- mouseUp(button = 0) {
712
- const event = new this.win.MouseEvent("mouseup", {
713
- button,
714
- bubbles: true,
715
- cancelable: true,
716
- view: this.win
717
- });
718
- const target = this.doc.pointerLockElement || this.doc;
719
- target.dispatchEvent(event);
748
+ if (enablePointerLock) {
749
+ MockPointerLock.setup(global.document);
720
750
  }
721
- wheel(deltaY) {
722
- const event = new this.win.WheelEvent("wheel", {
723
- deltaY,
724
- bubbles: true,
725
- cancelable: true,
726
- view: this.win
727
- });
728
- const target = this.doc.pointerLockElement || this.doc;
729
- target.dispatchEvent(event);
751
+ if (typeof global.requestAnimationFrame === "undefined") {
752
+ let lastTime = 0;
753
+ global.requestAnimationFrame = (callback) => {
754
+ const currTime = Date.now();
755
+ const timeToCall = Math.max(0, 16 - (currTime - lastTime));
756
+ const id = setTimeout(() => {
757
+ callback(currTime + timeToCall);
758
+ }, timeToCall);
759
+ lastTime = currTime + timeToCall;
760
+ return id;
761
+ };
762
+ global.cancelAnimationFrame = (id) => {
763
+ clearTimeout(id);
764
+ };
765
+ }
766
+ }
767
+ function teardownBrowserEnvironment() {
768
+ delete global.window;
769
+ delete global.document;
770
+ delete global.navigator;
771
+ delete global.localStorage;
772
+ delete global.location;
773
+ delete global.HTMLElement;
774
+ delete global.HTMLCanvasElement;
775
+ delete global.Image;
776
+ delete global.ImageData;
777
+ delete global.createImageBitmap;
778
+ delete global.Event;
779
+ delete global.CustomEvent;
780
+ delete global.DragEvent;
781
+ delete global.MouseEvent;
782
+ delete global.KeyboardEvent;
783
+ delete global.FocusEvent;
784
+ delete global.WheelEvent;
785
+ delete global.InputEvent;
786
+ delete global.UIEvent;
787
+ }
788
+
789
+ // src/setup/node.ts
790
+ function setupNodeEnvironment() {
791
+ if (typeof global.fetch === "undefined") {
792
+ }
793
+ }
794
+
795
+ // src/setup/canvas.ts
796
+ import { Canvas as Canvas2, Image as Image2, ImageData as ImageData2 } from "@napi-rs/canvas";
797
+ function createMockCanvas(width = 300, height = 150) {
798
+ if (typeof document !== "undefined" && document.createElement) {
799
+ const canvas2 = document.createElement("canvas");
800
+ canvas2.width = width;
801
+ canvas2.height = height;
802
+ return canvas2;
803
+ }
804
+ const canvas = new Canvas2(width, height);
805
+ const originalGetContext = canvas.getContext.bind(canvas);
806
+ canvas.getContext = function(contextId, options) {
807
+ if (contextId === "webgl2") {
808
+ return createMockWebGL2Context(canvas);
809
+ }
810
+ if (contextId === "2d") {
811
+ return originalGetContext("2d", options);
812
+ }
813
+ return originalGetContext(contextId, options);
814
+ };
815
+ return canvas;
816
+ }
817
+ function createMockCanvasContext2D(canvas) {
818
+ if (!canvas) {
819
+ canvas = createMockCanvas();
820
+ }
821
+ return canvas.getContext("2d");
822
+ }
823
+ function captureCanvasDrawCalls(context) {
824
+ const drawCalls = [];
825
+ const methodsToSpy = [
826
+ "fillRect",
827
+ "strokeRect",
828
+ "clearRect",
829
+ "fillText",
830
+ "strokeText",
831
+ "drawImage",
832
+ "beginPath",
833
+ "closePath",
834
+ "moveTo",
835
+ "lineTo",
836
+ "arc",
837
+ "arcTo",
838
+ "bezierCurveTo",
839
+ "quadraticCurveTo",
840
+ "stroke",
841
+ "fill",
842
+ "putImageData"
843
+ ];
844
+ methodsToSpy.forEach((method) => {
845
+ const original = context[method];
846
+ if (typeof original === "function") {
847
+ context[method] = function(...args) {
848
+ drawCalls.push({ method, args });
849
+ return original.apply(this, args);
850
+ };
851
+ }
852
+ });
853
+ return drawCalls;
854
+ }
855
+ function createMockImageData(width, height, fillColor) {
856
+ const imageData = new ImageData2(width, height);
857
+ if (fillColor) {
858
+ const [r, g, b, a] = fillColor;
859
+ for (let i = 0; i < imageData.data.length; i += 4) {
860
+ imageData.data[i] = r;
861
+ imageData.data[i + 1] = g;
862
+ imageData.data[i + 2] = b;
863
+ imageData.data[i + 3] = a;
864
+ }
865
+ }
866
+ return imageData;
867
+ }
868
+ function createMockImage(width, height, src) {
869
+ const img = new Image2();
870
+ if (width) img.width = width;
871
+ if (height) img.height = height;
872
+ if (src) img.src = src;
873
+ return img;
874
+ }
875
+
876
+ // src/setup/timing.ts
877
+ function createMockRAF() {
878
+ let callbacks = [];
879
+ let nextId = 1;
880
+ let currentTime = 0;
881
+ const originalRAF = global.requestAnimationFrame;
882
+ const originalCancelRAF = global.cancelAnimationFrame;
883
+ const raf = (callback) => {
884
+ const id = nextId++;
885
+ callbacks.push({ id, callback });
886
+ return id;
887
+ };
888
+ const cancel = (id) => {
889
+ callbacks = callbacks.filter((cb) => cb.id !== id);
890
+ };
891
+ const mock = {
892
+ tick(timestamp) {
893
+ if (typeof timestamp !== "number") {
894
+ currentTime += 16.6;
895
+ } else {
896
+ currentTime = timestamp;
897
+ }
898
+ const currentCallbacks = [...callbacks];
899
+ callbacks = [];
900
+ currentCallbacks.forEach(({ callback }) => {
901
+ callback(currentTime);
902
+ });
903
+ },
904
+ advance(deltaMs = 16.6) {
905
+ this.tick(currentTime + deltaMs);
906
+ },
907
+ getCallbacks() {
908
+ return callbacks.map((c) => c.callback);
909
+ },
910
+ reset() {
911
+ callbacks = [];
912
+ nextId = 1;
913
+ currentTime = 0;
914
+ },
915
+ enable() {
916
+ global.requestAnimationFrame = raf;
917
+ global.cancelAnimationFrame = cancel;
918
+ },
919
+ disable() {
920
+ if (originalRAF) {
921
+ global.requestAnimationFrame = originalRAF;
922
+ } else {
923
+ delete global.requestAnimationFrame;
924
+ }
925
+ if (originalCancelRAF) {
926
+ global.cancelAnimationFrame = originalCancelRAF;
927
+ } else {
928
+ delete global.cancelAnimationFrame;
929
+ }
930
+ }
931
+ };
932
+ return mock;
933
+ }
934
+ function createMockPerformance(startTime = 0) {
935
+ let currentTime = startTime;
936
+ const mockPerf = {
937
+ now: () => currentTime,
938
+ timeOrigin: startTime,
939
+ timing: {
940
+ navigationStart: startTime
941
+ },
942
+ // Add minimal navigation/resource timing interfaces to satisfy types if needed
943
+ clearMarks: () => {
944
+ },
945
+ clearMeasures: () => {
946
+ },
947
+ clearResourceTimings: () => {
948
+ },
949
+ getEntries: () => [],
950
+ getEntriesByName: () => [],
951
+ getEntriesByType: () => [],
952
+ mark: () => {
953
+ },
954
+ measure: () => {
955
+ },
956
+ setResourceTimingBufferSize: () => {
957
+ },
958
+ toJSON: () => ({}),
959
+ addEventListener: () => {
960
+ },
961
+ removeEventListener: () => {
962
+ },
963
+ dispatchEvent: () => true
964
+ };
965
+ mockPerf.advance = (deltaMs) => {
966
+ currentTime += deltaMs;
967
+ };
968
+ mockPerf.setTime = (time) => {
969
+ currentTime = time;
970
+ };
971
+ return mockPerf;
972
+ }
973
+ function simulateFrames(count, frameTimeMs = 16.6, callback) {
974
+ const raf = global.requestAnimationFrame;
975
+ if (!raf) return;
976
+ }
977
+ function simulateFramesWithMock(mock, count, frameTimeMs = 16.6, callback) {
978
+ for (let i = 0; i < count; i++) {
979
+ if (callback) callback(i);
980
+ mock.advance(frameTimeMs);
981
+ }
982
+ }
983
+
984
+ // src/setup/storage.ts
985
+ import "fake-indexeddb/auto";
986
+ function createMockLocalStorage(initialData = {}) {
987
+ const storage = new Map(Object.entries(initialData));
988
+ return {
989
+ getItem: (key) => storage.get(key) || null,
990
+ setItem: (key, value) => storage.set(key, value),
991
+ removeItem: (key) => storage.delete(key),
992
+ clear: () => storage.clear(),
993
+ key: (index) => Array.from(storage.keys())[index] || null,
994
+ get length() {
995
+ return storage.size;
996
+ }
997
+ };
998
+ }
999
+ function createMockSessionStorage(initialData = {}) {
1000
+ return createMockLocalStorage(initialData);
1001
+ }
1002
+ function createMockIndexedDB() {
1003
+ if (typeof indexedDB === "undefined") {
1004
+ throw new Error("IndexedDB mock not found. Ensure fake-indexeddb is loaded.");
1005
+ }
1006
+ return indexedDB;
1007
+ }
1008
+ function createStorageTestScenario(storageType = "local") {
1009
+ const storage = storageType === "local" ? createMockLocalStorage() : createMockSessionStorage();
1010
+ return {
1011
+ storage,
1012
+ populate(data) {
1013
+ Object.entries(data).forEach(([k, v]) => storage.setItem(k, v));
1014
+ },
1015
+ verify(key, value) {
1016
+ return storage.getItem(key) === value;
1017
+ }
1018
+ };
1019
+ }
1020
+
1021
+ // src/setup/audio.ts
1022
+ function createMockAudioContext() {
1023
+ return {
1024
+ createGain: () => ({
1025
+ connect: () => {
1026
+ },
1027
+ gain: { value: 1, setValueAtTime: () => {
1028
+ } }
1029
+ }),
1030
+ createOscillator: () => ({
1031
+ connect: () => {
1032
+ },
1033
+ start: () => {
1034
+ },
1035
+ stop: () => {
1036
+ },
1037
+ frequency: { value: 440 }
1038
+ }),
1039
+ createBufferSource: () => ({
1040
+ connect: () => {
1041
+ },
1042
+ start: () => {
1043
+ },
1044
+ stop: () => {
1045
+ },
1046
+ buffer: null,
1047
+ playbackRate: { value: 1 },
1048
+ loop: false
1049
+ }),
1050
+ destination: {},
1051
+ currentTime: 0,
1052
+ state: "running",
1053
+ resume: async () => {
1054
+ },
1055
+ suspend: async () => {
1056
+ },
1057
+ close: async () => {
1058
+ },
1059
+ decodeAudioData: async (buffer) => ({
1060
+ duration: 1,
1061
+ length: 44100,
1062
+ sampleRate: 44100,
1063
+ numberOfChannels: 2,
1064
+ getChannelData: () => new Float32Array(44100)
1065
+ }),
1066
+ createBuffer: (channels, length, sampleRate) => ({
1067
+ duration: length / sampleRate,
1068
+ length,
1069
+ sampleRate,
1070
+ numberOfChannels: channels,
1071
+ getChannelData: () => new Float32Array(length)
1072
+ })
1073
+ };
1074
+ }
1075
+ function setupMockAudioContext() {
1076
+ if (typeof global.AudioContext === "undefined" && typeof global.window !== "undefined") {
1077
+ global.AudioContext = class {
1078
+ constructor() {
1079
+ return createMockAudioContext();
1080
+ }
1081
+ };
1082
+ global.window.AudioContext = global.AudioContext;
1083
+ global.window.webkitAudioContext = global.AudioContext;
1084
+ }
1085
+ }
1086
+ function teardownMockAudioContext() {
1087
+ if (global.AudioContext && global.AudioContext.toString().includes("class")) {
1088
+ delete global.AudioContext;
1089
+ delete global.window.AudioContext;
1090
+ delete global.window.webkitAudioContext;
1091
+ }
1092
+ }
1093
+ function captureAudioEvents(context) {
1094
+ return [];
1095
+ }
1096
+
1097
+ // src/e2e/playwright.ts
1098
+ import { chromium } from "playwright";
1099
+ async function createPlaywrightTestClient(options = {}) {
1100
+ const browser = await chromium.launch({
1101
+ headless: options.headless ?? true,
1102
+ args: options.args || [
1103
+ "--use-gl=egl",
1104
+ "--ignore-gpu-blocklist",
1105
+ "--no-sandbox",
1106
+ "--disable-setuid-sandbox"
1107
+ ]
1108
+ });
1109
+ const context = await browser.newContext({
1110
+ viewport: options.viewport || { width: 1280, height: 720 },
1111
+ recordVideo: options.recordVideo,
1112
+ deviceScaleFactor: 1
1113
+ });
1114
+ const page = await context.newPage();
1115
+ const waitForGame = async (timeout = 1e4) => {
1116
+ try {
1117
+ await page.waitForFunction(() => {
1118
+ return window.game || document.querySelector("canvas");
1119
+ }, null, { timeout });
1120
+ } catch (e) {
1121
+ throw new Error(`Game did not initialize within ${timeout}ms`);
1122
+ }
1123
+ };
1124
+ const client = {
1125
+ browser,
1126
+ context,
1127
+ page,
1128
+ async navigate(url) {
1129
+ await page.goto(url, { waitUntil: "domcontentloaded" });
1130
+ },
1131
+ async waitForGame(timeout) {
1132
+ await waitForGame(timeout);
1133
+ },
1134
+ async injectInput(type, key) {
1135
+ if (type === "keydown") {
1136
+ await page.keyboard.down(key);
1137
+ } else {
1138
+ await page.keyboard.up(key);
1139
+ }
1140
+ },
1141
+ async injectMouse(type, x = 0, y = 0, button = 0) {
1142
+ if (type === "move") {
1143
+ await page.mouse.move(x, y);
1144
+ } else if (type === "down") {
1145
+ await page.mouse.down({ button: button === 0 ? "left" : button === 2 ? "right" : "middle" });
1146
+ } else if (type === "up") {
1147
+ await page.mouse.up({ button: button === 0 ? "left" : button === 2 ? "right" : "middle" });
1148
+ }
1149
+ },
1150
+ async screenshot(path2) {
1151
+ await page.screenshot({ path: path2 });
1152
+ },
1153
+ async close() {
1154
+ await browser.close();
1155
+ }
1156
+ };
1157
+ return client;
1158
+ }
1159
+ async function waitForGameReady(page, timeout = 1e4) {
1160
+ await page.waitForFunction(() => {
1161
+ return window.game || document.querySelector("canvas");
1162
+ }, null, { timeout });
1163
+ }
1164
+ async function captureGameState(page) {
1165
+ return await page.evaluate(() => {
1166
+ const game = window.game;
1167
+ if (!game) return {};
1168
+ return {};
1169
+ });
1170
+ }
1171
+
1172
+ // src/e2e/network.ts
1173
+ var CONDITIONS = {
1174
+ "good": {
1175
+ offline: false,
1176
+ downloadThroughput: 10 * 1024 * 1024,
1177
+ // 10 Mbps
1178
+ uploadThroughput: 5 * 1024 * 1024,
1179
+ // 5 Mbps
1180
+ latency: 20
1181
+ },
1182
+ "slow": {
1183
+ offline: false,
1184
+ downloadThroughput: 500 * 1024,
1185
+ // 500 Kbps
1186
+ uploadThroughput: 500 * 1024,
1187
+ latency: 400
1188
+ },
1189
+ "unstable": {
1190
+ offline: false,
1191
+ downloadThroughput: 1 * 1024 * 1024,
1192
+ uploadThroughput: 1 * 1024 * 1024,
1193
+ latency: 100
1194
+ // Jitter needs logic not simple preset
1195
+ },
1196
+ "offline": {
1197
+ offline: true,
1198
+ downloadThroughput: 0,
1199
+ uploadThroughput: 0,
1200
+ latency: 0
730
1201
  }
731
1202
  };
1203
+ function simulateNetworkCondition(condition) {
1204
+ const config = CONDITIONS[condition];
1205
+ return createCustomNetworkCondition(config.latency, 0, 0, config);
1206
+ }
1207
+ function createCustomNetworkCondition(latency, jitter = 0, packetLoss = 0, baseConfig) {
1208
+ return {
1209
+ async apply(page) {
1210
+ const client = await page.context().newCDPSession(page);
1211
+ await client.send("Network.enable");
1212
+ await client.send("Network.emulateNetworkConditions", {
1213
+ offline: baseConfig?.offline || false,
1214
+ latency: latency + Math.random() * jitter,
1215
+ // Basic jitter application on setup (static)
1216
+ downloadThroughput: baseConfig?.downloadThroughput || -1,
1217
+ uploadThroughput: baseConfig?.uploadThroughput || -1
1218
+ });
1219
+ },
1220
+ async clear(page) {
1221
+ const client = await page.context().newCDPSession(page);
1222
+ await client.send("Network.emulateNetworkConditions", {
1223
+ offline: false,
1224
+ latency: 0,
1225
+ downloadThroughput: -1,
1226
+ uploadThroughput: -1
1227
+ });
1228
+ }
1229
+ };
1230
+ }
1231
+ async function throttleBandwidth(page, bytesPerSecond) {
1232
+ const simulator = createCustomNetworkCondition(0, 0, 0, {
1233
+ offline: false,
1234
+ latency: 0,
1235
+ downloadThroughput: bytesPerSecond,
1236
+ uploadThroughput: bytesPerSecond
1237
+ });
1238
+ await simulator.apply(page);
1239
+ }
1240
+
1241
+ // src/e2e/visual.ts
1242
+ import path from "path";
1243
+ import fs from "fs/promises";
1244
+ async function captureGameScreenshot(page, name, options = {}) {
1245
+ const dir = options.dir || "__screenshots__";
1246
+ const screenshotPath = path.join(dir, `${name}.png`);
1247
+ await fs.mkdir(dir, { recursive: true });
1248
+ return await page.screenshot({
1249
+ path: screenshotPath,
1250
+ fullPage: options.fullPage ?? false,
1251
+ animations: "disabled",
1252
+ // Try to freeze animations if possible
1253
+ caret: "hide"
1254
+ });
1255
+ }
1256
+ async function compareScreenshots(baseline, current, threshold = 0.1) {
1257
+ if (baseline.equals(current)) {
1258
+ return { pixelDiff: 0, matched: true };
1259
+ }
1260
+ return {
1261
+ pixelDiff: -1,
1262
+ // Unknown magnitude
1263
+ matched: false
1264
+ };
1265
+ }
1266
+ function createVisualTestScenario(page, sceneName) {
1267
+ return {
1268
+ async capture(snapshotName) {
1269
+ return await captureGameScreenshot(page, `${sceneName}-${snapshotName}`);
1270
+ },
1271
+ async compare(snapshotName, baselineDir) {
1272
+ const name = `${sceneName}-${snapshotName}`;
1273
+ const current = await captureGameScreenshot(page, name, { dir: "__screenshots__/current" });
1274
+ try {
1275
+ const baselinePath = path.join(baselineDir, `${name}.png`);
1276
+ const baseline = await fs.readFile(baselinePath);
1277
+ return await compareScreenshots(baseline, current);
1278
+ } catch (e) {
1279
+ return { pixelDiff: -1, matched: false };
1280
+ }
1281
+ }
1282
+ };
1283
+ }
732
1284
  export {
733
1285
  InputInjector,
734
1286
  MockPointerLock,
1287
+ captureAudioEvents,
1288
+ captureCanvasDrawCalls,
1289
+ captureGameScreenshot,
1290
+ captureGameState,
1291
+ compareScreenshots,
735
1292
  createBinaryStreamMock,
736
1293
  createBinaryWriterMock,
1294
+ createCustomNetworkCondition,
737
1295
  createEntity,
738
1296
  createEntityStateFactory,
739
1297
  createGameStateSnapshotFactory,
1298
+ createMockAudioContext,
1299
+ createMockCanvas,
1300
+ createMockCanvasContext2D,
740
1301
  createMockEngine,
741
1302
  createMockGame,
1303
+ createMockImage,
1304
+ createMockImageData,
1305
+ createMockIndexedDB,
1306
+ createMockLocalStorage,
1307
+ createMockPerformance,
1308
+ createMockRAF,
1309
+ createMockSessionStorage,
742
1310
  createMockWebGL2Context,
743
1311
  createNetChanMock,
744
1312
  createPlayerStateFactory,
1313
+ createPlaywrightTestClient,
745
1314
  createSpawnContext,
1315
+ createStorageTestScenario,
746
1316
  createTestContext,
1317
+ createVisualTestScenario,
747
1318
  intersects,
748
1319
  ladderTrace,
749
1320
  makeAxisBrush,
@@ -754,8 +1325,15 @@ export {
754
1325
  makeNode,
755
1326
  makePlane,
756
1327
  setupBrowserEnvironment,
1328
+ setupMockAudioContext,
757
1329
  setupNodeEnvironment,
1330
+ simulateFrames,
1331
+ simulateFramesWithMock,
1332
+ simulateNetworkCondition,
758
1333
  stairTrace,
759
- teardownBrowserEnvironment
1334
+ teardownBrowserEnvironment,
1335
+ teardownMockAudioContext,
1336
+ throttleBandwidth,
1337
+ waitForGameReady
760
1338
  };
761
1339
  //# sourceMappingURL=index.js.map