@schwabyio/ata 0.0.0-stage → 0.20.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/LICENSE +21 -0
- package/README.md +352 -2
- package/dist/FUNCTIONS.md +594 -0
- package/dist/SPEC.md +2146 -0
- package/dist/THIRD_PARTY_NOTICES.txt +97 -0
- package/dist/ata.js +1938 -0
- package/dist/chunks/chunk-4LUFMFJ5.js +234 -0
- package/dist/chunks/chunk-I3XKICH2.js +592 -0
- package/dist/chunks/chunk-IY7FUPUW.js +67973 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +14 -0
- package/dist/playwright.d.ts +37 -0
- package/dist/playwright.js +183 -0
- package/dist/types.d.ts +255 -0
- package/dist/worker.js +14 -0
- package/package.json +72 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 schwabyio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,353 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ata
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The command-line runner of Accelerator Test Automation. Tests for HTTP APIs are plain YAML
|
|
4
|
+
files that live in your repository beside the code they test, and read and diff as text
|
|
5
|
+
in a pull request. `ata` runs them from a terminal or in CI, and writes JUnit, HTML and
|
|
6
|
+
JSON reports. Accelerator, the desktop app, edits and runs the same files on the same engine.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
You need Node.js 22.12 or later.
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npm install -g @schwabyio/ata
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or add it to a project's `package.json`, and run it there with `npx ata`:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npm install --save-dev @schwabyio/ata
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The package has no dependencies to install: everything `ata` uses is bundled into it.
|
|
23
|
+
|
|
24
|
+
## A first project
|
|
25
|
+
|
|
26
|
+
A project is a folder holding a `collections/` folder, an `environments/` one and a
|
|
27
|
+
`settings.yml`. The smallest project `ata` runs is three files:
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
# collections/health.yml
|
|
31
|
+
id: health
|
|
32
|
+
steps:
|
|
33
|
+
- name: service is up
|
|
34
|
+
GET: '{{baseUrl}}/health'
|
|
35
|
+
tests: |
|
|
36
|
+
ata.expectResponseStatusCodeToBe(200)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
# environments/local.yml
|
|
41
|
+
vars:
|
|
42
|
+
baseUrl: http://localhost:8080
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
# settings.yml: how ata runs the project
|
|
47
|
+
environmentType: local
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Then, from the project folder:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
ata all
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Collections
|
|
57
|
+
|
|
58
|
+
A collection is a list of requests, called steps. They run in order, and a later step can
|
|
59
|
+
use a value an earlier one saved, like `sessionId` here:
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
# collections/checkout.yml
|
|
63
|
+
id: checkout
|
|
64
|
+
headers:
|
|
65
|
+
Authorization: 'Bearer {{apiKey}}'
|
|
66
|
+
steps:
|
|
67
|
+
- name: create session
|
|
68
|
+
POST: '{{baseUrl}}/sessions'
|
|
69
|
+
body:
|
|
70
|
+
json: |
|
|
71
|
+
{ "amount": 1200 }
|
|
72
|
+
tests: |
|
|
73
|
+
ata.expectResponseStatusCodeToBe(201)
|
|
74
|
+
ata.expectResponseBodyToHaveProperty('id', 'sessionId', 'setAsCollectionVariable')
|
|
75
|
+
|
|
76
|
+
- name: read it back
|
|
77
|
+
GET: '{{baseUrl}}/sessions/{{sessionId}}'
|
|
78
|
+
tests: |
|
|
79
|
+
ata.expectResponseStatusCodeToBe(200)
|
|
80
|
+
ata.expectResponseBodyToHaveProperty('amount', 1200)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
An environment supplies the variables for one target. A secret's value is never written
|
|
84
|
+
in a file: it comes from the process environment variable of the same name, or from a
|
|
85
|
+
`.env` file that is not committed.
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
# environments/staging.yml
|
|
89
|
+
vars:
|
|
90
|
+
baseUrl: https://staging.example.com
|
|
91
|
+
apiKey: { secret: true }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Running
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
ata get # list what ata all would run
|
|
98
|
+
ata all # run every collection
|
|
99
|
+
ata smoke,checkout # run these collections, in this order
|
|
100
|
+
ata payments # run every collection in collections/payments/
|
|
101
|
+
ata all --tags smoke --generateJUnitResults
|
|
102
|
+
ata all --environmentType staging --limitConcurrency 8
|
|
103
|
+
ata all --json # print the results as JSON instead of the table
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Collections run in parallel up to `limitConcurrency`, each in a worker thread of its own.
|
|
107
|
+
The steps within a collection always run in order.
|
|
108
|
+
|
|
109
|
+
The exit code is `0` when everything passed, `1` when something failed, and `2` when
|
|
110
|
+
`ata` could not run at all, such as with a bad setting or an unknown collection.
|
|
111
|
+
`ata get` exits `1` when a collection is broken, or has a `use:`, an `extends:` or a
|
|
112
|
+
file its body sends that a run would stop at.
|
|
113
|
+
|
|
114
|
+
## Settings
|
|
115
|
+
|
|
116
|
+
Settings come from `settings.yml`, then `ATA_*` environment variables, then flags on the
|
|
117
|
+
command line, each overriding the one before. An unknown setting is an error.
|
|
118
|
+
`ata --help` lists them all, and `ata get` shows where each one came from:
|
|
119
|
+
|
|
120
|
+
| Setting | Default | What it does |
|
|
121
|
+
| ------------------------ | -------------- | -------------------------------------------------------------- |
|
|
122
|
+
| `environmentType` | none | The environment to run against: `environments/<name>.yml` |
|
|
123
|
+
| `limitConcurrency` | `1` | How many collections run at once |
|
|
124
|
+
| `timeoutCollection` | `3600000` | Milliseconds a collection may take before it is stopped |
|
|
125
|
+
| `bail` | `false` | Stop a collection at its first failing step |
|
|
126
|
+
| `tags` | none | Run only what has one of these tags |
|
|
127
|
+
| `notTags` | none | Leave out what has one of these tags |
|
|
128
|
+
| `generateJUnitResults` | `false` | Write `<testResultsBasePath>/junit/junit.xml` |
|
|
129
|
+
| `generateJsonResults` | `false` | Write `<testResultsBasePath>/json/results.json` |
|
|
130
|
+
| `generateHtmlResults` | `false` | Write `<testResultsBasePath>/html/`, a summary and a page each |
|
|
131
|
+
| `autoOpenTestResultHtml` | `false` | Write the HTML report and open it when the run ends |
|
|
132
|
+
| `testResultsBasePath` | `test-results` | Where reports go: relative to the project folder, or absolute |
|
|
133
|
+
|
|
134
|
+
A collection stopped at `timeoutCollection` still runs its teardown, for up to 60 seconds,
|
|
135
|
+
so it cleans up after itself; the failure says how the teardown went.
|
|
136
|
+
|
|
137
|
+
The results folder is emptied before every run, so everything in it is from the last one.
|
|
138
|
+
`ata` only ever deletes a folder that holds nothing but its own reports.
|
|
139
|
+
|
|
140
|
+
In a monorepo, projects that share a global project (`uses:` in `project.yml`) share its
|
|
141
|
+
`settings.yml` too. It comes before the project's own, so a project changes a shared
|
|
142
|
+
setting by setting it again in its own file. Each project still needs a `settings.yml`,
|
|
143
|
+
even an empty one.
|
|
144
|
+
|
|
145
|
+
## Project rules
|
|
146
|
+
|
|
147
|
+
A `rules.yml` beside `project.yml` writes down how a project's files are named, laid out
|
|
148
|
+
and written, so everyone working on it, people and coding agents alike, keeps it the
|
|
149
|
+
same:
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
# rules.yml
|
|
153
|
+
ids:
|
|
154
|
+
collections: kebab-case # or a pattern, such as '{folder}-[a-z0-9-]+'
|
|
155
|
+
layout:
|
|
156
|
+
folders: required # every collection in a folder of collections/
|
|
157
|
+
docs:
|
|
158
|
+
collections: required
|
|
159
|
+
tags:
|
|
160
|
+
allowed: [smoke, regression]
|
|
161
|
+
steps:
|
|
162
|
+
names: required
|
|
163
|
+
tests:
|
|
164
|
+
only: [ata] # tests call the ata.* functions, and nothing else
|
|
165
|
+
statusCode: required
|
|
166
|
+
guide: |
|
|
167
|
+
Name each step for what it proves.
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```sh
|
|
171
|
+
ata rules # the rules in effect, where each came from, what each means, the guide
|
|
172
|
+
ata lint # check every file against them
|
|
173
|
+
ata lint --json # the findings as JSON, for tools and agents
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
`ata lint` prints each finding at its file and line, with the rule it breaks, and exits
|
|
177
|
+
`1` when it finds one. Rules never change a run: a file that breaks one still runs. A
|
|
178
|
+
global project's `rules.yml` is shared like its `settings.yml`, and a project changes or
|
|
179
|
+
turns off (`null`) any rule in its own file. Every rule is in
|
|
180
|
+
[SPEC.md §1.4](https://github.com/schwabyio/accelerator/blob/main/SPEC.md#14-rulesyml).
|
|
181
|
+
|
|
182
|
+
## In CI
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
# .github/workflows/api-tests.yml (steps)
|
|
186
|
+
- uses: actions/setup-node@v4
|
|
187
|
+
with:
|
|
188
|
+
node-version: 22
|
|
189
|
+
- run: npm install -g @schwabyio/ata
|
|
190
|
+
- run: ata lint
|
|
191
|
+
- run: ata all --environmentType staging --generateJUnitResults
|
|
192
|
+
env:
|
|
193
|
+
apiKey: ${{ secrets.STAGING_API_KEY }}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## From Playwright and other code
|
|
197
|
+
|
|
198
|
+
The package is also a library. A test written in code can run a collection or a request
|
|
199
|
+
set, then use the values it saved, such as a token or the id of a user it created, in a
|
|
200
|
+
browser test.
|
|
201
|
+
|
|
202
|
+
### Playwright
|
|
203
|
+
|
|
204
|
+
`@schwabyio/ata/playwright` gives you Playwright's `test` with an `ata` fixture. Point it
|
|
205
|
+
at the project in `playwright.config.ts`:
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
// playwright.config.ts
|
|
209
|
+
import { defineConfig } from '@playwright/test'
|
|
210
|
+
import type { AcceleratorConfig } from '@schwabyio/ata/playwright'
|
|
211
|
+
|
|
212
|
+
export default defineConfig<{}, AcceleratorConfig>({
|
|
213
|
+
use: {
|
|
214
|
+
accelerator: { project: '../api-tests', environment: 'staging' }
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
// tests/dashboard.spec.ts
|
|
221
|
+
import { test, expect } from '@schwabyio/ata/playwright'
|
|
222
|
+
|
|
223
|
+
test('a new user sees their dashboard', async ({ page, ata }) => {
|
|
224
|
+
// requests/create-user.yml, run as a use: step would run it
|
|
225
|
+
const user = await ata.use('create-user', { plan: 'pro' })
|
|
226
|
+
|
|
227
|
+
await page.goto(`/users/${user.values.userId}`)
|
|
228
|
+
await expect(page.getByRole('heading')).toHaveText('Welcome')
|
|
229
|
+
|
|
230
|
+
// collections/billing.yml, starting from what create-user saved
|
|
231
|
+
await ata.run('billing', { vars: user.values })
|
|
232
|
+
})
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
- Each `ata.run` and `ata.use` call is a step in Playwright's report. Each request is a
|
|
236
|
+
step inside it, linked to its step in the YAML, with the request and response attached.
|
|
237
|
+
- A run that fails fails the test at the line that called it, with what failed. With
|
|
238
|
+
`soft: true` the test goes on and fails at the end, as `expect.soft` does.
|
|
239
|
+
- `project` is relative to the folder `playwright.config.ts` is in, and defaults to it.
|
|
240
|
+
`environment`, `flags`, `bail` and `timeoutCollection` go beside it. The project opens
|
|
241
|
+
once per worker, so an environment's flag command runs once per worker.
|
|
242
|
+
- A run counts toward the test's timeout, and one still going when the test ends is
|
|
243
|
+
stopped.
|
|
244
|
+
- To use this `test` with fixtures of your own, combine them with Playwright's
|
|
245
|
+
`mergeTests`.
|
|
246
|
+
|
|
247
|
+
It needs `@playwright/test` 1.51 or later, which installing `ata` does not install.
|
|
248
|
+
|
|
249
|
+
**When the project is in another repository**, check it out beside the app's and read
|
|
250
|
+
its path from an environment variable, so a checkout anywhere else can say where it is:
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
// playwright.config.ts
|
|
254
|
+
export default defineConfig<{}, AcceleratorConfig>({
|
|
255
|
+
use: {
|
|
256
|
+
accelerator: { project: process.env.ATA_PROJECT ?? '../api-tests' }
|
|
257
|
+
}
|
|
258
|
+
})
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`project` names the folder holding `collections/`. A project that `uses:` a global
|
|
262
|
+
project needs the repository checked out whole, since the global project is found from
|
|
263
|
+
it. In CI, check out both:
|
|
264
|
+
|
|
265
|
+
```yaml
|
|
266
|
+
# .github/workflows/e2e.yml (steps)
|
|
267
|
+
- uses: actions/checkout@v4
|
|
268
|
+
with:
|
|
269
|
+
path: web
|
|
270
|
+
- uses: actions/checkout@v4
|
|
271
|
+
with:
|
|
272
|
+
repository: your-org/api-tests
|
|
273
|
+
path: api-tests
|
|
274
|
+
token: ${{ secrets.API_TESTS_TOKEN }} # when that repository is private
|
|
275
|
+
- uses: actions/setup-node@v4
|
|
276
|
+
with:
|
|
277
|
+
node-version: 22
|
|
278
|
+
- run: npm ci && npx playwright install --with-deps
|
|
279
|
+
working-directory: web
|
|
280
|
+
- run: npx playwright test
|
|
281
|
+
working-directory: web
|
|
282
|
+
env:
|
|
283
|
+
ATA_PROJECT: ${{ github.workspace }}/api-tests
|
|
284
|
+
apiKey: ${{ secrets.STAGING_API_KEY }}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Any other code
|
|
288
|
+
|
|
289
|
+
```js
|
|
290
|
+
import { openProject } from '@schwabyio/ata'
|
|
291
|
+
|
|
292
|
+
const project = await openProject('api-tests', { environment: 'staging' })
|
|
293
|
+
const login = await project.use('login', { username: 'alice' })
|
|
294
|
+
const checkout = await project.run('checkout', { vars: login.values })
|
|
295
|
+
if (!checkout.passed) throw new Error(checkout.failures)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**`openProject(folder, options)`** opens the project in `folder`, the one holding
|
|
299
|
+
`collections/`. The options are `environment`, `flags`, `bail` and `timeoutCollection`.
|
|
300
|
+
Each one you leave out comes from `settings.yml`, the same way `ata` reads it, but here
|
|
301
|
+
the project does not need a `settings.yml`.
|
|
302
|
+
|
|
303
|
+
**`project.run(collection, options)`** runs a collection the way `ata` runs it: setup,
|
|
304
|
+
then the steps once for each data row, then teardown. Name the collection by its id or
|
|
305
|
+
its place in `collections/` (`checkout/sessions`). `tags` and `notTags` don't apply,
|
|
306
|
+
since you name what runs, and a collection or step with `exclude: true` runs too. The options:
|
|
307
|
+
|
|
308
|
+
| Option | What it does |
|
|
309
|
+
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
310
|
+
| `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. |
|
|
311
|
+
| `vars` | Values the run starts with. They sit over the environment and under a data row. |
|
|
312
|
+
| `bail` | Stop at the first failing step. |
|
|
313
|
+
| `signal` | An `AbortSignal` that stops the run. Its teardown still runs after it, for up to 60 seconds. |
|
|
314
|
+
| `onResult` | `(result, step) => void`, called as each request finishes. |
|
|
315
|
+
|
|
316
|
+
**`project.use(name, params, options)`** runs reusable requests as a `use:` step would:
|
|
317
|
+
`login` is `requests/login.yml`, in the project or its global project. `params` are what
|
|
318
|
+
`with:` gives, and a param you leave out takes its default. The options are those of
|
|
319
|
+
`run`, without `steps`.
|
|
320
|
+
|
|
321
|
+
Both resolve to the same outcome, however the steps fare:
|
|
322
|
+
|
|
323
|
+
| Field | What it holds |
|
|
324
|
+
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
325
|
+
| `passed` | `true` when nothing failed or errored and the run finished. |
|
|
326
|
+
| `values` | Every value the run set or captured, by name: `ata.set`, and checks that save what they read, such as `'setAsCollectionVariable'`. Secrets are not hidden here. |
|
|
327
|
+
| `summary` | Totals, and every request's result as ata's JSON report holds it, with secrets shown as `[secret: NAME]`. |
|
|
328
|
+
| `steps` | Where each result's step is: its file and line. |
|
|
329
|
+
| `failures` | What went wrong, as `ata` prints it under Failures. Empty when the run passed. |
|
|
330
|
+
| `error` | Why the run did not start or finish: a file that will not load, `timeoutCollection`, or a cancel. Otherwise `null`. |
|
|
331
|
+
|
|
332
|
+
They reject only when a collection, step or reusable requests file doesn't exist, or a
|
|
333
|
+
value isn't a string, number, boolean or null. Types ship with the package.
|
|
334
|
+
|
|
335
|
+
## The file format
|
|
336
|
+
|
|
337
|
+
[SPEC.md](https://github.com/schwabyio/accelerator/blob/main/SPEC.md) specifies every file,
|
|
338
|
+
every key, and every rule that makes a file invalid. It is written for people and coding
|
|
339
|
+
agents alike, and ends with a complete project to start from. It also ships in this
|
|
340
|
+
package as `dist/SPEC.md`, and `ata`'s messages cite its sections, as in "(SPEC.md §2.5)".
|
|
341
|
+
|
|
342
|
+
[FUNCTIONS.md](https://github.com/schwabyio/accelerator/blob/main/FUNCTIONS.md) documents every
|
|
343
|
+
`ata` function that `tests` and `before.script` can call, with examples. It ships as
|
|
344
|
+
`dist/FUNCTIONS.md`.
|
|
345
|
+
|
|
346
|
+
[SETUP-AND-TEARDOWN.md](https://github.com/schwabyio/accelerator/blob/main/SETUP-AND-TEARDOWN.md)
|
|
347
|
+
is an overview of setup and teardown: how they run, when to use them, and when plain steps
|
|
348
|
+
or reusable requests do better.
|
|
349
|
+
|
|
350
|
+
## License
|
|
351
|
+
|
|
352
|
+
MIT. The packages bundled into `ata` keep their own licenses, collected in
|
|
353
|
+
`dist/THIRD_PARTY_NOTICES.txt`.
|