@schwabyio/gta 0.11.0 → 0.13.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/README.md +4 -0
- package/dist/FUNCTIONS.md +560 -0
- package/dist/SPEC.md +223 -50
- package/dist/chunks/{chunk-OM3ZR56O.js → chunk-ABBBM5UZ.js} +709 -157
- package/dist/gta.js +18 -5
- package/dist/worker.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -159,6 +159,10 @@ every key, and every rule that makes a file invalid. It is written for people an
|
|
|
159
159
|
agents alike, and ends with a complete project to start from. It also ships in this
|
|
160
160
|
package as `dist/SPEC.md`, and `gta`'s messages cite its sections, as in "(SPEC.md §2.5)".
|
|
161
161
|
|
|
162
|
+
[FUNCTIONS.md](https://github.com/schwabyio/gravity/blob/main/FUNCTIONS.md) documents every
|
|
163
|
+
`gta` function that `tests` and `before.script` can call, with examples. It ships as
|
|
164
|
+
`dist/FUNCTIONS.md`.
|
|
165
|
+
|
|
162
166
|
## License
|
|
163
167
|
|
|
164
168
|
MIT. The packages bundled into `gta` keep their own licenses, collected in
|
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
# The `gta` functions
|
|
2
|
+
|
|
3
|
+
Code in a collection runs in two places: `before.script`, before a request is sent, and
|
|
4
|
+
`tests`, after its response arrives. Both have a `gta` object, with nothing to import or
|
|
5
|
+
load. This document lists every function on it.
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
- name: get user
|
|
9
|
+
GET: '{{baseUrl}}/users/7'
|
|
10
|
+
before:
|
|
11
|
+
script: |
|
|
12
|
+
gta.set('traceId', gta.uuidv7())
|
|
13
|
+
tests: |
|
|
14
|
+
gta.expectResponseStatusCodeToBe(200)
|
|
15
|
+
gta.expectResponseBodyToHaveProperty('user.name', 'Ada')
|
|
16
|
+
gta.expectResponseBodyToHaveProperty('user.email', 'userEmail', 'setAsCollectionVariable')
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
[SPEC.md](./SPEC.md) specifies the files this code lives in. §5 there covers where code
|
|
20
|
+
goes, the order it runs in, and the other globals: `res`, `req`, `assert`, `params`,
|
|
21
|
+
`endpoint` and `checks`.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## At a glance
|
|
26
|
+
|
|
27
|
+
| Function | What it does | `tests` | `before.script` |
|
|
28
|
+
| ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------- | :-----: | :-------------: |
|
|
29
|
+
| [`expectResponseStatusCodeToBe`](#gtaexpectresponsestatuscodetobe) | Check the status code | ✓ | |
|
|
30
|
+
| [`expectResponseToHaveHeader`](#gtaexpectresponsetohaveheader) | Check a header | ✓ | |
|
|
31
|
+
| [`expectResponseBodyToHaveProperty`](#gtaexpectresponsebodytohaveproperty) | Check a property of the body | ✓ | |
|
|
32
|
+
| [`expectResponseBodyToHaveUnorderedArray`](#gtaexpectresponsebodytohaveunorderedarray) | Check an array holds items, in any order | ✓ | |
|
|
33
|
+
| [`expectResponseBodyToHaveUnorderedArrayNotThisItem`](#gtaexpectresponsebodytohaveunorderedarraynotthisitem) | Check an array holds none of some items | ✓ | |
|
|
34
|
+
| [`sortResponseBodyArrays`](#gtasortresponsebodyarrays) | Sort arrays before the checks after it | ✓ | |
|
|
35
|
+
| [`useStrictValidation`](#gtausestrictvalidation) | Fail when any body property goes unchecked | ✓ | |
|
|
36
|
+
| [`ignoreResponseBodyProperty`](#gtaignoreresponsebodyproperty) | Leave a property out of strict validation | ✓ | |
|
|
37
|
+
| [`ignoreResponseBodyArrayObjectProperty`](#gtaignoreresponsebodyarrayobjectproperty) | The same, for a property of every item of an array | ✓ | |
|
|
38
|
+
| [`test`](#gtatest) | A named check of your own | ✓ | |
|
|
39
|
+
| [`get`](#gtaget) | Read a variable | ✓ | ✓ |
|
|
40
|
+
| [`set`](#gtaset) | Set a variable for the steps after | ✓ | ✓ |
|
|
41
|
+
| [`skip`](#gtaskip) | Send nothing for this step | | ✓ |
|
|
42
|
+
| [`skipRest`](#gtaskiprest) | Skip the steps after this one | ✓ | ✓ |
|
|
43
|
+
| [`flag`](#gtaflag) | Read a feature flag | ✓ | ✓ |
|
|
44
|
+
| [`uuid`](#gtauuid) | A random UUID | ✓ | ✓ |
|
|
45
|
+
| [`uuidv7`](#gtauuidv7) | A time-ordered UUID | ✓ | ✓ |
|
|
46
|
+
| [`randomInt`](#gtarandomint) | A random whole number | ✓ | ✓ |
|
|
47
|
+
| [`date`](#gtadate) | A formatted date, now or offset from now | ✓ | ✓ |
|
|
48
|
+
|
|
49
|
+
## How calls behave
|
|
50
|
+
|
|
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 a request set it runs
|
|
53
|
+
under (SPEC.md §2.5–§2.7). Strict validation counts them all together.
|
|
54
|
+
- **A check that fails does not stop the script.** The checks after it still run, and
|
|
55
|
+
the step fails.
|
|
56
|
+
- **A mistake in how a check is called is a failed check** that says what is wrong: an
|
|
57
|
+
unknown `specialHandling`, a length that is not a number, a path that is neither text
|
|
58
|
+
nor a list. The checks after it still run.
|
|
59
|
+
- **Any other error stops the script**: a misspelled function name, a call that belongs
|
|
60
|
+
in the other script, or a JavaScript error. The step is marked errored, with the line,
|
|
61
|
+
and checks made before it are kept.
|
|
62
|
+
- **A script is stopped after 10 seconds.**
|
|
63
|
+
- **Check files** in `checks/` call `gta` too, and what they check is reported on the
|
|
64
|
+
step that called them (SPEC.md §5).
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Checking the response
|
|
69
|
+
|
|
70
|
+
These run in `tests`. Calling one in `before.script` is an error, since nothing has been
|
|
71
|
+
received yet.
|
|
72
|
+
|
|
73
|
+
### Paths
|
|
74
|
+
|
|
75
|
+
A path finds a property in the body:
|
|
76
|
+
|
|
77
|
+
| Path | Finds |
|
|
78
|
+
| --------------------------------------- | --------------------------------------------------------------- |
|
|
79
|
+
| `user.name` | A property of a property |
|
|
80
|
+
| `groups.0.name` or `groups[0].name` | A property of an array's first item |
|
|
81
|
+
| `sessions[].id` | The property of every item of an array |
|
|
82
|
+
| `jwt.payload["https://x.io/id"]` | A key holding `.`, `[` or `]`, written in brackets as JSON text |
|
|
83
|
+
| `modules[""].edition` | An empty key |
|
|
84
|
+
| `['jwt', 'payload', 'https://x.io/id']` | A list of keys: each item is one key, whatever it holds |
|
|
85
|
+
|
|
86
|
+
In a list of keys a number is its digits, so `['groups', 0, 'name']` reads an index.
|
|
87
|
+
Every function that takes a path takes a list too, and so does `pathToProperty`.
|
|
88
|
+
|
|
89
|
+
The body is read as checks need it. JSON is used as it is. XML is converted: the root
|
|
90
|
+
element is the one top-level key, an element holding only text becomes that text, and a
|
|
91
|
+
repeated element becomes an array. A text or HTML body is one property, `plaintext`.
|
|
92
|
+
An event stream (`text/event-stream`) is a list with one item per event, holding its
|
|
93
|
+
`data` and, when the event set them, its `event` and `id`: `[1].data.price` is the
|
|
94
|
+
second event's price. SPEC.md §3 has the full rules.
|
|
95
|
+
|
|
96
|
+
### Values
|
|
97
|
+
|
|
98
|
+
- **A body property compares with its type.** `'12345'` does not equal `12345`, and the
|
|
99
|
+
failure says which is which.
|
|
100
|
+
- **The status and headers compare as text**, so `200` and `'200'` are the same.
|
|
101
|
+
- **A `RegExp` is a pattern**, flags included, tested against the value as text.
|
|
102
|
+
|
|
103
|
+
### `specialHandling`
|
|
104
|
+
|
|
105
|
+
The last argument of a check may be one of these strings, to change what it asks:
|
|
106
|
+
|
|
107
|
+
| String | Means |
|
|
108
|
+
| -------------------------- | ----------------------------------------------------------------------------------- |
|
|
109
|
+
| _(none, and no value)_ | The property or header is present. |
|
|
110
|
+
| `notThisExpectedKey` | It must not be present. Pass `null` as the value. |
|
|
111
|
+
| `notThisExpectedValue` | It must be present, and not equal the value or match the `RegExp`. |
|
|
112
|
+
| `setAsCollectionVariable` | Save it into the variable the value names, for the steps after. It must be present. |
|
|
113
|
+
| `setAsEnvironmentVariable` | The same. Nothing is written to the environment file. |
|
|
114
|
+
| `dateAsEpoch` | Epoch milliseconds, on the calendar day the value names (below). |
|
|
115
|
+
| `dateWithin<X>Sec` | A date within X seconds of the value, as in `dateWithin5Sec`. |
|
|
116
|
+
| `integerWithin<X>` | A number within X of the value, as in `integerWithin2`. |
|
|
117
|
+
| `isArray` | An array. What it holds is not checked. Pass `null` as the value. |
|
|
118
|
+
| `isArrayAndEmpty` | An empty array. Pass `null` as the value. |
|
|
119
|
+
| `isArrayAndNotEmpty` | An array with at least one item. Pass `null` as the value. |
|
|
120
|
+
| `isArrayAndHasLength` | An array of exactly the value's length. |
|
|
121
|
+
|
|
122
|
+
- The status takes `notThisExpectedValue` and the two `setAs…` strings. A header takes
|
|
123
|
+
those and `notThisExpectedKey`. The rest are for body properties.
|
|
124
|
+
- **`dateAsEpoch`**: the property holds epoch milliseconds, as a number or as digits.
|
|
125
|
+
The value is a number of seconds from now (`0` is today, `86400` tomorrow), or a date
|
|
126
|
+
whose first ten characters, `2026-10-01`, must match. Days are the calendar days of
|
|
127
|
+
the machine running the test.
|
|
128
|
+
- **`dateWithin<X>Sec`**: the property and the value are each an ISO 8601 date or epoch
|
|
129
|
+
milliseconds.
|
|
130
|
+
- **Saving** keeps a string, number, boolean or null as it is. An object or array is
|
|
131
|
+
saved as its JSON text.
|
|
132
|
+
|
|
133
|
+
### `gta.expectResponseStatusCodeToBe`
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
gta.expectResponseStatusCodeToBe(expected, specialHandling?)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The status code is `expected`, or matches it.
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
gta.expectResponseStatusCodeToBe(201)
|
|
143
|
+
gta.expectResponseStatusCodeToBe(/^2\d\d$/) // any 2xx
|
|
144
|
+
gta.expectResponseStatusCodeToBe(500, 'notThisExpectedValue') // anything but 500
|
|
145
|
+
gta.expectResponseStatusCodeToBe('lastStatus', 'setAsCollectionVariable')
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `gta.expectResponseToHaveHeader`
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
gta.expectResponseToHaveHeader(name, expected?, specialHandling?)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The header is present, and with `expected`, equals it or matches it.
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
gta.expectResponseToHaveHeader('X-Request-Id')
|
|
158
|
+
gta.expectResponseToHaveHeader('Content-Type', /^application\/json/)
|
|
159
|
+
gta.expectResponseToHaveHeader('Cache-Control', 'no-store')
|
|
160
|
+
gta.expectResponseToHaveHeader('X-Debug', null, 'notThisExpectedKey')
|
|
161
|
+
gta.expectResponseToHaveHeader('Server', /nginx/, 'notThisExpectedValue')
|
|
162
|
+
gta.expectResponseToHaveHeader('X-Request-Id', 'requestId', 'setAsCollectionVariable')
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
- The name matches in any case.
|
|
166
|
+
- A header sent more than once is its values joined with `, `, as in `a=1, b=2`.
|
|
167
|
+
|
|
168
|
+
### `gta.expectResponseBodyToHaveProperty`
|
|
169
|
+
|
|
170
|
+
```js
|
|
171
|
+
gta.expectResponseBodyToHaveProperty(path, expected?, specialHandling?)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The property at [`path`](#paths) is present, and with `expected`, equals it or matches
|
|
175
|
+
it.
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
gta.expectResponseBodyToHaveProperty('user.id')
|
|
179
|
+
gta.expectResponseBodyToHaveProperty('user.name', 'Ada')
|
|
180
|
+
gta.expectResponseBodyToHaveProperty('user.email', /@example\.com$/)
|
|
181
|
+
gta.expectResponseBodyToHaveProperty('user.nickname', null, 'notThisExpectedKey')
|
|
182
|
+
gta.expectResponseBodyToHaveProperty('user.score', 100, 'integerWithin2')
|
|
183
|
+
gta.expectResponseBodyToHaveProperty('user.roles', 2, 'isArrayAndHasLength')
|
|
184
|
+
gta.expectResponseBodyToHaveProperty('user.token', 'token', 'setAsCollectionVariable')
|
|
185
|
+
gta.expectResponseBodyToHaveProperty('items[].status', 'active') // every item
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
- **`expected` is a string, number, boolean, `null` or `RegExp`.** An object or array
|
|
189
|
+
never equals one. Check its properties one by one, use
|
|
190
|
+
[`expectResponseBodyToHaveUnorderedArray`](#gtaexpectresponsebodytohaveunorderedarray)
|
|
191
|
+
for an array, or compare it in [`gta.test`](#gtatest) with `assert.deepEqual`.
|
|
192
|
+
- **A property whose value is `null` is present.**
|
|
193
|
+
- **A path that runs into a `null` before its end**, such as `phone.number` when `phone`
|
|
194
|
+
is `null`, reads as `null` for a check that the value is `null`. For any other check,
|
|
195
|
+
the property is not present.
|
|
196
|
+
- **A path with `[]` checks every item**, and passes only when each one does. An empty
|
|
197
|
+
array has no items, so the property is not present. Saving one saves every item's
|
|
198
|
+
value, as a JSON list.
|
|
199
|
+
|
|
200
|
+
### `gta.expectResponseBodyToHaveUnorderedArray`
|
|
201
|
+
|
|
202
|
+
```js
|
|
203
|
+
gta.expectResponseBodyToHaveUnorderedArray(path, list)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The array at `path` holds what `list` describes, in any order. `list` takes one of two
|
|
207
|
+
forms.
|
|
208
|
+
|
|
209
|
+
**A list of values.** Each must be in the array, which may hold others too. A `RegExp`
|
|
210
|
+
is a pattern, which some item must match:
|
|
211
|
+
|
|
212
|
+
```js
|
|
213
|
+
gta.expectResponseBodyToHaveUnorderedArray('roles', ['admin', 'editor'])
|
|
214
|
+
gta.expectResponseBodyToHaveUnorderedArray('roles', [/^admin/, 'editor'])
|
|
215
|
+
gta.expectResponseBodyToHaveUnorderedArray('users', [{ name: 'Ada' }, { name: /^Grace/ }])
|
|
216
|
+
```
|
|
217
|
+
|
|
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 pattern is tested
|
|
220
|
+
against the value as text, so it never matches an item that is an object or an array.
|
|
221
|
+
|
|
222
|
+
**A list of `{ pathToProperty, expectedValue, specialHandling? }` entries.** Together
|
|
223
|
+
they describe **one** item, property by property, and some item must match every entry.
|
|
224
|
+
Call the function once for each item:
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
gta.expectResponseBodyToHaveUnorderedArray('users', [
|
|
228
|
+
{ pathToProperty: 'name', expectedValue: 'Ada' },
|
|
229
|
+
{ pathToProperty: 'role', expectedValue: /^admin/ },
|
|
230
|
+
{ pathToProperty: 'nickname', expectedValue: null, specialHandling: 'notThisExpectedKey' },
|
|
231
|
+
{ pathToProperty: 'id', expectedValue: 'adaId', specialHandling: 'setAsCollectionVariable' }
|
|
232
|
+
])
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
- `pathToProperty` is a path inside the item. `specialHandling` is any of the strings
|
|
236
|
+
above, and a save takes its value from the item that matched.
|
|
237
|
+
- A property may be named twice: once to check it, and once to save it.
|
|
238
|
+
- **Each call prefers items an earlier call did not match.** Two calls with the same
|
|
239
|
+
description find two items when there are two, so each saves from, and strict
|
|
240
|
+
validation counts, a different one. A sort starts this over.
|
|
241
|
+
- **A list of one `notThisExpectedValue` entry depends on strict validation.** Without
|
|
242
|
+
it, the entry means no item has that value, so an empty array passes. With it, the
|
|
243
|
+
entry means one item whose value is something else, as any list does. The step's last
|
|
244
|
+
call to `useStrictValidation` decides.
|
|
245
|
+
|
|
246
|
+
### `gta.expectResponseBodyToHaveUnorderedArrayNotThisItem`
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
gta.expectResponseBodyToHaveUnorderedArrayNotThisItem(path, list)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
No item of the array at `path` matches what `list` describes.
|
|
253
|
+
|
|
254
|
+
```js
|
|
255
|
+
gta.expectResponseBodyToHaveUnorderedArrayNotThisItem('roles', ['owner', /^guest/])
|
|
256
|
+
gta.expectResponseBodyToHaveUnorderedArrayNotThisItem('users', [
|
|
257
|
+
{ pathToProperty: 'status', compareValue: 'deleted' },
|
|
258
|
+
{ pathToProperty: 'email', compareValue: /@test\.invalid$/ }
|
|
259
|
+
])
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
- A list of values: none of them may be in the array, and no item may match a `RegExp`
|
|
263
|
+
among them. An object in the list may hold patterns too, as above.
|
|
264
|
+
- A list of `{ pathToProperty, compareValue }` entries describes one item. The check
|
|
265
|
+
fails when some item matches every entry. `compareValue` may be a `RegExp`.
|
|
266
|
+
- **The key is `compareValue`, not `expectedValue`.** An entry without it matches no
|
|
267
|
+
item, so the check always passes.
|
|
268
|
+
|
|
269
|
+
### `gta.sortResponseBodyArrays`
|
|
270
|
+
|
|
271
|
+
```js
|
|
272
|
+
gta.sortResponseBodyArrays(property)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Sorts every array of objects that holds `property`, anywhere in the body, for the
|
|
276
|
+
checks after it. Use it when an API returns a list in no fixed order and a check names
|
|
277
|
+
an index.
|
|
278
|
+
|
|
279
|
+
```js
|
|
280
|
+
gta.sortResponseBodyArrays('id')
|
|
281
|
+
gta.expectResponseBodyToHaveProperty('accounts[0].id', 'acct-100')
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
- `property` may be a path inside each item, such as `id.value`. Arrays inside the items
|
|
285
|
+
are sorted too.
|
|
286
|
+
- Items without the property go last. Values compare alphanumerically, so `Group 2`
|
|
287
|
+
comes before `Group 10`.
|
|
288
|
+
- Checks made before the call see the order as received, and so does `res.body`.
|
|
289
|
+
- Calling it again sorts by the new property first, and by the earlier ones where that
|
|
290
|
+
ties.
|
|
291
|
+
- Called with no property, it sorts nothing and writes a warning to the step's console.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Strict validation
|
|
296
|
+
|
|
297
|
+
### `gta.useStrictValidation`
|
|
298
|
+
|
|
299
|
+
```js
|
|
300
|
+
gta.useStrictValidation(enabled?)
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Fails the step unless every property of the body is checked, ignored or saved. It
|
|
304
|
+
catches a response that gained a field no test looks at. `enabled` is `true` when left
|
|
305
|
+
out.
|
|
306
|
+
|
|
307
|
+
```js
|
|
308
|
+
gta.useStrictValidation()
|
|
309
|
+
gta.expectResponseBodyToHaveProperty('id', 'orderId', 'setAsCollectionVariable')
|
|
310
|
+
gta.expectResponseBodyToHaveProperty('status', 'open')
|
|
311
|
+
gta.ignoreResponseBodyProperty('createdAt')
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
- It adds one check, `Strict: every body property is asserted`, which lists each
|
|
315
|
+
property left over.
|
|
316
|
+
- It is judged after every `tests` script of the step has run, over what any of them
|
|
317
|
+
checked. Put it in the collection's `tests` to cover every step.
|
|
318
|
+
- `null`, `""`, and empty arrays and objects never need a check of their own.
|
|
319
|
+
- A check of a value's content accounts for it and everything inside it. A check of
|
|
320
|
+
shape only (`isArray`, `isArrayAndHasLength`, or that an object is present) does not
|
|
321
|
+
vouch for what is inside.
|
|
322
|
+
- `false` turns it off. The last call wins, so a step can turn off what the collection
|
|
323
|
+
turned on. `'true'` as text counts as `true`, so a variable can decide:
|
|
324
|
+
`gta.useStrictValidation(gta.get('strictValidation'))`.
|
|
325
|
+
- A binary or HTML body has no properties, so strict validation passes.
|
|
326
|
+
|
|
327
|
+
### `gta.ignoreResponseBodyProperty`
|
|
328
|
+
|
|
329
|
+
```js
|
|
330
|
+
gta.ignoreResponseBodyProperty(path)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Counts the property at `path`, and everything inside it, as checked, without checking
|
|
334
|
+
it. For values that change on every call, such as timestamps.
|
|
335
|
+
|
|
336
|
+
```js
|
|
337
|
+
gta.ignoreResponseBodyProperty('meta')
|
|
338
|
+
gta.ignoreResponseBodyProperty('items[].updatedAt')
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
It changes nothing unless strict validation is on.
|
|
342
|
+
|
|
343
|
+
### `gta.ignoreResponseBodyArrayObjectProperty`
|
|
344
|
+
|
|
345
|
+
```js
|
|
346
|
+
gta.ignoreResponseBodyArrayObjectProperty(arrayPath, propertyPath)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
The same, for one property of every item of an array.
|
|
350
|
+
`gta.ignoreResponseBodyArrayObjectProperty('items', 'updatedAt')` is
|
|
351
|
+
`gta.ignoreResponseBodyProperty('items[].updatedAt')`.
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Checks of your own
|
|
356
|
+
|
|
357
|
+
### `gta.test`
|
|
358
|
+
|
|
359
|
+
```js
|
|
360
|
+
gta.test(name, fn)
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
A named check, for anything the functions above do not cover. It passes unless `fn`
|
|
364
|
+
throws, or the promise it returns rejects, and then the error's message is the reason.
|
|
365
|
+
|
|
366
|
+
```js
|
|
367
|
+
gta.test('ids are unique', () => {
|
|
368
|
+
const ids = res.body.items.map((item) => item.id)
|
|
369
|
+
assert.equal(new Set(ids).size, ids.length)
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
gta.test('total is the sum of the lines', () => {
|
|
373
|
+
const sum = res.body.lines.reduce((total, line) => total + line.amount, 0)
|
|
374
|
+
assert.equal(res.body.total, sum)
|
|
375
|
+
})
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
- `assert` is Node's strict `assert`, also reachable as `gta.assert`.
|
|
379
|
+
- `fn` may be `async`. The step waits for it, whether or not the script does.
|
|
380
|
+
- An endpoint base's named checks are never replaced by a step's own (SPEC.md §2.6).
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Variables
|
|
385
|
+
|
|
386
|
+
### `gta.get`
|
|
387
|
+
|
|
388
|
+
```js
|
|
389
|
+
gta.get(name)
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
A variable's current value, from whichever layer sets it: the project, the collection,
|
|
393
|
+
the environment, a data file row, or a value saved or set earlier in the run.
|
|
394
|
+
`undefined` when no layer does.
|
|
395
|
+
|
|
396
|
+
```js
|
|
397
|
+
gta.expectResponseStatusCodeToBe(gta.get('expectedStatus'))
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
A value comes back with its type. Every value from a CSV data file is text.
|
|
401
|
+
|
|
402
|
+
### `gta.set`
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
gta.set(name, value, options?)
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Sets a variable, which `{{name}}` and `gta.get(name)` read from then on: in this step's
|
|
409
|
+
request when it is set in `before.script`, and in every step after.
|
|
410
|
+
|
|
411
|
+
```js
|
|
412
|
+
gta.set('traceId', gta.uuidv7())
|
|
413
|
+
gta.set(
|
|
414
|
+
'ids',
|
|
415
|
+
res.body.items.map((item) => item.id)
|
|
416
|
+
) // saved as '["a","b"]'
|
|
417
|
+
gta.set('adminId', res.body.id, { scope: 'run' })
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
- **Anything computed goes here**, since `vars` in a file hold plain values only
|
|
421
|
+
(SPEC.md §4). A collection's `before.script` runs before every step, so a value set
|
|
422
|
+
there is fresh for each.
|
|
423
|
+
- A string, number, boolean or `null` is kept as it is. An object or array is saved as
|
|
424
|
+
its JSON text, so `{{ids}}` writes the list into a JSON body, and `forEach: '{{ids}}'`
|
|
425
|
+
sends a request for each item. Read it back in code with `JSON.parse(gta.get('ids'))`.
|
|
426
|
+
`undefined` is saved as `null`.
|
|
427
|
+
- **In a collection with a data file**, a value lasts the rest of its row.
|
|
428
|
+
`{ scope: 'run' }` keeps it for every row after, and for teardown (SPEC.md §2.10).
|
|
429
|
+
Any other `scope` is an error.
|
|
430
|
+
- Nothing is written to a file.
|
|
431
|
+
- SPEC.md §4 gives the order in which layers win.
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Skipping steps
|
|
436
|
+
|
|
437
|
+
### `gta.skip`
|
|
438
|
+
|
|
439
|
+
```js
|
|
440
|
+
gta.skip(reason?)
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
In `before.script` only. The request is not sent, and the step is reported as skipped,
|
|
444
|
+
with the reason. A skipped step never fails a run.
|
|
445
|
+
|
|
446
|
+
```js
|
|
447
|
+
if (!gta.get('adminToken')) gta.skip('no admin account in this environment')
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
- The script runs to its end. No later `before.script` runs for the step: when the
|
|
451
|
+
collection's skips it, the step's own does not run.
|
|
452
|
+
- In `tests` it is an error, because the request has been sent. Use `gta.skipRest`
|
|
453
|
+
there.
|
|
454
|
+
- To skip a step depending on a feature flag, give it `flags:` (SPEC.md §2.9).
|
|
455
|
+
|
|
456
|
+
### `gta.skipRest`
|
|
457
|
+
|
|
458
|
+
```js
|
|
459
|
+
gta.skipRest(reason?)
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
Skips the steps after this one, each reported as skipped with the reason.
|
|
463
|
+
|
|
464
|
+
```js
|
|
465
|
+
if (res.status === 404) gta.skipRest('no such account, so nothing more to check')
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
- In `tests`, this step's own result stands. In `before.script`, this step is skipped
|
|
469
|
+
too.
|
|
470
|
+
- It skips only the current row. The next row of a data file, and teardown, still run.
|
|
471
|
+
- The first reason given stands.
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Feature flags
|
|
476
|
+
|
|
477
|
+
### `gta.flag`
|
|
478
|
+
|
|
479
|
+
```js
|
|
480
|
+
gta.flag(name)
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
A feature flag's value in this run: a string, number or boolean, from the environment,
|
|
484
|
+
the flag command or an override (SPEC.md §2.9). Use it to check something different
|
|
485
|
+
when a flag is on, rather than skip a step.
|
|
486
|
+
|
|
487
|
+
```js
|
|
488
|
+
if (gta.flag('newCheckout')) {
|
|
489
|
+
gta.expectResponseBodyToHaveProperty('total.currency', 'USD')
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
A flag the run does not know is an error, so a misspelled name stops the script rather
|
|
494
|
+
than quietly reading as off.
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Generated values
|
|
499
|
+
|
|
500
|
+
### `gta.uuid`
|
|
501
|
+
|
|
502
|
+
```js
|
|
503
|
+
gta.uuid()
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
A random (version 4) UUID, such as `f397d495-8679-42de-8b69-d6ef86b3f5a1`.
|
|
507
|
+
|
|
508
|
+
### `gta.uuidv7`
|
|
509
|
+
|
|
510
|
+
```js
|
|
511
|
+
gta.uuidv7()
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
A time-ordered (version 7) UUID, such as `01a0f78d-cecb-73c4-ac6e-557141551574`. Ids made
|
|
515
|
+
later sort later, which suits a request id or a record that must read in creation
|
|
516
|
+
order.
|
|
517
|
+
|
|
518
|
+
### `gta.randomInt`
|
|
519
|
+
|
|
520
|
+
```js
|
|
521
|
+
gta.randomInt(min, max)
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
A whole number from `min` to `max`, both included: `gta.randomInt(1, 6)` rolls a die.
|
|
525
|
+
|
|
526
|
+
### `gta.date`
|
|
527
|
+
|
|
528
|
+
```js
|
|
529
|
+
gta.date(format, secondsOffset?, timeZone?)
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
The time now, moved by `secondsOffset` seconds and formatted. `secondsOffset` is `0`
|
|
533
|
+
when left out, and `timeZone` is `'local'`.
|
|
534
|
+
|
|
535
|
+
```js
|
|
536
|
+
gta.date('%Y-%m-%d') // today: 2026-10-01
|
|
537
|
+
gta.date('%F', 86400, 'utc') // tomorrow, in UTC
|
|
538
|
+
gta.date('%FT%T%z', -3600, 'America/New_York') // an hour ago: 2026-10-01T04:15:00-0400
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
| Specifier | Gives | Specifier | Gives |
|
|
542
|
+
| --------- | ---------------------------- | --------- | ---------------------------- |
|
|
543
|
+
| `%Y` | Year: `2026` | `%p` | `AM` or `PM` |
|
|
544
|
+
| `%y` | Year, two digits: `26` | `%b` | Month, short: `Oct` |
|
|
545
|
+
| `%m` | Month: `01`–`12` | `%B` | Month: `October` |
|
|
546
|
+
| `%d` | Day: `01`–`31` | `%a` | Weekday, short: `Thu` |
|
|
547
|
+
| `%e` | Day, space-padded: ` 1`–`31` | `%A` | Weekday: `Thursday` |
|
|
548
|
+
| `%H` | Hour: `00`–`23` | `%j` | Day of the year: `001`–`366` |
|
|
549
|
+
| `%I` | Hour: `01`–`12` | `%Z` | Time zone: `PDT` |
|
|
550
|
+
| `%M` | Minute: `00`–`59` | `%z` | Offset from UTC: `-0700` |
|
|
551
|
+
| `%S` | Second: `00`–`59` | `%s` | Epoch seconds |
|
|
552
|
+
| `%L` | Millisecond: `000`–`999` | `%F` | `%Y-%m-%d` |
|
|
553
|
+
| `%%` | `%` | `%T` | `%H:%M:%S` |
|
|
554
|
+
|
|
555
|
+
- A specifier not listed is left as written, so `%Q` stays `%Q` and a typo shows.
|
|
556
|
+
- A negative `secondsOffset` is in the past.
|
|
557
|
+
- `timeZone` is `local`, the time zone of the machine running the test; `utc`; an IANA
|
|
558
|
+
name, such as `America/New_York`; or a military letter. `A` to `M` are 1 to 12 hours
|
|
559
|
+
ahead of UTC, skipping `J`, `N` to `Y` are 1 to 12 hours behind, and `Z` is UTC, so
|
|
560
|
+
`U` is -08:00, not UTC. `IST` is India.
|