@testspectra/skills 1.2.8 → 1.2.10
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/skills/matchers-and-assertions/SKILL.md +40 -0
- package/dist/skills/page-objects-and-selectors/SKILL.md +26 -0
- package/dist/skills/workspace-structure/SKILL.md +4 -0
- package/package.json +1 -1
- package/skills/matchers-and-assertions/SKILL.md +40 -0
- package/skills/page-objects-and-selectors/SKILL.md +26 -0
- package/skills/workspace-structure/SKILL.md +4 -0
|
@@ -24,12 +24,49 @@ per action/assertion in `.testspectra/reports/`.
|
|
|
24
24
|
| `await el.clear()` | `Clear text in {el}` |
|
|
25
25
|
| `await el.select(option)` | `Select option "{option}" in {el}` |
|
|
26
26
|
| `await el.hover()` | `Hover over {el}` |
|
|
27
|
+
| `await el.focus()` | `Focus {el}` |
|
|
28
|
+
| `await el.blur()` | `Blur {el}` |
|
|
29
|
+
| `await el.click({ x, y })` | `Click on element "{el}" at (x, y)` |
|
|
27
30
|
| `await source.dragDrop(dest)` | `Drag {source} and drop onto {dest}` |
|
|
28
31
|
| `await el.scrollIntoView()` | `Scroll {el} into view` |
|
|
29
32
|
| `await el.longPress(durationMs)` | `Long-press on {el} for {durationMs}ms` |
|
|
30
33
|
| `await el.waitForElement(timeoutMs)` | `Wait for {el} to be displayed` |
|
|
34
|
+
| `await el.waitForElementRemoved(t?)` | `Wait for {el} to be removed` |
|
|
35
|
+
| `await el.waitForUndisplayed(o?)` | `Wait for {el} to be hidden` |
|
|
36
|
+
| `await el.waitForClickable(o?)` | `Wait for {el} to be clickable` |
|
|
37
|
+
| `await el.getBounds()` | `Get bounds of {el}` |
|
|
31
38
|
|
|
32
39
|
`type()` accepts an options object, e.g. `{ clearFirst: true }` to clear the field before typing.
|
|
40
|
+
`click({ x, y })` clicks at coordinates relative to the element; `Spectra.clickAt(x, y)` /
|
|
41
|
+
`Spectra.browser.clickAt(x, y)` clicks at absolute viewport coordinates.
|
|
42
|
+
`getText()` returns authored text (`textContent`) — CSS `text-transform` never leaks into assertions.
|
|
43
|
+
`getBounds()` returns `{ x, y, top, right, bottom, left, width, height }` (web
|
|
44
|
+
`getBoundingClientRect`, Android node bounds).
|
|
45
|
+
|
|
46
|
+
### 1b. DOM Traversal (cross-platform, no XPath)
|
|
47
|
+
|
|
48
|
+
| TestSpectra syntax | Meaning |
|
|
49
|
+
| :-------------------------------- | :--------------------------------------------------- |
|
|
50
|
+
| `el.parent()` | Parent element in the DOM / a11y tree |
|
|
51
|
+
| `await el.closest(selector)` | Closest matching ancestor, or `null` (like `closest`)|
|
|
52
|
+
| `el.children(selector?)` | Direct children as a collection (optional filter) |
|
|
53
|
+
| `el.siblings(selector?)` | Same-parent siblings (excluding self) as collection |
|
|
54
|
+
| `el.next(selector?)` | Next sibling, or first following sibling matching it |
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
await Spectra.get('ul').children('li').shouldHaveLength(3);
|
|
58
|
+
const card = await Spectra.get('#buy-button').closest('.product-card');
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Collection index survives traversal: `getAll('.x').nth(1).parent()` resolves the second
|
|
62
|
+
`.x`'s parent, not the first document match. No XPath here by design — XPath dialects differ
|
|
63
|
+
per platform, traversal keeps one API.
|
|
64
|
+
|
|
65
|
+
### 1c. State Queries (return values, not assertions)
|
|
66
|
+
|
|
67
|
+
`await el.isClickable()` → `true` when visible + enabled + in viewport. Combines with
|
|
68
|
+
`isVisible()` / `isExisting()` / `isEnabled()` for explicit branching; prefer
|
|
69
|
+
`shouldBe*` matchers + `waitForClickable()` for plain waiting.
|
|
33
70
|
|
|
34
71
|
---
|
|
35
72
|
|
|
@@ -107,6 +144,8 @@ collection carry the scope forward too. No behavior difference on web vs. Androi
|
|
|
107
144
|
| :------------- | :------------------------------------------------------------------------------------------------------------------------------- |
|
|
108
145
|
| Navigation | `await Spectra.navigate("/login")` / `.back()` / `.forward()` / `.refresh()` |
|
|
109
146
|
| Element query | `Spectra.get(selector)` / `Spectra.getAll(selector)` — chain `.get()`/`.getAll()` on the result to scope a lookup, see section 4 |
|
|
147
|
+
| Focus | `await Spectra.focus(target)` / `await Spectra.blur(target)` |
|
|
148
|
+
| Coordinate | `await Spectra.clickAt(x, y)` — absolute viewport click |
|
|
110
149
|
| Window | `await Spectra.setViewport(1920, 1080)` |
|
|
111
150
|
| Timing | `await Spectra.wait(1000)` |
|
|
112
151
|
| Keyboard | `await Spectra.pressKey("Enter")` |
|
|
@@ -118,6 +157,7 @@ collection carry the scope forward too. No behavior difference on web vs. Androi
|
|
|
118
157
|
|
|
119
158
|
| Syntax | Purpose |
|
|
120
159
|
| :-------------------------------------------------- | :------------------------------ |
|
|
160
|
+
| `await Spectra.browser.clickAt(x, y)` | Click at viewport coordinates |
|
|
121
161
|
| `await Spectra.browser.clearCookies()` | Clear all cookies |
|
|
122
162
|
| `await Spectra.browser.clearLocalStorage()` | Clear localStorage |
|
|
123
163
|
| `await Spectra.browser.shouldHaveUrl(url)` | Assert exact URL |
|
|
@@ -121,6 +121,32 @@ This is a Page Object concern, not a new selector prefix — `~`/`#`/xpath all s
|
|
|
121
121
|
child selector, resolved within the parent's subtree instead of the whole document/screen. See the
|
|
122
122
|
`matchers-and-assertions` skill for the full `.get()`/`.getAll()` chaining behavior.
|
|
123
123
|
|
|
124
|
+
### Traversal instead of compound selectors
|
|
125
|
+
|
|
126
|
+
For moving up/sideways in the tree, prefer traversal over xpath axes (xpath dialects differ per
|
|
127
|
+
platform — DOM attrs on web vs `@text`/`@resource-id` on Android — so traversal is the one
|
|
128
|
+
cross-platform API):
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
class ProductCard {
|
|
132
|
+
buyButton() {
|
|
133
|
+
return Spectra.get('#buy-button');
|
|
134
|
+
}
|
|
135
|
+
card() {
|
|
136
|
+
return this.buyButton().parent(); // or await .closest('.product-card')
|
|
137
|
+
}
|
|
138
|
+
siblings() {
|
|
139
|
+
return Spectra.get('.step-1').next('.step-2');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- `parent()` / `await closest(sel)` / `children(sel?)` / `siblings(sel?)` / `next(sel?)` work on
|
|
145
|
+
web (DOM) and Android (a11y-tree links) identically.
|
|
146
|
+
- Index survives traversal: `cards.nth(1).parent()` resolves the second card's parent, never the
|
|
147
|
+
first document match. Unfiltered `parent()` chains stay document-wide — scope with
|
|
148
|
+
`closest(selector)` or a filter when several subtrees match.
|
|
149
|
+
|
|
124
150
|
---
|
|
125
151
|
|
|
126
152
|
## 4. Never Use Raw `$` / `$$` / `browser` / `driver`
|
|
@@ -152,6 +152,7 @@ export default defineConfig({
|
|
|
152
152
|
normalResponseTime: '1000',
|
|
153
153
|
monitoredDomains: [{ domain: 'api.example.com', enabled: true }],
|
|
154
154
|
environmentVariables: { API_MODE: 'sandbox' },
|
|
155
|
+
plugins: ['@myorg/spectra-button-plugin'],
|
|
155
156
|
},
|
|
156
157
|
});
|
|
157
158
|
```
|
|
@@ -173,6 +174,9 @@ Numeric-looking fields (timeouts, ports, session counts) accept either a `number
|
|
|
173
174
|
`.testspectra/types/env.d.ts`, autocompleted, zero-import — **prefer this over `process.env`**,
|
|
174
175
|
which is untyped `string | undefined`) and a plain `process.env.KEY` string for code that must
|
|
175
176
|
consume the untyped standard API.
|
|
177
|
+
- **`plugins`**: module specifiers (package name or project-relative path) extending `Spectra`
|
|
178
|
+
with custom commands via `Spectra.registerCommand()`; installs are idempotent per specifier.
|
|
179
|
+
Run `spectra sync-types` to regenerate per-platform ambient declarations.
|
|
176
180
|
|
|
177
181
|
---
|
|
178
182
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testspectra/skills",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.10",
|
|
4
4
|
"description": "Installer & manager for modular AI agent skills that standardize TestSpectra script authoring (specs, page objects, steps, actions, hooks, fixtures, matchers)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -24,12 +24,49 @@ per action/assertion in `.testspectra/reports/`.
|
|
|
24
24
|
| `await el.clear()` | `Clear text in {el}` |
|
|
25
25
|
| `await el.select(option)` | `Select option "{option}" in {el}` |
|
|
26
26
|
| `await el.hover()` | `Hover over {el}` |
|
|
27
|
+
| `await el.focus()` | `Focus {el}` |
|
|
28
|
+
| `await el.blur()` | `Blur {el}` |
|
|
29
|
+
| `await el.click({ x, y })` | `Click on element "{el}" at (x, y)` |
|
|
27
30
|
| `await source.dragDrop(dest)` | `Drag {source} and drop onto {dest}` |
|
|
28
31
|
| `await el.scrollIntoView()` | `Scroll {el} into view` |
|
|
29
32
|
| `await el.longPress(durationMs)` | `Long-press on {el} for {durationMs}ms` |
|
|
30
33
|
| `await el.waitForElement(timeoutMs)` | `Wait for {el} to be displayed` |
|
|
34
|
+
| `await el.waitForElementRemoved(t?)` | `Wait for {el} to be removed` |
|
|
35
|
+
| `await el.waitForUndisplayed(o?)` | `Wait for {el} to be hidden` |
|
|
36
|
+
| `await el.waitForClickable(o?)` | `Wait for {el} to be clickable` |
|
|
37
|
+
| `await el.getBounds()` | `Get bounds of {el}` |
|
|
31
38
|
|
|
32
39
|
`type()` accepts an options object, e.g. `{ clearFirst: true }` to clear the field before typing.
|
|
40
|
+
`click({ x, y })` clicks at coordinates relative to the element; `Spectra.clickAt(x, y)` /
|
|
41
|
+
`Spectra.browser.clickAt(x, y)` clicks at absolute viewport coordinates.
|
|
42
|
+
`getText()` returns authored text (`textContent`) — CSS `text-transform` never leaks into assertions.
|
|
43
|
+
`getBounds()` returns `{ x, y, top, right, bottom, left, width, height }` (web
|
|
44
|
+
`getBoundingClientRect`, Android node bounds).
|
|
45
|
+
|
|
46
|
+
### 1b. DOM Traversal (cross-platform, no XPath)
|
|
47
|
+
|
|
48
|
+
| TestSpectra syntax | Meaning |
|
|
49
|
+
| :-------------------------------- | :--------------------------------------------------- |
|
|
50
|
+
| `el.parent()` | Parent element in the DOM / a11y tree |
|
|
51
|
+
| `await el.closest(selector)` | Closest matching ancestor, or `null` (like `closest`)|
|
|
52
|
+
| `el.children(selector?)` | Direct children as a collection (optional filter) |
|
|
53
|
+
| `el.siblings(selector?)` | Same-parent siblings (excluding self) as collection |
|
|
54
|
+
| `el.next(selector?)` | Next sibling, or first following sibling matching it |
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
await Spectra.get('ul').children('li').shouldHaveLength(3);
|
|
58
|
+
const card = await Spectra.get('#buy-button').closest('.product-card');
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Collection index survives traversal: `getAll('.x').nth(1).parent()` resolves the second
|
|
62
|
+
`.x`'s parent, not the first document match. No XPath here by design — XPath dialects differ
|
|
63
|
+
per platform, traversal keeps one API.
|
|
64
|
+
|
|
65
|
+
### 1c. State Queries (return values, not assertions)
|
|
66
|
+
|
|
67
|
+
`await el.isClickable()` → `true` when visible + enabled + in viewport. Combines with
|
|
68
|
+
`isVisible()` / `isExisting()` / `isEnabled()` for explicit branching; prefer
|
|
69
|
+
`shouldBe*` matchers + `waitForClickable()` for plain waiting.
|
|
33
70
|
|
|
34
71
|
---
|
|
35
72
|
|
|
@@ -107,6 +144,8 @@ collection carry the scope forward too. No behavior difference on web vs. Androi
|
|
|
107
144
|
| :------------- | :------------------------------------------------------------------------------------------------------------------------------- |
|
|
108
145
|
| Navigation | `await Spectra.navigate("/login")` / `.back()` / `.forward()` / `.refresh()` |
|
|
109
146
|
| Element query | `Spectra.get(selector)` / `Spectra.getAll(selector)` — chain `.get()`/`.getAll()` on the result to scope a lookup, see section 4 |
|
|
147
|
+
| Focus | `await Spectra.focus(target)` / `await Spectra.blur(target)` |
|
|
148
|
+
| Coordinate | `await Spectra.clickAt(x, y)` — absolute viewport click |
|
|
110
149
|
| Window | `await Spectra.setViewport(1920, 1080)` |
|
|
111
150
|
| Timing | `await Spectra.wait(1000)` |
|
|
112
151
|
| Keyboard | `await Spectra.pressKey("Enter")` |
|
|
@@ -118,6 +157,7 @@ collection carry the scope forward too. No behavior difference on web vs. Androi
|
|
|
118
157
|
|
|
119
158
|
| Syntax | Purpose |
|
|
120
159
|
| :-------------------------------------------------- | :------------------------------ |
|
|
160
|
+
| `await Spectra.browser.clickAt(x, y)` | Click at viewport coordinates |
|
|
121
161
|
| `await Spectra.browser.clearCookies()` | Clear all cookies |
|
|
122
162
|
| `await Spectra.browser.clearLocalStorage()` | Clear localStorage |
|
|
123
163
|
| `await Spectra.browser.shouldHaveUrl(url)` | Assert exact URL |
|
|
@@ -121,6 +121,32 @@ This is a Page Object concern, not a new selector prefix — `~`/`#`/xpath all s
|
|
|
121
121
|
child selector, resolved within the parent's subtree instead of the whole document/screen. See the
|
|
122
122
|
`matchers-and-assertions` skill for the full `.get()`/`.getAll()` chaining behavior.
|
|
123
123
|
|
|
124
|
+
### Traversal instead of compound selectors
|
|
125
|
+
|
|
126
|
+
For moving up/sideways in the tree, prefer traversal over xpath axes (xpath dialects differ per
|
|
127
|
+
platform — DOM attrs on web vs `@text`/`@resource-id` on Android — so traversal is the one
|
|
128
|
+
cross-platform API):
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
class ProductCard {
|
|
132
|
+
buyButton() {
|
|
133
|
+
return Spectra.get('#buy-button');
|
|
134
|
+
}
|
|
135
|
+
card() {
|
|
136
|
+
return this.buyButton().parent(); // or await .closest('.product-card')
|
|
137
|
+
}
|
|
138
|
+
siblings() {
|
|
139
|
+
return Spectra.get('.step-1').next('.step-2');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- `parent()` / `await closest(sel)` / `children(sel?)` / `siblings(sel?)` / `next(sel?)` work on
|
|
145
|
+
web (DOM) and Android (a11y-tree links) identically.
|
|
146
|
+
- Index survives traversal: `cards.nth(1).parent()` resolves the second card's parent, never the
|
|
147
|
+
first document match. Unfiltered `parent()` chains stay document-wide — scope with
|
|
148
|
+
`closest(selector)` or a filter when several subtrees match.
|
|
149
|
+
|
|
124
150
|
---
|
|
125
151
|
|
|
126
152
|
## 4. Never Use Raw `$` / `$$` / `browser` / `driver`
|
|
@@ -152,6 +152,7 @@ export default defineConfig({
|
|
|
152
152
|
normalResponseTime: '1000',
|
|
153
153
|
monitoredDomains: [{ domain: 'api.example.com', enabled: true }],
|
|
154
154
|
environmentVariables: { API_MODE: 'sandbox' },
|
|
155
|
+
plugins: ['@myorg/spectra-button-plugin'],
|
|
155
156
|
},
|
|
156
157
|
});
|
|
157
158
|
```
|
|
@@ -173,6 +174,9 @@ Numeric-looking fields (timeouts, ports, session counts) accept either a `number
|
|
|
173
174
|
`.testspectra/types/env.d.ts`, autocompleted, zero-import — **prefer this over `process.env`**,
|
|
174
175
|
which is untyped `string | undefined`) and a plain `process.env.KEY` string for code that must
|
|
175
176
|
consume the untyped standard API.
|
|
177
|
+
- **`plugins`**: module specifiers (package name or project-relative path) extending `Spectra`
|
|
178
|
+
with custom commands via `Spectra.registerCommand()`; installs are idempotent per specifier.
|
|
179
|
+
Run `spectra sync-types` to regenerate per-platform ambient declarations.
|
|
176
180
|
|
|
177
181
|
---
|
|
178
182
|
|