terra-draw 0.0.1-alpha.50 → 0.0.1-alpha.53

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.
Files changed (36) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/arcgis-maps-sdk.adapter.d.ts +106 -0
  3. package/dist/adapters/common/base.adapter.d.ts +6 -0
  4. package/dist/common.d.ts +2 -0
  5. package/dist/modes/base.mode.d.ts +6 -7
  6. package/dist/modes/circle/circle.mode.d.ts +7 -6
  7. package/dist/modes/freehand/freehand.mode.d.ts +8 -8
  8. package/dist/modes/greatcircle/great-circle.mode.d.ts +8 -8
  9. package/dist/modes/linestring/linestring.mode.d.ts +9 -9
  10. package/dist/modes/point/point.mode.d.ts +5 -5
  11. package/dist/modes/polygon/polygon.mode.d.ts +9 -9
  12. package/dist/modes/rectangle/rectangle.mode.d.ts +6 -6
  13. package/dist/modes/render/render.mode.d.ts +6 -5
  14. package/dist/modes/select/select.mode.d.ts +11 -11
  15. package/dist/terra-draw.cjs +1 -1
  16. package/dist/terra-draw.cjs.map +1 -1
  17. package/dist/terra-draw.d.ts +2 -1
  18. package/dist/terra-draw.modern.js +1 -1
  19. package/dist/terra-draw.modern.js.map +1 -1
  20. package/dist/terra-draw.module.js +1 -1
  21. package/dist/terra-draw.module.js.map +1 -1
  22. package/dist/terra-draw.umd.js +1 -1
  23. package/dist/terra-draw.umd.js.map +1 -1
  24. package/e2e/README.md +29 -0
  25. package/e2e/package-lock.json +3660 -0
  26. package/e2e/package.json +23 -0
  27. package/e2e/playwright.config.ts +77 -0
  28. package/e2e/public/index.html +53 -0
  29. package/e2e/src/index.ts +151 -0
  30. package/e2e/tests/leaflet.spec.ts +268 -0
  31. package/e2e/tests/setup.ts +88 -0
  32. package/e2e/webpack.config.js +38 -0
  33. package/jest.nocheck.config.ts +9 -1
  34. package/package.json +4 -3
  35. package/tsconfig.json +0 -3
  36. package/dist/modes/select/behaviors/features-at-mouse-event.behavior.d.ts +0 -15
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "terra-draw-e2e",
3
+ "version": "0.0.1",
4
+ "description": "The E2E test suite for Terra Draw",
5
+ "main": "index.ts",
6
+ "scripts": {
7
+ "build": "webpack",
8
+ "serve": "webpack serve",
9
+ "test": "playwright test",
10
+ "test:ui": "playwright test --ui --headed"
11
+ },
12
+ "author": "James Milner",
13
+ "license": "MIT",
14
+ "devDependencies": {
15
+ "@types/node": "^20.10.5",
16
+ "dotenv-webpack": "^8.0.0",
17
+ "typescript": "^4.7.4",
18
+ "webpack": "^5.73.0",
19
+ "webpack-cli": "^4.10.0",
20
+ "webpack-dev-server": "^4.11.1",
21
+ "@playwright/test": "^1.40.1"
22
+ }
23
+ }
@@ -0,0 +1,77 @@
1
+ import { defineConfig, devices } from "@playwright/test";
2
+
3
+ /**
4
+ * Read environment variables from file.
5
+ * https://github.com/motdotla/dotenv
6
+ */
7
+ // require('dotenv').config();
8
+
9
+ /**
10
+ * See https://playwright.dev/docs/test-configuration.
11
+ */
12
+ export default defineConfig({
13
+ testDir: "./tests",
14
+ /* Run tests in files in parallel */
15
+ fullyParallel: true,
16
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
17
+ forbidOnly: !!process.env.CI,
18
+ /* Retry on CI only */
19
+ retries: process.env.CI ? 2 : 0,
20
+ /* Opt out of parallel tests on CI. */
21
+ workers: process.env.CI ? 1 : undefined,
22
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
23
+ reporter: "html",
24
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
25
+ use: {
26
+ /* Base URL to use in actions like `await page.goto('/')`. */
27
+ // baseURL: 'http://127.0.0.1:3000',
28
+
29
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
30
+ trace: "on-first-retry",
31
+ },
32
+
33
+ /* Configure projects for major browsers */
34
+ projects: [
35
+ {
36
+ name: "chromium",
37
+ use: { ...devices["Desktop Chrome"] },
38
+ },
39
+
40
+ // {
41
+ // name: 'firefox',
42
+ // use: { ...devices['Desktop Firefox'] },
43
+ // },
44
+
45
+ // {
46
+ // name: 'webkit',
47
+ // use: { ...devices['Desktop Safari'] },
48
+ // },
49
+
50
+ /* Test against mobile viewports. */
51
+ // {
52
+ // name: 'Mobile Chrome',
53
+ // use: { ...devices['Pixel 5'] },
54
+ // },
55
+ // {
56
+ // name: 'Mobile Safari',
57
+ // use: { ...devices['iPhone 12'] },
58
+ // },
59
+
60
+ /* Test against branded browsers. */
61
+ // {
62
+ // name: 'Microsoft Edge',
63
+ // use: { ...devices['Desktop Edge'], channel: 'msedge' },
64
+ // },
65
+ // {
66
+ // name: 'Google Chrome',
67
+ // use: { ...devices['Desktop Chrome'], channel: 'chrome' },
68
+ // },
69
+ ],
70
+
71
+ /* Run your local dev server before starting the tests */
72
+ webServer: {
73
+ command: "npm run serve",
74
+ url: "http://127.0.0.1:3000",
75
+ reuseExistingServer: !process.env.CI,
76
+ },
77
+ });
@@ -0,0 +1,53 @@
1
+ <html>
2
+
3
+ <head>
4
+ <style>
5
+ .leaflet-map {
6
+ width: 100%;
7
+ height: 100%;
8
+ }
9
+
10
+ .buttons {
11
+ position: absolute;
12
+ top: 0;
13
+ width: 100%;
14
+ z-index: 1000;
15
+ display: flex;
16
+ flex-direction: row;
17
+ justify-content: center;
18
+ }
19
+
20
+ .buttons>button {
21
+ display: flex;
22
+ align-items: center;
23
+ height: 30px;
24
+ padding: 20px;
25
+ }
26
+ </style>
27
+ <link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
28
+ integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
29
+ crossorigin="" />
30
+ </head>
31
+
32
+ <body style="width: 100%; height: 100%; margin: 0">
33
+ <div style="display: flex; flex-direction: row; height: 100%; width: 100%">
34
+ <div class="leaflet-map" id="map" tabindex="0" id="map" role="application"
35
+ aria-label="A leaflet map used for testing purposes">
36
+ </div>
37
+ </div>
38
+ <div class="buttons">
39
+ <button id="select">Select</button>
40
+ <button id="point">Point</button>
41
+ <button id="linestring">Linestring</button>
42
+ <button id="polygon">Polygon</button>
43
+ <button id="rectangle">Rectangle</button>
44
+ <button id="circle">Circle</button>
45
+ <button id="greatcircle">Greatcircle</button>
46
+ <button id="clear">Clear</button>
47
+ </div>
48
+
49
+ </body>
50
+
51
+ <script src="./bundle.js"></script>
52
+
53
+ </html>
@@ -0,0 +1,151 @@
1
+ import L from "leaflet";
2
+ import {
3
+ TerraDraw,
4
+ TerraDrawCircleMode,
5
+ TerraDrawFreehandMode,
6
+ TerraDrawGreatCircleMode,
7
+ TerraDrawLeafletAdapter,
8
+ TerraDrawLineStringMode,
9
+ TerraDrawPointMode,
10
+ TerraDrawPolygonMode,
11
+ TerraDrawRectangleMode,
12
+ TerraDrawRenderMode,
13
+ TerraDrawSelectMode,
14
+ } from "../../src/terra-draw";
15
+
16
+ const example = {
17
+ lng: -0.118092,
18
+ lat: 51.509865,
19
+ zoom: 12,
20
+ initialised: [],
21
+ initLeaflet() {
22
+ const currentSelected: {
23
+ mode: undefined | string;
24
+ button: HTMLButtonElement | undefined;
25
+ } = { mode: undefined, button: undefined };
26
+
27
+ const { lng, lat, zoom } = this;
28
+
29
+ const map = L.map("map", {
30
+ center: [lat, lng],
31
+ zoom: zoom + 1, // starting zoom
32
+ });
33
+
34
+ map.removeControl(map.zoomControl);
35
+
36
+ L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
37
+ attribution:
38
+ '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
39
+ }).addTo(map);
40
+
41
+ const draw = new TerraDraw({
42
+ adapter: new TerraDrawLeafletAdapter({
43
+ lib: L,
44
+ map,
45
+ coordinatePrecision: 6,
46
+ }),
47
+ modes: [
48
+ new TerraDrawSelectMode({
49
+ flags: {
50
+ arbitary: {
51
+ feature: {},
52
+ },
53
+ polygon: {
54
+ feature: {
55
+ draggable: true,
56
+ rotateable: true,
57
+ scaleable: true,
58
+ coordinates: {
59
+ midpoints: true,
60
+ draggable: true,
61
+ deletable: true,
62
+ },
63
+ },
64
+ },
65
+ freehand: {
66
+ feature: { draggable: true, coordinates: {} },
67
+ },
68
+ linestring: {
69
+ feature: {
70
+ draggable: true,
71
+ coordinates: {
72
+ midpoints: true,
73
+ draggable: true,
74
+ deletable: true,
75
+ },
76
+ },
77
+ },
78
+ circle: {
79
+ feature: {
80
+ draggable: true,
81
+ },
82
+ },
83
+ point: {
84
+ feature: {
85
+ draggable: true,
86
+ },
87
+ },
88
+ },
89
+ }),
90
+ new TerraDrawPointMode(),
91
+ new TerraDrawLineStringMode({
92
+ snapping: true,
93
+ allowSelfIntersections: false,
94
+ }),
95
+ new TerraDrawGreatCircleMode({ snapping: true }),
96
+ new TerraDrawPolygonMode({
97
+ snapping: true,
98
+ allowSelfIntersections: false,
99
+ }),
100
+ new TerraDrawRectangleMode(),
101
+ new TerraDrawCircleMode(),
102
+ new TerraDrawFreehandMode(),
103
+ new TerraDrawRenderMode({
104
+ modeName: "arbitary",
105
+ styles: {
106
+ polygonFillColor: "#4357AD",
107
+ polygonOutlineColor: "#48A9A6",
108
+ polygonOutlineWidth: 2,
109
+ },
110
+ }),
111
+ ],
112
+ });
113
+
114
+ draw.start();
115
+
116
+ [
117
+ "select",
118
+ "point",
119
+ "linestring",
120
+ "polygon",
121
+ "rectangle",
122
+ "circle",
123
+ "greatcircle",
124
+ ].forEach((mode) => {
125
+ (document.getElementById(mode) as HTMLButtonElement).addEventListener(
126
+ "click",
127
+ () => {
128
+ currentSelected.mode = mode;
129
+ draw.setMode(currentSelected.mode);
130
+
131
+ if (currentSelected.button) {
132
+ currentSelected.button.style.color = "565656";
133
+ }
134
+ currentSelected.button = document.getElementById(
135
+ mode,
136
+ ) as HTMLButtonElement;
137
+ currentSelected.button.style.color = "#27ccff";
138
+ },
139
+ );
140
+ });
141
+
142
+ (document.getElementById("clear") as HTMLButtonElement).addEventListener(
143
+ "click",
144
+ () => {
145
+ draw.clear();
146
+ },
147
+ );
148
+ },
149
+ };
150
+
151
+ example.initLeaflet();
@@ -0,0 +1,268 @@
1
+ import { test, expect } from "@playwright/test";
2
+ import {
3
+ changeMode,
4
+ expectPathDimensions,
5
+ expectPaths,
6
+ pageUrl,
7
+ setupMap,
8
+ } from "./setup";
9
+
10
+ test.describe("page setup", () => {
11
+ test("loads map", async ({ page }) => {
12
+ await page.goto(pageUrl);
13
+
14
+ // Expect map application to exist
15
+ await expect(page.getByRole("application")).toBeVisible();
16
+ });
17
+
18
+ test("loads UI", async ({ page }) => {
19
+ await page.goto(pageUrl);
20
+
21
+ await expect(page.getByText("Point")).toBeVisible();
22
+ await expect(page.getByText("Linestring")).toBeVisible();
23
+ await expect(page.getByText("Polygon")).toBeVisible();
24
+ await expect(page.getByText("Select")).toBeVisible();
25
+ await expect(page.getByText("Clear")).toBeVisible();
26
+ });
27
+ });
28
+
29
+ test.describe("point mode", () => {
30
+ const mode = "point";
31
+
32
+ test("mode can set and can be used to create a point", async ({ page }) => {
33
+ const mapDiv = await setupMap({ page });
34
+ await changeMode({ page, mode });
35
+
36
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
37
+
38
+ expectPaths({ page, count: 1 });
39
+ });
40
+
41
+ test("mode can set and can be used to create multiple points", async ({
42
+ page,
43
+ }) => {
44
+ const mapDiv = await setupMap({ page });
45
+ await changeMode({ page, mode });
46
+
47
+ await page.mouse.click(mapDiv.width / 4, mapDiv.height / 4);
48
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
49
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
50
+
51
+ expectPaths({ page, count: 3 });
52
+ });
53
+ });
54
+
55
+ test.describe("linestring mode", () => {
56
+ const mode = "linestring";
57
+
58
+ test("mode can set and can be used to create a linestring", async ({
59
+ page,
60
+ }) => {
61
+ const mapDiv = await setupMap({ page });
62
+ await changeMode({ page, mode });
63
+
64
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2);
65
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
66
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3);
67
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
68
+
69
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
70
+
71
+ expectPaths({ page, count: 1 });
72
+ });
73
+
74
+ test("mode can set and can be used to create multiple linestrings", async ({
75
+ page,
76
+ }) => {
77
+ const mapDiv = await setupMap({ page });
78
+ await changeMode({ page, mode });
79
+
80
+ // First line
81
+ await page.mouse.move(mapDiv.width / 2, mapDiv.height / 2);
82
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
83
+ await page.mouse.move(mapDiv.width / 3, mapDiv.height / 3);
84
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
85
+
86
+ // One point + one line
87
+ expectPaths({ page, count: 2 });
88
+
89
+ // Close first line
90
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
91
+
92
+ // One line
93
+ expectPaths({ page, count: 2 });
94
+
95
+ // Second line
96
+ await page.mouse.move(mapDiv.width / 4, mapDiv.height / 4);
97
+ await page.mouse.click(mapDiv.width / 4, mapDiv.height / 4);
98
+ await page.mouse.move(mapDiv.width / 5, mapDiv.height / 5);
99
+ await page.mouse.click(mapDiv.width / 5, mapDiv.height / 5);
100
+
101
+ // Close second line
102
+ await page.mouse.click(mapDiv.width / 5, mapDiv.height / 5);
103
+
104
+ // Two lines
105
+ expectPaths({ page, count: 2 });
106
+ });
107
+ });
108
+
109
+ test.describe("polygon mode", () => {
110
+ const mode = "polygon";
111
+
112
+ test("mode can set and can be used to create a polygon", async ({ page }) => {
113
+ const mapDiv = await setupMap({ page });
114
+ await changeMode({ page, mode });
115
+
116
+ // The length of the square sides in pixels
117
+ const sideLength = 100;
118
+
119
+ // Calculating the half of the side length
120
+ const halfLength = sideLength / 2;
121
+
122
+ // Coordinates of the center
123
+ const centerX = mapDiv.width / 2;
124
+ const centerY = mapDiv.height / 2;
125
+
126
+ // Coordinates of the four corners of the square
127
+ const topLeft = { x: centerX - halfLength, y: centerY - halfLength };
128
+ const topRight = { x: centerX + halfLength, y: centerY - halfLength };
129
+ const bottomLeft = { x: centerX - halfLength, y: centerY + halfLength };
130
+ const bottomRight = { x: centerX + halfLength, y: centerY + halfLength };
131
+
132
+ // Perform clicks at each corner
133
+ await page.mouse.click(topLeft.x, topLeft.y);
134
+ await page.mouse.click(topRight.x, topRight.y);
135
+ await page.mouse.click(bottomRight.x, bottomRight.y);
136
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
137
+
138
+ // Close the square
139
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
140
+
141
+ // One point + one line
142
+ expectPaths({ page, count: 1 });
143
+ });
144
+ });
145
+
146
+ test.describe("rectangle mode", () => {
147
+ const mode = "rectangle";
148
+
149
+ test("mode can set and can be used to create a rectangle", async ({
150
+ page,
151
+ }) => {
152
+ const mapDiv = await setupMap({ page });
153
+ await changeMode({ page, mode });
154
+
155
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
156
+ await page.mouse.click(mapDiv.width / 2 + 50, mapDiv.height / 2 + 50);
157
+
158
+ // One point + one line
159
+ await expectPaths({ page, count: 1 });
160
+
161
+ await expectPathDimensions({ page, width: 54, height: 54 }); // Stroke width of 4
162
+ });
163
+ });
164
+
165
+ test.describe("circle mode", () => {
166
+ const mode = "circle";
167
+
168
+ test("mode can set and can be used to create a circle", async ({ page }) => {
169
+ const mapDiv = await setupMap({ page });
170
+ await changeMode({ page, mode });
171
+
172
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
173
+ await page.mouse.click(mapDiv.width / 2 + 50, mapDiv.height / 2 + 50);
174
+
175
+ // One point + one line
176
+ await expectPaths({ page, count: 1 });
177
+
178
+ await expectPathDimensions({ page, width: 146, height: 146 });
179
+ });
180
+ });
181
+
182
+ test.describe("greatcircle mode", () => {
183
+ const mode = "greatcircle";
184
+
185
+ test("mode can set and can be used to create a greatcircle", async ({
186
+ page,
187
+ }) => {
188
+ const mapDiv = await setupMap({ page });
189
+ await changeMode({ page, mode });
190
+
191
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
192
+ await page.mouse.click(mapDiv.width / 2 + 50, mapDiv.height / 2 + 50);
193
+
194
+ // One point + one line
195
+ await expectPaths({ page, count: 1 });
196
+ });
197
+ });
198
+
199
+ test.describe("select mode", () => {
200
+ const mode = "select";
201
+
202
+ test("mode can set and then polygon can be selected and deselected", async ({
203
+ page,
204
+ }) => {
205
+ const mapDiv = await setupMap({ page });
206
+
207
+ await changeMode({ page, mode: "polygon" });
208
+ const sideLength = 100;
209
+ const halfLength = sideLength / 2;
210
+ const centerX = mapDiv.width / 2;
211
+ const centerY = mapDiv.height / 2;
212
+ const topLeft = { x: centerX - halfLength, y: centerY - halfLength };
213
+ const topRight = { x: centerX + halfLength, y: centerY - halfLength };
214
+ const bottomLeft = { x: centerX - halfLength, y: centerY + halfLength };
215
+ const bottomRight = { x: centerX + halfLength, y: centerY + halfLength };
216
+ await page.mouse.click(topLeft.x, topLeft.y);
217
+ await page.mouse.click(topRight.x, topRight.y);
218
+ await page.mouse.click(bottomRight.x, bottomRight.y);
219
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
220
+ await page.mouse.click(bottomLeft.x, bottomLeft.y); // Closed
221
+
222
+ await changeMode({ page, mode });
223
+
224
+ // Select
225
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
226
+ await expectPaths({ page, count: 9 }); // 8 selection points and 1 square
227
+
228
+ // Deselect
229
+ await page.mouse.click(mapDiv.width - 10, mapDiv.height / 2);
230
+ await expectPaths({ page, count: 1 }); // 0 selection points and 1 square
231
+ });
232
+ });
233
+
234
+ test.describe("clear", () => {
235
+ test("drawn geometries can be cleared correctly", async ({ page }) => {
236
+ const mapDiv = await setupMap({ page });
237
+
238
+ await changeMode({ page, mode: "point" });
239
+ await page.mouse.click(mapDiv.width / 4, mapDiv.height / 4);
240
+
241
+ await changeMode({ page, mode: "linestring" });
242
+ await page.mouse.click(mapDiv.width / 2, mapDiv.height / 2);
243
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
244
+ await page.mouse.click(mapDiv.width / 3, mapDiv.height / 3);
245
+
246
+ await changeMode({ page, mode: "polygon" });
247
+ const sideLength = 100;
248
+ const halfLength = sideLength / 2;
249
+ const centerX = mapDiv.width / 2;
250
+ const centerY = mapDiv.height / 2;
251
+ const topLeft = { x: centerX - halfLength, y: centerY - halfLength };
252
+ const topRight = { x: centerX + halfLength, y: centerY - halfLength };
253
+ const bottomLeft = { x: centerX - halfLength, y: centerY + halfLength };
254
+ const bottomRight = { x: centerX + halfLength, y: centerY + halfLength };
255
+ await page.mouse.click(topLeft.x, topLeft.y);
256
+ await page.mouse.click(topRight.x, topRight.y);
257
+ await page.mouse.click(bottomRight.x, bottomRight.y);
258
+ await page.mouse.click(bottomLeft.x, bottomLeft.y);
259
+ await page.mouse.click(bottomLeft.x, bottomLeft.y); // Closed
260
+
261
+ expectPaths({ page, count: 3 });
262
+
263
+ const button = page.getByText("clear");
264
+ await button.click();
265
+
266
+ expectPaths({ page, count: 0 });
267
+ });
268
+ });
@@ -0,0 +1,88 @@
1
+ import { Page, expect } from "@playwright/test";
2
+
3
+ export const pageUrl = "http://localhost:3000/";
4
+
5
+ export const setupMap = async ({
6
+ page,
7
+ }: {
8
+ page: Page;
9
+ }): Promise<{
10
+ x: number;
11
+ y: number;
12
+ width: number;
13
+ height: number;
14
+ }> => {
15
+ await page.goto(pageUrl);
16
+
17
+ const mapDiv = await page.getByRole("application");
18
+
19
+ // Get the bounding box of the div
20
+ const mapBoundingBox = await mapDiv.boundingBox();
21
+
22
+ if (!mapBoundingBox) {
23
+ throw new Error();
24
+ }
25
+
26
+ return mapBoundingBox;
27
+ };
28
+
29
+ export const changeMode = async ({
30
+ page,
31
+ mode,
32
+ }: {
33
+ page: Page;
34
+ mode:
35
+ | "point"
36
+ | "polygon"
37
+ | "linestring"
38
+ | "select"
39
+ | "rectangle"
40
+ | "circle"
41
+ | "greatcircle";
42
+ }) => {
43
+ const modeText = mode.charAt(0).toUpperCase() + mode.slice(1);
44
+ const button = page.getByText(modeText);
45
+
46
+ // Click the mode button
47
+ await button.click();
48
+
49
+ // Ensure it has been clickde and updatedc correctly
50
+ const color = await button.evaluate((el) =>
51
+ window.getComputedStyle(el).getPropertyValue("color"),
52
+ );
53
+ expect(color).toBe("rgb(39, 204, 255)"); // We set hex but it gets computed to rgb
54
+ };
55
+
56
+ export const expectPaths = async ({
57
+ page,
58
+ count,
59
+ }: {
60
+ page: Page;
61
+ count: number;
62
+ }) => {
63
+ const selector = "svg > g > path";
64
+
65
+ if (count > 0) {
66
+ page.waitForSelector(selector);
67
+ expect(await page.locator(selector).count()).toBe(count);
68
+ } else {
69
+ await expect(await page.locator(selector).count()).toBe(0);
70
+ }
71
+ };
72
+
73
+ export const expectPathDimensions = async ({
74
+ page,
75
+ width,
76
+ height,
77
+ }: {
78
+ page: Page;
79
+ width: number;
80
+ height: number;
81
+ }) => {
82
+ const selector = "svg > g > path";
83
+
84
+ const boundingBox = await page.locator(selector).boundingBox();
85
+
86
+ expect(boundingBox?.width).toBe(width);
87
+ expect(boundingBox?.height).toBe(height);
88
+ };
@@ -0,0 +1,38 @@
1
+ const path = require("path");
2
+ const Dotenv = require("dotenv-webpack");
3
+
4
+ module.exports = {
5
+ mode: "development",
6
+ entry: "./src/index.ts",
7
+ devtool: "inline-source-map",
8
+ plugins: [new Dotenv()],
9
+ module: {
10
+ rules: [
11
+ {
12
+ test: /\.tsx?$/,
13
+ use: "ts-loader",
14
+ exclude: /node_modules/,
15
+ },
16
+ ],
17
+ },
18
+ resolve: {
19
+ extensions: [".tsx", ".ts", ".js"],
20
+ },
21
+ output: {
22
+ filename: "bundle.js",
23
+ path: path.resolve(__dirname, "dist"),
24
+ },
25
+ devServer: {
26
+ static: {
27
+ directory: path.join(__dirname, "public"),
28
+ },
29
+ watchFiles: [
30
+ "./src",
31
+ "./*.{js,json,ts,html}",
32
+ "../src",
33
+ "../*.{js,json,ts,html}",
34
+ ],
35
+ compress: true,
36
+ port: 3000,
37
+ },
38
+ };