@testspectra/skills 1.1.0-rc.0 → 1.1.0-rc.1

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.
@@ -53,6 +53,15 @@ per action/assertion in `.testspectra/reports/`.
53
53
  | `await el.shouldHaveAttribute(attr, val)` | `Expect element "{el}" attribute "{attr}" to be "{val}"` |
54
54
  | `await el.shouldBeFocused()` | `Expect element "{el}" to be focused` |
55
55
 
56
+ Every assertion above (and every collection matcher in section 3) accepts a trailing
57
+ `options?: { timeoutMs }` to override the adaptive fail-fast timeout for that one call, without
58
+ raising it for every other assertion in the test — use this when a specific assertion is known to
59
+ need longer, e.g. right after a deliberately delayed `Spectra.intercept(..., { delayMs })` mock:
60
+
61
+ ```typescript
62
+ await ReportPage.statusBadge.shouldHaveText('Ready', { timeoutMs: 5000 });
63
+ ```
64
+
56
65
  ---
57
66
 
58
67
  ## 3. Collection Matchers (on `Spectra.getAll(selector)` getters)
@@ -68,12 +77,36 @@ per action/assertion in `.testspectra/reports/`.
68
77
 
69
78
  ---
70
79
 
71
- ## 4. Global `Spectra.*` Commands
80
+ ## 4. Scoped Element Lookups: `.get()` / `.getAll()`
81
+
82
+ Any resolved element also has `.get(childSelector)` / `.getAll(childSelector)`, chaining a lookup
83
+ scoped to that element's own subtree — Playwright's `locator.locator()` model. **Prefer this over
84
+ a hand-written compound selector** whenever disambiguating repeated markup that shares one
85
+ selector across rows (a list of cards, a table's rows):
86
+
87
+ ```typescript
88
+ // WRONG: `.buy-btn` is the same selector on every card — this always resolves the first one.
89
+ await Spectra.get('.buy-btn').click();
90
+
91
+ // RIGHT: scoped to the specific card first.
92
+ const thirdCard = Spectra.getAll('.product-card').nth(2);
93
+ await thirdCard.get('.buy-btn').click();
94
+ await thirdCard.getAll('.badge').shouldHaveLength(2);
95
+ ```
96
+
97
+ Works identically from a Page Object property, since it's already a resolved element:
98
+ `await SettingsPage.modal.get('#save-btn').click()`. `.first()`/`.last()`/`.nth(i)` on a scoped
99
+ collection carry the scope forward too. No behavior difference on web vs. Android — resolution
100
+ (real DOM query vs. bounds-containment) is handled transparently underneath.
101
+
102
+ ---
103
+
104
+ ## 5. Global `Spectra.*` Commands
72
105
 
73
106
  | Category | Syntax |
74
107
  | :------------- | :------------------------------------------------------------------------------------------------------- |
75
108
  | Navigation | `await Spectra.navigate("/login")` / `.back()` / `.forward()` / `.refresh()` |
76
- | Element query | `Spectra.get(selector)` / `Spectra.getAll(selector)` |
109
+ | Element query | `Spectra.get(selector)` / `Spectra.getAll(selector)` — chain `.get()`/`.getAll()` on the result to scope a lookup, see section 4 |
77
110
  | Window | `await Spectra.setViewport(1920, 1080)` |
78
111
  | Timing | `await Spectra.wait(1000)` |
79
112
  | Keyboard | `await Spectra.pressKey("Enter")` |
@@ -81,7 +114,7 @@ per action/assertion in `.testspectra/reports/`.
81
114
  | Mobile gesture | `await Spectra.swipe({ direction: "left", distance: 300 })` |
82
115
  | Network mock | `const mock = await Spectra.intercept({ url, method, response })` — see the `network-interception` skill |
83
116
 
84
- ## 5. `Spectra.browser.*` — Browser/Context Level
117
+ ## 6. `Spectra.browser.*` — Browser/Context Level
85
118
 
86
119
  | Syntax | Purpose |
87
120
  | :-------------------------------------------------- | :------------------------------ |
@@ -96,7 +129,7 @@ per action/assertion in `.testspectra/reports/`.
96
129
 
97
130
  ---
98
131
 
99
- ## 6. Full Example
132
+ ## 7. Full Example
100
133
 
101
134
  ```typescript
102
135
  it('should login as administrator and assert dashboard metrics', async () => {
@@ -98,7 +98,32 @@ cross-matching.
98
98
 
99
99
  ---
100
100
 
101
- ## 3. Never Use Raw `$` / `$$` / `browser` / `driver`
101
+ ## 3. Scoping a Lookup Instead of Writing a Compound Selector
102
+
103
+ When the same selector repeats across rows (a list of cards, a table), **do not** reach for a
104
+ compound CSS selector (`.card:nth-child(3) .buy-btn`) or an index baked into an xpath — those are
105
+ brittle and don't have a cross-platform equivalent (Android has no CSS nth-child). Chain
106
+ `.get(childSelector)` / `.getAll(childSelector)` off an already-resolved element instead; it
107
+ scopes the lookup to that element's own subtree:
108
+
109
+ ```typescript
110
+ class ProductsPage {
111
+ get cards() {
112
+ return Spectra.getAll('.product-card');
113
+ }
114
+ cardBuyButton(index: number) {
115
+ return this.cards.nth(index).get('.buy-btn');
116
+ }
117
+ }
118
+ ```
119
+
120
+ This is a Page Object concern, not a new selector prefix — `~`/`#`/xpath all still apply as the
121
+ child selector, resolved within the parent's subtree instead of the whole document/screen. See the
122
+ `matchers-and-assertions` skill for the full `.get()`/`.getAll()` chaining behavior.
123
+
124
+ ---
125
+
126
+ ## 4. Never Use Raw `$` / `$$` / `browser` / `driver`
102
127
 
103
128
  TestSpectra encapsulates the entire runtime into a single global `Spectra` object. There is no raw
104
129
  WebdriverIO `$`, `$$`, `browser`, or `driver` in test-authoring code — always go through
@@ -123,11 +123,8 @@ export default defineConfig({
123
123
  maxConcurrentSessions: '1',
124
124
  headless: true,
125
125
  implicitWait: '5000',
126
- pageLoadTimeout: '30000',
127
- scriptTimeout: '30000',
128
126
  parallelizationMode: 'testcase', // "testcase" | "suite"
129
127
  },
130
- browsers: [{ id: 'chrome-desktop', type: 'chrome', mobileEmulation: false }],
131
128
  androidConfig: {
132
129
  driverServer: 'tcp://127.0.0.1:8200',
133
130
  appPackage: 'dev.example.app',
@@ -153,8 +150,8 @@ export default defineConfig({
153
150
  networkMonitoringEnabled: true,
154
151
  fastResponseTime: '200',
155
152
  normalResponseTime: '1000',
156
- monitoredDomains: [],
157
- environmentVariables: [],
153
+ monitoredDomains: [{ domain: 'api.example.com', enabled: true }],
154
+ environmentVariables: { API_MODE: 'sandbox' },
158
155
  },
159
156
  });
160
157
  ```
@@ -162,6 +159,21 @@ export default defineConfig({
162
159
  Numeric-looking fields (timeouts, ports, session counts) accept either a `number` or a numeric
163
160
  `string` — stay consistent with whatever the rest of the file already uses.
164
161
 
162
+ `executionConfig` notes:
163
+
164
+ - **`monitoredDomains`**: empty/absent = record every domain; non-empty = only requests matching
165
+ an `enabled: true` entry (exact hostname or leading-`*` wildcard) get recorded/streamed to the
166
+ Network panel. `networkMonitoringEnabled: false` disables recording outright regardless of this
167
+ list.
168
+ - **`fastResponseTime`/`normalResponseTime`**: millisecond thresholds the VS Code Network panel
169
+ uses to color each request's Duration cell (fast/normal/slow). No effect on test execution
170
+ itself.
171
+ - **`environmentVariables`**: a flat `Record<string, string>` (not an array, not nested
172
+ key/value pairs) — every key becomes both a typed `Spectra.env.KEY` entry (generated into
173
+ `.testspectra/types/env.d.ts`, autocompleted, zero-import — **prefer this over `process.env`**,
174
+ which is untyped `string | undefined`) and a plain `process.env.KEY` string for code that must
175
+ consume the untyped standard API.
176
+
165
177
  ---
166
178
 
167
179
  ## 6. Core `spectra` CLI Commands
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testspectra/skills",
3
- "version": "1.1.0-rc.0",
3
+ "version": "1.1.0-rc.1",
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",
@@ -53,6 +53,15 @@ per action/assertion in `.testspectra/reports/`.
53
53
  | `await el.shouldHaveAttribute(attr, val)` | `Expect element "{el}" attribute "{attr}" to be "{val}"` |
54
54
  | `await el.shouldBeFocused()` | `Expect element "{el}" to be focused` |
55
55
 
56
+ Every assertion above (and every collection matcher in section 3) accepts a trailing
57
+ `options?: { timeoutMs }` to override the adaptive fail-fast timeout for that one call, without
58
+ raising it for every other assertion in the test — use this when a specific assertion is known to
59
+ need longer, e.g. right after a deliberately delayed `Spectra.intercept(..., { delayMs })` mock:
60
+
61
+ ```typescript
62
+ await ReportPage.statusBadge.shouldHaveText('Ready', { timeoutMs: 5000 });
63
+ ```
64
+
56
65
  ---
57
66
 
58
67
  ## 3. Collection Matchers (on `Spectra.getAll(selector)` getters)
@@ -68,12 +77,36 @@ per action/assertion in `.testspectra/reports/`.
68
77
 
69
78
  ---
70
79
 
71
- ## 4. Global `Spectra.*` Commands
80
+ ## 4. Scoped Element Lookups: `.get()` / `.getAll()`
81
+
82
+ Any resolved element also has `.get(childSelector)` / `.getAll(childSelector)`, chaining a lookup
83
+ scoped to that element's own subtree — Playwright's `locator.locator()` model. **Prefer this over
84
+ a hand-written compound selector** whenever disambiguating repeated markup that shares one
85
+ selector across rows (a list of cards, a table's rows):
86
+
87
+ ```typescript
88
+ // WRONG: `.buy-btn` is the same selector on every card — this always resolves the first one.
89
+ await Spectra.get('.buy-btn').click();
90
+
91
+ // RIGHT: scoped to the specific card first.
92
+ const thirdCard = Spectra.getAll('.product-card').nth(2);
93
+ await thirdCard.get('.buy-btn').click();
94
+ await thirdCard.getAll('.badge').shouldHaveLength(2);
95
+ ```
96
+
97
+ Works identically from a Page Object property, since it's already a resolved element:
98
+ `await SettingsPage.modal.get('#save-btn').click()`. `.first()`/`.last()`/`.nth(i)` on a scoped
99
+ collection carry the scope forward too. No behavior difference on web vs. Android — resolution
100
+ (real DOM query vs. bounds-containment) is handled transparently underneath.
101
+
102
+ ---
103
+
104
+ ## 5. Global `Spectra.*` Commands
72
105
 
73
106
  | Category | Syntax |
74
107
  | :------------- | :------------------------------------------------------------------------------------------------------- |
75
108
  | Navigation | `await Spectra.navigate("/login")` / `.back()` / `.forward()` / `.refresh()` |
76
- | Element query | `Spectra.get(selector)` / `Spectra.getAll(selector)` |
109
+ | Element query | `Spectra.get(selector)` / `Spectra.getAll(selector)` — chain `.get()`/`.getAll()` on the result to scope a lookup, see section 4 |
77
110
  | Window | `await Spectra.setViewport(1920, 1080)` |
78
111
  | Timing | `await Spectra.wait(1000)` |
79
112
  | Keyboard | `await Spectra.pressKey("Enter")` |
@@ -81,7 +114,7 @@ per action/assertion in `.testspectra/reports/`.
81
114
  | Mobile gesture | `await Spectra.swipe({ direction: "left", distance: 300 })` |
82
115
  | Network mock | `const mock = await Spectra.intercept({ url, method, response })` — see the `network-interception` skill |
83
116
 
84
- ## 5. `Spectra.browser.*` — Browser/Context Level
117
+ ## 6. `Spectra.browser.*` — Browser/Context Level
85
118
 
86
119
  | Syntax | Purpose |
87
120
  | :-------------------------------------------------- | :------------------------------ |
@@ -96,7 +129,7 @@ per action/assertion in `.testspectra/reports/`.
96
129
 
97
130
  ---
98
131
 
99
- ## 6. Full Example
132
+ ## 7. Full Example
100
133
 
101
134
  ```typescript
102
135
  it('should login as administrator and assert dashboard metrics', async () => {
@@ -98,7 +98,32 @@ cross-matching.
98
98
 
99
99
  ---
100
100
 
101
- ## 3. Never Use Raw `$` / `$$` / `browser` / `driver`
101
+ ## 3. Scoping a Lookup Instead of Writing a Compound Selector
102
+
103
+ When the same selector repeats across rows (a list of cards, a table), **do not** reach for a
104
+ compound CSS selector (`.card:nth-child(3) .buy-btn`) or an index baked into an xpath — those are
105
+ brittle and don't have a cross-platform equivalent (Android has no CSS nth-child). Chain
106
+ `.get(childSelector)` / `.getAll(childSelector)` off an already-resolved element instead; it
107
+ scopes the lookup to that element's own subtree:
108
+
109
+ ```typescript
110
+ class ProductsPage {
111
+ get cards() {
112
+ return Spectra.getAll('.product-card');
113
+ }
114
+ cardBuyButton(index: number) {
115
+ return this.cards.nth(index).get('.buy-btn');
116
+ }
117
+ }
118
+ ```
119
+
120
+ This is a Page Object concern, not a new selector prefix — `~`/`#`/xpath all still apply as the
121
+ child selector, resolved within the parent's subtree instead of the whole document/screen. See the
122
+ `matchers-and-assertions` skill for the full `.get()`/`.getAll()` chaining behavior.
123
+
124
+ ---
125
+
126
+ ## 4. Never Use Raw `$` / `$$` / `browser` / `driver`
102
127
 
103
128
  TestSpectra encapsulates the entire runtime into a single global `Spectra` object. There is no raw
104
129
  WebdriverIO `$`, `$$`, `browser`, or `driver` in test-authoring code — always go through
@@ -123,11 +123,8 @@ export default defineConfig({
123
123
  maxConcurrentSessions: '1',
124
124
  headless: true,
125
125
  implicitWait: '5000',
126
- pageLoadTimeout: '30000',
127
- scriptTimeout: '30000',
128
126
  parallelizationMode: 'testcase', // "testcase" | "suite"
129
127
  },
130
- browsers: [{ id: 'chrome-desktop', type: 'chrome', mobileEmulation: false }],
131
128
  androidConfig: {
132
129
  driverServer: 'tcp://127.0.0.1:8200',
133
130
  appPackage: 'dev.example.app',
@@ -153,8 +150,8 @@ export default defineConfig({
153
150
  networkMonitoringEnabled: true,
154
151
  fastResponseTime: '200',
155
152
  normalResponseTime: '1000',
156
- monitoredDomains: [],
157
- environmentVariables: [],
153
+ monitoredDomains: [{ domain: 'api.example.com', enabled: true }],
154
+ environmentVariables: { API_MODE: 'sandbox' },
158
155
  },
159
156
  });
160
157
  ```
@@ -162,6 +159,21 @@ export default defineConfig({
162
159
  Numeric-looking fields (timeouts, ports, session counts) accept either a `number` or a numeric
163
160
  `string` — stay consistent with whatever the rest of the file already uses.
164
161
 
162
+ `executionConfig` notes:
163
+
164
+ - **`monitoredDomains`**: empty/absent = record every domain; non-empty = only requests matching
165
+ an `enabled: true` entry (exact hostname or leading-`*` wildcard) get recorded/streamed to the
166
+ Network panel. `networkMonitoringEnabled: false` disables recording outright regardless of this
167
+ list.
168
+ - **`fastResponseTime`/`normalResponseTime`**: millisecond thresholds the VS Code Network panel
169
+ uses to color each request's Duration cell (fast/normal/slow). No effect on test execution
170
+ itself.
171
+ - **`environmentVariables`**: a flat `Record<string, string>` (not an array, not nested
172
+ key/value pairs) — every key becomes both a typed `Spectra.env.KEY` entry (generated into
173
+ `.testspectra/types/env.d.ts`, autocompleted, zero-import — **prefer this over `process.env`**,
174
+ which is untyped `string | undefined`) and a plain `process.env.KEY` string for code that must
175
+ consume the untyped standard API.
176
+
165
177
  ---
166
178
 
167
179
  ## 6. Core `spectra` CLI Commands