@testspectra/skills 1.1.8-rc.2 → 1.1.8-rc.21
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/LICENSE.md +48 -48
- package/README.md +78 -78
- package/bin/spectra-skills.js +7 -7
- package/dist/index.js +29 -29
- package/dist/skills/fixtures-data/SKILL.md +109 -109
- package/dist/skills/lifecycle-hooks/SKILL.md +114 -114
- package/dist/skills/matchers-and-assertions/SKILL.md +156 -156
- package/dist/skills/network-interception/SKILL.md +115 -115
- package/dist/skills/page-objects-and-selectors/SKILL.md +132 -132
- package/dist/skills/shared-steps-and-actions/SKILL.md +184 -184
- package/dist/skills/spec-and-suite-authoring/SKILL.md +132 -132
- package/dist/skills/workspace-structure/SKILL.md +193 -193
- package/package.json +11 -12
- package/skills/fixtures-data/SKILL.md +109 -109
- package/skills/lifecycle-hooks/SKILL.md +114 -114
- package/skills/matchers-and-assertions/SKILL.md +156 -156
- package/skills/network-interception/SKILL.md +115 -115
- package/skills/page-objects-and-selectors/SKILL.md +132 -132
- package/skills/shared-steps-and-actions/SKILL.md +184 -184
- package/skills/spec-and-suite-authoring/SKILL.md +132 -132
- package/skills/workspace-structure/SKILL.md +193 -193
|
@@ -1,184 +1,184 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: shared-steps-and-actions
|
|
3
|
-
description: The difference between TestSpectra Shared Steps (Step.*, high-level business workflows, documented in spec.md via @step) and Spectra Actions (support/actions, low-level technical utilities) — directory layout, the mandatory anonymous async default export convention, and ambient type generation. Use whenever extracting reusable logic out of a test script.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Skill: Shared Steps vs. Custom Actions
|
|
7
|
-
|
|
8
|
-
Use this skill when you're about to extract repeated logic (e.g. login, checkout) out of test
|
|
9
|
-
scripts, or when deciding whether new reusable logic belongs under `support/steps/` or
|
|
10
|
-
`support/actions/`.
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## 1. Which One Do I Need?
|
|
15
|
-
|
|
16
|
-
| Attribute | Shared Steps (`Step.*`) | Custom Actions (`Spectra.*` / on-element helpers) |
|
|
17
|
-
| :---------------- | :--------------------------------------------- | :---------------------------------------------------------------------------- |
|
|
18
|
-
| Abstraction level | High-level business workflow (login, checkout) | Low-level technical utility |
|
|
19
|
-
| Directory | `support/steps/<stepName>/` | `support/actions/<actionName>/` |
|
|
20
|
-
| Spec mapping | Documented as `@step:<name>` in `spec.md` | Just called inline, not listed in spec steps |
|
|
21
|
-
| Metadata file | `step.md` (YAML frontmatter + description) | None — implementation file only |
|
|
22
|
-
| Files | `step.md` + `web.step.ts` [+ `mobile.step.ts`] | `web.action.ts` [+ `mobile.action.ts`] |
|
|
23
|
-
| Invocation | `await Step.loginAsAdmin(params)` | Called as a helper bound to an element/page, e.g. inside a Page Object method |
|
|
24
|
-
|
|
25
|
-
Rule of thumb: if it's a multi-step _business_ flow a human would describe in one sentence
|
|
26
|
-
("log in as admin"), it's a **Step**. If it's a small technical helper reused across Page Objects
|
|
27
|
-
(a resilient click retry, filling a pair of fields), it's an **Action**.
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## 2. Directory Layout
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
support/
|
|
35
|
-
├── steps/
|
|
36
|
-
│ └── loginAsAdmin/
|
|
37
|
-
│ ├── step.md # Metadata, docs, parameter types
|
|
38
|
-
│ ├── web.step.ts
|
|
39
|
-
│ └── mobile.step.ts # optional
|
|
40
|
-
└── actions/
|
|
41
|
-
└── fillCredentials/
|
|
42
|
-
├── web.action.ts
|
|
43
|
-
└── mobile.action.ts
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Both use **camelCase** directory/function names (`loginAsAdmin`, `fillCredentials`,
|
|
47
|
-
`applyDiscount`, `verifyOtp`) — never kebab-case or snake_case.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## 3. `step.md` Metadata
|
|
52
|
-
|
|
53
|
-
```markdown
|
|
54
|
-
---
|
|
55
|
-
id: step-login-as-admin
|
|
56
|
-
name: loginAsAdmin
|
|
57
|
-
description: Authenticates as an administrator and asserts landing dashboard
|
|
58
|
-
platform:
|
|
59
|
-
- web
|
|
60
|
-
- mobile
|
|
61
|
-
tags:
|
|
62
|
-
- auth
|
|
63
|
-
- admin
|
|
64
|
-
parameters:
|
|
65
|
-
- name: email
|
|
66
|
-
type: string
|
|
67
|
-
required: false
|
|
68
|
-
description: Admin email address (defaults to Fixture.users.admin.email)
|
|
69
|
-
- name: password
|
|
70
|
-
type: string
|
|
71
|
-
required: false
|
|
72
|
-
description: Admin password (defaults to Fixture.users.admin.password)
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
# Login as Admin Step
|
|
76
|
-
|
|
77
|
-
## Purpose
|
|
78
|
-
|
|
79
|
-
Provides a standard, hardened administrative login sequence for web and mobile platforms.
|
|
80
|
-
|
|
81
|
-
## Prerequisites
|
|
82
|
-
|
|
83
|
-
- User fixture file exists at `fixtures/users.json`.
|
|
84
|
-
- Browser is navigated to the base URL or login route.
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## 4. Implementation: Anonymous Async Default Export (Mandatory)
|
|
90
|
-
|
|
91
|
-
Every `*.step.ts` and `*.action.ts` file exports **one anonymous async function as its default
|
|
92
|
-
export** — no named exports, no `test()`/`it()` blocks. This is enforced by the linter
|
|
93
|
-
(`testspectra/require-anonymous-default-export`).
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
// support/steps/loginAsAdmin/web.step.ts
|
|
97
|
-
export default async function (params?: { email?: string; password?: string }) {
|
|
98
|
-
const email = params?.email ?? Fixture.users.admin.email;
|
|
99
|
-
const password = params?.password ?? Fixture.users.admin.password;
|
|
100
|
-
|
|
101
|
-
await Spectra.navigate('/auth/login');
|
|
102
|
-
await LoginPage.emailInput.type(email, { clearFirst: true });
|
|
103
|
-
await LoginPage.passwordInput.type(password);
|
|
104
|
-
await LoginPage.submitButton.click();
|
|
105
|
-
|
|
106
|
-
await DashboardPage.header.shouldBeVisible();
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Custom Actions follow the same shape and are commonly written with a `this` receiver so they can
|
|
111
|
-
be attached/bound as element/page helpers:
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
// support/actions/fillCredentials/web.action.ts
|
|
115
|
-
export default async function (this: any, email: string, token: string) {
|
|
116
|
-
await this.get('#demo-email-input-pg').type(email);
|
|
117
|
-
await this.get('#demo-token-input-pg').type(token);
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
// support/actions/fillCredentials/mobile.action.ts
|
|
123
|
-
export default async function (this: any, email: string, token: string) {
|
|
124
|
-
await this.get('~pg-email-input').type(email);
|
|
125
|
-
await this.get('~pg-token-input').type(token);
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Zero-import applies here too: never manually `import` a Page Object, `Fixture`, or `Spectra` — see
|
|
130
|
-
the `workspace-structure` skill.
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## 5. Type Generation & Invocation
|
|
135
|
-
|
|
136
|
-
The `TypeGenerator` scans `support/steps/` and emits the `Step` ambient namespace automatically:
|
|
137
|
-
|
|
138
|
-
```typescript
|
|
139
|
-
declare global {
|
|
140
|
-
namespace Step {
|
|
141
|
-
function loginAsAdmin(params?: { email?: string; password?: string }): Promise<void>;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### In `spec.md` (documents the step as part of the human-readable flow):
|
|
147
|
-
|
|
148
|
-
```markdown
|
|
149
|
-
## Test Steps
|
|
150
|
-
|
|
151
|
-
1. @step:loginAsAdmin
|
|
152
|
-
2. Navigate to user settings page
|
|
153
|
-
3. Update profile avatar
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### In `web.test.ts` (invokes it with zero manual imports):
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
it('should update admin profile avatar', async () => {
|
|
160
|
-
await Step.loginAsAdmin();
|
|
161
|
-
|
|
162
|
-
await SettingsPage.openProfile();
|
|
163
|
-
await SettingsPage.avatarInput.type('avatar.png');
|
|
164
|
-
await SettingsPage.successToast.shouldBeVisible();
|
|
165
|
-
});
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Every `@step:<name>` in `spec.md` must have a matching `Step.<name>()` call in the paired test
|
|
169
|
-
script, or `spectra lint` reports `testspectra/missing-step-call`. See the
|
|
170
|
-
`spec-and-suite-authoring` skill for the full linter rule matrix.
|
|
171
|
-
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
## 6. Renaming a Step or Action
|
|
175
|
-
|
|
176
|
-
Never rename a step/action folder by hand. Use:
|
|
177
|
-
|
|
178
|
-
```
|
|
179
|
-
spectra refactor step loginAsAdmin authenticateAdmin
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
This atomically: renames `support/steps/loginAsAdmin/` → `support/steps/authenticateAdmin/`,
|
|
183
|
-
updates `name:` in `step.md`, rewrites every `@step:loginAsAdmin` in every `spec.md`, rewrites
|
|
184
|
-
every `Step.loginAsAdmin()` call site, and regenerates `.testspectra/types/steps.d.ts`.
|
|
1
|
+
---
|
|
2
|
+
name: shared-steps-and-actions
|
|
3
|
+
description: The difference between TestSpectra Shared Steps (Step.*, high-level business workflows, documented in spec.md via @step) and Spectra Actions (support/actions, low-level technical utilities) — directory layout, the mandatory anonymous async default export convention, and ambient type generation. Use whenever extracting reusable logic out of a test script.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Shared Steps vs. Custom Actions
|
|
7
|
+
|
|
8
|
+
Use this skill when you're about to extract repeated logic (e.g. login, checkout) out of test
|
|
9
|
+
scripts, or when deciding whether new reusable logic belongs under `support/steps/` or
|
|
10
|
+
`support/actions/`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. Which One Do I Need?
|
|
15
|
+
|
|
16
|
+
| Attribute | Shared Steps (`Step.*`) | Custom Actions (`Spectra.*` / on-element helpers) |
|
|
17
|
+
| :---------------- | :--------------------------------------------- | :---------------------------------------------------------------------------- |
|
|
18
|
+
| Abstraction level | High-level business workflow (login, checkout) | Low-level technical utility |
|
|
19
|
+
| Directory | `support/steps/<stepName>/` | `support/actions/<actionName>/` |
|
|
20
|
+
| Spec mapping | Documented as `@step:<name>` in `spec.md` | Just called inline, not listed in spec steps |
|
|
21
|
+
| Metadata file | `step.md` (YAML frontmatter + description) | None — implementation file only |
|
|
22
|
+
| Files | `step.md` + `web.step.ts` [+ `mobile.step.ts`] | `web.action.ts` [+ `mobile.action.ts`] |
|
|
23
|
+
| Invocation | `await Step.loginAsAdmin(params)` | Called as a helper bound to an element/page, e.g. inside a Page Object method |
|
|
24
|
+
|
|
25
|
+
Rule of thumb: if it's a multi-step _business_ flow a human would describe in one sentence
|
|
26
|
+
("log in as admin"), it's a **Step**. If it's a small technical helper reused across Page Objects
|
|
27
|
+
(a resilient click retry, filling a pair of fields), it's an **Action**.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 2. Directory Layout
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
support/
|
|
35
|
+
├── steps/
|
|
36
|
+
│ └── loginAsAdmin/
|
|
37
|
+
│ ├── step.md # Metadata, docs, parameter types
|
|
38
|
+
│ ├── web.step.ts
|
|
39
|
+
│ └── mobile.step.ts # optional
|
|
40
|
+
└── actions/
|
|
41
|
+
└── fillCredentials/
|
|
42
|
+
├── web.action.ts
|
|
43
|
+
└── mobile.action.ts
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Both use **camelCase** directory/function names (`loginAsAdmin`, `fillCredentials`,
|
|
47
|
+
`applyDiscount`, `verifyOtp`) — never kebab-case or snake_case.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 3. `step.md` Metadata
|
|
52
|
+
|
|
53
|
+
```markdown
|
|
54
|
+
---
|
|
55
|
+
id: step-login-as-admin
|
|
56
|
+
name: loginAsAdmin
|
|
57
|
+
description: Authenticates as an administrator and asserts landing dashboard
|
|
58
|
+
platform:
|
|
59
|
+
- web
|
|
60
|
+
- mobile
|
|
61
|
+
tags:
|
|
62
|
+
- auth
|
|
63
|
+
- admin
|
|
64
|
+
parameters:
|
|
65
|
+
- name: email
|
|
66
|
+
type: string
|
|
67
|
+
required: false
|
|
68
|
+
description: Admin email address (defaults to Fixture.users.admin.email)
|
|
69
|
+
- name: password
|
|
70
|
+
type: string
|
|
71
|
+
required: false
|
|
72
|
+
description: Admin password (defaults to Fixture.users.admin.password)
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
# Login as Admin Step
|
|
76
|
+
|
|
77
|
+
## Purpose
|
|
78
|
+
|
|
79
|
+
Provides a standard, hardened administrative login sequence for web and mobile platforms.
|
|
80
|
+
|
|
81
|
+
## Prerequisites
|
|
82
|
+
|
|
83
|
+
- User fixture file exists at `fixtures/users.json`.
|
|
84
|
+
- Browser is navigated to the base URL or login route.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 4. Implementation: Anonymous Async Default Export (Mandatory)
|
|
90
|
+
|
|
91
|
+
Every `*.step.ts` and `*.action.ts` file exports **one anonymous async function as its default
|
|
92
|
+
export** — no named exports, no `test()`/`it()` blocks. This is enforced by the linter
|
|
93
|
+
(`testspectra/require-anonymous-default-export`).
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// support/steps/loginAsAdmin/web.step.ts
|
|
97
|
+
export default async function (params?: { email?: string; password?: string }) {
|
|
98
|
+
const email = params?.email ?? Fixture.users.admin.email;
|
|
99
|
+
const password = params?.password ?? Fixture.users.admin.password;
|
|
100
|
+
|
|
101
|
+
await Spectra.navigate('/auth/login');
|
|
102
|
+
await LoginPage.emailInput.type(email, { clearFirst: true });
|
|
103
|
+
await LoginPage.passwordInput.type(password);
|
|
104
|
+
await LoginPage.submitButton.click();
|
|
105
|
+
|
|
106
|
+
await DashboardPage.header.shouldBeVisible();
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Custom Actions follow the same shape and are commonly written with a `this` receiver so they can
|
|
111
|
+
be attached/bound as element/page helpers:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// support/actions/fillCredentials/web.action.ts
|
|
115
|
+
export default async function (this: any, email: string, token: string) {
|
|
116
|
+
await this.get('#demo-email-input-pg').type(email);
|
|
117
|
+
await this.get('#demo-token-input-pg').type(token);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// support/actions/fillCredentials/mobile.action.ts
|
|
123
|
+
export default async function (this: any, email: string, token: string) {
|
|
124
|
+
await this.get('~pg-email-input').type(email);
|
|
125
|
+
await this.get('~pg-token-input').type(token);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Zero-import applies here too: never manually `import` a Page Object, `Fixture`, or `Spectra` — see
|
|
130
|
+
the `workspace-structure` skill.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 5. Type Generation & Invocation
|
|
135
|
+
|
|
136
|
+
The `TypeGenerator` scans `support/steps/` and emits the `Step` ambient namespace automatically:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
declare global {
|
|
140
|
+
namespace Step {
|
|
141
|
+
function loginAsAdmin(params?: { email?: string; password?: string }): Promise<void>;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### In `spec.md` (documents the step as part of the human-readable flow):
|
|
147
|
+
|
|
148
|
+
```markdown
|
|
149
|
+
## Test Steps
|
|
150
|
+
|
|
151
|
+
1. @step:loginAsAdmin
|
|
152
|
+
2. Navigate to user settings page
|
|
153
|
+
3. Update profile avatar
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### In `web.test.ts` (invokes it with zero manual imports):
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
it('should update admin profile avatar', async () => {
|
|
160
|
+
await Step.loginAsAdmin();
|
|
161
|
+
|
|
162
|
+
await SettingsPage.openProfile();
|
|
163
|
+
await SettingsPage.avatarInput.type('avatar.png');
|
|
164
|
+
await SettingsPage.successToast.shouldBeVisible();
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Every `@step:<name>` in `spec.md` must have a matching `Step.<name>()` call in the paired test
|
|
169
|
+
script, or `spectra lint` reports `testspectra/missing-step-call`. See the
|
|
170
|
+
`spec-and-suite-authoring` skill for the full linter rule matrix.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 6. Renaming a Step or Action
|
|
175
|
+
|
|
176
|
+
Never rename a step/action folder by hand. Use:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
spectra refactor step loginAsAdmin authenticateAdmin
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This atomically: renames `support/steps/loginAsAdmin/` → `support/steps/authenticateAdmin/`,
|
|
183
|
+
updates `name:` in `step.md`, rewrites every `@step:loginAsAdmin` in every `spec.md`, rewrites
|
|
184
|
+
every `Step.loginAsAdmin()` call site, and regenerates `.testspectra/types/steps.d.ts`.
|
|
@@ -1,132 +1,132 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: spec-and-suite-authoring
|
|
3
|
-
description: How to write suite.md, spec.md, and the paired *.test.ts execution script for a TestSpectra test case — frontmatter schema, the @step directive convention, and every spec-schema-linter rule that must pass (single it(), no describe/test, zero-import, title parity). Use whenever creating or editing a test case.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Skill: Spec & Suite Authoring (`spec.md`, `suite.md`, `*.test.ts`)
|
|
7
|
-
|
|
8
|
-
Use this skill whenever you create a new test case, add a new suite, or edit an existing
|
|
9
|
-
`spec.md` / `*.test.ts` pair. TestSpectra treats the Markdown spec as the human-readable source of
|
|
10
|
-
truth and the TypeScript file as its execution — the CLI linter (`spectra lint`) enforces that the
|
|
11
|
-
two never drift apart.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 1. Directory Convention
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
specs/<SuiteName>/suite.md
|
|
19
|
-
specs/<SuiteName>/hooks/{before,beforeEach,afterEach,after}/web.hook.ts
|
|
20
|
-
specs/<SuiteName>/TC-<NNNN>-<kebab-slug>/spec.md
|
|
21
|
-
specs/<SuiteName>/TC-<NNNN>-<kebab-slug>/web.test.ts # + android/ios/mobile/common variants
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
`SuiteName` is a directory (no `describe()` block ever exists in code — the suite boundary is
|
|
25
|
-
purely the folder). The test case id (`TC-0001-valid-login`) is both the directory name and the
|
|
26
|
-
`id` in `spec.md`'s frontmatter, and must be unique across the entire workspace
|
|
27
|
-
(`testspectra/duplicate-spec-id`).
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## 2. `suite.md` Frontmatter
|
|
32
|
-
|
|
33
|
-
```markdown
|
|
34
|
-
---
|
|
35
|
-
name: Untitled Suite
|
|
36
|
-
id: suite-element-matchers
|
|
37
|
-
description: Element visibility, existence, form states and attributes
|
|
38
|
-
executionOrder: 1.0
|
|
39
|
-
parallel: true
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
# Suite: ElementMatchers
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## 3. `spec.md` Frontmatter & Body
|
|
48
|
-
|
|
49
|
-
```markdown
|
|
50
|
-
---
|
|
51
|
-
id: TC-0003-visibility-and-dom
|
|
52
|
-
title: Verify element visibility and existence matchers
|
|
53
|
-
priority: High
|
|
54
|
-
caseType: Positive
|
|
55
|
-
status: ready-for-automation
|
|
56
|
-
coverage:
|
|
57
|
-
web: automated
|
|
58
|
-
mobile: automated
|
|
59
|
-
---
|
|
60
|
-
|
|
61
|
-
# Verify element visibility and existence matchers
|
|
62
|
-
|
|
63
|
-
## Test Steps
|
|
64
|
-
|
|
65
|
-
1. Open visibility section in matchers page
|
|
66
|
-
2. Assert visible element has be.visible state
|
|
67
|
-
3. Assert existing element exists in DOM
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Required frontmatter: `id`, `title`, `priority`, `caseType`, `status` — missing any of these, or
|
|
71
|
-
missing the `# <Title>` / `## Test Steps` headings, triggers `testspectra/missing-frontmatter`.
|
|
72
|
-
Invalid enum values (an unrecognized `priority`, `caseType`, or `status`) trigger
|
|
73
|
-
`testspectra/invalid-frontmatter-enum`.
|
|
74
|
-
|
|
75
|
-
If the test case invokes a shared step (see the `shared-steps-and-actions` skill), reference it in
|
|
76
|
-
the `## Test Steps` list as `@step:<stepName>` — the linter cross-checks this against
|
|
77
|
-
`Step.<stepName>()` calls in the paired `*.test.ts`.
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
## 4. The Paired Test Script (`web.test.ts`)
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
it('Verify element visibility and existence matchers', async () => {
|
|
85
|
-
await MatchersPage.open('visibility');
|
|
86
|
-
|
|
87
|
-
await MatchersPage.visibleElement.shouldBeVisible();
|
|
88
|
-
await MatchersPage.hiddenElement.shouldNotBeVisible();
|
|
89
|
-
|
|
90
|
-
await MatchersPage.existingElement.shouldExist();
|
|
91
|
-
await Spectra.get('#demo-non-existent-el').shouldNotExist();
|
|
92
|
-
});
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Hard rules (each is a `spectra lint` error unless noted):
|
|
96
|
-
|
|
97
|
-
1. **Exactly one `it(...)` block, nothing else at the top level.** Zero or multiple `it()` blocks
|
|
98
|
-
→ `testspectra/single-it-required`.
|
|
99
|
-
2. **Never `test(...)`.** Only `it(...)` is allowed → `testspectra/no-test-block`.
|
|
100
|
-
3. **Never `describe(...)`.** Suite grouping is the directory, not code →
|
|
101
|
-
`testspectra/no-describe-block`.
|
|
102
|
-
4. **Zero manual `import`s.** See the `workspace-structure` skill →
|
|
103
|
-
`testspectra/no-manual-import`.
|
|
104
|
-
5. **`it()`'s title should read the same as `spec.md`'s `title`** (case-insensitive semantic
|
|
105
|
-
match). A mismatch is a warning, not an error → `testspectra/title-mismatch`.
|
|
106
|
-
6. **Every `@step:<name>` in `spec.md` must have a matching `Step.<name>()` call** in the test
|
|
107
|
-
script → `testspectra/missing-step-call` (error) if absent, and conversely a `Step.<name>()`
|
|
108
|
-
call not documented with `@step:<name>` in `spec.md` is
|
|
109
|
-
`testspectra/undocumented-step` (warning).
|
|
110
|
-
|
|
111
|
-
### Platform variants
|
|
112
|
-
|
|
113
|
-
A test case directory may contain any combination of `web.test.ts`, `android.test.ts`,
|
|
114
|
-
`ios.test.ts`, `mobile.test.ts`, `common.test.ts` — each is linted and can be run independently.
|
|
115
|
-
Reuse a shared step for the parts of the flow that are identical across platforms rather than
|
|
116
|
-
duplicating the `it()` body per platform.
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## 5. Running the Linter
|
|
121
|
-
|
|
122
|
-
- `spectra lint` — scan the whole workspace, human-readable output.
|
|
123
|
-
- `spectra lint --strict` — treat warnings as errors, exit code `1` on any diagnostic (use this in
|
|
124
|
-
CI).
|
|
125
|
-
- `spectra lint --json` — machine-readable diagnostics (what an AI agent should parse to
|
|
126
|
-
self-correct after generating a spec).
|
|
127
|
-
- `spectra lint <path>` — scan a single suite or test case folder.
|
|
128
|
-
|
|
129
|
-
Exit codes: `0` valid, `1` violations found, `2` fatal (malformed YAML/JSON).
|
|
130
|
-
|
|
131
|
-
After authoring or editing a `spec.md`/`*.test.ts` pair, run `spectra lint <path-to-that-case>`
|
|
132
|
-
before considering the task done.
|
|
1
|
+
---
|
|
2
|
+
name: spec-and-suite-authoring
|
|
3
|
+
description: How to write suite.md, spec.md, and the paired *.test.ts execution script for a TestSpectra test case — frontmatter schema, the @step directive convention, and every spec-schema-linter rule that must pass (single it(), no describe/test, zero-import, title parity). Use whenever creating or editing a test case.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Spec & Suite Authoring (`spec.md`, `suite.md`, `*.test.ts`)
|
|
7
|
+
|
|
8
|
+
Use this skill whenever you create a new test case, add a new suite, or edit an existing
|
|
9
|
+
`spec.md` / `*.test.ts` pair. TestSpectra treats the Markdown spec as the human-readable source of
|
|
10
|
+
truth and the TypeScript file as its execution — the CLI linter (`spectra lint`) enforces that the
|
|
11
|
+
two never drift apart.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. Directory Convention
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
specs/<SuiteName>/suite.md
|
|
19
|
+
specs/<SuiteName>/hooks/{before,beforeEach,afterEach,after}/web.hook.ts
|
|
20
|
+
specs/<SuiteName>/TC-<NNNN>-<kebab-slug>/spec.md
|
|
21
|
+
specs/<SuiteName>/TC-<NNNN>-<kebab-slug>/web.test.ts # + android/ios/mobile/common variants
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`SuiteName` is a directory (no `describe()` block ever exists in code — the suite boundary is
|
|
25
|
+
purely the folder). The test case id (`TC-0001-valid-login`) is both the directory name and the
|
|
26
|
+
`id` in `spec.md`'s frontmatter, and must be unique across the entire workspace
|
|
27
|
+
(`testspectra/duplicate-spec-id`).
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 2. `suite.md` Frontmatter
|
|
32
|
+
|
|
33
|
+
```markdown
|
|
34
|
+
---
|
|
35
|
+
name: Untitled Suite
|
|
36
|
+
id: suite-element-matchers
|
|
37
|
+
description: Element visibility, existence, form states and attributes
|
|
38
|
+
executionOrder: 1.0
|
|
39
|
+
parallel: true
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
# Suite: ElementMatchers
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 3. `spec.md` Frontmatter & Body
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
---
|
|
51
|
+
id: TC-0003-visibility-and-dom
|
|
52
|
+
title: Verify element visibility and existence matchers
|
|
53
|
+
priority: High
|
|
54
|
+
caseType: Positive
|
|
55
|
+
status: ready-for-automation
|
|
56
|
+
coverage:
|
|
57
|
+
web: automated
|
|
58
|
+
mobile: automated
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
# Verify element visibility and existence matchers
|
|
62
|
+
|
|
63
|
+
## Test Steps
|
|
64
|
+
|
|
65
|
+
1. Open visibility section in matchers page
|
|
66
|
+
2. Assert visible element has be.visible state
|
|
67
|
+
3. Assert existing element exists in DOM
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Required frontmatter: `id`, `title`, `priority`, `caseType`, `status` — missing any of these, or
|
|
71
|
+
missing the `# <Title>` / `## Test Steps` headings, triggers `testspectra/missing-frontmatter`.
|
|
72
|
+
Invalid enum values (an unrecognized `priority`, `caseType`, or `status`) trigger
|
|
73
|
+
`testspectra/invalid-frontmatter-enum`.
|
|
74
|
+
|
|
75
|
+
If the test case invokes a shared step (see the `shared-steps-and-actions` skill), reference it in
|
|
76
|
+
the `## Test Steps` list as `@step:<stepName>` — the linter cross-checks this against
|
|
77
|
+
`Step.<stepName>()` calls in the paired `*.test.ts`.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 4. The Paired Test Script (`web.test.ts`)
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
it('Verify element visibility and existence matchers', async () => {
|
|
85
|
+
await MatchersPage.open('visibility');
|
|
86
|
+
|
|
87
|
+
await MatchersPage.visibleElement.shouldBeVisible();
|
|
88
|
+
await MatchersPage.hiddenElement.shouldNotBeVisible();
|
|
89
|
+
|
|
90
|
+
await MatchersPage.existingElement.shouldExist();
|
|
91
|
+
await Spectra.get('#demo-non-existent-el').shouldNotExist();
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Hard rules (each is a `spectra lint` error unless noted):
|
|
96
|
+
|
|
97
|
+
1. **Exactly one `it(...)` block, nothing else at the top level.** Zero or multiple `it()` blocks
|
|
98
|
+
→ `testspectra/single-it-required`.
|
|
99
|
+
2. **Never `test(...)`.** Only `it(...)` is allowed → `testspectra/no-test-block`.
|
|
100
|
+
3. **Never `describe(...)`.** Suite grouping is the directory, not code →
|
|
101
|
+
`testspectra/no-describe-block`.
|
|
102
|
+
4. **Zero manual `import`s.** See the `workspace-structure` skill →
|
|
103
|
+
`testspectra/no-manual-import`.
|
|
104
|
+
5. **`it()`'s title should read the same as `spec.md`'s `title`** (case-insensitive semantic
|
|
105
|
+
match). A mismatch is a warning, not an error → `testspectra/title-mismatch`.
|
|
106
|
+
6. **Every `@step:<name>` in `spec.md` must have a matching `Step.<name>()` call** in the test
|
|
107
|
+
script → `testspectra/missing-step-call` (error) if absent, and conversely a `Step.<name>()`
|
|
108
|
+
call not documented with `@step:<name>` in `spec.md` is
|
|
109
|
+
`testspectra/undocumented-step` (warning).
|
|
110
|
+
|
|
111
|
+
### Platform variants
|
|
112
|
+
|
|
113
|
+
A test case directory may contain any combination of `web.test.ts`, `android.test.ts`,
|
|
114
|
+
`ios.test.ts`, `mobile.test.ts`, `common.test.ts` — each is linted and can be run independently.
|
|
115
|
+
Reuse a shared step for the parts of the flow that are identical across platforms rather than
|
|
116
|
+
duplicating the `it()` body per platform.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 5. Running the Linter
|
|
121
|
+
|
|
122
|
+
- `spectra lint` — scan the whole workspace, human-readable output.
|
|
123
|
+
- `spectra lint --strict` — treat warnings as errors, exit code `1` on any diagnostic (use this in
|
|
124
|
+
CI).
|
|
125
|
+
- `spectra lint --json` — machine-readable diagnostics (what an AI agent should parse to
|
|
126
|
+
self-correct after generating a spec).
|
|
127
|
+
- `spectra lint <path>` — scan a single suite or test case folder.
|
|
128
|
+
|
|
129
|
+
Exit codes: `0` valid, `1` violations found, `2` fatal (malformed YAML/JSON).
|
|
130
|
+
|
|
131
|
+
After authoring or editing a `spec.md`/`*.test.ts` pair, run `spectra lint <path-to-that-case>`
|
|
132
|
+
before considering the task done.
|