vease 1.52.0-rc.9 → 1.52.0
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 +22 -5
- package/.build/tests/e2e/utils/navigate.js +1 -0
- package/.build/tests/e2e/utils/project_interaction.js +32 -3
- package/package.json +7 -7
- package/tests/e2e/utils/camera_interaction.ts +31 -6
- package/tests/e2e/utils/fixtures.ts +45 -5
- package/tests/e2e/utils/navigate.ts +2 -1
- package/tests/e2e/utils/project_interaction.ts +52 -5
|
@@ -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,7 +18,7 @@ const test = test$1.extend({
|
|
|
18
18
|
screenshotMask: [async ({}, use) => {
|
|
19
19
|
await use({ locators: [] });
|
|
20
20
|
}, { scope: "test" }],
|
|
21
|
-
|
|
21
|
+
app: [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;
|
|
@@ -29,14 +29,30 @@ const test = test$1.extend({
|
|
|
29
29
|
channel
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const app = {
|
|
33
|
+
...await navigateToApp(mode, launchBrowser),
|
|
34
|
+
restart: async () => {
|
|
35
|
+
await app.cleanup();
|
|
36
|
+
const { window, cleanup, electronApp } = await navigateToApp(mode, launchBrowser);
|
|
37
|
+
app.window = window;
|
|
38
|
+
app.cleanup = cleanup;
|
|
39
|
+
app.electronApp = electronApp;
|
|
40
|
+
return window;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
await use(app);
|
|
44
|
+
await app.cleanup();
|
|
35
45
|
fs.rmSync(configPath, {
|
|
36
46
|
recursive: true,
|
|
37
47
|
force: true
|
|
38
48
|
});
|
|
39
49
|
}, { scope: "worker" }],
|
|
50
|
+
restartApp: [async ({ app }, use) => {
|
|
51
|
+
await use(app.restart);
|
|
52
|
+
}, { scope: "worker" }],
|
|
53
|
+
window: [async ({ app }, use) => {
|
|
54
|
+
await use(app.window);
|
|
55
|
+
}, { scope: "worker" }],
|
|
40
56
|
logTestProgress: [async ({}, use, testInfo) => {
|
|
41
57
|
const name = `${path.basename(testInfo.file)} › ${testInfo.title}`;
|
|
42
58
|
consola.info(`\u001B[33m[START]\u001B[0m ${name}`);
|
|
@@ -47,8 +63,9 @@ const test = test$1.extend({
|
|
|
47
63
|
const duration = ((Date.now() - start) / MILLISECONDS_PER_SECOND).toFixed(2);
|
|
48
64
|
consola.info(`\u001B[35m[END]\u001B[0m ${name} : ${statusColor}TEST ${status}\u001B[0m (${duration}s)`);
|
|
49
65
|
}, { auto: true }],
|
|
50
|
-
autoScreenshot: [async ({
|
|
66
|
+
autoScreenshot: [async ({ app, screenshotMask }, use, testInfo) => {
|
|
51
67
|
await use(void 0);
|
|
68
|
+
const { window } = app;
|
|
52
69
|
if (testInfo.status === testInfo.expectedStatus) await expect(window).toHaveScreenshot({ mask: [window.getByTestId("accountNavButton"), ...screenshotMask.locators] });
|
|
53
70
|
}, { auto: true }]
|
|
54
71
|
});
|
|
@@ -1,16 +1,45 @@
|
|
|
1
1
|
import { waitForActionSettled } from "./wait_for_action_settled.js";
|
|
2
|
+
import { closeFeedbackSnackbar } from "./app_interaction.js";
|
|
3
|
+
import { expect } from "@playwright/test";
|
|
2
4
|
//#region tests/e2e/utils/project_interaction.ts
|
|
3
|
-
|
|
5
|
+
const importProjectTimeout = 2e4;
|
|
6
|
+
const downloadTimeout = 3e4;
|
|
7
|
+
async function saveNextElectronDownload(electronApp, savePath, trigger) {
|
|
8
|
+
await electronApp.evaluate(({ session }, filePath) => {
|
|
9
|
+
globalThis.e2eDownloadState = "pending";
|
|
10
|
+
session.defaultSession.once("will-download", (_event, item) => {
|
|
11
|
+
item.setSavePath(filePath);
|
|
12
|
+
item.once("done", (_doneEvent, state) => {
|
|
13
|
+
globalThis.e2eDownloadState = state;
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
}, savePath);
|
|
17
|
+
await trigger();
|
|
18
|
+
async function getDownloadState() {
|
|
19
|
+
return await electronApp.evaluate(() => globalThis.e2eDownloadState);
|
|
20
|
+
}
|
|
21
|
+
await expect.poll(getDownloadState, { timeout: downloadTimeout }).toBe("completed");
|
|
22
|
+
}
|
|
23
|
+
async function exportProject(window, savePath, electronApp) {
|
|
4
24
|
await window.getByTestId("projectMenuButton").click();
|
|
5
25
|
await waitForActionSettled(window);
|
|
6
|
-
|
|
26
|
+
const exportProjectButton = window.getByTestId("exportProjectButton");
|
|
27
|
+
if (electronApp) await saveNextElectronDownload(electronApp, savePath, async () => {
|
|
28
|
+
await exportProjectButton.click();
|
|
29
|
+
});
|
|
30
|
+
else {
|
|
31
|
+
const [download] = await Promise.all([window.waitForEvent("download"), exportProjectButton.click()]);
|
|
32
|
+
await download.saveAs(savePath);
|
|
33
|
+
}
|
|
7
34
|
await waitForActionSettled(window);
|
|
35
|
+
await closeFeedbackSnackbar(window);
|
|
8
36
|
}
|
|
9
37
|
async function importProject(window, projectFilePath) {
|
|
10
38
|
await window.getByTestId("projectMenuButton").click();
|
|
11
39
|
await waitForActionSettled(window);
|
|
12
40
|
await window.getByTestId("importProjectInput").setInputFiles(projectFilePath);
|
|
13
|
-
await window
|
|
41
|
+
await waitForActionSettled(window, importProjectTimeout);
|
|
42
|
+
await closeFeedbackSnackbar(window);
|
|
14
43
|
}
|
|
15
44
|
//#endregion
|
|
16
45
|
export { exportProject, importProject };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vease",
|
|
3
|
-
"version": "1.52.0
|
|
3
|
+
"version": "1.52.0",
|
|
4
4
|
"description": "Desktop and cloud software for data visualization",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Desktop",
|
|
@@ -84,12 +84,12 @@
|
|
|
84
84
|
"@ai-sdk/vue": "4.0.93",
|
|
85
85
|
"@fontsource/michroma": "5.2.6",
|
|
86
86
|
"@fontsource/roboto": "5.2.10",
|
|
87
|
-
"@geode/cloud-api": "
|
|
88
|
-
"@geode/opengeodeweb-back": "
|
|
89
|
-
"@geode/opengeodeweb-front": "
|
|
90
|
-
"@geode/opengeodeweb-viewer": "
|
|
91
|
-
"@geode/vease-back": "
|
|
92
|
-
"@geode/vease-viewer": "
|
|
87
|
+
"@geode/cloud-api": "latest",
|
|
88
|
+
"@geode/opengeodeweb-back": "latest",
|
|
89
|
+
"@geode/opengeodeweb-front": "latest",
|
|
90
|
+
"@geode/opengeodeweb-viewer": "latest",
|
|
91
|
+
"@geode/vease-back": "latest",
|
|
92
|
+
"@geode/vease-viewer": "latest",
|
|
93
93
|
"@nuxtjs/mcp-toolkit": "0.18.1",
|
|
94
94
|
"ai": "7.0.93",
|
|
95
95
|
"bowser": "2.14.1",
|
|
@@ -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,
|
|
@@ -7,6 +7,7 @@ import path from "node:path";
|
|
|
7
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
|
+
import type { ElectronApplication } from "playwright";
|
|
10
11
|
import { consola } from "consola";
|
|
11
12
|
|
|
12
13
|
// Local imports
|
|
@@ -18,9 +19,19 @@ interface ScreenshotMask {
|
|
|
18
19
|
locators: Locator[];
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
interface RunningApp {
|
|
23
|
+
window: Page;
|
|
24
|
+
cleanup: () => Promise<void>;
|
|
25
|
+
// Only set in DESKTOP mode
|
|
26
|
+
electronApp?: ElectronApplication;
|
|
27
|
+
restart: () => Promise<Page>;
|
|
28
|
+
}
|
|
29
|
+
|
|
21
30
|
interface WorkerFixtures {
|
|
22
31
|
mode: string;
|
|
23
32
|
suiteId: string;
|
|
33
|
+
app: RunningApp;
|
|
34
|
+
restartApp: () => Promise<Page>;
|
|
24
35
|
window: Page;
|
|
25
36
|
}
|
|
26
37
|
|
|
@@ -43,7 +54,8 @@ const test = base.extend<TestFixtures, WorkerFixtures>({
|
|
|
43
54
|
{ scope: "test" },
|
|
44
55
|
],
|
|
45
56
|
|
|
46
|
-
|
|
57
|
+
// Mutable so restartApp can swap in a freshly launched app
|
|
58
|
+
app: [
|
|
47
59
|
async (
|
|
48
60
|
{ mode, playwright, browserName, headless, channel, launchOptions },
|
|
49
61
|
use,
|
|
@@ -64,14 +76,40 @@ const test = base.extend<TestFixtures, WorkerFixtures>({
|
|
|
64
76
|
});
|
|
65
77
|
return browser;
|
|
66
78
|
}
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
const app: RunningApp = {
|
|
80
|
+
...(await navigateToApp(mode, launchBrowser)),
|
|
81
|
+
restart: async (): Promise<Page> => {
|
|
82
|
+
await app.cleanup();
|
|
83
|
+
const { window, cleanup, electronApp } = await navigateToApp(mode, launchBrowser);
|
|
84
|
+
app.window = window;
|
|
85
|
+
app.cleanup = cleanup;
|
|
86
|
+
app.electronApp = electronApp;
|
|
87
|
+
return window;
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
await use(app);
|
|
91
|
+
await app.cleanup();
|
|
70
92
|
fs.rmSync(configPath, { recursive: true, force: true });
|
|
71
93
|
},
|
|
72
94
|
{ scope: "worker" },
|
|
73
95
|
],
|
|
74
96
|
|
|
97
|
+
// Kills the running app and launches a new one, like a user closing and reopening it
|
|
98
|
+
restartApp: [
|
|
99
|
+
async ({ app }, use): Promise<void> => {
|
|
100
|
+
await use(app.restart);
|
|
101
|
+
},
|
|
102
|
+
{ scope: "worker" },
|
|
103
|
+
],
|
|
104
|
+
|
|
105
|
+
// Page of the app launched with the worker: after restartApp, use the returned page or app.window
|
|
106
|
+
window: [
|
|
107
|
+
async ({ app }, use): Promise<void> => {
|
|
108
|
+
await use(app.window);
|
|
109
|
+
},
|
|
110
|
+
{ scope: "worker" },
|
|
111
|
+
],
|
|
112
|
+
|
|
75
113
|
logTestProgress: [
|
|
76
114
|
// oxlint-disable-next-line no-empty-pattern
|
|
77
115
|
async ({}, use, testInfo): Promise<void> => {
|
|
@@ -90,8 +128,10 @@ const test = base.extend<TestFixtures, WorkerFixtures>({
|
|
|
90
128
|
],
|
|
91
129
|
|
|
92
130
|
autoScreenshot: [
|
|
93
|
-
async ({
|
|
131
|
+
async ({ app, screenshotMask }, use, testInfo): Promise<void> => {
|
|
94
132
|
await use(undefined);
|
|
133
|
+
// Read at teardown: the test may have restarted the app
|
|
134
|
+
const { window } = app;
|
|
95
135
|
if (testInfo.status === testInfo.expectedStatus) {
|
|
96
136
|
// The account icon depends on login state (only cloud is logged in)
|
|
97
137
|
await expect(window).toHaveScreenshot({
|
|
@@ -218,7 +218,7 @@ async function newBrowserPage(browser: Browser): Promise<Page> {
|
|
|
218
218
|
async function navigateToApp(
|
|
219
219
|
mode: string,
|
|
220
220
|
launchBrowser: () => Promise<Browser>,
|
|
221
|
-
): Promise<{ window: Page; cleanup: () => Promise<void
|
|
221
|
+
): Promise<{ window: Page; cleanup: () => Promise<void>; electronApp?: ElectronApplication }> {
|
|
222
222
|
consola.info(`Testing app in ${mode} mode`);
|
|
223
223
|
// The desktop app is driven through Electron: no browser is launched
|
|
224
224
|
if (mode === "DESKTOP") {
|
|
@@ -227,6 +227,7 @@ async function navigateToApp(
|
|
|
227
227
|
await firstWindow.waitForFunction(() => document.readyState === "complete");
|
|
228
228
|
return {
|
|
229
229
|
window: firstWindow,
|
|
230
|
+
electronApp,
|
|
230
231
|
cleanup: async () => {
|
|
231
232
|
await electronApp.close();
|
|
232
233
|
},
|
|
@@ -1,11 +1,58 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Page, expect } from "@playwright/test";
|
|
2
|
+
import type { ElectronApplication } from "playwright";
|
|
3
|
+
import { closeFeedbackSnackbar } from "./app_interaction";
|
|
2
4
|
import { waitForActionSettled } from "./wait_for_action_settled";
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
const importProjectTimeout = 20_000;
|
|
7
|
+
const downloadTimeout = 30_000;
|
|
8
|
+
|
|
9
|
+
declare global {
|
|
10
|
+
var e2eDownloadState: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function saveNextElectronDownload(
|
|
14
|
+
electronApp: ElectronApplication,
|
|
15
|
+
savePath: string,
|
|
16
|
+
trigger: () => Promise<void>,
|
|
17
|
+
): Promise<void> {
|
|
18
|
+
await electronApp.evaluate(({ session }, filePath) => {
|
|
19
|
+
globalThis.e2eDownloadState = "pending";
|
|
20
|
+
session.defaultSession.once("will-download", (_event, item) => {
|
|
21
|
+
item.setSavePath(filePath);
|
|
22
|
+
item.once("done", (_doneEvent, state) => {
|
|
23
|
+
globalThis.e2eDownloadState = state;
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}, savePath);
|
|
27
|
+
await trigger();
|
|
28
|
+
async function getDownloadState(): Promise<string | undefined> {
|
|
29
|
+
const state = await electronApp.evaluate(() => globalThis.e2eDownloadState);
|
|
30
|
+
return state;
|
|
31
|
+
}
|
|
32
|
+
await expect.poll(getDownloadState, { timeout: downloadTimeout }).toBe("completed");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function exportProject(
|
|
36
|
+
window: Page,
|
|
37
|
+
savePath: string,
|
|
38
|
+
electronApp?: ElectronApplication,
|
|
39
|
+
): Promise<void> {
|
|
5
40
|
await window.getByTestId("projectMenuButton").click();
|
|
6
41
|
await waitForActionSettled(window);
|
|
7
|
-
|
|
42
|
+
const exportProjectButton = window.getByTestId("exportProjectButton");
|
|
43
|
+
if (electronApp) {
|
|
44
|
+
await saveNextElectronDownload(electronApp, savePath, async () => {
|
|
45
|
+
await exportProjectButton.click();
|
|
46
|
+
});
|
|
47
|
+
} else {
|
|
48
|
+
const [download] = await Promise.all([
|
|
49
|
+
window.waitForEvent("download"),
|
|
50
|
+
exportProjectButton.click(),
|
|
51
|
+
]);
|
|
52
|
+
await download.saveAs(savePath);
|
|
53
|
+
}
|
|
8
54
|
await waitForActionSettled(window);
|
|
55
|
+
await closeFeedbackSnackbar(window);
|
|
9
56
|
}
|
|
10
57
|
|
|
11
58
|
async function importProject(window: Page, projectFilePath: string): Promise<void> {
|
|
@@ -13,8 +60,8 @@ async function importProject(window: Page, projectFilePath: string): Promise<voi
|
|
|
13
60
|
await waitForActionSettled(window);
|
|
14
61
|
const fileInput = window.getByTestId("importProjectInput");
|
|
15
62
|
await fileInput.setInputFiles(projectFilePath);
|
|
16
|
-
|
|
17
|
-
await window
|
|
63
|
+
await waitForActionSettled(window, importProjectTimeout);
|
|
64
|
+
await closeFeedbackSnackbar(window);
|
|
18
65
|
}
|
|
19
66
|
|
|
20
67
|
export { exportProject, importProject };
|