execbro 2.9.2 → 2.9.4
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/README.md +12 -8
- package/build/__tests__/unit/apiOriginPin.test.d.ts +2 -0
- package/build/__tests__/unit/apiOriginPin.test.d.ts.map +1 -0
- package/build/__tests__/unit/apiOriginPin.test.js +50 -0
- package/build/__tests__/unit/apiOriginPin.test.js.map +1 -0
- package/build/__tests__/unit/licenseGrace.test.js +34 -0
- package/build/__tests__/unit/licenseGrace.test.js.map +1 -1
- package/build/__tests__/unit/passiveConnectionBanner.test.d.ts +2 -0
- package/build/__tests__/unit/passiveConnectionBanner.test.d.ts.map +1 -0
- package/build/__tests__/unit/passiveConnectionBanner.test.js +49 -0
- package/build/__tests__/unit/passiveConnectionBanner.test.js.map +1 -0
- package/build/__tests__/unit/planExpiryFormat.test.d.ts +2 -0
- package/build/__tests__/unit/planExpiryFormat.test.d.ts.map +1 -0
- package/build/__tests__/unit/planExpiryFormat.test.js +23 -0
- package/build/__tests__/unit/planExpiryFormat.test.js.map +1 -0
- package/build/__tests__/unit/pressablesSwitch.test.d.ts +2 -0
- package/build/__tests__/unit/pressablesSwitch.test.d.ts.map +1 -0
- package/build/__tests__/unit/pressablesSwitch.test.js +86 -0
- package/build/__tests__/unit/pressablesSwitch.test.js.map +1 -0
- package/build/__tests__/unit/reduxBatchDispatch.test.d.ts +2 -0
- package/build/__tests__/unit/reduxBatchDispatch.test.d.ts.map +1 -0
- package/build/__tests__/unit/reduxBatchDispatch.test.js +51 -0
- package/build/__tests__/unit/reduxBatchDispatch.test.js.map +1 -0
- package/build/__tests__/unit/requestDetailsInclude.test.d.ts +2 -0
- package/build/__tests__/unit/requestDetailsInclude.test.d.ts.map +1 -0
- package/build/__tests__/unit/requestDetailsInclude.test.js +46 -0
- package/build/__tests__/unit/requestDetailsInclude.test.js.map +1 -0
- package/build/__tests__/unit/screenStateSwitch.test.d.ts +2 -0
- package/build/__tests__/unit/screenStateSwitch.test.d.ts.map +1 -0
- package/build/__tests__/unit/screenStateSwitch.test.js +34 -0
- package/build/__tests__/unit/screenStateSwitch.test.js.map +1 -0
- package/build/__tests__/unit/sheetOffset.test.d.ts +2 -0
- package/build/__tests__/unit/sheetOffset.test.d.ts.map +1 -0
- package/build/__tests__/unit/sheetOffset.test.js +47 -0
- package/build/__tests__/unit/sheetOffset.test.js.map +1 -0
- package/build/__tests__/unit/usageCache.test.js +17 -0
- package/build/__tests__/unit/usageCache.test.js.map +1 -1
- package/build/__tests__/unit/usageGate.test.js +28 -0
- package/build/__tests__/unit/usageGate.test.js.map +1 -1
- package/build/core/config.d.ts +9 -0
- package/build/core/config.d.ts.map +1 -1
- package/build/core/config.js +19 -1
- package/build/core/config.js.map +1 -1
- package/build/core/connection.d.ts +1 -0
- package/build/core/connection.d.ts.map +1 -1
- package/build/core/connection.js +9 -0
- package/build/core/connection.js.map +1 -1
- package/build/core/guides.d.ts.map +1 -1
- package/build/core/guides.js +38 -3
- package/build/core/guides.js.map +1 -1
- package/build/core/index.d.ts +1 -1
- package/build/core/index.d.ts.map +1 -1
- package/build/core/index.js +1 -1
- package/build/core/index.js.map +1 -1
- package/build/core/injected/sheetOffset.d.ts +13 -0
- package/build/core/injected/sheetOffset.d.ts.map +1 -0
- package/build/core/injected/sheetOffset.js +37 -0
- package/build/core/injected/sheetOffset.js.map +1 -0
- package/build/core/inspector.d.ts.map +1 -1
- package/build/core/inspector.js +55 -3
- package/build/core/inspector.js.map +1 -1
- package/build/core/license.d.ts +1 -0
- package/build/core/license.d.ts.map +1 -1
- package/build/core/license.js +2 -0
- package/build/core/license.js.map +1 -1
- package/build/core/measureComponent.d.ts.map +1 -1
- package/build/core/measureComponent.js +49 -13
- package/build/core/measureComponent.js.map +1 -1
- package/build/core/network.d.ts +2 -0
- package/build/core/network.d.ts.map +1 -1
- package/build/core/network.js +23 -8
- package/build/core/network.js.map +1 -1
- package/build/core/pressables.d.ts.map +1 -1
- package/build/core/pressables.js +113 -10
- package/build/core/pressables.js.map +1 -1
- package/build/core/redux.d.ts +1 -1
- package/build/core/redux.d.ts.map +1 -1
- package/build/core/redux.js +4 -3
- package/build/core/redux.js.map +1 -1
- package/build/core/screenLayout.d.ts.map +1 -1
- package/build/core/screenLayout.js +50 -0
- package/build/core/screenLayout.js.map +1 -1
- package/build/core/screenState.d.ts +2 -0
- package/build/core/screenState.d.ts.map +1 -1
- package/build/core/screenState.js +111 -7
- package/build/core/screenState.js.map +1 -1
- package/build/core/swipeDiagnosis.d.ts.map +1 -1
- package/build/core/swipeDiagnosis.js +31 -2
- package/build/core/swipeDiagnosis.js.map +1 -1
- package/build/index.js +11 -0
- package/build/index.js.map +1 -1
- package/build/pro/tap.d.ts +14 -0
- package/build/pro/tap.d.ts.map +1 -1
- package/build/pro/tap.js +54 -1
- package/build/pro/tap.js.map +1 -1
- package/build/pro/usageGate.d.ts.map +1 -1
- package/build/pro/usageGate.js +7 -0
- package/build/pro/usageGate.js.map +1 -1
- package/build/tools/componentTools.js +1 -1
- package/build/tools/componentTools.js.map +1 -1
- package/build/tools/interactionTools.js +1 -1
- package/build/tools/interactionTools.js.map +1 -1
- package/build/tools/logTools.d.ts.map +1 -1
- package/build/tools/logTools.js +3 -9
- package/build/tools/logTools.js.map +1 -1
- package/build/tools/metaTools.d.ts +1 -0
- package/build/tools/metaTools.d.ts.map +1 -1
- package/build/tools/metaTools.js +9 -5
- package/build/tools/metaTools.js.map +1 -1
- package/build/tools/networkTools.d.ts.map +1 -1
- package/build/tools/networkTools.js +11 -12
- package/build/tools/networkTools.js.map +1 -1
- package/build/tools/reduxTools.d.ts.map +1 -1
- package/build/tools/reduxTools.js +5 -3
- package/build/tools/reduxTools.js.map +1 -1
- package/package.json +15 -4
- package/tools.json +1 -0
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ ExecBro is the runtime bridge between your AI coding assistant and your running
|
|
|
17
17
|
1. [Setup ExecBro as an MCP server for your agent of choice](#setup)
|
|
18
18
|
2. [Setup UI automation helpers](docs/setup.md#ios-simulator--ui-automation-setup)
|
|
19
19
|
3. [Install the SDK in your React Native app](#install-the-sdk-recommended) — optional, but recommended for the most robust log, network, and state experience
|
|
20
|
-
4. [Authorize and link to the web dashboard](#see-your-usage--execbrocom) — optional for usage stats and session history
|
|
20
|
+
4. [Authorize and link to the web dashboard](#see-your-usage--execbrocom) — optional, for usage stats and session history
|
|
21
21
|
5. Start your React Native app (`npm start` / `expo start`)
|
|
22
22
|
6. [Ask your AI assistant](#usage) in plain language — e.g. "Connect to the simulator and investigate what caused the error on the screen"
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@ ExecBro is the runtime bridge between your AI coding assistant and your running
|
|
|
25
25
|
|
|
26
26
|
Log in at **[execbro.com](https://execbro.com)** to see your ExecBro activity rendered back to you: which tools you use most, tool **error rates**, and your **session history** — so you can spot flaky tools, track usage over time, and understand how your agent drives the app across sessions. It's built from the same anonymous telemetry described in [Telemetry & Privacy](#telemetry--privacy), tied to your installation ID.
|
|
27
27
|
|
|
28
|
-
Linking
|
|
28
|
+
Linking is also how [ExecBro Pro](#pricing) attaches to your installation, if you ever subscribe.
|
|
29
29
|
|
|
30
30
|
## Features
|
|
31
31
|
|
|
@@ -70,11 +70,13 @@ Linking your installation here is also **required to unlock [ExecBro Pro](#prici
|
|
|
70
70
|
Add ExecBro to Claude Code in one command — no installation, `npx` fetches the latest version on demand:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
claude mcp add execbro --scope
|
|
73
|
+
claude mcp add execbro --scope project -- npx -y execbro@latest
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
Then fully restart the client (quit and relaunch) so it picks up the new server.
|
|
77
77
|
|
|
78
|
+
Project scope writes a `.mcp.json` you can commit, so the whole team picks ExecBro up in this repo and nowhere else. Swap `project` for `user` to register it globally instead — convenient if you work in React Native all day, but it starts ExecBro in every session you open, including repos with no Metro server to connect to.
|
|
79
|
+
|
|
78
80
|
**Using a different client or need platform setup?** The [full setup guide](docs/setup.md) covers Claude Desktop, Codex CLI, Cursor, VS Code Copilot, Windsurf, Zed, and Gemini CLI, plus [Android](docs/setup.md#android) and [iOS simulator UI automation](docs/setup.md#ios-simulator--ui-automation-setup) requirements.
|
|
79
81
|
|
|
80
82
|
## Install the SDK (recommended)
|
|
@@ -204,12 +206,14 @@ See the [full tool reference](docs/tools.md) for all tools with descriptions. Ke
|
|
|
204
206
|
|
|
205
207
|
## Telemetry & Privacy
|
|
206
208
|
|
|
207
|
-
|
|
209
|
+
**No source code, file paths, or app content is ever sent.** Your app and your repo stay on your machine.
|
|
210
|
+
|
|
211
|
+
ExecBro sends two small signals:
|
|
208
212
|
|
|
209
|
-
- **
|
|
210
|
-
- **
|
|
213
|
+
- **Product analytics** (optional) — tool names, success/failure, and durations. This is what powers your [usage dashboard](#see-your-usage--execbrocom) and tells me which tools are flaky and worth fixing. Turn it off any time with `EXECBRO_TELEMETRY=false` in your MCP server config.
|
|
214
|
+
- **Usage count** — a running tally of how many tool calls you've made, so the free tier knows where you stand against its monthly allowance. It's a number, not content, and it's the one signal that keeps running when analytics is off.
|
|
211
215
|
|
|
212
|
-
See the [Telemetry & Data Collection guide](docs/telemetry.md) for the full
|
|
216
|
+
See the [Telemetry & Data Collection guide](docs/telemetry.md) for the full field-by-field breakdown, and [PRIVACY.md](./PRIVACY.md) for the complete privacy policy.
|
|
213
217
|
|
|
214
218
|
## Supported React Native Versions
|
|
215
219
|
|
|
@@ -223,7 +227,7 @@ See the [Telemetry & Data Collection guide](docs/telemetry.md) for the full brea
|
|
|
223
227
|
|
|
224
228
|
## Pricing
|
|
225
229
|
|
|
226
|
-
ExecBro is **free
|
|
230
|
+
ExecBro is **free** — every tool, full power, no feature gates, no account needed to start. The free tier covers **600 tool calls a month**, which is evaluation plus everyday debugging; most people never reach it. If you drive your agent hard all day, **ExecBro Pro** ($8.99/mo) lifts the cap and includes every hosted feature as it ships. See [execbro.com/pricing](https://execbro.com/pricing).
|
|
227
231
|
|
|
228
232
|
> [!NOTE]
|
|
229
233
|
> **Grandfather notice:** the 600-call monthly cap starts applying **2026-08-01** for new installs. If you already had ExecBro installed before then, you get a free month on top — your cap doesn't start until **2026-08-31**. You'll also see this as an in-app notice. No action needed unless you want to [link your account and upgrade to Pro](#see-your-usage--execbrocom) ahead of time. Questions? [zigor535@gmail.com](mailto:zigor535@gmail.com).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiOriginPin.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/apiOriginPin.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, it, expect } from "@jest/globals";
|
|
2
|
+
import { resolveApiBaseUrl } from "../../core/config.js";
|
|
3
|
+
const PROD = "https://execbro.com";
|
|
4
|
+
const LOCAL = "http://localhost:3000";
|
|
5
|
+
const FAKE = "http://localhost:9999";
|
|
6
|
+
describe("resolveApiBaseUrl", () => {
|
|
7
|
+
it("published build ignores the EXECBRO_API_URL override", () => {
|
|
8
|
+
const r = resolveApiBaseUrl({ envUrl: FAKE, published: true, devMode: false });
|
|
9
|
+
expect(r.url).toBe(PROD);
|
|
10
|
+
expect(r.overrideIgnored).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
it("published build ignores the config.json apiUrl override", () => {
|
|
13
|
+
const r = resolveApiBaseUrl({ configUrl: FAKE, published: true, devMode: false });
|
|
14
|
+
expect(r.url).toBe(PROD);
|
|
15
|
+
expect(r.overrideIgnored).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
it("published build with no override uses production silently", () => {
|
|
18
|
+
const r = resolveApiBaseUrl({ published: true, devMode: false });
|
|
19
|
+
expect(r.url).toBe(PROD);
|
|
20
|
+
expect(r.overrideIgnored).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
it("source checkout honors the env override", () => {
|
|
23
|
+
const r = resolveApiBaseUrl({ envUrl: FAKE, published: false, devMode: false });
|
|
24
|
+
expect(r.url).toBe(FAKE);
|
|
25
|
+
expect(r.overrideIgnored).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
it("source checkout honors the config.json override", () => {
|
|
28
|
+
const r = resolveApiBaseUrl({ configUrl: FAKE, published: false, devMode: false });
|
|
29
|
+
expect(r.url).toBe(FAKE);
|
|
30
|
+
expect(r.overrideIgnored).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
it("env override wins over config.json in a checkout", () => {
|
|
33
|
+
const r = resolveApiBaseUrl({ envUrl: FAKE, configUrl: "http://other", published: false, devMode: false });
|
|
34
|
+
expect(r.url).toBe(FAKE);
|
|
35
|
+
});
|
|
36
|
+
it("dev-server.sh case: checkout, --http, env pinned to production", () => {
|
|
37
|
+
const r = resolveApiBaseUrl({ envUrl: PROD, published: false, devMode: true });
|
|
38
|
+
expect(r.url).toBe(PROD);
|
|
39
|
+
expect(r.overrideIgnored).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
it("checkout in --http mode with no override defaults to localhost", () => {
|
|
42
|
+
const r = resolveApiBaseUrl({ published: false, devMode: true });
|
|
43
|
+
expect(r.url).toBe(LOCAL);
|
|
44
|
+
});
|
|
45
|
+
it("empty-string overrides are treated as absent, not as a redirect", () => {
|
|
46
|
+
expect(resolveApiBaseUrl({ envUrl: "", published: true, devMode: false }).overrideIgnored).toBe(false);
|
|
47
|
+
expect(resolveApiBaseUrl({ envUrl: "", published: false, devMode: false }).url).toBe(PROD);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=apiOriginPin.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiOriginPin.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/apiOriginPin.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,4 +56,38 @@ describe("computeOfflineUsage (fail-closed after grace)", () => {
|
|
|
56
56
|
expect(computeOfflineUsage(cached, laterMonth).canUse).toBe(true);
|
|
57
57
|
});
|
|
58
58
|
});
|
|
59
|
+
describe("revoked verdict offline", () => {
|
|
60
|
+
it("past grace: a flagged verdict keeps blocking even though used < limit", () => {
|
|
61
|
+
const cached = base({
|
|
62
|
+
used: 0,
|
|
63
|
+
canUse: false,
|
|
64
|
+
blockReason: "flagged",
|
|
65
|
+
verdictFreshUntil: new Date(NOW - 1000).toISOString(),
|
|
66
|
+
});
|
|
67
|
+
expect(computeOfflineUsage(cached, NOW).canUse).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
it("a flagged verdict is not cleared by a month rollover", () => {
|
|
70
|
+
const cached = base({
|
|
71
|
+
used: 0,
|
|
72
|
+
canUse: false,
|
|
73
|
+
blockReason: "flagged",
|
|
74
|
+
monthKey: "2001-08",
|
|
75
|
+
verdictFreshUntil: new Date(NOW - 1000).toISOString(),
|
|
76
|
+
});
|
|
77
|
+
expect(computeOfflineUsage(cached, NOW).canUse).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
it("the reason survives so the offline message stays correct", () => {
|
|
80
|
+
const cached = base({
|
|
81
|
+
used: 0,
|
|
82
|
+
canUse: false,
|
|
83
|
+
blockReason: "flagged",
|
|
84
|
+
verdictFreshUntil: new Date(NOW - 1000).toISOString(),
|
|
85
|
+
});
|
|
86
|
+
expect(computeOfflineUsage(cached, NOW).blockReason).toBe("flagged");
|
|
87
|
+
});
|
|
88
|
+
it("a cap verdict is unaffected: past grace and under cap still allows", () => {
|
|
89
|
+
const cached = base({ used: 100, canUse: true, verdictFreshUntil: new Date(NOW - 1000).toISOString() });
|
|
90
|
+
expect(computeOfflineUsage(cached, NOW).canUse).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
59
93
|
//# sourceMappingURL=licenseGrace.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"licenseGrace.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/licenseGrace.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"licenseGrace.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/licenseGrace.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passiveConnectionBanner.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/passiveConnectionBanner.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "@jest/globals";
|
|
2
|
+
import { connectedApps, clearAllCDPMessageTimes, updateLastCDPMessageTime } from "../../core/state.js";
|
|
3
|
+
import { markContextStale, initContextHealth, clearContextHealth } from "../../core/connectionState.js";
|
|
4
|
+
import { passiveConnectionBanner } from "../../core/connection.js";
|
|
5
|
+
const APP_KEY = "8081-device1";
|
|
6
|
+
function connect() {
|
|
7
|
+
connectedApps.set(APP_KEY, {
|
|
8
|
+
ws: { readyState: 1 },
|
|
9
|
+
port: 8081,
|
|
10
|
+
platform: "ios",
|
|
11
|
+
deviceInfo: { id: "device1", title: "iPhone", deviceName: "iPhone" }
|
|
12
|
+
});
|
|
13
|
+
initContextHealth(APP_KEY);
|
|
14
|
+
}
|
|
15
|
+
describe("passiveConnectionBanner", () => {
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
connectedApps.clear();
|
|
18
|
+
clearAllCDPMessageTimes();
|
|
19
|
+
clearContextHealth(APP_KEY);
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
connectedApps.clear();
|
|
23
|
+
clearAllCDPMessageTimes();
|
|
24
|
+
});
|
|
25
|
+
it("says nothing while the connection is healthy", () => {
|
|
26
|
+
connect();
|
|
27
|
+
updateLastCDPMessageTime(APP_KEY, new Date());
|
|
28
|
+
expect(passiveConnectionBanner()).toBe("");
|
|
29
|
+
});
|
|
30
|
+
it("reports a genuinely absent socket as disconnected", () => {
|
|
31
|
+
expect(passiveConnectionBanner()).toContain("Disconnected");
|
|
32
|
+
});
|
|
33
|
+
it("does not claim disconnection from an inferred stale context", () => {
|
|
34
|
+
connect();
|
|
35
|
+
updateLastCDPMessageTime(APP_KEY, new Date());
|
|
36
|
+
markContextStale(APP_KEY);
|
|
37
|
+
const banner = passiveConnectionBanner();
|
|
38
|
+
expect(banner).not.toContain("Disconnected");
|
|
39
|
+
expect(banner).toContain("Status unknown");
|
|
40
|
+
expect(banner).toContain("ensure_connection");
|
|
41
|
+
});
|
|
42
|
+
it("does not claim disconnection merely because no CDP traffic was recorded", () => {
|
|
43
|
+
connect();
|
|
44
|
+
const banner = passiveConnectionBanner();
|
|
45
|
+
expect(banner).not.toContain("Disconnected");
|
|
46
|
+
expect(banner).toContain("no_activity");
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=passiveConnectionBanner.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passiveConnectionBanner.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/passiveConnectionBanner.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AACvG,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxG,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAWnE,MAAM,OAAO,GAAG,cAAc,CAAC;AAE/B,SAAS,OAAO;IACZ,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE;QACvB,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE;QACrB,IAAI,EAAE,IAAI;QACV,QAAQ,EAAE,KAAK;QACf,UAAU,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE;KAC5C,CAAC,CAAC;IAC9B,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACrC,UAAU,CAAC,GAAG,EAAE;QACZ,aAAa,CAAC,KAAK,EAAE,CAAC;QACtB,uBAAuB,EAAE,CAAC;QAC1B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACX,aAAa,CAAC,KAAK,EAAE,CAAC;QACtB,uBAAuB,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACpD,OAAO,EAAE,CAAC;QACV,wBAAwB,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,CAAC,uBAAuB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,uBAAuB,EAAE,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACnE,OAAO,EAAE,CAAC;QACV,wBAAwB,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QAC9C,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAE1B,MAAM,MAAM,GAAG,uBAAuB,EAAE,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QAC/E,OAAO,EAAE,CAAC;QAEV,MAAM,MAAM,GAAG,uBAAuB,EAAE,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planExpiryFormat.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/planExpiryFormat.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, it, expect } from "@jest/globals";
|
|
2
|
+
import { formatPlanExpiry } from "../../tools/metaTools.js";
|
|
3
|
+
describe("formatPlanExpiry", () => {
|
|
4
|
+
it("formats a valid ISO string", () => {
|
|
5
|
+
expect(formatPlanExpiry("2027-01-01T00:00:00.000Z")).not.toBeNull();
|
|
6
|
+
});
|
|
7
|
+
it("returns null for null, so the line is omitted rather than printed as the epoch", () => {
|
|
8
|
+
expect(formatPlanExpiry(null)).toBeNull();
|
|
9
|
+
});
|
|
10
|
+
it("returns null for undefined", () => {
|
|
11
|
+
expect(formatPlanExpiry(undefined)).toBeNull();
|
|
12
|
+
});
|
|
13
|
+
it("returns null for an object, instead of [object Object]", () => {
|
|
14
|
+
expect(formatPlanExpiry({ _seconds: 1, _nanoseconds: 0 })).toBeNull();
|
|
15
|
+
});
|
|
16
|
+
it("returns null for an unparseable string", () => {
|
|
17
|
+
expect(formatPlanExpiry("not a date")).toBeNull();
|
|
18
|
+
});
|
|
19
|
+
it("returns null for the empty string", () => {
|
|
20
|
+
expect(formatPlanExpiry("")).toBeNull();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=planExpiryFormat.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planExpiryFormat.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/planExpiryFormat.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,gBAAgB,CAAC,0BAA0B,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QAGtF,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAI9D,MAAM,CAAC,gBAAgB,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5C,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pressablesSwitch.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/pressablesSwitch.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, expect, jest, beforeEach } from "@jest/globals";
|
|
2
|
+
const evaluated = [];
|
|
3
|
+
let evalResult = null;
|
|
4
|
+
jest.unstable_mockModule("../../core/jsExecute.js", () => ({
|
|
5
|
+
executeInApp: async (expression) => {
|
|
6
|
+
evaluated.push(expression);
|
|
7
|
+
return { success: true, result: JSON.stringify(evalResult) };
|
|
8
|
+
},
|
|
9
|
+
delay: async () => { }
|
|
10
|
+
}));
|
|
11
|
+
const { pressElement } = await import("../../core/pressables.js");
|
|
12
|
+
function fiber(props, type = "View", children = []) {
|
|
13
|
+
const node = {
|
|
14
|
+
type,
|
|
15
|
+
memoizedProps: props,
|
|
16
|
+
stateNode: { measureInWindow: (cb) => cb(10, 20, 100, 50) },
|
|
17
|
+
child: null,
|
|
18
|
+
sibling: null,
|
|
19
|
+
return: null
|
|
20
|
+
};
|
|
21
|
+
let prev = null;
|
|
22
|
+
for (const c of children) {
|
|
23
|
+
c.return = node;
|
|
24
|
+
if (prev)
|
|
25
|
+
prev.sibling = c;
|
|
26
|
+
else
|
|
27
|
+
node.child = c;
|
|
28
|
+
prev = c;
|
|
29
|
+
}
|
|
30
|
+
return node;
|
|
31
|
+
}
|
|
32
|
+
async function search(options, root) {
|
|
33
|
+
evaluated.length = 0;
|
|
34
|
+
evalResult = { dispatched: 1 };
|
|
35
|
+
await pressElement(options);
|
|
36
|
+
const globalThisStub = {
|
|
37
|
+
__REACT_DEVTOOLS_GLOBAL_HOOK__: {
|
|
38
|
+
getFiberRoots: () => new Set([{ current: root }]),
|
|
39
|
+
renderers: new Map()
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
let last = null;
|
|
43
|
+
for (const expression of evaluated) {
|
|
44
|
+
const fn = new Function("globalThis", `return (${expression.trim()});`);
|
|
45
|
+
last = fn(globalThisStub);
|
|
46
|
+
}
|
|
47
|
+
return typeof last === "string" ? JSON.parse(last) : last;
|
|
48
|
+
}
|
|
49
|
+
describe("fiber search and Switch elements", () => {
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
evaluated.length = 0;
|
|
52
|
+
});
|
|
53
|
+
const switchTree = (value) => fiber({}, "View", [
|
|
54
|
+
fiber({ children: "Push notifications" }, "Text"),
|
|
55
|
+
fiber({ testID: "settings-push", onValueChange: () => { }, value }, "Switch", [
|
|
56
|
+
fiber({}, "RCTSwitch")
|
|
57
|
+
])
|
|
58
|
+
]);
|
|
59
|
+
it("resolves a switch by testID even though it has no onPress", async () => {
|
|
60
|
+
const out = await search({ testID: "settings-push" }, switchTree(false));
|
|
61
|
+
expect(out.needsNativeTap).toBe(true);
|
|
62
|
+
expect(out.switchValue).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
it("reports the value the caller is about to change", async () => {
|
|
65
|
+
const out = await search({ testID: "settings-push" }, switchTree(true));
|
|
66
|
+
expect(out.switchValue).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
it("resolves a Switch that carries no handler at all", async () => {
|
|
69
|
+
const root = fiber({}, "View", [
|
|
70
|
+
fiber({ children: "Sponsor" }, "Text"),
|
|
71
|
+
fiber({ value: false }, { name: "Switch" }, [fiber({}, "RCTSwitch")])
|
|
72
|
+
]);
|
|
73
|
+
const out = await search({ component: "Switch" }, root);
|
|
74
|
+
expect(out.needsNativeTap).toBe(true);
|
|
75
|
+
expect(out.switchValue).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
it("leaves switchValue null for an ordinary button", async () => {
|
|
78
|
+
const root = fiber({}, "View", [
|
|
79
|
+
fiber({ testID: "save", onPress: () => { } }, "View", [fiber({ children: "Save" }, "Text")])
|
|
80
|
+
]);
|
|
81
|
+
const out = await search({ testID: "save" }, root);
|
|
82
|
+
expect(out.needsNativeTap).toBe(true);
|
|
83
|
+
expect(out.switchValue).toBeNull();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=pressablesSwitch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pressablesSwitch.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/pressablesSwitch.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reduxBatchDispatch.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/reduxBatchDispatch.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { describe, it, expect, jest } from "@jest/globals";
|
|
2
|
+
const evaluated = [];
|
|
3
|
+
jest.unstable_mockModule("../../core/executor.js", () => ({
|
|
4
|
+
executeInApp: async (expression) => {
|
|
5
|
+
evaluated.push(expression);
|
|
6
|
+
return { success: true, result: run(expression) };
|
|
7
|
+
}
|
|
8
|
+
}));
|
|
9
|
+
const dispatched = [];
|
|
10
|
+
const store = {
|
|
11
|
+
dispatch: (a) => dispatched.push(a),
|
|
12
|
+
getState: () => ({ settings: { a: 1 } }),
|
|
13
|
+
subscribe: () => { }
|
|
14
|
+
};
|
|
15
|
+
function run(expression) {
|
|
16
|
+
const globalThisStub = {
|
|
17
|
+
__REACT_DEVTOOLS_GLOBAL_HOOK__: {
|
|
18
|
+
renderers: new Map([[1, {}]]),
|
|
19
|
+
getFiberRoots: () => new Set([{ current: { type: { name: "Provider" }, memoizedProps: { store } } }])
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
return new Function("globalThis", `return (${expression.trim()});`)(globalThisStub);
|
|
23
|
+
}
|
|
24
|
+
const { reduxDispatch } = await import("../../core/redux.js");
|
|
25
|
+
describe("redux_dispatch batching", () => {
|
|
26
|
+
it("dispatches an array in order in a single round trip", async () => {
|
|
27
|
+
dispatched.length = 0;
|
|
28
|
+
evaluated.length = 0;
|
|
29
|
+
const result = await reduxDispatch({
|
|
30
|
+
action: [
|
|
31
|
+
{ type: "settings/setA", payload: false },
|
|
32
|
+
{ type: "settings/setB", payload: true }
|
|
33
|
+
],
|
|
34
|
+
returnPath: "settings"
|
|
35
|
+
});
|
|
36
|
+
expect(evaluated).toHaveLength(1);
|
|
37
|
+
expect(dispatched).toEqual([
|
|
38
|
+
{ type: "settings/setA", payload: false },
|
|
39
|
+
{ type: "settings/setB", payload: true }
|
|
40
|
+
]);
|
|
41
|
+
expect(result.success).toBe(true);
|
|
42
|
+
expect(result.state).toEqual({ a: 1 });
|
|
43
|
+
});
|
|
44
|
+
it("still accepts a single action object", async () => {
|
|
45
|
+
dispatched.length = 0;
|
|
46
|
+
const result = await reduxDispatch({ action: { type: "app/setIsLoading", payload: true } });
|
|
47
|
+
expect(dispatched).toEqual([{ type: "app/setIsLoading", payload: true }]);
|
|
48
|
+
expect(result.previousAction).toEqual({ type: "app/setIsLoading", payload: true });
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=reduxBatchDispatch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reduxBatchDispatch.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/reduxBatchDispatch.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestDetailsInclude.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/requestDetailsInclude.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it, expect } from "@jest/globals";
|
|
2
|
+
import { formatRequestDetails, redactHeaderValue } from "../../core/network.js";
|
|
3
|
+
const JWT = "Bearer " + "e".repeat(1500);
|
|
4
|
+
function request(overrides = {}) {
|
|
5
|
+
return {
|
|
6
|
+
requestId: "js-1",
|
|
7
|
+
url: "https://api.example.com/graphql",
|
|
8
|
+
method: "POST",
|
|
9
|
+
headers: { authorization: JWT, accept: "application/json" },
|
|
10
|
+
postData: JSON.stringify({ query: "query GetThings { things { id } }" }),
|
|
11
|
+
responseBody: JSON.stringify({ data: { things: [{ id: "t1" }] } }),
|
|
12
|
+
timestamp: new Date("2026-08-25T10:00:00Z"),
|
|
13
|
+
epoch: 1,
|
|
14
|
+
completed: true,
|
|
15
|
+
status: 200,
|
|
16
|
+
...overrides
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
describe("get_request_details request/response split", () => {
|
|
20
|
+
it("keeps a live token out of the transcript unless verbose asks for it", () => {
|
|
21
|
+
const out = formatRequestDetails(request(), { include: "request" });
|
|
22
|
+
expect(out).not.toContain(JWT);
|
|
23
|
+
expect(out).toContain("Bearer [redacted, 1507 chars");
|
|
24
|
+
expect(formatRequestDetails(request(), { include: "request", verbose: true })).toContain(JWT);
|
|
25
|
+
expect(redactHeaderValue("accept", "application/json")).toBe("application/json");
|
|
26
|
+
});
|
|
27
|
+
it("renders only the queried side, so narrowing does not re-dump the request", () => {
|
|
28
|
+
const out = formatRequestDetails(request(), { query: "data.things[0].id" });
|
|
29
|
+
expect(out).toContain("t1");
|
|
30
|
+
expect(out).not.toContain("Request Headers");
|
|
31
|
+
expect(out).not.toContain("Request Body");
|
|
32
|
+
expect(out).not.toContain("Response Headers");
|
|
33
|
+
expect(out).toContain('include:"both"');
|
|
34
|
+
});
|
|
35
|
+
it("still shows both sides when there is no query", () => {
|
|
36
|
+
const out = formatRequestDetails(request());
|
|
37
|
+
expect(out).toContain("Request Headers");
|
|
38
|
+
expect(out).toContain("Response Body");
|
|
39
|
+
});
|
|
40
|
+
it("honours an explicit include over the query default", () => {
|
|
41
|
+
const out = formatRequestDetails(request(), { query: "data.things[0].id", include: "both" });
|
|
42
|
+
expect(out).toContain("Request Headers");
|
|
43
|
+
expect(out).toContain("t1");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=requestDetailsInclude.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestDetailsInclude.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/requestDetailsInclude.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAGhF,MAAM,GAAG,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAEzC,SAAS,OAAO,CAAC,YAAqC,EAAE;IACpD,OAAO;QACH,SAAS,EAAE,MAAM;QACjB,GAAG,EAAE,iCAAiC;QACtC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,kBAAkB,EAAE;QAC3D,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mCAAmC,EAAE,CAAC;QACxE,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAClE,SAAS,EAAE,IAAI,IAAI,CAAC,sBAAsB,CAAC;QAC3C,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,GAAG;QACX,GAAG,SAAS;KACG,CAAC;AACxB,CAAC;AAED,QAAQ,CAAC,4CAA4C,EAAE,GAAG,EAAE;IACxD,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC3E,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QACpE,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC;QACtD,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC9F,MAAM,CAAC,iBAAiB,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAChF,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAC5E,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5B,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC7C,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAC9C,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACrD,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC1D,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAC7F,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenStateSwitch.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/screenStateSwitch.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from "@jest/globals";
|
|
2
|
+
import { formatScreenStateSummary } from "../../core/screenState.js";
|
|
3
|
+
function toggle(over = {}) {
|
|
4
|
+
return {
|
|
5
|
+
label: "Push notifications",
|
|
6
|
+
component: "Switch",
|
|
7
|
+
center: { x: 775, y: 320 },
|
|
8
|
+
bounds: { x: 745, y: 305, width: 60, height: 30 },
|
|
9
|
+
testID: "settings-push",
|
|
10
|
+
...over
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const screen = (pressables) => ({ route: null, overlays: [], pressables, texts: [], images: [] });
|
|
14
|
+
describe("get_screen_state switch reporting", () => {
|
|
15
|
+
it("lists a switch with its current value and a tappable testID", () => {
|
|
16
|
+
const out = formatScreenStateSummary(screen([toggle({ switchValue: true })]), undefined, {
|
|
17
|
+
pressablesOnly: true
|
|
18
|
+
});
|
|
19
|
+
expect(out).toContain("[switch:ON]");
|
|
20
|
+
expect(out).toContain('testID="settings-push"');
|
|
21
|
+
expect(out).toContain("(775, 320)");
|
|
22
|
+
});
|
|
23
|
+
it("distinguishes off from on", () => {
|
|
24
|
+
const out = formatScreenStateSummary(screen([toggle({ switchValue: false })]), undefined, {
|
|
25
|
+
pressablesOnly: true
|
|
26
|
+
});
|
|
27
|
+
expect(out).toContain("[switch:OFF]");
|
|
28
|
+
});
|
|
29
|
+
it("says nothing about elements that are not switches", () => {
|
|
30
|
+
const out = formatScreenStateSummary(screen([toggle({ component: "Button", switchValue: undefined })]), undefined, { pressablesOnly: true });
|
|
31
|
+
expect(out).not.toContain("[switch:");
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=screenStateSwitch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenStateSwitch.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/screenStateSwitch.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAA+C,MAAM,2BAA2B,CAAC;AAQlH,SAAS,MAAM,CAAC,OAAsC,EAAE;IACpD,OAAO;QACH,KAAK,EAAE,oBAAoB;QAC3B,SAAS,EAAE,QAAQ;QACnB,MAAM,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE;QAC1B,MAAM,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACjD,MAAM,EAAE,eAAe;QACvB,GAAG,IAAI;KACV,CAAC;AACN,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,UAAkC,EAAe,EAAE,CAC/D,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;AAEvE,QAAQ,CAAC,mCAAmC,EAAE,GAAG,EAAE;IAC/C,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACnE,MAAM,GAAG,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE;YACrF,cAAc,EAAE,IAAI;SACvB,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QACrC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;QAChD,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACjC,MAAM,GAAG,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE;YACtF,cAAc,EAAE,IAAI;SACvB,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QACzD,MAAM,GAAG,GAAG,wBAAwB,CAChC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EACjE,SAAS,EACT,EAAE,cAAc,EAAE,IAAI,EAAE,CAC3B,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheetOffset.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/sheetOffset.test.ts"],"names":[],"mappings":""}
|