mmt-mcp 1.42.4 → 1.43.0-pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/examples/README.md +1 -1
- package/dist/examples/examples-index.json +178 -4
- package/dist/examples/intermediate/12_dynamic_values/README.md +89 -0
- package/dist/examples/intermediate/12_dynamic_values/api/current.mmt +29 -0
- package/dist/examples/intermediate/12_dynamic_values/api/random_identity.mmt +29 -0
- package/dist/examples/intermediate/12_dynamic_values/api/random_network.mmt +21 -0
- package/dist/examples/intermediate/12_dynamic_values/api/random_time.mmt +27 -0
- package/dist/examples/intermediate/12_dynamic_values/api/random_types.mmt +25 -0
- package/dist/examples/intermediate/12_dynamic_values/current_test.mmt +22 -0
- package/dist/examples/intermediate/12_dynamic_values/random_identity_test.mmt +20 -0
- package/dist/examples/intermediate/12_dynamic_values/random_network_test.mmt +16 -0
- package/dist/examples/intermediate/12_dynamic_values/random_time_test.mmt +24 -0
- package/dist/examples/intermediate/12_dynamic_values/random_types_test.mmt +21 -0
- package/dist/examples/intermediate/12_dynamic_values/suite.mmt +9 -0
- package/dist/examples/intermediate/13_stages_and_conditions/stages_test.mmt +1 -1
- package/dist/examples/intermediate/23_check_operators/README.md +2 -1
- package/dist/examples/intermediate/23_check_operators/api/sample.mmt +14 -0
- package/dist/examples/intermediate/23_check_operators/operators_test.mmt +22 -0
- package/dist/examples/intermediate/24_test_call_cache/create_session.mmt +1 -1
- package/dist/examples/intermediate/28_http_body_formats/README.md +57 -0
- package/dist/examples/intermediate/28_http_body_formats/body_formats_test.mmt +63 -0
- package/dist/examples/intermediate/28_http_body_formats/post_binary.mmt +10 -0
- package/dist/examples/intermediate/28_http_body_formats/post_json.mmt +13 -0
- package/dist/examples/intermediate/28_http_body_formats/post_multipart.mmt +16 -0
- package/dist/examples/intermediate/28_http_body_formats/post_text.mmt +12 -0
- package/dist/examples/intermediate/28_http_body_formats/post_urlencoded.mmt +16 -0
- package/dist/examples/intermediate/28_http_body_formats/post_xml.mmt +15 -0
- package/dist/examples/intermediate/28_http_body_formats/post_xmle.mmt +16 -0
- package/dist/examples/intermediate/29_suite_tag_filter/README.md +56 -0
- package/dist/examples/intermediate/29_suite_tag_filter/nested/auth.mmt +8 -0
- package/dist/examples/intermediate/29_suite_tag_filter/nested/login.mmt +11 -0
- package/dist/examples/intermediate/29_suite_tag_filter/nested/profile.mmt +9 -0
- package/dist/examples/intermediate/29_suite_tag_filter/suite.mmt +11 -0
- package/dist/examples/intermediate/29_suite_tag_filter/suite_ci.mmt +17 -0
- package/dist/examples/intermediate/29_suite_tag_filter/suite_smoke.mmt +14 -0
- package/dist/examples/intermediate/29_suite_tag_filter/tests/api_echo.mmt +14 -0
- package/dist/examples/intermediate/29_suite_tag_filter/tests/flaky_echo.mmt +14 -0
- package/dist/examples/intermediate/29_suite_tag_filter/tests/slow_status.mmt +11 -0
- package/dist/examples/intermediate/29_suite_tag_filter/tests/smoke_get.mmt +12 -0
- package/dist/examples/intermediate/29_suite_tag_filter/tests/smoke_post.mmt +14 -0
- package/dist/examples/intermediate/29_suite_tag_filter/tests/untagged.mmt +9 -0
- package/dist/examples/professional/09_ci_pipelines/README.md +1 -1
- package/dist/guides/generate-suite.md +21 -2
- package/dist/guides/generate-test.md +2 -1
- package/dist/guides/min/suite.md +1 -1
- package/dist/server.cjs +2626 -728
- package/dist/server.js +2626 -728
- package/package.json +1 -1
- package/dist/examples/intermediate/12_random_values/README.md +0 -59
- package/dist/examples/intermediate/12_random_values/api/random_echo.mmt +0 -21
- package/dist/examples/intermediate/12_random_values/random_values_test.mmt +0 -15
package/dist/examples/README.md
CHANGED
|
@@ -12,7 +12,7 @@ The examples are grouped by complexity so new users can start simple and add pow
|
|
|
12
12
|
|
|
13
13
|
## Intermediate
|
|
14
14
|
|
|
15
|
-
Use these when you are ready for reusable APIs, authentication, mock servers, richer environment variables, inputs and outputs, suites, imports, data-driven tests, environment presets, documentation options/ranges, control flow, comparison operators (`expect` / `check` / `assert`), helper JavaScript, additional protocol or file formats, converting a small OpenAPI / Postman / WSDL / HTTP / Bruno file to `.mmt`, and the `omit` keyword.
|
|
15
|
+
Use these when you are ready for reusable APIs, authentication, mock servers, richer environment variables, inputs and outputs, suites, tag filters (`filter.only` / `filter.skip`), imports, data-driven tests, environment presets, documentation options/ranges, control flow, comparison operators (`expect` / `check` / `assert`), helper JavaScript, additional protocol or file formats, converting a small OpenAPI / Postman / WSDL / HTTP / Bruno file to `.mmt`, and the `omit` keyword.
|
|
16
16
|
|
|
17
17
|
## Professional
|
|
18
18
|
|
|
@@ -333,16 +333,70 @@
|
|
|
333
333
|
"title": "Control Flow — repeat and delay"
|
|
334
334
|
},
|
|
335
335
|
{
|
|
336
|
-
"path": "intermediate/
|
|
336
|
+
"path": "intermediate/12_dynamic_values/api/current.mmt",
|
|
337
337
|
"type": "api",
|
|
338
338
|
"category": "intermediate",
|
|
339
|
-
"title": "
|
|
339
|
+
"title": "Current values"
|
|
340
340
|
},
|
|
341
341
|
{
|
|
342
|
-
"path": "intermediate/
|
|
342
|
+
"path": "intermediate/12_dynamic_values/api/random_identity.mmt",
|
|
343
|
+
"type": "api",
|
|
344
|
+
"category": "intermediate",
|
|
345
|
+
"title": "Random identity"
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"path": "intermediate/12_dynamic_values/api/random_network.mmt",
|
|
349
|
+
"type": "api",
|
|
350
|
+
"category": "intermediate",
|
|
351
|
+
"title": "Random network"
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
"path": "intermediate/12_dynamic_values/api/random_time.mmt",
|
|
355
|
+
"type": "api",
|
|
356
|
+
"category": "intermediate",
|
|
357
|
+
"title": "Random time"
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
"path": "intermediate/12_dynamic_values/api/random_types.mmt",
|
|
361
|
+
"type": "api",
|
|
362
|
+
"category": "intermediate",
|
|
363
|
+
"title": "Random types"
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"path": "intermediate/12_dynamic_values/current_test.mmt",
|
|
367
|
+
"type": "test",
|
|
368
|
+
"category": "intermediate",
|
|
369
|
+
"title": "Current values"
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
"path": "intermediate/12_dynamic_values/random_identity_test.mmt",
|
|
373
|
+
"type": "test",
|
|
374
|
+
"category": "intermediate",
|
|
375
|
+
"title": "Random identity"
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"path": "intermediate/12_dynamic_values/random_network_test.mmt",
|
|
379
|
+
"type": "test",
|
|
380
|
+
"category": "intermediate",
|
|
381
|
+
"title": "Random network"
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
"path": "intermediate/12_dynamic_values/random_time_test.mmt",
|
|
385
|
+
"type": "test",
|
|
386
|
+
"category": "intermediate",
|
|
387
|
+
"title": "Random time"
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"path": "intermediate/12_dynamic_values/random_types_test.mmt",
|
|
343
391
|
"type": "test",
|
|
344
392
|
"category": "intermediate",
|
|
345
|
-
"title": "Random
|
|
393
|
+
"title": "Random types"
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"path": "intermediate/12_dynamic_values/suite.mmt",
|
|
397
|
+
"type": "suite",
|
|
398
|
+
"category": "intermediate",
|
|
399
|
+
"title": "Dynamic values"
|
|
346
400
|
},
|
|
347
401
|
{
|
|
348
402
|
"path": "intermediate/13_stages_and_conditions/api/get_profile.mmt",
|
|
@@ -613,6 +667,126 @@
|
|
|
613
667
|
"category": "intermediate",
|
|
614
668
|
"title": "Local quality judge"
|
|
615
669
|
},
|
|
670
|
+
{
|
|
671
|
+
"path": "intermediate/28_http_body_formats/body_formats_test.mmt",
|
|
672
|
+
"type": "test",
|
|
673
|
+
"category": "intermediate",
|
|
674
|
+
"title": "HTTP body formats"
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
"path": "intermediate/28_http_body_formats/post_binary.mmt",
|
|
678
|
+
"type": "api",
|
|
679
|
+
"category": "intermediate",
|
|
680
|
+
"title": "POST binary body"
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
"path": "intermediate/28_http_body_formats/post_json.mmt",
|
|
684
|
+
"type": "api",
|
|
685
|
+
"category": "intermediate",
|
|
686
|
+
"title": "POST JSON body"
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
"path": "intermediate/28_http_body_formats/post_multipart.mmt",
|
|
690
|
+
"type": "api",
|
|
691
|
+
"category": "intermediate",
|
|
692
|
+
"title": "POST multipart body"
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
"path": "intermediate/28_http_body_formats/post_text.mmt",
|
|
696
|
+
"type": "api",
|
|
697
|
+
"category": "intermediate",
|
|
698
|
+
"title": "POST text body"
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
"path": "intermediate/28_http_body_formats/post_urlencoded.mmt",
|
|
702
|
+
"type": "api",
|
|
703
|
+
"category": "intermediate",
|
|
704
|
+
"title": "POST urlencoded body"
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
"path": "intermediate/28_http_body_formats/post_xml.mmt",
|
|
708
|
+
"type": "api",
|
|
709
|
+
"category": "intermediate",
|
|
710
|
+
"title": "POST XML body"
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
"path": "intermediate/28_http_body_formats/post_xmle.mmt",
|
|
714
|
+
"type": "api",
|
|
715
|
+
"category": "intermediate",
|
|
716
|
+
"title": "POST expanded XML body"
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
"path": "intermediate/29_suite_tag_filter/nested/auth.mmt",
|
|
720
|
+
"type": "suite",
|
|
721
|
+
"category": "intermediate",
|
|
722
|
+
"title": "Nested auth"
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
"path": "intermediate/29_suite_tag_filter/nested/login.mmt",
|
|
726
|
+
"type": "test",
|
|
727
|
+
"category": "intermediate",
|
|
728
|
+
"title": "Nested login"
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
"path": "intermediate/29_suite_tag_filter/nested/profile.mmt",
|
|
732
|
+
"type": "test",
|
|
733
|
+
"category": "intermediate",
|
|
734
|
+
"title": "Nested profile"
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
"path": "intermediate/29_suite_tag_filter/suite_ci.mmt",
|
|
738
|
+
"type": "suite",
|
|
739
|
+
"category": "intermediate",
|
|
740
|
+
"title": "Suite tag filter — CI"
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
"path": "intermediate/29_suite_tag_filter/suite_smoke.mmt",
|
|
744
|
+
"type": "suite",
|
|
745
|
+
"category": "intermediate",
|
|
746
|
+
"title": "Suite tag filter — smoke"
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
"path": "intermediate/29_suite_tag_filter/suite.mmt",
|
|
750
|
+
"type": "suite",
|
|
751
|
+
"category": "intermediate",
|
|
752
|
+
"title": "Suite tag filter — all"
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
"path": "intermediate/29_suite_tag_filter/tests/api_echo.mmt",
|
|
756
|
+
"type": "test",
|
|
757
|
+
"category": "intermediate",
|
|
758
|
+
"title": "API echo"
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
"path": "intermediate/29_suite_tag_filter/tests/flaky_echo.mmt",
|
|
762
|
+
"type": "test",
|
|
763
|
+
"category": "intermediate",
|
|
764
|
+
"title": "Flaky echo"
|
|
765
|
+
},
|
|
766
|
+
{
|
|
767
|
+
"path": "intermediate/29_suite_tag_filter/tests/slow_status.mmt",
|
|
768
|
+
"type": "test",
|
|
769
|
+
"category": "intermediate",
|
|
770
|
+
"title": "Slow status"
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
"path": "intermediate/29_suite_tag_filter/tests/smoke_get.mmt",
|
|
774
|
+
"type": "test",
|
|
775
|
+
"category": "intermediate",
|
|
776
|
+
"title": "Smoke GET"
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
"path": "intermediate/29_suite_tag_filter/tests/smoke_post.mmt",
|
|
780
|
+
"type": "test",
|
|
781
|
+
"category": "intermediate",
|
|
782
|
+
"title": "Smoke POST"
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
"path": "intermediate/29_suite_tag_filter/tests/untagged.mmt",
|
|
786
|
+
"type": "test",
|
|
787
|
+
"category": "intermediate",
|
|
788
|
+
"title": "Untagged"
|
|
789
|
+
},
|
|
616
790
|
{
|
|
617
791
|
"path": "professional/01_report_generation/api/echo.mmt",
|
|
618
792
|
"type": "api",
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Dynamic Values
|
|
2
|
+
|
|
3
|
+
Demonstrates built-in `r:` (random) and `c:` (current) tokens in YAML files. These tokens resolve at runtime without a `js` step.
|
|
4
|
+
|
|
5
|
+
Random tokens are split by kind. Current tokens live in their own test. Nearby random/current timestamps are checked with `=5s~`.
|
|
6
|
+
|
|
7
|
+
## Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
12_dynamic_values/
|
|
11
|
+
├── api/
|
|
12
|
+
│ ├── random_types.mmt # Primitive and identifier r: tokens
|
|
13
|
+
│ ├── random_network.mmt # Network r: tokens
|
|
14
|
+
│ ├── random_identity.mmt # People, place, business, and text r: tokens
|
|
15
|
+
│ ├── random_time.mmt # Calendar and epoch r: tokens plus current times
|
|
16
|
+
│ └── current.mmt # c: clock and locale tokens
|
|
17
|
+
├── random_types_test.mmt
|
|
18
|
+
├── random_network_test.mmt
|
|
19
|
+
├── random_identity_test.mmt
|
|
20
|
+
├── random_time_test.mmt
|
|
21
|
+
├── current_test.mmt
|
|
22
|
+
├── suite.mmt
|
|
23
|
+
└── README.md
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Files
|
|
27
|
+
|
|
28
|
+
| File | Description |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `api/random_types.mmt` | `r:uuid`, `r:int`, `r:bool`, `r:float`, `r:alphanumeric`, `r:password` |
|
|
31
|
+
| `api/random_network.mmt` | `r:domain`, `r:url`, `r:mac`, `r:ip`, `r:hostname`, `r:user_agent` |
|
|
32
|
+
| `api/random_identity.mmt` | `r:email`, names, address, company, and text tokens |
|
|
33
|
+
| `api/random_time.mmt` | Ranged and near-now datetimes/epochs, plus `c:` times for proximity |
|
|
34
|
+
| `api/current.mmt` | `c:utc_datetime`, offsets such as `(+2s)` / `(+1h)`, date, time, epoch, timezone |
|
|
35
|
+
| `*_test.mmt` | Calls the matching API and validates the echoed values |
|
|
36
|
+
| `suite.mmt` | Runs every dynamic-values test together |
|
|
37
|
+
|
|
38
|
+
## Example tokens
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
body:
|
|
42
|
+
id: r:uuid
|
|
43
|
+
lucky_number: r:int(10,20)
|
|
44
|
+
email: r:email
|
|
45
|
+
random_url: r:url
|
|
46
|
+
datetime_near_now: r:utc_datetime_now(2s)
|
|
47
|
+
created_utc: c:utc_datetime
|
|
48
|
+
created_utc_plus_2s: c:utc_datetime(+2s)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
- check: ${result.datetime_near_now} =5s~ ${result.created_utc}
|
|
53
|
+
- check: ${result.created_utc} !5s~ ${result.created_utc_plus_1h}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Key concepts
|
|
57
|
+
|
|
58
|
+
- **Standalone tokens** keep their native type. For example, `r:int` becomes a number and `r:bool` becomes a boolean.
|
|
59
|
+
- **Embedded tokens** must use `<< >>`. In this example, `req-<<r:uuid>>` generates a string with a random suffix.
|
|
60
|
+
- **Parameterized generators** use parentheses for lengths and ranges, such as `r:int(10,20)` and `r:alphanumeric(12)`.
|
|
61
|
+
- **Local vs UTC** — `r:datetime` / `c:datetime` use local time; `r:utc_datetime` / `c:utc_datetime` use UTC and end in `Z`.
|
|
62
|
+
- **Ranges around now** accept combined durations such as `2s` or `1h1m`.
|
|
63
|
+
- **Current offsets** use a signed duration: `c:utc_datetime(+2s)`, `c:date(+7d)`.
|
|
64
|
+
- **Time comparison** — `=5s~` / `!5s~` check that two times differ by at most (or more than) the velocity. A duration is required; bare `=~` is the deprecated as-string operator.
|
|
65
|
+
- **No JS required** — tokens can be used directly in API `body`, `headers`, `query`, `cookies`, `url`, and input defaults.
|
|
66
|
+
|
|
67
|
+
## How to use
|
|
68
|
+
|
|
69
|
+
### In VS Code
|
|
70
|
+
|
|
71
|
+
1. Open any `*_test.mmt` file, or `suite.mmt` to run them all.
|
|
72
|
+
2. Click **Run**.
|
|
73
|
+
3. Inspect the response to see generated values change on each run.
|
|
74
|
+
|
|
75
|
+
### With the CLI
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
npx testlight run examples/intermediate/12_dynamic_values/random_types_test.mmt
|
|
79
|
+
npx testlight run examples/intermediate/12_dynamic_values/random_time_test.mmt
|
|
80
|
+
npx testlight run examples/intermediate/12_dynamic_values/current_test.mmt
|
|
81
|
+
npx testlight run examples/intermediate/12_dynamic_values/suite.mmt
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Next steps
|
|
85
|
+
|
|
86
|
+
- See [Check operators](../23_check_operators/) for a fixed-payload `=5s~` / `!5s~` example.
|
|
87
|
+
- See [Simple Mock Server](../18_simple_mock_server/) for random tokens in mock server responses.
|
|
88
|
+
- See [JavaScript Helpers](../14_javascript_helpers/) for the JavaScript `Random.*` helpers.
|
|
89
|
+
- See [Dynamic values](../../../docs/features/dynamic-values/index.md) for the full token list.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
type: api
|
|
2
|
+
title: Current values
|
|
3
|
+
description: "Sends c: clock and locale tokens, including offsets, and extracts the echoed values"
|
|
4
|
+
outputs:
|
|
5
|
+
created_utc: body.body.created_utc
|
|
6
|
+
created_utc_plus_2s: body.body.created_utc_plus_2s
|
|
7
|
+
created_utc_plus_1h: body.body.created_utc_plus_1h
|
|
8
|
+
created_local: body.body.created_local
|
|
9
|
+
created_date: body.body.created_date
|
|
10
|
+
created_time: body.body.created_time
|
|
11
|
+
created_epoch: body.body.created_epoch
|
|
12
|
+
timezone: body.body.timezone
|
|
13
|
+
utc_offset: body.body.utc_offset
|
|
14
|
+
year: body.body.year
|
|
15
|
+
request_method: body.method
|
|
16
|
+
url: https://test.mmt.dev/echo
|
|
17
|
+
method: post
|
|
18
|
+
format: json
|
|
19
|
+
body:
|
|
20
|
+
created_utc: c:utc_datetime
|
|
21
|
+
created_utc_plus_2s: c:utc_datetime(+2s)
|
|
22
|
+
created_utc_plus_1h: c:utc_datetime(+1h)
|
|
23
|
+
created_local: c:datetime
|
|
24
|
+
created_date: c:date
|
|
25
|
+
created_time: c:time
|
|
26
|
+
created_epoch: c:epoch
|
|
27
|
+
timezone: c:timezone
|
|
28
|
+
utc_offset: c:utc_offset
|
|
29
|
+
year: c:year
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
type: api
|
|
2
|
+
title: Random identity
|
|
3
|
+
description: "Sends people, place, business, and text r: tokens and extracts the echoed values"
|
|
4
|
+
outputs:
|
|
5
|
+
email: body.body.email
|
|
6
|
+
name: body.body.name
|
|
7
|
+
username: body.body.username
|
|
8
|
+
company: body.body.company
|
|
9
|
+
job_title: body.body.job_title
|
|
10
|
+
postal_code: body.body.postal_code
|
|
11
|
+
street_address: body.body.street_address
|
|
12
|
+
random_word: body.body.random_word
|
|
13
|
+
random_sentence: body.body.random_sentence
|
|
14
|
+
random_paragraph: body.body.random_paragraph
|
|
15
|
+
request_method: body.method
|
|
16
|
+
url: https://test.mmt.dev/echo
|
|
17
|
+
method: post
|
|
18
|
+
format: json
|
|
19
|
+
body:
|
|
20
|
+
email: r:email
|
|
21
|
+
name: r:first_name
|
|
22
|
+
username: r:username
|
|
23
|
+
company: r:company
|
|
24
|
+
job_title: r:job_title
|
|
25
|
+
postal_code: r:postal_code
|
|
26
|
+
street_address: r:street_address
|
|
27
|
+
random_word: r:word
|
|
28
|
+
random_sentence: r:sentence
|
|
29
|
+
random_paragraph: r:paragraph
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type: api
|
|
2
|
+
title: Random network
|
|
3
|
+
description: "Sends network r: tokens and extracts the echoed values"
|
|
4
|
+
outputs:
|
|
5
|
+
domain: body.body.domain
|
|
6
|
+
random_url: body.body.random_url
|
|
7
|
+
mac: body.body.mac
|
|
8
|
+
user_agent: body.body.user_agent
|
|
9
|
+
ip: body.body.ip
|
|
10
|
+
hostname: body.body.hostname
|
|
11
|
+
request_method: body.method
|
|
12
|
+
url: https://test.mmt.dev/echo
|
|
13
|
+
method: post
|
|
14
|
+
format: json
|
|
15
|
+
body:
|
|
16
|
+
domain: r:domain
|
|
17
|
+
random_url: r:url
|
|
18
|
+
mac: r:mac
|
|
19
|
+
user_agent: r:user_agent
|
|
20
|
+
ip: r:ip
|
|
21
|
+
hostname: r:hostname
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
type: api
|
|
2
|
+
title: Random time
|
|
3
|
+
description: "Sends calendar and epoch r: tokens plus a current timestamp for proximity checks"
|
|
4
|
+
outputs:
|
|
5
|
+
random_datetime: body.body.random_datetime
|
|
6
|
+
random_utc_datetime: body.body.random_utc_datetime
|
|
7
|
+
datetime_near_now: body.body.datetime_near_now
|
|
8
|
+
utc_datetime_near_now: body.body.utc_datetime_near_now
|
|
9
|
+
ranged_epoch: body.body.ranged_epoch
|
|
10
|
+
epoch_near_now: body.body.epoch_near_now
|
|
11
|
+
current_utc: body.body.current_utc
|
|
12
|
+
current_local: body.body.current_local
|
|
13
|
+
current_epoch: body.body.current_epoch
|
|
14
|
+
request_method: body.method
|
|
15
|
+
url: https://test.mmt.dev/echo
|
|
16
|
+
method: post
|
|
17
|
+
format: json
|
|
18
|
+
body:
|
|
19
|
+
random_datetime: r:datetime(2026-01-01,2026-12-31)
|
|
20
|
+
random_utc_datetime: r:utc_datetime(2026-01-01T00:00:00Z,2026-12-31T23:59:59Z)
|
|
21
|
+
datetime_near_now: r:datetime_now(2s)
|
|
22
|
+
utc_datetime_near_now: r:utc_datetime_now(2s)
|
|
23
|
+
ranged_epoch: r:epoch(1700000000,1800000000)
|
|
24
|
+
epoch_near_now: r:epoch_now(2s)
|
|
25
|
+
current_utc: c:utc_datetime
|
|
26
|
+
current_local: c:datetime
|
|
27
|
+
current_epoch: c:epoch
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type: api
|
|
2
|
+
title: Random types
|
|
3
|
+
description: "Sends primitive and identifier r: tokens and extracts the echoed values"
|
|
4
|
+
outputs:
|
|
5
|
+
id: body.body.id
|
|
6
|
+
lucky_number: body.body.lucky_number
|
|
7
|
+
active: body.body.active
|
|
8
|
+
request_id: body.body.request_id
|
|
9
|
+
bounded_int: body.body.bounded_int
|
|
10
|
+
random_float: body.body.random_float
|
|
11
|
+
short_code: body.body.short_code
|
|
12
|
+
password: body.body.password
|
|
13
|
+
request_method: body.method
|
|
14
|
+
url: https://test.mmt.dev/echo
|
|
15
|
+
method: post
|
|
16
|
+
format: json
|
|
17
|
+
body:
|
|
18
|
+
id: r:uuid
|
|
19
|
+
lucky_number: r:int
|
|
20
|
+
active: r:bool
|
|
21
|
+
request_id: req-<<r:uuid>>
|
|
22
|
+
bounded_int: r:int(10,20)
|
|
23
|
+
random_float: r:float(0,1)
|
|
24
|
+
short_code: r:alphanumeric(12)
|
|
25
|
+
password: r:password(20)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type: test
|
|
2
|
+
title: Current values
|
|
3
|
+
description: "Calls an API that uses c: tokens and checks nearby times with =5s~"
|
|
4
|
+
import:
|
|
5
|
+
currentValues: ./api/current.mmt
|
|
6
|
+
steps:
|
|
7
|
+
- call: currentValues
|
|
8
|
+
id: result
|
|
9
|
+
expect:
|
|
10
|
+
request_method: POST
|
|
11
|
+
created_utc: =$ Z
|
|
12
|
+
created_utc_plus_2s: =$ Z
|
|
13
|
+
created_utc_plus_1h: =$ Z
|
|
14
|
+
created_local: != null
|
|
15
|
+
created_date: =^ 20
|
|
16
|
+
created_time: '=* ^[0-9]{2}:[0-9]{2}:[0-9]{2}$'
|
|
17
|
+
created_epoch: != null
|
|
18
|
+
timezone: != null
|
|
19
|
+
utc_offset: != null
|
|
20
|
+
year: >= 2026
|
|
21
|
+
- check: ${result.created_utc} =5s~ ${result.created_utc_plus_2s}
|
|
22
|
+
- check: ${result.created_utc} !5s~ ${result.created_utc_plus_1h}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type: test
|
|
2
|
+
title: Random identity
|
|
3
|
+
description: "Calls an API that uses people, place, business, and text r: tokens"
|
|
4
|
+
import:
|
|
5
|
+
randomIdentity: ./api/random_identity.mmt
|
|
6
|
+
steps:
|
|
7
|
+
- call: randomIdentity
|
|
8
|
+
id: result
|
|
9
|
+
expect:
|
|
10
|
+
request_method: POST
|
|
11
|
+
email: =C @
|
|
12
|
+
name: != null
|
|
13
|
+
username: =C .
|
|
14
|
+
company: != null
|
|
15
|
+
job_title: != null
|
|
16
|
+
postal_code: =* ^[0-9]{5}$
|
|
17
|
+
street_address: =$ Street
|
|
18
|
+
random_word: != null
|
|
19
|
+
random_sentence: =$ .
|
|
20
|
+
random_paragraph: =C .
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type: test
|
|
2
|
+
title: Random network
|
|
3
|
+
description: "Calls an API that uses network r: tokens"
|
|
4
|
+
import:
|
|
5
|
+
randomNetwork: ./api/random_network.mmt
|
|
6
|
+
steps:
|
|
7
|
+
- call: randomNetwork
|
|
8
|
+
id: result
|
|
9
|
+
expect:
|
|
10
|
+
request_method: POST
|
|
11
|
+
domain: =C .
|
|
12
|
+
random_url: =^ https://
|
|
13
|
+
mac: =* ^([0-9a-f]{2}:){5}[0-9a-f]{2}$
|
|
14
|
+
user_agent: != null
|
|
15
|
+
ip: '=* ^[0-9]{1,3}(.[0-9]{1,3}){3}$'
|
|
16
|
+
hostname: =C .
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type: test
|
|
2
|
+
title: Random time
|
|
3
|
+
description: "Calls an API that uses calendar and epoch r: tokens and checks times with =5s~"
|
|
4
|
+
import:
|
|
5
|
+
randomTime: ./api/random_time.mmt
|
|
6
|
+
steps:
|
|
7
|
+
- call: randomTime
|
|
8
|
+
id: result
|
|
9
|
+
expect:
|
|
10
|
+
request_method: POST
|
|
11
|
+
random_datetime: =^ 2026-
|
|
12
|
+
random_utc_datetime:
|
|
13
|
+
- =^ 2026-
|
|
14
|
+
- =$ Z
|
|
15
|
+
datetime_near_now: != null
|
|
16
|
+
utc_datetime_near_now: =$ Z
|
|
17
|
+
ranged_epoch:
|
|
18
|
+
- >= 1700000000
|
|
19
|
+
- <= 1800000000
|
|
20
|
+
epoch_near_now: != null
|
|
21
|
+
current_utc: =$ Z
|
|
22
|
+
- check: ${result.utc_datetime_near_now} =5s~ ${result.current_utc}
|
|
23
|
+
- check: ${result.datetime_near_now} =5s~ ${result.current_local}
|
|
24
|
+
- check: ${result.epoch_near_now} =5s~ ${result.current_epoch}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type: test
|
|
2
|
+
title: Random types
|
|
3
|
+
description: "Calls an API that uses primitive and identifier r: tokens"
|
|
4
|
+
import:
|
|
5
|
+
randomTypes: ./api/random_types.mmt
|
|
6
|
+
steps:
|
|
7
|
+
- call: randomTypes
|
|
8
|
+
id: result
|
|
9
|
+
expect:
|
|
10
|
+
request_method: POST
|
|
11
|
+
id: != null
|
|
12
|
+
lucky_number: != null
|
|
13
|
+
request_id: =^ req-
|
|
14
|
+
bounded_int:
|
|
15
|
+
- >= 10
|
|
16
|
+
- <= 20
|
|
17
|
+
random_float:
|
|
18
|
+
- >= 0
|
|
19
|
+
- <= 1
|
|
20
|
+
short_code: =# 12
|
|
21
|
+
password: =# 20
|
|
@@ -7,7 +7,7 @@ Intermediate example that exercises every comparison operator against a live ech
|
|
|
7
7
|
| File | Description |
|
|
8
8
|
|---|---|
|
|
9
9
|
| `api/sample.mmt` | POST echo API with a fixed JSON body and named outputs |
|
|
10
|
-
| `operators_test.mmt` | Test covering numeric, string, membership, regex, length, and
|
|
10
|
+
| `operators_test.mmt` | Test covering numeric, string, membership, regex, length, fuzzy, and time operators |
|
|
11
11
|
|
|
12
12
|
## How to use
|
|
13
13
|
|
|
@@ -28,4 +28,5 @@ npx testlight run examples/intermediate/23_check_operators/operators_test.mmt
|
|
|
28
28
|
- **`check`** — log failures and continue.
|
|
29
29
|
- **`assert`** — stop the flow on failure.
|
|
30
30
|
- **Fuzzy operators** — `>N%` (at least N% similar) and `<N%` (less than N% similar); UI forms are `>%` / `<%` with a percent selector.
|
|
31
|
+
- **Time operators** — `=5s~` / `!5s~` compare ISO datetimes, epoch values, or quoted `HH:mm[:ss]` times within a velocity. A duration is required. Compare two outputs (`${res.created_at} =5s~ ${res.updated_at}`), a literal (`=5s~ 2026-09-18T12:00:02Z`), or a current token (`=5s~ c:utc_datetime`). Quote operators that start with `!` (for example `"!5s~"`).
|
|
31
32
|
- **YAML quoting** — operators that start with `>` (including `>80%` and `>%`) must be quoted in YAML.
|
|
@@ -11,6 +11,13 @@ outputs:
|
|
|
11
11
|
tags: body.body.tags
|
|
12
12
|
message: body.body.message
|
|
13
13
|
path: body.body.path
|
|
14
|
+
created_at: body.body.created_at
|
|
15
|
+
updated_at: body.body.updated_at
|
|
16
|
+
expired_at: body.body.expired_at
|
|
17
|
+
opened_at: body.body.opened_at
|
|
18
|
+
closed_at: body.body.closed_at
|
|
19
|
+
sent_at: body.body.sent_at
|
|
20
|
+
sent_epoch: body.body.sent_epoch
|
|
14
21
|
url: https://test.mmt.dev/echo
|
|
15
22
|
method: post
|
|
16
23
|
format: json
|
|
@@ -25,3 +32,10 @@ body:
|
|
|
25
32
|
- demo
|
|
26
33
|
message: Hello world from Multimeter
|
|
27
34
|
path: /api/v1/users
|
|
35
|
+
created_at: "2026-09-18T12:00:00Z"
|
|
36
|
+
updated_at: "2026-09-18T12:00:02Z"
|
|
37
|
+
expired_at: "2026-09-18T13:00:00Z"
|
|
38
|
+
opened_at: "14:30:00"
|
|
39
|
+
closed_at: "14:30:03"
|
|
40
|
+
sent_at: c:utc_datetime
|
|
41
|
+
sent_epoch: c:epoch
|
|
@@ -20,6 +20,10 @@ steps:
|
|
|
20
20
|
path: =* /users/
|
|
21
21
|
message: >60% Hello world from MMT
|
|
22
22
|
tags: =# 3
|
|
23
|
+
created_at: =5s~ 2026-09-18T12:00:02Z
|
|
24
|
+
updated_at: "!5s~ 2026-09-18T13:00:00Z"
|
|
25
|
+
sent_at: =5s~ c:utc_datetime
|
|
26
|
+
sent_epoch: =5s~ c:epoch
|
|
23
27
|
- assert: ${res.status_code} == 200
|
|
24
28
|
- assert: ${res.score} != 0
|
|
25
29
|
- assert: ${res.role} !@ guest,user
|
|
@@ -30,6 +34,9 @@ steps:
|
|
|
30
34
|
- check: ${res.path} !$ /admin
|
|
31
35
|
- check: ${res.message} !* /error/i
|
|
32
36
|
- check: ${res.tags} !# 0
|
|
37
|
+
- check: ${res.created_at} =5s~ ${res.updated_at}
|
|
38
|
+
- check: ${res.created_at} !5s~ ${res.expired_at}
|
|
39
|
+
- check: ${res.opened_at} =5s~ ${res.closed_at}
|
|
33
40
|
- check: ${res.role} =@ admin
|
|
34
41
|
- check: ${res.name} <40% completely-different
|
|
35
42
|
- check:
|
|
@@ -42,6 +49,21 @@ steps:
|
|
|
42
49
|
actual: ${res.message}
|
|
43
50
|
operator: <50%
|
|
44
51
|
expected: Hi Universe
|
|
52
|
+
- check:
|
|
53
|
+
title: Times within 5s
|
|
54
|
+
actual: ${res.created_at}
|
|
55
|
+
operator: =5s~
|
|
56
|
+
expected: ${res.updated_at}
|
|
57
|
+
- check:
|
|
58
|
+
title: Times not within 5s
|
|
59
|
+
actual: ${res.created_at}
|
|
60
|
+
operator: "!5s~"
|
|
61
|
+
expected: ${res.expired_at}
|
|
62
|
+
- check:
|
|
63
|
+
title: Sent just now
|
|
64
|
+
actual: ${res.sent_at}
|
|
65
|
+
operator: =5s~
|
|
66
|
+
expected: c:utc_datetime
|
|
45
67
|
- check:
|
|
46
68
|
title: Path starts with /api/
|
|
47
69
|
actual: ${res.path}
|