vease 1.58.1 → 1.59.0-rc.1

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.
@@ -9,10 +9,11 @@ async function closeAllMenus(window) {
9
9
  await waitForActionSettled(window);
10
10
  }
11
11
  async function closeFeedbackSnackbar(window) {
12
- const snackbar = window.getByTestId("feedbackSnackbar");
13
- if (await snackbar.isVisible()) {
14
- await snackbar.getByRole("button").click();
15
- await expect(snackbar).not.toBeVisible();
12
+ const snackbars = window.getByTestId("feedbackSnackbar");
13
+ while (await snackbars.count() > 0) {
14
+ const count = await snackbars.count();
15
+ await snackbars.first().getByTestId("feedbackCloseBtn").click();
16
+ await expect(snackbars).toHaveCount(count - 1);
16
17
  }
17
18
  }
18
19
  //#endregion
@@ -0,0 +1,127 @@
1
+ import { waitForActionSettled } from "./wait_for_action_settled.js";
2
+ import { closeFeedbackSnackbar } from "./app_interaction.js";
3
+ import { expandGeodeObjectTypeInTree, getTreeRowByTextAndParent } from "./object_trees/common.js";
4
+ import { getMainObjectTree } from "./object_trees/main_object_tree.js";
5
+ import { getDataTableRow } from "./data_manager.js";
6
+ import { expect } from "@playwright/test";
7
+ //#region tests/e2e/utils/crs.ts
8
+ async function expectDataRows(window, itemNames) {
9
+ for (const itemName of itemNames) await expect(getDataTableRow(window, itemName)).toBeVisible();
10
+ }
11
+ async function openCrsByButton(window, itemName) {
12
+ await getDataTableRow(window, itemName).getByTestId("crsCell").click();
13
+ await waitForActionSettled(window);
14
+ }
15
+ async function expectRowCrs(window, itemName, expected) {
16
+ await expect(getDataTableRow(window, itemName).getByTestId("crsCell")).toContainText(expected);
17
+ }
18
+ async function getDataTreeRow(window, geodeObjectType, dataName) {
19
+ const tree = getMainObjectTree(window);
20
+ await expandGeodeObjectTypeInTree(window, geodeObjectType, tree);
21
+ return getTreeRowByTextAndParent(window, geodeObjectType, dataName, tree);
22
+ }
23
+ async function openCrsFromTree(window, geodeObjectType, dataName) {
24
+ await (await getDataTreeRow(window, geodeObjectType, dataName)).getByTestId("treeItemLabel").first().hover();
25
+ await waitForActionSettled(window);
26
+ const editButton = window.locator(".v-overlay--active").getByTestId("editCrsBtn");
27
+ await editButton.hover();
28
+ await editButton.click();
29
+ await waitForActionSettled(window);
30
+ }
31
+ async function openCrsFromInfoCard(window, geodeObjectType, dataName) {
32
+ await (await getDataTreeRow(window, geodeObjectType, dataName)).click({ button: "right" });
33
+ await waitForActionSettled(window);
34
+ await window.getByTestId("circularMenuCenterButton").click();
35
+ await window.getByTestId("infoEditCrsBtn").click();
36
+ await waitForActionSettled(window);
37
+ }
38
+ async function openCrsFromWarning(window, geodeObjectType, dataName) {
39
+ await (await getDataTreeRow(window, geodeObjectType, dataName)).getByTestId("crsMismatchIcon").click();
40
+ await waitForActionSettled(window);
41
+ }
42
+ async function openCrsFromFeedback(window, text) {
43
+ const snackbar = window.getByTestId("feedbackSnackbar").filter({ hasText: text });
44
+ await expect(snackbar).toBeVisible();
45
+ await snackbar.getByTestId("feedbackActionBtn").click();
46
+ await waitForActionSettled(window);
47
+ }
48
+ async function selectCrs(window, crsName) {
49
+ await window.getByTestId("crsSearchInput").locator("input").fill(crsName);
50
+ await window.locator("tr").filter({ hasText: crsName }).locator("input").first().check();
51
+ await waitForActionSettled(window);
52
+ }
53
+ async function confirmAssign(window) {
54
+ await window.getByTestId("crsAssignButton").click();
55
+ await waitForActionSettled(window);
56
+ await closeFeedbackSnackbar(window);
57
+ }
58
+ async function expectCurrentCrs(window, expected) {
59
+ await expect(window.getByTestId("crsCurrentValue")).toContainText(expected);
60
+ }
61
+ async function selectAssignMode(window) {
62
+ await window.getByTestId("crsModeAssign").click();
63
+ await waitForActionSettled(window);
64
+ }
65
+ async function clickAssign(window) {
66
+ await window.getByTestId("crsAssignButton").click();
67
+ await waitForActionSettled(window);
68
+ }
69
+ async function expectFeedback(window, text) {
70
+ await expect(window.getByTestId("feedbackSnackbar").filter({ hasText: text })).toBeVisible();
71
+ await closeFeedbackSnackbar(window);
72
+ }
73
+ async function selectConvertMode(window) {
74
+ await window.getByTestId("crsModeConvert").click();
75
+ await waitForActionSettled(window);
76
+ }
77
+ async function confirmConvert(window) {
78
+ await window.getByTestId("crsConvertButton").click();
79
+ await waitForActionSettled(window);
80
+ await closeFeedbackSnackbar(window);
81
+ }
82
+ async function startAlignment(window) {
83
+ await window.getByTestId("crsModeAlign").click();
84
+ await window.getByTestId("crsStartAlignButton").click();
85
+ await waitForActionSettled(window);
86
+ }
87
+ async function selectAlignMode(window, mode) {
88
+ await window.getByTestId(`crsAlignMode-${mode}`).click();
89
+ await waitForActionSettled(window);
90
+ }
91
+ async function fillAlignPoints(window, prefix, points) {
92
+ for (const [index, { x, y }] of points.entries()) {
93
+ const inputs = window.getByTestId(`${prefix}-${index}`).locator("input");
94
+ await inputs.nth(0).fill(String(x));
95
+ await inputs.nth(1).fill(String(y));
96
+ }
97
+ }
98
+ async function selectAlignmentCrs(window, crsName) {
99
+ const panel = window.getByTestId("crsAlignPanel");
100
+ await panel.getByTestId("crsSearchInput").locator("input").fill(crsName);
101
+ await panel.locator("tr").filter({ hasText: crsName }).locator("input").first().check();
102
+ await waitForActionSettled(window);
103
+ }
104
+ async function selectScope(window, scope, testId = "crsScope") {
105
+ await window.getByTestId(`${testId}-${scope}`).locator("input").check();
106
+ await waitForActionSettled(window);
107
+ }
108
+ async function expectCrsMismatch(window, geodeObjectType, dataName, expected) {
109
+ const icon = (await getDataTreeRow(window, geodeObjectType, dataName)).getByTestId("crsMismatchIcon");
110
+ await (expected ? expect(icon).toBeVisible() : expect(icon).toBeHidden());
111
+ }
112
+ async function openProjectCrs(window) {
113
+ await window.getByTestId("projectCrs").click();
114
+ await waitForActionSettled(window);
115
+ }
116
+ async function confirmProjectCrs(window) {
117
+ await window.getByTestId("projectCrsApply").click();
118
+ await waitForActionSettled(window);
119
+ await closeFeedbackSnackbar(window);
120
+ }
121
+ async function applyAlignment(window) {
122
+ await window.getByTestId("crsAlignApplyButton").click();
123
+ await waitForActionSettled(window);
124
+ await closeFeedbackSnackbar(window);
125
+ }
126
+ //#endregion
127
+ export { applyAlignment, clickAssign, confirmAssign, confirmConvert, confirmProjectCrs, expectCrsMismatch, expectCurrentCrs, expectDataRows, expectFeedback, expectRowCrs, fillAlignPoints, openCrsByButton, openCrsFromFeedback, openCrsFromInfoCard, openCrsFromTree, openCrsFromWarning, openProjectCrs, selectAlignMode, selectAlignmentCrs, selectAssignMode, selectConvertMode, selectCrs, selectScope, startAlignment };
@@ -1,8 +1,8 @@
1
1
  import { modalTransitionWait } from "./constants.js";
2
2
  import { waitForLoadingScreen } from "./other.js";
3
3
  import { navigateToExtensionsPage } from "./navigate.js";
4
- import path from "node:path";
5
4
  import { consola } from "consola";
5
+ import path from "node:path";
6
6
  //#region tests/e2e/utils/extension.ts
7
7
  async function loadExtension(window, extensionFilePath) {
8
8
  await waitForLoadingScreen(window);
@@ -1,8 +1,8 @@
1
1
  import { waitForActionSettled } from "./wait_for_action_settled.js";
2
2
  import { navigateToApp } from "./navigate.js";
3
3
  import { expect, test as test$1 } from "@playwright/test";
4
- import path from "node:path";
5
4
  import { consola } from "consola";
5
+ import path from "node:path";
6
6
  import fs from "node:fs";
7
7
  import os from "node:os";
8
8
  //#region tests/e2e/utils/fixtures.ts
@@ -1,7 +1,7 @@
1
1
  import { waitForActionSettled } from "./wait_for_action_settled.js";
2
2
  import { expect } from "@playwright/test";
3
- import path from "node:path";
4
3
  import { consola } from "consola";
4
+ import path from "node:path";
5
5
  //#region tests/e2e/utils/load.ts
6
6
  const __dirname = import.meta.dirname;
7
7
  const loadWorkflowTimeout = 8e3;
@@ -1,8 +1,8 @@
1
1
  import { logBrowserConsole } from "../../../utils/browser_console.js";
2
2
  import { expect } from "@playwright/test";
3
3
  import { isWindows } from "std-env";
4
- import path from "node:path";
5
4
  import { consola } from "consola";
5
+ import path from "node:path";
6
6
  import { execSync } from "node:child_process";
7
7
  import fs from "node:fs";
8
8
  import { setTimeout } from "node:timers/promises";
@@ -1,9 +1,9 @@
1
1
  import { waitForActionSettled } from "../wait_for_action_settled.js";
2
2
  import { closeAllMenus, moveMouseOutOfTheWay } from "../app_interaction.js";
3
3
  import { ensureMenuOpen, resetMenuScroll } from "../viewer_interaction.js";
4
- import { setModelColor } from "../data/model/color.js";
5
4
  import { clickCollapseOrExpandAll, collapseGeodeObjectTypeInTree, collapseTreeGroup, expandGeodeObjectTypeInTree, getTreeRowByTextAndParent } from "./common.js";
6
5
  import { expandGeodeObjectType, getMainObjectTree } from "./main_object_tree.js";
6
+ import { setModelColor } from "../data/model/color.js";
7
7
  //#region tests/e2e/utils/object_trees/model_components_object_tree.ts
8
8
  function getModelComponentsObjectTree(window) {
9
9
  return window.getByTestId("modelComponentsObjectTree");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vease",
3
- "version": "1.58.1",
3
+ "version": "1.59.0-rc.1",
4
4
  "description": "Desktop and cloud software for data visualization",
5
5
  "keywords": [
6
6
  "Desktop",
@@ -90,12 +90,12 @@
90
90
  "@ai-sdk/vue": "4.0.93",
91
91
  "@fontsource/michroma": "5.2.6",
92
92
  "@fontsource/roboto": "5.2.10",
93
- "@geode/cloud-api": "latest",
94
- "@geode/opengeodeweb-back": "latest",
95
- "@geode/opengeodeweb-front": "latest",
96
- "@geode/opengeodeweb-viewer": "latest",
97
- "@geode/vease-back": "latest",
98
- "@geode/vease-viewer": "latest",
93
+ "@geode/cloud-api": "next",
94
+ "@geode/opengeodeweb-back": "next",
95
+ "@geode/opengeodeweb-front": "next",
96
+ "@geode/opengeodeweb-viewer": "next",
97
+ "@geode/vease-back": "next",
98
+ "@geode/vease-viewer": "next",
99
99
  "@nuxtjs/mcp-toolkit": "0.18.1",
100
100
  "ai": "7.0.93",
101
101
  "bowser": "2.14.1",
@@ -11,12 +11,17 @@ async function closeAllMenus(window: Page): Promise<void> {
11
11
 
12
12
  // Snackbars auto-dismiss after 10s (see feedback store), which is too slow to rely on between tests.
13
13
  // Not every action produces a snackbar (e.g. a successful visibility toggle doesn't), so only close it if present.
14
+ // Some actions stack several (e.g. an assign with an implausible CRS warning): all of them are closed.
14
15
  async function closeFeedbackSnackbar(window: Page): Promise<void> {
15
- const snackbar = window.getByTestId("feedbackSnackbar");
16
- if (await snackbar.isVisible()) {
17
- await snackbar.getByRole("button").click();
18
- await expect(snackbar).not.toBeVisible();
16
+ const snackbars = window.getByTestId("feedbackSnackbar");
17
+ // Each close removes a snackbar: they must be closed one after another
18
+ // oxlint-disable no-await-in-loop
19
+ while ((await snackbars.count()) > 0) {
20
+ const count = await snackbars.count();
21
+ await snackbars.first().getByTestId("feedbackCloseBtn").click();
22
+ await expect(snackbars).toHaveCount(count - 1);
19
23
  }
24
+ // oxlint-enable no-await-in-loop
20
25
  }
21
26
 
22
27
  export { closeAllMenus, closeFeedbackSnackbar, moveMouseOutOfTheWay };
@@ -0,0 +1,227 @@
1
+ // Node imports
2
+
3
+ // Third party imports
4
+ import { type Locator, type Page, expect } from "@playwright/test";
5
+
6
+ // Local imports
7
+ import { expandGeodeObjectTypeInTree, getTreeRowByTextAndParent } from "./object_trees/common";
8
+ import { closeFeedbackSnackbar } from "./app_interaction";
9
+ import { getDataTableRow } from "./data_manager";
10
+ import { getMainObjectTree } from "./object_trees/main_object_tree";
11
+ import { waitForActionSettled } from "./wait_for_action_settled";
12
+
13
+ async function expectDataRows(window: Page, itemNames: string[]): Promise<void> {
14
+ // oxlint-disable no-await-in-loop
15
+ for (const itemName of itemNames) {
16
+ await expect(getDataTableRow(window, itemName)).toBeVisible();
17
+ }
18
+ // oxlint-enable no-await-in-loop
19
+ }
20
+
21
+ async function openCrsByButton(window: Page, itemName: string): Promise<void> {
22
+ await getDataTableRow(window, itemName).getByTestId("crsCell").click();
23
+ await waitForActionSettled(window);
24
+ }
25
+
26
+ async function expectRowCrs(window: Page, itemName: string, expected: string): Promise<void> {
27
+ await expect(getDataTableRow(window, itemName).getByTestId("crsCell")).toContainText(expected);
28
+ }
29
+
30
+ async function getDataTreeRow(
31
+ window: Page,
32
+ geodeObjectType: string,
33
+ dataName: string,
34
+ ): Promise<Locator> {
35
+ const tree = getMainObjectTree(window);
36
+ await expandGeodeObjectTypeInTree(window, geodeObjectType, tree);
37
+ return getTreeRowByTextAndParent(window, geodeObjectType, dataName, tree);
38
+ }
39
+
40
+ async function openCrsFromTree(
41
+ window: Page,
42
+ geodeObjectType: string,
43
+ dataName: string,
44
+ ): Promise<void> {
45
+ const row = await getDataTreeRow(window, geodeObjectType, dataName);
46
+ await row.getByTestId("treeItemLabel").first().hover();
47
+ await waitForActionSettled(window);
48
+ const editButton = window.locator(".v-overlay--active").getByTestId("editCrsBtn");
49
+ await editButton.hover();
50
+ await editButton.click();
51
+ await waitForActionSettled(window);
52
+ }
53
+
54
+ async function openCrsFromInfoCard(
55
+ window: Page,
56
+ geodeObjectType: string,
57
+ dataName: string,
58
+ ): Promise<void> {
59
+ const row = await getDataTreeRow(window, geodeObjectType, dataName);
60
+ await row.click({ button: "right" });
61
+ await waitForActionSettled(window);
62
+ await window.getByTestId("circularMenuCenterButton").click();
63
+ await window.getByTestId("infoEditCrsBtn").click();
64
+ await waitForActionSettled(window);
65
+ }
66
+
67
+ // The warning icon of the tree opens the crs dialog of the data
68
+ async function openCrsFromWarning(
69
+ window: Page,
70
+ geodeObjectType: string,
71
+ dataName: string,
72
+ ): Promise<void> {
73
+ const row = await getDataTreeRow(window, geodeObjectType, dataName);
74
+ await row.getByTestId("crsMismatchIcon").click();
75
+ await waitForActionSettled(window);
76
+ }
77
+
78
+ async function openCrsFromFeedback(window: Page, text: string): Promise<void> {
79
+ const snackbar = window.getByTestId("feedbackSnackbar").filter({ hasText: text });
80
+ await expect(snackbar).toBeVisible();
81
+ await snackbar.getByTestId("feedbackActionBtn").click();
82
+ await waitForActionSettled(window);
83
+ }
84
+
85
+ // Selecting is its own step so the dialog state is captured before the action
86
+ async function selectCrs(window: Page, crsName: string): Promise<void> {
87
+ await window.getByTestId("crsSearchInput").locator("input").fill(crsName);
88
+ await window.locator("tr").filter({ hasText: crsName }).locator("input").first().check();
89
+ await waitForActionSettled(window);
90
+ }
91
+
92
+ async function confirmAssign(window: Page): Promise<void> {
93
+ await window.getByTestId("crsAssignButton").click();
94
+ await waitForActionSettled(window);
95
+ // The global feedback snackbar outlives the next step: close it so screenshots stay stable
96
+ await closeFeedbackSnackbar(window);
97
+ }
98
+
99
+ async function expectCurrentCrs(window: Page, expected: string): Promise<void> {
100
+ await expect(window.getByTestId("crsCurrentValue")).toContainText(expected);
101
+ }
102
+
103
+ // A georeferenced data opens on convert
104
+ async function selectAssignMode(window: Page): Promise<void> {
105
+ await window.getByTestId("crsModeAssign").click();
106
+ await waitForActionSettled(window);
107
+ }
108
+
109
+ // Without closing the feedback: the step checks the dialog or the warning it shows
110
+ async function clickAssign(window: Page): Promise<void> {
111
+ await window.getByTestId("crsAssignButton").click();
112
+ await waitForActionSettled(window);
113
+ }
114
+
115
+ async function expectFeedback(window: Page, text: string): Promise<void> {
116
+ await expect(window.getByTestId("feedbackSnackbar").filter({ hasText: text })).toBeVisible();
117
+ await closeFeedbackSnackbar(window);
118
+ }
119
+
120
+ async function selectConvertMode(window: Page): Promise<void> {
121
+ await window.getByTestId("crsModeConvert").click();
122
+ await waitForActionSettled(window);
123
+ }
124
+
125
+ async function confirmConvert(window: Page): Promise<void> {
126
+ await window.getByTestId("crsConvertButton").click();
127
+ await waitForActionSettled(window);
128
+ await closeFeedbackSnackbar(window);
129
+ }
130
+
131
+ async function startAlignment(window: Page): Promise<void> {
132
+ await window.getByTestId("crsModeAlign").click();
133
+ await window.getByTestId("crsStartAlignButton").click();
134
+ await waitForActionSettled(window);
135
+ }
136
+
137
+ async function selectAlignMode(window: Page, mode: "similarity" | "affine"): Promise<void> {
138
+ await window.getByTestId(`crsAlignMode-${mode}`).click();
139
+ await waitForActionSettled(window);
140
+ }
141
+
142
+ async function fillAlignPoints(
143
+ window: Page,
144
+ prefix: "crsAlignSource" | "crsAlignTarget",
145
+ points: { x: number; y: number }[],
146
+ ): Promise<void> {
147
+ // Fills share the keyboard focus: they must run one after another
148
+ // oxlint-disable no-await-in-loop
149
+ for (const [index, { x, y }] of points.entries()) {
150
+ const inputs = window.getByTestId(`${prefix}-${index}`).locator("input");
151
+ await inputs.nth(0).fill(String(x));
152
+ await inputs.nth(1).fill(String(y));
153
+ }
154
+ // oxlint-enable no-await-in-loop
155
+ }
156
+
157
+ async function selectAlignmentCrs(window: Page, crsName: string): Promise<void> {
158
+ const panel = window.getByTestId("crsAlignPanel");
159
+ await panel.getByTestId("crsSearchInput").locator("input").fill(crsName);
160
+ await panel.locator("tr").filter({ hasText: crsName }).locator("input").first().check();
161
+ await waitForActionSettled(window);
162
+ }
163
+
164
+ // "All data" or "This data only", in the crs dialog (crsScope) or the georeference drawer (crsAlignScope)
165
+ async function selectScope(
166
+ window: Page,
167
+ scope: "all" | "one",
168
+ testId: "crsScope" | "crsAlignScope" = "crsScope",
169
+ ): Promise<void> {
170
+ await window.getByTestId(`${testId}-${scope}`).locator("input").check();
171
+ await waitForActionSettled(window);
172
+ }
173
+
174
+ async function expectCrsMismatch(
175
+ window: Page,
176
+ geodeObjectType: string,
177
+ dataName: string,
178
+ expected: boolean,
179
+ ): Promise<void> {
180
+ const row = await getDataTreeRow(window, geodeObjectType, dataName);
181
+ const icon = row.getByTestId("crsMismatchIcon");
182
+ await (expected ? expect(icon).toBeVisible() : expect(icon).toBeHidden());
183
+ }
184
+
185
+ async function openProjectCrs(window: Page): Promise<void> {
186
+ await window.getByTestId("projectCrs").click();
187
+ await waitForActionSettled(window);
188
+ }
189
+
190
+ async function confirmProjectCrs(window: Page): Promise<void> {
191
+ await window.getByTestId("projectCrsApply").click();
192
+ await waitForActionSettled(window);
193
+ await closeFeedbackSnackbar(window);
194
+ }
195
+
196
+ async function applyAlignment(window: Page): Promise<void> {
197
+ await window.getByTestId("crsAlignApplyButton").click();
198
+ await waitForActionSettled(window);
199
+ await closeFeedbackSnackbar(window);
200
+ }
201
+
202
+ export {
203
+ applyAlignment,
204
+ clickAssign,
205
+ confirmAssign,
206
+ confirmConvert,
207
+ confirmProjectCrs,
208
+ expectCrsMismatch,
209
+ expectCurrentCrs,
210
+ expectDataRows,
211
+ expectFeedback,
212
+ expectRowCrs,
213
+ fillAlignPoints,
214
+ openCrsByButton,
215
+ openCrsFromFeedback,
216
+ openCrsFromInfoCard,
217
+ openCrsFromTree,
218
+ openCrsFromWarning,
219
+ openProjectCrs,
220
+ selectAlignmentCrs,
221
+ selectConvertMode,
222
+ selectCrs,
223
+ selectScope,
224
+ selectAlignMode,
225
+ selectAssignMode,
226
+ startAlignment,
227
+ };