testflow-ai 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -234,9 +234,8 @@ my-api/
234
234
  │ ├── index.ts # Test runner
235
235
  │ ├── context.md # API context
236
236
  │ └── flows/
237
- │ ├── health-check.yaml
238
237
  │ ├── todo-crud.yaml
239
- │ └── todo-complete-flow.yaml
238
+ │ └── todo-graphql.yaml
240
239
  └── package.json
241
240
  ```
242
241
 
@@ -352,14 +351,14 @@ import { TestRunner, FlowExecutor, parseYamlFile, parseContextFile } from 'testf
352
351
  // Runner with full control
353
352
  const runner = new TestRunner({
354
353
  contextFile: './context.md',
355
- testFiles: ['./tests/critical.yaml'],
354
+ testFiles: ['./tests/todo-crud.yaml'],
356
355
  ai: { provider: 'ollama', model: 'mistral:7b' },
357
356
  });
358
357
  const report = await runner.run();
359
358
 
360
359
  // Manual execution
361
360
  const context = await parseContextFile('./context.md');
362
- const flow = await parseYamlFile('./tests/flow.yaml');
361
+ const flow = await parseYamlFile('./tests/todo-crud.yaml');
363
362
  const executor = new FlowExecutor(context, true);
364
363
  const result = await executor.executeFlow(flow);
365
364
  ```
@@ -374,65 +373,65 @@ const result = await executor.executeFlow(flow);
374
373
  ### Basic structure
375
374
 
376
375
  ```yaml
377
- name: User Registration Flow
378
- description: Create and verify a new user
376
+ name: Todo Lifecycle
377
+ description: Create a todo and verify it exists
379
378
  tags:
380
- - users
379
+ - todos
381
380
  - smoke
382
381
 
383
382
  steps:
384
- - name: Create user
383
+ - name: Create todo
385
384
  request:
386
385
  method: POST
387
- url: "{api}/users"
386
+ url: "{api}/todos"
388
387
  headers:
389
388
  Content-Type: application/json
390
389
  body:
391
- email: alice@example.com
392
- name: Alice
390
+ title: "Buy groceries"
391
+ completed: false
393
392
  capture:
394
- - name: userId
393
+ - name: todoId
395
394
  path: data.id
396
395
  assertions:
397
396
  - path: status
398
397
  operator: equals
399
398
  value: 201
400
- - path: data.email
399
+ - path: data.title
401
400
  operator: equals
402
- value: alice@example.com
401
+ value: "Buy groceries"
403
402
 
404
- - name: Verify user
403
+ - name: Verify todo
405
404
  request:
406
405
  method: GET
407
- url: "{api}/users/${userId}"
406
+ url: "{api}/todos/${todoId}"
408
407
  assertions:
409
408
  - path: data.id
410
409
  operator: equals
411
- value: "${userId}"
410
+ value: "${todoId}"
412
411
  ```
413
412
 
414
413
  ### GraphQL requests
415
414
 
416
415
  ```yaml
417
416
  steps:
418
- - name: Query user
417
+ - name: Query todo
419
418
  request:
420
419
  method: POST
421
420
  url: "{graphql}"
422
421
  graphql:
423
422
  query: |
424
- query GetUser($id: ID!) {
425
- user(id: $id) {
423
+ query GetTodo($id: ID!) {
424
+ todo(id: $id) {
426
425
  id
427
- email
428
- name
426
+ title
427
+ completed
429
428
  }
430
429
  }
431
430
  variables:
432
- id: "${userId}"
431
+ id: "${todoId}"
433
432
  capture:
434
- - name: userEmail
435
- path: data.user.email
433
+ - name: todoTitle
434
+ path: data.todo.title
436
435
  ```
437
436
 
438
437
  ### Variable capture and interpolation
@@ -441,25 +440,29 @@ Variables captured in one step are available in all subsequent steps:
441
440
 
442
441
  ```yaml
443
442
  steps:
444
- - name: Login
443
+ - name: Create todo
445
444
  request:
446
445
  method: POST
447
- url: "{api}/auth/login"
446
+ url: "{api}/todos"
447
+ headers:
448
+ Content-Type: application/json
448
449
  body:
449
- email: admin@example.com
450
- password: secret
450
+ title: "Read docs"
451
+ completed: false
451
452
  capture:
452
- - name: token
453
- path: data.accessToken
454
- - name: userId
455
- path: data.user.id
453
+ - name: todoId
454
+ path: data.id
455
+ - name: todoTitle
456
+ path: data.title
456
457
 
457
- - name: Get profile
458
+ - name: Verify todo title
458
459
  request:
459
460
  method: GET
460
- url: "{api}/users/${userId}"
461
- headers:
462
- Authorization: "Bearer ${token}"
461
+ url: "{api}/todos/${todoId}"
462
+ assertions:
463
+ - path: data.title
464
+ operator: equals
465
+ value: "${todoTitle}"
463
466
  ```
464
467
 
465
468
  **Supported patterns:**
@@ -474,20 +477,20 @@ For operations that take time — polls until condition is met or timeout:
474
477
 
475
478
  ```yaml
476
479
  steps:
477
- - name: Wait for job completion
480
+ - name: Wait for todo sync
478
481
  request:
479
482
  method: GET
480
- url: "{api}/jobs/${jobId}"
483
+ url: "{api}/todos/${todoId}/sync-status"
481
484
  waitUntil:
482
485
  path: data.status
483
486
  operator: equals
484
- value: "COMPLETED"
487
+ value: "SYNCED"
485
488
  timeout: 30000 # max wait (ms)
486
489
  interval: 2000 # poll every (ms)
487
490
  assertions:
488
491
  - path: data.status
489
492
  operator: equals
490
- value: "COMPLETED"
493
+ value: "SYNCED"
491
494
  ```
492
495
 
493
496
  </details>
@@ -633,19 +636,19 @@ const report = await runTests({
633
636
 
634
637
  ```yaml
635
638
  steps:
636
- - name: Check article quality
639
+ - name: Check todo description
637
640
  request:
638
641
  method: GET
639
- url: "{api}/articles/1"
642
+ url: "{api}/todos/${todoId}"
640
643
  assertions:
641
644
  # Traditional assertion
642
645
  - path: status
643
646
  operator: equals
644
647
  value: 200
645
648
  # AI-powered assertion (works with any provider)
646
- - path: data.content
649
+ - path: data.description
647
650
  operator: ai-evaluate
648
- value: "Does this article contain a coherent explanation with at least two paragraphs?"
651
+ value: "Is this a well-formed task description with a clear action item?"
649
652
  ```
650
653
 
651
654
  ### Context file AI config
@@ -744,23 +747,25 @@ This gives you:
744
747
  Define your project context in Markdown. The runner uses it to resolve `{baseUrlKey}` references in your YAML flows.
745
748
 
746
749
  ```markdown
747
- # My API
750
+ # Todo List API
748
751
 
749
752
  ## Description
750
- Brief description of your API.
753
+ A REST + GraphQL API for managing todo items.
751
754
 
752
755
  ## Base URLs
753
756
  - api: http://localhost:3000
754
757
  - graphql: http://localhost:3000/graphql
755
758
 
756
759
  ## Endpoints
757
- - POST /users - Create user
758
- - GET /users/:id - Get user
760
+ - POST /todos - Create todo
761
+ - GET /todos/:id - Get todo by ID
762
+ - PUT /todos/:id - Update todo
763
+ - DELETE /todos/:id - Delete todo
759
764
  - POST /graphql - GraphQL endpoint
760
765
 
761
766
  ## Rules
762
767
  - All endpoints return JSON
763
- - Authentication required for /users
768
+ - Todos have: id, title, completed, createdAt
764
769
 
765
770
  ## AI Configuration
766
771
  - provider: ollama
@@ -815,26 +820,27 @@ That's it. If tests fail, the job fails automatically (exit code 1).
815
820
  ══════════════════════════════════════════════════════════════
816
821
 
817
822
  Summary:
818
- Total: 5 flows
819
- Passed: 5
820
- Failed: 0
821
- Duration: 2450ms
823
+ Total: 3 flows
824
+ Passed: 2
825
+ Failed: 1
826
+ Duration: 1850ms
822
827
 
823
828
  Narrative:
824
829
 
825
- ✅ **User CRUD**
826
- → Create user
827
- 📦 userId: abc-123
828
- → Read user
829
- → Update user
830
+ ✅ **Todo CRUD**
831
+ → Create todo
832
+ 📦 todoId: abc-123
833
+ → Read todo
834
+ → Update todo
835
+ → Delete todo
830
836
 
831
- ✅ **Auth Flow**
832
- Login
833
- 📦 token: eyJhbG…
834
- Access protected route
837
+ ✅ **Todo GraphQL**
838
+ Create todo (mutation)
839
+ 📦 todoId: def-456
840
+ Query todo
835
841
 
836
- ❌ **Payment Flow**
837
- Create payment
842
+ ❌ **Todo Bulk Import**
843
+ Import todos from CSV
838
844
  ⚠️ Expected status to equal 200, got 500
839
845
 
840
846
  ══════════════════════════════════════════════════════════════
@@ -863,20 +869,23 @@ Narrative:
863
869
 
864
870
  See the [`examples/`](./examples) directory for:
865
871
 
866
- - **Todo List CRUD** (`todo-crud.yaml`) - Complete REST CRUD flow
867
- - **Todo GraphQL** (`todo-graphql.yaml`) - GraphQL mutations and queries
868
- - **REST CRUD** (`rest-crud.yaml`) - User management example
869
- - **GraphQL Flow** (`graphql-flow.yaml`) - GraphQL with variable capture
870
- - **Auth Flow** (`auth-flow.yaml`) - Authentication and protected routes
871
- - **Context Files** (`context.md`, `todo-list-context.md`) - API context templates
872
+ - **REST CRUD** (`rest-crud.yaml`) Full todo lifecycle: create → read → update → verify
873
+ - **Auth Flow** (`auth-flow.yaml`) Login, create todo with token, verify access control
874
+ - **GraphQL Flow** (`graphql-flow.yaml`) Create + query todos via GraphQL mutations
875
+ - **Todo CRUD** (`todo-crud.yaml`) Extended CRUD with delete + verify deletion
876
+ - **Todo GraphQL** (`todo-graphql.yaml`) GraphQL mutations and queries with variable capture
877
+ - **Context Files** (`context.md`, `todo-list-context.md`) API context templates
872
878
 
873
879
  **Quick start with examples:**
874
880
 
875
881
  ```bash
876
- # Run specific example
877
- npx testflow --context ./examples/todo-list-context.md ./examples/todo-crud.yaml
882
+ # Run a specific flow
883
+ npx testflow --context ./examples/context.md ./examples/rest-crud.yaml
884
+
885
+ # Run the auth flow
886
+ npx testflow --context ./examples/context.md ./examples/auth-flow.yaml
878
887
 
879
- # Run all examples in directory
888
+ # Run all examples
880
889
  npx testflow --dir ./examples --context ./examples/context.md
881
890
  ```
882
891
 
@@ -1,9 +1,10 @@
1
- # Auth flow — Login, use token, access protected resource.
1
+ # Auth flow — Login, use token, create and access a protected todo.
2
2
 
3
- name: Authentication Flow
4
- description: Login and access a protected endpoint using the returned token
3
+ name: Authenticated Todo Flow
4
+ description: Login, create a todo with auth token, and verify access control
5
5
  tags:
6
6
  - auth
7
+ - todos
7
8
  - smoke
8
9
 
9
10
  steps:
@@ -19,8 +20,6 @@ steps:
19
20
  capture:
20
21
  - name: token
21
22
  path: data.accessToken
22
- - name: userId
23
- path: data.user.id
24
23
  assertions:
25
24
  - path: status
26
25
  operator: equals
@@ -28,10 +27,31 @@ steps:
28
27
  - path: data.accessToken
29
28
  operator: exists
30
29
 
31
- - name: Access protected route
30
+ - name: Create todo (authenticated)
31
+ request:
32
+ method: POST
33
+ url: "{api}/todos"
34
+ headers:
35
+ Content-Type: application/json
36
+ Authorization: "Bearer ${token}"
37
+ body:
38
+ title: "Deploy to production"
39
+ completed: false
40
+ capture:
41
+ - name: todoId
42
+ path: data.id
43
+ assertions:
44
+ - path: status
45
+ operator: equals
46
+ value: 201
47
+ - path: data.title
48
+ operator: equals
49
+ value: "Deploy to production"
50
+
51
+ - name: Read todo (authenticated)
32
52
  request:
33
53
  method: GET
34
- url: "{api}/users/${userId}"
54
+ url: "{api}/todos/${todoId}"
35
55
  headers:
36
56
  Authorization: "Bearer ${token}"
37
57
  assertions:
@@ -40,12 +60,16 @@ steps:
40
60
  value: 200
41
61
  - path: data.id
42
62
  operator: equals
43
- value: "${userId}"
63
+ value: "${todoId}"
44
64
 
45
65
  - name: Reject without token
46
66
  request:
47
- method: GET
48
- url: "{api}/users/${userId}"
67
+ method: POST
68
+ url: "{api}/todos"
69
+ headers:
70
+ Content-Type: application/json
71
+ body:
72
+ title: "Should fail"
49
73
  assertions:
50
74
  - path: status
51
75
  operator: equals
@@ -1,25 +1,27 @@
1
- # My API
1
+ # Todo API
2
2
 
3
3
  ## Description
4
- Example API context for testflow-ai.
4
+ Example API context for testflow-ai — a simple Todo REST + GraphQL API.
5
5
 
6
6
  ## Base URLs
7
7
  - api: http://localhost:3000
8
8
  - graphql: http://localhost:3000/graphql
9
9
 
10
10
  ## Endpoints
11
- - POST /users - Create a new user
12
- - GET /users/:id - Get user by ID
13
- - PUT /users/:id - Update user
14
- - DELETE /users/:id - Delete user
11
+ - POST /todos - Create a new todo
12
+ - GET /todos/:id - Get todo by ID
13
+ - GET /todos - List all todos
14
+ - PUT /todos/:id - Update todo
15
+ - DELETE /todos/:id - Delete todo
15
16
  - POST /auth/login - Authenticate and get token
16
17
  - POST /graphql - GraphQL endpoint
17
18
 
18
19
  ## Rules
19
20
  - All endpoints return JSON
20
- - Authentication required for /users endpoints
21
+ - Authentication required for write operations
21
22
  - Rate limit: 100 requests per minute
22
23
 
23
24
  ## AI Configuration
25
+ - provider: ollama
24
26
  - url: http://localhost:11434
25
27
  - model: llama3.2:3b
@@ -1,58 +1,58 @@
1
- # GraphQL — Mutation + query with variable capture.
1
+ # GraphQL — Mutation + query with variable capture for todos.
2
2
 
3
- name: GraphQL User Flow
4
- description: Create a user via mutation, then query it back
3
+ name: GraphQL Todo Flow
4
+ description: Create a todo via mutation, then query it back
5
5
  tags:
6
6
  - graphql
7
- - users
7
+ - todos
8
8
 
9
9
  steps:
10
- - name: Create user (mutation)
10
+ - name: Create todo (mutation)
11
11
  request:
12
12
  method: POST
13
13
  url: "{graphql}"
14
14
  graphql:
15
15
  query: |
16
- mutation CreateUser($input: CreateUserInput!) {
17
- createUser(input: $input) {
16
+ mutation CreateTodo($input: CreateTodoInput!) {
17
+ createTodo(input: $input) {
18
18
  id
19
- email
20
- name
19
+ title
20
+ completed
21
21
  }
22
22
  }
23
23
  variables:
24
24
  input:
25
- email: bob@example.com
26
- name: Bob
25
+ title: "Learn GraphQL"
26
+ completed: false
27
27
  capture:
28
- - name: userId
29
- path: data.createUser.id
28
+ - name: todoId
29
+ path: data.createTodo.id
30
30
  assertions:
31
- - path: data.createUser.email
31
+ - path: data.createTodo.title
32
32
  operator: equals
33
- value: bob@example.com
34
- - path: data.createUser.id
33
+ value: "Learn GraphQL"
34
+ - path: data.createTodo.id
35
35
  operator: exists
36
36
 
37
- - name: Query user
37
+ - name: Query todo
38
38
  request:
39
39
  method: POST
40
40
  url: "{graphql}"
41
41
  graphql:
42
42
  query: |
43
- query GetUser($id: ID!) {
44
- user(id: $id) {
43
+ query GetTodo($id: ID!) {
44
+ todo(id: $id) {
45
45
  id
46
- email
47
- name
46
+ title
47
+ completed
48
48
  }
49
49
  }
50
50
  variables:
51
- id: "${userId}"
51
+ id: "${todoId}"
52
52
  assertions:
53
- - path: data.user.id
53
+ - path: data.todo.id
54
54
  operator: equals
55
- value: "${userId}"
56
- - path: data.user.email
55
+ value: "${todoId}"
56
+ - path: data.todo.title
57
57
  operator: equals
58
- value: bob@example.com
58
+ value: "Learn GraphQL"
@@ -1,76 +1,77 @@
1
- # REST CRUD — Create, read, update, verify a user.
1
+ # REST CRUD — Create, read, update, verify a todo item.
2
2
 
3
- name: User CRUD
4
- description: Full lifecycle test for a REST user resource
3
+ name: Todo REST CRUD
4
+ description: Full lifecycle test for a REST todo resource
5
5
  tags:
6
- - users
6
+ - todos
7
7
  - crud
8
8
  - smoke
9
9
 
10
10
  steps:
11
- - name: Create user
11
+ - name: Create todo
12
12
  request:
13
13
  method: POST
14
- url: "{api}/users"
14
+ url: "{api}/todos"
15
15
  headers:
16
16
  Content-Type: application/json
17
17
  body:
18
- email: alice@example.com
19
- name: Alice
18
+ title: "Write unit tests"
19
+ completed: false
20
20
  capture:
21
- - name: userId
21
+ - name: todoId
22
22
  path: data.id
23
- - name: userEmail
24
- path: data.email
23
+ - name: todoTitle
24
+ path: data.title
25
25
  assertions:
26
26
  - path: status
27
27
  operator: equals
28
28
  value: 201
29
- - path: data.email
29
+ - path: data.title
30
30
  operator: equals
31
- value: alice@example.com
31
+ value: "Write unit tests"
32
32
  - path: data.id
33
33
  operator: exists
34
34
 
35
- - name: Read user
35
+ - name: Read todo
36
36
  request:
37
37
  method: GET
38
- url: "{api}/users/${userId}"
38
+ url: "{api}/todos/${todoId}"
39
39
  assertions:
40
40
  - path: status
41
41
  operator: equals
42
42
  value: 200
43
43
  - path: data.id
44
44
  operator: equals
45
- value: "${userId}"
46
- - path: data.email
45
+ value: "${todoId}"
46
+ - path: data.title
47
47
  operator: equals
48
- value: "${userEmail}"
48
+ value: "${todoTitle}"
49
49
 
50
- - name: Update user
50
+ - name: Update todo
51
51
  request:
52
52
  method: PUT
53
- url: "{api}/users/${userId}"
53
+ url: "{api}/todos/${todoId}"
54
54
  headers:
55
55
  Content-Type: application/json
56
56
  body:
57
- name: Alice Updated
57
+ title: "Write unit tests (done)"
58
+ completed: true
58
59
  assertions:
59
60
  - path: status
60
61
  operator: equals
61
62
  value: 200
62
- - path: data.name
63
+ - path: data.title
63
64
  operator: equals
64
- value: Alice Updated
65
+ value: "Write unit tests (done)"
65
66
 
66
67
  - name: Verify update
67
68
  request:
68
69
  method: GET
69
- url: "{api}/users/${userId}"
70
+ url: "{api}/todos/${todoId}"
70
71
  assertions:
71
- - path: data.name
72
+ - path: data.title
72
73
  operator: equals
73
- value: Alice Updated
74
- - path: data.email
74
+ value: "Write unit tests (done)"
75
+ - path: data.completed
75
76
  operator: equals
76
- value: "${userEmail}"
77
+ value: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testflow-ai",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Declarative API testing powered by YAML flows. Replace Postman with version-controlled, AI-friendly test definitions.",
5
5
  "author": "Marcos Carbajal",
6
6
  "license": "MIT",