@xoxoai/checkmate 0.4.0 → 0.4.2

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.
Files changed (122) hide show
  1. package/README.md +80 -68
  2. package/bin/checkmate.js +13 -0
  3. package/dist/ai/client.d.ts +4 -4
  4. package/dist/ai/client.d.ts.map +1 -1
  5. package/dist/ai/client.js +5 -5
  6. package/dist/ai/client.js.map +1 -1
  7. package/dist/ai/message-handler.d.ts +3 -3
  8. package/dist/ai/message-handler.d.ts.map +1 -1
  9. package/dist/ai/message-handler.js +2 -2
  10. package/dist/ai/message-handler.js.map +1 -1
  11. package/dist/ai/message-history.d.ts +1 -1
  12. package/dist/ai/message-history.d.ts.map +1 -1
  13. package/dist/ai/prompts.d.ts +1 -1
  14. package/dist/ai/prompts.d.ts.map +1 -1
  15. package/dist/ai/prompts.js +1 -1
  16. package/dist/ai/prompts.js.map +1 -1
  17. package/dist/ai/rate-limit-policy.d.ts +1 -1
  18. package/dist/ai/rate-limit-policy.d.ts.map +1 -1
  19. package/dist/ai/rate-limit-policy.js +2 -2
  20. package/dist/ai/rate-limit-policy.js.map +1 -1
  21. package/dist/ai/response-processor.d.ts +3 -3
  22. package/dist/ai/response-processor.d.ts.map +1 -1
  23. package/dist/ai/response-processor.js +6 -6
  24. package/dist/ai/response-processor.js.map +1 -1
  25. package/dist/ai/token-tracker.d.ts +1 -1
  26. package/dist/ai/token-tracker.d.ts.map +1 -1
  27. package/dist/ai/token-tracker.js +3 -3
  28. package/dist/ai/token-tracker.js.map +1 -1
  29. package/dist/ai/tool-response-handler.d.ts +7 -7
  30. package/dist/ai/tool-response-handler.d.ts.map +1 -1
  31. package/dist/cli/create-examples.d.ts +21 -0
  32. package/dist/cli/create-examples.d.ts.map +1 -0
  33. package/dist/cli/create-examples.js +116 -0
  34. package/dist/cli/create-examples.js.map +1 -0
  35. package/dist/cli.d.ts +15 -0
  36. package/dist/cli.d.ts.map +1 -0
  37. package/dist/cli.js +69 -0
  38. package/dist/cli.js.map +1 -0
  39. package/dist/config/runtime-config.d.ts +1 -1
  40. package/dist/config/runtime-config.d.ts.map +1 -1
  41. package/dist/core.d.ts +7 -7
  42. package/dist/core.d.ts.map +1 -1
  43. package/dist/core.js +3 -3
  44. package/dist/core.js.map +1 -1
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +1 -1
  48. package/dist/index.js.map +1 -1
  49. package/dist/integrations/salesforce/authenticator.d.ts +1 -1
  50. package/dist/integrations/salesforce/authenticator.d.ts.map +1 -1
  51. package/dist/logging/index.js +2 -2
  52. package/dist/logging/index.js.map +1 -1
  53. package/dist/playwright.d.ts +3 -3
  54. package/dist/playwright.d.ts.map +1 -1
  55. package/dist/playwright.js +6 -6
  56. package/dist/playwright.js.map +1 -1
  57. package/dist/runtime/extension.d.ts +5 -5
  58. package/dist/runtime/extension.d.ts.map +1 -1
  59. package/dist/runtime/runner.d.ts +3 -3
  60. package/dist/runtime/runner.d.ts.map +1 -1
  61. package/dist/runtime/runner.js +6 -6
  62. package/dist/runtime/runner.js.map +1 -1
  63. package/dist/runtime/step-execution.d.ts +3 -3
  64. package/dist/runtime/step-execution.d.ts.map +1 -1
  65. package/dist/runtime/step-execution.js +3 -3
  66. package/dist/runtime/step-execution.js.map +1 -1
  67. package/dist/salesforce.d.ts +3 -3
  68. package/dist/salesforce.d.ts.map +1 -1
  69. package/dist/salesforce.js +4 -4
  70. package/dist/salesforce.js.map +1 -1
  71. package/dist/tools/browser/snapshot-filter/index.d.ts +3 -3
  72. package/dist/tools/browser/snapshot-filter/index.d.ts.map +1 -1
  73. package/dist/tools/browser/snapshot-filter/index.js +3 -3
  74. package/dist/tools/browser/snapshot-filter/index.js.map +1 -1
  75. package/dist/tools/browser/snapshot-filter/snapshot-filter.d.ts +2 -2
  76. package/dist/tools/browser/snapshot-filter/snapshot-filter.d.ts.map +1 -1
  77. package/dist/tools/browser/snapshot-filter/snapshot-filter.js +3 -3
  78. package/dist/tools/browser/snapshot-filter/snapshot-filter.js.map +1 -1
  79. package/dist/tools/browser/snapshot-filter/tree-reconstructor.d.ts +1 -1
  80. package/dist/tools/browser/snapshot-filter/tree-reconstructor.d.ts.map +1 -1
  81. package/dist/tools/browser/snapshot-service.d.ts +1 -1
  82. package/dist/tools/browser/snapshot-service.d.ts.map +1 -1
  83. package/dist/tools/browser/snapshot-service.js +3 -3
  84. package/dist/tools/browser/snapshot-service.js.map +1 -1
  85. package/dist/tools/browser/tool.d.ts +2 -2
  86. package/dist/tools/browser/tool.d.ts.map +1 -1
  87. package/dist/tools/browser/tool.js +4 -4
  88. package/dist/tools/browser/tool.js.map +1 -1
  89. package/dist/tools/browser/transient-state-tracker.js +1 -1
  90. package/dist/tools/browser/transient-state-tracker.js.map +1 -1
  91. package/dist/tools/define-agent-tool.d.ts +1 -1
  92. package/dist/tools/define-agent-tool.d.ts.map +1 -1
  93. package/dist/tools/dispatcher.d.ts +2 -2
  94. package/dist/tools/dispatcher.d.ts.map +1 -1
  95. package/dist/tools/dispatcher.js +2 -2
  96. package/dist/tools/dispatcher.js.map +1 -1
  97. package/dist/tools/loop-detector.d.ts +1 -1
  98. package/dist/tools/loop-detector.d.ts.map +1 -1
  99. package/dist/tools/registry.d.ts +2 -2
  100. package/dist/tools/registry.d.ts.map +1 -1
  101. package/dist/tools/registry.js +1 -1
  102. package/dist/tools/registry.js.map +1 -1
  103. package/dist/tools/salesforce/login-tool.d.ts +2 -2
  104. package/dist/tools/salesforce/login-tool.d.ts.map +1 -1
  105. package/dist/tools/salesforce/login-tool.js +3 -3
  106. package/dist/tools/salesforce/login-tool.js.map +1 -1
  107. package/dist/tools/step/result-tool.d.ts +1 -1
  108. package/dist/tools/step/result-tool.d.ts.map +1 -1
  109. package/dist/tools/step/result-tool.js +1 -1
  110. package/dist/tools/step/result-tool.js.map +1 -1
  111. package/dist/tools/tool-contract.d.ts +2 -2
  112. package/dist/tools/tool-contract.d.ts.map +1 -1
  113. package/dist/tools/tool-contract.js +1 -1
  114. package/dist/tools/tool-contract.js.map +1 -1
  115. package/dist/tools/types.d.ts +1 -1
  116. package/dist/tools/types.d.ts.map +1 -1
  117. package/docs/EXTENSIONS.md +16 -17
  118. package/docs/GUIDE.md +6 -8
  119. package/package.json +15 -2
  120. package/playwright.config.ts +39 -0
  121. package/test/examples/salesforce/trial-dev-org.spec.ts +82 -0
  122. package/test/examples/web/website-testing.spec.ts +281 -0
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@xoxoai/checkmate",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "AI‑driven e2e test automation framework built on Playwright Test and OpenAI API",
5
5
  "homepage": "https://github.com/dawiddiwad/checkmate",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/dawiddiwad/checkmate.git"
8
+ "url": "git+https://github.com/dawiddiwad/checkmate.git"
9
9
  },
10
10
  "keywords": [
11
11
  "test-automation",
@@ -20,13 +20,19 @@
20
20
  "groq"
21
21
  ],
22
22
  "files": [
23
+ "bin",
23
24
  "dist",
24
25
  "docs/EXTENSIONS.md",
25
26
  "docs/GUIDE.md",
26
27
  "docs/ROADMAP.md",
28
+ "playwright.config.ts",
27
29
  "README.md",
30
+ "test/examples",
28
31
  "LICENSE"
29
32
  ],
33
+ "bin": {
34
+ "checkmate": "bin/checkmate.js"
35
+ },
30
36
  "publishConfig": {
31
37
  "access": "public"
32
38
  },
@@ -102,5 +108,12 @@
102
108
  "typescript": "^5.9.3",
103
109
  "typescript-eslint": "^8.58.2",
104
110
  "vitest": "^4.1.2"
111
+ },
112
+ "directories": {
113
+ "doc": "docs",
114
+ "test": "test"
115
+ },
116
+ "bugs": {
117
+ "url": "https://github.com/dawiddiwad/checkmate/issues"
105
118
  }
106
119
  }
@@ -0,0 +1,39 @@
1
+ import { defineConfig } from '@playwright/test'
2
+ import { config as envConfig } from 'dotenv'
3
+
4
+ envConfig({ quiet: true })
5
+
6
+ export default defineConfig({
7
+ projects: [
8
+ {
9
+ name: 'salesforce',
10
+ testDir: './test/examples/salesforce',
11
+ },
12
+ {
13
+ name: 'web',
14
+ testDir: './test/examples/web',
15
+ },
16
+ ],
17
+ outputDir: process.env.CI ? undefined : './test-reports/results',
18
+ reporter: [
19
+ ['junit', { outputFile: './test-reports/junit/results.xml' }],
20
+ ['html', { outputFolder: './test-reports/html' }],
21
+ ['list'],
22
+ ],
23
+ timeout: 10 * 60000,
24
+ repeatEach: 1,
25
+ retries: 1,
26
+ workers: 1,
27
+ expect: {
28
+ timeout: 1 * 10000,
29
+ },
30
+ use: {
31
+ viewport: { width: 1360, height: 768 },
32
+ browserName: 'chromium',
33
+ actionTimeout: 1 * 5000,
34
+ navigationTimeout: 1 * 30000,
35
+ screenshot: 'only-on-failure',
36
+ trace: 'retain-on-failure',
37
+ video: 'on',
38
+ },
39
+ })
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @fileoverview
3
+ * Playwright E2E test for Salesforce Developer org.
4
+ *
5
+ * @summary
6
+ * Example of a multi-step test that creates a new Account record in the Sales app.
7
+ *
8
+ * @description
9
+ * This test automates the following user journey in a Salesforce Developer or trial org:
10
+ * 1. Log in to the Salesforce org.
11
+ * 2. Open the Sales app via the App Launcher.
12
+ * 3. Navigate to the Accounts tab.
13
+ * 4. Create a new Account with a random name.
14
+ * 5. Save the new Account record.
15
+ *
16
+ * @preconditions
17
+ * - A Salesforce Developer or trial org is required. Sign-up: https://www.salesforce.com/form/developer-signup/
18
+ * - Salesforce CLI is recommended for authorizing the org: https://developer.salesforce.com/tools/salesforcecli
19
+ * - The org must be authorized (for example: `sf org login web --set-default`) before running the test.
20
+ * - The user executing the test should have access to the Sales app and the Accounts tab in Lightning Experience.
21
+ *
22
+ * @see {@link https://developer.salesforce.com/tools/salesforcecli} - Salesforce CLI installation and documentation.
23
+ * @see {@link https://www.salesforce.com/form/developer-signup/} - Sign up for a Salesforce Developer org.
24
+ *
25
+ * @note
26
+ * All tests use the `ai` fixture and call `ai.run({ action, expect })`
27
+ * to describe actions and assert visible outcomes.
28
+ */
29
+ import { test } from '@xoxoai/checkmate/salesforce'
30
+
31
+ test.describe('trial dev org', async () => {
32
+ test('creating new account in sales app', async ({ ai }) => {
33
+ await test.step('Login to Salesforce Org', async () => {
34
+ await ai.run({
35
+ action: `
36
+ Login to Salesforce org`,
37
+ expect: `
38
+ Salesforce org loads successfully and user is authenticated/not on the login page.`,
39
+ })
40
+ })
41
+
42
+ await test.step('Open Sales App from App Launcher', async () => {
43
+ await ai.run({
44
+ action: `
45
+ Click the App Launcher icon (nine dots) in the top left corner.
46
+ Type 'Sales' into the App Launcher 'Search apps and items' search bar.
47
+ Click on the app that is named exactly the 'Sales' app from the results.`,
48
+ expect: `
49
+ Sales app opens successfully in Lightning context.`,
50
+ })
51
+ })
52
+
53
+ await test.step('Switch to Accounts tab', async () => {
54
+ await ai.run({
55
+ action: `
56
+ Click the 'Accounts' tab within the Sales app.`,
57
+ expect: `
58
+ The Accounts tab is active and a list of accounts is displayed.`,
59
+ })
60
+ })
61
+
62
+ await test.step('Start creating a new Account', async () => {
63
+ await ai.run({
64
+ action: `
65
+ Click the 'New' button on the Accounts tab to create a new Account record.
66
+ Fill 'Account Name' field with 'Agentic Test Account' followed by space and some random alphanumeric string
67
+ Don't save the record or fill any other fields.`,
68
+ expect: `
69
+ 'New Account' form is displayed and filled with random data`,
70
+ })
71
+ })
72
+
73
+ await test.step('Save new Account record', async () => {
74
+ await ai.run({
75
+ action: `
76
+ Click the 'Save' button on the 'New Account' form.`,
77
+ expect: `
78
+ Account record was saved successfully and details view is displayed.`,
79
+ })
80
+ })
81
+ })
82
+ })
@@ -0,0 +1,281 @@
1
+ /**
2
+ * @fileoverview
3
+ * Playwright E2E tests for various websites.
4
+ *
5
+ * @summary
6
+ * Examples of single-step and multi-step AI-driven web interactions using Playwright and _checkmate_.
7
+ *
8
+ * @description
9
+ * - Single-step:
10
+ * - Ollama: search for "qwen3" and open the qwen3-vl model page.
11
+ * - HuggingFace: search for "Qwen3-VL-4B" and open the model page.
12
+ * - Mojeek: search Playwright docs and open the Planner Agent page.
13
+ * - NYPL: check availability for "The Catcher in the Rye" - with and without fuzzy search.
14
+ *
15
+ * - Multi-step (polymer-shop):
16
+ * - Full AI mode: all steps executed via `ai.run`.
17
+ * - Hybrid mode: mix of `ai.run` steps and direct Playwright commands.
18
+ *
19
+ * @note
20
+ * All tests use the `ai` fixture and call `ai.run({ action, expect })`
21
+ * to describe actions and assert visible outcomes.
22
+ */
23
+ import { test } from '@xoxoai/checkmate/playwright'
24
+
25
+ test.describe('single-step : quick examples', async () => {
26
+ test('browsing ollama models', async ({ ai }) => {
27
+ await test.step('Navigate to ollama.com and search for model details', async () => {
28
+ await ai.run({
29
+ action: `
30
+ Navigate to https://ollama.com
31
+ Type 'qwen3-vl' into the 'Search models' search bar
32
+ Click on 'qwen3-vl' link from the results,
33
+ Click on 'qwen3-vl:235b' link from the models list,`,
34
+ expect: `
35
+ qwen3-vl:235b model page is displayed with model details,
36
+ describing its features and capabilities.`,
37
+ })
38
+ })
39
+ })
40
+
41
+ test('browsing huggingface models', async ({ ai }) => {
42
+ await test.step('Navigate to huggingface.co', async () => {
43
+ await ai.run({
44
+ action: `
45
+ Navigate to the https://huggingface.co website.
46
+ Type 'Qwen3-VL-4B' in the search bar.
47
+ Click on the 'Qwen/Qwen3-VL-4B-Instruct' link from the search results.`,
48
+ expect: `
49
+ Qwen3-VL-4B-Instruct model page is displayed with model details`,
50
+ })
51
+ })
52
+ })
53
+
54
+ test('searching with mojeek', async ({ ai }) => {
55
+ await test.step('Search for Playwright docs using mojeek.com', async () => {
56
+ await ai.run({
57
+ action: `
58
+ Test: Mojeek Search
59
+ Navigate to the Mojeek search engine at https://www.mojeek.com/.
60
+ In the search field, type playwright test automation and press Enter.
61
+ From the search results, click on the link that goes to playwright.dev.
62
+ Once on the Playwright website, click the site's search icon and type Agent into the Search docs field.
63
+ Click on the Planner result displayed in the documentation search.
64
+ `,
65
+ expect: `
66
+ The Planner Agent documentation page is displayed, providing details on how to use this agent within Playwright.`,
67
+ })
68
+ })
69
+ })
70
+
71
+ test('searching new york public library', async ({ ai }) => {
72
+ await test.step('the catcher in the rye availability', async () => {
73
+ await ai.run({
74
+ action: `
75
+ Navigate to https://www.nypl.org.
76
+ Search for 'The Catcher in the Rye'.`,
77
+ expect: `
78
+ 'The Catcher in the Rye' physical branch's bookshelf availability information is displayed.`,
79
+ })
80
+ })
81
+ })
82
+
83
+ test('searching new york public library - fuzzy search enabled', async ({ ai }) => {
84
+ await test.step('the catcher in the rye availability', async () => {
85
+ await ai.run({
86
+ action: `
87
+ Navigate to https://www.nypl.org.
88
+ Search for 'The Catcher in the Rye'.`,
89
+ expect: `
90
+ 'The Catcher in the Rye' physical branch's bookshelf availability information is displayed.`,
91
+
92
+ search: ['search', 'the catcher in the rye', 'shelf'],
93
+ topPercent: 10, // aggressive snapshot filtering (top 10% of elements on page)
94
+ })
95
+ })
96
+ })
97
+ })
98
+
99
+ test.describe('multi-step : Polymer Shop : full AI mode', async () => {
100
+ test.beforeEach(async ({ ai }) => {
101
+ await ai.run({
102
+ action: `Navigate to https://shop.polymer-project.org/`,
103
+ expect: `Polymer Shop home page is loaded`,
104
+ })
105
+ })
106
+
107
+ test('successful end-to-end purchase flow', async ({ ai }) => {
108
+ await test.step('Navigate to shop and select product', async () => {
109
+ await ai.run({
110
+ action: `
111
+ Click "Shop Now" on "Men's Outerwear" category
112
+ Click on the first product: "Men's Tech Shell Full-Zip"`,
113
+ expect: `Product detail page is displayed with title, price, and selectors`,
114
+ })
115
+ })
116
+
117
+ await test.step('Add product to cart and proceed to checkout', async () => {
118
+ await ai.run({
119
+ action: `
120
+ Click "Add to Cart"
121
+ Click "Checkout" in the "Added to cart" dialog`,
122
+ expect: `Checkout page loads showing the 'Order Summary' with correct total`,
123
+ })
124
+ })
125
+
126
+ await test.step('Fill checkout details and place order', async () => {
127
+ await ai.run({
128
+ action: `
129
+ Fill in the required fields in one go:
130
+ - Email: 'test@example.com'
131
+ - Phone: '1234567890'
132
+ - Address: '123 Test St'
133
+ - City: 'Test City'
134
+ - State: 'Test State'
135
+ - Zip: '12345'
136
+ - Country: 'Canada'
137
+ - Cardholder: 'Test User'
138
+ - Card Number: '1111222233334444'
139
+ - Expiry month: 'Dec'
140
+ - Expiry year: '2026'
141
+ - CVV: '123'
142
+ Click "Place Order"`,
143
+ expect: `Checkout process completed message is displayed along with Finish button`,
144
+ })
145
+ })
146
+
147
+ await test.step('Finish and return to home', async () => {
148
+ await ai.run({
149
+ action: `Finish and return to home`,
150
+ expect: `User is returned to the home page`,
151
+ })
152
+ })
153
+ })
154
+
155
+ test('cart management - adding multiple items & verifying total', async ({ ai }) => {
156
+ await test.step('Add items from different categories', async () => {
157
+ await ai.run({
158
+ action: `
159
+ Go to 'Ladies Outerwear' and add an item to the cart.
160
+ Press page up to return to the top.
161
+ Go back to home page, navigate to 'Men's T-Shirts' and add an item to the cart.`,
162
+ expect: `Cart counter in the header updates to '2'`,
163
+ })
164
+ })
165
+
166
+ await test.step('Verify cart total', async () => {
167
+ await ai.run({
168
+ action: `Click the Cart icon in the header.`,
169
+ expect: `The 'Your Cart' page shows both items and the 'Total' matches the sum of individual prices.`,
170
+ })
171
+ })
172
+ })
173
+
174
+ test('cart management - updating quantity and removing items', async ({ ai }) => {
175
+ await test.step('Add item and update quantity', async () => {
176
+ await ai.run({
177
+ action: `
178
+ Go to 'Men's Outerwear' and add an item to cart, then click "View Cart".
179
+ Select "2" from the "Quantity" dropdown for the item.`,
180
+ expect: `The quantity is updated and total price reflects the change.`,
181
+ })
182
+ })
183
+
184
+ await test.step('Remove item from cart', async () => {
185
+ await ai.run({
186
+ action: `Click the 'Delete' (trash icon) button for the item.`,
187
+ expect: `The item is removed, cart shows 'Your cart is empty', and header counter is '0'.`,
188
+ })
189
+ })
190
+ })
191
+
192
+ test('category navigation & product display consistency', async ({ ai }) => {
193
+ await test.step('Navigate between categories', async () => {
194
+ await ai.run({
195
+ action: `
196
+ Click "Ladies T-Shirts" in the top navigation menu.
197
+ Click "Men's Outerwear" in the top navigation menu.`,
198
+ expect: `User can navigate between categories correctly.`,
199
+ })
200
+ })
201
+
202
+ await test.step('Return to home via SHOP logo', async () => {
203
+ await ai.run({
204
+ action: `Click "SHOP" logo in the header.`,
205
+ expect: `User is returned to the home page.`,
206
+ })
207
+ })
208
+ })
209
+
210
+ test('checkout form validation (error handling)', async ({ ai }) => {
211
+ await test.step('Submit empty checkout form', async () => {
212
+ await ai.run({
213
+ action: `
214
+ Add any item to cart and proceed to "Checkout".
215
+ Click "Place Order" without filling any fields.`,
216
+ expect: `Validation error messages like "Invalid Email" and "Invalid Address" are visible.`,
217
+ })
218
+ })
219
+
220
+ await test.step('Verify persistent errors for invalid input', async () => {
221
+ await ai.run({
222
+ action: `Type 'invalid-email' in the Email field and click "Place Order".`,
223
+ expect: `"Invalid Email" error message is still displayed.`,
224
+ })
225
+ })
226
+ })
227
+ })
228
+
229
+ test.describe('multi-step : Polymer Shop : hybrid mode', async () => {
230
+ test.beforeEach(async ({ page }) => {
231
+ await page.goto('https://shop.polymer-project.org/')
232
+ })
233
+
234
+ test('successful end-to-end purchase flow', async ({ page, ai }) => {
235
+ await test.step('Navigate to shop and select product', async () => {
236
+ await page.getByRole('link', { name: "Men's Outerwear Shop Now" }).click()
237
+ await page.getByRole('link', { name: "Men's Tech Shell Full-Zip Men" }).click()
238
+ await ai.run({
239
+ action: ``,
240
+ expect: `Product detail page is displayed with title, price, and selectors`,
241
+ })
242
+ })
243
+
244
+ await test.step('Add product to cart and proceed to checkout', async () => {
245
+ await page.getByRole('button', { name: 'Add this item to cart' }).click()
246
+ await page.getByRole('link', { name: 'Checkout' }).click()
247
+ await ai.run({
248
+ action: ``,
249
+ expect: `Checkout page loads showing the 'Order Summary' with correct total`,
250
+ })
251
+ })
252
+
253
+ await test.step('Fill checkout details and place order', async () => {
254
+ await ai.run({
255
+ action: `
256
+ Fill in the required fields in one go:
257
+ - Email: 'test@example.com'
258
+ - Phone: '1234567890'
259
+ - Address: '123 Test St'
260
+ - City: 'Test City'
261
+ - State: 'Test State'
262
+ - Zip: '12345'
263
+ - Country: 'Canada'
264
+ - Cardholder: 'Test User'
265
+ - Card Number: '1111222233334444'
266
+ - Expiry month: 'Dec'
267
+ - Expiry year: '2026'
268
+ - CVV: '123'
269
+ Click "Place Order"`,
270
+ expect: `Demo checkout process completed message is displayed along with Finish button`,
271
+ })
272
+ })
273
+
274
+ await test.step('Finish and return to home', async () => {
275
+ await ai.run({
276
+ action: `Finish and return to home`,
277
+ expect: `User is returned to the home page`,
278
+ })
279
+ })
280
+ })
281
+ })