expect-sdk 0.0.24

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 (324) hide show
  1. package/.claude/settings.local.json +48 -0
  2. package/.expect/replays/08a6cacb-cdfb-47ba-9cf7-41a13ac07a36.html +286 -0
  3. package/.expect/replays/08a6cacb-cdfb-47ba-9cf7-41a13ac07a36.ndjson +2 -0
  4. package/.expect/replays/08a6cacb-cdfb-47ba-9cf7-41a13ac07a36.ndjson.js +2 -0
  5. package/.expect/replays/0abc2d0c-30d4-405b-8f6a-ad55eab10797.html +286 -0
  6. package/.expect/replays/0abc2d0c-30d4-405b-8f6a-ad55eab10797.ndjson +2 -0
  7. package/.expect/replays/0abc2d0c-30d4-405b-8f6a-ad55eab10797.ndjson.js +2 -0
  8. package/.expect/replays/0be009ad-fc3d-4aa8-81e2-2473dddf876a.html +286 -0
  9. package/.expect/replays/0be009ad-fc3d-4aa8-81e2-2473dddf876a.ndjson +7 -0
  10. package/.expect/replays/0be009ad-fc3d-4aa8-81e2-2473dddf876a.ndjson.js +2 -0
  11. package/.expect/replays/0bf0f4f1-9c7d-4dac-ae8f-6990ec08b82b.html +286 -0
  12. package/.expect/replays/0bf0f4f1-9c7d-4dac-ae8f-6990ec08b82b.ndjson +10 -0
  13. package/.expect/replays/0bf0f4f1-9c7d-4dac-ae8f-6990ec08b82b.ndjson.js +2 -0
  14. package/.expect/replays/0cdb0236-3fdf-4c48-8ef1-fbc8539a8d32.html +286 -0
  15. package/.expect/replays/0cdb0236-3fdf-4c48-8ef1-fbc8539a8d32.ndjson +49 -0
  16. package/.expect/replays/0cdb0236-3fdf-4c48-8ef1-fbc8539a8d32.ndjson.js +2 -0
  17. package/.expect/replays/0dbbf37b-6749-4973-ae20-b37b9b734ce6.html +286 -0
  18. package/.expect/replays/0dbbf37b-6749-4973-ae20-b37b9b734ce6.ndjson +44 -0
  19. package/.expect/replays/0dbbf37b-6749-4973-ae20-b37b9b734ce6.ndjson.js +2 -0
  20. package/.expect/replays/15009a95-16f4-4f14-9f52-a2a650b6de23.html +286 -0
  21. package/.expect/replays/15009a95-16f4-4f14-9f52-a2a650b6de23.ndjson +23 -0
  22. package/.expect/replays/15009a95-16f4-4f14-9f52-a2a650b6de23.ndjson.js +2 -0
  23. package/.expect/replays/2095af47-e1dc-444b-ab84-f614d755fd04.html +286 -0
  24. package/.expect/replays/2095af47-e1dc-444b-ab84-f614d755fd04.ndjson +10 -0
  25. package/.expect/replays/2095af47-e1dc-444b-ab84-f614d755fd04.ndjson.js +2 -0
  26. package/.expect/replays/26962ef6-a3ac-4033-aee6-d09414c2232d.html +286 -0
  27. package/.expect/replays/26962ef6-a3ac-4033-aee6-d09414c2232d.ndjson +8 -0
  28. package/.expect/replays/26962ef6-a3ac-4033-aee6-d09414c2232d.ndjson.js +2 -0
  29. package/.expect/replays/28d1ed69-05c0-44dc-a369-77b0d37b64c8.html +286 -0
  30. package/.expect/replays/28d1ed69-05c0-44dc-a369-77b0d37b64c8.ndjson +12 -0
  31. package/.expect/replays/28d1ed69-05c0-44dc-a369-77b0d37b64c8.ndjson.js +2 -0
  32. package/.expect/replays/2ece9734-85bf-4d45-9738-7e3c7a4b6c9e.html +286 -0
  33. package/.expect/replays/2ece9734-85bf-4d45-9738-7e3c7a4b6c9e.ndjson +20 -0
  34. package/.expect/replays/2ece9734-85bf-4d45-9738-7e3c7a4b6c9e.ndjson.js +2 -0
  35. package/.expect/replays/301ecd28-499b-4367-80c8-8f5c740a4011.html +286 -0
  36. package/.expect/replays/301ecd28-499b-4367-80c8-8f5c740a4011.ndjson +6 -0
  37. package/.expect/replays/301ecd28-499b-4367-80c8-8f5c740a4011.ndjson.js +2 -0
  38. package/.expect/replays/323fdb67-102e-45c2-a6ae-2ed78e590928.html +286 -0
  39. package/.expect/replays/323fdb67-102e-45c2-a6ae-2ed78e590928.ndjson +7 -0
  40. package/.expect/replays/323fdb67-102e-45c2-a6ae-2ed78e590928.ndjson.js +2 -0
  41. package/.expect/replays/338b9a53-a211-448a-99cd-a95873edef79.html +286 -0
  42. package/.expect/replays/338b9a53-a211-448a-99cd-a95873edef79.ndjson +7 -0
  43. package/.expect/replays/338b9a53-a211-448a-99cd-a95873edef79.ndjson.js +2 -0
  44. package/.expect/replays/33bfd732-9116-4200-b732-41faba42ae75.html +286 -0
  45. package/.expect/replays/33bfd732-9116-4200-b732-41faba42ae75.ndjson +10 -0
  46. package/.expect/replays/33bfd732-9116-4200-b732-41faba42ae75.ndjson.js +2 -0
  47. package/.expect/replays/33eb7162-e0c8-40ae-8e72-8ad273b0fca7.html +286 -0
  48. package/.expect/replays/33eb7162-e0c8-40ae-8e72-8ad273b0fca7.ndjson +7 -0
  49. package/.expect/replays/33eb7162-e0c8-40ae-8e72-8ad273b0fca7.ndjson.js +2 -0
  50. package/.expect/replays/365939fb-9693-4219-b5f5-0bafef524617.html +286 -0
  51. package/.expect/replays/365939fb-9693-4219-b5f5-0bafef524617.ndjson +2 -0
  52. package/.expect/replays/365939fb-9693-4219-b5f5-0bafef524617.ndjson.js +2 -0
  53. package/.expect/replays/383ea7a8-0ff8-4958-a148-3032f0a52eab.html +286 -0
  54. package/.expect/replays/383ea7a8-0ff8-4958-a148-3032f0a52eab.ndjson +54 -0
  55. package/.expect/replays/383ea7a8-0ff8-4958-a148-3032f0a52eab.ndjson.js +2 -0
  56. package/.expect/replays/397a5665-4344-441b-a424-2ac53df712a1.html +286 -0
  57. package/.expect/replays/397a5665-4344-441b-a424-2ac53df712a1.ndjson +14 -0
  58. package/.expect/replays/397a5665-4344-441b-a424-2ac53df712a1.ndjson.js +2 -0
  59. package/.expect/replays/39a5d9cc-72d0-483d-bfcc-506a6fc85f13.html +286 -0
  60. package/.expect/replays/39a5d9cc-72d0-483d-bfcc-506a6fc85f13.ndjson +10 -0
  61. package/.expect/replays/39a5d9cc-72d0-483d-bfcc-506a6fc85f13.ndjson.js +2 -0
  62. package/.expect/replays/39ccd62e-2f4c-4a4a-9b43-40524b7a945b.html +286 -0
  63. package/.expect/replays/39ccd62e-2f4c-4a4a-9b43-40524b7a945b.ndjson +14 -0
  64. package/.expect/replays/39ccd62e-2f4c-4a4a-9b43-40524b7a945b.ndjson.js +2 -0
  65. package/.expect/replays/3eff073f-7e14-49d8-a2e2-1b7634a117cd.html +286 -0
  66. package/.expect/replays/3eff073f-7e14-49d8-a2e2-1b7634a117cd.ndjson +45 -0
  67. package/.expect/replays/3eff073f-7e14-49d8-a2e2-1b7634a117cd.ndjson.js +2 -0
  68. package/.expect/replays/3f144b2f-78ce-4d23-bd96-99994bf07edd.html +286 -0
  69. package/.expect/replays/3f144b2f-78ce-4d23-bd96-99994bf07edd.ndjson +34 -0
  70. package/.expect/replays/3f144b2f-78ce-4d23-bd96-99994bf07edd.ndjson.js +2 -0
  71. package/.expect/replays/436e0182-8590-4520-97b5-d62b08ebe822.html +286 -0
  72. package/.expect/replays/436e0182-8590-4520-97b5-d62b08ebe822.ndjson +15 -0
  73. package/.expect/replays/436e0182-8590-4520-97b5-d62b08ebe822.ndjson.js +2 -0
  74. package/.expect/replays/43e9a6e6-ce7d-4ed4-b593-f07ce6d53009.html +286 -0
  75. package/.expect/replays/43e9a6e6-ce7d-4ed4-b593-f07ce6d53009.ndjson +85 -0
  76. package/.expect/replays/43e9a6e6-ce7d-4ed4-b593-f07ce6d53009.ndjson.js +2 -0
  77. package/.expect/replays/4568fc07-ea40-4740-be6f-0f6a8e632175.html +286 -0
  78. package/.expect/replays/4568fc07-ea40-4740-be6f-0f6a8e632175.ndjson +53 -0
  79. package/.expect/replays/4568fc07-ea40-4740-be6f-0f6a8e632175.ndjson.js +2 -0
  80. package/.expect/replays/47b43574-9b41-44be-af9c-fb7c0a81196f.html +286 -0
  81. package/.expect/replays/47b43574-9b41-44be-af9c-fb7c0a81196f.ndjson +2 -0
  82. package/.expect/replays/47b43574-9b41-44be-af9c-fb7c0a81196f.ndjson.js +2 -0
  83. package/.expect/replays/47d846d6-f86e-46e4-94d7-f0abff232b20.html +286 -0
  84. package/.expect/replays/47d846d6-f86e-46e4-94d7-f0abff232b20.ndjson +10 -0
  85. package/.expect/replays/47d846d6-f86e-46e4-94d7-f0abff232b20.ndjson.js +2 -0
  86. package/.expect/replays/486cd227-9d22-49cf-b050-cb546d374206.html +286 -0
  87. package/.expect/replays/486cd227-9d22-49cf-b050-cb546d374206.ndjson +2 -0
  88. package/.expect/replays/486cd227-9d22-49cf-b050-cb546d374206.ndjson.js +2 -0
  89. package/.expect/replays/4c53e4c2-ece4-4767-87fe-394fe0ab4300.html +286 -0
  90. package/.expect/replays/4c53e4c2-ece4-4767-87fe-394fe0ab4300.ndjson +33 -0
  91. package/.expect/replays/4c53e4c2-ece4-4767-87fe-394fe0ab4300.ndjson.js +2 -0
  92. package/.expect/replays/4d1c0166-77e7-49ee-9bdc-9e3382e7f60c.html +286 -0
  93. package/.expect/replays/4d1c0166-77e7-49ee-9bdc-9e3382e7f60c.ndjson +58 -0
  94. package/.expect/replays/4d1c0166-77e7-49ee-9bdc-9e3382e7f60c.ndjson.js +2 -0
  95. package/.expect/replays/4ee7ecf6-20ce-42c3-8ed6-9476e74498eb.html +286 -0
  96. package/.expect/replays/4ee7ecf6-20ce-42c3-8ed6-9476e74498eb.ndjson +10 -0
  97. package/.expect/replays/4ee7ecf6-20ce-42c3-8ed6-9476e74498eb.ndjson.js +2 -0
  98. package/.expect/replays/5438a8a6-ef42-42e2-8764-fde7c6529d95.html +286 -0
  99. package/.expect/replays/5438a8a6-ef42-42e2-8764-fde7c6529d95.ndjson +33 -0
  100. package/.expect/replays/5438a8a6-ef42-42e2-8764-fde7c6529d95.ndjson.js +2 -0
  101. package/.expect/replays/5709193a-1153-46b2-b19c-736e4bda525d.html +286 -0
  102. package/.expect/replays/5709193a-1153-46b2-b19c-736e4bda525d.ndjson +16 -0
  103. package/.expect/replays/5709193a-1153-46b2-b19c-736e4bda525d.ndjson.js +2 -0
  104. package/.expect/replays/5eee229c-5e60-4cb2-a1c2-f7720a94ea1c.html +286 -0
  105. package/.expect/replays/5eee229c-5e60-4cb2-a1c2-f7720a94ea1c.ndjson +2 -0
  106. package/.expect/replays/5eee229c-5e60-4cb2-a1c2-f7720a94ea1c.ndjson.js +2 -0
  107. package/.expect/replays/63657ec6-87d8-4250-a0db-05d12fa2983e.html +286 -0
  108. package/.expect/replays/63657ec6-87d8-4250-a0db-05d12fa2983e.ndjson +48 -0
  109. package/.expect/replays/63657ec6-87d8-4250-a0db-05d12fa2983e.ndjson.js +2 -0
  110. package/.expect/replays/6623c0d4-cfcf-461a-8029-0f157ff21080.html +286 -0
  111. package/.expect/replays/6623c0d4-cfcf-461a-8029-0f157ff21080.ndjson +8 -0
  112. package/.expect/replays/6623c0d4-cfcf-461a-8029-0f157ff21080.ndjson.js +2 -0
  113. package/.expect/replays/69a4dab6-06ad-4d54-99c9-1113d6f5a033.html +286 -0
  114. package/.expect/replays/69a4dab6-06ad-4d54-99c9-1113d6f5a033.ndjson +7 -0
  115. package/.expect/replays/69a4dab6-06ad-4d54-99c9-1113d6f5a033.ndjson.js +2 -0
  116. package/.expect/replays/6b3fae01-5e61-48e3-b675-334572bdaf67.html +286 -0
  117. package/.expect/replays/6b3fae01-5e61-48e3-b675-334572bdaf67.ndjson +14 -0
  118. package/.expect/replays/6b3fae01-5e61-48e3-b675-334572bdaf67.ndjson.js +2 -0
  119. package/.expect/replays/709859dd-cd9d-4f4a-93f3-0185631feaf5.html +286 -0
  120. package/.expect/replays/709859dd-cd9d-4f4a-93f3-0185631feaf5.ndjson +2 -0
  121. package/.expect/replays/709859dd-cd9d-4f4a-93f3-0185631feaf5.ndjson.js +2 -0
  122. package/.expect/replays/76b454d4-ba48-47a0-9336-486a7b106322.html +286 -0
  123. package/.expect/replays/76b454d4-ba48-47a0-9336-486a7b106322.ndjson +37 -0
  124. package/.expect/replays/76b454d4-ba48-47a0-9336-486a7b106322.ndjson.js +2 -0
  125. package/.expect/replays/76c75bfa-d266-487e-a4d2-54d6f64760b5.html +286 -0
  126. package/.expect/replays/76c75bfa-d266-487e-a4d2-54d6f64760b5.ndjson +18 -0
  127. package/.expect/replays/76c75bfa-d266-487e-a4d2-54d6f64760b5.ndjson.js +2 -0
  128. package/.expect/replays/78333bb7-5172-4839-98a0-745372a1032b.html +286 -0
  129. package/.expect/replays/78333bb7-5172-4839-98a0-745372a1032b.ndjson +65 -0
  130. package/.expect/replays/78333bb7-5172-4839-98a0-745372a1032b.ndjson.js +2 -0
  131. package/.expect/replays/7be24ce2-8544-492e-9b66-b56c0c1e027b.html +286 -0
  132. package/.expect/replays/7be24ce2-8544-492e-9b66-b56c0c1e027b.ndjson +10 -0
  133. package/.expect/replays/7be24ce2-8544-492e-9b66-b56c0c1e027b.ndjson.js +2 -0
  134. package/.expect/replays/825423b3-7e83-4037-b0b7-c4eafe6282b8.html +286 -0
  135. package/.expect/replays/825423b3-7e83-4037-b0b7-c4eafe6282b8.ndjson +54 -0
  136. package/.expect/replays/825423b3-7e83-4037-b0b7-c4eafe6282b8.ndjson.js +2 -0
  137. package/.expect/replays/83641ba6-ccfa-4400-88ee-b8e4a1775c12.html +286 -0
  138. package/.expect/replays/83641ba6-ccfa-4400-88ee-b8e4a1775c12.ndjson +18 -0
  139. package/.expect/replays/83641ba6-ccfa-4400-88ee-b8e4a1775c12.ndjson.js +2 -0
  140. package/.expect/replays/87af45a5-dd8f-433a-8e5d-5ab136d653b9.html +286 -0
  141. package/.expect/replays/87af45a5-dd8f-433a-8e5d-5ab136d653b9.ndjson +3 -0
  142. package/.expect/replays/87af45a5-dd8f-433a-8e5d-5ab136d653b9.ndjson.js +2 -0
  143. package/.expect/replays/882a48e3-15b5-47fb-9f96-3e63c282557c.html +286 -0
  144. package/.expect/replays/882a48e3-15b5-47fb-9f96-3e63c282557c.ndjson +44 -0
  145. package/.expect/replays/882a48e3-15b5-47fb-9f96-3e63c282557c.ndjson.js +2 -0
  146. package/.expect/replays/8efca11f-3649-4433-a61c-f3b844aaa0b9.html +286 -0
  147. package/.expect/replays/8efca11f-3649-4433-a61c-f3b844aaa0b9.ndjson +33 -0
  148. package/.expect/replays/8efca11f-3649-4433-a61c-f3b844aaa0b9.ndjson.js +2 -0
  149. package/.expect/replays/8f563116-c926-4de3-9d16-3dfe33dd52b6.html +286 -0
  150. package/.expect/replays/8f563116-c926-4de3-9d16-3dfe33dd52b6.ndjson +12 -0
  151. package/.expect/replays/8f563116-c926-4de3-9d16-3dfe33dd52b6.ndjson.js +2 -0
  152. package/.expect/replays/9321eb59-9587-4819-80b0-b387c50aaaf4.html +286 -0
  153. package/.expect/replays/9321eb59-9587-4819-80b0-b387c50aaaf4.ndjson +10 -0
  154. package/.expect/replays/9321eb59-9587-4819-80b0-b387c50aaaf4.ndjson.js +2 -0
  155. package/.expect/replays/94cb0431-e2a6-4a8d-800a-6918adb25660.html +286 -0
  156. package/.expect/replays/94cb0431-e2a6-4a8d-800a-6918adb25660.ndjson +10 -0
  157. package/.expect/replays/94cb0431-e2a6-4a8d-800a-6918adb25660.ndjson.js +2 -0
  158. package/.expect/replays/94d30b76-3fb0-476a-93c5-c9acb88eb45a.html +286 -0
  159. package/.expect/replays/94d30b76-3fb0-476a-93c5-c9acb88eb45a.ndjson +43 -0
  160. package/.expect/replays/94d30b76-3fb0-476a-93c5-c9acb88eb45a.ndjson.js +2 -0
  161. package/.expect/replays/94da15c7-217f-4167-aad9-0ed7d69fb1a9.html +286 -0
  162. package/.expect/replays/94da15c7-217f-4167-aad9-0ed7d69fb1a9.ndjson +2 -0
  163. package/.expect/replays/94da15c7-217f-4167-aad9-0ed7d69fb1a9.ndjson.js +2 -0
  164. package/.expect/replays/9998db1c-b008-497f-8a13-1fc0eb6a8845.html +286 -0
  165. package/.expect/replays/9998db1c-b008-497f-8a13-1fc0eb6a8845.ndjson +31 -0
  166. package/.expect/replays/9998db1c-b008-497f-8a13-1fc0eb6a8845.ndjson.js +2 -0
  167. package/.expect/replays/9c54b7fe-d113-4d99-9df9-42af0779a176.html +286 -0
  168. package/.expect/replays/9c54b7fe-d113-4d99-9df9-42af0779a176.ndjson +52 -0
  169. package/.expect/replays/9c54b7fe-d113-4d99-9df9-42af0779a176.ndjson.js +2 -0
  170. package/.expect/replays/9d8b9d7f-2fad-44c8-92bc-5377adb4ca1b.html +286 -0
  171. package/.expect/replays/9d8b9d7f-2fad-44c8-92bc-5377adb4ca1b.ndjson +24 -0
  172. package/.expect/replays/9d8b9d7f-2fad-44c8-92bc-5377adb4ca1b.ndjson.js +2 -0
  173. package/.expect/replays/9f6d215a-17bd-44f8-be75-4f21c36cb7a5.html +286 -0
  174. package/.expect/replays/9f6d215a-17bd-44f8-be75-4f21c36cb7a5.ndjson +14 -0
  175. package/.expect/replays/9f6d215a-17bd-44f8-be75-4f21c36cb7a5.ndjson.js +2 -0
  176. package/.expect/replays/9fddc5ad-02e8-4f8e-96cf-c249444bf123.html +286 -0
  177. package/.expect/replays/9fddc5ad-02e8-4f8e-96cf-c249444bf123.ndjson +2 -0
  178. package/.expect/replays/9fddc5ad-02e8-4f8e-96cf-c249444bf123.ndjson.js +2 -0
  179. package/.expect/replays/a1e5b091-888f-43c5-95c3-c25f91f8925a.html +286 -0
  180. package/.expect/replays/a1e5b091-888f-43c5-95c3-c25f91f8925a.ndjson +12 -0
  181. package/.expect/replays/a1e5b091-888f-43c5-95c3-c25f91f8925a.ndjson.js +2 -0
  182. package/.expect/replays/a2e5372c-e459-4c47-8133-921303e7c74d.html +286 -0
  183. package/.expect/replays/a2e5372c-e459-4c47-8133-921303e7c74d.ndjson +2 -0
  184. package/.expect/replays/a2e5372c-e459-4c47-8133-921303e7c74d.ndjson.js +2 -0
  185. package/.expect/replays/a41a8fe3-4abc-4bde-bea0-526ef9d5c16f.html +286 -0
  186. package/.expect/replays/a41a8fe3-4abc-4bde-bea0-526ef9d5c16f.ndjson +16 -0
  187. package/.expect/replays/a41a8fe3-4abc-4bde-bea0-526ef9d5c16f.ndjson.js +2 -0
  188. package/.expect/replays/a726e14d-080c-4b30-b413-fcf6d14d0daf.html +286 -0
  189. package/.expect/replays/a726e14d-080c-4b30-b413-fcf6d14d0daf.ndjson +8 -0
  190. package/.expect/replays/a726e14d-080c-4b30-b413-fcf6d14d0daf.ndjson.js +2 -0
  191. package/.expect/replays/ab5651bb-3528-4b4b-809d-1e6d1fef2ade.html +286 -0
  192. package/.expect/replays/ab5651bb-3528-4b4b-809d-1e6d1fef2ade.ndjson +52 -0
  193. package/.expect/replays/ab5651bb-3528-4b4b-809d-1e6d1fef2ade.ndjson.js +2 -0
  194. package/.expect/replays/ac83d5ac-73c5-48f0-8d73-53f50151e4bf.html +286 -0
  195. package/.expect/replays/ac83d5ac-73c5-48f0-8d73-53f50151e4bf.ndjson +2 -0
  196. package/.expect/replays/ac83d5ac-73c5-48f0-8d73-53f50151e4bf.ndjson.js +2 -0
  197. package/.expect/replays/afeb4664-90ba-4525-9f4e-54349c5254f4.html +286 -0
  198. package/.expect/replays/afeb4664-90ba-4525-9f4e-54349c5254f4.ndjson +8 -0
  199. package/.expect/replays/afeb4664-90ba-4525-9f4e-54349c5254f4.ndjson.js +2 -0
  200. package/.expect/replays/b205a14f-ea04-41f7-b3f6-6a24881a4907.html +286 -0
  201. package/.expect/replays/b205a14f-ea04-41f7-b3f6-6a24881a4907.ndjson +44 -0
  202. package/.expect/replays/b205a14f-ea04-41f7-b3f6-6a24881a4907.ndjson.js +2 -0
  203. package/.expect/replays/b23eafd9-c876-4a66-a5e6-8d560672d5a8.html +286 -0
  204. package/.expect/replays/b23eafd9-c876-4a66-a5e6-8d560672d5a8.ndjson +84 -0
  205. package/.expect/replays/b23eafd9-c876-4a66-a5e6-8d560672d5a8.ndjson.js +2 -0
  206. package/.expect/replays/b4116451-32d0-4b85-a404-503bb4123815.html +286 -0
  207. package/.expect/replays/b4116451-32d0-4b85-a404-503bb4123815.ndjson +10 -0
  208. package/.expect/replays/b4116451-32d0-4b85-a404-503bb4123815.ndjson.js +2 -0
  209. package/.expect/replays/b649a6ef-45e3-49c2-bd02-284deb7ea9b1.html +286 -0
  210. package/.expect/replays/b649a6ef-45e3-49c2-bd02-284deb7ea9b1.ndjson +32 -0
  211. package/.expect/replays/b649a6ef-45e3-49c2-bd02-284deb7ea9b1.ndjson.js +2 -0
  212. package/.expect/replays/b8487d6d-87db-4453-9a87-f3ef57b9596a.html +286 -0
  213. package/.expect/replays/b8487d6d-87db-4453-9a87-f3ef57b9596a.ndjson +12 -0
  214. package/.expect/replays/b8487d6d-87db-4453-9a87-f3ef57b9596a.ndjson.js +2 -0
  215. package/.expect/replays/b9126d9e-93e9-44d1-901b-f4e4700a2ac7.html +286 -0
  216. package/.expect/replays/b9126d9e-93e9-44d1-901b-f4e4700a2ac7.ndjson +16 -0
  217. package/.expect/replays/b9126d9e-93e9-44d1-901b-f4e4700a2ac7.ndjson.js +2 -0
  218. package/.expect/replays/bc9ac26e-6915-466d-a250-61679c7d8785.html +286 -0
  219. package/.expect/replays/bc9ac26e-6915-466d-a250-61679c7d8785.ndjson +58 -0
  220. package/.expect/replays/bc9ac26e-6915-466d-a250-61679c7d8785.ndjson.js +2 -0
  221. package/.expect/replays/bf71f292-d0fa-4b38-88d2-838d631b4fd3.html +286 -0
  222. package/.expect/replays/bf71f292-d0fa-4b38-88d2-838d631b4fd3.ndjson +18 -0
  223. package/.expect/replays/bf71f292-d0fa-4b38-88d2-838d631b4fd3.ndjson.js +2 -0
  224. package/.expect/replays/c064a436-aa74-411c-b4ff-228e6016748c.html +286 -0
  225. package/.expect/replays/c064a436-aa74-411c-b4ff-228e6016748c.ndjson +14 -0
  226. package/.expect/replays/c064a436-aa74-411c-b4ff-228e6016748c.ndjson.js +2 -0
  227. package/.expect/replays/c293319a-56fc-47c2-be0a-efebab7e5547.html +286 -0
  228. package/.expect/replays/c293319a-56fc-47c2-be0a-efebab7e5547.ndjson +10 -0
  229. package/.expect/replays/c293319a-56fc-47c2-be0a-efebab7e5547.ndjson.js +2 -0
  230. package/.expect/replays/c48e7ccb-f40a-4d86-9ada-f9ac0f174809.html +286 -0
  231. package/.expect/replays/c48e7ccb-f40a-4d86-9ada-f9ac0f174809.ndjson +18 -0
  232. package/.expect/replays/c48e7ccb-f40a-4d86-9ada-f9ac0f174809.ndjson.js +2 -0
  233. package/.expect/replays/c4ec751f-4c2f-4ac4-83e1-9d53ebd275b0.html +286 -0
  234. package/.expect/replays/c4ec751f-4c2f-4ac4-83e1-9d53ebd275b0.ndjson +12 -0
  235. package/.expect/replays/c4ec751f-4c2f-4ac4-83e1-9d53ebd275b0.ndjson.js +2 -0
  236. package/.expect/replays/c5f8f2de-415c-4605-90e9-8a31286c1d33.html +286 -0
  237. package/.expect/replays/c5f8f2de-415c-4605-90e9-8a31286c1d33.ndjson +36 -0
  238. package/.expect/replays/c5f8f2de-415c-4605-90e9-8a31286c1d33.ndjson.js +2 -0
  239. package/.expect/replays/c92defec-c6f7-4334-89f4-d3b1010a592b.html +286 -0
  240. package/.expect/replays/c92defec-c6f7-4334-89f4-d3b1010a592b.ndjson +97 -0
  241. package/.expect/replays/c92defec-c6f7-4334-89f4-d3b1010a592b.ndjson.js +2 -0
  242. package/.expect/replays/ce024389-749b-4d9f-9cbe-d2add9b5d506.html +286 -0
  243. package/.expect/replays/ce024389-749b-4d9f-9cbe-d2add9b5d506.ndjson +8 -0
  244. package/.expect/replays/ce024389-749b-4d9f-9cbe-d2add9b5d506.ndjson.js +2 -0
  245. package/.expect/replays/d0106187-b170-4208-b6e2-1652906fb952.html +286 -0
  246. package/.expect/replays/d0106187-b170-4208-b6e2-1652906fb952.ndjson +52 -0
  247. package/.expect/replays/d0106187-b170-4208-b6e2-1652906fb952.ndjson.js +2 -0
  248. package/.expect/replays/d4aa55a2-9b5f-4eb5-b795-5324e5c5d7db.html +286 -0
  249. package/.expect/replays/d4aa55a2-9b5f-4eb5-b795-5324e5c5d7db.ndjson +84 -0
  250. package/.expect/replays/d4aa55a2-9b5f-4eb5-b795-5324e5c5d7db.ndjson.js +2 -0
  251. package/.expect/replays/d4fc939c-c97d-4125-95dc-a8745709e879.html +286 -0
  252. package/.expect/replays/d4fc939c-c97d-4125-95dc-a8745709e879.ndjson +2 -0
  253. package/.expect/replays/d4fc939c-c97d-4125-95dc-a8745709e879.ndjson.js +2 -0
  254. package/.expect/replays/d59474f3-6eee-4145-9252-ac56d7d634d1.html +286 -0
  255. package/.expect/replays/d59474f3-6eee-4145-9252-ac56d7d634d1.ndjson +46 -0
  256. package/.expect/replays/d59474f3-6eee-4145-9252-ac56d7d634d1.ndjson.js +2 -0
  257. package/.expect/replays/d842aee0-a2e0-45a4-84bb-02571ea704ef.html +286 -0
  258. package/.expect/replays/d842aee0-a2e0-45a4-84bb-02571ea704ef.ndjson +10 -0
  259. package/.expect/replays/d842aee0-a2e0-45a4-84bb-02571ea704ef.ndjson.js +2 -0
  260. package/.expect/replays/dbacab2e-6e47-4c2e-861b-881a3439cc61.html +286 -0
  261. package/.expect/replays/dbacab2e-6e47-4c2e-861b-881a3439cc61.ndjson +40 -0
  262. package/.expect/replays/dbacab2e-6e47-4c2e-861b-881a3439cc61.ndjson.js +2 -0
  263. package/.expect/replays/e47ad94c-1326-4e5f-9e36-9187b2475dc4.html +286 -0
  264. package/.expect/replays/e47ad94c-1326-4e5f-9e36-9187b2475dc4.ndjson +10 -0
  265. package/.expect/replays/e47ad94c-1326-4e5f-9e36-9187b2475dc4.ndjson.js +2 -0
  266. package/.expect/replays/e4e7c05e-0def-4eb4-80de-5c0abc6e9707.html +286 -0
  267. package/.expect/replays/e4e7c05e-0def-4eb4-80de-5c0abc6e9707.ndjson +32 -0
  268. package/.expect/replays/e4e7c05e-0def-4eb4-80de-5c0abc6e9707.ndjson.js +2 -0
  269. package/.expect/replays/e7fbb2f5-f5be-430f-b9d8-e9b5980c4e25.html +286 -0
  270. package/.expect/replays/e7fbb2f5-f5be-430f-b9d8-e9b5980c4e25.ndjson +30 -0
  271. package/.expect/replays/e7fbb2f5-f5be-430f-b9d8-e9b5980c4e25.ndjson.js +2 -0
  272. package/.expect/replays/ef25484d-6e02-4cde-bf19-7251a9ada2b3.html +286 -0
  273. package/.expect/replays/ef25484d-6e02-4cde-bf19-7251a9ada2b3.ndjson +37 -0
  274. package/.expect/replays/ef25484d-6e02-4cde-bf19-7251a9ada2b3.ndjson.js +2 -0
  275. package/.expect/replays/f114ddaa-f891-4be1-b626-eaeeba692e0f.html +286 -0
  276. package/.expect/replays/f114ddaa-f891-4be1-b626-eaeeba692e0f.ndjson +12 -0
  277. package/.expect/replays/f114ddaa-f891-4be1-b626-eaeeba692e0f.ndjson.js +2 -0
  278. package/.expect/replays/f39c87c6-34c7-4b81-8350-a644e309430f.html +286 -0
  279. package/.expect/replays/f39c87c6-34c7-4b81-8350-a644e309430f.ndjson +8 -0
  280. package/.expect/replays/f39c87c6-34c7-4b81-8350-a644e309430f.ndjson.js +2 -0
  281. package/.expect/replays/f6484a4f-c647-4f78-9a2e-f41f00683c15.html +286 -0
  282. package/.expect/replays/f6484a4f-c647-4f78-9a2e-f41f00683c15.ndjson +14 -0
  283. package/.expect/replays/f6484a4f-c647-4f78-9a2e-f41f00683c15.ndjson.js +2 -0
  284. package/.turbo/turbo-build.log +22 -0
  285. package/.turbo/turbo-check.log +6 -0
  286. package/.turbo/turbo-typecheck.log +4 -0
  287. package/CHANGELOG.md +12 -0
  288. package/LICENSE +110 -0
  289. package/README.md +536 -0
  290. package/dist/constants-DFJAD4-F.mjs +152 -0
  291. package/dist/constants-DFJAD4-F.mjs.map +1 -0
  292. package/dist/effect.d.mts +30 -0
  293. package/dist/effect.d.mts.map +1 -0
  294. package/dist/effect.mjs +2 -0
  295. package/dist/index.d.mts +20 -0
  296. package/dist/index.d.mts.map +1 -0
  297. package/dist/index.mjs +279 -0
  298. package/dist/index.mjs.map +1 -0
  299. package/dist/types-0J0EwTM4.d.mts +124 -0
  300. package/dist/types-0J0EwTM4.d.mts.map +1 -0
  301. package/package.json +46 -0
  302. package/src/build-instruction.ts +35 -0
  303. package/src/config.ts +15 -0
  304. package/src/constants.ts +2 -0
  305. package/src/effect.ts +14 -0
  306. package/src/errors.ts +17 -0
  307. package/src/expect.ts +432 -0
  308. package/src/index.ts +23 -0
  309. package/src/layers.ts +14 -0
  310. package/src/result-builder.ts +184 -0
  311. package/src/test-run.ts +19 -0
  312. package/src/tool.ts +26 -0
  313. package/src/types.ts +98 -0
  314. package/tests/build-instruction.test.ts +62 -0
  315. package/tests/config.test.ts +44 -0
  316. package/tests/e2e.ts +81 -0
  317. package/tests/examples.test.ts +44 -0
  318. package/tests/expect.test.ts +143 -0
  319. package/tests/fixtures/fixture-server.ts +111 -0
  320. package/tests/result-builder.test.ts +292 -0
  321. package/tests/test-run.test.ts +95 -0
  322. package/tests/tool.test.ts +60 -0
  323. package/tsconfig.json +9 -0
  324. package/vite.config.ts +13 -0
package/README.md ADDED
@@ -0,0 +1,536 @@
1
+ # expect-sdk
2
+
3
+ > **Alpha:** This package is currently in alpha. APIs may change between releases.
4
+
5
+ **Expect** tests your app in a browser so you don't have to.
6
+
7
+ - Spawns agents simulating real logged-in users to find issues and regressions.
8
+ - No more writing Playwright by hand or token-hungry computer use tools.
9
+ - Get video recordings and GitHub Actions out of the box.
10
+
11
+ ```ts
12
+ import { Expect } from "expect-sdk";
13
+
14
+ const result = await Expect.test({
15
+ url: "http://localhost:3000/login",
16
+ tests: ["valid credentials redirect to the dashboard"],
17
+ });
18
+ ```
19
+
20
+ `expect-sdk` is the TypeScript SDK for [Expect](https://expect.dev). Use it when you need test results in code: CI scripts, test suites, custom tooling. Use [expect-cli](https://npmjs.com/package/expect-cli) for everything else.
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ npm install expect-sdk
26
+ ```
27
+
28
+ ## Set up
29
+
30
+ Expect works with any [supported coding agent](https://github.com/millionco/expect#supported-agents), including Claude Code, Codex, Gemini CLI, GitHub Copilot, Cursor, OpenCode, and Factory Droid. Install at least one:
31
+
32
+ ```bash
33
+ npm install -g @anthropic-ai/claude-code # default
34
+ ```
35
+
36
+ Set your API key:
37
+
38
+ ```bash
39
+ export ANTHROPIC_API_KEY=your-api-key
40
+ ```
41
+
42
+ The SDK uses Claude Code by default. See the [full list of supported agents](https://github.com/millionco/expect#supported-agents) for other providers and their setup instructions.
43
+
44
+ Playwright is an optional peer dependency, only needed for `page`/`browserContext` interoperability and function-based `setup`/`teardown`.
45
+
46
+ ## Run your first test
47
+
48
+ ```ts
49
+ import { Expect } from "expect-sdk";
50
+
51
+ const result = await Expect.test({
52
+ url: "http://localhost:3000",
53
+ tests: ["the homepage loads and shows a welcome heading"],
54
+ });
55
+
56
+ console.log(result.status); // "passed" or "failed"
57
+ ```
58
+
59
+ The SDK launches a browser, navigates to your URL, and uses AI to verify each test. No test framework is required.
60
+
61
+ ## Capabilities
62
+
63
+ ### Tests as plain English
64
+
65
+ Tests are written as strings describing expected behavior. The AI agent handles navigation, interaction, and verification on your behalf.
66
+
67
+ ```ts
68
+ await Expect.test({
69
+ url: "http://localhost:3000/signup",
70
+ tests: [
71
+ "submitting empty form shows validation errors on all fields",
72
+ "mismatched passwords show 'passwords do not match'",
73
+ "valid submission redirects to the dashboard with welcome message",
74
+ ],
75
+ });
76
+ ```
77
+
78
+ ### Detailed test prompts
79
+
80
+ For tests that need more context than a single sentence, use the `{ title, prompt }` object form. The `title` is displayed in results, and the `prompt` gives the AI detailed instructions:
81
+
82
+ ```ts
83
+ await Expect.test({
84
+ url: "http://localhost:3000/dashboard",
85
+ tests: [
86
+ "sidebar navigation works",
87
+ {
88
+ title: "dashboard data loads correctly",
89
+ prompt:
90
+ "verify the user's name appears in the header, the sidebar shows Settings/Projects/Team links, no loading spinners remain after 3 seconds, and there are no console errors",
91
+ },
92
+ ],
93
+ });
94
+ ```
95
+
96
+ ### Live streaming
97
+
98
+ `Expect.test()` returns a `TestRun`, which is both a `PromiseLike<TestResult>` and an `AsyncIterable<TestEvent>`. You can await it for the final result, or iterate over it for live progress updates:
99
+
100
+ ```ts
101
+ const run = Expect.test({
102
+ url: "http://localhost:3000",
103
+ tests: ["login works", "dashboard loads"],
104
+ });
105
+
106
+ for await (const event of run) {
107
+ if (event.type === "step:passed") console.log(`✅ ${event.step.title}`);
108
+ if (event.type === "step:failed") console.log(`❌ ${event.step.title}`);
109
+ }
110
+
111
+ const result = await run;
112
+ ```
113
+
114
+ ### Playwright interoperability
115
+
116
+ You can use Playwright for deterministic setup steps and let the AI handle fuzzy verification. Pass a string for AI-driven actions, or a callback that receives the Playwright `Page`:
117
+
118
+ ```ts
119
+ await Expect.test({
120
+ url: "/admin",
121
+ cookies: "chrome",
122
+ setup: async (page) => {
123
+ await page.fill("#email", "admin@test.com");
124
+ await page.click("button[type=submit]");
125
+ await page.waitForURL("**/dashboard");
126
+ },
127
+ tests: ["admin panel shows user management table"],
128
+ teardown: "delete any test data created during this test",
129
+ });
130
+ ```
131
+
132
+ You can also pass an existing Playwright `Page` if you've already set up the browser yourself:
133
+
134
+ ```ts
135
+ import { chromium } from "playwright";
136
+
137
+ const browser = await chromium.launch();
138
+ const page = await browser.newPage();
139
+ await page.goto("http://localhost:3000/login");
140
+ await page.fill("#email", "test@test.com");
141
+
142
+ const result = await Expect.test({
143
+ page,
144
+ tests: ["login form is pre-filled with test@test.com"],
145
+ });
146
+ ```
147
+
148
+ ### Sessions
149
+
150
+ Sessions create a persistent browser context where cookies and localStorage carry across multiple `.test()` calls. Each call opens a fresh page within the same context.
151
+
152
+ ```ts
153
+ const session = Expect.session({ url: "http://localhost:3000", cookies: "chrome" });
154
+
155
+ await session.test({ url: "/login", tests: ["login form loads"] });
156
+ await session.test({ url: "/dashboard", tests: ["dashboard loads while authenticated"] });
157
+ await session.test({ url: "/settings", tests: ["settings page is accessible"] });
158
+
159
+ await session.close();
160
+ ```
161
+
162
+ ### Cookie extraction
163
+
164
+ `Expect.cookies()` extracts cookies from a local browser profile for authenticated testing. It returns a Playwright-compatible `Cookie[]` that you can spread into your test input.
165
+
166
+ ```ts
167
+ const cookies = await Expect.cookies("chrome");
168
+
169
+ await Expect.test({
170
+ url: "/dashboard",
171
+ cookies: [
172
+ ...cookies,
173
+ {
174
+ name: "feature_flag",
175
+ value: "new_ui",
176
+ domain: "localhost",
177
+ path: "/",
178
+ expires: -1,
179
+ httpOnly: false,
180
+ secure: false,
181
+ sameSite: "Lax",
182
+ },
183
+ ],
184
+ tests: ["dashboard loads with authentication"],
185
+ });
186
+ ```
187
+
188
+ As a shorthand, you can pass a browser name or `true` directly to `cookies` on `Expect.test()` instead of calling `Expect.cookies()` separately:
189
+
190
+ ```ts
191
+ await Expect.test({ url: "/dashboard", cookies: "chrome", tests: ["loads"] });
192
+ await Expect.test({ url: "/dashboard", cookies: true, tests: ["loads"] });
193
+ ```
194
+
195
+ ### Custom tools
196
+
197
+ You can provide custom tools that the AI agent can call during test execution. This is useful for database setup, API calls, or any server-side action the agent needs to perform as part of a test.
198
+
199
+ ```ts
200
+ import { tool } from "expect-sdk";
201
+
202
+ const createUser = tool(
203
+ "create_user",
204
+ "Create a test user in the database",
205
+ { type: "object", properties: { email: { type: "string" } }, required: ["email"] },
206
+ async (input) => {
207
+ const user = await db.users.create({ email: input.email as string });
208
+ return `Created user ${user.id}`;
209
+ },
210
+ );
211
+
212
+ await Expect.test({
213
+ url: "/admin/users",
214
+ tools: [createUser],
215
+ tests: ["new user appears in the users table"],
216
+ });
217
+ ```
218
+
219
+ ### Configuration
220
+
221
+ `configure()` sets global defaults that apply to all subsequent `Expect.test()` and `Expect.session()` calls, so you don't need to repeat common options:
222
+
223
+ ```ts
224
+ import { Expect, configure } from "expect-sdk";
225
+
226
+ configure({ baseUrl: "http://localhost:3000", mode: "headless" });
227
+
228
+ await Expect.test({ url: "/login", tests: ["login page loads"] });
229
+ await Expect.test({ url: "/signup", tests: ["signup page loads"] });
230
+ ```
231
+
232
+ ### Config file
233
+
234
+ For project-wide defaults, create an `expect.config.ts` file in your project root. The SDK automatically loads this file when running tests, so you don't need to call `configure()` in every test script.
235
+
236
+ ```ts
237
+ // expect.config.ts
238
+ import { defineConfig } from "expect-sdk";
239
+
240
+ export default defineConfig({
241
+ baseUrl: "http://localhost:3000",
242
+ browser: "chrome",
243
+ mode: "headless",
244
+ cookies: "chrome",
245
+ timeout: 120_000,
246
+ });
247
+ ```
248
+
249
+ With this file in place, all `Expect.test()` calls resolve relative URLs against `baseUrl` and use Chrome cookies automatically:
250
+
251
+ ```ts
252
+ // No need to specify baseUrl or cookies in each call
253
+ await Expect.test({ url: "/login", tests: ["login page loads"] });
254
+ await Expect.test({ url: "/signup", tests: ["signup page loads"] });
255
+ ```
256
+
257
+ Inline `configure()` calls take precedence over config file values, so you can override specific options per-script when needed.
258
+
259
+ ### Error handling
260
+
261
+ The SDK throws `ExpectConfigError` for invalid input (missing URL, empty tests array) and `ExpectTimeoutError` when a test exceeds its timeout. Both are exported from the package:
262
+
263
+ ```ts
264
+ import { Expect, ExpectConfigError } from "expect-sdk";
265
+
266
+ try {
267
+ const result = await Expect.test({
268
+ url: "http://localhost:3000",
269
+ tests: ["login works"],
270
+ timeout: 60_000,
271
+ });
272
+ if (result.status === "failed") {
273
+ console.error("Test failures:");
274
+ for (const error of result.errors) {
275
+ console.error(` ${error.title}: ${error.summary}`);
276
+ }
277
+ process.exit(1);
278
+ }
279
+ } catch (error) {
280
+ if (error instanceof ExpectConfigError) {
281
+ console.error("Configuration error:", error.message);
282
+ } else {
283
+ console.error("Unexpected error:", error);
284
+ }
285
+ process.exit(1);
286
+ }
287
+ ```
288
+
289
+ ### Parallel execution
290
+
291
+ Tests run sequentially by default. To run multiple tests in parallel, use `Promise.all` or `Promise.allSettled`:
292
+
293
+ ```ts
294
+ const [login, signup, dashboard] = await Promise.all([
295
+ Expect.test({ url: "/login", tests: ["login page loads"] }),
296
+ Expect.test({ url: "/signup", tests: ["signup page loads"] }),
297
+ Expect.test({ url: "/dashboard", tests: ["dashboard loads"] }),
298
+ ]);
299
+ ```
300
+
301
+ Each test launches its own browser instance, so they don't interfere with each other.
302
+
303
+ ### CI/CD
304
+
305
+ The SDK works in any CI environment that has Node.js and a supported agent installed. Here's an example GitHub Actions workflow:
306
+
307
+ ```yaml
308
+ # .github/workflows/expect.yml
309
+ name: Browser Tests
310
+ on: [push, pull_request]
311
+
312
+ jobs:
313
+ test:
314
+ runs-on: ubuntu-latest
315
+ steps:
316
+ - uses: actions/checkout@v4
317
+ - uses: actions/setup-node@v4
318
+ with:
319
+ node-version: 20
320
+ - run: npm ci
321
+ - run: npm install -g @anthropic-ai/claude-code
322
+ - run: npm start & npx wait-on http://localhost:3000
323
+ - run: npx tsx tests/browser.ts
324
+ env:
325
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
326
+ ```
327
+
328
+ Where `tests/browser.ts` is a script that uses the SDK:
329
+
330
+ ```ts
331
+ import { Expect, configure } from "expect-sdk";
332
+
333
+ configure({ baseUrl: "http://localhost:3000" });
334
+
335
+ const result = await Expect.test({
336
+ url: "/login",
337
+ tests: ["login form validates required fields", "valid credentials redirect to the dashboard"],
338
+ });
339
+
340
+ if (result.status === "failed") {
341
+ console.error(result.errors.map((e) => e.summary).join("\n"));
342
+ process.exit(1);
343
+ }
344
+ ```
345
+
346
+ ## Compare to other testing tools
347
+
348
+ | | expect-sdk | Playwright / Cypress | Manual QA |
349
+ | -------------- | ------------------------------- | ------------------------ | -------------- |
350
+ | Test authoring | Plain English | Selectors + assertions | Click around |
351
+ | Maintenance | Tests don't break on UI changes | Brittle selectors | N/A |
352
+ | Setup | `npm install expect-sdk` | Page objects, fixtures | Hire people |
353
+ | Flakiness | AI retries intelligently | Explicit waits | Human judgment |
354
+ | Best for | Behavior verification | Pixel-precise assertions | Exploratory |
355
+
356
+ Use expect-sdk when you care about **what** the app does. Use Playwright when you care about **how** it renders.
357
+
358
+ ---
359
+
360
+ ## API reference
361
+
362
+ ### `Expect.test(input): TestRun`
363
+
364
+ Runs a one-shot test. The SDK launches a browser, navigates to the URL, executes all tests, and closes the browser when finished.
365
+
366
+ ```ts
367
+ const result = await Expect.test({
368
+ url: "http://localhost:3000/login",
369
+ cookies: "chrome",
370
+ tests: ["login form validates email", "valid credentials redirect to dashboard"],
371
+ setup: "navigate to the login page",
372
+ timeout: 60_000,
373
+ });
374
+ ```
375
+
376
+ | Field | Type | Default | Description |
377
+ | ------------- | ------------- | ------------ | ---------------------------------------------------------------- | ------------------ |
378
+ | `url` | `string` | - | URL to navigate to (absolute or relative to `baseUrl`) |
379
+ | `page` | `Page` | - | Existing Playwright page (skips browser creation, `url` ignored) |
380
+ | `cookies` | `CookieInput` | - | `true`, browser name, browser name array, or `Cookie[]` |
381
+ | `tools` | `Tool[]` | - | Custom tools the AI can call |
382
+ | `tests` | `Test[]` | **required** | Test descriptions as strings or `{ title?, prompt }` objects |
383
+ | `setup` | `Action` | - | String instruction or `(page: Page) => Promise<void | string>` |
384
+ | `teardown` | `Action` | - | String instruction or `(page: Page) => Promise<void | string>` |
385
+ | `mode` | `"headed" | "headless"` | `"headless"` | Browser visibility |
386
+ | `timeout` | `number` | `300000` | Timeout in milliseconds |
387
+ | `isRecording` | `boolean` | `false` | Enable session recording |
388
+
389
+ ### `TestRun`
390
+
391
+ The object returned by `Expect.test()`. It implements both `PromiseLike<TestResult>` and `AsyncIterable<TestEvent>`, so you can either await the final result or iterate over events as they stream in.
392
+
393
+ ```ts
394
+ interface TestRun extends PromiseLike<TestResult> {
395
+ [Symbol.asyncIterator](): AsyncIterator<TestEvent>;
396
+ }
397
+ ```
398
+
399
+ ### `TestResult`
400
+
401
+ The final result returned when a `TestRun` resolves.
402
+
403
+ ```ts
404
+ interface TestResult {
405
+ status: "pending" | "passed" | "failed";
406
+ url: string;
407
+ duration: number;
408
+ recordingPath?: string;
409
+ steps: StepResult[];
410
+ errors: StepResult[]; // steps.filter(s => s.status === "failed")
411
+ }
412
+ ```
413
+
414
+ ### `StepResult`
415
+
416
+ Represents the outcome of a single test step within a run.
417
+
418
+ ```ts
419
+ interface StepResult {
420
+ title: string;
421
+ status: "pending" | "passed" | "failed";
422
+ summary: string;
423
+ screenshotPath?: string;
424
+ duration: number;
425
+ }
426
+ ```
427
+
428
+ ### `TestEvent`
429
+
430
+ Events emitted during test execution. Use `for await (const event of run)` to consume them:
431
+
432
+ ```ts
433
+ type TestEvent =
434
+ | { type: "run:started"; title: string; baseUrl?: string }
435
+ | { type: "step:started"; title: string }
436
+ | { type: "step:passed"; step: StepResult }
437
+ | { type: "step:failed"; step: StepResult }
438
+ | { type: "step:skipped"; title: string; reason: string }
439
+ | { type: "screenshot"; title: string; path: string }
440
+ | { type: "completed"; result: TestResult };
441
+ ```
442
+
443
+ ### `Expect.session(config): ExpectSession`
444
+
445
+ Creates a persistent browser context where cookies and localStorage are preserved across multiple `.test()` calls.
446
+
447
+ ```ts
448
+ const session = Expect.session({
449
+ url: "http://localhost:3000",
450
+ cookies: "chrome",
451
+ mode: "headless",
452
+ });
453
+
454
+ await session.test({ url: "/login", tests: ["login works"] });
455
+ await session.test({ url: "/dashboard", tests: ["loads while authenticated"] });
456
+ await session.close();
457
+ ```
458
+
459
+ | Field | Type | Default | Description |
460
+ | --------- | ------------- | ----------- | --------------------------------- | ------------------ |
461
+ | `url` | `string` | - | Base URL for the session |
462
+ | `cookies` | `CookieInput` | - | Cookies to inject |
463
+ | `mode` | `"headed" | "headless"` | `"headless"` | Browser visibility |
464
+ | `timeout` | `number` | `300000` | Default timeout for session tests |
465
+
466
+ ### `ExpectSession`
467
+
468
+ ```ts
469
+ interface ExpectSession {
470
+ test(input: SessionTestInput): TestRun;
471
+ close(): Promise<void>;
472
+ [Symbol.asyncDispose](): Promise<void>;
473
+ }
474
+ ```
475
+
476
+ ### `Expect.cookies(browser): Promise<Cookie[]>`
477
+
478
+ Extracts cookies from a local browser profile and returns them as a Playwright-compatible `Cookie[]`.
479
+
480
+ ```ts
481
+ const cookies = await Expect.cookies("chrome");
482
+ const multi = await Expect.cookies(["chrome", "firefox"]);
483
+ const autoDetect = await Expect.cookies(true);
484
+ ```
485
+
486
+ ### `tool(name, description, schema, handler): Tool`
487
+
488
+ Creates a custom tool that the AI agent can invoke during test execution. The schema follows the MCP tool input schema format.
489
+
490
+ ```ts
491
+ import { tool } from "expect-sdk";
492
+
493
+ const createUser = tool(
494
+ "create_user",
495
+ "Create a test user",
496
+ { type: "object", properties: { email: { type: "string" } }, required: ["email"] },
497
+ async (input) => `Created user ${input.email}`,
498
+ );
499
+ ```
500
+
501
+ ### `configure(config): void`
502
+
503
+ Sets global configuration defaults. Each call shallow-merges into the existing config, so you can call it multiple times to build up options incrementally.
504
+
505
+ ```ts
506
+ import { configure } from "expect-sdk";
507
+ configure({ baseUrl: "http://localhost:3000", mode: "headless", timeout: 60_000 });
508
+ ```
509
+
510
+ ### `defineConfig(config): ExpectConfig`
511
+
512
+ An identity function that provides type inference when writing `expect.config.ts` files. It returns the config object unchanged.
513
+
514
+ ```ts
515
+ import { defineConfig } from "expect-sdk";
516
+ export default defineConfig({ baseUrl: "http://localhost:3000", cookies: "chrome" });
517
+ ```
518
+
519
+ ### `ExpectConfig`
520
+
521
+ ```ts
522
+ interface ExpectConfig {
523
+ baseUrl?: string;
524
+ browser?: BrowserName;
525
+ mode?: "headed" | "headless";
526
+ cookies?: CookieInput;
527
+ timeout?: number;
528
+ model?: string;
529
+ apiKey?: string;
530
+ rootDir?: string;
531
+ }
532
+ ```
533
+
534
+ ## License
535
+
536
+ FSL-1.1-MIT © [Million Software, Inc.](https://million.dev)
@@ -0,0 +1,152 @@
1
+ import { DateTime, Layer, Option, References, Schema } from "effect";
2
+ import { Executor, Git } from "@expect/supervisor";
3
+ import { Agent } from "@expect/agent";
4
+ //#region src/errors.ts
5
+ var ExpectTimeoutError = class extends Schema.ErrorClass("ExpectTimeoutError")({
6
+ _tag: Schema.tag("ExpectTimeoutError"),
7
+ timeoutMs: Schema.Number
8
+ }) {
9
+ message = `expect execution timed out after ${this.timeoutMs}ms`;
10
+ };
11
+ var ExpectConfigError = class extends Error {
12
+ constructor(message, fix) {
13
+ super(`${message}\n\nFix: ${fix}`);
14
+ this.name = "ExpectConfigError";
15
+ }
16
+ };
17
+ //#endregion
18
+ //#region src/build-instruction.ts
19
+ const resolveUrl = (url, baseUrl) => {
20
+ if (typeof url !== "string") throw new ExpectConfigError(`Expected a URL string, got ${typeof url}.`, `Expect.test({ url: "http://localhost:3000/login", tests: [...] })`);
21
+ try {
22
+ return new URL(url).href;
23
+ } catch {}
24
+ if (!baseUrl) throw new ExpectConfigError(`No baseUrl configured and URL "${url}" is relative.`, `configure({ baseUrl: "http://localhost:3000" })\nOr use a full URL: Expect.test({ url: "http://localhost:3000${url}", tests: [...] })`);
25
+ return new URL(url, baseUrl).href;
26
+ };
27
+ const buildInstruction = (url, tests) => {
28
+ const lines = [`Navigate to ${url} and verify the following requirements:`, ""];
29
+ for (const [index, title] of tests.entries()) lines.push(`${index + 1}. ${title}`);
30
+ return lines.join("\n");
31
+ };
32
+ //#endregion
33
+ //#region src/layers.ts
34
+ const layerSdk = (agentBackend, rootDir) => {
35
+ const gitLayer = Git.withRepoRoot(rootDir);
36
+ const agentLayer = Agent.layerFor(agentBackend);
37
+ const executorLayer = Executor.layer.pipe(Layer.provide(gitLayer));
38
+ return Layer.mergeAll(executorLayer, gitLayer).pipe(Layer.provideMerge(agentLayer), Layer.provideMerge(Layer.succeed(References.MinimumLogLevel, "Error")));
39
+ };
40
+ //#endregion
41
+ //#region src/result-builder.ts
42
+ const REPLAY_SESSION_PREFIX = "rrweb replay:";
43
+ const SCREENSHOT_PREFIX = "Screenshot:";
44
+ const stepDurationMs = (step) => {
45
+ if (Option.isNone(step.startedAt)) return 0;
46
+ if (Option.isNone(step.endedAt)) return Date.now() - Number(DateTime.toEpochMillis(step.startedAt.value));
47
+ return Number(DateTime.toEpochMillis(step.endedAt.value)) - Number(DateTime.toEpochMillis(step.startedAt.value));
48
+ };
49
+ const stepStatusToResultStatus = (status) => {
50
+ if (status === "passed") return "passed";
51
+ if (status === "failed" || status === "skipped") return "failed";
52
+ return "pending";
53
+ };
54
+ const extractArtifacts = (events) => {
55
+ const closeResult = events.slice().reverse().find((event) => event._tag === "ToolResult" && event.toolName === "close" && !event.isError && event.result.length > 0);
56
+ if (!closeResult || closeResult._tag !== "ToolResult") return {
57
+ recordingPath: void 0,
58
+ screenshotPaths: []
59
+ };
60
+ const lines = closeResult.result.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
61
+ return {
62
+ recordingPath: lines.find((line) => line.startsWith(REPLAY_SESSION_PREFIX))?.replace(REPLAY_SESSION_PREFIX, "").trim() || void 0,
63
+ screenshotPaths: lines.filter((line) => line.startsWith(SCREENSHOT_PREFIX)).map((line) => line.replace(SCREENSHOT_PREFIX, "").trim()).filter((value) => value.length > 0)
64
+ };
65
+ };
66
+ const buildStepResult = (step, screenshotPaths, stepIndex) => ({
67
+ title: step.title,
68
+ status: stepStatusToResultStatus(step.status),
69
+ summary: Option.getOrElse(step.summary, () => ""),
70
+ screenshotPath: screenshotPaths[stepIndex],
71
+ duration: stepDurationMs(step)
72
+ });
73
+ const buildTestResult = (executed, url, startedAt, artifacts) => {
74
+ const steps = executed.steps.map((step, index) => buildStepResult(step, artifacts.screenshotPaths, index));
75
+ const errors = steps.filter((step) => step.status === "failed");
76
+ const hasFailure = errors.length > 0;
77
+ const hasPending = steps.some((step) => step.status === "pending");
78
+ let status = "passed";
79
+ if (hasFailure) status = "failed";
80
+ else if (hasPending || steps.length === 0) status = "pending";
81
+ return {
82
+ status,
83
+ url,
84
+ duration: Date.now() - startedAt,
85
+ recordingPath: artifacts.recordingPath,
86
+ steps,
87
+ errors
88
+ };
89
+ };
90
+ const mapExecutionEvent = (event, context) => {
91
+ switch (event._tag) {
92
+ case "RunStarted": return {
93
+ type: "run:started",
94
+ title: event.plan.title,
95
+ baseUrl: Option.getOrUndefined(event.plan.baseUrl)
96
+ };
97
+ case "StepStarted": return {
98
+ type: "step:started",
99
+ title: event.title
100
+ };
101
+ case "StepCompleted": {
102
+ const step = context.stepMap.get(event.stepId);
103
+ const index = context.stepIndexMap.get(event.stepId) ?? -1;
104
+ return step ? {
105
+ type: "step:passed",
106
+ step: buildStepResult(step, context.artifacts.screenshotPaths, index)
107
+ } : void 0;
108
+ }
109
+ case "StepFailed": {
110
+ const step = context.stepMap.get(event.stepId);
111
+ const index = context.stepIndexMap.get(event.stepId) ?? -1;
112
+ return step ? {
113
+ type: "step:failed",
114
+ step: buildStepResult(step, context.artifacts.screenshotPaths, index)
115
+ } : void 0;
116
+ }
117
+ case "StepSkipped": return {
118
+ type: "step:skipped",
119
+ title: context.stepMap.get(event.stepId)?.title ?? event.stepId,
120
+ reason: event.reason
121
+ };
122
+ case "ToolResult": return event.toolName.endsWith("__screenshot") && !event.isError ? {
123
+ type: "screenshot",
124
+ title: event.toolName,
125
+ path: event.result
126
+ } : void 0;
127
+ case "RunFinished": return {
128
+ type: "completed",
129
+ result: buildTestResult(context.executed, context.url, context.startedAt, context.artifacts)
130
+ };
131
+ default: return;
132
+ }
133
+ };
134
+ const diffEvents = (previous, current, executed, url, startedAt) => {
135
+ const context = {
136
+ stepMap: new Map(executed.steps.map((step) => [step.id, step])),
137
+ stepIndexMap: new Map(executed.steps.map((step, index) => [step.id, index])),
138
+ artifacts: extractArtifacts(executed.events),
139
+ executed,
140
+ url,
141
+ startedAt
142
+ };
143
+ return current.slice(previous.length).map((event) => mapExecutionEvent(event, context)).filter((event) => event !== void 0);
144
+ };
145
+ //#endregion
146
+ //#region src/constants.ts
147
+ const DEFAULT_TIMEOUT_MS = 300 * 1e3;
148
+ const DEFAULT_AGENT_BACKEND = "claude";
149
+ //#endregion
150
+ export { diffEvents as a, buildInstruction as c, ExpectTimeoutError as d, buildTestResult as i, resolveUrl as l, DEFAULT_TIMEOUT_MS as n, extractArtifacts as o, buildStepResult as r, layerSdk as s, DEFAULT_AGENT_BACKEND as t, ExpectConfigError as u };
151
+
152
+ //# sourceMappingURL=constants-DFJAD4-F.mjs.map