vease 1.51.0 → 1.52.0-rc.10
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.
- package/.build/tests/e2e/utils/camera_interaction.js +23 -6
- package/.build/tests/e2e/utils/fixtures.js +9 -2
- package/.build/tests/e2e/utils/navigate.js +35 -32
- package/.build/tests/e2e/utils/object_trees/main_object_tree.js +11 -2
- package/.build/tests/e2e/utils/object_trees/model_components_object_tree.js +1 -8
- package/package.json +13 -14
- package/tests/e2e/utils/camera_interaction.ts +31 -6
- package/tests/e2e/utils/fixtures.ts +16 -3
- package/tests/e2e/utils/navigate.ts +49 -42
- package/tests/e2e/utils/object_trees/main_object_tree.ts +22 -0
- package/tests/e2e/utils/object_trees/model_components_object_tree.ts +0 -14
|
@@ -105,17 +105,19 @@ async function toggleShrinkFilter(window) {
|
|
|
105
105
|
await window.getByTestId("shrinkFilterButton").click();
|
|
106
106
|
await waitForActionSettled(window);
|
|
107
107
|
}
|
|
108
|
-
async function
|
|
109
|
-
const slider = window.getByTestId(
|
|
108
|
+
async function setSliderRatio(window, sliderTestId, ratio) {
|
|
109
|
+
const slider = window.getByTestId(sliderTestId);
|
|
110
110
|
const box = await slider.boundingBox();
|
|
111
|
-
if (!box) throw new Error(
|
|
112
|
-
const clickX = box.width * shrinkFactorValue;
|
|
111
|
+
if (!box) throw new Error(`Could not get bounding box of the ${sliderTestId} slider.`);
|
|
113
112
|
await slider.click({ position: {
|
|
114
|
-
x:
|
|
113
|
+
x: box.width * ratio,
|
|
115
114
|
y: box.height / 2
|
|
116
115
|
} });
|
|
117
116
|
await waitForActionSettled(window);
|
|
118
117
|
}
|
|
118
|
+
async function setShrinkFactor(window, shrinkFactorValue) {
|
|
119
|
+
await setSliderRatio(window, "shrinkFactorSlider", shrinkFactorValue);
|
|
120
|
+
}
|
|
119
121
|
async function resetShrinkFilter(window) {
|
|
120
122
|
await window.getByTestId("resetShrinkButton").click();
|
|
121
123
|
await waitForActionSettled(window);
|
|
@@ -133,6 +135,21 @@ async function selectShrinkDatasets(window, datasetName, index = 0) {
|
|
|
133
135
|
await select.click();
|
|
134
136
|
await waitForActionSettled(window);
|
|
135
137
|
}
|
|
138
|
+
async function toggleExplodeFilter(window) {
|
|
139
|
+
await window.getByTestId("explodeFilterButton").click();
|
|
140
|
+
await waitForActionSettled(window);
|
|
141
|
+
}
|
|
142
|
+
async function setExplodeFactor(window, explodeFactorValue) {
|
|
143
|
+
await setSliderRatio(window, "explodeFactorSlider", explodeFactorValue);
|
|
144
|
+
}
|
|
145
|
+
async function resetExplodeFilter(window) {
|
|
146
|
+
await window.getByTestId("resetExplodeButton").click();
|
|
147
|
+
await waitForActionSettled(window);
|
|
148
|
+
}
|
|
149
|
+
async function removeExplodeFilter(window) {
|
|
150
|
+
await window.getByTestId("removeExplodeButton").click();
|
|
151
|
+
await waitForActionSettled(window);
|
|
152
|
+
}
|
|
136
153
|
async function toggleThresholdFilter(window) {
|
|
137
154
|
await window.getByTestId("thresholdFilterButton").click();
|
|
138
155
|
await waitForActionSettled(window);
|
|
@@ -207,4 +224,4 @@ async function drawZoomBox(window, deltaX, deltaY) {
|
|
|
207
224
|
await expect(window.getByTestId("zoomBoxActiveChip")).toBeHidden();
|
|
208
225
|
}
|
|
209
226
|
//#endregion
|
|
210
|
-
export { activateZoomToBox, clearRuler, closeCameraManager, drawZoomBox, ensureHighlightMenuOpen, removeThresholdFilter, resetCamera, resetShrinkFilter, resetThresholdFilter, restoreCameraPosition, rotateCamera, saveCameraPosition, selectCameraOrientation, selectShrinkDatasets, selectThresholdBlockPolyhedron, selectThresholdCellAttribute, setRulerPointInput, setShrinkFactor, setThresholdMinimum, setZScaling, toggleCameraManager, toggleCameraOrientation, toggleCenterOnClick, toggleGridScale, toggleRuler, toggleRulerSnap, toggleShrinkFilter, toggleShrinkTargetAllVisible, toggleThresholdFilter };
|
|
227
|
+
export { activateZoomToBox, clearRuler, closeCameraManager, drawZoomBox, ensureHighlightMenuOpen, removeExplodeFilter, removeThresholdFilter, resetCamera, resetExplodeFilter, resetShrinkFilter, resetThresholdFilter, restoreCameraPosition, rotateCamera, saveCameraPosition, selectCameraOrientation, selectShrinkDatasets, selectThresholdBlockPolyhedron, selectThresholdCellAttribute, setExplodeFactor, setRulerPointInput, setShrinkFactor, setThresholdMinimum, setZScaling, toggleCameraManager, toggleCameraOrientation, toggleCenterOnClick, toggleExplodeFilter, toggleGridScale, toggleRuler, toggleRulerSnap, toggleShrinkFilter, toggleShrinkTargetAllVisible, toggleThresholdFilter };
|
|
@@ -18,11 +18,18 @@ const test = test$1.extend({
|
|
|
18
18
|
screenshotMask: [async ({}, use) => {
|
|
19
19
|
await use({ locators: [] });
|
|
20
20
|
}, { scope: "test" }],
|
|
21
|
-
window: [async ({ mode,
|
|
21
|
+
window: [async ({ mode, playwright, browserName, headless, channel, launchOptions }, use, workerInfo) => {
|
|
22
22
|
const configPath = fs.mkdtempSync(path.join(os.tmpdir(), `vease-e2e-worker${workerInfo.parallelIndex}-`));
|
|
23
23
|
process.env.XDG_CONFIG_HOME = configPath;
|
|
24
24
|
process.env.APPDATA = configPath;
|
|
25
|
-
|
|
25
|
+
async function launchBrowser() {
|
|
26
|
+
return await playwright[browserName].launch({
|
|
27
|
+
...launchOptions,
|
|
28
|
+
headless,
|
|
29
|
+
channel
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const { window, cleanup } = await navigateToApp(mode, launchBrowser);
|
|
26
33
|
await use(window);
|
|
27
34
|
await cleanup();
|
|
28
35
|
fs.rmSync(configPath, {
|
|
@@ -143,7 +143,7 @@ async function signInToCloudApp(page) {
|
|
|
143
143
|
await expect(page.getByTestId("layoutImportButton")).toBeEnabled({ timeout: WAIT_TIMES.cloud });
|
|
144
144
|
await page.waitForFunction(() => document.readyState === "complete");
|
|
145
145
|
}
|
|
146
|
-
async function
|
|
146
|
+
async function newBrowserPage(browser) {
|
|
147
147
|
const context = await browser.newContext({
|
|
148
148
|
viewport: {
|
|
149
149
|
width: PAGE_WIDTH,
|
|
@@ -159,13 +159,29 @@ async function navigateToApp(mode, browser) {
|
|
|
159
159
|
consola.info("PAGE CLOSED:", newPage.url());
|
|
160
160
|
});
|
|
161
161
|
});
|
|
162
|
-
|
|
162
|
+
return context.newPage();
|
|
163
|
+
}
|
|
164
|
+
async function navigateToApp(mode, launchBrowser) {
|
|
163
165
|
consola.info(`Testing app in ${mode} mode`);
|
|
166
|
+
if (mode === "DESKTOP") {
|
|
167
|
+
const { electronApp, firstWindow } = await runDesktopBuild();
|
|
168
|
+
consola.info(`Waiting for ${WAIT_TIMES.desktop / MILLISECONDS} seconds for the app to load...`);
|
|
169
|
+
await firstWindow.waitForFunction(() => document.readyState === "complete");
|
|
170
|
+
return {
|
|
171
|
+
window: firstWindow,
|
|
172
|
+
cleanup: async () => {
|
|
173
|
+
await electronApp.close();
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (mode !== "BROWSER" && mode !== "CLOUD") throw new Error(`Unknown mode: ${mode}`);
|
|
178
|
+
const browser = await launchBrowser();
|
|
179
|
+
const page = await newBrowserPage(browser);
|
|
180
|
+
page.on("console", (msg) => {
|
|
181
|
+
consola.info(`Browser console: ${msg.text()}`);
|
|
182
|
+
});
|
|
164
183
|
if (mode === "BROWSER") {
|
|
165
184
|
const nuxtPort = await runBrowser("preview:browser");
|
|
166
|
-
page.on("console", (msg) => {
|
|
167
|
-
consola.info(`Browser console: ${msg.text()}`);
|
|
168
|
-
});
|
|
169
185
|
const appUrl = `http://localhost:${nuxtPort}`;
|
|
170
186
|
await page.goto(appUrl);
|
|
171
187
|
consola.info("Navigated to", page.url());
|
|
@@ -176,37 +192,24 @@ async function navigateToApp(mode, browser) {
|
|
|
176
192
|
window: page,
|
|
177
193
|
cleanup: async () => {
|
|
178
194
|
await page.close();
|
|
195
|
+
await browser.close();
|
|
179
196
|
await kill(nuxtPort);
|
|
180
197
|
}
|
|
181
198
|
};
|
|
182
|
-
} else if (mode === "CLOUD") {
|
|
183
|
-
page.on("console", (msg) => {
|
|
184
|
-
consola.info(`Browser console: ${msg.text()}`);
|
|
185
|
-
});
|
|
186
|
-
let prefix = "";
|
|
187
|
-
const branch = execSync("git branch --show-current", { encoding: "utf8" }).trim();
|
|
188
|
-
consola.info("Current branch:", branch);
|
|
189
|
-
if (branch === "next") prefix = "next.";
|
|
190
|
-
await navigateToCloudApp(page, `https://${prefix}vease.geode-solutions.com`, 10);
|
|
191
|
-
await signInToCloudApp(page);
|
|
192
|
-
return {
|
|
193
|
-
window: page,
|
|
194
|
-
cleanup: async () => {
|
|
195
|
-
await page.close();
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
} else if (mode === "DESKTOP") {
|
|
199
|
-
const { electronApp, firstWindow } = await runDesktopBuild();
|
|
200
|
-
consola.info(`Waiting for ${WAIT_TIMES.desktop / MILLISECONDS} seconds for the app to load...`);
|
|
201
|
-
await firstWindow.waitForFunction(() => document.readyState === "complete");
|
|
202
|
-
return {
|
|
203
|
-
window: firstWindow,
|
|
204
|
-
cleanup: async () => {
|
|
205
|
-
await electronApp.close();
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
199
|
}
|
|
209
|
-
|
|
200
|
+
let prefix = "";
|
|
201
|
+
const branch = execSync("git branch --show-current", { encoding: "utf8" }).trim();
|
|
202
|
+
consola.info("Current branch:", branch);
|
|
203
|
+
if (branch === "next") prefix = "next.";
|
|
204
|
+
await navigateToCloudApp(page, `https://${prefix}vease.geode-solutions.com`, 10);
|
|
205
|
+
await signInToCloudApp(page);
|
|
206
|
+
return {
|
|
207
|
+
window: page,
|
|
208
|
+
cleanup: async () => {
|
|
209
|
+
await page.close();
|
|
210
|
+
await browser.close();
|
|
211
|
+
}
|
|
212
|
+
};
|
|
210
213
|
}
|
|
211
214
|
async function navigateToViewerPage(window) {
|
|
212
215
|
await window.getByTestId("viewerNavButton").click();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { waitForActionSettled } from "../wait_for_action_settled.js";
|
|
2
2
|
import { moveMouseOutOfTheWay } from "../app_interaction.js";
|
|
3
|
-
import { clickCollapseOrExpandAll, collapseGeodeObjectTypeInTree, collapseTreeGroup, expandGeodeObjectTypeInTree, getTreeRowByTextAndParent } from "./common.js";
|
|
3
|
+
import { clickCollapseOrExpandAll, collapseGeodeObjectTypeInTree, collapseTreeGroup, expandGeodeObjectTypeInTree, getTreeRowByTextAndParent, openObjectTreeContextMenu } from "./common.js";
|
|
4
4
|
import { consola } from "consola";
|
|
5
5
|
//#region tests/e2e/utils/object_trees/main_object_tree.ts
|
|
6
6
|
const HIGHLIGHT_HOVER_ATTEMPTS = 3;
|
|
@@ -57,6 +57,15 @@ async function showObjectInTree(window, objectName) {
|
|
|
57
57
|
await waitForActionSettled(window);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
async function openGeodeObjectTypeContextMenu(window, geodeObjectType) {
|
|
61
|
+
await openObjectTreeContextMenu(window, geodeObjectType, getMainObjectTree(window));
|
|
62
|
+
}
|
|
63
|
+
async function openDataContextMenu(window, geodeObjectType, dataName) {
|
|
64
|
+
await expandGeodeObjectType(window, geodeObjectType);
|
|
65
|
+
const mainObjectTree = getMainObjectTree(window);
|
|
66
|
+
await (await getTreeRowByTextAndParent(window, geodeObjectType, dataName, mainObjectTree)).getByTestId("treeItemLabel").first().click({ button: "right" });
|
|
67
|
+
await waitForActionSettled(window);
|
|
68
|
+
}
|
|
60
69
|
async function toggleObjectsTree(window) {
|
|
61
70
|
await window.getByTestId("toggleObjectsButton").click();
|
|
62
71
|
await waitForActionSettled(window);
|
|
@@ -74,4 +83,4 @@ async function openObjectsTree(window) {
|
|
|
74
83
|
}
|
|
75
84
|
}
|
|
76
85
|
//#endregion
|
|
77
|
-
export { closeObjectsTree, collapseGeodeObjectType, collapseMainObjectTree, collapseMainObjectTreeGroup, expandGeodeObjectType, expandMainObjectTree, focusObjectInTree, getMainObjectTree, highlightData, openObjectsTree, showObjectInTree, toggleObjectsTree };
|
|
86
|
+
export { closeObjectsTree, collapseGeodeObjectType, collapseMainObjectTree, collapseMainObjectTreeGroup, expandGeodeObjectType, expandMainObjectTree, focusObjectInTree, getMainObjectTree, highlightData, openDataContextMenu, openGeodeObjectTypeContextMenu, openObjectsTree, showObjectInTree, toggleObjectsTree };
|
|
@@ -82,13 +82,6 @@ async function openModelComponentsTree(window, geodeObjectType, dataName) {
|
|
|
82
82
|
await moveMouseOutOfTheWay(window);
|
|
83
83
|
await waitForActionSettled(window);
|
|
84
84
|
}
|
|
85
|
-
async function openModelCollectionsTree(window, geodeObjectType, dataName) {
|
|
86
|
-
await expandGeodeObjectType(window, geodeObjectType);
|
|
87
|
-
const mainObjectTree = getMainObjectTree(window);
|
|
88
|
-
await (await getTreeRowByTextAndParent(window, geodeObjectType, dataName, mainObjectTree)).getByTestId("expandModelCollectionsButton").first().click();
|
|
89
|
-
await moveMouseOutOfTheWay(window);
|
|
90
|
-
await waitForActionSettled(window);
|
|
91
|
-
}
|
|
92
85
|
async function hideAllComponentLeafRows(window, categoryName) {
|
|
93
86
|
const tree = getModelComponentsObjectTree(window);
|
|
94
87
|
await expandGeodeObjectTypeInTree(window, categoryName, tree);
|
|
@@ -101,4 +94,4 @@ async function hideAllComponentLeafRows(window, categoryName) {
|
|
|
101
94
|
await waitForActionSettled(window);
|
|
102
95
|
}
|
|
103
96
|
//#endregion
|
|
104
|
-
export { collapseMeshComponentType, collapseModelComponentTypes, collapseModelComponentsObjectTree, collapseModelComponentsObjectTreeGroup, expandMeshComponentType, expandModelComponentsObjectTree, getModelComponentTypeOptions, getModelComponentsObjectTree, hideAllComponentLeafRows, hoverCorners, hoverLines, hoverModelBlock, hoverSurfaces,
|
|
97
|
+
export { collapseMeshComponentType, collapseModelComponentTypes, collapseModelComponentsObjectTree, collapseModelComponentsObjectTreeGroup, expandMeshComponentType, expandModelComponentsObjectTree, getModelComponentTypeOptions, getModelComponentsObjectTree, hideAllComponentLeafRows, hoverCorners, hoverLines, hoverModelBlock, hoverSurfaces, openModelComponentContextMenu, openModelComponentsTree, setModelTreeRowColorRandom, toggleModelTreeRow };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vease",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.52.0-rc.10",
|
|
4
4
|
"description": "Desktop and cloud software for data visualization",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Desktop",
|
|
@@ -71,12 +71,11 @@
|
|
|
71
71
|
"test:e2e": "npm run pretest && npx playwright test --config ./tests/e2e/playwright.config.ts",
|
|
72
72
|
"test:e2e:browser:chrome": "npm run test:e2e -- --project=browser-chrome",
|
|
73
73
|
"test:e2e:browser:firefox": "npm run test:e2e -- --project=browser-firefox",
|
|
74
|
-
"test:e2e:browser": "npm run test:e2e:browser:chrome",
|
|
74
|
+
"test:e2e:browser": "npm run test:e2e:browser:chrome --",
|
|
75
75
|
"test:e2e:cloud": "npm run test:e2e -- --project=cloud",
|
|
76
76
|
"test:e2e:desktop": "npm run test:e2e -- --project=desktop",
|
|
77
77
|
"test:e2e:update_snapshots": "npm run test:e2e:browser:chrome -- --update-snapshots",
|
|
78
|
-
"prepare:types": "cross-env MODE=BROWSER nuxi prepare"
|
|
79
|
-
"typecheck": "npm run prepare:types && vue-tsc --noEmit -p tsconfig.json && tsc --noEmit -p .nuxt/tsconfig.server.json --noImplicitAny false && tsc --noEmit -p tsconfig.node.json && tsc --noEmit -p tests/e2e/tsconfig.json"
|
|
78
|
+
"prepare:types": "cross-env MODE=BROWSER nuxi prepare"
|
|
80
79
|
},
|
|
81
80
|
"dependencies": {
|
|
82
81
|
"@ai-sdk/gateway": "4.0.75",
|
|
@@ -85,12 +84,12 @@
|
|
|
85
84
|
"@ai-sdk/vue": "4.0.93",
|
|
86
85
|
"@fontsource/michroma": "5.2.6",
|
|
87
86
|
"@fontsource/roboto": "5.2.10",
|
|
88
|
-
"@geode/cloud-api": "
|
|
89
|
-
"@geode/opengeodeweb-back": "
|
|
90
|
-
"@geode/opengeodeweb-front": "
|
|
91
|
-
"@geode/opengeodeweb-viewer": "
|
|
92
|
-
"@geode/vease-back": "
|
|
93
|
-
"@geode/vease-viewer": "
|
|
87
|
+
"@geode/cloud-api": "next",
|
|
88
|
+
"@geode/opengeodeweb-back": "next",
|
|
89
|
+
"@geode/opengeodeweb-front": "next",
|
|
90
|
+
"@geode/opengeodeweb-viewer": "next",
|
|
91
|
+
"@geode/vease-back": "next",
|
|
92
|
+
"@geode/vease-viewer": "next",
|
|
94
93
|
"@nuxtjs/mcp-toolkit": "0.18.1",
|
|
95
94
|
"ai": "7.0.93",
|
|
96
95
|
"bowser": "2.14.1",
|
|
@@ -116,18 +115,18 @@
|
|
|
116
115
|
"concurrently": "9.2.1",
|
|
117
116
|
"cross-env": "10.0.0",
|
|
118
117
|
"electron": "36.4.0",
|
|
119
|
-
"electron-builder": "26.
|
|
118
|
+
"electron-builder": "26.15.3",
|
|
120
119
|
"electron-playwright-helpers": "1.7.1",
|
|
121
120
|
"happy-dom": "20.0.11",
|
|
122
121
|
"nuxt-electron": "0.7.0",
|
|
122
|
+
"oxlint": "latest",
|
|
123
|
+
"oxlint-tsgolint": "latest",
|
|
123
124
|
"pinia": "4.0.2",
|
|
124
125
|
"playwright": "1.54.1",
|
|
125
126
|
"rolldown": "1.2.8",
|
|
126
127
|
"std-env": "3.9.0",
|
|
127
|
-
"typescript": "5.9.3",
|
|
128
128
|
"vitest": "4.1.10",
|
|
129
129
|
"vitest-environment-nuxt": "2.0.0",
|
|
130
|
-
"vitest-indexeddb": "0.0.1"
|
|
131
|
-
"vue-tsc": "3.3.11"
|
|
130
|
+
"vitest-indexeddb": "0.0.1"
|
|
132
131
|
}
|
|
133
132
|
}
|
|
@@ -15,7 +15,6 @@ async function resetCamera(window: Page): Promise<void> {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const ROTATE_DRAG_STEPS = 20;
|
|
18
|
-
|
|
19
18
|
// Vtk.js' RenderWindowInteractor turns a pointermove arriving more than 200ms after the previous one into a StartMouseMove, which InteractorStyleTrackballCamera ignores.
|
|
20
19
|
// A skipped move mid-drag is caught up by the next handled one (rotation uses the delta from the last handled position), but a skipped final move is lost for good.
|
|
21
20
|
// On slow runners (Windows + swiftshader) the last step regularly lands late, leaving the camera one step short of the requested angle.
|
|
@@ -145,17 +144,20 @@ async function toggleShrinkFilter(window: Page): Promise<void> {
|
|
|
145
144
|
await waitForActionSettled(window);
|
|
146
145
|
}
|
|
147
146
|
|
|
148
|
-
async function
|
|
149
|
-
const slider = window.getByTestId(
|
|
147
|
+
async function setSliderRatio(window: Page, sliderTestId: string, ratio: number): Promise<void> {
|
|
148
|
+
const slider = window.getByTestId(sliderTestId);
|
|
150
149
|
const box = await slider.boundingBox();
|
|
151
150
|
if (!box) {
|
|
152
|
-
throw new Error(
|
|
151
|
+
throw new Error(`Could not get bounding box of the ${sliderTestId} slider.`);
|
|
153
152
|
}
|
|
154
|
-
|
|
155
|
-
await slider.click({ position: { x: clickX, y: box.height / 2 } });
|
|
153
|
+
await slider.click({ position: { x: box.width * ratio, y: box.height / 2 } });
|
|
156
154
|
await waitForActionSettled(window);
|
|
157
155
|
}
|
|
158
156
|
|
|
157
|
+
async function setShrinkFactor(window: Page, shrinkFactorValue: number): Promise<void> {
|
|
158
|
+
await setSliderRatio(window, "shrinkFactorSlider", shrinkFactorValue);
|
|
159
|
+
}
|
|
160
|
+
|
|
159
161
|
async function resetShrinkFilter(window: Page): Promise<void> {
|
|
160
162
|
await window.getByTestId("resetShrinkButton").click();
|
|
161
163
|
await waitForActionSettled(window);
|
|
@@ -179,6 +181,25 @@ async function selectShrinkDatasets(window: Page, datasetName: string, index = 0
|
|
|
179
181
|
await waitForActionSettled(window);
|
|
180
182
|
}
|
|
181
183
|
|
|
184
|
+
async function toggleExplodeFilter(window: Page): Promise<void> {
|
|
185
|
+
await window.getByTestId("explodeFilterButton").click();
|
|
186
|
+
await waitForActionSettled(window);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function setExplodeFactor(window: Page, explodeFactorValue: number): Promise<void> {
|
|
190
|
+
await setSliderRatio(window, "explodeFactorSlider", explodeFactorValue);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function resetExplodeFilter(window: Page): Promise<void> {
|
|
194
|
+
await window.getByTestId("resetExplodeButton").click();
|
|
195
|
+
await waitForActionSettled(window);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function removeExplodeFilter(window: Page): Promise<void> {
|
|
199
|
+
await window.getByTestId("removeExplodeButton").click();
|
|
200
|
+
await waitForActionSettled(window);
|
|
201
|
+
}
|
|
202
|
+
|
|
182
203
|
async function toggleThresholdFilter(window: Page): Promise<void> {
|
|
183
204
|
await window.getByTestId("thresholdFilterButton").click();
|
|
184
205
|
await waitForActionSettled(window);
|
|
@@ -308,6 +329,10 @@ export {
|
|
|
308
329
|
resetShrinkFilter,
|
|
309
330
|
toggleShrinkTargetAllVisible,
|
|
310
331
|
selectShrinkDatasets,
|
|
332
|
+
toggleExplodeFilter,
|
|
333
|
+
setExplodeFactor,
|
|
334
|
+
resetExplodeFilter,
|
|
335
|
+
removeExplodeFilter,
|
|
311
336
|
toggleThresholdFilter,
|
|
312
337
|
selectThresholdCellAttribute,
|
|
313
338
|
selectThresholdBlockPolyhedron,
|
|
@@ -4,7 +4,7 @@ import os from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
6
|
// Third party imports
|
|
7
|
-
import type { Locator, Page } from "@playwright/test";
|
|
7
|
+
import type { Browser, Locator, Page } from "@playwright/test";
|
|
8
8
|
// oxlint-disable-next-line eslint/no-duplicate-imports
|
|
9
9
|
import { test as base, expect } from "@playwright/test";
|
|
10
10
|
import { consola } from "consola";
|
|
@@ -44,14 +44,27 @@ const test = base.extend<TestFixtures, WorkerFixtures>({
|
|
|
44
44
|
],
|
|
45
45
|
|
|
46
46
|
window: [
|
|
47
|
-
async (
|
|
47
|
+
async (
|
|
48
|
+
{ mode, playwright, browserName, headless, channel, launchOptions },
|
|
49
|
+
use,
|
|
50
|
+
workerInfo,
|
|
51
|
+
): Promise<void> => {
|
|
48
52
|
// Each worker runs its own app: give it its own config folder (where extensions are installed) so parallel installs don't overwrite each other
|
|
49
53
|
const configPath = fs.mkdtempSync(
|
|
50
54
|
path.join(os.tmpdir(), `vease-e2e-worker${workerInfo.parallelIndex}-`),
|
|
51
55
|
);
|
|
52
56
|
process.env.XDG_CONFIG_HOME = configPath;
|
|
53
57
|
process.env.APPDATA = configPath;
|
|
54
|
-
|
|
58
|
+
// Launched on demand instead of using the browser fixture, which would start (and require installing) a browser in DESKTOP mode too
|
|
59
|
+
async function launchBrowser(): Promise<Browser> {
|
|
60
|
+
const browser = await playwright[browserName].launch({
|
|
61
|
+
...launchOptions,
|
|
62
|
+
headless,
|
|
63
|
+
channel,
|
|
64
|
+
});
|
|
65
|
+
return browser;
|
|
66
|
+
}
|
|
67
|
+
const { window, cleanup } = await navigateToApp(mode, launchBrowser);
|
|
55
68
|
await use(window);
|
|
56
69
|
await cleanup();
|
|
57
70
|
fs.rmSync(configPath, { recursive: true, force: true });
|
|
@@ -199,10 +199,7 @@ async function signInToCloudApp(page: Page): Promise<void> {
|
|
|
199
199
|
await page.waitForFunction(() => document.readyState === "complete");
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
async function
|
|
203
|
-
mode: string,
|
|
204
|
-
browser: Browser,
|
|
205
|
-
): Promise<{ window: Page; cleanup: () => Promise<void> }> {
|
|
202
|
+
async function newBrowserPage(browser: Browser): Promise<Page> {
|
|
206
203
|
const context = await browser.newContext({
|
|
207
204
|
viewport: { width: PAGE_WIDTH, height: PAGE_HEIGHT },
|
|
208
205
|
locale: LOCALE,
|
|
@@ -215,13 +212,36 @@ async function navigateToApp(
|
|
|
215
212
|
consola.info("PAGE CLOSED:", newPage.url());
|
|
216
213
|
});
|
|
217
214
|
});
|
|
218
|
-
|
|
215
|
+
return context.newPage();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function navigateToApp(
|
|
219
|
+
mode: string,
|
|
220
|
+
launchBrowser: () => Promise<Browser>,
|
|
221
|
+
): Promise<{ window: Page; cleanup: () => Promise<void> }> {
|
|
219
222
|
consola.info(`Testing app in ${mode} mode`);
|
|
223
|
+
// The desktop app is driven through Electron: no browser is launched
|
|
224
|
+
if (mode === "DESKTOP") {
|
|
225
|
+
const { electronApp, firstWindow } = await runDesktopBuild();
|
|
226
|
+
consola.info(`Waiting for ${WAIT_TIMES.desktop / MILLISECONDS} seconds for the app to load...`);
|
|
227
|
+
await firstWindow.waitForFunction(() => document.readyState === "complete");
|
|
228
|
+
return {
|
|
229
|
+
window: firstWindow,
|
|
230
|
+
cleanup: async () => {
|
|
231
|
+
await electronApp.close();
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
if (mode !== "BROWSER" && mode !== "CLOUD") {
|
|
236
|
+
throw new Error(`Unknown mode: ${mode}`);
|
|
237
|
+
}
|
|
238
|
+
const browser = await launchBrowser();
|
|
239
|
+
const page = await newBrowserPage(browser);
|
|
240
|
+
page.on("console", (msg) => {
|
|
241
|
+
consola.info(`Browser console: ${msg.text()}`);
|
|
242
|
+
});
|
|
220
243
|
if (mode === "BROWSER") {
|
|
221
244
|
const nuxtPort = await runBrowser("preview:browser");
|
|
222
|
-
page.on("console", (msg) => {
|
|
223
|
-
consola.info(`Browser console: ${msg.text()}`);
|
|
224
|
-
});
|
|
225
245
|
const appUrl = `http://localhost:${nuxtPort}`;
|
|
226
246
|
await page.goto(appUrl);
|
|
227
247
|
consola.info("Navigated to", page.url());
|
|
@@ -233,45 +253,32 @@ async function navigateToApp(
|
|
|
233
253
|
window: page,
|
|
234
254
|
cleanup: async () => {
|
|
235
255
|
await page.close();
|
|
256
|
+
await browser.close();
|
|
236
257
|
await kill(nuxtPort);
|
|
237
258
|
},
|
|
238
259
|
};
|
|
239
|
-
}
|
|
240
|
-
page.on("console", (msg) => {
|
|
241
|
-
consola.info(`Browser console: ${msg.text()}`);
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
let prefix = "";
|
|
245
|
-
const branch = execSync("git branch --show-current", {
|
|
246
|
-
encoding: "utf8",
|
|
247
|
-
}).trim();
|
|
248
|
-
consola.info("Current branch:", branch);
|
|
249
|
-
if (branch === "next") {
|
|
250
|
-
prefix = "next.";
|
|
251
|
-
}
|
|
252
|
-
const url = `https://${prefix}vease.geode-solutions.com`;
|
|
253
|
-
const maxRetries = 10;
|
|
254
|
-
await navigateToCloudApp(page, url, maxRetries);
|
|
255
|
-
await signInToCloudApp(page);
|
|
260
|
+
}
|
|
256
261
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const { electronApp, firstWindow } = await runDesktopBuild();
|
|
265
|
-
consola.info(`Waiting for ${WAIT_TIMES.desktop / MILLISECONDS} seconds for the app to load...`);
|
|
266
|
-
await firstWindow.waitForFunction(() => document.readyState === "complete");
|
|
267
|
-
return {
|
|
268
|
-
window: firstWindow,
|
|
269
|
-
cleanup: async () => {
|
|
270
|
-
await electronApp.close();
|
|
271
|
-
},
|
|
272
|
-
};
|
|
262
|
+
let prefix = "";
|
|
263
|
+
const branch = execSync("git branch --show-current", {
|
|
264
|
+
encoding: "utf8",
|
|
265
|
+
}).trim();
|
|
266
|
+
consola.info("Current branch:", branch);
|
|
267
|
+
if (branch === "next") {
|
|
268
|
+
prefix = "next.";
|
|
273
269
|
}
|
|
274
|
-
|
|
270
|
+
const url = `https://${prefix}vease.geode-solutions.com`;
|
|
271
|
+
const maxRetries = 10;
|
|
272
|
+
await navigateToCloudApp(page, url, maxRetries);
|
|
273
|
+
await signInToCloudApp(page);
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
window: page,
|
|
277
|
+
cleanup: async () => {
|
|
278
|
+
await page.close();
|
|
279
|
+
await browser.close();
|
|
280
|
+
},
|
|
281
|
+
};
|
|
275
282
|
}
|
|
276
283
|
|
|
277
284
|
async function navigateToViewerPage(window: Page): Promise<void> {
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
collapseTreeGroup,
|
|
6
6
|
expandGeodeObjectTypeInTree,
|
|
7
7
|
getTreeRowByTextAndParent,
|
|
8
|
+
openObjectTreeContextMenu,
|
|
8
9
|
} from "./common";
|
|
9
10
|
import { consola } from "consola";
|
|
10
11
|
import { moveMouseOutOfTheWay } from "@vease_tests/utils/app_interaction";
|
|
@@ -102,6 +103,25 @@ async function showObjectInTree(window: Page, objectName: string): Promise<void>
|
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
async function openGeodeObjectTypeContextMenu(
|
|
107
|
+
window: Page,
|
|
108
|
+
geodeObjectType: string,
|
|
109
|
+
): Promise<void> {
|
|
110
|
+
await openObjectTreeContextMenu(window, geodeObjectType, getMainObjectTree(window));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function openDataContextMenu(
|
|
114
|
+
window: Page,
|
|
115
|
+
geodeObjectType: string,
|
|
116
|
+
dataName: string,
|
|
117
|
+
): Promise<void> {
|
|
118
|
+
await expandGeodeObjectType(window, geodeObjectType);
|
|
119
|
+
const mainObjectTree = getMainObjectTree(window);
|
|
120
|
+
const row = await getTreeRowByTextAndParent(window, geodeObjectType, dataName, mainObjectTree);
|
|
121
|
+
await row.getByTestId("treeItemLabel").first().click({ button: "right" });
|
|
122
|
+
await waitForActionSettled(window);
|
|
123
|
+
}
|
|
124
|
+
|
|
105
125
|
async function toggleObjectsTree(window: Page): Promise<void> {
|
|
106
126
|
await window.getByTestId("toggleObjectsButton").click();
|
|
107
127
|
await waitForActionSettled(window);
|
|
@@ -139,6 +159,8 @@ export {
|
|
|
139
159
|
focusObjectInTree,
|
|
140
160
|
getMainObjectTree,
|
|
141
161
|
highlightData,
|
|
162
|
+
openDataContextMenu,
|
|
163
|
+
openGeodeObjectTypeContextMenu,
|
|
142
164
|
openObjectsTree,
|
|
143
165
|
showObjectInTree,
|
|
144
166
|
toggleObjectsTree,
|
|
@@ -149,19 +149,6 @@ async function openModelComponentsTree(
|
|
|
149
149
|
await waitForActionSettled(window);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
async function openModelCollectionsTree(
|
|
153
|
-
window: Page,
|
|
154
|
-
geodeObjectType: string,
|
|
155
|
-
dataName: string,
|
|
156
|
-
): Promise<void> {
|
|
157
|
-
await expandGeodeObjectType(window, geodeObjectType);
|
|
158
|
-
const mainObjectTree = getMainObjectTree(window);
|
|
159
|
-
const row = await getTreeRowByTextAndParent(window, geodeObjectType, dataName, mainObjectTree);
|
|
160
|
-
await row.getByTestId("expandModelCollectionsButton").first().click();
|
|
161
|
-
await moveMouseOutOfTheWay(window);
|
|
162
|
-
await waitForActionSettled(window);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
152
|
async function hideAllComponentLeafRows(window: Page, categoryName: string): Promise<void> {
|
|
166
153
|
const tree = getModelComponentsObjectTree(window);
|
|
167
154
|
await expandGeodeObjectTypeInTree(window, categoryName, tree);
|
|
@@ -192,7 +179,6 @@ export {
|
|
|
192
179
|
hoverModelBlock,
|
|
193
180
|
hoverSurfaces,
|
|
194
181
|
openModelComponentContextMenu,
|
|
195
|
-
openModelCollectionsTree,
|
|
196
182
|
openModelComponentsTree,
|
|
197
183
|
setModelTreeRowColorRandom,
|
|
198
184
|
toggleModelTreeRow,
|