@schwabyio/gta 0.13.0 → 0.14.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.
- package/README.md +178 -1
- package/dist/FUNCTIONS.md +6 -3
- package/dist/SPEC.md +289 -111
- package/dist/THIRD_PARTY_NOTICES.txt +26 -0
- package/dist/chunks/chunk-4JUUUUWB.js +234 -0
- package/dist/chunks/chunk-4W4TFJ53.js +577 -0
- package/dist/chunks/{chunk-ABBBM5UZ.js → chunk-S563G22M.js} +8812 -1953
- package/dist/gta.js +1036 -998
- package/dist/index.d.ts +3 -0
- package/dist/index.js +14 -0
- package/dist/playwright.d.ts +37 -0
- package/dist/playwright.js +178 -0
- package/dist/types.d.ts +246 -0
- package/dist/worker.js +1 -1
- package/package.json +25 -2
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ The package has no dependencies to install: everything `gta` uses is bundled int
|
|
|
23
23
|
|
|
24
24
|
## A first project
|
|
25
25
|
|
|
26
|
-
A project is a folder holding a `collections/`
|
|
26
|
+
A project is a folder holding a `collections/` folder, an `environments/` one and a
|
|
27
27
|
`settings.yml`. The smallest project `gta` runs is three files:
|
|
28
28
|
|
|
29
29
|
```yaml
|
|
@@ -139,6 +139,43 @@ In a monorepo, projects that share a global project (`uses:` in `project.yml`) s
|
|
|
139
139
|
setting by setting it again in its own file. Each project still needs a `settings.yml`,
|
|
140
140
|
even an empty one.
|
|
141
141
|
|
|
142
|
+
## Project rules
|
|
143
|
+
|
|
144
|
+
A `rules.yml` beside `project.yml` writes down how a project's files are named, laid out
|
|
145
|
+
and written, so everyone working on it, people and coding agents alike, keeps it the
|
|
146
|
+
same:
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
# rules.yml
|
|
150
|
+
ids:
|
|
151
|
+
collections: kebab-case # or a pattern, such as '{folder}-[a-z0-9-]+'
|
|
152
|
+
layout:
|
|
153
|
+
folders: required # every collection in a folder of collections/
|
|
154
|
+
docs:
|
|
155
|
+
collections: required
|
|
156
|
+
tags:
|
|
157
|
+
allowed: [smoke, regression]
|
|
158
|
+
steps:
|
|
159
|
+
names: required
|
|
160
|
+
tests:
|
|
161
|
+
only: [gta] # tests call the gta.* functions, and nothing else
|
|
162
|
+
statusCode: required
|
|
163
|
+
guide: |
|
|
164
|
+
Name each step for what it proves.
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```sh
|
|
168
|
+
gta rules # the rules in effect, where each came from, what each means, the guide
|
|
169
|
+
gta lint # check every file against them
|
|
170
|
+
gta lint --json # the findings as JSON, for tools and agents
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`gta lint` prints each finding at its file and line, with the rule it breaks, and exits
|
|
174
|
+
`1` when it finds one. Rules never change a run: a file that breaks one still runs. A
|
|
175
|
+
global project's `rules.yml` is shared like its `settings.yml`, and a project changes or
|
|
176
|
+
turns off (`null`) any rule in its own file. Every rule is in
|
|
177
|
+
[SPEC.md §1.4](https://github.com/schwabyio/gravity/blob/main/SPEC.md#14-rulesyml).
|
|
178
|
+
|
|
142
179
|
## In CI
|
|
143
180
|
|
|
144
181
|
```yaml
|
|
@@ -147,11 +184,151 @@ even an empty one.
|
|
|
147
184
|
with:
|
|
148
185
|
node-version: 22
|
|
149
186
|
- run: npm install -g @schwabyio/gta
|
|
187
|
+
- run: gta lint
|
|
150
188
|
- run: gta all --environmentType staging --generateJUnitResults
|
|
151
189
|
env:
|
|
152
190
|
apiKey: ${{ secrets.STAGING_API_KEY }}
|
|
153
191
|
```
|
|
154
192
|
|
|
193
|
+
## From Playwright and other code
|
|
194
|
+
|
|
195
|
+
The package is also a library. A test written in code can run a collection or a request
|
|
196
|
+
set, then use the values it saved, such as a token or the id of a user it created, in a
|
|
197
|
+
browser test.
|
|
198
|
+
|
|
199
|
+
### Playwright
|
|
200
|
+
|
|
201
|
+
`@schwabyio/gta/playwright` gives you Playwright's `test` with a `gta` fixture. Point it
|
|
202
|
+
at the project in `playwright.config.ts`:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
// playwright.config.ts
|
|
206
|
+
import { defineConfig } from '@playwright/test'
|
|
207
|
+
import type { GravityConfig } from '@schwabyio/gta/playwright'
|
|
208
|
+
|
|
209
|
+
export default defineConfig<{}, GravityConfig>({
|
|
210
|
+
use: {
|
|
211
|
+
gravity: { project: '../api-tests', environment: 'staging' }
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
// tests/dashboard.spec.ts
|
|
218
|
+
import { test, expect } from '@schwabyio/gta/playwright'
|
|
219
|
+
|
|
220
|
+
test('a new user sees their dashboard', async ({ page, gta }) => {
|
|
221
|
+
// requests/create-user.yml, run as a use: step would run it
|
|
222
|
+
const user = await gta.use('create-user', { plan: 'pro' })
|
|
223
|
+
|
|
224
|
+
await page.goto(`/users/${user.values.userId}`)
|
|
225
|
+
await expect(page.getByRole('heading')).toHaveText('Welcome')
|
|
226
|
+
|
|
227
|
+
// collections/billing.yml, starting from what create-user saved
|
|
228
|
+
await gta.run('billing', { vars: user.values })
|
|
229
|
+
})
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
- Each `gta.run` and `gta.use` call is a step in Playwright's report. Each request is a
|
|
233
|
+
step inside it, linked to its step in the YAML, with the request and response attached.
|
|
234
|
+
- A run that fails fails the test at the line that called it, with what failed. With
|
|
235
|
+
`soft: true` the test goes on and fails at the end, as `expect.soft` does.
|
|
236
|
+
- `project` is relative to the folder `playwright.config.ts` is in, and defaults to it.
|
|
237
|
+
`environment`, `flags`, `bail` and `timeoutCollection` go beside it. The project opens
|
|
238
|
+
once per worker, so an environment's flag command runs once per worker.
|
|
239
|
+
- A run counts toward the test's timeout, and one still going when the test ends is
|
|
240
|
+
stopped.
|
|
241
|
+
- To use this `test` with fixtures of your own, combine them with Playwright's
|
|
242
|
+
`mergeTests`.
|
|
243
|
+
|
|
244
|
+
It needs `@playwright/test` 1.51 or later, which installing `gta` does not install.
|
|
245
|
+
|
|
246
|
+
**When the project is in another repository**, check it out beside the app's and read
|
|
247
|
+
its path from an environment variable, so a checkout anywhere else can say where it is:
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
// playwright.config.ts
|
|
251
|
+
export default defineConfig<{}, GravityConfig>({
|
|
252
|
+
use: {
|
|
253
|
+
gravity: { project: process.env.GTA_PROJECT ?? '../api-tests' }
|
|
254
|
+
}
|
|
255
|
+
})
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`project` names the folder holding `collections/`. A project that `uses:` a global
|
|
259
|
+
project needs the repository checked out whole, since the global project is found from
|
|
260
|
+
it. In CI, check out both:
|
|
261
|
+
|
|
262
|
+
```yaml
|
|
263
|
+
# .github/workflows/e2e.yml (steps)
|
|
264
|
+
- uses: actions/checkout@v4
|
|
265
|
+
with:
|
|
266
|
+
path: web
|
|
267
|
+
- uses: actions/checkout@v4
|
|
268
|
+
with:
|
|
269
|
+
repository: your-org/api-tests
|
|
270
|
+
path: api-tests
|
|
271
|
+
token: ${{ secrets.API_TESTS_TOKEN }} # when that repository is private
|
|
272
|
+
- uses: actions/setup-node@v4
|
|
273
|
+
with:
|
|
274
|
+
node-version: 22
|
|
275
|
+
- run: npm ci && npx playwright install --with-deps
|
|
276
|
+
working-directory: web
|
|
277
|
+
- run: npx playwright test
|
|
278
|
+
working-directory: web
|
|
279
|
+
env:
|
|
280
|
+
GTA_PROJECT: ${{ github.workspace }}/api-tests
|
|
281
|
+
apiKey: ${{ secrets.STAGING_API_KEY }}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Any other code
|
|
285
|
+
|
|
286
|
+
```js
|
|
287
|
+
import { openProject } from '@schwabyio/gta'
|
|
288
|
+
|
|
289
|
+
const project = await openProject('api-tests', { environment: 'staging' })
|
|
290
|
+
const login = await project.use('login', { username: 'alice' })
|
|
291
|
+
const checkout = await project.run('checkout', { vars: login.values })
|
|
292
|
+
if (!checkout.passed) throw new Error(checkout.failures)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**`openProject(folder, options)`** opens the project in `folder`, the one holding
|
|
296
|
+
`collections/`. The options are `environment`, `flags`, `bail` and `timeoutCollection`.
|
|
297
|
+
Each one you leave out comes from `settings.yml`, the same way `gta` reads it, but here
|
|
298
|
+
the project does not need a `settings.yml`.
|
|
299
|
+
|
|
300
|
+
**`project.run(collection, options)`** runs a collection the way `gta` runs it: setup,
|
|
301
|
+
then the steps once for each data row, then teardown. Name the collection by its id or
|
|
302
|
+
its place in `collections/` (`checkout/sessions`). `tags` and `notTags` don't apply,
|
|
303
|
+
since you name what runs, and a collection with `exclude: true` runs too. The options:
|
|
304
|
+
|
|
305
|
+
| Option | What it does |
|
|
306
|
+
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
307
|
+
| `steps` | Run only these steps, named as reports name them or numbered from 1. They run in the file's order, and setup and teardown still run. |
|
|
308
|
+
| `vars` | Values the run starts with. They sit over the environment and under a data row. |
|
|
309
|
+
| `bail` | Stop at the first failing step. |
|
|
310
|
+
| `signal` | An `AbortSignal` that stops the run. |
|
|
311
|
+
| `onResult` | `(result, step) => void`, called as each request finishes. |
|
|
312
|
+
|
|
313
|
+
**`project.use(name, params, options)`** runs reusable requests as a `use:` step would:
|
|
314
|
+
`login` is `requests/login.yml`, in the project or its global project. `params` are what
|
|
315
|
+
`with:` gives, and a param you leave out takes its default. The options are those of
|
|
316
|
+
`run`, without `steps`.
|
|
317
|
+
|
|
318
|
+
Both resolve to the same outcome, however the steps fare:
|
|
319
|
+
|
|
320
|
+
| Field | What it holds |
|
|
321
|
+
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
322
|
+
| `passed` | `true` when nothing failed or errored and the run finished. |
|
|
323
|
+
| `values` | Every value the run set or captured, by name: `gta.set`, and checks that save what they read, such as `'setAsCollectionVariable'`. Secrets are not hidden here. |
|
|
324
|
+
| `summary` | Totals, and every request's result as gta's JSON report holds it, with secrets shown as `[secret: NAME]`. |
|
|
325
|
+
| `steps` | Where each result's step is: its file and line. |
|
|
326
|
+
| `failures` | What went wrong, as `gta` prints it under Failures. Empty when the run passed. |
|
|
327
|
+
| `error` | Why the run did not start or finish: a file that will not load, `timeoutCollection`, or a cancel. Otherwise `null`. |
|
|
328
|
+
|
|
329
|
+
They reject only when a collection, step or reusable requests file doesn't exist, or a
|
|
330
|
+
value isn't a string, number, boolean or null. Types ship with the package.
|
|
331
|
+
|
|
155
332
|
## The file format
|
|
156
333
|
|
|
157
334
|
[SPEC.md](https://github.com/schwabyio/gravity/blob/main/SPEC.md) specifies every file,
|
package/dist/FUNCTIONS.md
CHANGED
|
@@ -49,7 +49,7 @@ goes, the order it runs in, and the other globals: `res`, `req`, `assert`, `para
|
|
|
49
49
|
## How calls behave
|
|
50
50
|
|
|
51
51
|
- **Every `tests` script of a step feeds one list of checks**: the collection's, the
|
|
52
|
-
step's, and those of an endpoint base, a base collection or
|
|
52
|
+
step's, and those of an endpoint base, a base collection or reusable requests it runs
|
|
53
53
|
under (SPEC.md §2.5–§2.7). Strict validation counts them all together.
|
|
54
54
|
- **A check that fails does not stop the script.** The checks after it still run, and
|
|
55
55
|
the step fails.
|
|
@@ -216,8 +216,11 @@ gta.expectResponseBodyToHaveUnorderedArray('users', [{ name: 'Ada' }, { name: /^
|
|
|
216
216
|
```
|
|
217
217
|
|
|
218
218
|
An object in the list matches an item holding each of its properties with that value, or
|
|
219
|
-
matching it when the value is a `RegExp`. The item may have others. A
|
|
220
|
-
|
|
219
|
+
matching it when the value is a `RegExp`. The item may have others. A property that is
|
|
220
|
+
itself an object is matched the same way, so `{ data: { status: 'reversed' } }` finds an
|
|
221
|
+
item whose `data` has that status, whatever else `data` holds. An array compares whole.
|
|
222
|
+
A pattern is tested against the value as text, so it never matches an item that is an
|
|
223
|
+
object or an array.
|
|
221
224
|
|
|
222
225
|
**A list of `{ pathToProperty, expectedValue, specialHandling? }` entries.** Together
|
|
223
226
|
they describe **one** item, property by property, and some item must match every entry.
|