@melra/browser-runtime 0.3.0-alpha.11 → 0.3.0-alpha.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/bounded.d.ts +27 -0
- package/dist/bounded.d.ts.map +1 -0
- package/dist/bounded.js +50 -0
- package/dist/bounded.js.map +1 -0
- package/dist/browser-connection.d.ts.map +1 -1
- package/dist/browser-connection.js +22 -7
- package/dist/browser-connection.js.map +1 -1
- package/dist/index.d.ts +106 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +429 -57
- package/dist/index.js.map +1 -1
- package/dist/pinning-proxy.d.ts.map +1 -1
- package/dist/pinning-proxy.js +7 -8
- package/dist/pinning-proxy.js.map +1 -1
- package/dist/stable-dom.d.ts +13 -1
- package/dist/stable-dom.d.ts.map +1 -1
- package/dist/stable-dom.js +22 -3
- package/dist/stable-dom.js.map +1 -1
- package/package.json +6 -6
- package/dist/browser-connection.test.d.ts +0 -2
- package/dist/browser-connection.test.d.ts.map +0 -1
- package/dist/browser-connection.test.js +0 -210
- package/dist/browser-connection.test.js.map +0 -1
- package/dist/dialogs.test.d.ts +0 -2
- package/dist/dialogs.test.d.ts.map +0 -1
- package/dist/dialogs.test.js +0 -165
- package/dist/dialogs.test.js.map +0 -1
- package/dist/frames.test.d.ts +0 -2
- package/dist/frames.test.d.ts.map +0 -1
- package/dist/frames.test.js +0 -157
- package/dist/frames.test.js.map +0 -1
- package/dist/history-tabs.test.d.ts +0 -2
- package/dist/history-tabs.test.d.ts.map +0 -1
- package/dist/history-tabs.test.js +0 -176
- package/dist/history-tabs.test.js.map +0 -1
- package/dist/input-fidelity.test.d.ts +0 -2
- package/dist/input-fidelity.test.d.ts.map +0 -1
- package/dist/input-fidelity.test.js +0 -260
- package/dist/input-fidelity.test.js.map +0 -1
- package/dist/pinning-proxy.test.d.ts +0 -2
- package/dist/pinning-proxy.test.d.ts.map +0 -1
- package/dist/pinning-proxy.test.js +0 -80
- package/dist/pinning-proxy.test.js.map +0 -1
- package/dist/popups-profile.test.d.ts +0 -2
- package/dist/popups-profile.test.d.ts.map +0 -1
- package/dist/popups-profile.test.js +0 -170
- package/dist/popups-profile.test.js.map +0 -1
- package/dist/see-act.test.d.ts +0 -2
- package/dist/see-act.test.d.ts.map +0 -1
- package/dist/see-act.test.js +0 -152
- package/dist/see-act.test.js.map +0 -1
- package/dist/selector.test.d.ts +0 -2
- package/dist/selector.test.d.ts.map +0 -1
- package/dist/selector.test.js +0 -34
- package/dist/selector.test.js.map +0 -1
- package/dist/stable-dom.test.d.ts +0 -2
- package/dist/stable-dom.test.d.ts.map +0 -1
- package/dist/stable-dom.test.js +0 -22
- package/dist/stable-dom.test.js.map +0 -1
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 XAGI Labs Private Limited
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { createServer } from "node:http";
|
|
4
|
-
import { mkdtemp, rm } from "node:fs/promises";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
6
|
-
import { join } from "node:path";
|
|
7
|
-
import { BrowserOperationSchema } from "@melra/protocol";
|
|
8
|
-
import { afterEach, describe, expect, it } from "vitest";
|
|
9
|
-
import { BrowserRuntime, detectBrowserExecutable } from "./index.js";
|
|
10
|
-
/**
|
|
11
|
-
* Typing went through `.fill()`, which assigns the value and fires one `input`
|
|
12
|
-
* event. Every widget that listens for keystrokes — autocomplete, comboboxes,
|
|
13
|
-
* submit buttons enabled on `keyup` — saw nothing. There was also no way to wait
|
|
14
|
-
* for the page to reach a state, so callers padded `settleTimeoutMs` and hoped.
|
|
15
|
-
*/
|
|
16
|
-
const roots = [];
|
|
17
|
-
const servers = [];
|
|
18
|
-
afterEach(async () => {
|
|
19
|
-
await Promise.all(servers.splice(0).map((server) => new Promise((done) => {
|
|
20
|
-
server.close(() => done());
|
|
21
|
-
})));
|
|
22
|
-
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
|
23
|
-
});
|
|
24
|
-
/**
|
|
25
|
-
* A form that records the keystrokes it receives, a panel that appears late,
|
|
26
|
-
* and enough height to scroll. `/done` is where submitting lands.
|
|
27
|
-
*/
|
|
28
|
-
const PAGE = `<!doctype html><html><head><title>form</title></head><body>
|
|
29
|
-
<form action="/done" method="get">
|
|
30
|
-
<input id="email" name="email">
|
|
31
|
-
<input id="password" name="password">
|
|
32
|
-
<button id="sign-in" type="submit">Sign in</button>
|
|
33
|
-
</form>
|
|
34
|
-
<div id="keys">keys: 0</div>
|
|
35
|
-
<div style="height: 4000px"></div>
|
|
36
|
-
<script>
|
|
37
|
-
let keys = 0;
|
|
38
|
-
for (const field of document.querySelectorAll('input')) {
|
|
39
|
-
field.addEventListener('keydown', () => {
|
|
40
|
-
keys += 1;
|
|
41
|
-
document.getElementById('keys').textContent = 'keys: ' + keys;
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
setTimeout(() => {
|
|
45
|
-
const panel = document.createElement('div');
|
|
46
|
-
panel.id = 'late';
|
|
47
|
-
panel.textContent = 'ready at last';
|
|
48
|
-
document.body.append(panel);
|
|
49
|
-
}, 400);
|
|
50
|
-
</script>
|
|
51
|
-
</body></html>`;
|
|
52
|
-
async function fixture() {
|
|
53
|
-
const executablePath = await detectBrowserExecutable();
|
|
54
|
-
if (executablePath === undefined)
|
|
55
|
-
return undefined;
|
|
56
|
-
const server = createServer((request, response) => {
|
|
57
|
-
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
58
|
-
response.end((request.url ?? "/").startsWith("/done")
|
|
59
|
-
? "<!doctype html><html><head><title>done</title></head><body><h1>done</h1></body></html>"
|
|
60
|
-
: PAGE);
|
|
61
|
-
});
|
|
62
|
-
servers.push(server);
|
|
63
|
-
await new Promise((done) => {
|
|
64
|
-
server.listen(0, "127.0.0.1", done);
|
|
65
|
-
});
|
|
66
|
-
const address = server.address();
|
|
67
|
-
if (address === null || typeof address === "string") {
|
|
68
|
-
throw new Error("fixture_server_address_unavailable");
|
|
69
|
-
}
|
|
70
|
-
const root = await mkdtemp(join(tmpdir(), "melra-input-fidelity-"));
|
|
71
|
-
roots.push(root);
|
|
72
|
-
return {
|
|
73
|
-
runtime: new BrowserRuntime({
|
|
74
|
-
workspaceRoot: root,
|
|
75
|
-
artifactDirectory: join(root, "artifacts"),
|
|
76
|
-
executablePath,
|
|
77
|
-
allowedDomains: ["127.0.0.1"],
|
|
78
|
-
allowLocalhost: true,
|
|
79
|
-
}),
|
|
80
|
-
url: `http://127.0.0.1:${address.port}`,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
const op = (fields) => BrowserOperationSchema.parse({ kind: "browser", ...fields });
|
|
84
|
-
const valueOf = (result, id) => result.elements.find((element) => element.id === id)?.value ?? null;
|
|
85
|
-
describe("browser typing", () => {
|
|
86
|
-
it("dispatches one key event per character", async () => {
|
|
87
|
-
const context = await fixture();
|
|
88
|
-
if (context === undefined)
|
|
89
|
-
return;
|
|
90
|
-
const { runtime, url } = context;
|
|
91
|
-
try {
|
|
92
|
-
await runtime.execute(op({ action: "navigate", url }));
|
|
93
|
-
const typed = await runtime.execute(op({
|
|
94
|
-
action: "type",
|
|
95
|
-
target: { selector: "#email" },
|
|
96
|
-
value: "hello",
|
|
97
|
-
// Clearing an empty field costs a `Delete` keystroke of its own, so
|
|
98
|
-
// skip it here to make the count exactly the text.
|
|
99
|
-
clearFirst: false,
|
|
100
|
-
}));
|
|
101
|
-
expect(valueOf(typed, "email")).toBe("hello");
|
|
102
|
-
// `.fill()` would leave this at 0: the page would have the text but no
|
|
103
|
-
// idea anyone had typed it.
|
|
104
|
-
expect(typed.text).toContain("keys: 5");
|
|
105
|
-
}
|
|
106
|
-
finally {
|
|
107
|
-
await runtime.close();
|
|
108
|
-
}
|
|
109
|
-
}, 120_000);
|
|
110
|
-
it("replaces the field by default and appends when told not to clear", async () => {
|
|
111
|
-
const context = await fixture();
|
|
112
|
-
if (context === undefined)
|
|
113
|
-
return;
|
|
114
|
-
const { runtime, url } = context;
|
|
115
|
-
try {
|
|
116
|
-
await runtime.execute(op({ action: "navigate", url }));
|
|
117
|
-
await runtime.execute(op({ action: "type", target: { selector: "#email" }, value: "first" }));
|
|
118
|
-
const replaced = await runtime.execute(op({ action: "type", target: { selector: "#email" }, value: "second" }));
|
|
119
|
-
expect(valueOf(replaced, "email")).toBe("second");
|
|
120
|
-
const appended = await runtime.execute(op({
|
|
121
|
-
action: "type",
|
|
122
|
-
target: { selector: "#email" },
|
|
123
|
-
value: "-more",
|
|
124
|
-
clearFirst: false,
|
|
125
|
-
}));
|
|
126
|
-
expect(valueOf(appended, "email")).toBe("second-more");
|
|
127
|
-
}
|
|
128
|
-
finally {
|
|
129
|
-
await runtime.close();
|
|
130
|
-
}
|
|
131
|
-
}, 120_000);
|
|
132
|
-
it("fills a whole form and submits it as one action", async () => {
|
|
133
|
-
const context = await fixture();
|
|
134
|
-
if (context === undefined)
|
|
135
|
-
return;
|
|
136
|
-
const { runtime, url } = context;
|
|
137
|
-
try {
|
|
138
|
-
await runtime.execute(op({ action: "navigate", url }));
|
|
139
|
-
const filled = await runtime.execute(op({
|
|
140
|
-
action: "fill_form",
|
|
141
|
-
fields: [
|
|
142
|
-
{ target: { selector: "#email" }, value: "user@example.com" },
|
|
143
|
-
{ target: { selector: "#password" }, value: "hunter2" },
|
|
144
|
-
],
|
|
145
|
-
target: { selector: "#sign-in" },
|
|
146
|
-
}));
|
|
147
|
-
expect(filled.filled).toBe(2);
|
|
148
|
-
expect(filled.submitted).toBe(true);
|
|
149
|
-
expect(filled.title).toBe("done");
|
|
150
|
-
}
|
|
151
|
-
finally {
|
|
152
|
-
await runtime.close();
|
|
153
|
-
}
|
|
154
|
-
}, 120_000);
|
|
155
|
-
it("fills without submitting when no submit target is given", async () => {
|
|
156
|
-
const context = await fixture();
|
|
157
|
-
if (context === undefined)
|
|
158
|
-
return;
|
|
159
|
-
const { runtime, url } = context;
|
|
160
|
-
try {
|
|
161
|
-
await runtime.execute(op({ action: "navigate", url }));
|
|
162
|
-
const filled = await runtime.execute(op({
|
|
163
|
-
action: "fill_form",
|
|
164
|
-
fields: [{ target: { selector: "#password" }, value: "hunter2" }],
|
|
165
|
-
}));
|
|
166
|
-
expect(filled.submitted).toBe(false);
|
|
167
|
-
expect(valueOf(filled, "password")).toBe("hunter2");
|
|
168
|
-
}
|
|
169
|
-
finally {
|
|
170
|
-
await runtime.close();
|
|
171
|
-
}
|
|
172
|
-
}, 120_000);
|
|
173
|
-
});
|
|
174
|
-
describe("browser wait", () => {
|
|
175
|
-
it("waits for an element that has not rendered yet", async () => {
|
|
176
|
-
const context = await fixture();
|
|
177
|
-
if (context === undefined)
|
|
178
|
-
return;
|
|
179
|
-
const { runtime, url } = context;
|
|
180
|
-
try {
|
|
181
|
-
await runtime.execute(op({ action: "navigate", url }));
|
|
182
|
-
// The panel is added 400ms in, which is past the DOM-settle window, so
|
|
183
|
-
// acting on it without waiting is a race.
|
|
184
|
-
const waited = await runtime.execute(op({ action: "wait", target: { selector: "#late" }, state: "visible" }));
|
|
185
|
-
expect(waited.waited).toBe(true);
|
|
186
|
-
expect(waited.text).toContain("ready at last");
|
|
187
|
-
}
|
|
188
|
-
finally {
|
|
189
|
-
await runtime.close();
|
|
190
|
-
}
|
|
191
|
-
}, 120_000);
|
|
192
|
-
it("waits for a URL substring and for page text", async () => {
|
|
193
|
-
const context = await fixture();
|
|
194
|
-
if (context === undefined)
|
|
195
|
-
return;
|
|
196
|
-
const { runtime, url } = context;
|
|
197
|
-
try {
|
|
198
|
-
await runtime.execute(op({ action: "navigate", url }));
|
|
199
|
-
await runtime.execute(op({ action: "click", target: { selector: "#sign-in" } }));
|
|
200
|
-
const arrived = await runtime.execute(op({ action: "wait", urlContains: "/done" }));
|
|
201
|
-
expect(arrived.url).toContain("/done");
|
|
202
|
-
const text = await runtime.execute(op({ action: "wait", value: "done" }));
|
|
203
|
-
expect(text.waited).toBe(true);
|
|
204
|
-
}
|
|
205
|
-
finally {
|
|
206
|
-
await runtime.close();
|
|
207
|
-
}
|
|
208
|
-
}, 120_000);
|
|
209
|
-
it("refuses a wait with no condition", async () => {
|
|
210
|
-
const context = await fixture();
|
|
211
|
-
if (context === undefined)
|
|
212
|
-
return;
|
|
213
|
-
const { runtime, url } = context;
|
|
214
|
-
try {
|
|
215
|
-
await runtime.execute(op({ action: "navigate", url }));
|
|
216
|
-
await expect(runtime.execute(op({ action: "wait" }))).rejects.toThrow("browser_wait_requires_target_url_contains_or_value");
|
|
217
|
-
}
|
|
218
|
-
finally {
|
|
219
|
-
await runtime.close();
|
|
220
|
-
}
|
|
221
|
-
}, 120_000);
|
|
222
|
-
});
|
|
223
|
-
describe("browser scroll", () => {
|
|
224
|
-
it("scrolls by the requested distance and reports where it landed", async () => {
|
|
225
|
-
const context = await fixture();
|
|
226
|
-
if (context === undefined)
|
|
227
|
-
return;
|
|
228
|
-
const { runtime, url } = context;
|
|
229
|
-
try {
|
|
230
|
-
await runtime.execute(op({ action: "navigate", url }));
|
|
231
|
-
const scrolled = await runtime.execute(op({ action: "scroll", direction: "down", pixels: 1_200 }));
|
|
232
|
-
expect(scrolled.scrollY).toBe(1_200);
|
|
233
|
-
const back = await runtime.execute(op({ action: "scroll", direction: "top" }));
|
|
234
|
-
expect(back.scrollY).toBe(0);
|
|
235
|
-
}
|
|
236
|
-
finally {
|
|
237
|
-
await runtime.close();
|
|
238
|
-
}
|
|
239
|
-
}, 120_000);
|
|
240
|
-
});
|
|
241
|
-
describe("browser results", () => {
|
|
242
|
-
it("reports success, which is what derived evidence checks", async () => {
|
|
243
|
-
const context = await fixture();
|
|
244
|
-
if (context === undefined)
|
|
245
|
-
return;
|
|
246
|
-
const { runtime, url } = context;
|
|
247
|
-
try {
|
|
248
|
-
// Policy derives `result_equals success true` for a browser mutation the
|
|
249
|
-
// caller declared no evidence for. Without the flag every such task
|
|
250
|
-
// verified as `partial` however well it went.
|
|
251
|
-
expect((await runtime.execute(op({ action: "navigate", url }))).success).toBe(true);
|
|
252
|
-
expect((await runtime.execute(op({ action: "click", target: { selector: "#sign-in" } })))
|
|
253
|
-
.success).toBe(true);
|
|
254
|
-
}
|
|
255
|
-
finally {
|
|
256
|
-
await runtime.close();
|
|
257
|
-
}
|
|
258
|
-
}, 120_000);
|
|
259
|
-
});
|
|
260
|
-
//# sourceMappingURL=input-fidelity.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"input-fidelity.test.js","sourceRoot":"","sources":["../src/input-fidelity.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pinning-proxy.test.d.ts","sourceRoot":"","sources":["../src/pinning-proxy.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 XAGI Labs Private Limited
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { createServer, request as httpRequest } from "node:http";
|
|
4
|
-
import { connect } from "node:net";
|
|
5
|
-
import { describe, expect, it, vi } from "vitest";
|
|
6
|
-
// `rebind.test` resolves nowhere in reality, which is what makes this a test of
|
|
7
|
-
// pinning rather than of DNS: only a proxy that connects to the address the
|
|
8
|
-
// policy check returned can reach the server below. One that resolved the name
|
|
9
|
-
// a second time — the rebinding window — would fail outright.
|
|
10
|
-
vi.mock("node:dns/promises", () => ({
|
|
11
|
-
lookup: async () => [{ address: "127.0.0.1", family: 4 }],
|
|
12
|
-
}));
|
|
13
|
-
const { startPinningProxy } = await import("./pinning-proxy.js");
|
|
14
|
-
async function listen() {
|
|
15
|
-
const server = createServer((_req, res) => res.end("pinned"));
|
|
16
|
-
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
17
|
-
return {
|
|
18
|
-
port: server.address().port,
|
|
19
|
-
close: () => server.close(),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function throughProxy(proxyPort, target) {
|
|
23
|
-
return new Promise((resolve, reject) => {
|
|
24
|
-
// Absolute-form request URI: how a browser addresses a proxy.
|
|
25
|
-
const req = httpRequest({ host: "127.0.0.1", port: proxyPort, path: target }, (res) => {
|
|
26
|
-
let body = "";
|
|
27
|
-
res.on("data", (chunk) => (body += String(chunk)));
|
|
28
|
-
res.on("end", () => resolve({ status: res.statusCode ?? 0, body }));
|
|
29
|
-
});
|
|
30
|
-
req.on("error", reject);
|
|
31
|
-
req.end();
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
describe("pinning proxy", () => {
|
|
35
|
-
it("connects to the address the policy check returned", async () => {
|
|
36
|
-
const upstream = await listen();
|
|
37
|
-
const proxy = await startPinningProxy({
|
|
38
|
-
allowedDomains: ["*"],
|
|
39
|
-
allowLocalhost: true,
|
|
40
|
-
});
|
|
41
|
-
try {
|
|
42
|
-
const port = Number(new URL(proxy.server).port);
|
|
43
|
-
const response = await throughProxy(port, `http://rebind.test:${upstream.port}/`);
|
|
44
|
-
expect(response).toEqual({ status: 200, body: "pinned" });
|
|
45
|
-
}
|
|
46
|
-
finally {
|
|
47
|
-
await proxy.close();
|
|
48
|
-
upstream.close();
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
it("refuses a destination policy denies", async () => {
|
|
52
|
-
const upstream = await listen();
|
|
53
|
-
const proxy = await startPinningProxy({
|
|
54
|
-
allowedDomains: ["*"],
|
|
55
|
-
allowLocalhost: false,
|
|
56
|
-
});
|
|
57
|
-
try {
|
|
58
|
-
const port = Number(new URL(proxy.server).port);
|
|
59
|
-
const response = await throughProxy(port, `http://rebind.test:${upstream.port}/`);
|
|
60
|
-
expect(response.status).toBe(502);
|
|
61
|
-
// CONNECT carries no path to check, so the authority has to be enough.
|
|
62
|
-
const refusal = await new Promise((resolve, reject) => {
|
|
63
|
-
const socket = connect(port, "127.0.0.1", () => {
|
|
64
|
-
socket.write(`CONNECT rebind.test:443 HTTP/1.1\r\nHost: rebind.test:443\r\n\r\n`);
|
|
65
|
-
});
|
|
66
|
-
socket.on("data", (chunk) => {
|
|
67
|
-
resolve(String(chunk));
|
|
68
|
-
socket.destroy();
|
|
69
|
-
});
|
|
70
|
-
socket.on("error", reject);
|
|
71
|
-
});
|
|
72
|
-
expect(refusal).toContain("502");
|
|
73
|
-
}
|
|
74
|
-
finally {
|
|
75
|
-
await proxy.close();
|
|
76
|
-
upstream.close();
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
//# sourceMappingURL=pinning-proxy.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pinning-proxy.test.js","sourceRoot":"","sources":["../src/pinning-proxy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"popups-profile.test.d.ts","sourceRoot":"","sources":["../src/popups-profile.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 XAGI Labs Private Limited
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { createServer } from "node:http";
|
|
4
|
-
import { mkdtemp, rm } from "node:fs/promises";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
6
|
-
import { join } from "node:path";
|
|
7
|
-
import { BrowserOperationSchema } from "@melra/protocol";
|
|
8
|
-
import { afterEach, describe, expect, it } from "vitest";
|
|
9
|
-
import { BrowserRuntime, detectBrowserExecutable } from "./index.js";
|
|
10
|
-
/**
|
|
11
|
-
* Two gaps, both invisible to the caller. A click that spawned a window
|
|
12
|
-
* returned plain success while the window sat there holding focus and a
|
|
13
|
-
* session, and every run started from an empty profile, so a site that had
|
|
14
|
-
* been logged into had to be logged into again on the next task.
|
|
15
|
-
*/
|
|
16
|
-
const roots = [];
|
|
17
|
-
const servers = [];
|
|
18
|
-
afterEach(async () => {
|
|
19
|
-
await Promise.all(servers.splice(0).map((server) => new Promise((done) => {
|
|
20
|
-
server.close(() => done());
|
|
21
|
-
})));
|
|
22
|
-
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
|
23
|
-
});
|
|
24
|
-
/**
|
|
25
|
-
* `/` opens a window on click; `/set` plants a cookie; `/read` reports whether
|
|
26
|
-
* the cookie survived. One server covers both halves of this file.
|
|
27
|
-
*/
|
|
28
|
-
async function serve() {
|
|
29
|
-
const server = createServer((request, response) => {
|
|
30
|
-
const path = (request.url ?? "/").split("?")[0];
|
|
31
|
-
if (path === "/set") {
|
|
32
|
-
response.writeHead(200, {
|
|
33
|
-
"content-type": "text/html; charset=utf-8",
|
|
34
|
-
"set-cookie": "melra=kept; Path=/; Max-Age=3600",
|
|
35
|
-
});
|
|
36
|
-
response.end("<!doctype html><title>set</title><body>set</body>");
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
if (path === "/read") {
|
|
40
|
-
const seen = (request.headers.cookie ?? "").includes("melra=kept");
|
|
41
|
-
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
42
|
-
response.end(`<!doctype html><title>read</title><body><div id="cookie">${seen ? "kept" : "gone"}</div></body>`);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
46
|
-
response.end(`<!doctype html><title>opener</title><body>
|
|
47
|
-
<button id="pop">Open</button>
|
|
48
|
-
<script>
|
|
49
|
-
document.getElementById('pop').addEventListener('click', () => {
|
|
50
|
-
window.open('/read', '_blank');
|
|
51
|
-
});
|
|
52
|
-
</script>
|
|
53
|
-
</body>`);
|
|
54
|
-
});
|
|
55
|
-
servers.push(server);
|
|
56
|
-
await new Promise((done) => {
|
|
57
|
-
server.listen(0, "127.0.0.1", done);
|
|
58
|
-
});
|
|
59
|
-
const address = server.address();
|
|
60
|
-
if (address === null || typeof address === "string") {
|
|
61
|
-
throw new Error("fixture_server_address_unavailable");
|
|
62
|
-
}
|
|
63
|
-
return `http://127.0.0.1:${address.port}`;
|
|
64
|
-
}
|
|
65
|
-
async function root(name) {
|
|
66
|
-
const created = await mkdtemp(join(tmpdir(), `melra-${name}-`));
|
|
67
|
-
roots.push(created);
|
|
68
|
-
return created;
|
|
69
|
-
}
|
|
70
|
-
const runtime = (workspaceRoot, executablePath, extra = {}) => new BrowserRuntime({
|
|
71
|
-
workspaceRoot,
|
|
72
|
-
artifactDirectory: join(workspaceRoot, "artifacts"),
|
|
73
|
-
executablePath,
|
|
74
|
-
allowedDomains: ["127.0.0.1"],
|
|
75
|
-
allowLocalhost: true,
|
|
76
|
-
...extra,
|
|
77
|
-
});
|
|
78
|
-
const op = (fields) => BrowserOperationSchema.parse({ kind: "browser", ...fields });
|
|
79
|
-
describe("browser popups", () => {
|
|
80
|
-
it("reports the window a page opened and closes it by default", async () => {
|
|
81
|
-
const executablePath = await detectBrowserExecutable();
|
|
82
|
-
if (executablePath === undefined)
|
|
83
|
-
return;
|
|
84
|
-
const url = await serve();
|
|
85
|
-
const session = runtime(await root("popup-block"), executablePath);
|
|
86
|
-
try {
|
|
87
|
-
await session.execute(op({ action: "navigate", url }));
|
|
88
|
-
const clicked = await session.execute(op({ action: "click", target: { selector: "#pop" } }));
|
|
89
|
-
// The point: the caller is told what the click opened behind it.
|
|
90
|
-
expect(clicked.popups).toEqual([
|
|
91
|
-
expect.objectContaining({ url: `${url}/read`, blocked: true }),
|
|
92
|
-
]);
|
|
93
|
-
// And it is gone by the time the next action runs, not eventually.
|
|
94
|
-
const tabs = await session.execute(op({ action: "tabs" }));
|
|
95
|
-
expect(tabs.tabs.length).toBe(1);
|
|
96
|
-
}
|
|
97
|
-
finally {
|
|
98
|
-
await session.close();
|
|
99
|
-
}
|
|
100
|
-
}, 120_000);
|
|
101
|
-
it("keeps the window as an addressable tab when popups are allowed", async () => {
|
|
102
|
-
const executablePath = await detectBrowserExecutable();
|
|
103
|
-
if (executablePath === undefined)
|
|
104
|
-
return;
|
|
105
|
-
const url = await serve();
|
|
106
|
-
const session = runtime(await root("popup-allow"), executablePath, {
|
|
107
|
-
popups: "allow",
|
|
108
|
-
});
|
|
109
|
-
try {
|
|
110
|
-
await session.execute(op({ action: "navigate", url }));
|
|
111
|
-
const clicked = await session.execute(op({ action: "click", target: { selector: "#pop" } }));
|
|
112
|
-
expect(clicked.popups[0]?.blocked).toBe(false);
|
|
113
|
-
const tabs = await session.execute(op({ action: "tabs" }));
|
|
114
|
-
expect(tabs.tabs.length).toBe(2);
|
|
115
|
-
}
|
|
116
|
-
finally {
|
|
117
|
-
await session.close();
|
|
118
|
-
}
|
|
119
|
-
}, 120_000);
|
|
120
|
-
it("does not mistake a tab the caller asked for for a popup", async () => {
|
|
121
|
-
const executablePath = await detectBrowserExecutable();
|
|
122
|
-
if (executablePath === undefined)
|
|
123
|
-
return;
|
|
124
|
-
const url = await serve();
|
|
125
|
-
const session = runtime(await root("popup-tab-new"), executablePath);
|
|
126
|
-
try {
|
|
127
|
-
await session.execute(op({ action: "navigate", url }));
|
|
128
|
-
// Both arrive as the same `page` event. If this were treated as a popup,
|
|
129
|
-
// `tab_new` would close the tab it just opened.
|
|
130
|
-
const opened = await session.execute(op({ action: "tab_new", url: `${url}/read` }));
|
|
131
|
-
expect(opened.popups).toBeUndefined();
|
|
132
|
-
expect((await session.execute(op({ action: "tabs" }))).tabs).toHaveLength(2);
|
|
133
|
-
}
|
|
134
|
-
finally {
|
|
135
|
-
await session.close();
|
|
136
|
-
}
|
|
137
|
-
}, 120_000);
|
|
138
|
-
});
|
|
139
|
-
describe("persistent browser profile", () => {
|
|
140
|
-
it("keeps a cookie across two sessions, and drops it without a profile", async () => {
|
|
141
|
-
const executablePath = await detectBrowserExecutable();
|
|
142
|
-
if (executablePath === undefined)
|
|
143
|
-
return;
|
|
144
|
-
const url = await serve();
|
|
145
|
-
const workspace = await root("profile");
|
|
146
|
-
const userDataDir = join(workspace, "profile");
|
|
147
|
-
const read = async (extra) => {
|
|
148
|
-
const session = runtime(workspace, executablePath, extra);
|
|
149
|
-
try {
|
|
150
|
-
await session.execute(op({ action: "navigate", url: `${url}/read` }));
|
|
151
|
-
const seen = await session.execute(op({ action: "inspect", target: { selector: "#cookie" } }));
|
|
152
|
-
return String(seen.text ?? "").trim();
|
|
153
|
-
}
|
|
154
|
-
finally {
|
|
155
|
-
await session.close();
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
const first = runtime(workspace, executablePath, { userDataDir });
|
|
159
|
-
try {
|
|
160
|
-
await first.execute(op({ action: "navigate", url: `${url}/set` }));
|
|
161
|
-
}
|
|
162
|
-
finally {
|
|
163
|
-
await first.close();
|
|
164
|
-
}
|
|
165
|
-
expect(await read({ userDataDir })).toBe("kept");
|
|
166
|
-
// The default is still a throwaway profile, so nothing leaked into it.
|
|
167
|
-
expect(await read({})).toBe("gone");
|
|
168
|
-
}, 180_000);
|
|
169
|
-
});
|
|
170
|
-
//# sourceMappingURL=popups-profile.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"popups-profile.test.js","sourceRoot":"","sources":["../src/popups-profile.test.ts"],"names":[],"mappings":"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"}
|
package/dist/see-act.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"see-act.test.d.ts","sourceRoot":"","sources":["../src/see-act.test.ts"],"names":[],"mappings":""}
|