@nyssance/tauri-hasgard 0.6.1 → 0.6.3
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 +70 -61
- package/dist/index.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,101 +1,110 @@
|
|
|
1
1
|
# @nyssance/tauri-hasgard
|
|
2
2
|
|
|
3
|
-
Playwright Test fixtures for real Tauri 3 Wry
|
|
3
|
+
Playwright Test fixtures for real Tauri 3 Wry applications. Playwright handles scheduling, retries, assertions, and reports; Hasgard controls native webviews through the plugin.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 1. Prepare your app
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[Register the Rust plugin and grant `hasgard:default`](https://github.com/nyssance/tauri-hasgard#register-the-plugin). Use Node.js 24 or newer and install:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
```sh
|
|
10
|
+
bun add --dev @nyssance/tauri-hasgard @playwright/test
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Set a readiness marker in your frontend **after initialization finishes**:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
document.documentElement.dataset.appReady = "true"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Hasgard waits for this marker before tests start. No Playwright browser download is needed.
|
|
20
|
+
|
|
21
|
+
## 2. Configure the fixture
|
|
22
|
+
|
|
23
|
+
Create `e2e/fixtures.ts`:
|
|
10
24
|
|
|
11
25
|
```ts
|
|
12
|
-
import {
|
|
26
|
+
import { join } from "node:path"
|
|
27
|
+
|
|
28
|
+
import { createHasgardTest, hasgardEndpointPath } from "@nyssance/tauri-hasgard"
|
|
13
29
|
import { expect as playwrightExpect, test as playwrightTest } from "@playwright/test"
|
|
14
30
|
|
|
15
31
|
export const { test, expect } = createHasgardTest({
|
|
16
32
|
test: playwrightTest,
|
|
17
33
|
expect: playwrightExpect,
|
|
18
|
-
socketPath: (workerIndex) =>
|
|
34
|
+
socketPath: (workerIndex) => hasgardEndpointPath(`my-app-${process.pid}-${workerIndex}`),
|
|
19
35
|
windowLabel: "main",
|
|
20
|
-
readySelector: '[data-app-ready="true"]',
|
|
36
|
+
readySelector: 'html[data-app-ready="true"]',
|
|
21
37
|
launch: {
|
|
22
38
|
command: "bun",
|
|
23
39
|
args: ["run", "tauri", "dev"],
|
|
24
|
-
cwd: import.meta.dirname,
|
|
40
|
+
cwd: join(import.meta.dirname, ".."),
|
|
25
41
|
timeoutMs: 120_000
|
|
26
42
|
}
|
|
27
43
|
})
|
|
28
44
|
```
|
|
29
45
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
waits for that group to exit, including children left behind by a launcher,
|
|
34
|
-
and escalates from SIGTERM to SIGKILL after five seconds. Startup failures also
|
|
35
|
-
clean up, and concurrent `stop()` calls share the same cleanup. A live endpoint
|
|
36
|
-
is rejected rather than unlinked; readiness requires a successful connection.
|
|
37
|
-
If cleanup fails, ownership is retained so `stop()` can be retried; another
|
|
38
|
-
launch is blocked until that cleanup succeeds.
|
|
39
|
-
Diagnostics retain the last 64 Ki characters per output stream with a truncation
|
|
40
|
-
marker. `await process.diagnostics()` exposes those tails and the actual exit
|
|
41
|
-
code or signal. Failed tests attach them; a failed screenshot does not replace
|
|
42
|
-
the original test error. Teardown removes the owned stale socket after its
|
|
43
|
-
process group exits, checking its identity and preserving live or replaced paths.
|
|
44
|
-
|
|
45
|
-
An independent supervisor owns the application and watches the worker's IPC
|
|
46
|
-
connection. If the worker is killed with SIGKILL, the supervisor still terminates
|
|
47
|
-
the application group and exits. Killing the supervisor itself or children that
|
|
48
|
-
deliberately create a new session or process group are outside this guarantee.
|
|
49
|
-
Attach-only fixtures do not terminate an application they did not launch.
|
|
50
|
-
|
|
51
|
-
`window.press(key)` uses native OS input and, by default, waits for a trusted
|
|
52
|
-
WebView keyup before the next press may switch windows. For OS shortcuts and
|
|
53
|
-
keys that navigate or close the document, explicitly use
|
|
54
|
-
`window.press(key, { completion: "native" })`; that mode confirms posting only.
|
|
55
|
-
Bare modifiers also use native posting completion. The active input method
|
|
56
|
-
remains in effect: use `fill` for exact text, and `Shift+m` for a shifted key.
|
|
57
|
-
|
|
58
|
-
To keep keyboard ownership until an application state is observable:
|
|
46
|
+
Use your app's actual window label and launch command. `hasgardEndpointPath` creates a Unix socket path or Windows named-pipe name. The fixture passes it to the app as `TAURI_HASGARD_SOCKET`.
|
|
47
|
+
|
|
48
|
+
Create `playwright.config.ts` in the app root:
|
|
59
49
|
|
|
60
50
|
```ts
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
51
|
+
import { defineConfig } from "@playwright/test"
|
|
52
|
+
|
|
53
|
+
export default defineConfig({
|
|
54
|
+
testDir: "./e2e",
|
|
55
|
+
workers: 1,
|
|
56
|
+
timeout: 30_000,
|
|
57
|
+
expect: { timeout: 5_000 }
|
|
64
58
|
})
|
|
65
59
|
```
|
|
66
60
|
|
|
67
|
-
|
|
68
|
-
`HasgardRpcError.data.phase` and `injected` status; never blindly retry an
|
|
69
|
-
already-injected or uncertain press. See [the wire contract](../../docs/protocol.md#native-keyboard-completion).
|
|
61
|
+
Start with one worker: development servers share ports, and native keyboard input shares desktop focus. For parallel non-keyboard tests, build a debug executable once and launch that binary per worker instead of starting several dev servers. Give each instance separate application data if your app persists state.
|
|
70
62
|
|
|
71
|
-
|
|
72
|
-
matching the plugin. Oversized requests fail before transmission. An explicit
|
|
73
|
-
null result is supported; malformed responses are rejected instead of returning
|
|
74
|
-
an invented value.
|
|
63
|
+
## 3. Write and run a test
|
|
75
64
|
|
|
76
|
-
|
|
65
|
+
Create `e2e/settings.spec.ts`. Adapt the button, window label, and heading to your UI:
|
|
77
66
|
|
|
78
67
|
```ts
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
await
|
|
83
|
-
await
|
|
68
|
+
import { expect, test } from "./fixtures"
|
|
69
|
+
|
|
70
|
+
test("opens settings", async ({ hasgard, window }) => {
|
|
71
|
+
await window.getByRole("button", { name: "Settings", exact: true }).click()
|
|
72
|
+
const settings = await hasgard.waitForWindow("settings", 5_000)
|
|
73
|
+
await expect(settings.getByRole("heading", { name: "Settings", exact: true })).toBeVisible()
|
|
84
74
|
})
|
|
85
75
|
```
|
|
86
76
|
|
|
87
|
-
|
|
77
|
+
```sh
|
|
78
|
+
bunx playwright test
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`hasgard` is a worker-scoped `HasgardApplication`; `window` selects the configured primary `HasgardWindow`. Tests in the same worker share application state. Reset data and close secondary windows in your test setup or teardown as needed.
|
|
82
|
+
|
|
83
|
+
For a complete runnable example, see the repository's [fixture app](https://github.com/nyssance/tauri-hasgard/tree/main/examples/fixture-app) and [development instructions](https://github.com/nyssance/tauri-hasgard/blob/main/CONTRIBUTING.md).
|
|
84
|
+
|
|
85
|
+
## Common operations
|
|
88
86
|
|
|
89
87
|
```ts
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
await window.getByRole("textbox", { name: "Display name", exact: true }).fill("Nyssance")
|
|
89
|
+
await window.locator('[data-testid="save"]').click()
|
|
90
|
+
await expect(window.getByRole("status")).toHaveText("Saved")
|
|
91
|
+
await window.press("Tab", {
|
|
92
|
+
waitFor: "document.activeElement.id === 'save'",
|
|
93
|
+
timeoutMs: 1_000
|
|
92
94
|
})
|
|
93
95
|
```
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
- Use `fill` for exact text. `press` sends native input through the active input method.
|
|
98
|
+
- For shortcuts that close or navigate a document, use `press(key, { completion: "native" })`; it confirms posting only. Do not blindly retry a key that may already have been injected.
|
|
99
|
+
- CSS locators use the live selector. Role locators take a fresh accessibility snapshot and require exactly one match for an action.
|
|
100
|
+
- To attach to an existing app, omit `launch` and set `socketPath` to its endpoint. Teardown leaves that app running.
|
|
101
|
+
|
|
102
|
+
## Lifecycle and limits
|
|
103
|
+
|
|
104
|
+
Managed launches are cleaned up at worker teardown and on startup failure. On macOS/Linux, a supervisor also cleans up the app's process group if the worker is killed. Children that create a separate process group, or killing the supervisor itself, are outside this guarantee.
|
|
105
|
+
|
|
106
|
+
Failed tests using the `window` fixture attach process diagnostics and a screenshot when available. Logs retain a bounded tail. Live endpoints are rejected rather than overwritten.
|
|
96
107
|
|
|
97
|
-
|
|
98
|
-
- `window.getByRole(role, query)` takes a fresh accessibility snapshot, demands exactly one match for actions, then sends its snapshot ref.
|
|
99
|
-
- `byPoint(x, y)` and `byRef(ref)` are available for low-level calls.
|
|
108
|
+
There is no `page` fixture or mocked browser mode. Use `HasgardApplication → HasgardWindow → HasgardLocator`; full Playwright `Page` APIs are not supported.
|
|
100
109
|
|
|
101
|
-
|
|
110
|
+
[Protocol and keyboard semantics](https://github.com/nyssance/tauri-hasgard/blob/main/docs/protocol.md) · [Troubleshooting](https://github.com/nyssance/tauri-hasgard/blob/main/docs/troubleshooting.md)
|
package/dist/index.js
CHANGED
|
@@ -1072,6 +1072,7 @@ class HasgardWindow {
|
|
|
1072
1072
|
}
|
|
1073
1073
|
async screenshotNative(options) {
|
|
1074
1074
|
const value = expectRecord(await this.rpc.call("screenshot_native", {
|
|
1075
|
+
window: this.label,
|
|
1075
1076
|
...options.windowId === undefined ? {} : { window_id: options.windowId },
|
|
1076
1077
|
output_path: options.outputPath
|
|
1077
1078
|
}), "screenshot_native result");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nyssance/tauri-hasgard",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "Playwright Test fixtures for native Tauri Hasgard automation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@playwright/test": "1.64.1",
|
|
35
|
-
"@types/node": "^26.6.
|
|
35
|
+
"@types/node": "^26.6.6",
|
|
36
36
|
"typescript": "^7.0.2",
|
|
37
37
|
"vitest": "^5.0.5"
|
|
38
38
|
},
|