From 3e14bed41fb556c7cbce2ee258f11dfdbeb3d3e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrian=20Or=C5=82=C3=B3w?= <adrian.orlow@fishbrain.com>
Date: Fri, 17 Nov 2023 18:00:23 +0100
Subject: [PATCH] test: add tests for the pin rendering module

---
 package-lock.json                             |  26 +++++
 package.json                                  |   1 +
 setupTests.ts                                 |   1 +
 .../utils/config/getCanvasIcon.test.ts        | 100 ++++++++++++++++++
 .../MapViewer/utils/config/getCanvasIcon.ts   |  14 ++-
 .../utils/config/useOlMapLayers.test.ts       |  21 +++-
 .../MapViewer/utils/config/useOlMapLayers.ts  |   2 +-
 .../utils/config/useOlMapTileLayer.test.ts    |  77 ++++++++++++++
 .../utils/config/useOlMapView.test.ts         |   2 +-
 src/utils/canvas/getCanvas.test.ts            |  15 +++
 src/utils/canvas/getFontSizeToFit.test.ts     |  25 +++++
 src/utils/canvas/getFontSizeToFit.ts          |   4 +-
 yarn.lock                                     |  68 +++++-------
 13 files changed, 302 insertions(+), 54 deletions(-)
 create mode 100644 src/components/Map/MapViewer/utils/config/getCanvasIcon.test.ts
 create mode 100644 src/components/Map/MapViewer/utils/config/useOlMapTileLayer.test.ts
 create mode 100644 src/utils/canvas/getCanvas.test.ts
 create mode 100644 src/utils/canvas/getFontSizeToFit.test.ts

diff --git a/package-lock.json b/package-lock.json
index 6b0f180a..fb3ac0a3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -62,6 +62,7 @@
         "eslint-plugin-testing-library": "^6.0.1",
         "husky": "^8.0.0",
         "jest": "^29.7.0",
+        "jest-canvas-mock": "^2.5.2",
         "jest-environment-jsdom": "^29.7.0",
         "jest-junit": "^16.0.0",
         "jest-watch-typeahead": "^2.2.2",
@@ -4024,6 +4025,12 @@
         "node": ">=4"
       }
     },
+    "node_modules/cssfontparser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/cssfontparser/-/cssfontparser-1.2.1.tgz",
+      "integrity": "sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==",
+      "dev": true
+    },
     "node_modules/cssom": {
       "version": "0.5.0",
       "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
@@ -7648,6 +7655,16 @@
         }
       }
     },
+    "node_modules/jest-canvas-mock": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/jest-canvas-mock/-/jest-canvas-mock-2.5.2.tgz",
+      "integrity": "sha512-vgnpPupjOL6+L5oJXzxTxFrlGEIbHdZqFU+LFNdtLxZ3lRDCl17FlTMM7IatoRQkrcyOTMlDinjUguqmQ6bR2A==",
+      "dev": true,
+      "dependencies": {
+        "cssfontparser": "^1.2.1",
+        "moo-color": "^1.0.2"
+      }
+    },
     "node_modules/jest-changed-files": {
       "version": "29.7.0",
       "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
@@ -9745,6 +9762,15 @@
         "node": ">=10"
       }
     },
+    "node_modules/moo-color": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/moo-color/-/moo-color-1.0.3.tgz",
+      "integrity": "sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "^1.1.4"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
diff --git a/package.json b/package.json
index c5b84e0b..8b060676 100644
--- a/package.json
+++ b/package.json
@@ -76,6 +76,7 @@
     "eslint-plugin-testing-library": "^6.0.1",
     "husky": "^8.0.0",
     "jest": "^29.7.0",
+    "jest-canvas-mock": "^2.5.2",
     "jest-environment-jsdom": "^29.7.0",
     "jest-junit": "^16.0.0",
     "jest-watch-typeahead": "^2.2.2",
diff --git a/setupTests.ts b/setupTests.ts
index 11a7da9a..db87ae92 100644
--- a/setupTests.ts
+++ b/setupTests.ts
@@ -1,4 +1,5 @@
 import '@testing-library/jest-dom';
+import 'jest-canvas-mock';
 
 // used by openlayers module
 global.ResizeObserver = jest.fn().mockImplementation(() => ({
diff --git a/src/components/Map/MapViewer/utils/config/getCanvasIcon.test.ts b/src/components/Map/MapViewer/utils/config/getCanvasIcon.test.ts
new file mode 100644
index 00000000..2915ff79
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/getCanvasIcon.test.ts
@@ -0,0 +1,100 @@
+/* eslint-disable no-magic-numbers */
+import { DEFAULT_FONT_FAMILY } from '@/constants/font';
+import { getCanvas } from '@/utils/canvas/getCanvas';
+import {
+  drawNumberOnCanvas,
+  drawPinOnCanvas,
+  getTextPosition,
+  getTextWidth,
+} from './getCanvasIcon';
+
+const getContext = (): CanvasRenderingContext2D => {
+  const canvas = getCanvas({ width: 100, height: 100 });
+  return canvas.getContext('2d') as CanvasRenderingContext2D;
+};
+
+const ONCE = 1;
+
+describe('getCanvasIcon - util', () => {
+  beforeEach(() => {
+    jest.restoreAllMocks();
+  });
+
+  describe('getTextWidth - subUtil', () => {
+    const cases: [number, number][] = [
+      [1, 6.25],
+      [7, 8.333],
+      [43, 12.5],
+      [105, 16.666],
+    ];
+
+    it.each(cases)('on value=%s should return %s', (input, output) => {
+      expect(getTextWidth(input)).toBeCloseTo(output);
+    });
+  });
+
+  describe('getTextPosition - subUtil', () => {
+    const cases: [number, number, number, number][] = [
+      [100, 100, -37.5, -27.2],
+      [532, 443, -253.5, -164.4],
+      [10, 0, 7.5, 12.8],
+      [0, 10, 12.5, 8.8],
+      [0, 0, 12.5, 12.8],
+    ];
+
+    it.each(cases)(
+      'on textWidth=%s textHeight=%s should return x=%s y=%s',
+      (textWidth, textHeight, x, y) => {
+        expect(getTextPosition(textWidth, textHeight)).toMatchObject({
+          x,
+          y,
+        });
+      },
+    );
+  });
+
+  describe('drawPinOnCanvas - subUtil', () => {
+    const color = '#000000';
+
+    it('should run set fillStyle with color', () => {
+      const ctx = getContext();
+      drawPinOnCanvas({ color }, ctx);
+      expect(ctx.fillStyle).toBe(color);
+    });
+
+    it('should run fill method with valid arguments', () => {
+      const ctx = getContext();
+      const fillSpy = jest.spyOn(ctx, 'fill');
+      drawPinOnCanvas({ color }, ctx);
+
+      const call = fillSpy.mock.calls[0][0];
+      expect(call).toBeInstanceOf(Path2D);
+      expect(fillSpy).toBeCalledTimes(ONCE);
+    });
+  });
+
+  describe('drawNumberOnCanvas - subUtil', () => {
+    const ctx = getContext();
+    const fillTextSpy = jest.spyOn(ctx, 'fillText');
+    const value = 69;
+
+    beforeAll(() => {
+      drawNumberOnCanvas(
+        {
+          value,
+        },
+        ctx,
+      );
+    });
+    it('should set valid ctx fields', () => {
+      expect(ctx.fillStyle).toBe('#ffffff');
+      expect(ctx.textBaseline).toBe('top');
+      expect(ctx.font).toBe(`6.25px ${DEFAULT_FONT_FAMILY}`);
+    });
+
+    it('should run fillText once with valid args', () => {
+      expect(fillTextSpy).toBeCalledWith(`${value}`, 6.25, 12.8);
+      expect(fillTextSpy).toBeCalledTimes(ONCE);
+    });
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/getCanvasIcon.ts b/src/components/Map/MapViewer/utils/config/getCanvasIcon.ts
index 0229e86b..7df1b0b0 100644
--- a/src/components/Map/MapViewer/utils/config/getCanvasIcon.ts
+++ b/src/components/Map/MapViewer/utils/config/getCanvasIcon.ts
@@ -14,13 +14,16 @@ interface Args {
   value: number;
 }
 
-const drawPinOnCanvas = ({ color }: Args, ctx: CanvasRenderingContext2D): void => {
+export const drawPinOnCanvas = (
+  { color }: Pick<Args, 'color'>,
+  ctx: CanvasRenderingContext2D,
+): void => {
   const path = new Path2D(PIN_PATH2D);
   ctx.fillStyle = color;
   ctx.fill(path);
 };
 
-const getTextWidth = (value: number): number => {
+export const getTextWidth = (value: number): number => {
   switch (true) {
     case value === SMALL_TEXT_VALUE:
       return PIN_SIZE.width / QUARTER;
@@ -33,12 +36,15 @@ const getTextWidth = (value: number): number => {
   }
 };
 
-const getTextPosition = (textWidth: number, textHeight: number): Point => ({
+export const getTextPosition = (textWidth: number, textHeight: number): Point => ({
   x: (PIN_SIZE.width - textWidth) / HALF,
   y: (PIN_SIZE.height - textHeight) / TWO_AND_HALF,
 });
 
-const drawNumberOnCanvas = ({ value }: Args, ctx: CanvasRenderingContext2D): void => {
+export const drawNumberOnCanvas = (
+  { value }: Pick<Args, 'value'>,
+  ctx: CanvasRenderingContext2D,
+): void => {
   const text = `${value}`;
   const textMetrics = ctx.measureText(text);
 
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts b/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts
index 1ed0fcc6..00a22c0b 100644
--- a/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts
+++ b/src/components/Map/MapViewer/utils/config/useOlMapLayers.test.ts
@@ -5,7 +5,9 @@ import { getReduxWrapperUsingSliceReducer } from '@/utils/testing/getReduxWrappe
 import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { renderHook, waitFor } from '@testing-library/react';
 import { Map } from 'ol';
+import BaseLayer from 'ol/layer/Base';
 import TileLayer from 'ol/layer/Tile';
+import VectorLayer from 'ol/layer/Vector';
 import React from 'react';
 import { useOlMap } from '../useOlMap';
 import { useOlMapLayers } from './useOlMapLayers';
@@ -46,7 +48,7 @@ describe('useOlMapLayers - util', () => {
     await waitFor(() => expect(setLayersSpy).toBeCalledTimes(CALLED_ONCE));
   });
 
-  it('should return valid View instance', async () => {
+  const getRenderedHookResults = (): BaseLayer[] => {
     const { Wrapper } = getReduxWrapperWithStore({
       map: {
         data: {
@@ -89,7 +91,20 @@ describe('useOlMapLayers - util', () => {
       },
     );
 
-    expect(result.current[0]).toBeInstanceOf(TileLayer);
-    expect(result.current[0].getSourceState()).toBe('ready');
+    return result.current;
+  };
+
+  it('should return valid TileLayer instance', () => {
+    const result = getRenderedHookResults();
+
+    expect(result[0]).toBeInstanceOf(TileLayer);
+    expect(result[0].getSourceState()).toBe('ready');
+  });
+
+  it('should return valid VectorLayer instance', () => {
+    const result = getRenderedHookResults();
+
+    expect(result[1]).toBeInstanceOf(VectorLayer);
+    expect(result[1].getSourceState()).toBe('ready');
   });
 });
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts b/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts
index 350a1aec..c092a146 100644
--- a/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts
+++ b/src/components/Map/MapViewer/utils/config/useOlMapLayers.ts
@@ -20,5 +20,5 @@ export const useOlMapLayers = ({ mapInstance }: UseOlMapLayersInput): MapConfig[
     mapInstance.setLayers([tileLayer, pinsLayer]);
   }, [tileLayer, pinsLayer, mapInstance]);
 
-  return [tileLayer];
+  return [tileLayer, pinsLayer];
 };
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapTileLayer.test.ts b/src/components/Map/MapViewer/utils/config/useOlMapTileLayer.test.ts
new file mode 100644
index 00000000..8c5321cb
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/useOlMapTileLayer.test.ts
@@ -0,0 +1,77 @@
+/* eslint-disable no-magic-numbers */
+import { MAP_DATA_INITIAL_STATE, OPENED_MAPS_INITIAL_STATE } from '@/redux/map/map.constants';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
+import BaseLayer from 'ol/layer/Base';
+import TileLayer from 'ol/layer/Tile';
+import React from 'react';
+import { useOlMapTileLayer } from './useOlMapTileLayer';
+
+const useRefValue = {
+  current: null,
+};
+
+Object.defineProperty(useRefValue, 'current', {
+  get: jest.fn(() => ({
+    innerHTML: '',
+    appendChild: jest.fn(),
+    addEventListener: jest.fn(),
+    getRootNode: jest.fn(),
+  })),
+  set: jest.fn(() => ({
+    innerHTML: '',
+    appendChild: jest.fn(),
+    addEventListener: jest.fn(),
+    getRootNode: jest.fn(),
+  })),
+});
+
+jest.spyOn(React, 'useRef').mockReturnValue(useRefValue);
+
+describe('useOlMapTileLayer - util', () => {
+  const getRenderedHookResults = (): BaseLayer => {
+    const { Wrapper } = getReduxWrapperWithStore({
+      map: {
+        data: {
+          ...MAP_DATA_INITIAL_STATE,
+          size: {
+            width: 256,
+            height: 256,
+            tileSize: 256,
+            minZoom: 1,
+            maxZoom: 1,
+          },
+          position: {
+            initial: {
+              x: 256,
+              y: 256,
+            },
+            last: {
+              x: 256,
+              y: 256,
+            },
+          },
+        },
+        loading: 'idle',
+        error: {
+          name: '',
+          message: '',
+        },
+        openedMaps: OPENED_MAPS_INITIAL_STATE,
+      },
+    });
+
+    const { result } = renderHook(() => useOlMapTileLayer(), {
+      wrapper: Wrapper,
+    });
+
+    return result.current;
+  };
+
+  it('should return valid TileLayer instance', () => {
+    const result = getRenderedHookResults();
+
+    expect(result).toBeInstanceOf(TileLayer);
+    expect(result.getSourceState()).toBe('ready');
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts b/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts
index aa6137cb..c50c543a 100644
--- a/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts
+++ b/src/components/Map/MapViewer/utils/config/useOlMapView.test.ts
@@ -1,9 +1,9 @@
 /* eslint-disable no-magic-numbers */
+import { MAP_DATA_INITIAL_STATE, OPENED_MAPS_INITIAL_STATE } from '@/redux/map/map.constants';
 import mapSlice, { setMapPosition } from '@/redux/map/map.slice';
 import { getReduxWrapperUsingSliceReducer } from '@/utils/testing/getReduxWrapperUsingSliceReducer';
 import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { renderHook, waitFor } from '@testing-library/react';
-import { MAP_DATA_INITIAL_STATE, OPENED_MAPS_INITIAL_STATE } from '@/redux/map/map.constants';
 import { View } from 'ol';
 import Map from 'ol/Map';
 import React from 'react';
diff --git a/src/utils/canvas/getCanvas.test.ts b/src/utils/canvas/getCanvas.test.ts
new file mode 100644
index 00000000..fec95f0b
--- /dev/null
+++ b/src/utils/canvas/getCanvas.test.ts
@@ -0,0 +1,15 @@
+/* eslint-disable no-magic-numbers */
+import { getCanvas } from './getCanvas';
+
+describe('getCanvas', () => {
+  it('should return HTMLCanvasElement with valid size on positive params', () => {
+    const result = getCanvas({
+      width: 800,
+      height: 600,
+    });
+
+    expect(result).toBeInstanceOf(HTMLCanvasElement);
+    expect(result.width).toEqual(800);
+    expect(result.height).toEqual(600);
+  });
+});
diff --git a/src/utils/canvas/getFontSizeToFit.test.ts b/src/utils/canvas/getFontSizeToFit.test.ts
new file mode 100644
index 00000000..3f5dea7b
--- /dev/null
+++ b/src/utils/canvas/getFontSizeToFit.test.ts
@@ -0,0 +1,25 @@
+/* eslint-disable no-magic-numbers */
+import { getCanvas } from './getCanvas';
+import { getFontSizeToFit } from './getFontSizeToFit';
+
+const getContext = (): CanvasRenderingContext2D => {
+  const canvas = getCanvas({ width: 100, height: 100 });
+  return canvas.getContext('2d') as CanvasRenderingContext2D;
+};
+
+describe('getFontSizeToFit', () => {
+  const cases: [string, string, number, number][] = [
+    ['Hello', 'Helvetica', 50, 10],
+    ['123', 'Arial', 48, 16],
+    ['1', '', 48, 48],
+    ['Text', '', 0, 0],
+    ['', '', 0, 0],
+  ];
+  it.each(cases)(
+    'on text=%s, fontFace=%s, maxWidth=%s it should return value %s',
+    (text, fontFace, maxWidth, result) => {
+      const ctx = getContext();
+      expect(getFontSizeToFit(ctx, text, fontFace, maxWidth)).toBeCloseTo(result);
+    },
+  );
+});
diff --git a/src/utils/canvas/getFontSizeToFit.ts b/src/utils/canvas/getFontSizeToFit.ts
index c74b4b05..dfad99cf 100644
--- a/src/utils/canvas/getFontSizeToFit.ts
+++ b/src/utils/canvas/getFontSizeToFit.ts
@@ -1,3 +1,5 @@
+const DEFAULT_VALID_SIZE = 0;
+
 export const getFontSizeToFit = (
   ctx: CanvasRenderingContext2D,
   text: string,
@@ -5,5 +7,5 @@ export const getFontSizeToFit = (
   maxWidth: number,
 ): number => {
   ctx.font = `1px ${fontFace}`;
-  return maxWidth / ctx.measureText(text).width;
+  return maxWidth / ctx.measureText(text).width || DEFAULT_VALID_SIZE;
 };
diff --git a/yarn.lock b/yarn.lock
index e5bd596f..2c6c5417 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -847,49 +847,9 @@
   "resolved" "https://registry.npmjs.org/@next/font/-/font-13.5.4.tgz"
   "version" "13.5.4"
 
-"@next/swc-darwin-x64@13.4.19":
-  "integrity" "sha512-jyzO6wwYhx6F+7gD8ddZfuqO4TtpJdw3wyOduR4fxTUCm3aLw7YmHGYNjS0xRSYGAkLpBkH1E0RcelyId6lNsw=="
-  "resolved" "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.19.tgz"
-  "version" "13.4.19"
-
-"@next/swc-darwin-x64@13.4.19":
-  "integrity" "sha512-jyzO6wwYhx6F+7gD8ddZfuqO4TtpJdw3wyOduR4fxTUCm3aLw7YmHGYNjS0xRSYGAkLpBkH1E0RcelyId6lNsw=="
-  "resolved" "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.19.tgz"
-  "version" "13.4.19"
-
-"@next/swc-linux-arm64-gnu@13.4.19":
-  "integrity" "sha512-vdlnIlaAEh6H+G6HrKZB9c2zJKnpPVKnA6LBwjwT2BTjxI7e0Hx30+FoWCgi50e+YO49p6oPOtesP9mXDRiiUg=="
-  "resolved" "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.19.tgz"
-  "version" "13.4.19"
-
-"@next/swc-linux-arm64-musl@13.4.19":
-  "integrity" "sha512-aU0HkH2XPgxqrbNRBFb3si9Ahu/CpaR5RPmN2s9GiM9qJCiBBlZtRTiEca+DC+xRPyCThTtWYgxjWHgU7ZkyvA=="
-  "resolved" "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.19.tgz"
-  "version" "13.4.19"
-
-"@next/swc-linux-x64-gnu@13.4.19":
-  "integrity" "sha512-htwOEagMa/CXNykFFeAHHvMJeqZfNQEoQvHfsA4wgg5QqGNqD5soeCer4oGlCol6NGUxknrQO6VEustcv+Md+g=="
-  "resolved" "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.19.tgz"
-  "version" "13.4.19"
-
-"@next/swc-linux-x64-musl@13.4.19":
-  "integrity" "sha512-4Gj4vvtbK1JH8ApWTT214b3GwUh9EKKQjY41hH/t+u55Knxi/0wesMzwQRhppK6Ddalhu0TEttbiJ+wRcoEj5Q=="
-  "resolved" "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.19.tgz"
-  "version" "13.4.19"
-
-"@next/swc-win32-arm64-msvc@13.4.19":
-  "integrity" "sha512-bUfDevQK4NsIAHXs3/JNgnvEY+LRyneDN788W2NYiRIIzmILjba7LaQTfihuFawZDhRtkYCv3JDC3B4TwnmRJw=="
-  "resolved" "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.19.tgz"
-  "version" "13.4.19"
-
-"@next/swc-win32-ia32-msvc@13.4.19":
-  "integrity" "sha512-Y5kikILFAr81LYIFaw6j/NrOtmiM4Sf3GtOc0pn50ez2GCkr+oejYuKGcwAwq3jiTKuzF6OF4iT2INPoxRycEA=="
-  "resolved" "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.19.tgz"
-  "version" "13.4.19"
-
-"@next/swc-win32-x64-msvc@13.4.19":
-  "integrity" "sha512-YzA78jBDXMYiINdPdJJwGgPNT3YqBNNGhsthsDoWHL9p24tEJn9ViQf/ZqTbwSpX/RrkPupLfuuTH2sf73JBAw=="
-  "resolved" "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.19.tgz"
+"@next/swc-darwin-arm64@13.4.19":
+  "integrity" "sha512-vv1qrjXeGbuF2mOkhkdxMDtv9np7W4mcBtaDnHU+yJG+bBwa6rYsYSCI/9Xm5+TuF5SbZbrWO6G1NfTh1TMjvQ=="
+  "resolved" "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.19.tgz"
   "version" "13.4.19"
 
 "@nodelib/fs.scandir@2.1.5":
@@ -2189,7 +2149,7 @@
   dependencies:
     "color-name" "~1.1.4"
 
-"color-name@~1.1.4":
+"color-name@^1.1.4", "color-name@~1.1.4":
   "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
   "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
   "version" "1.1.4"
@@ -2360,6 +2320,11 @@
   "resolved" "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz"
   "version" "3.0.0"
 
+"cssfontparser@^1.2.1":
+  "integrity" "sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg=="
+  "resolved" "https://registry.npmjs.org/cssfontparser/-/cssfontparser-1.2.1.tgz"
+  "version" "1.2.1"
+
 "cssom@^0.5.0":
   "integrity" "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw=="
   "resolved" "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz"
@@ -4451,6 +4416,14 @@
     "reflect.getprototypeof" "^1.0.4"
     "set-function-name" "^2.0.1"
 
+"jest-canvas-mock@^2.5.2":
+  "integrity" "sha512-vgnpPupjOL6+L5oJXzxTxFrlGEIbHdZqFU+LFNdtLxZ3lRDCl17FlTMM7IatoRQkrcyOTMlDinjUguqmQ6bR2A=="
+  "resolved" "https://registry.npmjs.org/jest-canvas-mock/-/jest-canvas-mock-2.5.2.tgz"
+  "version" "2.5.2"
+  dependencies:
+    "cssfontparser" "^1.2.1"
+    "moo-color" "^1.0.2"
+
 "jest-changed-files@^29.7.0":
   "integrity" "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w=="
   "resolved" "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz"
@@ -5377,6 +5350,13 @@
   "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
   "version" "1.0.4"
 
+"moo-color@^1.0.2":
+  "integrity" "sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ=="
+  "resolved" "https://registry.npmjs.org/moo-color/-/moo-color-1.0.3.tgz"
+  "version" "1.0.3"
+  dependencies:
+    "color-name" "^1.1.4"
+
 "ms@^2.1.1", "ms@2.1.2":
   "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
   "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
-- 
GitLab