@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.
Files changed (59) hide show
  1. package/dist/bounded.d.ts +27 -0
  2. package/dist/bounded.d.ts.map +1 -0
  3. package/dist/bounded.js +50 -0
  4. package/dist/bounded.js.map +1 -0
  5. package/dist/browser-connection.d.ts.map +1 -1
  6. package/dist/browser-connection.js +22 -7
  7. package/dist/browser-connection.js.map +1 -1
  8. package/dist/index.d.ts +106 -4
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +429 -57
  11. package/dist/index.js.map +1 -1
  12. package/dist/pinning-proxy.d.ts.map +1 -1
  13. package/dist/pinning-proxy.js +7 -8
  14. package/dist/pinning-proxy.js.map +1 -1
  15. package/dist/stable-dom.d.ts +13 -1
  16. package/dist/stable-dom.d.ts.map +1 -1
  17. package/dist/stable-dom.js +22 -3
  18. package/dist/stable-dom.js.map +1 -1
  19. package/package.json +6 -6
  20. package/dist/browser-connection.test.d.ts +0 -2
  21. package/dist/browser-connection.test.d.ts.map +0 -1
  22. package/dist/browser-connection.test.js +0 -210
  23. package/dist/browser-connection.test.js.map +0 -1
  24. package/dist/dialogs.test.d.ts +0 -2
  25. package/dist/dialogs.test.d.ts.map +0 -1
  26. package/dist/dialogs.test.js +0 -165
  27. package/dist/dialogs.test.js.map +0 -1
  28. package/dist/frames.test.d.ts +0 -2
  29. package/dist/frames.test.d.ts.map +0 -1
  30. package/dist/frames.test.js +0 -157
  31. package/dist/frames.test.js.map +0 -1
  32. package/dist/history-tabs.test.d.ts +0 -2
  33. package/dist/history-tabs.test.d.ts.map +0 -1
  34. package/dist/history-tabs.test.js +0 -176
  35. package/dist/history-tabs.test.js.map +0 -1
  36. package/dist/input-fidelity.test.d.ts +0 -2
  37. package/dist/input-fidelity.test.d.ts.map +0 -1
  38. package/dist/input-fidelity.test.js +0 -260
  39. package/dist/input-fidelity.test.js.map +0 -1
  40. package/dist/pinning-proxy.test.d.ts +0 -2
  41. package/dist/pinning-proxy.test.d.ts.map +0 -1
  42. package/dist/pinning-proxy.test.js +0 -80
  43. package/dist/pinning-proxy.test.js.map +0 -1
  44. package/dist/popups-profile.test.d.ts +0 -2
  45. package/dist/popups-profile.test.d.ts.map +0 -1
  46. package/dist/popups-profile.test.js +0 -170
  47. package/dist/popups-profile.test.js.map +0 -1
  48. package/dist/see-act.test.d.ts +0 -2
  49. package/dist/see-act.test.d.ts.map +0 -1
  50. package/dist/see-act.test.js +0 -152
  51. package/dist/see-act.test.js.map +0 -1
  52. package/dist/selector.test.d.ts +0 -2
  53. package/dist/selector.test.d.ts.map +0 -1
  54. package/dist/selector.test.js +0 -34
  55. package/dist/selector.test.js.map +0 -1
  56. package/dist/stable-dom.test.d.ts +0 -2
  57. package/dist/stable-dom.test.d.ts.map +0 -1
  58. package/dist/stable-dom.test.js +0 -22
  59. package/dist/stable-dom.test.js.map +0 -1
@@ -1,152 +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
- * The see/act loop is the thing that was broken: a caller could read a snapshot
12
- * but had no way to turn what it saw into a target it could act on. These tests
13
- * drive a real page, so they fail if the emitted selector does not address the
14
- * element it was reported for.
15
- */
16
- const PAGE = `<!doctype html><html><head><title>See act</title></head><body>
17
- <form id="login">
18
- <input name="email" placeholder="Email">
19
- <input name="password" type="password">
20
- <button type="submit" data-testid="submit"> Sign in </button>
21
- </form>
22
- <div><span>Total</span><section id="cart"><p>2 items</p></section></div>
23
- <button disabled>Locked</button>
24
- </body></html>`;
25
- const roots = [];
26
- const servers = [];
27
- afterEach(async () => {
28
- await Promise.all(servers.splice(0).map((server) => new Promise((done) => {
29
- server.close(() => done());
30
- })));
31
- await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
32
- });
33
- async function fixture() {
34
- const executablePath = await detectBrowserExecutable();
35
- if (executablePath === undefined)
36
- return undefined;
37
- const server = createServer((_request, response) => {
38
- response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
39
- response.end(PAGE);
40
- });
41
- servers.push(server);
42
- await new Promise((done) => {
43
- server.listen(0, "127.0.0.1", done);
44
- });
45
- const address = server.address();
46
- if (address === null || typeof address === "string") {
47
- throw new Error("fixture_server_address_unavailable");
48
- }
49
- const root = await mkdtemp(join(tmpdir(), "melra-see-act-"));
50
- roots.push(root);
51
- return {
52
- runtime: new BrowserRuntime({
53
- workspaceRoot: root,
54
- artifactDirectory: join(root, "artifacts"),
55
- executablePath,
56
- allowedDomains: ["127.0.0.1"],
57
- allowLocalhost: true,
58
- }),
59
- url: `http://127.0.0.1:${address.port}`,
60
- };
61
- }
62
- describe("browser see/act loop", () => {
63
- it("emits a selector that addresses the element it was reported for", async () => {
64
- const context = await fixture();
65
- if (context === undefined)
66
- return;
67
- const { runtime, url } = context;
68
- try {
69
- const observed = await runtime.execute(BrowserOperationSchema.parse({ kind: "browser", action: "navigate", url }));
70
- const elements = observed.elements;
71
- const submit = elements.find((item) => item.testId === "submit");
72
- expect(submit?.selector).toBe('[data-testid="submit"]');
73
- const email = elements.find((item) => item.attributeName === "email");
74
- // Anchored on the form's id rather than a path from <html>.
75
- expect(email?.selector).toBe("#login > input:nth-child(1)");
76
- expect(email?.placeholder).toBe("Email");
77
- expect(elements.find((item) => item.name === "Locked")?.disabled).toBe(true);
78
- expect(elements.every((item) => typeof item.index === "number")).toBe(true);
79
- // The loop closes only if the selector can be acted on.
80
- const typed = await runtime.execute(BrowserOperationSchema.parse({
81
- kind: "browser",
82
- action: "type",
83
- target: { selector: email.selector },
84
- value: "user@example.com",
85
- }));
86
- expect(typed.typed).toBe(true);
87
- const after = (await runtime.execute(BrowserOperationSchema.parse({ kind: "browser", action: "inspect" }))).elements.find((item) => item.attributeName === "email");
88
- expect(after?.value).toBe("user@example.com");
89
- }
90
- finally {
91
- await runtime.close();
92
- }
93
- }, 120_000);
94
- it("matches text through surrounding whitespace instead of failing exact", async () => {
95
- const context = await fixture();
96
- if (context === undefined)
97
- return;
98
- const { runtime, url } = context;
99
- try {
100
- await runtime.execute(BrowserOperationSchema.parse({ kind: "browser", action: "navigate", url }));
101
- // `<button> Sign in </button>` never matched `getByText("Sign in", {exact:true})`.
102
- const clicked = await runtime.execute(BrowserOperationSchema.parse({
103
- kind: "browser",
104
- action: "click",
105
- target: { text: "Sign in" },
106
- }));
107
- expect(clicked.clicked).toBe(true);
108
- }
109
- finally {
110
- await runtime.close();
111
- }
112
- }, 120_000);
113
- it("reports a target that matches nothing instead of timing out opaquely", async () => {
114
- const context = await fixture();
115
- if (context === undefined)
116
- return;
117
- const { runtime, url } = context;
118
- try {
119
- await runtime.execute(BrowserOperationSchema.parse({ kind: "browser", action: "navigate", url }));
120
- await expect(runtime.execute(BrowserOperationSchema.parse({
121
- kind: "browser",
122
- action: "click",
123
- target: { selector: "#nothing-here" },
124
- timeoutMs: 120_000,
125
- }))).rejects.toThrow("browser_target_not_found");
126
- }
127
- finally {
128
- await runtime.close();
129
- }
130
- }, 120_000);
131
- it("scopes extraction to a target rather than returning the whole page", async () => {
132
- const context = await fixture();
133
- if (context === undefined)
134
- return;
135
- const { runtime, url } = context;
136
- try {
137
- await runtime.execute(BrowserOperationSchema.parse({ kind: "browser", action: "navigate", url }));
138
- const extracted = await runtime.execute(BrowserOperationSchema.parse({
139
- kind: "browser",
140
- action: "inspect",
141
- target: { selector: "#cart" },
142
- }));
143
- expect(extracted.text).toBe("2 items");
144
- expect(extracted.html).toBe("<p>2 items</p>");
145
- expect(extracted.text).not.toContain("Total");
146
- }
147
- finally {
148
- await runtime.close();
149
- }
150
- }, 120_000);
151
- });
152
- //# sourceMappingURL=see-act.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"see-act.test.js","sourceRoot":"","sources":["../src/see-act.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=selector.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"selector.test.d.ts","sourceRoot":"","sources":["../src/selector.test.ts"],"names":[],"mappings":""}
@@ -1,34 +0,0 @@
1
- // Copyright 2026 XAGI Labs Private Limited
2
- // SPDX-License-Identifier: Apache-2.0
3
- import { describe, expect, it } from "vitest";
4
- import { buildSelector } from "./selector.js";
5
- describe("buildSelector", () => {
6
- it("anchors on an id when the page provides one", () => {
7
- expect(buildSelector([
8
- { tag: "form", nth: 2, id: "login" },
9
- { tag: "input", nth: 3 },
10
- ])).toBe("#login > input:nth-child(3)");
11
- });
12
- it("prefers a test id over positional descent", () => {
13
- expect(buildSelector([
14
- { tag: "div", nth: 1, testId: "cart" },
15
- { tag: "button", nth: 2 },
16
- ])).toBe('[data-testid="cart"] > button:nth-child(2)');
17
- });
18
- it("falls back to a positional path when nothing is labelled", () => {
19
- expect(buildSelector([
20
- { tag: "html", nth: 1 },
21
- { tag: "body", nth: 2 },
22
- { tag: "a", nth: 5 },
23
- ])).toBe("html:nth-child(1) > body:nth-child(2) > a:nth-child(5)");
24
- });
25
- it("quotes an id that is not a bare CSS identifier", () => {
26
- // Frameworks emit ids like `:r1:` and `user.email`, which `#id` cannot spell.
27
- expect(buildSelector([{ tag: "input", nth: 1, id: ":r1:" }])).toBe('[id=":r1:"]');
28
- expect(buildSelector([{ tag: "input", nth: 1, id: 'a"b' }])).toBe('[id="a\\"b"]');
29
- });
30
- it("refuses an empty chain rather than emitting a selector matching everything", () => {
31
- expect(() => buildSelector([])).toThrow("browser_selector_requires_chain");
32
- });
33
- });
34
- //# sourceMappingURL=selector.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"selector.test.js","sourceRoot":"","sources":["../src/selector.test.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,sCAAsC;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CACJ,aAAa,CAAC;YACZ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE;YACpC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE;SACzB,CAAC,CACH,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CACJ,aAAa,CAAC;YACZ,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE;YACtC,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE;SAC1B,CAAC,CACH,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CACJ,aAAa,CAAC;YACZ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE;YACvB,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE;YACvB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;SACrB,CAAC,CACH,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,8EAA8E;QAC9E,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAChE,aAAa,CACd,CAAC;QACF,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAC/D,cAAc,CACf,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=stable-dom.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stable-dom.test.d.ts","sourceRoot":"","sources":["../src/stable-dom.test.ts"],"names":[],"mappings":""}
@@ -1,22 +0,0 @@
1
- // Copyright 2026 XAGI Labs Private Limited
2
- // SPDX-License-Identifier: Apache-2.0
3
- import { describe, expect, it } from "vitest";
4
- import { normalizeDomStabilityOptions } from "./stable-dom.js";
5
- describe("DOM stability options", () => {
6
- it("applies bounded defaults", () => {
7
- expect(normalizeDomStabilityOptions()).toEqual({
8
- quietWindowMs: 180,
9
- timeoutMs: 1_500,
10
- });
11
- });
12
- it("keeps the timeout at or above the quiet window", () => {
13
- expect(normalizeDomStabilityOptions({
14
- quietWindowMs: 900,
15
- timeoutMs: 100,
16
- })).toEqual({
17
- quietWindowMs: 900,
18
- timeoutMs: 900,
19
- });
20
- });
21
- });
22
- //# sourceMappingURL=stable-dom.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stable-dom.test.js","sourceRoot":"","sources":["../src/stable-dom.test.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,sCAAsC;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAE/D,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,4BAA4B,EAAE,CAAC,CAAC,OAAO,CAAC;YAC7C,aAAa,EAAE,GAAG;YAClB,SAAS,EAAE,KAAK;SACjB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CACJ,4BAA4B,CAAC;YAC3B,aAAa,EAAE,GAAG;YAClB,SAAS,EAAE,GAAG;SACf,CAAC,CACH,CAAC,OAAO,CAAC;YACR,aAAa,EAAE,GAAG;YAClB,SAAS,EAAE,GAAG;SACf,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}