@pipelab/plugin-construct 1.0.0-beta.12 → 1.0.0-beta.13
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/dist/assets/construct.webp +0 -0
- package/dist/assets/script.ts +288 -0
- package/dist/index.cjs +3646 -746
- package/dist/index.mjs +3230 -333
- package/dist/index.mjs.map +1 -1
- package/package.json +22 -4
|
Binary file
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { Page } from "playwright";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
const registerInstallButtonListener = (page: Page, log: typeof console.log) => {
|
|
5
|
+
// as soon as it appear, without blocking flow
|
|
6
|
+
// accept installing plugins
|
|
7
|
+
const installDialog = page.locator("#addonConfirmInstallDialog");
|
|
8
|
+
const installBtn = installDialog.locator(".okButton");
|
|
9
|
+
installBtn
|
|
10
|
+
.waitFor({
|
|
11
|
+
timeout: 0,
|
|
12
|
+
})
|
|
13
|
+
.then(async () => {
|
|
14
|
+
await installBtn.click();
|
|
15
|
+
log("installBtn clicked");
|
|
16
|
+
registerInstallButtonListener(page, log);
|
|
17
|
+
})
|
|
18
|
+
.catch(async (e) => {
|
|
19
|
+
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
20
|
+
log("installBtn.click() failed", e.message);
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const registerSaveLoginExpiredistener = (page: Page, log: typeof console.log) => {
|
|
25
|
+
// as soon as it appear, without blocking flow
|
|
26
|
+
// accept installing plugins
|
|
27
|
+
const installDialog = page.locator("#confirmDialog");
|
|
28
|
+
const cancelBtn = installDialog.locator(".cancelConfirmButton");
|
|
29
|
+
cancelBtn
|
|
30
|
+
.waitFor({
|
|
31
|
+
timeout: 0,
|
|
32
|
+
})
|
|
33
|
+
.then(async () => {
|
|
34
|
+
await cancelBtn.click();
|
|
35
|
+
log("cancelBtn clicked");
|
|
36
|
+
registerSaveLoginExpiredistener(page, log);
|
|
37
|
+
})
|
|
38
|
+
.catch(async (e) => {
|
|
39
|
+
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
40
|
+
log("cancelBtn.click() failed", e.message);
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const registerWebglErrorListener = (page: Page, log: typeof console.log) => {
|
|
45
|
+
// as soon as it appear, without blocking flow
|
|
46
|
+
// ignore webgl error
|
|
47
|
+
const okDialog = page.locator("#okDialog");
|
|
48
|
+
const webglErrorButton = okDialog.locator(".okButton");
|
|
49
|
+
webglErrorButton
|
|
50
|
+
.waitFor({
|
|
51
|
+
timeout: 0,
|
|
52
|
+
})
|
|
53
|
+
.then(async () => {
|
|
54
|
+
const text = await okDialog.allInnerTexts();
|
|
55
|
+
|
|
56
|
+
if (text.join().toLowerCase().includes("webgl")) {
|
|
57
|
+
await webglErrorButton.click();
|
|
58
|
+
log("webglErrorButton clicked");
|
|
59
|
+
registerWebglErrorListener(page, log);
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
.catch(async (e) => {
|
|
63
|
+
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
64
|
+
log("webglErrorButton.click() failed", e.message);
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
const registerDeprecatedFeatures = (page: Page, log: typeof console.log) => {
|
|
68
|
+
// as soon as it appear, without blocking flow
|
|
69
|
+
// ignore deprecated feature
|
|
70
|
+
const deprecatedFeaturesDialog = page.locator("#deprecatedFeaturesDialog");
|
|
71
|
+
const okButton = deprecatedFeaturesDialog.locator(".okButton");
|
|
72
|
+
okButton
|
|
73
|
+
.waitFor({
|
|
74
|
+
timeout: 0,
|
|
75
|
+
})
|
|
76
|
+
.then(async () => {
|
|
77
|
+
await okButton.click();
|
|
78
|
+
log("okButton clicked");
|
|
79
|
+
registerDeprecatedFeatures(page, log);
|
|
80
|
+
})
|
|
81
|
+
.catch(async (e) => {
|
|
82
|
+
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
83
|
+
log("deprecatedFeatures.okButton.click() failed", e.message);
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
const registerWelcomeToConstructListener = (page: Page, log: typeof console.log) => {
|
|
87
|
+
// as soon as it appear, without blocking flow
|
|
88
|
+
// ignore deprecated feature
|
|
89
|
+
const welcomeTourDialog = page.locator("#welcomeTourDialog");
|
|
90
|
+
const okButton = welcomeTourDialog.locator(".noThanksLink");
|
|
91
|
+
okButton
|
|
92
|
+
.waitFor({
|
|
93
|
+
timeout: 0,
|
|
94
|
+
})
|
|
95
|
+
.then(async () => {
|
|
96
|
+
await okButton.click();
|
|
97
|
+
log("okButton clicked");
|
|
98
|
+
// registerWelcomeToConstructListener(page, log); // usually only once
|
|
99
|
+
})
|
|
100
|
+
.catch(async (e) => {
|
|
101
|
+
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
102
|
+
log("welcomeTour.okButton.click() failed", e.message);
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const registerMissingAddonErrorListener = (page: Page, log: typeof console.log) => {
|
|
107
|
+
// as soon as it appear, without blocking flow
|
|
108
|
+
// ignore missing addon and throw
|
|
109
|
+
const okDialog = page.locator("#missingAddonsDialog");
|
|
110
|
+
const webglErrorButton = okDialog.locator(".okButton");
|
|
111
|
+
webglErrorButton
|
|
112
|
+
.waitFor({
|
|
113
|
+
timeout: 0,
|
|
114
|
+
})
|
|
115
|
+
.then(async () => {
|
|
116
|
+
throw new Error("Missing addon. You should bundle addons with your project");
|
|
117
|
+
})
|
|
118
|
+
.catch(async (e) => {
|
|
119
|
+
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
120
|
+
log("missingAddon.okButton.waitFor() failed", e.message);
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const registerNewVersionAvailableListener = (page: Page, log: typeof console.log) => {
|
|
125
|
+
// as soon as it appear, without blocking flow
|
|
126
|
+
// ignore new version available and throw
|
|
127
|
+
const newVersionAvailableDialog = page.locator("#confirmDialog");
|
|
128
|
+
const cancelButton = newVersionAvailableDialog.locator(".cancelConfirmButton");
|
|
129
|
+
cancelButton
|
|
130
|
+
.waitFor({
|
|
131
|
+
timeout: 0,
|
|
132
|
+
})
|
|
133
|
+
.then(async () => {
|
|
134
|
+
await cancelButton.click();
|
|
135
|
+
log("cancelButton clicked");
|
|
136
|
+
registerNewVersionAvailableListener(page, log);
|
|
137
|
+
})
|
|
138
|
+
.catch(async (e) => {
|
|
139
|
+
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
140
|
+
log("cancelButton.click() failed", e.message);
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const script = async (
|
|
145
|
+
page: Page,
|
|
146
|
+
log: typeof console.log,
|
|
147
|
+
filePath: string,
|
|
148
|
+
username: string | undefined,
|
|
149
|
+
password: string | undefined,
|
|
150
|
+
version: string | undefined,
|
|
151
|
+
downloadDir: string,
|
|
152
|
+
) => {
|
|
153
|
+
let url = "https://editor.construct.net/";
|
|
154
|
+
if (version) {
|
|
155
|
+
url += version;
|
|
156
|
+
}
|
|
157
|
+
log("Navigating to URL", url);
|
|
158
|
+
// const serviceWorkerPromise = page.waitForEvent("serviceworker");
|
|
159
|
+
await page.goto(url);
|
|
160
|
+
log("after navigating");
|
|
161
|
+
|
|
162
|
+
// const serviceworker = await serviceWorkerPromise;
|
|
163
|
+
registerWelcomeToConstructListener(page, log);
|
|
164
|
+
registerNewVersionAvailableListener(page, log);
|
|
165
|
+
|
|
166
|
+
log("after event");
|
|
167
|
+
|
|
168
|
+
await page.waitForTimeout(2000);
|
|
169
|
+
log("after wait");
|
|
170
|
+
|
|
171
|
+
if (username && password) {
|
|
172
|
+
log("Authenticating");
|
|
173
|
+
await page.getByTitle("User account").locator("ui-icon").click();
|
|
174
|
+
await page.getByRole("menuitem", { name: "Log in" }).locator("span").click();
|
|
175
|
+
await page.frameLocator("#loginDialog iframe").getByLabel("Username").fill(username);
|
|
176
|
+
await page.frameLocator("#loginDialog iframe").getByLabel("Password").fill(password);
|
|
177
|
+
|
|
178
|
+
const tokenPromise = page.waitForResponse(/https:\/\/account.*\.construct\.net\/login.json/i);
|
|
179
|
+
|
|
180
|
+
await page.frameLocator("#loginDialog iframe").getByRole("button", { name: "Log in" }).click();
|
|
181
|
+
|
|
182
|
+
const response = await tokenPromise;
|
|
183
|
+
const jsonResponse = await response.json();
|
|
184
|
+
|
|
185
|
+
if (jsonResponse.request.status === "error") {
|
|
186
|
+
await page.close();
|
|
187
|
+
|
|
188
|
+
throw new Error("Invalid credentials");
|
|
189
|
+
}
|
|
190
|
+
log("Authenticated");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
await page.waitForTimeout(2000);
|
|
194
|
+
|
|
195
|
+
const [fileChooser] = await Promise.all([
|
|
196
|
+
page.waitForEvent("filechooser"),
|
|
197
|
+
page.keyboard.press("ControlOrMeta+O"),
|
|
198
|
+
]);
|
|
199
|
+
log("filechooser");
|
|
200
|
+
|
|
201
|
+
console.log("filePath", filePath);
|
|
202
|
+
await fileChooser.setFiles([filePath]);
|
|
203
|
+
log("Set file");
|
|
204
|
+
|
|
205
|
+
// await page.getByText("Not now").click({
|
|
206
|
+
// timeout: 1000
|
|
207
|
+
// });
|
|
208
|
+
|
|
209
|
+
const progressDialog = page.locator("#progressDialog");
|
|
210
|
+
// <progress class="progressBar" value="0.293996941070648" max="1"></progress>
|
|
211
|
+
const progessBar = progressDialog.locator(".progressBar");
|
|
212
|
+
|
|
213
|
+
log("Waiting for progress dialog");
|
|
214
|
+
await progressDialog.waitFor({
|
|
215
|
+
timeout: 0,
|
|
216
|
+
});
|
|
217
|
+
log("Got loading progress dialog");
|
|
218
|
+
|
|
219
|
+
const progressInterval = setInterval(async () => {
|
|
220
|
+
const text = await progessBar.getAttribute("value");
|
|
221
|
+
const textAsNumber = parseFloat(text);
|
|
222
|
+
const finalText = Number.isNaN(textAsNumber) ? 0 : textAsNumber;
|
|
223
|
+
log("progress", `${finalText * 100}%`);
|
|
224
|
+
}, 500);
|
|
225
|
+
|
|
226
|
+
// as soon as it appear, without blocking flow
|
|
227
|
+
// ignore asking for update
|
|
228
|
+
const notNowBtn = page.getByText("Not now");
|
|
229
|
+
notNowBtn
|
|
230
|
+
.waitFor({
|
|
231
|
+
timeout: 0,
|
|
232
|
+
})
|
|
233
|
+
.then(async () => {
|
|
234
|
+
return notNowBtn.click();
|
|
235
|
+
})
|
|
236
|
+
.then(() => {
|
|
237
|
+
log("notNowBtn clicked");
|
|
238
|
+
})
|
|
239
|
+
.catch(async (e) => {
|
|
240
|
+
if (e.message.includes("Target page, context or browser has been closed")) return;
|
|
241
|
+
log("notNowBtn.click() failed", e.message);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
registerInstallButtonListener(page, log);
|
|
245
|
+
registerWebglErrorListener(page, log);
|
|
246
|
+
registerMissingAddonErrorListener(page, log);
|
|
247
|
+
registerDeprecatedFeatures(page, log);
|
|
248
|
+
registerSaveLoginExpiredistener(page, log);
|
|
249
|
+
|
|
250
|
+
log("Waiting for progress dialog to disapear");
|
|
251
|
+
await progressDialog.waitFor({
|
|
252
|
+
state: "detached",
|
|
253
|
+
timeout: 0,
|
|
254
|
+
});
|
|
255
|
+
log("Got progress dialog to disapear");
|
|
256
|
+
clearTimeout(progressInterval);
|
|
257
|
+
|
|
258
|
+
await page.getByRole("button", { name: "Menu" }).click();
|
|
259
|
+
await page.getByRole("menuitem", { name: "Project" }).click();
|
|
260
|
+
await page.getByRole("menuitem", { name: "Export" }).click();
|
|
261
|
+
log('"Export" clicked');
|
|
262
|
+
await page
|
|
263
|
+
.locator("ui-iconviewitem")
|
|
264
|
+
.filter({ hasText: "Web (HTML5)" })
|
|
265
|
+
.locator("ui-icon")
|
|
266
|
+
.click();
|
|
267
|
+
log('"Web" clicked');
|
|
268
|
+
|
|
269
|
+
await page.locator("#exportSelectPlatformDialog").getByRole("button", { name: "Next" }).click();
|
|
270
|
+
|
|
271
|
+
await page.getByLabel("Offline support").uncheck();
|
|
272
|
+
log("Disabled offline support");
|
|
273
|
+
|
|
274
|
+
await page.locator("#exportStandardOptionsDialog").getByRole("button", { name: "Next" }).click();
|
|
275
|
+
log('"Next" clicked');
|
|
276
|
+
const downloadPromise = page.waitForEvent("download");
|
|
277
|
+
await page.locator(".downloadExportedProject").click();
|
|
278
|
+
const download = await downloadPromise;
|
|
279
|
+
await page.getByRole("button", { name: "OK" }).click();
|
|
280
|
+
log('"Download" clicked');
|
|
281
|
+
|
|
282
|
+
const finalPath = join(downloadDir, download.suggestedFilename());
|
|
283
|
+
await download.saveAs(finalPath);
|
|
284
|
+
log("File Downloaded");
|
|
285
|
+
|
|
286
|
+
await page.close();
|
|
287
|
+
return finalPath;
|
|
288
|
+
};
|