system-testing 1.0.34 → 1.0.36

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/index.js ADDED
@@ -0,0 +1,3 @@
1
+ const stub = "Hello world";
2
+ export { stub };
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXguanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsTUFBTSxJQUFJLEdBQUcsYUFBYSxDQUFBO0FBRTFCLE9BQU8sRUFBQyxJQUFJLEVBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHN0dWIgPSBcIkhlbGxvIHdvcmxkXCJcblxuZXhwb3J0IHtzdHVifVxuIl19
@@ -5,10 +5,10 @@ export default class SystemTestBrowserHelper {
5
5
  events: EventEmitter<any>;
6
6
  startScoundrel(): Promise<void>;
7
7
  scoundrelWs: WebSocket;
8
- scoundrelClientWebSocket: any;
9
- scoundrelClient: any;
8
+ scoundrelClientWebSocket: ClientWebSocket;
9
+ scoundrelClient: Client;
10
10
  waitForScoundrelStarted(): Promise<any>;
11
- getScoundrel(): any;
11
+ getScoundrel(): Client;
12
12
  connectOnError(): void;
13
13
  connectUnhandledRejection(): void;
14
14
  /**
@@ -104,3 +104,5 @@ export default class SystemTestBrowserHelper {
104
104
  }
105
105
  import SystemTestCommunicator from "./system-test-communicator.js";
106
106
  import EventEmitter from "events";
107
+ import ClientWebSocket from "scoundrel-remote-eval/build/client/connections/web-socket/index.js";
108
+ import Client from "scoundrel-remote-eval/build/client/index.js";
@@ -0,0 +1,238 @@
1
+ // @ts-check
2
+ import Client from "scoundrel-remote-eval/build/client/index.js";
3
+ import ClientWebSocket from "scoundrel-remote-eval/build/client/connections/web-socket/index.js";
4
+ import { digg } from "diggerize";
5
+ import EventEmitter from "events";
6
+ import SystemTestCommunicator from "./system-test-communicator.js";
7
+ /** @type {{systemTestBrowserHelper: SystemTestBrowserHelper | null}} */
8
+ const shared = {
9
+ systemTestBrowserHelper: null
10
+ };
11
+ export default class SystemTestBrowserHelper {
12
+ static current() {
13
+ if (!shared.systemTestBrowserHelper) {
14
+ throw new Error("No current SystemTestBrowserHelper set");
15
+ }
16
+ return shared.systemTestBrowserHelper;
17
+ }
18
+ constructor() {
19
+ /**
20
+ * @param {any[]} args
21
+ * @returns {void}
22
+ */
23
+ this.fakeConsoleError = (...args) => {
24
+ this.communicator.sendCommand({ type: "console.error", value: this.consoleLogMessage(args) });
25
+ if (this.originalConsoleError) {
26
+ return this.originalConsoleError(...args);
27
+ }
28
+ };
29
+ /**
30
+ * @param {any[]} args
31
+ * @returns {void}
32
+ */
33
+ this.fakeConsoleLog = (...args) => {
34
+ this.communicator.sendCommand({ type: "console.log", value: this.consoleLogMessage(args) });
35
+ if (this.originalConsoleLog) {
36
+ return this.originalConsoleLog(...args);
37
+ }
38
+ };
39
+ /**
40
+ * @param {{data: {path: string, type: string}}} args
41
+ * @returns {Promise<{result: string} | void>}
42
+ */
43
+ this.onCommand = async ({ data }) => {
44
+ if (data.type == "initialize") {
45
+ this.events.emit("initialize");
46
+ if (this._onInitializeCallback) {
47
+ await this._onInitializeCallback();
48
+ }
49
+ return { result: "initialized" };
50
+ }
51
+ else if (data.type == "visit") {
52
+ this.events.emit("navigate", { path: data.path });
53
+ }
54
+ else if (data.type == "dismissTo") {
55
+ this.events.emit("dismissTo", { path: data.path });
56
+ }
57
+ else {
58
+ throw new Error(`Unknown command type for SystemTestBrowserHelper: ${data.type}`);
59
+ }
60
+ };
61
+ this.communicator = new SystemTestCommunicator({ parent: this, onCommand: this.onCommand });
62
+ this._enabled = false;
63
+ this.events = new EventEmitter();
64
+ shared.systemTestBrowserHelper = this;
65
+ this.startScoundrel();
66
+ }
67
+ async startScoundrel() {
68
+ this.scoundrelWs = new WebSocket("http://localhost:8090");
69
+ // @ts-expect-error
70
+ this.scoundrelClientWebSocket = new ClientWebSocket(this.scoundrelWs);
71
+ await this.scoundrelClientWebSocket.waitForOpened();
72
+ this.scoundrelClient = new Client(this.scoundrelClientWebSocket);
73
+ this.events.emit("scoundrelStarted");
74
+ }
75
+ waitForScoundrelStarted() {
76
+ return new Promise((resolve) => {
77
+ if (this.scoundrelClient) {
78
+ resolve(undefined);
79
+ }
80
+ else {
81
+ this.events.once("scoundrelStarted", () => {
82
+ resolve(undefined);
83
+ });
84
+ }
85
+ });
86
+ }
87
+ getScoundrel() {
88
+ if (!this.scoundrelClient) {
89
+ throw new Error("Scoundrel client is not started yet");
90
+ }
91
+ return this.scoundrelClient;
92
+ }
93
+ connectOnError() {
94
+ window.addEventListener("error", (event) => {
95
+ this.handleError({
96
+ type: "error",
97
+ error: event.error,
98
+ errorClass: event.error?.name,
99
+ file: event.filename,
100
+ line: event.lineno,
101
+ message: event.message || "Unknown error",
102
+ url: window.location.href
103
+ });
104
+ });
105
+ }
106
+ connectUnhandledRejection() {
107
+ window.addEventListener("unhandledrejection", (event) => {
108
+ this.handleError({
109
+ type: "unhandledrejection",
110
+ error: event.reason,
111
+ errorClass: "UnhandledRejection",
112
+ message: event.reason.message || event.reason || "Unhandled promise rejection without a message",
113
+ url: window.location.href
114
+ });
115
+ });
116
+ }
117
+ /**
118
+ * @param {object} data
119
+ * @param {string} [data.backtrace]
120
+ * @param {Error} [data.error]
121
+ * @param {string} [data.errorClass]
122
+ * @param {string} [data.file]
123
+ * @param {number} [data.line]
124
+ * @param {string} [data.message]
125
+ * @param {string} [data.type]
126
+ * @param {string} [data.url]
127
+ * @returns {void}
128
+ */
129
+ handleError(data) {
130
+ let backtrace;
131
+ if (data.error && data.error.stack) {
132
+ backtrace = data.error.stack.split("\n");
133
+ backtrace.shift();
134
+ backtrace = backtrace.join("\n");
135
+ }
136
+ else if (data.file) {
137
+ backtrace = `${data.file}:${data.line}`;
138
+ }
139
+ data.backtrace = backtrace;
140
+ this.communicator.sendCommand(data);
141
+ }
142
+ /**
143
+ * @returns {void}
144
+ */
145
+ connectWebSocket() {
146
+ this.ws = new WebSocket("ws://localhost:1985");
147
+ this.communicator.ws = this.ws;
148
+ this.ws.addEventListener("error", digg(this, "communicator", "onError"));
149
+ this.ws.addEventListener("open", digg(this, "communicator", "onOpen"));
150
+ this.ws.addEventListener("message", (event) => this.communicator.onMessage(event.data));
151
+ }
152
+ /**
153
+ * @returns {void}
154
+ */
155
+ enableOnBrowser() {
156
+ this._enabled = true;
157
+ this.connectWebSocket();
158
+ this.connectOnError();
159
+ this.connectUnhandledRejection();
160
+ this.overrideConsoleLog();
161
+ }
162
+ /**
163
+ * @returns {boolean}
164
+ */
165
+ getEnabled() { return this._enabled; }
166
+ /**
167
+ * @returns {EventEmitter}
168
+ */
169
+ getEvents() { return this.events; }
170
+ /**
171
+ * @param {any} arg
172
+ * @param {any[]} [scannedObjects]
173
+ * @returns {any}
174
+ */
175
+ consoleLogMessage(arg, scannedObjects = []) {
176
+ if (Array.isArray(arg)) {
177
+ if (scannedObjects.includes(arg)) {
178
+ return "[recursive]";
179
+ }
180
+ else {
181
+ scannedObjects.push(arg);
182
+ }
183
+ const result = [];
184
+ for (const value of arg) {
185
+ result.push(this.consoleLogMessage(value, scannedObjects));
186
+ }
187
+ return result;
188
+ }
189
+ else if (Object.prototype.toString.call(arg) === '[object Object]') {
190
+ if (scannedObjects.includes(arg)) {
191
+ return "[recursive]";
192
+ }
193
+ else {
194
+ scannedObjects.push(arg);
195
+ }
196
+ /** @type {Record<string, any>} */
197
+ const result = {};
198
+ for (const key in arg) {
199
+ result[key] = this.consoleLogMessage(arg[key], scannedObjects);
200
+ }
201
+ return result;
202
+ }
203
+ else if (typeof arg == "object") {
204
+ return `[object ${arg?.constructor?.name}]`;
205
+ }
206
+ else {
207
+ return arg;
208
+ }
209
+ }
210
+ /**
211
+ * @param {function() : void} callback
212
+ * @returns {void}
213
+ */
214
+ onInitialize(callback) {
215
+ this._onInitializeCallback = callback;
216
+ }
217
+ /**
218
+ * @returns {void}
219
+ */
220
+ overrideConsoleLog() {
221
+ if (this.originalConsoleError || this.originalConsoleLog) {
222
+ throw new Error("Console methods has already been overridden!");
223
+ }
224
+ this.originalConsoleError = console.error;
225
+ this.originalConsoleLog = console.log;
226
+ console.error = this.fakeConsoleError;
227
+ console.log = this.fakeConsoleLog;
228
+ }
229
+ /**
230
+ * @param {string} sql
231
+ * @returns {Promise<Array<Record<string, any>>>}
232
+ */
233
+ async sendQuery(sql) {
234
+ // @ts-expect-error
235
+ return await this.communicator.sendCommand({ type: "query", sql });
236
+ }
237
+ }
238
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3lzdGVtLXRlc3QtYnJvd3Nlci1oZWxwZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc3lzdGVtLXRlc3QtYnJvd3Nlci1oZWxwZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sTUFBTSxNQUFNLDZDQUE2QyxDQUFBO0FBQ2hFLE9BQU8sZUFBZSxNQUFNLG9FQUFvRSxDQUFBO0FBQ2hHLE9BQU8sRUFBQyxJQUFJLEVBQUMsTUFBTSxXQUFXLENBQUE7QUFDOUIsT0FBTyxZQUFZLE1BQU0sUUFBUSxDQUFBO0FBRWpDLE9BQU8sc0JBQXNCLE1BQU0sK0JBQStCLENBQUE7QUFFbEUsd0VBQXdFO0FBQ3hFLE1BQU0sTUFBTSxHQUFHO0lBQ2IsdUJBQXVCLEVBQUUsSUFBSTtDQUM5QixDQUFBO0FBRUQsTUFBTSxDQUFDLE9BQU8sT0FBTyx1QkFBdUI7SUFDMUMsTUFBTSxDQUFDLE9BQU87UUFDWixJQUFJLENBQUMsTUFBTSxDQUFDLHVCQUF1QixFQUFFLENBQUM7WUFDcEMsTUFBTSxJQUFJLEtBQUssQ0FBQyx3Q0FBd0MsQ0FBQyxDQUFBO1FBQzNELENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQyx1QkFBdUIsQ0FBQTtJQUN2QyxDQUFDO0lBRUQ7UUFnSUE7OztXQUdHO1FBQ0gscUJBQWdCLEdBQUcsQ0FBQyxHQUFHLElBQUksRUFBRSxFQUFFO1lBQzdCLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLEVBQUMsSUFBSSxFQUFFLGVBQWUsRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsQ0FBQTtZQUUzRixJQUFJLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO2dCQUM5QixPQUFPLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFBO1lBQzNDLENBQUM7UUFDSCxDQUFDLENBQUE7UUFFRDs7O1dBR0c7UUFDSCxtQkFB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ckMsT0FBTyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUE7UUFDckMsT0FBTyxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFBO0lBQ25DLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsU0FBUyxDQUFDLEdBQUc7UUFDakIsbUJBQW1CO1FBQ25CLE9BQU8sTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxFQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQTtJQUNsRSxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IENsaWVudCBmcm9tIFwic2NvdW5kcmVsLXJlbW90ZS1ldmFsL2J1aWxkL2NsaWVudC9pbmRleC5qc1wiXG5pbXBvcnQgQ2xpZW50V2ViU29ja2V0IGZyb20gXCJzY291bmRyZWwtcmVtb3RlLWV2YWwvYnVpbGQvY2xpZW50L2Nvbm5lY3Rpb25zL3dlYi1zb2NrZXQvaW5kZXguanNcIlxuaW1wb3J0IHtkaWdnfSBmcm9tIFwiZGlnZ2VyaXplXCJcbmltcG9ydCBFdmVudEVtaXR0ZXIgZnJvbSBcImV2ZW50c1wiXG5cbmltcG9ydCBTeXN0ZW1UZXN0Q29tbXVuaWNhdG9yIGZyb20gXCIuL3N5c3RlbS10ZXN0LWNvbW11bmljYXRvci5qc1wiXG5cbi8qKiBAdHlwZSB7e3N5c3RlbVRlc3RCcm93c2VySGVscGVyOiBTeXN0ZW1UZXN0QnJvd3NlckhlbHBlciB8IG51bGx9fSAqL1xuY29uc3Qgc2hhcmVkID0ge1xuICBzeXN0ZW1UZXN0QnJvd3NlckhlbHBlcjogbnVsbFxufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTeXN0ZW1UZXN0QnJvd3NlckhlbHBlciB7XG4gIHN0YXRpYyBjdXJyZW50KCkge1xuICAgIGlmICghc2hhcmVkLnN5c3RlbVRlc3RCcm93c2VySGVscGVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyBjdXJyZW50IFN5c3RlbVRlc3RCcm93c2VySGVscGVyIHNldFwiKVxuICAgIH1cblxuICAgIHJldHVybiBzaGFyZWQuc3lzdGVtVGVzdEJyb3dzZXJIZWxwZXJcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMuY29tbXVuaWNhdG9yID0gbmV3IFN5c3RlbVRlc3RDb21tdW5pY2F0b3Ioe3BhcmVudDogdGhpcywgb25Db21tYW5kOiB0aGlzLm9uQ29tbWFuZH0pXG4gICAgdGhpcy5fZW5hYmxlZCA9IGZhbHNlXG4gICAgdGhpcy5ldmVudHMgPSBuZXcgRXZlbnRFbWl0dGVyKClcblxuICAgIHNoYXJlZC5zeXN0ZW1UZXN0QnJvd3NlckhlbHBlciA9IHRoaXNcblxuICAgIHRoaXMuc3RhcnRTY291bmRyZWwoKVxuICB9XG5cbiAgYXN5bmMgc3RhcnRTY291bmRyZWwoKSB7XG4gICAgdGhpcy5zY291bmRyZWxXcyA9IG5ldyBXZWJTb2NrZXQoXCJodHRwOi8vbG9jYWxob3N0OjgwOTBcIilcblxuICAgIC8vIEB0cy1leHBlY3QtZXJyb3JcbiAgICB0aGlzLnNjb3VuZHJlbENsaWVudFdlYlNvY2tldCA9IG5ldyBDbGllbnRXZWJTb2NrZXQodGhpcy5zY291bmRyZWxXcylcblxuICAgIGF3YWl0IHRoaXMuc2NvdW5kcmVsQ2xpZW50V2ViU29ja2V0LndhaXRGb3JPcGVuZWQoKVxuXG4gICAgdGhpcy5zY291bmRyZWxDbGllbnQgPSBuZXcgQ2xpZW50KHRoaXMuc2NvdW5kcmVsQ2xpZW50V2ViU29ja2V0KVxuICAgIHRoaXMuZXZlbnRzLmVtaXQoXCJzY291bmRyZWxTdGFydGVkXCIpXG4gIH1cblxuICB3YWl0Rm9yU2NvdW5kcmVsU3RhcnRlZCgpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIGlmICh0aGlzLnNjb3VuZHJlbENsaWVudCkge1xuICAgICAgICByZXNvbHZlKHVuZGVmaW5lZClcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuZXZlbnRzLm9uY2UoXCJzY291bmRyZWxTdGFydGVkXCIsICgpID0+IHtcbiAgICAgICAgICByZXNvbHZlKHVuZGVmaW5lZClcbiAgICAgICAgfSlcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgZ2V0U2NvdW5kcmVsKCkge1xuICAgIGlmICghdGhpcy5zY291bmRyZWxDbGllbnQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlNjb3VuZHJlbCBjbGllbnQgaXMgbm90IHN0YXJ0ZWQgeWV0XCIpXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuc2NvdW5kcmVsQ2xpZW50XG4gIH1cblxuICBjb25uZWN0T25FcnJvcigpIHtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcImVycm9yXCIsIChldmVudCkgPT4ge1xuICAgICAgdGhpcy5oYW5kbGVFcnJvcih7XG4gICAgICAgIHR5cGU6IFwiZXJyb3JcIixcbiAgICAgICAgZXJyb3I6IGV2ZW50LmVycm9yLFxuICAgICAgICBlcnJvckNsYXNzOiBldmVudC5lcnJvcj8ubmFtZSxcbiAgICAgICAgZmlsZTogZXZlbnQuZmlsZW5hbWUsXG4gICAgICAgIGxpbmU6IGV2ZW50LmxpbmVubyxcbiAgICAgICAgbWVzc2FnZTogZXZlbnQubWVzc2FnZSB8fCBcIlVua25vd24gZXJyb3JcIixcbiAgICAgICAgdXJsOiB3aW5kb3cubG9jYXRpb24uaHJlZlxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgY29ubmVjdFVuaGFuZGxlZFJlamVjdGlvbigpIHtcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInVuaGFuZGxlZHJlamVjdGlvblwiLCAoZXZlbnQpID0+IHtcbiAgICAgIHRoaXMuaGFuZGxlRXJyb3Ioe1xuICAgICAgICB0eXBlOiBcInVuaGFuZGxlZHJlamVjdGlvblwiLFxuICAgICAgICBlcnJvcjogZXZlbnQucmVhc29uLFxuICAgICAgICBlcnJvckNsYXNzOiBcIlVuaGFuZGxlZFJlamVjdGlvblwiLFxuICAgICAgICBtZXNzYWdlOiBldmVudC5yZWFzb24ubWVzc2FnZSB8fCBldmVudC5yZWFzb24gfHwgXCJVbmhhbmRsZWQgcHJvbWlzZSByZWplY3Rpb24gd2l0aG91dCBhIG1lc3NhZ2VcIixcbiAgICAgICAgdXJsOiB3aW5kb3cubG9jYXRpb24uaHJlZlxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBkYXRhXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbZGF0YS5iYWNrdHJhY2VdXG4gICAqIEBwYXJhbSB7RXJyb3J9IFtkYXRhLmVycm9yXVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2RhdGEuZXJyb3JDbGFzc11cbiAgICogQHBhcmFtIHtzdHJpbmd9IFtkYXRhLmZpbGVdXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbZGF0YS5saW5lXVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2RhdGEubWVzc2FnZV1cbiAgICogQHBhcmFtIHtzdHJpbmd9IFtkYXRhLnR5cGVdXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbZGF0YS51cmxdXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgaGFuZGxlRXJyb3IoZGF0YSkge1xuICAgIGxldCBiYWNrdHJhY2VcblxuICAgIGlmIChkYXRhLmVycm9yICYmIGRhdGEuZXJyb3Iuc3RhY2spIHtcbiAgICAgIGJhY2t0cmFjZSA9IGRhdGEuZXJyb3Iuc3RhY2suc3BsaXQoXCJcXG5cIilcbiAgICAgIGJhY2t0cmFjZS5zaGlmdCgpXG4gICAgICBiYWNrdHJhY2UgPSBiYWNrdHJhY2Uuam9pbihcIlxcblwiKVxuICAgIH0gZWxzZSBpZiAoZGF0YS5maWxlKSB7XG4gICAgICBiYWNrdHJhY2UgPSBgJHtkYXRhLmZpbGV9OiR7ZGF0YS5saW5lfWBcbiAgICB9XG5cbiAgICBkYXRhLmJhY2t0cmFjZSA9IGJhY2t0cmFjZVxuXG4gICAgdGhpcy5jb21tdW5pY2F0b3Iuc2VuZENvbW1hbmQoZGF0YSlcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIGNvbm5lY3RXZWJTb2NrZXQoKSB7XG4gICAgdGhpcy53cyA9IG5ldyBXZWJTb2NrZXQoXCJ3czovL2xvY2FsaG9zdDoxOTg1XCIpXG4gICAgdGhpcy5jb21tdW5pY2F0b3Iud3MgPSB0aGlzLndzXG4gICAgdGhpcy53cy5hZGRFdmVudExpc3RlbmVyKFwiZXJyb3JcIiwgZGlnZyh0aGlzLCBcImNvbW11bmljYXRvclwiLCBcIm9uRXJyb3JcIikpXG4gICAgdGhpcy53cy5hZGRFdmVudExpc3RlbmVyKFwib3BlblwiLCBkaWdnKHRoaXMsIFwiY29tbXVuaWNhdG9yXCIsIFwib25PcGVuXCIpKVxuICAgIHRoaXMud3MuYWRkRXZlbnRMaXN0ZW5lcihcIm1lc3NhZ2VcIiwgKGV2ZW50KSA9PiB0aGlzLmNvbW11bmljYXRvci5vbk1lc3NhZ2UoZXZlbnQuZGF0YSkpXG4gIH1cblxuICAvKipcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqL1xuICBlbmFibGVPbkJyb3dzZXIoKSB7XG4gICAgdGhpcy5fZW5hYmxlZCA9IHRydWVcbiAgICB0aGlzLmNvbm5lY3RXZWJTb2NrZXQoKVxuICAgIHRoaXMuY29ubmVjdE9uRXJyb3IoKVxuICAgIHRoaXMuY29ubmVjdFVuaGFuZGxlZFJlamVjdGlvbigpXG4gICAgdGhpcy5vdmVycmlkZUNvbnNvbGVMb2coKVxuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgKi9cbiAgZ2V0RW5hYmxlZCgpIHsgcmV0dXJuIHRoaXMuX2VuYWJsZWQgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJucyB7RXZlbnRFbWl0dGVyfVxuICAgKi9cbiAgZ2V0RXZlbnRzKCkgeyByZXR1cm4gdGhpcy5ldmVudHMgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge2FueVtdfSBhcmdzXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgZmFrZUNvbnNvbGVFcnJvciA9ICguLi5hcmdzKSA9PiB7XG4gICAgdGhpcy5jb21tdW5pY2F0b3Iuc2VuZENvbW1hbmQoe3R5cGU6IFwiY29uc29sZS5lcnJvclwiLCB2YWx1ZTogdGhpcy5jb25zb2xlTG9nTWVzc2FnZShhcmdzKX0pXG5cbiAgICBpZiAodGhpcy5vcmlnaW5hbENvbnNvbGVFcnJvcikge1xuICAgICAgcmV0dXJuIHRoaXMub3JpZ2luYWxDb25zb2xlRXJyb3IoLi4uYXJncylcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHthbnlbXX0gYXJnc1xuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIGZha2VDb25zb2xlTG9nID0gKC4uLmFyZ3MpID0+IHtcbiAgICB0aGlzLmNvbW11bmljYXRvci5zZW5kQ29tbWFuZCh7dHlwZTogXCJjb25zb2xlLmxvZ1wiLCB2YWx1ZTogdGhpcy5jb25zb2xlTG9nTWVzc2FnZShhcmdzKX0pXG5cbiAgICBpZiAodGhpcy5vcmlnaW5hbENvbnNvbGVMb2cpIHtcbiAgICAgIHJldHVybiB0aGlzLm9yaWdpbmFsQ29uc29sZUxvZyguLi5hcmdzKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge2FueX0gYXJnXG4gICAqIEBwYXJhbSB7YW55W119IFtzY2FubmVkT2JqZWN0c11cbiAgICogQHJldHVybnMge2FueX1cbiAgICovXG4gIGNvbnNvbGVMb2dNZXNzYWdlKGFyZywgc2Nhbm5lZE9iamVjdHMgPSBbXSkge1xuICAgIGlmIChBcnJheS5pc0FycmF5KGFyZykpIHtcbiAgICAgIGlmIChzY2FubmVkT2JqZWN0cy5pbmNsdWRlcyhhcmcpKSB7XG4gICAgICAgIHJldHVybiBcIltyZWN1cnNpdmVdXCJcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNjYW5uZWRPYmplY3RzLnB1c2goYXJnKVxuICAgICAgfVxuXG4gICAgICBjb25zdCByZXN1bHQgPSBbXVxuXG4gICAgICBmb3IgKGNvbnN0IHZhbHVlIG9mIGFyZykge1xuICAgICAgICByZXN1bHQucHVzaCh0aGlzLmNvbnNvbGVMb2dNZXNzYWdlKHZhbHVlLCBzY2FubmVkT2JqZWN0cykpXG4gICAgICB9XG5cbiAgICAgIHJldHVybiByZXN1bHRcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChhcmcpID09PSAnW29iamVjdCBPYmplY3RdJykge1xuICAgICAgaWYgKHNjYW5uZWRPYmplY3RzLmluY2x1ZGVzKGFyZykpIHtcbiAgICAgICAgcmV0dXJuIFwiW3JlY3Vyc2l2ZV1cIlxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2Nhbm5lZE9iamVjdHMucHVzaChhcmcpXG4gICAgICB9XG5cbiAgICAgIC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZywgYW55Pn0gKi9cbiAgICAgIGNvbnN0IHJlc3VsdCA9IHt9XG5cbiAgICAgIGZvciAoY29uc3Qga2V5IGluIGFyZykge1xuICAgICAgICByZXN1bHRba2V5XSA9IHRoaXMuY29uc29sZUxvZ01lc3NhZ2UoYXJnW2tleV0sIHNjYW5uZWRPYmplY3RzKVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gcmVzdWx0XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgYXJnID09IFwib2JqZWN0XCIpIHtcbiAgICAgIHJldHVybiBgW29iamVjdCAke2FyZz8uY29uc3RydWN0b3I/Lm5hbWV9XWBcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGFyZ1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3tkYXRhOiB7cGF0aDogc3RyaW5nLCB0eXBlOiBzdHJpbmd9fX0gYXJnc1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx7cmVzdWx0OiBzdHJpbmd9IHwgdm9pZD59XG4gICAqL1xuICBvbkNvbW1hbmQgPSBhc3luYyAoe2RhdGF9KSA9PiB7XG4gICAgaWYgKGRhdGEudHlwZSA9PSBcImluaXRpYWxpemVcIikge1xuICAgICAgdGhpcy5ldmVudHMuZW1pdChcImluaXRpYWxpemVcIilcblxuICAgICAgaWYgKHRoaXMuX29uSW5pdGlhbGl6ZUNhbGxiYWNrKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX29uSW5pdGlhbGl6ZUNhbGxiYWNrKClcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtyZXN1bHQ6IFwiaW5pdGlhbGl6ZWRcIn1cbiAgICB9IGVsc2UgaWYgKGRhdGEudHlwZSA9PSBcInZpc2l0XCIpIHtcbiAgICAgIHRoaXMuZXZlbnRzLmVtaXQoXCJuYXZpZ2F0ZVwiLCB7cGF0aDogZGF0YS5wYXRofSlcbiAgICB9IGVsc2UgaWYgKGRhdGEudHlwZSA9PSBcImRpc21pc3NUb1wiKSB7XG4gICAgICB0aGlzLmV2ZW50cy5lbWl0KFwiZGlzbWlzc1RvXCIsIHtwYXRoOiBkYXRhLnBhdGh9KVxuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gY29tbWFuZCB0eXBlIGZvciBTeXN0ZW1UZXN0QnJvd3NlckhlbHBlcjogJHtkYXRhLnR5cGV9YClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtmdW5jdGlvbigpIDogdm9pZH0gY2FsbGJhY2tcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqL1xuICBvbkluaXRpYWxpemUoY2FsbGJhY2spIHtcbiAgICB0aGlzLl9vbkluaXRpYWxpemVDYWxsYmFjayA9IGNhbGxiYWNrXG4gIH1cblxuICAvKipcbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqL1xuICBvdmVycmlkZUNvbnNvbGVMb2coKSB7XG4gICAgaWYgKHRoaXMub3JpZ2luYWxDb25zb2xlRXJyb3IgfHwgdGhpcy5vcmlnaW5hbENvbnNvbGVMb2cpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkNvbnNvbGUgbWV0aG9kcyBoYXMgYWxyZWFkeSBiZWVuIG92ZXJyaWRkZW4hXCIpXG4gICAgfVxuXG4gICAgdGhpcy5vcmlnaW5hbENvbnNvbGVFcnJvciA9IGNvbnNvbGUuZXJyb3JcbiAgICB0aGlzLm9yaWdpbmFsQ29uc29sZUxvZyA9IGNvbnNvbGUubG9nXG5cbiAgICBjb25zb2xlLmVycm9yID0gdGhpcy5mYWtlQ29uc29sZUVycm9yXG4gICAgY29uc29sZS5sb2cgPSB0aGlzLmZha2VDb25zb2xlTG9nXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNxbFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pj59XG4gICAqL1xuICBhc3luYyBzZW5kUXVlcnkoc3FsKSB7XG4gICAgLy8gQHRzLWV4cGVjdC1lcnJvclxuICAgIHJldHVybiBhd2FpdCB0aGlzLmNvbW11bmljYXRvci5zZW5kQ29tbWFuZCh7dHlwZTogXCJxdWVyeVwiLCBzcWx9KVxuICB9XG59XG4iXX0=
@@ -0,0 +1,105 @@
1
+ // @ts-check
2
+ export default class SystemTestCommunicator {
3
+ /**
4
+ * @param {object} args
5
+ * @param {(args: Record<string, any>) => Promise<{result: string} | void>} args.onCommand
6
+ * @param {object} [args.parent]
7
+ */
8
+ constructor({ onCommand, parent }) {
9
+ /** @type {Record<string, {resolve: (data: any) => void, reject: (data: any) => void}>} */
10
+ this._responses = {};
11
+ /** @type {Record<string, any>} */
12
+ this._sendQueue = [];
13
+ this._sendQueueCount = 0;
14
+ /** @type {WebSocket | null} */
15
+ this.ws = null;
16
+ /** @param {Error} error */
17
+ this.onError = (error) => {
18
+ console.error("onWebSocketClientError", error);
19
+ };
20
+ /** @param {string} rawData */
21
+ this.onMessage = async (rawData) => {
22
+ /** @type {{data: any, id: number, type: string, isTrusted?: boolean}} */
23
+ const data = JSON.parse(rawData);
24
+ if (data.isTrusted) {
25
+ // Ignore
26
+ }
27
+ else if (data.type == "command") {
28
+ try {
29
+ const result = await this.onCommand({ data: data.data });
30
+ this.respond(data.id, { result });
31
+ }
32
+ catch (error) {
33
+ if (error instanceof Error) {
34
+ this.respond(data.id, { error: error.message });
35
+ }
36
+ else {
37
+ this.respond(data.id, { error: error });
38
+ }
39
+ }
40
+ }
41
+ else if (data.type == "response") {
42
+ const response = this._responses[data.id];
43
+ if (!response) {
44
+ throw new Error(`No such response: ${data.id}`);
45
+ }
46
+ delete this._responses[data.id];
47
+ if (data.data.error) {
48
+ response.reject(data.data.error);
49
+ }
50
+ else {
51
+ response.resolve(data.data.result);
52
+ }
53
+ }
54
+ else {
55
+ throw new Error(`Unknown type for SystemTestCommunicator: ${data.type}: ${JSON.stringify(data)}`);
56
+ }
57
+ };
58
+ this.onOpen = () => {
59
+ this.flushSendQueue();
60
+ };
61
+ this.onCommand = onCommand;
62
+ this.parent = parent;
63
+ }
64
+ flushSendQueue() {
65
+ while (this._sendQueue.length !== 0) {
66
+ const data = this._sendQueue.shift();
67
+ if (!this.ws || this.ws.readyState !== 1) {
68
+ throw new Error("WebSocket is not open");
69
+ }
70
+ this.ws.send(JSON.stringify(data));
71
+ }
72
+ }
73
+ /**
74
+ * @param {Record<string, any>} data
75
+ * @returns {void}
76
+ */
77
+ send(data) {
78
+ this._sendQueue.push(data);
79
+ if (this.ws.readyState == 1) {
80
+ this.flushSendQueue();
81
+ }
82
+ }
83
+ /**
84
+ * Sends a command and returns a promise that resolves with the response.
85
+ * @param {Record<string, any>} data - The command data to send.
86
+ * @returns {Promise<void>} A promise that resolves with the response data.
87
+ */
88
+ sendCommand(data) {
89
+ return new Promise((resolve, reject) => {
90
+ const id = this._sendQueueCount;
91
+ this._sendQueueCount += 1;
92
+ this._responses[id] = { resolve, reject };
93
+ this.send({ type: "command", id, data });
94
+ });
95
+ }
96
+ /**
97
+ * @param {number} id
98
+ * @param {Record<string, any>} data
99
+ * @returns {void}
100
+ */
101
+ respond(id, data) {
102
+ this.send({ type: "response", id, data });
103
+ }
104
+ }
105
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3lzdGVtLXRlc3QtY29tbXVuaWNhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3N5c3RlbS10ZXN0LWNvbW11bmljYXRvci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosTUFBTSxDQUFDLE9BQU8sT0FBTyxzQkFBc0I7SUFZekM7Ozs7T0FJRztJQUNILFlBQVksRUFBQyxTQUFTLEVBQUUsTUFBTSxFQUFDO1FBaEIvQiwwRkFBMEY7UUFDMUYsZUFBVSxHQUFHLEVBQUUsQ0FBQTtRQUVmLGtDQUFrQztRQUNsQyxlQUFVLEdBQUcsRUFBRSxDQUFBO1FBRWYsb0JBQWUsR0FBRyxDQUFDLENBQUE7UUFFbkIsK0JBQStCO1FBQy9CLE9BQUUsR0FBRyxJQUFJLENBQUE7UUF3QlQsMkJBQTJCO1FBQzNCLFlBQU8sR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQ2xCLE9BQU8sQ0FBQyxLQUFLLENBQUMsd0JBQXdCLEVBQUUsS0FBSyxDQUFDLENBQUE7UUFDaEQsQ0FBQyxDQUFBO1FBRUQsOEJBQThCO1FBQzlCLGNBQVMsR0FBRyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7WUFDNUIseUVBQXlFO1lBQ3pFLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7WUFFaEMsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ25CLFNBQVM7WUFDWCxDQUFDO2lCQUFNLElBQUksSUFBSSxDQUFDLElBQUksSUFBSSxTQUFTLEVBQUUsQ0FBQztnQkFDbEMsSUFBSSxDQUFDO29CQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQTtvQkFFdEQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQTtnQkFD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QUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUMsQ0FBQTtZQUV2QyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUMsSUFBSSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFDLENBQUMsQ0FBQTtRQUN4QyxDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsT0FBTyxDQUFDLEVBQUUsRUFBRSxJQUFJO1FBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFDLElBQUksRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBQyxDQUFDLENBQUE7SUFDekMsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFN5c3RlbVRlc3RDb21tdW5pY2F0b3Ige1xuICAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsIHtyZXNvbHZlOiAoZGF0YTogYW55KSA9PiB2b2lkLCByZWplY3Q6IChkYXRhOiBhbnkpID0+IHZvaWR9Pn0gKi9cbiAgX3Jlc3BvbnNlcyA9IHt9XG5cbiAgLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSAqL1xuICBfc2VuZFF1ZXVlID0gW11cblxuICBfc2VuZFF1ZXVlQ291bnQgPSAwXG5cbiAgLyoqIEB0eXBlIHtXZWJTb2NrZXQgfCBudWxsfSAqL1xuICB3cyA9IG51bGxcblxuICAvKipcbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3NcbiAgICogQHBhcmFtIHsoYXJnczogUmVjb3JkPHN0cmluZywgYW55PikgPT4gUHJvbWlzZTx7cmVzdWx0OiBzdHJpbmd9IHwgdm9pZD59IGFyZ3Mub25Db21tYW5kXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBbYXJncy5wYXJlbnRdXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7b25Db21tYW5kLCBwYXJlbnR9KSB7XG4gICAgdGhpcy5vbkNvbW1hbmQgPSBvbkNvbW1hbmRcbiAgICB0aGlzLnBhcmVudCA9IHBhcmVudFxuICB9XG5cbiAgZmx1c2hTZW5kUXVldWUoKSB7XG4gICAgd2hpbGUgKHRoaXMuX3NlbmRRdWV1ZS5sZW5ndGggIT09IDApIHtcbiAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLl9zZW5kUXVldWUuc2hpZnQoKVxuXG4gICAgICBpZiAoIXRoaXMud3MgfHwgdGhpcy53cy5yZWFkeVN0YXRlICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIldlYlNvY2tldCBpcyBub3Qgb3BlblwiKVxuICAgICAgfVxuXG4gICAgICB0aGlzLndzLnNlbmQoSlNPTi5zdHJpbmdpZnkoZGF0YSkpXG4gICAgfVxuICB9XG5cbiAgLyoqIEBwYXJhbSB7RXJyb3J9IGVycm9yICovXG4gIG9uRXJyb3IgPSAoZXJyb3IpID0+IHtcbiAgICBjb25zb2xlLmVycm9yKFwib25XZWJTb2NrZXRDbGllbnRFcnJvclwiLCBlcnJvcilcbiAgfVxuXG4gIC8qKiBAcGFyYW0ge3N0cmluZ30gcmF3RGF0YSAqL1xuICBvbk1lc3NhZ2UgPSBhc3luYyAocmF3RGF0YSkgPT4ge1xuICAgIC8qKiBAdHlwZSB7e2RhdGE6IGFueSwgaWQ6IG51bWJlciwgdHlwZTogc3RyaW5nLCBpc1RydXN0ZWQ/OiBib29sZWFufX0gKi9cbiAgICBjb25zdCBkYXRhID0gSlNPTi5wYXJzZShyYXdEYXRhKVxuXG4gICAgaWYgKGRhdGEuaXNUcnVzdGVkKSB7XG4gICAgICAvLyBJZ25vcmVcbiAgICB9IGVsc2UgaWYgKGRhdGEudHlwZSA9PSBcImNvbW1hbmRcIikge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5vbkNvbW1hbmQoe2RhdGE6IGRhdGEuZGF0YX0pXG5cbiAgICAgICAgdGhpcy5yZXNwb25kKGRhdGEuaWQsIHtyZXN1bHR9KVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICB0aGlzLnJlc3BvbmQoZGF0YS5pZCwge2Vycm9yOiBlcnJvci5tZXNzYWdlfSlcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnJlc3BvbmQoZGF0YS5pZCwge2Vycm9yOiBlcnJvcn0pXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGRhdGEudHlwZSA9PSBcInJlc3BvbnNlXCIpIHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gdGhpcy5fcmVzcG9uc2VzW2RhdGEuaWRdXG5cbiAgICAgIGlmICghcmVzcG9uc2UpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyBzdWNoIHJlc3BvbnNlOiAke2RhdGEuaWR9YClcbiAgICAgIH1cblxuICAgICAgZGVsZXRlIHRoaXMuX3Jlc3BvbnNlc1tkYXRhLmlkXVxuXG4gICAgICBpZiAoZGF0YS5kYXRhLmVycm9yKSB7XG4gICAgICAgIHJlc3BvbnNlLnJlamVjdChkYXRhLmRhdGEuZXJyb3IpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXNwb25zZS5yZXNvbHZlKGRhdGEuZGF0YS5yZXN1bHQpXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biB0eXBlIGZvciBTeXN0ZW1UZXN0Q29tbXVuaWNhdG9yOiAke2RhdGEudHlwZX06ICR7SlNPTi5zdHJpbmdpZnkoZGF0YSl9YClcbiAgICB9XG4gIH1cblxuICBvbk9wZW4gPSAoKSA9PiB7XG4gICAgdGhpcy5mbHVzaFNlbmRRdWV1ZSgpXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSBkYXRhXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgc2VuZChkYXRhKSB7XG4gICAgdGhpcy5fc2VuZFF1ZXVlLnB1c2goZGF0YSlcblxuICAgIGlmICh0aGlzLndzLnJlYWR5U3RhdGUgPT0gMSkge1xuICAgICAgdGhpcy5mbHVzaFNlbmRRdWV1ZSgpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNlbmRzIGEgY29tbWFuZCBhbmQgcmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXNwb25zZS5cbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSBkYXRhIC0gVGhlIGNvbW1hbmQgZGF0YSB0byBzZW5kLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcmVzcG9uc2UgZGF0YS5cbiAgICovXG4gIHNlbmRDb21tYW5kKGRhdGEpIHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgaWQgPSB0aGlzLl9zZW5kUXVldWVDb3VudFxuXG4gICAgICB0aGlzLl9zZW5kUXVldWVDb3VudCArPSAxXG4gICAgICB0aGlzLl9yZXNwb25zZXNbaWRdID0ge3Jlc29sdmUsIHJlamVjdH1cblxuICAgICAgdGhpcy5zZW5kKHt0eXBlOiBcImNvbW1hbmRcIiwgaWQsIGRhdGF9KVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtudW1iZXJ9IGlkXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gZGF0YVxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIHJlc3BvbmQoaWQsIGRhdGEpIHtcbiAgICB0aGlzLnNlbmQoe3R5cGU6IFwicmVzcG9uc2VcIiwgaWQsIGRhdGF9KVxuICB9XG59XG4iXX0=
@@ -0,0 +1,66 @@
1
+ // @ts-check
2
+ import fs from "node:fs/promises";
3
+ import http from "node:http";
4
+ import mime from "mime";
5
+ import url from "url";
6
+ export default class SystemTestHttpServer {
7
+ constructor() {
8
+ /**
9
+ * @param {http.IncomingMessage} request
10
+ * @param {http.ServerResponse} response
11
+ * @returns {Promise<void>}
12
+ */
13
+ this.onHttpServerRequest = async (request, response) => {
14
+ if (!request.url) {
15
+ response.statusCode = 400;
16
+ response.end("Bad Request");
17
+ return;
18
+ }
19
+ const parsedUrl = url.parse(request.url);
20
+ let filePath = `${process.cwd()}/dist${parsedUrl.pathname}`;
21
+ if (filePath.endsWith("/")) {
22
+ filePath += "index.html";
23
+ }
24
+ let fileExists;
25
+ try {
26
+ await fs.stat(filePath);
27
+ fileExists = true;
28
+ }
29
+ catch (_error) { // eslint-disable-line no-unused-vars
30
+ fileExists = false;
31
+ }
32
+ if (!fileExists) {
33
+ filePath = `${process.cwd()}/dist/index.html`;
34
+ }
35
+ const fileContent = await fs.readFile(filePath);
36
+ const mimeType = mime.getType(filePath);
37
+ response.statusCode = 200;
38
+ if (mimeType) {
39
+ response.setHeader("Content-Type", mimeType);
40
+ }
41
+ response.end(fileContent);
42
+ };
43
+ }
44
+ /** @returns {void} */
45
+ close() {
46
+ if (!this.httpServer) {
47
+ throw new Error("HTTP server is not initialized");
48
+ }
49
+ this.httpServer.close();
50
+ }
51
+ /** @returns {Promise<void>} */
52
+ async start() {
53
+ this.basePath = await fs.realpath(`${__dirname}/../..`);
54
+ await this.startHttpServer();
55
+ }
56
+ /** @returns {Promise<void>} */
57
+ startHttpServer() {
58
+ return new Promise((resolve) => {
59
+ this.httpServer = http.createServer(this.onHttpServerRequest);
60
+ this.httpServer.listen(1984, "localhost", () => {
61
+ resolve();
62
+ });
63
+ });
64
+ }
65
+ }
66
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3lzdGVtLXRlc3QtaHR0cC1zZXJ2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc3lzdGVtLXRlc3QtaHR0cC1zZXJ2ZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBQ2pDLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUM1QixPQUFPLElBQUksTUFBTSxNQUFNLENBQUE7QUFDdkIsT0FBTyxHQUFHLE1BQU0sS0FBSyxDQUFBO0FBRXJCLE1BQU0sQ0FBQyxPQUFPLE9BQU8sb0JBQW9CO0lBQXpDO1FBVUU7Ozs7V0FJRztRQUNILHdCQUFtQixHQUFHLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUU7WUFDaEQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDakIsUUFBUSxDQUFDLFVBQVUsR0FBRyxHQUFHLENBQUE7Z0JBQ3pCLFFBQVEsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUE7Z0JBQzNCLE9BQU07WUFDUixDQUFDO1lBRUQsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUE7WUFDeEMsSUFBSSxRQUFRLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxFQUFFLFFBQVEsU0FBUyxDQUFDLFFBQVEsRUFBRSxDQUFBO1lBRTNELElBQUksUUFBUSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMzQixRQUFRLElBQUksWUFBWSxDQUFBO1lBQzFCLENBQUM7WUFFRCxJQUFJLFVBQVUsQ0FBQTtZQUVkLElBQUksQ0FBQztnQkFDSCxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7Z0JBQ3ZCLFVBQVUsR0FBRyxJQUFJLENBQUE7WUFDbkIsQ0FBQztZQUFDLE9BQU8sTUFBTSxFQUFFLENBQUMsQ0FBQyxxQ0FBcUM7Z0JBQ3RELFVBQVUsR0FBRyxLQUFLLENBQUE7WUFDcEIsQ0FBQztZQUVELElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztnQkFDaEIsUUFBUSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRSxrQkFBa0IsQ0FBQTtZQUMvQyxDQUFDO1lBRUQsTUFBTSxXQUFXLEdBQUcsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFBO1lBQy9DLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7WUFFdkMsUUFBUSxDQUFDLFVBQVUsR0FBRyxHQUFHLENBQUE7WUFFekIsSUFBSSxRQUFRLEVBQUUsQ0FBQztnQkFDYixRQUFRLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRSxRQUFRLENBQUMsQ0FBQTtZQUM5QyxDQUFDO1lBRUQsUUFBUSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQTtRQUMzQixDQUFDLENBQUE7SUFpQkgsQ0FBQztJQXBFQyxzQkFBc0I7SUFDdEIsS0FBSztRQUNILElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDckIsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFBO1FBQ25ELENBQUM7UUFFRCxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFBO0lBQ3pCLENBQUM7SUE4Q0QsK0JBQStCO0lBQy9CLEtBQUssQ0FBQyxLQUFLO1FBQ1QsSUFBSSxDQUFDLFFBQVEsR0FBRyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsR0FBRyxTQUFTLFFBQVEsQ0FBQyxDQUFBO1FBQ3ZELE1BQU0sSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFBO0lBQzlCLENBQUM7SUFFRCwrQkFBK0I7SUFDL0IsZUFBZTtRQUNiLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUM3QixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUE7WUFDN0QsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLFdBQVcsRUFBRSxHQUFHLEVBQUU7Z0JBQzdDLE9BQU8sRUFBRSxDQUFBO1lBQ1gsQ0FBQyxDQUFDLENBQUE7UUFDSixDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgZnMgZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIlxuaW1wb3J0IGh0dHAgZnJvbSBcIm5vZGU6aHR0cFwiXG5pbXBvcnQgbWltZSBmcm9tIFwibWltZVwiXG5pbXBvcnQgdXJsIGZyb20gXCJ1cmxcIlxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTeXN0ZW1UZXN0SHR0cFNlcnZlciB7XG4gIC8qKiBAcmV0dXJucyB7dm9pZH0gKi9cbiAgY2xvc2UoKSB7XG4gICAgaWYgKCF0aGlzLmh0dHBTZXJ2ZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkhUVFAgc2VydmVyIGlzIG5vdCBpbml0aWFsaXplZFwiKVxuICAgIH1cblxuICAgIHRoaXMuaHR0cFNlcnZlci5jbG9zZSgpXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtodHRwLkluY29taW5nTWVzc2FnZX0gcmVxdWVzdFxuICAgKiBAcGFyYW0ge2h0dHAuU2VydmVyUmVzcG9uc2V9IHJlc3BvbnNlXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgb25IdHRwU2VydmVyUmVxdWVzdCA9IGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgIGlmICghcmVxdWVzdC51cmwpIHtcbiAgICAgIHJlc3BvbnNlLnN0YXR1c0NvZGUgPSA0MDBcbiAgICAgIHJlc3BvbnNlLmVuZChcIkJhZCBSZXF1ZXN0XCIpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBjb25zdCBwYXJzZWRVcmwgPSB1cmwucGFyc2UocmVxdWVzdC51cmwpXG4gICAgbGV0IGZpbGVQYXRoID0gYCR7cHJvY2Vzcy5jd2QoKX0vZGlzdCR7cGFyc2VkVXJsLnBhdGhuYW1lfWBcblxuICAgIGlmIChmaWxlUGF0aC5lbmRzV2l0aChcIi9cIikpIHtcbiAgICAgIGZpbGVQYXRoICs9IFwiaW5kZXguaHRtbFwiXG4gICAgfVxuXG4gICAgbGV0IGZpbGVFeGlzdHNcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBmcy5zdGF0KGZpbGVQYXRoKVxuICAgICAgZmlsZUV4aXN0cyA9IHRydWVcbiAgICB9IGNhdGNoIChfZXJyb3IpIHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICAgICAgZmlsZUV4aXN0cyA9IGZhbHNlXG4gICAgfVxuXG4gICAgaWYgKCFmaWxlRXhpc3RzKSB7XG4gICAgICBmaWxlUGF0aCA9IGAke3Byb2Nlc3MuY3dkKCl9L2Rpc3QvaW5kZXguaHRtbGBcbiAgICB9XG5cbiAgICBjb25zdCBmaWxlQ29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKGZpbGVQYXRoKVxuICAgIGNvbnN0IG1pbWVUeXBlID0gbWltZS5nZXRUeXBlKGZpbGVQYXRoKVxuXG4gICAgcmVzcG9uc2Uuc3RhdHVzQ29kZSA9IDIwMFxuXG4gICAgaWYgKG1pbWVUeXBlKSB7XG4gICAgICByZXNwb25zZS5zZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIiwgbWltZVR5cGUpXG4gICAgfVxuXG4gICAgcmVzcG9uc2UuZW5kKGZpbGVDb250ZW50KVxuICB9XG5cbiAgLyoqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAqL1xuICBhc3luYyBzdGFydCgpIHtcbiAgICB0aGlzLmJhc2VQYXRoID0gYXdhaXQgZnMucmVhbHBhdGgoYCR7X19kaXJuYW1lfS8uLi8uLmApXG4gICAgYXdhaXQgdGhpcy5zdGFydEh0dHBTZXJ2ZXIoKVxuICB9XG5cbiAgLyoqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAqL1xuICBzdGFydEh0dHBTZXJ2ZXIoKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICB0aGlzLmh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcih0aGlzLm9uSHR0cFNlcnZlclJlcXVlc3QpXG4gICAgICB0aGlzLmh0dHBTZXJ2ZXIubGlzdGVuKDE5ODQsIFwibG9jYWxob3N0XCIsICgpID0+IHtcbiAgICAgICAgcmVzb2x2ZSgpXG4gICAgICB9KVxuICAgIH0pXG4gIH1cbn1cbiJdfQ==
@@ -34,6 +34,7 @@ export default class SystemTest {
34
34
  _started: boolean;
35
35
  _driverTimeouts: number;
36
36
  _timeouts: number;
37
+ /** @returns {SystemTestCommunicator} */
37
38
  getCommunicator(): SystemTestCommunicator;
38
39
  _host: string;
39
40
  _port: number;
@@ -45,9 +46,7 @@ export default class SystemTest {
45
46
  * @returns {string | undefined}
46
47
  */
47
48
  getBaseSelector(): string | undefined;
48
- /**
49
- * @returns {import("selenium-webdriver").WebDriver}
50
- */
49
+ /** @returns {import("selenium-webdriver").WebDriver} */
51
50
  getDriver(): import("selenium-webdriver").WebDriver;
52
51
  /**
53
52
  * Sets the base selector for scoping element searches
@@ -67,8 +66,8 @@ export default class SystemTest {
67
66
  */
68
67
  startScoundrel(): void;
69
68
  wss: import("ws").Server<typeof import("ws").default, typeof import("node:http").IncomingMessage>;
70
- serverWebSocket: any;
71
- server: any;
69
+ serverWebSocket: ServerWebSocket;
70
+ server: Server;
72
71
  /**
73
72
  * @returns {void}
74
73
  */
@@ -76,7 +75,7 @@ export default class SystemTest {
76
75
  /**
77
76
  * Finds all elements by CSS selector
78
77
  * @param {string} selector
79
- * @param {object} args
78
+ * @param {object} [args]
80
79
  * @param {number} [args.timeout]
81
80
  * @param {boolean} [args.visible]
82
81
  * @param {boolean} [args.useBaseSelector]
@@ -96,17 +95,17 @@ export default class SystemTest {
96
95
  /**
97
96
  * Finds a single element by CSS selector
98
97
  * @param {string} selector
99
- * @param {object} args
98
+ * @param {object} [args]
100
99
  * @returns {Promise<import("selenium-webdriver").WebElement>}
101
100
  */
102
101
  find(selector: string, args?: object): Promise<import("selenium-webdriver").WebElement>;
103
102
  /**
104
103
  * Finds a single element by test ID
105
104
  * @param {string} testID
106
- * @param {object} args
105
+ * @param {object} [args]
107
106
  * @returns {Promise<import("selenium-webdriver").WebElement>}
108
107
  */
109
- findByTestID(testID: string, args: object): Promise<import("selenium-webdriver").WebElement>;
108
+ findByTestID(testID: string, args?: object): Promise<import("selenium-webdriver").WebElement>;
110
109
  /**
111
110
  * @param {string|import("selenium-webdriver").WebElement} elementOrIdentifier
112
111
  * @returns {Promise<import("selenium-webdriver").WebElement>}
@@ -124,20 +123,16 @@ export default class SystemTest {
124
123
  * @returns {Promise<string[]>}
125
124
  */
126
125
  getBrowserLogs(): Promise<string[]>;
127
- /**
128
- * @returns {Promise<string>}
129
- */
126
+ /** @returns {Promise<string>} */
130
127
  getCurrentUrl(): Promise<string>;
131
- /**
132
- * @returns {number}
133
- */
128
+ /** @returns {number} */
134
129
  getTimeouts(): number;
135
130
  /**
136
131
  * Interacts with an element by calling a method on it with the given arguments.
137
132
  * Retrying on ElementNotInteractableError.
138
- * @param {import("selenium-webdriver").WebElement|string} elementOrIdentifier - The element or a CSS selector to find the element.
139
- * @param {string} methodName - The method name to call on the element.
140
- * @param {...any} args - Arguments to pass to the method.
133
+ * @param {import("selenium-webdriver").WebElement|string} elementOrIdentifier The element or a CSS selector to find the element.
134
+ * @param {string} methodName The method name to call on the element.
135
+ * @param {...any} args Arguments to pass to the method.
141
136
  * @returns {Promise<any>}
142
137
  */
143
138
  interact(elementOrIdentifier: import("selenium-webdriver").WebElement | string, methodName: string, ...args: any[]): Promise<any>;
@@ -149,11 +144,11 @@ export default class SystemTest {
149
144
  expectNoElement(selector: string): Promise<void>;
150
145
  /**
151
146
  * @param {string} selector
152
- * @param {object} args
147
+ * @param {object} [args]
153
148
  * @param {boolean} [args.useBaseSelector]
154
149
  * @returns {Promise<void>}
155
150
  */
156
- waitForNoSelector(selector: string, args: {
151
+ waitForNoSelector(selector: string, args?: {
157
152
  useBaseSelector?: boolean;
158
153
  }): Promise<void>;
159
154
  /**
@@ -167,9 +162,7 @@ export default class SystemTest {
167
162
  * @returns {Promise<void>}
168
163
  */
169
164
  expectNotificationMessage(expectedNotificationMessage: string): Promise<void>;
170
- /**
171
- * @returns {Promise<void>}
172
- */
165
+ /** @returns {Promise<void>} */
173
166
  dismissNotificationMessages(): Promise<void>;
174
167
  /**
175
168
  * Indicates whether the system test has been started
@@ -249,9 +242,7 @@ export default class SystemTest {
249
242
  */
250
243
  onWebSocketConnection: (ws: WebSocket) => Promise<void>;
251
244
  ws: WebSocket;
252
- /**
253
- * @returns {void}
254
- */
245
+ /** @returns {void} */
255
246
  onWebSocketClose: () => void;
256
247
  /**
257
248
  * Handles an error reported from the browser
@@ -294,4 +285,6 @@ export default class SystemTest {
294
285
  dismissTo(path: string): Promise<void>;
295
286
  }
296
287
  import SystemTestCommunicator from "./system-test-communicator.js";
288
+ import ServerWebSocket from "scoundrel-remote-eval/build/server/connections/web-socket/index.js";
289
+ import Server from "scoundrel-remote-eval/build/server/index.js";
297
290
  import SystemTestHttpServer from "./system-test-http-server.js";