nativeproof 0.8.0 → 0.10.0
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/CHANGELOG.md +22 -0
- package/README.md +3 -1
- package/dist/expect.d.ts +4 -0
- package/dist/expect.js +6 -0
- package/dist/locator.d.ts +4 -0
- package/dist/locator.js +10 -0
- package/dist/mock.d.ts +2 -2
- package/dist/mock.js +14 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to NativeProof are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/) and the project adheres to
|
|
5
5
|
[Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## 0.10.0
|
|
8
|
+
|
|
9
|
+
Element enabled-state assertions.
|
|
10
|
+
|
|
11
|
+
**Added**
|
|
12
|
+
|
|
13
|
+
- **`Locator.isEnabled()` / `isDisabled()` and `expect(locator).toBeEnabled()` / `toBeDisabled()`** —
|
|
14
|
+
read the matched element's `enabled` attribute (present and not `enabled="false"` is enabled, matching
|
|
15
|
+
Playwright's default-enabled semantics). Auto-waiting, `.not` inverts. For asserting a button/control
|
|
16
|
+
flips between enabled and disabled as a form validates.
|
|
17
|
+
|
|
18
|
+
## 0.9.0
|
|
19
|
+
|
|
20
|
+
Regex frame matching — `expect(mock)` matches traffic by pattern.
|
|
21
|
+
|
|
22
|
+
**Added**
|
|
23
|
+
|
|
24
|
+
- **`toHaveSent` / `toHaveReceived` (and `FrameMatch`) accept a `RegExp`** for `path`, `type`, and any
|
|
25
|
+
payload field — `expect(mock).toHaveSent({ path: /\/users/, type: "request" })` matches a
|
|
26
|
+
query-suffixed or otherwise variable path, mirroring regex selectors on the locator side. A string
|
|
27
|
+
stays an exact match (deep equality for payload objects); a RegExp tests the actual string value.
|
|
28
|
+
|
|
7
29
|
## 0.8.0
|
|
8
30
|
|
|
9
31
|
Relative locators — `Locator.near` scopes to the match nearest an anchor.
|
package/README.md
CHANGED
|
@@ -489,6 +489,7 @@ await expect(member.spinner).not.toBeVisible({ timeout: 5_000 });
|
|
|
489
489
|
- `toShow(text, opts?)` — the selector is present **and** `text` appears in the source.
|
|
490
490
|
- `toHaveText(text, opts?)` — the matched node's **own** text contains / matches `text`.
|
|
491
491
|
- `toBeChecked(opts?)` — the matched checkbox / switch is checked (`checked="true"`).
|
|
492
|
+
- `toBeEnabled(opts?)` / `toBeDisabled(opts?)` — the matched element's `enabled` state.
|
|
492
493
|
- `toHaveCount(n, opts?)` — exactly `n` elements match the selector.
|
|
493
494
|
- `opts` is `{ timeout?, interval? }` (ms).
|
|
494
495
|
|
|
@@ -555,7 +556,8 @@ test.describe("chat room", "member", () => {
|
|
|
555
556
|
- `mock.route(path).reject({ code })` — fail it (HTTP status, or WebSocket close code 3000–4999).
|
|
556
557
|
- `mock.route(path).abort()` — drop the connect/request entirely.
|
|
557
558
|
- `expect(mock).toHaveSent(match)` / `toHaveReceived(match)` — `match` is a partial frame:
|
|
558
|
-
`path` / `type` plus any payload fields.
|
|
559
|
+
`path` / `type` plus any payload fields. Each field is a string (exact / deep-equal) **or a `RegExp`**
|
|
560
|
+
(`toHaveSent({ path: /\/users/, type: "request" })`) to match a query-suffixed or variable path.
|
|
559
561
|
|
|
560
562
|
**Frame types** — real protocol messages keep their own `type` (a WS JSON message's `type`); the
|
|
561
563
|
server also synthesises types for primitives so you can assert on them:
|
package/dist/expect.d.ts
CHANGED
|
@@ -16,6 +16,10 @@ export interface LocatorAssertions {
|
|
|
16
16
|
toHaveText(text: string | RegExp, options?: WaitOptions): Promise<void>;
|
|
17
17
|
/** The matched checkbox/switch is checked (`checked="true"`). */
|
|
18
18
|
toBeChecked(options?: WaitOptions): Promise<void>;
|
|
19
|
+
/** The matched element is enabled (present and not `enabled="false"`). */
|
|
20
|
+
toBeEnabled(options?: WaitOptions): Promise<void>;
|
|
21
|
+
/** The matched element is present and `enabled="false"`. */
|
|
22
|
+
toBeDisabled(options?: WaitOptions): Promise<void>;
|
|
19
23
|
/** Exactly `count` elements match the selector. */
|
|
20
24
|
toHaveCount(count: number, options?: WaitOptions): Promise<void>;
|
|
21
25
|
}
|
package/dist/expect.js
CHANGED
|
@@ -28,6 +28,12 @@ class LocatorExpectation {
|
|
|
28
28
|
toBeChecked(options = {}) {
|
|
29
29
|
return this.check(() => this.locator.isChecked(), "be checked", options);
|
|
30
30
|
}
|
|
31
|
+
toBeEnabled(options = {}) {
|
|
32
|
+
return this.check(() => this.locator.isEnabled(), "be enabled", options);
|
|
33
|
+
}
|
|
34
|
+
toBeDisabled(options = {}) {
|
|
35
|
+
return this.check(() => this.locator.isDisabled(), "be disabled", options);
|
|
36
|
+
}
|
|
31
37
|
toHaveCount(count, options = {}) {
|
|
32
38
|
return this.check(async () => (await this.locator.count()) === count, `have count ${count}`, options);
|
|
33
39
|
}
|
package/dist/locator.d.ts
CHANGED
|
@@ -130,6 +130,10 @@ export declare class Locator {
|
|
|
130
130
|
fill(text: string, options?: WaitOptions): Promise<void>;
|
|
131
131
|
/** True if the matched node is a checked checkbox/switch (`checked="true"`). */
|
|
132
132
|
isChecked(): Promise<boolean>;
|
|
133
|
+
/** True if the matched node is present and not `enabled="false"` (matches Playwright's default-enabled). */
|
|
134
|
+
isEnabled(): Promise<boolean>;
|
|
135
|
+
/** True if the matched node is present and explicitly `enabled="false"`. */
|
|
136
|
+
isDisabled(): Promise<boolean>;
|
|
133
137
|
/** Tap to bring a checkbox/switch to checked; a no-op if it already is. */
|
|
134
138
|
check(options?: WaitOptions): Promise<void>;
|
|
135
139
|
/** Tap to bring a checkbox/switch to unchecked; a no-op if it already is. */
|
package/dist/locator.js
CHANGED
|
@@ -212,6 +212,16 @@ export class Locator {
|
|
|
212
212
|
const node = this.pick(await this.matchedNodes());
|
|
213
213
|
return node !== null && /\bchecked="true"/.test(node);
|
|
214
214
|
}
|
|
215
|
+
/** True if the matched node is present and not `enabled="false"` (matches Playwright's default-enabled). */
|
|
216
|
+
async isEnabled() {
|
|
217
|
+
const node = this.pick(await this.matchedNodes());
|
|
218
|
+
return node !== null && !/\benabled="false"/.test(node);
|
|
219
|
+
}
|
|
220
|
+
/** True if the matched node is present and explicitly `enabled="false"`. */
|
|
221
|
+
async isDisabled() {
|
|
222
|
+
const node = this.pick(await this.matchedNodes());
|
|
223
|
+
return node !== null && /\benabled="false"/.test(node);
|
|
224
|
+
}
|
|
215
225
|
/** Tap to bring a checkbox/switch to checked; a no-op if it already is. */
|
|
216
226
|
async check(options = {}) {
|
|
217
227
|
await this.setChecked(true, options);
|
package/dist/mock.d.ts
CHANGED
|
@@ -18,8 +18,8 @@ export interface MockFrame {
|
|
|
18
18
|
}
|
|
19
19
|
/** A partial frame to match against: `path` / `type` plus any payload fields. */
|
|
20
20
|
export interface FrameMatch {
|
|
21
|
-
path?: string;
|
|
22
|
-
type?: string;
|
|
21
|
+
path?: string | RegExp;
|
|
22
|
+
type?: string | RegExp;
|
|
23
23
|
[key: string]: unknown;
|
|
24
24
|
}
|
|
25
25
|
/** Controls how an intercepted path replies — the Playwright `Route` equivalent. */
|
package/dist/mock.js
CHANGED
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
import { isDeepStrictEqual } from "node:util";
|
|
2
|
+
/**
|
|
3
|
+
* Match one field of an observed frame against an expected value: a `RegExp` tests the
|
|
4
|
+
* actual string (so paths with query/suffix match — `toHaveSent({ path: /\/users/ })`),
|
|
5
|
+
* anything else is deep structural equality.
|
|
6
|
+
*/
|
|
7
|
+
function fieldMatches(actual, expected) {
|
|
8
|
+
if (expected instanceof RegExp)
|
|
9
|
+
return typeof actual === "string" && expected.test(actual);
|
|
10
|
+
return isDeepStrictEqual(actual, expected);
|
|
11
|
+
}
|
|
2
12
|
/**
|
|
3
13
|
* True if `frame` satisfies every field of `match`: `path` / `type` at the top level,
|
|
4
14
|
* every other key against the frame's payload.
|
|
5
15
|
*/
|
|
6
16
|
export function matchesFrame(frame, match) {
|
|
7
|
-
if (match.path !== undefined && frame.path
|
|
17
|
+
if (match.path !== undefined && !fieldMatches(frame.path, match.path))
|
|
8
18
|
return false;
|
|
9
|
-
if (match.type !== undefined && frame.type
|
|
19
|
+
if (match.type !== undefined && !fieldMatches(frame.type, match.type))
|
|
10
20
|
return false;
|
|
11
21
|
for (const [key, value] of Object.entries(match)) {
|
|
12
22
|
if (key === "path" || key === "type")
|
|
13
23
|
continue;
|
|
14
|
-
if (!
|
|
24
|
+
if (!fieldMatches(frame.payload?.[key], value))
|
|
15
25
|
return false;
|
|
16
26
|
}
|
|
17
27
|
return true;
|
|
18
28
|
}
|
|
19
29
|
export function describeMatch(match) {
|
|
20
|
-
return JSON.stringify(match);
|
|
30
|
+
return JSON.stringify(match, (_key, value) => (value instanceof RegExp ? String(value) : value));
|
|
21
31
|
}
|
|
22
32
|
/** Single-shot check: does any observed frame match `match` in `direction`? */
|
|
23
33
|
export async function frameExists(source, direction, match) {
|
package/package.json
CHANGED