doc-detective-common 1.21.0-openapi.9 → 1.21.1-dev.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.
@@ -1,1798 +1,2035 @@
1
- {
2
- "title": "specification",
3
- "type": "object",
4
- "properties": {
5
- "id": {
6
- "type": "string",
7
- "description": "Unique identifier for the test specification."
8
- },
9
- "description": {
10
- "type": "string",
11
- "description": "Description of the test specification."
12
- },
13
- "file": {
14
- "type": "string",
15
- "description": "Path to the file that the specification is associated with."
16
- },
17
- "contexts": {
18
- "type": "array",
19
- "description": "Application/platform sets to run tests in. Overrides `contexts` defined at the config-level.",
20
- "items": {
21
- "oneOf": [
22
- {
23
- "title": "context",
24
- "type": "object",
25
- "description": "An application and supported platforms.\n\nIf no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For browsers, context priority is Firefox > Chrome > Chromium.",
26
- "properties": {
27
- "app": {
28
- "type": "object",
29
- "description": "The application to run.",
30
- "additionalProperties": false,
31
- "required": [
32
- "name"
33
- ],
34
- "properties": {
35
- "name": {
36
- "type": "string",
37
- "description": "Name of the application.",
38
- "enum": [
39
- "chrome",
40
- "firefox",
41
- "safari",
42
- "edge"
43
- ]
44
- },
45
- "path": {
46
- "type": "string",
47
- "description": "Absolute path or command for the application. If not specified, defaults to typical install paths per platform. If specified but the path is invalid, the context is skipped."
48
- },
49
- "options": {
50
- "type": "object",
51
- "description": "Options to pass to the app. Only works when `name` is `firefox` or `chrome`.",
52
- "additionalProperties": false,
53
- "properties": {
54
- "width": {
55
- "type": "integer",
56
- "description": "Width of the window in pixels."
57
- },
58
- "height": {
59
- "type": "integer",
60
- "description": "Height of the window in pixels."
61
- },
62
- "headless": {
63
- "type": "boolean",
64
- "description": "If `true`, runs the browser in headless mode. Not supported by Safari."
65
- },
66
- "driverPath": {
67
- "type": "string",
68
- "description": "Path to the browser driver. If not specified, defaults to internally managed dependencies."
69
- }
70
- }
71
- }
72
- }
73
- },
74
- "platforms": {
75
- "description": "Supported platforms for the application.",
76
- "type": "array",
77
- "items": {
78
- "type": "string",
79
- "enum": [
80
- "linux",
81
- "mac",
82
- "windows"
83
- ]
84
- }
85
- }
86
- },
87
- "required": [
88
- "app",
89
- "platforms"
90
- ],
91
- "additionalProperties": false,
92
- "examples": [
93
- {
94
- "app": {
95
- "name": "chrome"
96
- },
97
- "platforms": [
98
- "linux"
99
- ]
100
- },
101
- {
102
- "app": {
103
- "name": "firefox",
104
- "options": {
105
- "width": 800,
106
- "height": 600,
107
- "headless": false,
108
- "driverPath": "/usr/bin/geckodriver"
109
- }
110
- },
111
- "platforms": [
112
- "linux",
113
- "windows",
114
- "mac"
115
- ]
116
- },
117
- {
118
- "app": {
119
- "name": "safari"
120
- },
121
- "platforms": [
122
- "mac"
123
- ]
124
- },
125
- {
126
- "app": {
127
- "name": "firefox",
128
- "path": "/usr/bin/firefox"
129
- },
130
- "platforms": [
131
- "linux"
132
- ]
133
- }
134
- ]
135
- }
136
- ]
137
- }
138
- },
139
- "tests": {
140
- "description": "[Tests](test) to perform.",
141
- "type": "array",
142
- "minItems": 1,
143
- "items": {
144
- "oneOf": [
145
- {
146
- "title": "test",
147
- "type": "object",
148
- "description": "A Doc Detective test.",
149
- "properties": {
150
- "id": {
151
- "type": "string",
152
- "description": "Unique identifier for the test."
153
- },
154
- "description": {
155
- "type": "string",
156
- "description": "Description of the test."
157
- },
158
- "file": {
159
- "type": "string",
160
- "description": "Path to the file that the test is associated with."
161
- },
162
- "detectSteps": {
163
- "type": "boolean",
164
- "description": "Whether or not to detect steps in input files based on markup regex. Defaults to `true`."
165
- },
166
- "contexts": {
167
- "type": "array",
168
- "description": "Application/platform sets to run the test in. Overrides `contexts` defined at the config-level and spec-level.",
169
- "items": {
170
- "oneOf": [
171
- {
172
- "title": "context",
173
- "type": "object",
174
- "description": "An application and supported platforms.\n\nIf no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For browsers, context priority is Firefox > Chrome > Chromium.",
175
- "properties": {
176
- "app": {
177
- "type": "object",
178
- "description": "The application to run.",
179
- "additionalProperties": false,
180
- "required": [
181
- "name"
182
- ],
183
- "properties": {
184
- "name": {
185
- "type": "string",
186
- "description": "Name of the application.",
187
- "enum": [
188
- "chrome",
189
- "firefox",
190
- "safari",
191
- "edge"
192
- ]
193
- },
194
- "path": {
195
- "type": "string",
196
- "description": "Absolute path or command for the application. If not specified, defaults to typical install paths per platform. If specified but the path is invalid, the context is skipped."
197
- },
198
- "options": {
199
- "type": "object",
200
- "description": "Options to pass to the app. Only works when `name` is `firefox` or `chrome`.",
201
- "additionalProperties": false,
202
- "properties": {
203
- "width": {
204
- "type": "integer",
205
- "description": "Width of the window in pixels."
206
- },
207
- "height": {
208
- "type": "integer",
209
- "description": "Height of the window in pixels."
210
- },
211
- "headless": {
212
- "type": "boolean",
213
- "description": "If `true`, runs the browser in headless mode. Not supported by Safari."
214
- },
215
- "driverPath": {
216
- "type": "string",
217
- "description": "Path to the browser driver. If not specified, defaults to internally managed dependencies."
218
- }
219
- }
220
- }
221
- }
222
- },
223
- "platforms": {
224
- "description": "Supported platforms for the application.",
225
- "type": "array",
226
- "items": {
227
- "type": "string",
228
- "enum": [
229
- "linux",
230
- "mac",
231
- "windows"
232
- ]
233
- }
234
- }
235
- },
236
- "required": [
237
- "app",
238
- "platforms"
239
- ],
240
- "additionalProperties": false,
241
- "examples": [
242
- {
243
- "app": {
244
- "name": "chrome"
245
- },
246
- "platforms": [
247
- "linux"
248
- ]
249
- },
250
- {
251
- "app": {
252
- "name": "firefox",
253
- "options": {
254
- "width": 800,
255
- "height": 600,
256
- "headless": false,
257
- "driverPath": "/usr/bin/geckodriver"
258
- }
259
- },
260
- "platforms": [
261
- "linux",
262
- "windows",
263
- "mac"
264
- ]
265
- },
266
- {
267
- "app": {
268
- "name": "safari"
269
- },
270
- "platforms": [
271
- "mac"
272
- ]
273
- },
274
- {
275
- "app": {
276
- "name": "firefox",
277
- "path": "/usr/bin/firefox"
278
- },
279
- "platforms": [
280
- "linux"
281
- ]
282
- }
283
- ]
284
- }
285
- ]
286
- }
287
- },
288
- "setup": {
289
- "type": "string",
290
- "description": "Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec."
291
- },
292
- "cleanup": {
293
- "type": "string",
294
- "description": "Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec."
295
- },
296
- "steps": {
297
- "description": "Actions to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails.",
298
- "type": "array",
299
- "minItems": 1,
300
- "items": {
301
- "anyOf": [
302
- {
303
- "title": "checkLink",
304
- "type": "object",
305
- "description": "Check if a URL returns an acceptable status code from a GET request.",
306
- "properties": {
307
- "id": {
308
- "type": "string",
309
- "description": "ID of the step."
310
- },
311
- "description": {
312
- "type": "string",
313
- "description": "Description of the step."
314
- },
315
- "action": {
316
- "type": "string",
317
- "const": "checkLink",
318
- "description": "Action to perform."
319
- },
320
- "url": {
321
- "type": "string",
322
- "description": "URL to check.",
323
- "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)",
324
- "transform": [
325
- "trim"
326
- ]
327
- },
328
- "origin": {
329
- "type": "string",
330
- "description": "Protocol and domain to navigate to. Prepended to `url`.",
331
- "transform": [
332
- "trim"
333
- ]
334
- },
335
- "statusCodes": {
336
- "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.",
337
- "type": "array",
338
- "items": {
339
- "oneOf": [
340
- {
341
- "type": "integer"
342
- }
343
- ]
344
- },
345
- "default": [
346
- 200,
347
- 201,
348
- 202
349
- ]
350
- }
351
- },
352
- "dynamicDefaults": {
353
- "id": "uuid"
354
- },
355
- "required": [
356
- "action",
357
- "url"
358
- ],
359
- "additionalProperties": false,
360
- "examples": [
361
- {
362
- "action": "checkLink",
363
- "url": "https://www.google.com"
364
- },
365
- {
366
- "action": "checkLink",
367
- "url": "https://www.google.com",
368
- "statusCodes": [
369
- 200
370
- ]
371
- },
372
- {
373
- "action": "checkLink",
374
- "url": "/search",
375
- "origin": "www.google.com",
376
- "statusCodes": [
377
- 200
378
- ]
379
- }
380
- ]
381
- },
382
- {
383
- "title": "goTo",
384
- "type": "object",
385
- "description": "Navigate to a specified URL.",
386
- "properties": {
387
- "id": {
388
- "type": "string",
389
- "description": "ID of the step."
390
- },
391
- "description": {
392
- "type": "string",
393
- "description": "Description of the step."
394
- },
395
- "action": {
396
- "type": "string",
397
- "const": "goTo",
398
- "description": "Action to perform."
399
- },
400
- "url": {
401
- "type": "string",
402
- "description": "URL to navigate to.",
403
- "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)",
404
- "transform": [
405
- "trim"
406
- ]
407
- },
408
- "origin": {
409
- "type": "string",
410
- "description": "Protocol and domain to navigate to. Prepended to `url`.",
411
- "transform": [
412
- "trim"
413
- ]
414
- }
415
- },
416
- "dynamicDefaults": {
417
- "id": "uuid"
418
- },
419
- "required": [
420
- "action",
421
- "url"
422
- ],
423
- "additionalProperties": false,
424
- "examples": [
425
- {
426
- "action": "goTo",
427
- "url": "https://www.google.com"
428
- },
429
- {
430
- "id": "ddec5e20-2e81-4f38-867c-92c8d9516755",
431
- "description": "This is a test!",
432
- "action": "goTo",
433
- "url": "https://www.google.com"
434
- },
435
- {
436
- "id": "ddec5e20-2e81-4f38-867c-92c8d9516756",
437
- "description": "This is a test!",
438
- "action": "goTo",
439
- "url": "/search",
440
- "origin": "https://www.google.com"
441
- }
442
- ]
443
- },
444
- {
445
- "title": "httpRequest",
446
- "type": "object",
447
- "description": "Perform a generic HTTP request, for example to an API.",
448
- "properties": {
449
- "id": {
450
- "type": "string",
451
- "description": "ID of the step."
452
- },
453
- "description": {
454
- "type": "string",
455
- "description": "Description of the step."
456
- },
457
- "action": {
458
- "type": "string",
459
- "const": "httpRequest",
460
- "description": "Aciton to perform."
461
- },
462
- "url": {
463
- "type": "string",
464
- "description": "URL for the HTTP request.",
465
- "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)",
466
- "transform": [
467
- "trim"
468
- ]
469
- },
470
- "openApi": {
471
- "allOf": [
472
- {
473
- "title": "openApi",
474
- "type": "object",
475
- "description": "OpenAPI definition and configuration.",
476
- "additionalProperties": false,
477
- "properties": {
478
- "name": {
479
- "type": "string",
480
- "description": "Name of the OpenAPI definition, as defined in your configuration."
481
- },
482
- "definitionPath": {
483
- "type": "string",
484
- "description": "URL or local path to the OpenAPI definition."
485
- },
486
- "operationId": {
487
- "type": "string",
488
- "description": "ID of the operation to use for the request."
489
- },
490
- "server": {
491
- "type": "string",
492
- "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition."
493
- },
494
- "validateAgainstSchema": {
495
- "type": "string",
496
- "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.",
497
- "enum": [
498
- "request",
499
- "response",
500
- "both",
501
- "none"
502
- ],
503
- "default": "both"
504
- },
505
- "mockResponse": {
506
- "type": "boolean",
507
- "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code."
508
- },
509
- "statusCode": {
510
- "type": "integer",
511
- "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified."
512
- },
513
- "useExample": {
514
- "type": [
515
- "string"
516
- ],
517
- "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.",
518
- "enum": [
519
- "request",
520
- "response",
521
- "both",
522
- "none"
523
- ],
524
- "default": "none"
525
- },
526
- "exampleKey": {
527
- "type": "string",
528
- "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.",
529
- "default": ""
530
- },
531
- "requestHeaders": {
532
- "type": "object",
533
- "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.",
534
- "additionalProperties": {
535
- "type": "string"
536
- }
537
- }
538
- },
539
- "examples": [
540
- {
541
- "definitionPath": "https://petstore.swagger.io/v2/swagger.json"
542
- }
543
- ]
544
- },
545
- {
546
- "type": "object",
547
- "required": [
548
- "operationId"
549
- ]
550
- }
551
- ]
552
- },
553
- "statusCodes": {
554
- "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.",
555
- "type": "array",
556
- "items": {
557
- "oneOf": [
558
- {
559
- "type": "integer"
560
- }
561
- ]
562
- },
563
- "default": [
564
- 200
565
- ]
566
- },
567
- "method": {
568
- "type": "string",
569
- "description": "Method of the HTTP request",
570
- "enum": [
571
- "get",
572
- "put",
573
- "post",
574
- "patch",
575
- "delete"
576
- ],
577
- "transform": [
578
- "trim",
579
- "toEnumCase"
580
- ],
581
- "default": "get"
582
- },
583
- "timeout": {
584
- "type": "integer",
585
- "description": "Timeout for the HTTP request, in milliseconds.",
586
- "default": 60000
587
- },
588
- "requestHeaders": {
589
- "description": "Headers to include in the HTTP request, in key/value format.",
590
- "type": "object",
591
- "additionalProperties": true,
592
- "properties": {},
593
- "default": {}
594
- },
595
- "responseHeaders": {
596
- "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.",
597
- "type": "object",
598
- "additionalProperties": true,
599
- "properties": {},
600
- "default": {}
601
- },
602
- "requestParams": {
603
- "description": "URL parameters to include in the HTTP request, in key/value format.",
604
- "type": "object",
605
- "additionalProperties": true,
606
- "default": {},
607
- "properties": {}
608
- },
609
- "responseParams": {
610
- "description": "DEPRECATED.",
611
- "type": "object",
612
- "additionalProperties": true,
613
- "default": {},
614
- "properties": {}
615
- },
616
- "requestData": {
617
- "description": "JSON object to include as the body of the HTTP request.",
618
- "type": "object",
619
- "additionalProperties": true,
620
- "default": {},
621
- "properties": {}
622
- },
623
- "responseData": {
624
- "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.",
625
- "type": "object",
626
- "additionalProperties": true,
627
- "default": {},
628
- "properties": {}
629
- },
630
- "allowAdditionalFields": {
631
- "type": "boolean",
632
- "description": "If `false`, the step fails when the response data contains fields not specified in `responseData`.",
633
- "default": true
634
- },
635
- "savePath": {
636
- "type": "string",
637
- "description": "File path to save the command's output, relative to `saveDirectory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings."
638
- },
639
- "saveDirectory": {
640
- "type": "string",
641
- "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory."
642
- },
643
- "maxVariation": {
644
- "type": "integer",
645
- "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.",
646
- "default": 0,
647
- "minimum": 0,
648
- "maximum": 100
649
- },
650
- "overwrite": {
651
- "type": "string",
652
- "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.",
653
- "enum": [
654
- "true",
655
- "false",
656
- "byVariation"
657
- ],
658
- "default": "false"
659
- },
660
- "envsFromResponseData": {
661
- "description": "Environment variables to set based on response variables, as an object of the environment variable name and the jq filter applied to the response data to identify the variable's value.",
662
- "type": "array",
663
- "default": [],
664
- "items": {
665
- "oneOf": [
666
- {
667
- "description": "",
668
- "type": "object",
669
- "properties": {
670
- "name": {
671
- "description": "Name of the environment variable to set.",
672
- "type": "string"
673
- },
674
- "jqFilter": {
675
- "description": "jq filter to apply to the response data. If the filter doesn't return a value, the environment variable isn't set.",
676
- "type": "string"
677
- }
678
- },
679
- "required": [
680
- "name",
681
- "jqFilter"
682
- ]
683
- }
684
- ]
685
- }
686
- }
687
- },
688
- "dynamicDefaults": {
689
- "id": "uuid"
690
- },
691
- "anyOf": [
692
- {
693
- "required": [
694
- "url"
695
- ]
696
- },
697
- {
698
- "required": [
699
- "openApi"
700
- ]
701
- }
702
- ],
703
- "required": [
704
- "action"
705
- ],
706
- "additionalProperties": false,
707
- "examples": [
708
- {
709
- "action": "httpRequest",
710
- "url": "https://reqres.in/api/users"
711
- },
712
- {
713
- "action": "httpRequest",
714
- "url": "https://reqres.in/api/users/2",
715
- "method": "put",
716
- "requestData": {
717
- "name": "morpheus",
718
- "job": "zion resident"
719
- }
720
- },
721
- {
722
- "action": "httpRequest",
723
- "url": "https://reqres.in/api/users",
724
- "method": "post",
725
- "requestData": {
726
- "name": "morpheus",
727
- "job": "leader"
728
- },
729
- "responseData": {
730
- "name": "morpheus",
731
- "job": "leader"
732
- },
733
- "statusCodes": [
734
- 200,
735
- 201
736
- ]
737
- },
738
- {
739
- "action": "httpRequest",
740
- "url": "https://www.api-server.com",
741
- "method": "post",
742
- "timeout": 30000,
743
- "requestHeaders": {
744
- "header": "value"
745
- },
746
- "requestParams": {
747
- "param": "value"
748
- },
749
- "requestData": {
750
- "field": "value"
751
- },
752
- "responseHeaders": {
753
- "header": "value"
754
- },
755
- "responseData": {
756
- "field": "value"
757
- },
758
- "statusCodes": [
759
- 200
760
- ]
761
- },
762
- {
763
- "action": "httpRequest",
764
- "url": "https://reqres.in/api/users",
765
- "method": "post",
766
- "requestData": {
767
- "name": "morpheus",
768
- "job": "leader"
769
- },
770
- "responseData": {
771
- "name": "morpheus",
772
- "job": "leader"
773
- },
774
- "statusCodes": [
775
- 200,
776
- 201
777
- ],
778
- "savePath": "response.json",
779
- "saveDirectory": "media",
780
- "maxVariation": 5,
781
- "overwrite": "byVariation"
782
- },
783
- {
784
- "action": "httpRequest",
785
- "openApi": {
786
- "name": "Reqres",
787
- "operationId": "getUserById"
788
- },
789
- "requestParams": {
790
- "id": 123
791
- }
792
- },
793
- {
794
- "action": "httpRequest",
795
- "openApi": {
796
- "definitionPath": "https://api.example.com/openapi.json",
797
- "operationId": "getUserById"
798
- },
799
- "requestParams": {
800
- "id": 123
801
- }
802
- },
803
- {
804
- "action": "httpRequest",
805
- "openApi": {
806
- "definitionPath": "https://api.example.com/openapi.json",
807
- "operationId": "createUser",
808
- "useExample": "both"
809
- }
810
- },
811
- {
812
- "action": "httpRequest",
813
- "openApi": {
814
- "definitionPath": "https://api.example.com/openapi.json",
815
- "operationId": "updateUser",
816
- "useExample": "request",
817
- "exampleKey": "acme"
818
- }
819
- },
820
- {
821
- "action": "httpRequest",
822
- "openApi": {
823
- "definitionPath": "https://api.example.com/openapi.json",
824
- "operationId": "updateUser",
825
- "useExample": "request",
826
- "exampleKey": "acme",
827
- "requestHeaders": {
828
- "Authorization": "Bearer $TOKEN"
829
- }
830
- }
831
- }
832
- ]
833
- },
834
- {
835
- "title": "runShell",
836
- "type": "object",
837
- "description": "Perform a native shell command.",
838
- "properties": {
839
- "id": {
840
- "type": "string",
841
- "description": "ID of the step."
842
- },
843
- "description": {
844
- "type": "string",
845
- "description": "Description of the step."
846
- },
847
- "action": {
848
- "type": "string",
849
- "const": "runShell",
850
- "description": "The action to perform."
851
- },
852
- "command": {
853
- "type": "string",
854
- "description": "Command to perform in the machine's default shell."
855
- },
856
- "args": {
857
- "type": "array",
858
- "description": "Arguments for the command.",
859
- "items": {
860
- "oneOf": [
861
- {
862
- "type": "string"
863
- }
864
- ]
865
- },
866
- "default": []
867
- },
868
- "workingDirectory": {
869
- "type": "string",
870
- "description": "Working directory for the command.",
871
- "default": "."
872
- },
873
- "exitCodes": {
874
- "type": "array",
875
- "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.",
876
- "items": {
877
- "oneOf": [
878
- {
879
- "type": "integer"
880
- }
881
- ]
882
- },
883
- "default": [
884
- 0
885
- ]
886
- },
887
- "output": {
888
- "type": "string",
889
- "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`."
890
- },
891
- "savePath": {
892
- "type": "string",
893
- "description": "File path to save the command's output, relative to `saveDirectory`."
894
- },
895
- "saveDirectory": {
896
- "type": "string",
897
- "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory."
898
- },
899
- "maxVariation": {
900
- "type": "integer",
901
- "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.",
902
- "default": 0,
903
- "minimum": 0,
904
- "maximum": 100
905
- },
906
- "overwrite": {
907
- "type": "string",
908
- "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.",
909
- "enum": [
910
- "true",
911
- "false",
912
- "byVariation"
913
- ],
914
- "default": "false"
915
- },
916
- "timeout": {
917
- "type": "integer",
918
- "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.",
919
- "default": 60000
920
- },
921
- "setVariables": {
922
- "type": "array",
923
- "description": "Extract environment variables from the command's output.",
924
- "items": {
925
- "oneOf": [
926
- {
927
- "description": "",
928
- "type": "object",
929
- "properties": {
930
- "name": {
931
- "description": "Name of the environment variable to set.",
932
- "type": "string"
933
- },
934
- "regex": {
935
- "description": "Regex to extract the environment variable from the command's output.",
936
- "type": "string"
937
- }
938
- },
939
- "required": [
940
- "name",
941
- "regex"
942
- ]
943
- }
944
- ]
945
- },
946
- "default": []
947
- }
948
- },
949
- "dynamicDefaults": {
950
- "id": "uuid"
951
- },
952
- "additionalProperties": false,
953
- "required": [
954
- "action",
955
- "command"
956
- ],
957
- "examples": [
958
- {
959
- "action": "runShell",
960
- "command": "echo",
961
- "args": [
962
- "$USER"
963
- ]
964
- },
965
- {
966
- "action": "runShell",
967
- "command": "echo",
968
- "args": [
969
- "hello-world"
970
- ],
971
- "id": "ddec5e20-2e81-4f38-867c-92c8d9516755",
972
- "description": "This is a test!"
973
- },
974
- {
975
- "action": "runShell",
976
- "command": "docker run hello-world",
977
- "timeout": 20000,
978
- "exitCodes": [
979
- 0
980
- ],
981
- "output": "Hello from Docker!"
982
- },
983
- {
984
- "action": "runShell",
985
- "command": "false",
986
- "exitCodes": [
987
- 1
988
- ]
989
- },
990
- {
991
- "action": "runShell",
992
- "command": "echo",
993
- "args": [
994
- "setup"
995
- ],
996
- "exitCodes": [
997
- 0
998
- ],
999
- "output": "/.*?/",
1000
- "setVariables": [
1001
- {
1002
- "name": "TEST",
1003
- "regex": ".*"
1004
- }
1005
- ]
1006
- },
1007
- {
1008
- "action": "runShell",
1009
- "command": "docker run hello-world",
1010
- "workingDirectory": ".",
1011
- "exitCodes": [
1012
- 0
1013
- ],
1014
- "output": "Hello from Docker!",
1015
- "savePath": "docker-output.txt",
1016
- "saveDirectory": "output",
1017
- "maxVariation": 10,
1018
- "overwrite": "byVariation"
1019
- }
1020
- ]
1021
- },
1022
- {
1023
- "title": "saveScreenshot",
1024
- "type": "object",
1025
- "description": "Takes a screenshot in PNG format.",
1026
- "properties": {
1027
- "id": {
1028
- "type": "string",
1029
- "description": "ID of the step."
1030
- },
1031
- "description": {
1032
- "type": "string",
1033
- "description": "Description of the step."
1034
- },
1035
- "action": {
1036
- "type": "string",
1037
- "const": "saveScreenshot",
1038
- "description": "The action to perform."
1039
- },
1040
- "path": {
1041
- "type": "string",
1042
- "description": "File path of the PNG file, relative to `directory`. If not specified, the file name is the ID of the step.",
1043
- "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)"
1044
- },
1045
- "directory": {
1046
- "type": "string",
1047
- "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory."
1048
- },
1049
- "maxVariation": {
1050
- "type": "number",
1051
- "description": "Allowed variation in percentage of pixels between the new screenshot and the exisitng screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.",
1052
- "default": 5,
1053
- "minimum": 0,
1054
- "maximum": 100
1055
- },
1056
- "overwrite": {
1057
- "type": "string",
1058
- "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `byVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.",
1059
- "enum": [
1060
- "true",
1061
- "false",
1062
- "byVariation"
1063
- ],
1064
- "default": "false"
1065
- },
1066
- "crop": {
1067
- "type": "object",
1068
- "description": "Crops the screenshot.",
1069
- "properties": {
1070
- "selector": {
1071
- "type": "string",
1072
- "description": "Selector of the element to crop the image to."
1073
- },
1074
- "padding": {
1075
- "oneOf": [
1076
- {
1077
- "type": "number",
1078
- "description": "Padding in pixels to add to the bounds of the element.",
1079
- "minimum": 0
1080
- },
1081
- {
1082
- "type": "object",
1083
- "properties": {
1084
- "top": {
1085
- "type": "number",
1086
- "minimum": 0
1087
- },
1088
- "right": {
1089
- "type": "number",
1090
- "minimum": 0
1091
- },
1092
- "bottom": {
1093
- "type": "number",
1094
- "minimum": 0
1095
- },
1096
- "left": {
1097
- "type": "number",
1098
- "minimum": 0
1099
- }
1100
- }
1101
- }
1102
- ]
1103
- }
1104
- },
1105
- "required": [
1106
- "selector"
1107
- ],
1108
- "additionalProperties": false
1109
- }
1110
- },
1111
- "dynamicDefaults": {
1112
- "id": "uuid"
1113
- },
1114
- "required": [
1115
- "action"
1116
- ],
1117
- "additionalProperties": false,
1118
- "examples": [
1119
- {
1120
- "action": "saveScreenshot"
1121
- },
1122
- {
1123
- "action": "saveScreenshot",
1124
- "path": "results.png"
1125
- },
1126
- {
1127
- "action": "saveScreenshot",
1128
- "path": "results.png",
1129
- "directory": "static/images"
1130
- },
1131
- {
1132
- "action": "saveScreenshot",
1133
- "path": "results.png",
1134
- "directory": "static/images",
1135
- "maxVariation": 10,
1136
- "overwrite": "byVariation"
1137
- },
1138
- {
1139
- "action": "saveScreenshot",
1140
- "path": "results.png",
1141
- "directory": "static/images",
1142
- "crop": {
1143
- "selector": "#element"
1144
- }
1145
- },
1146
- {
1147
- "action": "saveScreenshot",
1148
- "path": "results.png",
1149
- "directory": "static/images",
1150
- "crop": {
1151
- "selector": "#element",
1152
- "padding": 10
1153
- }
1154
- },
1155
- {
1156
- "action": "saveScreenshot",
1157
- "path": "results.png",
1158
- "directory": "static/images",
1159
- "crop": {
1160
- "selector": "#element",
1161
- "padding": {
1162
- "top": 10,
1163
- "right": 20,
1164
- "bottom": 30,
1165
- "left": 40
1166
- }
1167
- }
1168
- }
1169
- ]
1170
- },
1171
- {
1172
- "title": "setVariables",
1173
- "type": "object",
1174
- "description": "Load environment variables from a `.env` file.",
1175
- "properties": {
1176
- "id": {
1177
- "type": "string",
1178
- "description": "ID of the step."
1179
- },
1180
- "description": {
1181
- "type": "string",
1182
- "description": "Description of the step."
1183
- },
1184
- "action": {
1185
- "type": "string",
1186
- "const": "setVariables",
1187
- "description": "Action to perform."
1188
- },
1189
- "path": {
1190
- "type": "string",
1191
- "description": "Path to the `.env` file."
1192
- }
1193
- },
1194
- "dynamicDefaults": {
1195
- "id": "uuid"
1196
- },
1197
- "required": [
1198
- "action",
1199
- "path"
1200
- ],
1201
- "additionalProperties": false,
1202
- "examples": [
1203
- {
1204
- "action": "setVariables",
1205
- "path": ".env"
1206
- }
1207
- ]
1208
- },
1209
- {
1210
- "title": "startRecording",
1211
- "type": "object",
1212
- "description": "Start recording the current browser viewport. Must be followed by a `stopRecording` action. Only runs when the context `app` is `chrome` and `headless` is `false`. Supported extensions: [ '.mp4', '.webm', '.gif' ]",
1213
- "properties": {
1214
- "id": {
1215
- "type": "string",
1216
- "description": "ID of the step."
1217
- },
1218
- "description": {
1219
- "type": "string",
1220
- "description": "Description of the step."
1221
- },
1222
- "action": {
1223
- "type": "string",
1224
- "const": "startRecording",
1225
- "description": "The action to perform."
1226
- },
1227
- "path": {
1228
- "type": "string",
1229
- "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.",
1230
- "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)"
1231
- },
1232
- "directory": {
1233
- "type": "string",
1234
- "description": "Directory of the file. Attempts to create the directory if it doesn't exist."
1235
- },
1236
- "overwrite": {
1237
- "type": "boolean",
1238
- "description": "If `true`, overwrites the existing file at `path` if it exists.",
1239
- "default": false
1240
- }
1241
- },
1242
- "dynamicDefaults": {
1243
- "id": "uuid"
1244
- },
1245
- "required": [
1246
- "action"
1247
- ],
1248
- "additionalProperties": false,
1249
- "examples": [
1250
- {
1251
- "action": "startRecording"
1252
- },
1253
- {
1254
- "action": "startRecording",
1255
- "path": "results.mp4"
1256
- },
1257
- {
1258
- "action": "startRecording",
1259
- "path": "results.mp4",
1260
- "directory": "static/media",
1261
- "overwrite": true
1262
- }
1263
- ]
1264
- },
1265
- {
1266
- "title": "stopRecording",
1267
- "type": "object",
1268
- "description": "Stop the current recording.",
1269
- "properties": {
1270
- "id": {
1271
- "type": "string",
1272
- "description": "ID of the step."
1273
- },
1274
- "description": {
1275
- "type": "string",
1276
- "description": "Description of the step."
1277
- },
1278
- "action": {
1279
- "type": "string",
1280
- "const": "stopRecording",
1281
- "description": "The action to perform."
1282
- }
1283
- },
1284
- "dynamicDefaults": {
1285
- "id": "uuid"
1286
- },
1287
- "required": [
1288
- "action"
1289
- ],
1290
- "additionalProperties": false,
1291
- "examples": [
1292
- {
1293
- "action": "stopRecording"
1294
- }
1295
- ]
1296
- },
1297
- {
1298
- "title": "typeKeys",
1299
- "type": "object",
1300
- "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's enum. For example, to type the Escape key, enter `$ESCAPE$`.",
1301
- "properties": {
1302
- "id": {
1303
- "type": "string",
1304
- "description": "ID of the step."
1305
- },
1306
- "description": {
1307
- "type": "string",
1308
- "description": "Description of the step."
1309
- },
1310
- "action": {
1311
- "type": "string",
1312
- "const": "typeKeys",
1313
- "description": "The action to perform."
1314
- },
1315
- "keys": {
1316
- "description": "String of keys to enter.",
1317
- "anyOf": [
1318
- {
1319
- "type": "string"
1320
- },
1321
- {
1322
- "type": "array",
1323
- "items": {
1324
- "oneOf": [
1325
- {
1326
- "type": "string"
1327
- }
1328
- ]
1329
- }
1330
- }
1331
- ]
1332
- },
1333
- "delay": {
1334
- "type": "number",
1335
- "description": "Delay in milliseconds between each key press. Only valid during a recording.",
1336
- "default": 100
1337
- }
1338
- },
1339
- "dynamicDefaults": {
1340
- "id": "uuid"
1341
- },
1342
- "required": [
1343
- "action",
1344
- "keys"
1345
- ],
1346
- "additionalProperties": false,
1347
- "examples": [
1348
- {
1349
- "action": "typeKeys",
1350
- "keys": "kittens"
1351
- },
1352
- {
1353
- "action": "typeKeys",
1354
- "keys": [
1355
- "$ENTER$"
1356
- ]
1357
- },
1358
- {
1359
- "action": "typeKeys",
1360
- "keys": [
1361
- "kittens",
1362
- "$ENTER$"
1363
- ],
1364
- "delay": 500
1365
- }
1366
- ]
1367
- },
1368
- {
1369
- "title": "find",
1370
- "type": "object",
1371
- "description": "Check if an element exists with the specified CSS selector.",
1372
- "properties": {
1373
- "id": {
1374
- "type": "string",
1375
- "description": "ID of the step."
1376
- },
1377
- "description": {
1378
- "type": "string",
1379
- "description": "Description of the step."
1380
- },
1381
- "action": {
1382
- "type": "string",
1383
- "const": "find",
1384
- "description": "Action to perform."
1385
- },
1386
- "selector": {
1387
- "description": "Selector that uniquely identifies the element.",
1388
- "type": "string"
1389
- },
1390
- "timeout": {
1391
- "type": "integer",
1392
- "description": "Max duration in milliseconds to wait for the element to exist.",
1393
- "default": 5000
1394
- },
1395
- "matchText": {
1396
- "type": "string",
1397
- "description": "Text that the element should contain. If the element doesn't contain the text, the step fails. Accepts both strings an regular expressions. To use a regular expression, the expression should start and end with a `/`. For example, `/search/`."
1398
- },
1399
- "moveTo": {
1400
- "description": "Move to the element. If the element isn't visible, it's scrolled into view. Only runs the if the test is being recorded.",
1401
- "oneOf": [
1402
- {
1403
- "type": "boolean"
1404
- }
1405
- ],
1406
- "default": false
1407
- },
1408
- "click": {
1409
- "type": "boolean",
1410
- "description": "Click the element.",
1411
- "default": false
1412
- },
1413
- "typeKeys": {
1414
- "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`typeKeys`](typeKeys). To type in the element, make the element active with the `click` parameter.",
1415
- "oneOf": [
1416
- {
1417
- "type": "string"
1418
- },
1419
- {
1420
- "type": "object",
1421
- "additionalProperties": false,
1422
- "properties": {
1423
- "keys": {
1424
- "description": "String of keys to enter.",
1425
- "anyOf": [
1426
- {
1427
- "type": "string"
1428
- },
1429
- {
1430
- "type": "array",
1431
- "items": {
1432
- "oneOf": [
1433
- {
1434
- "type": "string"
1435
- }
1436
- ]
1437
- }
1438
- }
1439
- ]
1440
- },
1441
- "delay": {
1442
- "type": "number",
1443
- "description": "Delay in milliseconds between each key press. Only valid during a recording.",
1444
- "default": 100
1445
- }
1446
- }
1447
- }
1448
- ]
1449
- },
1450
- "setVariables": {
1451
- "type": "array",
1452
- "description": "Extract environment variables from the element's text.",
1453
- "items": {
1454
- "oneOf": [
1455
- {
1456
- "description": "",
1457
- "type": "object",
1458
- "properties": {
1459
- "name": {
1460
- "description": "Name of the environment variable to set.",
1461
- "type": "string"
1462
- },
1463
- "regex": {
1464
- "description": "Regex to extract the environment variable from the element's text.",
1465
- "type": "string"
1466
- }
1467
- },
1468
- "required": [
1469
- "name",
1470
- "regex"
1471
- ]
1472
- }
1473
- ]
1474
- },
1475
- "default": []
1476
- }
1477
- },
1478
- "required": [
1479
- "action",
1480
- "selector"
1481
- ],
1482
- "dynamicDefaults": {
1483
- "id": "uuid"
1484
- },
1485
- "additionalProperties": false,
1486
- "examples": [
1487
- {
1488
- "action": "find",
1489
- "selector": "[title=Search]"
1490
- },
1491
- {
1492
- "action": "find",
1493
- "selector": "[title=Search]",
1494
- "timeout": 10000,
1495
- "matchText": "Search",
1496
- "moveTo": true,
1497
- "click": true,
1498
- "typeKeys": "shorthair cat"
1499
- },
1500
- {
1501
- "action": "find",
1502
- "selector": "[title=Search]",
1503
- "timeout": 10000,
1504
- "matchText": "Search",
1505
- "moveTo": true,
1506
- "click": true,
1507
- "typeKeys": {
1508
- "keys": [
1509
- "shorthair cat"
1510
- ],
1511
- "delay": 100
1512
- }
1513
- },
1514
- {
1515
- "action": "find",
1516
- "selector": "[title=ResultsCount]",
1517
- "setVariables": [
1518
- {
1519
- "name": "resultsCount",
1520
- "regex": ".*"
1521
- }
1522
- ]
1523
- }
1524
- ]
1525
- },
1526
- {
1527
- "title": "wait",
1528
- "type": "object",
1529
- "description": "Pause before performing the next action.",
1530
- "properties": {
1531
- "id": {
1532
- "type": "string",
1533
- "description": "ID of the step."
1534
- },
1535
- "description": {
1536
- "type": "string",
1537
- "description": "Description of the step."
1538
- },
1539
- "action": {
1540
- "type": "string",
1541
- "const": "wait",
1542
- "description": "The action to perform."
1543
- },
1544
- "duration": {
1545
- "type": "number",
1546
- "description": "Milliseconds to wait.",
1547
- "default": 5000
1548
- }
1549
- },
1550
- "dynamicDefaults": {
1551
- "id": "uuid"
1552
- },
1553
- "required": [
1554
- "action"
1555
- ],
1556
- "additionalProperties": false,
1557
- "examples": [
1558
- {
1559
- "action": "wait"
1560
- },
1561
- {
1562
- "action": "wait",
1563
- "duration": 5000
1564
- }
1565
- ]
1566
- }
1567
- ]
1568
- }
1569
- }
1570
- },
1571
- "dynamicDefaults": {
1572
- "id": "uuid"
1573
- },
1574
- "required": [
1575
- "steps"
1576
- ],
1577
- "additionalProperties": false,
1578
- "examples": [
1579
- {
1580
- "steps": [
1581
- {
1582
- "action": "checkLink",
1583
- "url": "https://www.duckduckgo.com"
1584
- }
1585
- ]
1586
- },
1587
- {
1588
- "steps": [
1589
- {
1590
- "action": "goTo",
1591
- "url": "https://www.duckduckgo.com"
1592
- },
1593
- {
1594
- "action": "find",
1595
- "selector": "[title=Search]",
1596
- "click": true,
1597
- "typeKeys": {
1598
- "keys": [
1599
- "shorthair cats",
1600
- "$ENTER$"
1601
- ]
1602
- }
1603
- }
1604
- ]
1605
- },
1606
- {
1607
- "id": "Do all the things! - Test",
1608
- "description": "This test includes every property across all actions.",
1609
- "contexts": [
1610
- {
1611
- "app": {
1612
- "name": "firefox",
1613
- "path": "/usr/bin/firefox"
1614
- },
1615
- "platforms": [
1616
- "linux"
1617
- ]
1618
- }
1619
- ],
1620
- "setup": "setup.json",
1621
- "cleanup": "cleanup.json",
1622
- "steps": [
1623
- {
1624
- "action": "setVariables",
1625
- "path": ".env"
1626
- },
1627
- {
1628
- "action": "runShell",
1629
- "command": "echo",
1630
- "args": [
1631
- "$USER"
1632
- ]
1633
- },
1634
- {
1635
- "action": "checkLink",
1636
- "url": "https://www.duckduckgo.com"
1637
- },
1638
- {
1639
- "action": "httpRequest",
1640
- "url": "https://reqres.in/api/users",
1641
- "method": "post",
1642
- "requestData": {
1643
- "name": "morpheus",
1644
- "job": "leader"
1645
- },
1646
- "responseData": {
1647
- "name": "morpheus",
1648
- "job": "leader"
1649
- },
1650
- "statusCodes": [
1651
- 200,
1652
- 201
1653
- ]
1654
- },
1655
- {
1656
- "action": "goTo",
1657
- "url": "https://www.duckduckgo.com"
1658
- },
1659
- {
1660
- "action": "find",
1661
- "selector": "[title=Search]",
1662
- "timeout": 10000,
1663
- "matchText": "Search",
1664
- "moveTo": true,
1665
- "click": true,
1666
- "typeKeys": {
1667
- "keys": [
1668
- "shorthair cat"
1669
- ]
1670
- }
1671
- },
1672
- {
1673
- "action": "typeKeys",
1674
- "keys": [
1675
- "$ENTER$"
1676
- ]
1677
- },
1678
- {
1679
- "action": "saveScreenshot"
1680
- }
1681
- ]
1682
- }
1683
- ]
1684
- }
1685
- ]
1686
- }
1687
- }
1688
- },
1689
- "required": [
1690
- "tests"
1691
- ],
1692
- "examples": [
1693
- {
1694
- "tests": [
1695
- {
1696
- "steps": [
1697
- {
1698
- "action": "checkLink",
1699
- "url": "https://www.duckduckgo.com"
1700
- }
1701
- ]
1702
- }
1703
- ]
1704
- },
1705
- {
1706
- "id": "Do all the things! - Spec",
1707
- "contexts": [
1708
- {
1709
- "app": {
1710
- "name": "chrome",
1711
- "path": "/usr/bin/firefox"
1712
- },
1713
- "platforms": [
1714
- "windows",
1715
- "mac"
1716
- ]
1717
- }
1718
- ],
1719
- "tests": [
1720
- {
1721
- "id": "Do all the things! - Test",
1722
- "description": "This test includes nearly every property across all actions.",
1723
- "contexts": [
1724
- {
1725
- "app": {
1726
- "name": "firefox",
1727
- "path": "/usr/bin/firefox"
1728
- },
1729
- "platforms": [
1730
- "linux"
1731
- ]
1732
- }
1733
- ],
1734
- "steps": [
1735
- {
1736
- "action": "setVariables",
1737
- "path": ".env"
1738
- },
1739
- {
1740
- "action": "runShell",
1741
- "command": "echo",
1742
- "args": [
1743
- "$USER"
1744
- ]
1745
- },
1746
- {
1747
- "action": "checkLink",
1748
- "url": "https://www.duckduckgo.com"
1749
- },
1750
- {
1751
- "action": "httpRequest",
1752
- "url": "https://reqres.in/api/users",
1753
- "method": "post",
1754
- "requestData": {
1755
- "name": "morpheus",
1756
- "job": "leader"
1757
- },
1758
- "responseData": {
1759
- "name": "morpheus",
1760
- "job": "leader"
1761
- },
1762
- "statusCodes": [
1763
- 200,
1764
- 201
1765
- ]
1766
- },
1767
- {
1768
- "action": "goTo",
1769
- "url": "https://www.duckduckgo.com"
1770
- },
1771
- {
1772
- "action": "find",
1773
- "selector": "[title=Search]",
1774
- "timeout": 10000,
1775
- "matchText": "Search",
1776
- "moveTo": true,
1777
- "click": true,
1778
- "typeKeys": {
1779
- "keys": [
1780
- "shorthair cat"
1781
- ]
1782
- }
1783
- },
1784
- {
1785
- "action": "typeKeys",
1786
- "keys": [
1787
- "$ENTER$"
1788
- ]
1789
- },
1790
- {
1791
- "action": "saveScreenshot"
1792
- }
1793
- ]
1794
- }
1795
- ]
1796
- }
1797
- ]
1
+ {
2
+ "title": "specification",
3
+ "type": "object",
4
+ "properties": {
5
+ "id": {
6
+ "type": "string",
7
+ "description": "Unique identifier for the test specification."
8
+ },
9
+ "description": {
10
+ "type": "string",
11
+ "description": "Description of the test specification."
12
+ },
13
+ "file": {
14
+ "type": "string",
15
+ "description": "Path to the file that the specification is associated with."
16
+ },
17
+ "contexts": {
18
+ "type": "array",
19
+ "description": "Application/platform sets to run tests in. Overrides `contexts` defined at the config-level.",
20
+ "items": {
21
+ "oneOf": [
22
+ {
23
+ "title": "context",
24
+ "type": "object",
25
+ "description": "An application and supported platforms.\n\nIf no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For browsers, context priority is Firefox > Chrome > Chromium.",
26
+ "properties": {
27
+ "app": {
28
+ "type": "object",
29
+ "description": "The application to run.",
30
+ "additionalProperties": false,
31
+ "required": [
32
+ "name"
33
+ ],
34
+ "properties": {
35
+ "name": {
36
+ "type": "string",
37
+ "description": "Name of the application.",
38
+ "enum": [
39
+ "chrome",
40
+ "firefox",
41
+ "safari",
42
+ "edge"
43
+ ]
44
+ },
45
+ "path": {
46
+ "type": "string",
47
+ "description": "Absolute path or command for the application. If not specified, defaults to typical install paths per platform. If specified but the path is invalid, the context is skipped."
48
+ },
49
+ "options": {
50
+ "type": "object",
51
+ "description": "Options to pass to the app. Only works when `name` is `firefox` or `chrome`.",
52
+ "additionalProperties": false,
53
+ "properties": {
54
+ "width": {
55
+ "type": "integer",
56
+ "description": "Width of the window in pixels."
57
+ },
58
+ "height": {
59
+ "type": "integer",
60
+ "description": "Height of the window in pixels."
61
+ },
62
+ "headless": {
63
+ "type": "boolean",
64
+ "description": "If `true`, runs the browser in headless mode. Not supported by Safari."
65
+ },
66
+ "driverPath": {
67
+ "type": "string",
68
+ "description": "Path to the browser driver. If not specified, defaults to internally managed dependencies."
69
+ }
70
+ }
71
+ }
72
+ }
73
+ },
74
+ "platforms": {
75
+ "description": "Supported platforms for the application.",
76
+ "type": "array",
77
+ "items": {
78
+ "type": "string",
79
+ "enum": [
80
+ "linux",
81
+ "mac",
82
+ "windows"
83
+ ]
84
+ }
85
+ }
86
+ },
87
+ "required": [
88
+ "app",
89
+ "platforms"
90
+ ],
91
+ "additionalProperties": false,
92
+ "examples": [
93
+ {
94
+ "app": {
95
+ "name": "chrome"
96
+ },
97
+ "platforms": [
98
+ "linux"
99
+ ]
100
+ },
101
+ {
102
+ "app": {
103
+ "name": "firefox",
104
+ "options": {
105
+ "width": 800,
106
+ "height": 600,
107
+ "headless": false,
108
+ "driverPath": "/usr/bin/geckodriver"
109
+ }
110
+ },
111
+ "platforms": [
112
+ "linux",
113
+ "windows",
114
+ "mac"
115
+ ]
116
+ },
117
+ {
118
+ "app": {
119
+ "name": "safari"
120
+ },
121
+ "platforms": [
122
+ "mac"
123
+ ]
124
+ },
125
+ {
126
+ "app": {
127
+ "name": "firefox",
128
+ "path": "/usr/bin/firefox"
129
+ },
130
+ "platforms": [
131
+ "linux"
132
+ ]
133
+ }
134
+ ]
135
+ }
136
+ ]
137
+ }
138
+ },
139
+ "openApi": {
140
+ "type": "array",
141
+ "items": {
142
+ "allOf": [
143
+ {
144
+ "version": "1.0.0",
145
+ "$schema": "http://json-schema.org/draft-07/schema#",
146
+ "title": "openApi",
147
+ "type": "object",
148
+ "description": "OpenAPI definition and configuration.",
149
+ "additionalProperties": false,
150
+ "properties": {
151
+ "name": {
152
+ "type": "string",
153
+ "description": "Name of the OpenAPI definition, as defined in your configuration."
154
+ },
155
+ "descriptionPath": {
156
+ "type": "string",
157
+ "description": "URL or local path to the OpenAPI definition."
158
+ },
159
+ "operationId": {
160
+ "type": "string",
161
+ "description": "ID of the operation to use for the request."
162
+ },
163
+ "server": {
164
+ "type": "string",
165
+ "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition."
166
+ },
167
+ "validateAgainstSchema": {
168
+ "type": "string",
169
+ "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.",
170
+ "enum": [
171
+ "request",
172
+ "response",
173
+ "both",
174
+ "none"
175
+ ],
176
+ "default": "both"
177
+ },
178
+ "mockResponse": {
179
+ "type": "boolean",
180
+ "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code."
181
+ },
182
+ "statusCode": {
183
+ "type": "integer",
184
+ "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified."
185
+ },
186
+ "useExample": {
187
+ "type": [
188
+ "string"
189
+ ],
190
+ "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.",
191
+ "enum": [
192
+ "request",
193
+ "response",
194
+ "both",
195
+ "none"
196
+ ],
197
+ "default": "none"
198
+ },
199
+ "exampleKey": {
200
+ "type": "string",
201
+ "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.",
202
+ "default": ""
203
+ },
204
+ "requestHeaders": {
205
+ "type": "object",
206
+ "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.",
207
+ "additionalProperties": {
208
+ "type": "string"
209
+ }
210
+ }
211
+ },
212
+ "examples": [
213
+ {
214
+ "descriptionPath": "https://petstore.swagger.io/v2/swagger.json"
215
+ }
216
+ ]
217
+ },
218
+ {
219
+ "type": "object",
220
+ "properties": {
221
+ "operationId": {
222
+ "type": "null",
223
+ "$commment": "Only allow operationId at the step level."
224
+ }
225
+ },
226
+ "required": [
227
+ "name",
228
+ "descriptionPath"
229
+ ]
230
+ }
231
+ ]
232
+ }
233
+ },
234
+ "tests": {
235
+ "description": "[Tests](test) to perform.",
236
+ "type": "array",
237
+ "minItems": 1,
238
+ "items": {
239
+ "oneOf": [
240
+ {
241
+ "title": "test",
242
+ "type": "object",
243
+ "description": "A Doc Detective test.",
244
+ "properties": {
245
+ "id": {
246
+ "type": "string",
247
+ "description": "Unique identifier for the test."
248
+ },
249
+ "description": {
250
+ "type": "string",
251
+ "description": "Description of the test."
252
+ },
253
+ "file": {
254
+ "type": "string",
255
+ "description": "Path to the file that the test is associated with."
256
+ },
257
+ "detectSteps": {
258
+ "type": "boolean",
259
+ "description": "Whether or not to detect steps in input files based on markup regex. Defaults to `true`."
260
+ },
261
+ "contexts": {
262
+ "type": "array",
263
+ "description": "Application/platform sets to run the test in. Overrides `contexts` defined at the config-level and spec-level.",
264
+ "items": {
265
+ "oneOf": [
266
+ {
267
+ "title": "context",
268
+ "type": "object",
269
+ "description": "An application and supported platforms.\n\nIf no contexts are specified but a context is required by one or more tests, Doc Detective attempts to identify a supported context in the current environment and run tests against it. For browsers, context priority is Firefox > Chrome > Chromium.",
270
+ "properties": {
271
+ "app": {
272
+ "type": "object",
273
+ "description": "The application to run.",
274
+ "additionalProperties": false,
275
+ "required": [
276
+ "name"
277
+ ],
278
+ "properties": {
279
+ "name": {
280
+ "type": "string",
281
+ "description": "Name of the application.",
282
+ "enum": [
283
+ "chrome",
284
+ "firefox",
285
+ "safari",
286
+ "edge"
287
+ ]
288
+ },
289
+ "path": {
290
+ "type": "string",
291
+ "description": "Absolute path or command for the application. If not specified, defaults to typical install paths per platform. If specified but the path is invalid, the context is skipped."
292
+ },
293
+ "options": {
294
+ "type": "object",
295
+ "description": "Options to pass to the app. Only works when `name` is `firefox` or `chrome`.",
296
+ "additionalProperties": false,
297
+ "properties": {
298
+ "width": {
299
+ "type": "integer",
300
+ "description": "Width of the window in pixels."
301
+ },
302
+ "height": {
303
+ "type": "integer",
304
+ "description": "Height of the window in pixels."
305
+ },
306
+ "headless": {
307
+ "type": "boolean",
308
+ "description": "If `true`, runs the browser in headless mode. Not supported by Safari."
309
+ },
310
+ "driverPath": {
311
+ "type": "string",
312
+ "description": "Path to the browser driver. If not specified, defaults to internally managed dependencies."
313
+ }
314
+ }
315
+ }
316
+ }
317
+ },
318
+ "platforms": {
319
+ "description": "Supported platforms for the application.",
320
+ "type": "array",
321
+ "items": {
322
+ "type": "string",
323
+ "enum": [
324
+ "linux",
325
+ "mac",
326
+ "windows"
327
+ ]
328
+ }
329
+ }
330
+ },
331
+ "required": [
332
+ "app",
333
+ "platforms"
334
+ ],
335
+ "additionalProperties": false,
336
+ "examples": [
337
+ {
338
+ "app": {
339
+ "name": "chrome"
340
+ },
341
+ "platforms": [
342
+ "linux"
343
+ ]
344
+ },
345
+ {
346
+ "app": {
347
+ "name": "firefox",
348
+ "options": {
349
+ "width": 800,
350
+ "height": 600,
351
+ "headless": false,
352
+ "driverPath": "/usr/bin/geckodriver"
353
+ }
354
+ },
355
+ "platforms": [
356
+ "linux",
357
+ "windows",
358
+ "mac"
359
+ ]
360
+ },
361
+ {
362
+ "app": {
363
+ "name": "safari"
364
+ },
365
+ "platforms": [
366
+ "mac"
367
+ ]
368
+ },
369
+ {
370
+ "app": {
371
+ "name": "firefox",
372
+ "path": "/usr/bin/firefox"
373
+ },
374
+ "platforms": [
375
+ "linux"
376
+ ]
377
+ }
378
+ ]
379
+ }
380
+ ]
381
+ }
382
+ },
383
+ "openApi": {
384
+ "type": "array",
385
+ "items": {
386
+ "allOf": [
387
+ {
388
+ "version": "1.0.0",
389
+ "$schema": "http://json-schema.org/draft-07/schema#",
390
+ "title": "openApi",
391
+ "type": "object",
392
+ "description": "OpenAPI definition and configuration.",
393
+ "additionalProperties": false,
394
+ "properties": {
395
+ "name": {
396
+ "type": "string",
397
+ "description": "Name of the OpenAPI definition, as defined in your configuration."
398
+ },
399
+ "descriptionPath": {
400
+ "type": "string",
401
+ "description": "URL or local path to the OpenAPI definition."
402
+ },
403
+ "operationId": {
404
+ "type": "string",
405
+ "description": "ID of the operation to use for the request."
406
+ },
407
+ "server": {
408
+ "type": "string",
409
+ "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition."
410
+ },
411
+ "validateAgainstSchema": {
412
+ "type": "string",
413
+ "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.",
414
+ "enum": [
415
+ "request",
416
+ "response",
417
+ "both",
418
+ "none"
419
+ ],
420
+ "default": "both"
421
+ },
422
+ "mockResponse": {
423
+ "type": "boolean",
424
+ "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code."
425
+ },
426
+ "statusCode": {
427
+ "type": "integer",
428
+ "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified."
429
+ },
430
+ "useExample": {
431
+ "type": [
432
+ "string"
433
+ ],
434
+ "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.",
435
+ "enum": [
436
+ "request",
437
+ "response",
438
+ "both",
439
+ "none"
440
+ ],
441
+ "default": "none"
442
+ },
443
+ "exampleKey": {
444
+ "type": "string",
445
+ "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.",
446
+ "default": ""
447
+ },
448
+ "requestHeaders": {
449
+ "type": "object",
450
+ "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.",
451
+ "additionalProperties": {
452
+ "type": "string"
453
+ }
454
+ }
455
+ },
456
+ "examples": [
457
+ {
458
+ "descriptionPath": "https://petstore.swagger.io/v2/swagger.json"
459
+ }
460
+ ]
461
+ },
462
+ {
463
+ "type": "object",
464
+ "properties": {
465
+ "operationId": {
466
+ "type": "null",
467
+ "$commment": "Only allow operationId at the step level."
468
+ }
469
+ },
470
+ "required": [
471
+ "name",
472
+ "descriptionPath"
473
+ ]
474
+ }
475
+ ]
476
+ }
477
+ },
478
+ "setup": {
479
+ "type": "string",
480
+ "description": "Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec."
481
+ },
482
+ "cleanup": {
483
+ "type": "string",
484
+ "description": "Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec."
485
+ },
486
+ "steps": {
487
+ "description": "Actions to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails.",
488
+ "type": "array",
489
+ "minItems": 1,
490
+ "items": {
491
+ "anyOf": [
492
+ {
493
+ "title": "checkLink",
494
+ "type": "object",
495
+ "description": "Check if a URL returns an acceptable status code from a GET request.",
496
+ "properties": {
497
+ "id": {
498
+ "type": "string",
499
+ "description": "ID of the step."
500
+ },
501
+ "description": {
502
+ "type": "string",
503
+ "description": "Description of the step."
504
+ },
505
+ "action": {
506
+ "type": "string",
507
+ "const": "checkLink",
508
+ "description": "Action to perform."
509
+ },
510
+ "url": {
511
+ "type": "string",
512
+ "description": "URL to check.",
513
+ "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)",
514
+ "transform": [
515
+ "trim"
516
+ ]
517
+ },
518
+ "origin": {
519
+ "type": "string",
520
+ "description": "Protocol and domain to navigate to. Prepended to `url`.",
521
+ "transform": [
522
+ "trim"
523
+ ]
524
+ },
525
+ "statusCodes": {
526
+ "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.",
527
+ "type": "array",
528
+ "items": {
529
+ "oneOf": [
530
+ {
531
+ "type": "integer"
532
+ }
533
+ ]
534
+ },
535
+ "default": [
536
+ 200,
537
+ 201,
538
+ 202
539
+ ]
540
+ }
541
+ },
542
+ "dynamicDefaults": {
543
+ "id": "uuid"
544
+ },
545
+ "required": [
546
+ "action",
547
+ "url"
548
+ ],
549
+ "additionalProperties": false,
550
+ "examples": [
551
+ {
552
+ "action": "checkLink",
553
+ "url": "https://www.google.com"
554
+ },
555
+ {
556
+ "action": "checkLink",
557
+ "url": "https://www.google.com",
558
+ "statusCodes": [
559
+ 200
560
+ ]
561
+ },
562
+ {
563
+ "action": "checkLink",
564
+ "url": "/search",
565
+ "origin": "www.google.com",
566
+ "statusCodes": [
567
+ 200
568
+ ]
569
+ }
570
+ ]
571
+ },
572
+ {
573
+ "title": "goTo",
574
+ "type": "object",
575
+ "description": "Navigate to a specified URL.",
576
+ "properties": {
577
+ "id": {
578
+ "type": "string",
579
+ "description": "ID of the step."
580
+ },
581
+ "description": {
582
+ "type": "string",
583
+ "description": "Description of the step."
584
+ },
585
+ "action": {
586
+ "type": "string",
587
+ "const": "goTo",
588
+ "description": "Action to perform."
589
+ },
590
+ "url": {
591
+ "type": "string",
592
+ "description": "URL to navigate to.",
593
+ "pattern": "(^(http://|https://|/).*|\\$[A-Za-z0-9_]+)",
594
+ "transform": [
595
+ "trim"
596
+ ]
597
+ },
598
+ "origin": {
599
+ "type": "string",
600
+ "description": "Protocol and domain to navigate to. Prepended to `url`.",
601
+ "transform": [
602
+ "trim"
603
+ ]
604
+ }
605
+ },
606
+ "dynamicDefaults": {
607
+ "id": "uuid"
608
+ },
609
+ "required": [
610
+ "action",
611
+ "url"
612
+ ],
613
+ "additionalProperties": false,
614
+ "examples": [
615
+ {
616
+ "action": "goTo",
617
+ "url": "https://www.google.com"
618
+ },
619
+ {
620
+ "id": "ddec5e20-2e81-4f38-867c-92c8d9516755",
621
+ "description": "This is a test!",
622
+ "action": "goTo",
623
+ "url": "https://www.google.com"
624
+ },
625
+ {
626
+ "id": "ddec5e20-2e81-4f38-867c-92c8d9516756",
627
+ "description": "This is a test!",
628
+ "action": "goTo",
629
+ "url": "/search",
630
+ "origin": "https://www.google.com"
631
+ }
632
+ ]
633
+ },
634
+ {
635
+ "title": "httpRequest",
636
+ "type": "object",
637
+ "description": "Perform a generic HTTP request, for example to an API.",
638
+ "properties": {
639
+ "id": {
640
+ "type": "string",
641
+ "description": "ID of the step."
642
+ },
643
+ "description": {
644
+ "type": "string",
645
+ "description": "Description of the step."
646
+ },
647
+ "action": {
648
+ "type": "string",
649
+ "const": "httpRequest",
650
+ "description": "Aciton to perform."
651
+ },
652
+ "url": {
653
+ "type": "string",
654
+ "description": "URL for the HTTP request.",
655
+ "pattern": "(^(http://|https://).*|\\$[A-Za-z0-9_]+)",
656
+ "transform": [
657
+ "trim"
658
+ ]
659
+ },
660
+ "openApi": {
661
+ "allOf": [
662
+ {
663
+ "version": "1.0.0",
664
+ "$schema": "http://json-schema.org/draft-07/schema#",
665
+ "title": "openApi",
666
+ "type": "object",
667
+ "description": "OpenAPI definition and configuration.",
668
+ "additionalProperties": false,
669
+ "properties": {
670
+ "name": {
671
+ "type": "string",
672
+ "description": "Name of the OpenAPI definition, as defined in your configuration."
673
+ },
674
+ "descriptionPath": {
675
+ "type": "string",
676
+ "description": "URL or local path to the OpenAPI definition."
677
+ },
678
+ "operationId": {
679
+ "type": "string",
680
+ "description": "ID of the operation to use for the request."
681
+ },
682
+ "server": {
683
+ "type": "string",
684
+ "description": "Server to use for example requests. Only valid if `useExample` is `request` or `both`. If not specified but an example is used for the request, uses the first server defined in the OpenAPI definition."
685
+ },
686
+ "validateAgainstSchema": {
687
+ "type": "string",
688
+ "description": "Validates the request and/or response against the schema in the OpenAPI definition. If the request or response doesn't match the schema, the step fails.",
689
+ "enum": [
690
+ "request",
691
+ "response",
692
+ "both",
693
+ "none"
694
+ ],
695
+ "default": "both"
696
+ },
697
+ "mockResponse": {
698
+ "type": "boolean",
699
+ "description": "If `true`, doesn't make the HTTP request, but instead uses the response example or schema from the OpenAPI definition as the response data. Useful for creating tests when an API isn't fully implemented yet. If `statusCode` isn't specified, uses the first defined response code."
700
+ },
701
+ "statusCode": {
702
+ "type": "integer",
703
+ "description": "Response code to use for validation, examples, and status code checking. If the response code doesn't match, the step fails. `statusCodes` overrides this value when specified."
704
+ },
705
+ "useExample": {
706
+ "type": [
707
+ "string"
708
+ ],
709
+ "description": "Uses the example from the OpenAPI definition as the request and response data. If the request or response has multiple examples, specify `exampleKey`. If `statusCode` isn't specified, uses the first defined response code. `requestData`, `requestParams`, and `requestHeaders` override portions of request examples when specified. `responseData` overrides portions of response examples when specified.",
710
+ "enum": [
711
+ "request",
712
+ "response",
713
+ "both",
714
+ "none"
715
+ ],
716
+ "default": "none"
717
+ },
718
+ "exampleKey": {
719
+ "type": "string",
720
+ "description": "Key of the example to use from the `examples` property in the OpenAPI definition. If an `examples` key isn't specified or isn't available for a given parameter or object, the `example` property value is used.",
721
+ "default": ""
722
+ },
723
+ "requestHeaders": {
724
+ "type": "object",
725
+ "description": "Request headers to add to the request. If specified in both a config and a step, the step value overrides the config value.",
726
+ "additionalProperties": {
727
+ "type": "string"
728
+ }
729
+ }
730
+ },
731
+ "examples": [
732
+ {
733
+ "descriptionPath": "https://petstore.swagger.io/v2/swagger.json"
734
+ }
735
+ ]
736
+ },
737
+ {
738
+ "type": "object",
739
+ "required": [
740
+ "operationId"
741
+ ]
742
+ }
743
+ ]
744
+ },
745
+ "statusCodes": {
746
+ "description": "Accepted status codes. If the specified URL returns a code other than what is specified here, the action fails.",
747
+ "type": "array",
748
+ "items": {
749
+ "oneOf": [
750
+ {
751
+ "type": "integer"
752
+ }
753
+ ]
754
+ },
755
+ "default": [
756
+ 200
757
+ ]
758
+ },
759
+ "method": {
760
+ "type": "string",
761
+ "description": "Method of the HTTP request",
762
+ "enum": [
763
+ "get",
764
+ "put",
765
+ "post",
766
+ "patch",
767
+ "delete"
768
+ ],
769
+ "transform": [
770
+ "trim",
771
+ "toEnumCase"
772
+ ],
773
+ "default": "get"
774
+ },
775
+ "timeout": {
776
+ "type": "integer",
777
+ "description": "Timeout for the HTTP request, in milliseconds.",
778
+ "default": 60000
779
+ },
780
+ "requestHeaders": {
781
+ "description": "Headers to include in the HTTP request, in key/value format.",
782
+ "type": "object",
783
+ "additionalProperties": true,
784
+ "properties": {},
785
+ "default": {}
786
+ },
787
+ "responseHeaders": {
788
+ "description": "Headers expected in the response, in key/value format. If one or more `responseHeaders` entries aren't present in the response, the step fails.",
789
+ "type": "object",
790
+ "additionalProperties": true,
791
+ "properties": {},
792
+ "default": {}
793
+ },
794
+ "requestParams": {
795
+ "description": "URL parameters to include in the HTTP request, in key/value format.",
796
+ "type": "object",
797
+ "additionalProperties": true,
798
+ "default": {},
799
+ "properties": {}
800
+ },
801
+ "responseParams": {
802
+ "description": "DEPRECATED.",
803
+ "type": "object",
804
+ "additionalProperties": true,
805
+ "default": {},
806
+ "properties": {}
807
+ },
808
+ "requestData": {
809
+ "description": "JSON object to include as the body of the HTTP request.",
810
+ "type": "object",
811
+ "additionalProperties": true,
812
+ "default": {},
813
+ "properties": {}
814
+ },
815
+ "responseData": {
816
+ "description": "JSON object expected in the response. If one or more key/value pairs aren't present in the response, the step fails.",
817
+ "type": "object",
818
+ "additionalProperties": true,
819
+ "default": {},
820
+ "properties": {}
821
+ },
822
+ "allowAdditionalFields": {
823
+ "type": "boolean",
824
+ "description": "If `false`, the step fails when the response data contains fields not specified in `responseData`.",
825
+ "default": true
826
+ },
827
+ "savePath": {
828
+ "type": "string",
829
+ "description": "File path to save the command's output, relative to `saveDirectory`. Specify a file extension that matches the expected response type, such as `.json` for JSON content or `.txt` for strings."
830
+ },
831
+ "saveDirectory": {
832
+ "type": "string",
833
+ "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory."
834
+ },
835
+ "maxVariation": {
836
+ "type": "integer",
837
+ "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.",
838
+ "default": 0,
839
+ "minimum": 0,
840
+ "maximum": 100
841
+ },
842
+ "overwrite": {
843
+ "type": "string",
844
+ "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.",
845
+ "enum": [
846
+ "true",
847
+ "false",
848
+ "byVariation"
849
+ ],
850
+ "default": "false"
851
+ },
852
+ "envsFromResponseData": {
853
+ "description": "Environment variables to set based on response variables, as an object of the environment variable name and the jq filter applied to the response data to identify the variable's value.",
854
+ "type": "array",
855
+ "default": [],
856
+ "items": {
857
+ "oneOf": [
858
+ {
859
+ "description": "",
860
+ "type": "object",
861
+ "properties": {
862
+ "name": {
863
+ "description": "Name of the environment variable to set.",
864
+ "type": "string"
865
+ },
866
+ "jqFilter": {
867
+ "description": "jq filter to apply to the response data. If the filter doesn't return a value, the environment variable isn't set.",
868
+ "type": "string"
869
+ }
870
+ },
871
+ "required": [
872
+ "name",
873
+ "jqFilter"
874
+ ]
875
+ }
876
+ ]
877
+ }
878
+ }
879
+ },
880
+ "dynamicDefaults": {
881
+ "id": "uuid"
882
+ },
883
+ "anyOf": [
884
+ {
885
+ "required": [
886
+ "url"
887
+ ]
888
+ },
889
+ {
890
+ "required": [
891
+ "openApi"
892
+ ]
893
+ }
894
+ ],
895
+ "required": [
896
+ "action"
897
+ ],
898
+ "additionalProperties": false,
899
+ "examples": [
900
+ {
901
+ "action": "httpRequest",
902
+ "url": "https://reqres.in/api/users"
903
+ },
904
+ {
905
+ "action": "httpRequest",
906
+ "url": "https://reqres.in/api/users/2",
907
+ "method": "put",
908
+ "requestData": {
909
+ "name": "morpheus",
910
+ "job": "zion resident"
911
+ }
912
+ },
913
+ {
914
+ "action": "httpRequest",
915
+ "url": "https://reqres.in/api/users",
916
+ "method": "post",
917
+ "requestData": {
918
+ "name": "morpheus",
919
+ "job": "leader"
920
+ },
921
+ "responseData": {
922
+ "name": "morpheus",
923
+ "job": "leader"
924
+ },
925
+ "statusCodes": [
926
+ 200,
927
+ 201
928
+ ]
929
+ },
930
+ {
931
+ "action": "httpRequest",
932
+ "url": "https://www.api-server.com",
933
+ "method": "post",
934
+ "timeout": 30000,
935
+ "requestHeaders": {
936
+ "header": "value"
937
+ },
938
+ "requestParams": {
939
+ "param": "value"
940
+ },
941
+ "requestData": {
942
+ "field": "value"
943
+ },
944
+ "responseHeaders": {
945
+ "header": "value"
946
+ },
947
+ "responseData": {
948
+ "field": "value"
949
+ },
950
+ "statusCodes": [
951
+ 200
952
+ ]
953
+ },
954
+ {
955
+ "action": "httpRequest",
956
+ "url": "https://reqres.in/api/users",
957
+ "method": "post",
958
+ "requestData": {
959
+ "name": "morpheus",
960
+ "job": "leader"
961
+ },
962
+ "responseData": {
963
+ "name": "morpheus",
964
+ "job": "leader"
965
+ },
966
+ "statusCodes": [
967
+ 200,
968
+ 201
969
+ ],
970
+ "savePath": "response.json",
971
+ "saveDirectory": "media",
972
+ "maxVariation": 5,
973
+ "overwrite": "byVariation"
974
+ },
975
+ {
976
+ "action": "httpRequest",
977
+ "openApi": {
978
+ "name": "Reqres",
979
+ "operationId": "getUserById"
980
+ },
981
+ "requestParams": {
982
+ "id": 123
983
+ }
984
+ },
985
+ {
986
+ "action": "httpRequest",
987
+ "openApi": {
988
+ "descriptionPath": "https://api.example.com/openapi.json",
989
+ "operationId": "getUserById"
990
+ },
991
+ "requestParams": {
992
+ "id": 123
993
+ }
994
+ },
995
+ {
996
+ "action": "httpRequest",
997
+ "openApi": {
998
+ "descriptionPath": "https://api.example.com/openapi.json",
999
+ "operationId": "createUser",
1000
+ "useExample": "both"
1001
+ }
1002
+ },
1003
+ {
1004
+ "action": "httpRequest",
1005
+ "openApi": {
1006
+ "descriptionPath": "https://api.example.com/openapi.json",
1007
+ "operationId": "updateUser",
1008
+ "useExample": "request",
1009
+ "exampleKey": "acme"
1010
+ }
1011
+ },
1012
+ {
1013
+ "action": "httpRequest",
1014
+ "openApi": {
1015
+ "descriptionPath": "https://api.example.com/openapi.json",
1016
+ "operationId": "updateUser",
1017
+ "useExample": "request",
1018
+ "exampleKey": "acme",
1019
+ "requestHeaders": {
1020
+ "Authorization": "Bearer $TOKEN"
1021
+ }
1022
+ }
1023
+ }
1024
+ ]
1025
+ },
1026
+ {
1027
+ "title": "runShell",
1028
+ "type": "object",
1029
+ "description": "Perform a native shell command.",
1030
+ "properties": {
1031
+ "id": {
1032
+ "type": "string",
1033
+ "description": "ID of the step."
1034
+ },
1035
+ "description": {
1036
+ "type": "string",
1037
+ "description": "Description of the step."
1038
+ },
1039
+ "action": {
1040
+ "type": "string",
1041
+ "const": "runShell",
1042
+ "description": "The action to perform."
1043
+ },
1044
+ "command": {
1045
+ "type": "string",
1046
+ "description": "Command to perform in the machine's default shell."
1047
+ },
1048
+ "args": {
1049
+ "type": "array",
1050
+ "description": "Arguments for the command.",
1051
+ "items": {
1052
+ "oneOf": [
1053
+ {
1054
+ "type": "string"
1055
+ }
1056
+ ]
1057
+ },
1058
+ "default": []
1059
+ },
1060
+ "workingDirectory": {
1061
+ "type": "string",
1062
+ "description": "Working directory for the command.",
1063
+ "default": "."
1064
+ },
1065
+ "exitCodes": {
1066
+ "type": "array",
1067
+ "description": "Expected exit codes of the command. If the command's actual exit code isn't in this list, the step fails.",
1068
+ "items": {
1069
+ "oneOf": [
1070
+ {
1071
+ "type": "integer"
1072
+ }
1073
+ ]
1074
+ },
1075
+ "default": [
1076
+ 0
1077
+ ]
1078
+ },
1079
+ "output": {
1080
+ "type": "string",
1081
+ "description": "Content expected in the command's output. If the expected content can't be found in the command's output (either stdout or stderr), the step fails. Supports strings and regular expressions. To use a regular expression, the string must start and end with a forward slash, like in `/^hello-world.*/`."
1082
+ },
1083
+ "savePath": {
1084
+ "type": "string",
1085
+ "description": "File path to save the command's output, relative to `saveDirectory`."
1086
+ },
1087
+ "saveDirectory": {
1088
+ "type": "string",
1089
+ "description": "Directory to save the command's output. If the directory doesn't exist, creates the directory. If not specified, the directory is your media directory."
1090
+ },
1091
+ "maxVariation": {
1092
+ "type": "integer",
1093
+ "description": "Allowed variation in percentage of text different between the current output and previously saved output. If the difference between the current output and the previous output is greater than `maxVariation`, the step fails. If output doesn't exist at `savePath`, this value is ignored.",
1094
+ "default": 0,
1095
+ "minimum": 0,
1096
+ "maximum": 100
1097
+ },
1098
+ "overwrite": {
1099
+ "type": "string",
1100
+ "description": "If `true`, overwrites the existing output at `savePath` if it exists.\nIf `byVariation`, overwrites the existing output at `savePath` if the difference between the new output and the existing output is greater than `maxVariation`.",
1101
+ "enum": [
1102
+ "true",
1103
+ "false",
1104
+ "byVariation"
1105
+ ],
1106
+ "default": "false"
1107
+ },
1108
+ "timeout": {
1109
+ "type": "integer",
1110
+ "description": "Max time in milliseconds the command is allowed to run. If the command runs longer than this, the step fails.",
1111
+ "default": 60000
1112
+ },
1113
+ "setVariables": {
1114
+ "type": "array",
1115
+ "description": "Extract environment variables from the command's output.",
1116
+ "items": {
1117
+ "oneOf": [
1118
+ {
1119
+ "description": "",
1120
+ "type": "object",
1121
+ "properties": {
1122
+ "name": {
1123
+ "description": "Name of the environment variable to set.",
1124
+ "type": "string"
1125
+ },
1126
+ "regex": {
1127
+ "description": "Regex to extract the environment variable from the command's output.",
1128
+ "type": "string"
1129
+ }
1130
+ },
1131
+ "required": [
1132
+ "name",
1133
+ "regex"
1134
+ ]
1135
+ }
1136
+ ]
1137
+ },
1138
+ "default": []
1139
+ }
1140
+ },
1141
+ "dynamicDefaults": {
1142
+ "id": "uuid"
1143
+ },
1144
+ "additionalProperties": false,
1145
+ "required": [
1146
+ "action",
1147
+ "command"
1148
+ ],
1149
+ "examples": [
1150
+ {
1151
+ "action": "runShell",
1152
+ "command": "echo",
1153
+ "args": [
1154
+ "$USER"
1155
+ ]
1156
+ },
1157
+ {
1158
+ "action": "runShell",
1159
+ "command": "echo",
1160
+ "args": [
1161
+ "hello-world"
1162
+ ],
1163
+ "id": "ddec5e20-2e81-4f38-867c-92c8d9516755",
1164
+ "description": "This is a test!"
1165
+ },
1166
+ {
1167
+ "action": "runShell",
1168
+ "command": "docker run hello-world",
1169
+ "timeout": 20000,
1170
+ "exitCodes": [
1171
+ 0
1172
+ ],
1173
+ "output": "Hello from Docker!"
1174
+ },
1175
+ {
1176
+ "action": "runShell",
1177
+ "command": "false",
1178
+ "exitCodes": [
1179
+ 1
1180
+ ]
1181
+ },
1182
+ {
1183
+ "action": "runShell",
1184
+ "command": "echo",
1185
+ "args": [
1186
+ "setup"
1187
+ ],
1188
+ "exitCodes": [
1189
+ 0
1190
+ ],
1191
+ "output": "/.*?/",
1192
+ "setVariables": [
1193
+ {
1194
+ "name": "TEST",
1195
+ "regex": ".*"
1196
+ }
1197
+ ]
1198
+ },
1199
+ {
1200
+ "action": "runShell",
1201
+ "command": "docker run hello-world",
1202
+ "workingDirectory": ".",
1203
+ "exitCodes": [
1204
+ 0
1205
+ ],
1206
+ "output": "Hello from Docker!",
1207
+ "savePath": "docker-output.txt",
1208
+ "saveDirectory": "output",
1209
+ "maxVariation": 10,
1210
+ "overwrite": "byVariation"
1211
+ }
1212
+ ]
1213
+ },
1214
+ {
1215
+ "title": "saveScreenshot",
1216
+ "type": "object",
1217
+ "description": "Takes a screenshot in PNG format.",
1218
+ "properties": {
1219
+ "id": {
1220
+ "type": "string",
1221
+ "description": "ID of the step."
1222
+ },
1223
+ "description": {
1224
+ "type": "string",
1225
+ "description": "Description of the step."
1226
+ },
1227
+ "action": {
1228
+ "type": "string",
1229
+ "const": "saveScreenshot",
1230
+ "description": "The action to perform."
1231
+ },
1232
+ "path": {
1233
+ "type": "string",
1234
+ "description": "File path of the PNG file, relative to `directory`. If not specified, the file name is the ID of the step.",
1235
+ "pattern": "([A-Za-z0-9_-]*\\.(png|PNG)$|\\$[A-Za-z0-9_]+)"
1236
+ },
1237
+ "directory": {
1238
+ "type": "string",
1239
+ "description": "Directory of the PNG file. If the directory doesn't exist, creates the directory."
1240
+ },
1241
+ "maxVariation": {
1242
+ "type": "number",
1243
+ "description": "Allowed variation in percentage of pixels between the new screenshot and the exisitng screenshot at `path`. If the difference between the new screenshot and the existing screenshot is greater than `maxVariation`, the step fails. If a screenshot doesn't exist at `path`, this value is ignored.",
1244
+ "default": 5,
1245
+ "minimum": 0,
1246
+ "maximum": 100
1247
+ },
1248
+ "overwrite": {
1249
+ "type": "string",
1250
+ "description": "If `true`, overwrites the existing screenshot at `path` if it exists.\nIf `byVariation`, overwrites the existing screenshot at `path` if the difference between the new screenshot and the existing screenshot is greater than `maxVariation`.",
1251
+ "enum": [
1252
+ "true",
1253
+ "false",
1254
+ "byVariation"
1255
+ ],
1256
+ "default": "false"
1257
+ },
1258
+ "crop": {
1259
+ "type": "object",
1260
+ "description": "Crops the screenshot.",
1261
+ "properties": {
1262
+ "selector": {
1263
+ "type": "string",
1264
+ "description": "Selector of the element to crop the image to."
1265
+ },
1266
+ "padding": {
1267
+ "oneOf": [
1268
+ {
1269
+ "type": "number",
1270
+ "description": "Padding in pixels to add to the bounds of the element.",
1271
+ "minimum": 0
1272
+ },
1273
+ {
1274
+ "type": "object",
1275
+ "properties": {
1276
+ "top": {
1277
+ "type": "number",
1278
+ "minimum": 0
1279
+ },
1280
+ "right": {
1281
+ "type": "number",
1282
+ "minimum": 0
1283
+ },
1284
+ "bottom": {
1285
+ "type": "number",
1286
+ "minimum": 0
1287
+ },
1288
+ "left": {
1289
+ "type": "number",
1290
+ "minimum": 0
1291
+ }
1292
+ }
1293
+ }
1294
+ ]
1295
+ }
1296
+ },
1297
+ "required": [
1298
+ "selector"
1299
+ ],
1300
+ "additionalProperties": false
1301
+ }
1302
+ },
1303
+ "dynamicDefaults": {
1304
+ "id": "uuid"
1305
+ },
1306
+ "required": [
1307
+ "action"
1308
+ ],
1309
+ "additionalProperties": false,
1310
+ "examples": [
1311
+ {
1312
+ "action": "saveScreenshot"
1313
+ },
1314
+ {
1315
+ "action": "saveScreenshot",
1316
+ "path": "results.png"
1317
+ },
1318
+ {
1319
+ "action": "saveScreenshot",
1320
+ "path": "results.png",
1321
+ "directory": "static/images"
1322
+ },
1323
+ {
1324
+ "action": "saveScreenshot",
1325
+ "path": "results.png",
1326
+ "directory": "static/images",
1327
+ "maxVariation": 10,
1328
+ "overwrite": "byVariation"
1329
+ },
1330
+ {
1331
+ "action": "saveScreenshot",
1332
+ "path": "results.png",
1333
+ "directory": "static/images",
1334
+ "crop": {
1335
+ "selector": "#element"
1336
+ }
1337
+ },
1338
+ {
1339
+ "action": "saveScreenshot",
1340
+ "path": "results.png",
1341
+ "directory": "static/images",
1342
+ "crop": {
1343
+ "selector": "#element",
1344
+ "padding": 10
1345
+ }
1346
+ },
1347
+ {
1348
+ "action": "saveScreenshot",
1349
+ "path": "results.png",
1350
+ "directory": "static/images",
1351
+ "crop": {
1352
+ "selector": "#element",
1353
+ "padding": {
1354
+ "top": 10,
1355
+ "right": 20,
1356
+ "bottom": 30,
1357
+ "left": 40
1358
+ }
1359
+ }
1360
+ }
1361
+ ]
1362
+ },
1363
+ {
1364
+ "title": "setVariables",
1365
+ "type": "object",
1366
+ "description": "Load environment variables from a `.env` file.",
1367
+ "properties": {
1368
+ "id": {
1369
+ "type": "string",
1370
+ "description": "ID of the step."
1371
+ },
1372
+ "description": {
1373
+ "type": "string",
1374
+ "description": "Description of the step."
1375
+ },
1376
+ "action": {
1377
+ "type": "string",
1378
+ "const": "setVariables",
1379
+ "description": "Action to perform."
1380
+ },
1381
+ "path": {
1382
+ "type": "string",
1383
+ "description": "Path to the `.env` file."
1384
+ }
1385
+ },
1386
+ "dynamicDefaults": {
1387
+ "id": "uuid"
1388
+ },
1389
+ "required": [
1390
+ "action",
1391
+ "path"
1392
+ ],
1393
+ "additionalProperties": false,
1394
+ "examples": [
1395
+ {
1396
+ "action": "setVariables",
1397
+ "path": ".env"
1398
+ }
1399
+ ]
1400
+ },
1401
+ {
1402
+ "title": "startRecording",
1403
+ "type": "object",
1404
+ "description": "Start recording the current browser viewport. Must be followed by a `stopRecording` action. Only runs when the context `app` is `chrome` and `headless` is `false`. Supported extensions: [ '.mp4', '.webm', '.gif' ]",
1405
+ "properties": {
1406
+ "id": {
1407
+ "type": "string",
1408
+ "description": "ID of the step."
1409
+ },
1410
+ "description": {
1411
+ "type": "string",
1412
+ "description": "Description of the step."
1413
+ },
1414
+ "action": {
1415
+ "type": "string",
1416
+ "const": "startRecording",
1417
+ "description": "The action to perform."
1418
+ },
1419
+ "path": {
1420
+ "type": "string",
1421
+ "description": "File path of the recording. Supports the `.mp4`, `.webm`, and `.gif` extensions. If not specified, the file name is the ID of the step, and the extension is `.mp4`.",
1422
+ "pattern": "([A-Za-z0-9_-]*\\.(mp4|webm|gif)$|\\$[A-Za-z0-9_]+)"
1423
+ },
1424
+ "directory": {
1425
+ "type": "string",
1426
+ "description": "Directory of the file. Attempts to create the directory if it doesn't exist."
1427
+ },
1428
+ "overwrite": {
1429
+ "type": "boolean",
1430
+ "description": "If `true`, overwrites the existing file at `path` if it exists.",
1431
+ "default": false
1432
+ }
1433
+ },
1434
+ "dynamicDefaults": {
1435
+ "id": "uuid"
1436
+ },
1437
+ "required": [
1438
+ "action"
1439
+ ],
1440
+ "additionalProperties": false,
1441
+ "examples": [
1442
+ {
1443
+ "action": "startRecording"
1444
+ },
1445
+ {
1446
+ "action": "startRecording",
1447
+ "path": "results.mp4"
1448
+ },
1449
+ {
1450
+ "action": "startRecording",
1451
+ "path": "results.mp4",
1452
+ "directory": "static/media",
1453
+ "overwrite": true
1454
+ }
1455
+ ]
1456
+ },
1457
+ {
1458
+ "title": "stopRecording",
1459
+ "type": "object",
1460
+ "description": "Stop the current recording.",
1461
+ "properties": {
1462
+ "id": {
1463
+ "type": "string",
1464
+ "description": "ID of the step."
1465
+ },
1466
+ "description": {
1467
+ "type": "string",
1468
+ "description": "Description of the step."
1469
+ },
1470
+ "action": {
1471
+ "type": "string",
1472
+ "const": "stopRecording",
1473
+ "description": "The action to perform."
1474
+ }
1475
+ },
1476
+ "dynamicDefaults": {
1477
+ "id": "uuid"
1478
+ },
1479
+ "required": [
1480
+ "action"
1481
+ ],
1482
+ "additionalProperties": false,
1483
+ "examples": [
1484
+ {
1485
+ "action": "stopRecording"
1486
+ }
1487
+ ]
1488
+ },
1489
+ {
1490
+ "title": "typeKeys",
1491
+ "type": "object",
1492
+ "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's enum. For example, to type the Escape key, enter `$ESCAPE$`.",
1493
+ "properties": {
1494
+ "id": {
1495
+ "type": "string",
1496
+ "description": "ID of the step."
1497
+ },
1498
+ "description": {
1499
+ "type": "string",
1500
+ "description": "Description of the step."
1501
+ },
1502
+ "action": {
1503
+ "type": "string",
1504
+ "const": "typeKeys",
1505
+ "description": "The action to perform."
1506
+ },
1507
+ "keys": {
1508
+ "description": "String of keys to enter.",
1509
+ "anyOf": [
1510
+ {
1511
+ "type": "string"
1512
+ },
1513
+ {
1514
+ "type": "array",
1515
+ "items": {
1516
+ "oneOf": [
1517
+ {
1518
+ "type": "string"
1519
+ }
1520
+ ]
1521
+ }
1522
+ }
1523
+ ]
1524
+ },
1525
+ "delay": {
1526
+ "type": "number",
1527
+ "description": "Delay in milliseconds between each key press. Only valid during a recording.",
1528
+ "default": 100
1529
+ }
1530
+ },
1531
+ "dynamicDefaults": {
1532
+ "id": "uuid"
1533
+ },
1534
+ "required": [
1535
+ "action",
1536
+ "keys"
1537
+ ],
1538
+ "additionalProperties": false,
1539
+ "examples": [
1540
+ {
1541
+ "action": "typeKeys",
1542
+ "keys": "kittens"
1543
+ },
1544
+ {
1545
+ "action": "typeKeys",
1546
+ "keys": [
1547
+ "$ENTER$"
1548
+ ]
1549
+ },
1550
+ {
1551
+ "action": "typeKeys",
1552
+ "keys": [
1553
+ "kittens",
1554
+ "$ENTER$"
1555
+ ],
1556
+ "delay": 500
1557
+ }
1558
+ ]
1559
+ },
1560
+ {
1561
+ "title": "find",
1562
+ "type": "object",
1563
+ "description": "Check if an element exists with the specified CSS selector.",
1564
+ "properties": {
1565
+ "id": {
1566
+ "type": "string",
1567
+ "description": "ID of the step."
1568
+ },
1569
+ "description": {
1570
+ "type": "string",
1571
+ "description": "Description of the step."
1572
+ },
1573
+ "action": {
1574
+ "type": "string",
1575
+ "const": "find",
1576
+ "description": "Action to perform."
1577
+ },
1578
+ "selector": {
1579
+ "description": "Selector that uniquely identifies the element.",
1580
+ "type": "string"
1581
+ },
1582
+ "timeout": {
1583
+ "type": "integer",
1584
+ "description": "Max duration in milliseconds to wait for the element to exist.",
1585
+ "default": 5000
1586
+ },
1587
+ "matchText": {
1588
+ "type": "string",
1589
+ "description": "Text that the element should contain. If the element doesn't contain the text, the step fails. Accepts both strings an regular expressions. To use a regular expression, the expression should start and end with a `/`. For example, `/search/`."
1590
+ },
1591
+ "moveTo": {
1592
+ "description": "Move to the element. If the element isn't visible, it's scrolled into view. Only runs the if the test is being recorded.",
1593
+ "oneOf": [
1594
+ {
1595
+ "type": "boolean"
1596
+ }
1597
+ ],
1598
+ "default": false
1599
+ },
1600
+ "click": {
1601
+ "type": "boolean",
1602
+ "description": "Click the element.",
1603
+ "default": false
1604
+ },
1605
+ "typeKeys": {
1606
+ "description": "Type keys after finding the element. Either a string or an object with a `keys` field as defined in [`typeKeys`](typeKeys). To type in the element, make the element active with the `click` parameter.",
1607
+ "oneOf": [
1608
+ {
1609
+ "type": "string"
1610
+ },
1611
+ {
1612
+ "type": "object",
1613
+ "additionalProperties": false,
1614
+ "properties": {
1615
+ "keys": {
1616
+ "description": "String of keys to enter.",
1617
+ "anyOf": [
1618
+ {
1619
+ "type": "string"
1620
+ },
1621
+ {
1622
+ "type": "array",
1623
+ "items": {
1624
+ "oneOf": [
1625
+ {
1626
+ "type": "string"
1627
+ }
1628
+ ]
1629
+ }
1630
+ }
1631
+ ]
1632
+ },
1633
+ "delay": {
1634
+ "type": "number",
1635
+ "description": "Delay in milliseconds between each key press. Only valid during a recording.",
1636
+ "default": 100
1637
+ }
1638
+ }
1639
+ }
1640
+ ]
1641
+ },
1642
+ "setVariables": {
1643
+ "type": "array",
1644
+ "description": "Extract environment variables from the element's text.",
1645
+ "items": {
1646
+ "oneOf": [
1647
+ {
1648
+ "description": "",
1649
+ "type": "object",
1650
+ "properties": {
1651
+ "name": {
1652
+ "description": "Name of the environment variable to set.",
1653
+ "type": "string"
1654
+ },
1655
+ "regex": {
1656
+ "description": "Regex to extract the environment variable from the element's text.",
1657
+ "type": "string"
1658
+ }
1659
+ },
1660
+ "required": [
1661
+ "name",
1662
+ "regex"
1663
+ ]
1664
+ }
1665
+ ]
1666
+ },
1667
+ "default": []
1668
+ }
1669
+ },
1670
+ "required": [
1671
+ "action",
1672
+ "selector"
1673
+ ],
1674
+ "dynamicDefaults": {
1675
+ "id": "uuid"
1676
+ },
1677
+ "additionalProperties": false,
1678
+ "examples": [
1679
+ {
1680
+ "action": "find",
1681
+ "selector": "[title=Search]"
1682
+ },
1683
+ {
1684
+ "action": "find",
1685
+ "selector": "[title=Search]",
1686
+ "timeout": 10000,
1687
+ "matchText": "Search",
1688
+ "moveTo": true,
1689
+ "click": true,
1690
+ "typeKeys": "shorthair cat"
1691
+ },
1692
+ {
1693
+ "action": "find",
1694
+ "selector": "[title=Search]",
1695
+ "timeout": 10000,
1696
+ "matchText": "Search",
1697
+ "moveTo": true,
1698
+ "click": true,
1699
+ "typeKeys": {
1700
+ "keys": [
1701
+ "shorthair cat"
1702
+ ],
1703
+ "delay": 100
1704
+ }
1705
+ },
1706
+ {
1707
+ "action": "find",
1708
+ "selector": "[title=ResultsCount]",
1709
+ "setVariables": [
1710
+ {
1711
+ "name": "resultsCount",
1712
+ "regex": ".*"
1713
+ }
1714
+ ]
1715
+ }
1716
+ ]
1717
+ },
1718
+ {
1719
+ "title": "wait",
1720
+ "type": "object",
1721
+ "description": "Pause before performing the next action.",
1722
+ "properties": {
1723
+ "id": {
1724
+ "type": "string",
1725
+ "description": "ID of the step."
1726
+ },
1727
+ "description": {
1728
+ "type": "string",
1729
+ "description": "Description of the step."
1730
+ },
1731
+ "action": {
1732
+ "type": "string",
1733
+ "const": "wait",
1734
+ "description": "The action to perform."
1735
+ },
1736
+ "duration": {
1737
+ "type": "number",
1738
+ "description": "Milliseconds to wait.",
1739
+ "default": 5000
1740
+ }
1741
+ },
1742
+ "dynamicDefaults": {
1743
+ "id": "uuid"
1744
+ },
1745
+ "required": [
1746
+ "action"
1747
+ ],
1748
+ "additionalProperties": false,
1749
+ "examples": [
1750
+ {
1751
+ "action": "wait"
1752
+ },
1753
+ {
1754
+ "action": "wait",
1755
+ "duration": 5000
1756
+ }
1757
+ ]
1758
+ }
1759
+ ]
1760
+ }
1761
+ }
1762
+ },
1763
+ "dynamicDefaults": {
1764
+ "id": "uuid"
1765
+ },
1766
+ "required": [
1767
+ "steps"
1768
+ ],
1769
+ "additionalProperties": false,
1770
+ "examples": [
1771
+ {
1772
+ "steps": [
1773
+ {
1774
+ "action": "checkLink",
1775
+ "url": "https://www.duckduckgo.com"
1776
+ }
1777
+ ]
1778
+ },
1779
+ {
1780
+ "steps": [
1781
+ {
1782
+ "action": "goTo",
1783
+ "url": "https://www.duckduckgo.com"
1784
+ },
1785
+ {
1786
+ "action": "find",
1787
+ "selector": "[title=Search]",
1788
+ "click": true,
1789
+ "typeKeys": {
1790
+ "keys": [
1791
+ "shorthair cats",
1792
+ "$ENTER$"
1793
+ ]
1794
+ }
1795
+ }
1796
+ ]
1797
+ },
1798
+ {
1799
+ "id": "Do all the things! - Test",
1800
+ "description": "This test includes every property across all actions.",
1801
+ "contexts": [
1802
+ {
1803
+ "app": {
1804
+ "name": "firefox",
1805
+ "path": "/usr/bin/firefox"
1806
+ },
1807
+ "platforms": [
1808
+ "linux"
1809
+ ]
1810
+ }
1811
+ ],
1812
+ "setup": "setup.json",
1813
+ "cleanup": "cleanup.json",
1814
+ "steps": [
1815
+ {
1816
+ "action": "setVariables",
1817
+ "path": ".env"
1818
+ },
1819
+ {
1820
+ "action": "runShell",
1821
+ "command": "echo",
1822
+ "args": [
1823
+ "$USER"
1824
+ ]
1825
+ },
1826
+ {
1827
+ "action": "checkLink",
1828
+ "url": "https://www.duckduckgo.com"
1829
+ },
1830
+ {
1831
+ "action": "httpRequest",
1832
+ "url": "https://reqres.in/api/users",
1833
+ "method": "post",
1834
+ "requestData": {
1835
+ "name": "morpheus",
1836
+ "job": "leader"
1837
+ },
1838
+ "responseData": {
1839
+ "name": "morpheus",
1840
+ "job": "leader"
1841
+ },
1842
+ "statusCodes": [
1843
+ 200,
1844
+ 201
1845
+ ]
1846
+ },
1847
+ {
1848
+ "action": "goTo",
1849
+ "url": "https://www.duckduckgo.com"
1850
+ },
1851
+ {
1852
+ "action": "find",
1853
+ "selector": "[title=Search]",
1854
+ "timeout": 10000,
1855
+ "matchText": "Search",
1856
+ "moveTo": true,
1857
+ "click": true,
1858
+ "typeKeys": {
1859
+ "keys": [
1860
+ "shorthair cat"
1861
+ ]
1862
+ }
1863
+ },
1864
+ {
1865
+ "action": "typeKeys",
1866
+ "keys": [
1867
+ "$ENTER$"
1868
+ ]
1869
+ },
1870
+ {
1871
+ "action": "saveScreenshot"
1872
+ }
1873
+ ]
1874
+ },
1875
+ {
1876
+ "openApi": [
1877
+ {
1878
+ "name": "Acme",
1879
+ "descriptionPath": "https://www.acme.com/openapi.json",
1880
+ "server": "https://api.acme.com"
1881
+ }
1882
+ ],
1883
+ "steps": [
1884
+ {
1885
+ "action": "httpRequest",
1886
+ "openApi": {
1887
+ "operationId": "getUserById"
1888
+ },
1889
+ "requestParams": {
1890
+ "id": 123
1891
+ }
1892
+ }
1893
+ ]
1894
+ }
1895
+ ]
1896
+ }
1897
+ ]
1898
+ }
1899
+ }
1900
+ },
1901
+ "required": [
1902
+ "tests"
1903
+ ],
1904
+ "examples": [
1905
+ {
1906
+ "tests": [
1907
+ {
1908
+ "steps": [
1909
+ {
1910
+ "action": "checkLink",
1911
+ "url": "https://www.duckduckgo.com"
1912
+ }
1913
+ ]
1914
+ }
1915
+ ]
1916
+ },
1917
+ {
1918
+ "id": "Do all the things! - Spec",
1919
+ "contexts": [
1920
+ {
1921
+ "app": {
1922
+ "name": "chrome",
1923
+ "path": "/usr/bin/firefox"
1924
+ },
1925
+ "platforms": [
1926
+ "windows",
1927
+ "mac"
1928
+ ]
1929
+ }
1930
+ ],
1931
+ "tests": [
1932
+ {
1933
+ "id": "Do all the things! - Test",
1934
+ "description": "This test includes nearly every property across all actions.",
1935
+ "contexts": [
1936
+ {
1937
+ "app": {
1938
+ "name": "firefox",
1939
+ "path": "/usr/bin/firefox"
1940
+ },
1941
+ "platforms": [
1942
+ "linux"
1943
+ ]
1944
+ }
1945
+ ],
1946
+ "steps": [
1947
+ {
1948
+ "action": "setVariables",
1949
+ "path": ".env"
1950
+ },
1951
+ {
1952
+ "action": "runShell",
1953
+ "command": "echo",
1954
+ "args": [
1955
+ "$USER"
1956
+ ]
1957
+ },
1958
+ {
1959
+ "action": "checkLink",
1960
+ "url": "https://www.duckduckgo.com"
1961
+ },
1962
+ {
1963
+ "action": "httpRequest",
1964
+ "url": "https://reqres.in/api/users",
1965
+ "method": "post",
1966
+ "requestData": {
1967
+ "name": "morpheus",
1968
+ "job": "leader"
1969
+ },
1970
+ "responseData": {
1971
+ "name": "morpheus",
1972
+ "job": "leader"
1973
+ },
1974
+ "statusCodes": [
1975
+ 200,
1976
+ 201
1977
+ ]
1978
+ },
1979
+ {
1980
+ "action": "goTo",
1981
+ "url": "https://www.duckduckgo.com"
1982
+ },
1983
+ {
1984
+ "action": "find",
1985
+ "selector": "[title=Search]",
1986
+ "timeout": 10000,
1987
+ "matchText": "Search",
1988
+ "moveTo": true,
1989
+ "click": true,
1990
+ "typeKeys": {
1991
+ "keys": [
1992
+ "shorthair cat"
1993
+ ]
1994
+ }
1995
+ },
1996
+ {
1997
+ "action": "typeKeys",
1998
+ "keys": [
1999
+ "$ENTER$"
2000
+ ]
2001
+ },
2002
+ {
2003
+ "action": "saveScreenshot"
2004
+ }
2005
+ ]
2006
+ }
2007
+ ]
2008
+ },
2009
+ {
2010
+ "id": "Make a request from an OpenAPI definition",
2011
+ "openApi": [
2012
+ {
2013
+ "name": "Acme",
2014
+ "descriptionPath": "https://www.acme.com/openapi.json",
2015
+ "server": "https://api.acme.com"
2016
+ }
2017
+ ],
2018
+ "tests": [
2019
+ {
2020
+ "steps": [
2021
+ {
2022
+ "action": "httpRequest",
2023
+ "openApi": {
2024
+ "operationId": "getUserById"
2025
+ },
2026
+ "requestParams": {
2027
+ "id": 123
2028
+ }
2029
+ }
2030
+ ]
2031
+ }
2032
+ ]
2033
+ }
2034
+ ]
1798
2035
  }