jest-fuzzy 0.1.2 → 0.1.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.
Files changed (66) hide show
  1. package/README.md +55 -5
  2. package/dist/cjs/index.d.ts +2 -2
  3. package/dist/cjs/index.d.ts.map +1 -1
  4. package/dist/cjs/index.js +2 -0
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/matchers/index.d.ts +1 -0
  7. package/dist/cjs/matchers/index.d.ts.map +1 -1
  8. package/dist/cjs/matchers/index.js +3 -1
  9. package/dist/cjs/matchers/index.js.map +1 -1
  10. package/dist/cjs/matchers/toSemanticallyMatch.js +1 -1
  11. package/dist/cjs/matchers/toSemanticallyMatch.js.map +1 -1
  12. package/dist/cjs/matchers/toVisuallyMatch.d.ts +3 -0
  13. package/dist/cjs/matchers/toVisuallyMatch.d.ts.map +1 -0
  14. package/dist/cjs/matchers/toVisuallyMatch.js +62 -0
  15. package/dist/cjs/matchers/toVisuallyMatch.js.map +1 -0
  16. package/dist/cjs/providers/anthropic.d.ts +2 -1
  17. package/dist/cjs/providers/anthropic.d.ts.map +1 -1
  18. package/dist/cjs/providers/anthropic.js +46 -0
  19. package/dist/cjs/providers/anthropic.js.map +1 -1
  20. package/dist/cjs/providers/google.d.ts +2 -1
  21. package/dist/cjs/providers/google.d.ts.map +1 -1
  22. package/dist/cjs/providers/google.js +39 -0
  23. package/dist/cjs/providers/google.js.map +1 -1
  24. package/dist/cjs/providers/openai.d.ts +2 -1
  25. package/dist/cjs/providers/openai.d.ts.map +1 -1
  26. package/dist/cjs/providers/openai.js +46 -0
  27. package/dist/cjs/providers/openai.js.map +1 -1
  28. package/dist/cjs/types.d.ts +13 -1
  29. package/dist/cjs/types.d.ts.map +1 -1
  30. package/dist/cjs/utils/imageUtils.d.ts +8 -0
  31. package/dist/cjs/utils/imageUtils.d.ts.map +1 -0
  32. package/dist/cjs/utils/imageUtils.js +89 -0
  33. package/dist/cjs/utils/imageUtils.js.map +1 -0
  34. package/dist/esm/index.d.ts +2 -2
  35. package/dist/esm/index.d.ts.map +1 -1
  36. package/dist/esm/index.js +2 -0
  37. package/dist/esm/index.js.map +1 -1
  38. package/dist/esm/matchers/index.d.ts +1 -0
  39. package/dist/esm/matchers/index.d.ts.map +1 -1
  40. package/dist/esm/matchers/index.js +1 -0
  41. package/dist/esm/matchers/index.js.map +1 -1
  42. package/dist/esm/matchers/toSemanticallyMatch.js +1 -1
  43. package/dist/esm/matchers/toSemanticallyMatch.js.map +1 -1
  44. package/dist/esm/matchers/toVisuallyMatch.d.ts +3 -0
  45. package/dist/esm/matchers/toVisuallyMatch.d.ts.map +1 -0
  46. package/dist/esm/matchers/toVisuallyMatch.js +59 -0
  47. package/dist/esm/matchers/toVisuallyMatch.js.map +1 -0
  48. package/dist/esm/providers/anthropic.d.ts +2 -1
  49. package/dist/esm/providers/anthropic.d.ts.map +1 -1
  50. package/dist/esm/providers/anthropic.js +46 -0
  51. package/dist/esm/providers/anthropic.js.map +1 -1
  52. package/dist/esm/providers/google.d.ts +2 -1
  53. package/dist/esm/providers/google.d.ts.map +1 -1
  54. package/dist/esm/providers/google.js +39 -0
  55. package/dist/esm/providers/google.js.map +1 -1
  56. package/dist/esm/providers/openai.d.ts +2 -1
  57. package/dist/esm/providers/openai.d.ts.map +1 -1
  58. package/dist/esm/providers/openai.js +46 -0
  59. package/dist/esm/providers/openai.js.map +1 -1
  60. package/dist/esm/types.d.ts +13 -1
  61. package/dist/esm/types.d.ts.map +1 -1
  62. package/dist/esm/utils/imageUtils.d.ts +8 -0
  63. package/dist/esm/utils/imageUtils.d.ts.map +1 -0
  64. package/dist/esm/utils/imageUtils.js +81 -0
  65. package/dist/esm/utils/imageUtils.js.map +1 -0
  66. package/package.json +1 -1
package/README.md CHANGED
@@ -122,7 +122,7 @@ await expect("Hello! How can I help you today?").toSemanticallyMatch(
122
122
  | Option | Type | Default | Description |
123
123
  | ----------- | ----------------------- | --------- | ------------------------------------------ |
124
124
  | `threshold` | `"strict"` \| `"loose"` | `"loose"` | How strictly to judge semantic equivalence |
125
- | `context` | `string` | - | Additional context to help the LLM judge |
125
+ | `additionalContext` | `string` | - | Additional context to help the LLM judge |
126
126
 
127
127
  **Examples:**
128
128
 
@@ -137,9 +137,9 @@ await expect(response).toSemanticallyMatch("The capital of France is Paris", {
137
137
  threshold: "strict",
138
138
  });
139
139
 
140
- // With context
140
+ // With additional context
141
141
  await expect("Paris").toSemanticallyMatch("The capital of France", {
142
- context: "Testing a geography Q&A bot asking about France's capital",
142
+ additionalContext: "Testing a geography Q&A bot asking about France's capital",
143
143
  });
144
144
 
145
145
  // Negation
@@ -176,6 +176,56 @@ await expect(response).not.toSatisfy(
176
176
  );
177
177
  ```
178
178
 
179
+ ### `toVisuallyMatch(description, options?)`
180
+
181
+ Tests whether an image matches the given description using vision-capable LLMs.
182
+
183
+ **Supported inputs:**
184
+
185
+ - File path: `"./images/button.png"`
186
+ - URL: `"https://example.com/image.jpg"`
187
+ - Base64 string: `"iVBORw0KGgo..."`
188
+ - Buffer: `fs.readFileSync("./image.png")`
189
+
190
+ ```typescript
191
+ await expect("./screenshot.png").toVisuallyMatch("a login form with email and password fields");
192
+ ```
193
+
194
+ **Options:**
195
+
196
+ | Option | Type | Default | Description |
197
+ | ----------- | ---------------------------------------------------------- | --------- | -------------------------------------------- |
198
+ | `threshold` | `"strict"` \| `"loose"` | `"loose"` | How strictly to judge the visual match |
199
+ | `additionalContext` | `string` | - | Additional context to help the LLM judge |
200
+ | `mimeType` | `"image/jpeg"` \| `"image/png"` \| `"image/gif"` \| `"image/webp"` | auto | Override MIME type detection |
201
+
202
+ **Examples:**
203
+
204
+ ```typescript
205
+ import { readFileSync } from "fs";
206
+
207
+ // File path
208
+ await expect("./tests/screenshot.png").toVisuallyMatch("a blue button with white text");
209
+
210
+ // Buffer
211
+ const imageBuffer = readFileSync("./tests/chart.png");
212
+ await expect(imageBuffer).toVisuallyMatch("a bar chart showing sales data");
213
+
214
+ // With additional context
215
+ await expect("./tests/ui.png").toVisuallyMatch("shows an error state", {
216
+ additionalContext: "Testing error handling in a form validation component",
217
+ });
218
+
219
+ // With strict threshold
220
+ await expect("./tests/error-dialog.png").toVisuallyMatch(
221
+ "a dialog box with a red error icon and a 'Retry' button",
222
+ { threshold: "strict" }
223
+ );
224
+
225
+ // Negation
226
+ await expect("./tests/dashboard.png").not.toVisuallyMatch("contains sensitive user data");
227
+ ```
228
+
179
229
  ## Configuration
180
230
 
181
231
  ### API Keys
@@ -245,11 +295,11 @@ pleasant weather conditions, while the second describes heavy rainfall.
245
295
  await expect(response).toSatisfy("mentions the user's name 'John'");
246
296
  ```
247
297
 
248
- 2. **Provide context when the comparison needs domain knowledge:**
298
+ 2. **Provide additional context when the comparison needs domain knowledge:**
249
299
 
250
300
  ```typescript
251
301
  await expect("42").toSemanticallyMatch("The answer", {
252
- context: "Testing a Hitchhiker's Guide to the Galaxy trivia bot",
302
+ additionalContext: "Testing a Hitchhiker's Guide to the Galaxy trivia bot",
253
303
  });
254
304
  ```
255
305
 
@@ -1,5 +1,5 @@
1
1
  import { configure, getConfig, getProvider } from "./config.js";
2
- import type { JestFuzzyConfig, SemanticMatchOptions, ModelName, ApiKeys, LLMProvider } from "./types.js";
2
+ import type { JestFuzzyConfig, SemanticMatchOptions, VisualMatchOptions, ModelName, ApiKeys, LLMProvider } from "./types.js";
3
3
  export { configure, getConfig, getProvider };
4
- export type { JestFuzzyConfig, SemanticMatchOptions, ModelName, ApiKeys, LLMProvider, };
4
+ export type { JestFuzzyConfig, SemanticMatchOptions, VisualMatchOptions, ModelName, ApiKeys, LLMProvider, };
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,SAAS,EACT,OAAO,EACP,WAAW,EACZ,MAAM,YAAY,CAAC;AAUpB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AAC7C,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,SAAS,EACT,OAAO,EACP,WAAW,GACZ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAIhE,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,SAAS,EACT,OAAO,EACP,WAAW,EACZ,MAAM,YAAY,CAAC;AAWpB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AAC7C,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,SAAS,EACT,OAAO,EACP,WAAW,GACZ,CAAC"}
package/dist/cjs/index.js CHANGED
@@ -7,11 +7,13 @@ Object.defineProperty(exports, "getConfig", { enumerable: true, get: function ()
7
7
  Object.defineProperty(exports, "getProvider", { enumerable: true, get: function () { return config_js_1.getProvider; } });
8
8
  const toSemanticallyMatch_js_1 = require("./matchers/toSemanticallyMatch.js");
9
9
  const toSatisfy_js_1 = require("./matchers/toSatisfy.js");
10
+ const toVisuallyMatch_js_1 = require("./matchers/toVisuallyMatch.js");
10
11
  // Register matchers with Jest
11
12
  if (typeof expect !== "undefined" && expect.extend) {
12
13
  expect.extend({
13
14
  toSemanticallyMatch: toSemanticallyMatch_js_1.toSemanticallyMatch,
14
15
  toSatisfy: toSatisfy_js_1.toSatisfy,
16
+ toVisuallyMatch: toVisuallyMatch_js_1.toVisuallyMatch,
15
17
  });
16
18
  }
17
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAAgE;AAmBvD,0FAnBA,qBAAS,OAmBA;AAAE,0FAnBA,qBAAS,OAmBA;AAAE,4FAnBA,uBAAW,OAmBA;AAlB1C,8EAAwE;AACxE,0DAAoD;AASpD,8BAA8B;AAC9B,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;IACnD,MAAM,CAAC,MAAM,CAAC;QACZ,mBAAmB,EAAnB,4CAAmB;QACnB,SAAS,EAAT,wBAAS;KACV,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAAgE;AAsBvD,0FAtBA,qBAAS,OAsBA;AAAE,0FAtBA,qBAAS,OAsBA;AAAE,4FAtBA,uBAAW,OAsBA;AArB1C,8EAAwE;AACxE,0DAAoD;AACpD,sEAAgE;AAUhE,8BAA8B;AAC9B,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;IACnD,MAAM,CAAC,MAAM,CAAC;QACZ,mBAAmB,EAAnB,4CAAmB;QACnB,SAAS,EAAT,wBAAS;QACT,eAAe,EAAf,oCAAe;KAChB,CAAC,CAAC;AACL,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export { toSemanticallyMatch } from "./toSemanticallyMatch.js";
2
2
  export { toSatisfy } from "./toSatisfy.js";
3
+ export { toVisuallyMatch } from "./toVisuallyMatch.js";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/matchers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/matchers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toSatisfy = exports.toSemanticallyMatch = void 0;
3
+ exports.toVisuallyMatch = exports.toSatisfy = exports.toSemanticallyMatch = void 0;
4
4
  var toSemanticallyMatch_js_1 = require("./toSemanticallyMatch.js");
5
5
  Object.defineProperty(exports, "toSemanticallyMatch", { enumerable: true, get: function () { return toSemanticallyMatch_js_1.toSemanticallyMatch; } });
6
6
  var toSatisfy_js_1 = require("./toSatisfy.js");
7
7
  Object.defineProperty(exports, "toSatisfy", { enumerable: true, get: function () { return toSatisfy_js_1.toSatisfy; } });
8
+ var toVisuallyMatch_js_1 = require("./toVisuallyMatch.js");
9
+ Object.defineProperty(exports, "toVisuallyMatch", { enumerable: true, get: function () { return toVisuallyMatch_js_1.toVisuallyMatch; } });
8
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/matchers/index.ts"],"names":[],"mappings":";;;AAAA,mEAA+D;AAAtD,6HAAA,mBAAmB,OAAA;AAC5B,+CAA2C;AAAlC,yGAAA,SAAS,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/matchers/index.ts"],"names":[],"mappings":";;;AAAA,mEAA+D;AAAtD,6HAAA,mBAAmB,OAAA;AAC5B,+CAA2C;AAAlC,yGAAA,SAAS,OAAA;AAClB,2DAAuD;AAA9C,qHAAA,eAAe,OAAA"}
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toSemanticallyMatch = toSemanticallyMatch;
4
4
  const config_js_1 = require("../config.js");
5
5
  function buildPrompt(received, expected, options) {
6
- const contextLine = options.context ? `Context: ${options.context}\n` : "";
6
+ const contextLine = options.additionalContext ? `Additional Context: ${options.additionalContext}\n` : "";
7
7
  const threshold = options.threshold ?? "loose";
8
8
  return `Do these two texts have the same semantic meaning?
9
9
  ${contextLine}Strictness: ${threshold}
@@ -1 +1 @@
1
- {"version":3,"file":"toSemanticallyMatch.js","sourceRoot":"","sources":["../../../src/matchers/toSemanticallyMatch.ts"],"names":[],"mappings":";;AAoBA,kDAqCC;AAxDD,4CAA2C;AAE3C,SAAS,WAAW,CAClB,QAAgB,EAChB,QAAgB,EAChB,OAA6B;IAE7B,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC;IAE/C,OAAO;EACP,WAAW,eAAe,SAAS;;WAE1B,QAAQ;WACR,QAAQ;;6EAE0D,CAAC;AAC9E,CAAC;AAEM,KAAK,UAAU,mBAAmB,CAEvC,QAAiB,EACjB,QAAgB,EAChB,UAAgC,EAAE;IAElC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO;YACL,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,GAAG,EAAE,CACZ,kCAAkC,OAAO,QAAQ,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE;SACnF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,IAAA,uBAAW,GAAE,CAAC;IACrC,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAExD,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAE9D,OAAO;YACL,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,GAAG,EAAE;gBACZ,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,aAAa,QAAQ,gCAAgC,QAAQ,uBAAuB,WAAW,EAAE,CAAC;gBAC3G,CAAC;qBAAM,CAAC;oBACN,OAAO,aAAa,QAAQ,4BAA4B,QAAQ,uBAAuB,WAAW,EAAE,CAAC;gBACvG,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,GAAG,EAAE,CACZ,sCAAsC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;SACjG,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"toSemanticallyMatch.js","sourceRoot":"","sources":["../../../src/matchers/toSemanticallyMatch.ts"],"names":[],"mappings":";;AAoBA,kDAqCC;AAxDD,4CAA2C;AAE3C,SAAS,WAAW,CAClB,QAAgB,EAChB,QAAgB,EAChB,OAA6B;IAE7B,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,uBAAuB,OAAO,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1G,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC;IAE/C,OAAO;EACP,WAAW,eAAe,SAAS;;WAE1B,QAAQ;WACR,QAAQ;;6EAE0D,CAAC;AAC9E,CAAC;AAEM,KAAK,UAAU,mBAAmB,CAEvC,QAAiB,EACjB,QAAgB,EAChB,UAAgC,EAAE;IAElC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO;YACL,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,GAAG,EAAE,CACZ,kCAAkC,OAAO,QAAQ,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE;SACnF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,IAAA,uBAAW,GAAE,CAAC;IACrC,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAExD,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAE9D,OAAO;YACL,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,GAAG,EAAE;gBACZ,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,aAAa,QAAQ,gCAAgC,QAAQ,uBAAuB,WAAW,EAAE,CAAC;gBAC3G,CAAC;qBAAM,CAAC;oBACN,OAAO,aAAa,QAAQ,4BAA4B,QAAQ,uBAAuB,WAAW,EAAE,CAAC;gBACvG,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,GAAG,EAAE,CACZ,sCAAsC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;SACjG,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { VisualMatchOptions, MatcherResult } from "../types.js";
2
+ export declare function toVisuallyMatch(this: jest.MatcherContext, received: unknown, description: string, options?: VisualMatchOptions): Promise<MatcherResult>;
3
+ //# sourceMappingURL=toVisuallyMatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toVisuallyMatch.d.ts","sourceRoot":"","sources":["../../../src/matchers/toVisuallyMatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAa,MAAM,aAAa,CAAC;AAiBhF,wBAAsB,eAAe,CACnC,IAAI,EAAE,IAAI,CAAC,cAAc,EACzB,QAAQ,EAAE,OAAO,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,aAAa,CAAC,CAkDxB"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toVisuallyMatch = toVisuallyMatch;
4
+ const config_js_1 = require("../config.js");
5
+ const imageUtils_js_1 = require("../utils/imageUtils.js");
6
+ function buildPrompt(description, options) {
7
+ const contextLine = options.additionalContext ? `Additional Context: ${options.additionalContext}\n` : "";
8
+ const threshold = options.threshold ?? "loose";
9
+ return `Does this image match the following description?
10
+
11
+ Description: "${description}"
12
+
13
+ ${contextLine}Strictness: ${threshold}
14
+
15
+ Return verdict=true if the image matches the description, false otherwise.`;
16
+ }
17
+ async function toVisuallyMatch(received, description, options = {}) {
18
+ if (typeof received !== "string" && !Buffer.isBuffer(received)) {
19
+ return {
20
+ pass: false,
21
+ message: () => `Expected a string (file path, URL, or base64) or Buffer but received ${typeof received}`,
22
+ };
23
+ }
24
+ let imageData;
25
+ try {
26
+ imageData = await (0, imageUtils_js_1.normalizeImageInput)(received, options.mimeType);
27
+ }
28
+ catch (error) {
29
+ return {
30
+ pass: false,
31
+ message: () => `Failed to process image: ${error instanceof Error ? error.message : String(error)}`,
32
+ };
33
+ }
34
+ const provider = await (0, config_js_1.getProvider)();
35
+ const prompt = buildPrompt(description, options);
36
+ try {
37
+ const { verdict, explanation } = await provider.judgeImage(imageData, prompt);
38
+ return {
39
+ pass: verdict,
40
+ message: () => {
41
+ const inputDesc = typeof received === "string"
42
+ ? received.length > 50
43
+ ? `${received.slice(0, 50)}...`
44
+ : received
45
+ : "[Buffer]";
46
+ if (verdict) {
47
+ return `Expected image (${inputDesc}) NOT to visually match "${description}"\n\nLLM reasoning: ${explanation}`;
48
+ }
49
+ else {
50
+ return `Expected image (${inputDesc}) to visually match "${description}"\n\nLLM reasoning: ${explanation}`;
51
+ }
52
+ },
53
+ };
54
+ }
55
+ catch (error) {
56
+ return {
57
+ pass: false,
58
+ message: () => `Failed to evaluate visual match: ${error instanceof Error ? error.message : String(error)}`,
59
+ };
60
+ }
61
+ }
62
+ //# sourceMappingURL=toVisuallyMatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toVisuallyMatch.js","sourceRoot":"","sources":["../../../src/matchers/toVisuallyMatch.ts"],"names":[],"mappings":";;AAiBA,0CAuDC;AAvED,4CAA2C;AAC3C,0DAA6D;AAE7D,SAAS,WAAW,CAAC,WAAmB,EAAE,OAA2B;IACnE,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,uBAAuB,OAAO,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1G,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC;IAE/C,OAAO;;gBAEO,WAAW;;EAEzB,WAAW,eAAe,SAAS;;2EAEsC,CAAC;AAC5E,CAAC;AAEM,KAAK,UAAU,eAAe,CAEnC,QAAiB,EACjB,WAAmB,EACnB,UAA8B,EAAE;IAEhC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,OAAO;YACL,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,GAAG,EAAE,CACZ,wEAAwE,OAAO,QAAQ,EAAE;SAC5F,CAAC;IACJ,CAAC;IAED,IAAI,SAAoB,CAAC;IACzB,IAAI,CAAC;QACH,SAAS,GAAG,MAAM,IAAA,mCAAmB,EAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,GAAG,EAAE,CACZ,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;SACvF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,IAAA,uBAAW,GAAE,CAAC;IACrC,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAEjD,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAE9E,OAAO;YACL,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,GAAG,EAAE;gBACZ,MAAM,SAAS,GACb,OAAO,QAAQ,KAAK,QAAQ;oBAC1B,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,EAAE;wBACpB,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK;wBAC/B,CAAC,CAAC,QAAQ;oBACZ,CAAC,CAAC,UAAU,CAAC;gBAEjB,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,mBAAmB,SAAS,4BAA4B,WAAW,uBAAuB,WAAW,EAAE,CAAC;gBACjH,CAAC;qBAAM,CAAC;oBACN,OAAO,mBAAmB,SAAS,wBAAwB,WAAW,uBAAuB,WAAW,EAAE,CAAC;gBAC7G,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,GAAG,EAAE,CACZ,oCAAoC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;SAC/F,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -1,8 +1,9 @@
1
- import type { LLMProvider, JudgmentResult } from "../types.js";
1
+ import type { LLMProvider, JudgmentResult, ImageData } from "../types.js";
2
2
  export declare class AnthropicProvider implements LLMProvider {
3
3
  private apiKey;
4
4
  private constructor();
5
5
  static create(apiKey?: string): Promise<AnthropicProvider>;
6
6
  judge(prompt: string): Promise<JudgmentResult>;
7
+ judgeImage(imageData: ImageData, prompt: string): Promise<JudgmentResult>;
7
8
  }
8
9
  //# sourceMappingURL=anthropic.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAoB/D,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;WAIM,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAW1D,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAmCrD"}
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAoB1E,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;WAIM,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAW1D,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAoC9C,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAkDhF"}
@@ -61,6 +61,52 @@ class AnthropicProvider {
61
61
  const parsed = JSON.parse(text);
62
62
  return { verdict: parsed.verdict, explanation: parsed.explanation };
63
63
  }
64
+ async judgeImage(imageData, prompt) {
65
+ const response = await fetch(ANTHROPIC_API_URL, {
66
+ method: "POST",
67
+ headers: {
68
+ "content-type": "application/json",
69
+ "x-api-key": this.apiKey,
70
+ "anthropic-version": "2023-06-01",
71
+ "anthropic-beta": "structured-outputs-2025-11-13",
72
+ },
73
+ body: JSON.stringify({
74
+ model: "claude-haiku-4-5",
75
+ max_tokens: 1024,
76
+ messages: [
77
+ {
78
+ role: "user",
79
+ content: [
80
+ {
81
+ type: "image",
82
+ source: {
83
+ type: "base64",
84
+ media_type: imageData.mediaType,
85
+ data: imageData.base64,
86
+ },
87
+ },
88
+ { type: "text", text: prompt },
89
+ ],
90
+ },
91
+ ],
92
+ output_format: {
93
+ type: "json_schema",
94
+ schema: JUDGMENT_SCHEMA,
95
+ },
96
+ }),
97
+ });
98
+ if (!response.ok) {
99
+ const errorText = await response.text();
100
+ throw new Error(`jest-fuzzy: Anthropic API error (${response.status}): ${errorText}`);
101
+ }
102
+ const data = (await response.json());
103
+ const text = data.content?.[0]?.text;
104
+ if (!text) {
105
+ throw new Error("jest-fuzzy: Anthropic API returned no content");
106
+ }
107
+ const parsed = JSON.parse(text);
108
+ return { verdict: parsed.verdict, explanation: parsed.explanation };
109
+ }
64
110
  }
65
111
  exports.AnthropicProvider = AnthropicProvider;
66
112
  //# sourceMappingURL=anthropic.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/providers/anthropic.ts"],"names":[],"mappings":";;;AAEA,MAAM,iBAAiB,GAAG,uCAAuC,CAAC;AAElE,MAAM,eAAe,GAAG;IACtB,IAAI,EAAE,QAAiB;IACvB,UAAU,EAAE;QACV,OAAO,EAAE;YACP,IAAI,EAAE,SAAkB;YACxB,WAAW,EAAE,qDAAqD;SACnE;QACD,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,WAAW,EAAE,oCAAoC;SAClD;KACF;IACD,QAAQ,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC;IACpC,oBAAoB,EAAE,KAAK;CAC5B,CAAC;AAEF,MAAa,iBAAiB;IACpB,MAAM,CAAS;IAEvB,YAAoB,MAAc;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAe;QACjC,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;QACpD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,0DAA0D;gBACxD,gHAAgH,CACnH,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc;QACxB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,iBAAiB,EAAE;YAC9C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,mBAAmB,EAAE,YAAY;gBACjC,gBAAgB,EAAE,+BAA+B;aAClD;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,kBAAkB;gBACzB,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC7C,aAAa,EAAE;oBACb,IAAI,EAAE,aAAa;oBACnB,MAAM,EAAE,eAAe;iBACxB;aACF,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA2C,CAAC;QAC/E,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QAErC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA8C,CAAC;QAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;IACtE,CAAC;CACF;AArDD,8CAqDC"}
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/providers/anthropic.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
- import type { LLMProvider, JudgmentResult } from "../types.js";
1
+ import type { LLMProvider, JudgmentResult, ImageData } from "../types.js";
2
2
  export declare class GoogleProvider implements LLMProvider {
3
3
  private apiKey;
4
4
  private constructor();
5
5
  static create(apiKey?: string): Promise<GoogleProvider>;
6
6
  judge(prompt: string): Promise<JudgmentResult>;
7
+ judgeImage(imageData: ImageData, prompt: string): Promise<JudgmentResult>;
7
8
  }
8
9
  //# sourceMappingURL=google.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../src/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAmB/D,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;WAIM,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAWvD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAsCrD"}
1
+ {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../src/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAmB1E,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;WAIM,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAWvD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAuC9C,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CA8ChF"}
@@ -60,6 +60,45 @@ class GoogleProvider {
60
60
  const parsed = JSON.parse(text);
61
61
  return { verdict: parsed.verdict, explanation: parsed.explanation };
62
62
  }
63
+ async judgeImage(imageData, prompt) {
64
+ const url = `${GEMINI_API_URL}?key=${this.apiKey}`;
65
+ const response = await fetch(url, {
66
+ method: "POST",
67
+ headers: {
68
+ "Content-Type": "application/json",
69
+ },
70
+ body: JSON.stringify({
71
+ contents: [
72
+ {
73
+ parts: [
74
+ { text: prompt },
75
+ {
76
+ inline_data: {
77
+ mime_type: imageData.mediaType,
78
+ data: imageData.base64,
79
+ },
80
+ },
81
+ ],
82
+ },
83
+ ],
84
+ generationConfig: {
85
+ responseMimeType: "application/json",
86
+ responseSchema: JUDGMENT_SCHEMA,
87
+ },
88
+ }),
89
+ });
90
+ if (!response.ok) {
91
+ const errorText = await response.text();
92
+ throw new Error(`jest-fuzzy: Google API error (${response.status}): ${errorText}`);
93
+ }
94
+ const data = (await response.json());
95
+ const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
96
+ if (!text) {
97
+ throw new Error("jest-fuzzy: Google API returned no content");
98
+ }
99
+ const parsed = JSON.parse(text);
100
+ return { verdict: parsed.verdict, explanation: parsed.explanation };
101
+ }
63
102
  }
64
103
  exports.GoogleProvider = GoogleProvider;
65
104
  //# sourceMappingURL=google.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"google.js","sourceRoot":"","sources":["../../../src/providers/google.ts"],"names":[],"mappings":";;;AAEA,MAAM,cAAc,GAAG,0FAA0F,CAAC;AAElH,MAAM,eAAe,GAAG;IACtB,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,OAAO,EAAE;YACP,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,qDAAqD;SACnE;QACD,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,oCAAoC;SAClD;KACF;IACD,QAAQ,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC;CACrC,CAAC;AAEF,MAAa,cAAc;IACjB,MAAM,CAAS;IAEvB,YAAoB,MAAc;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAe;QACjC,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACjD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,gEAAgE;gBAC9D,0GAA0G,CAC7G,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc;QACxB,MAAM,GAAG,GAAG,GAAG,cAAc,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QAEnD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,QAAQ,EAAE;oBACR;wBACE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;qBAC1B;iBACF;gBACD,gBAAgB,EAAE;oBAChB,gBAAgB,EAAE,kBAAkB;oBACpC,cAAc,EAAE,eAAe;iBAChC;aACF,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CAAC,CAAC;QACrF,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAElC,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QAE7D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA8C,CAAC;QAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;IACtE,CAAC;CACF;AAxDD,wCAwDC"}
1
+ {"version":3,"file":"google.js","sourceRoot":"","sources":["../../../src/providers/google.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
- import type { LLMProvider, JudgmentResult } from "../types.js";
1
+ import type { LLMProvider, JudgmentResult, ImageData } from "../types.js";
2
2
  export declare class OpenAIProvider implements LLMProvider {
3
3
  private apiKey;
4
4
  private constructor();
5
5
  static create(apiKey?: string): Promise<OpenAIProvider>;
6
6
  judge(prompt: string): Promise<JudgmentResult>;
7
+ judgeImage(imageData: ImageData, prompt: string): Promise<JudgmentResult>;
7
8
  }
8
9
  //# sourceMappingURL=openai.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAoB/D,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;WAIM,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAWvD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAuCrD"}
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAoB1E,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;WAIM,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAWvD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAwC9C,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;CAoDhF"}
@@ -63,6 +63,52 @@ class OpenAIProvider {
63
63
  const parsed = JSON.parse(text);
64
64
  return { verdict: parsed.verdict, explanation: parsed.explanation };
65
65
  }
66
+ async judgeImage(imageData, prompt) {
67
+ const response = await fetch(OPENAI_API_URL, {
68
+ method: "POST",
69
+ headers: {
70
+ "Content-Type": "application/json",
71
+ Authorization: `Bearer ${this.apiKey}`,
72
+ },
73
+ body: JSON.stringify({
74
+ model: "gpt-4o-mini",
75
+ max_output_tokens: 1024,
76
+ input: [
77
+ {
78
+ role: "user",
79
+ content: [
80
+ { type: "text", text: prompt },
81
+ {
82
+ type: "image_url",
83
+ image_url: {
84
+ url: `data:${imageData.mediaType};base64,${imageData.base64}`,
85
+ },
86
+ },
87
+ ],
88
+ },
89
+ ],
90
+ text: {
91
+ format: {
92
+ type: "json_schema",
93
+ name: "judgment",
94
+ strict: true,
95
+ schema: JUDGMENT_SCHEMA,
96
+ },
97
+ },
98
+ }),
99
+ });
100
+ if (!response.ok) {
101
+ const errorText = await response.text();
102
+ throw new Error(`jest-fuzzy: OpenAI API error (${response.status}): ${errorText}`);
103
+ }
104
+ const data = (await response.json());
105
+ const text = data.output?.[0]?.content?.[0]?.text;
106
+ if (!text) {
107
+ throw new Error("jest-fuzzy: OpenAI API returned no content");
108
+ }
109
+ const parsed = JSON.parse(text);
110
+ return { verdict: parsed.verdict, explanation: parsed.explanation };
111
+ }
66
112
  }
67
113
  exports.OpenAIProvider = OpenAIProvider;
68
114
  //# sourceMappingURL=openai.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/providers/openai.ts"],"names":[],"mappings":";;;AAEA,MAAM,cAAc,GAAG,qCAAqC,CAAC;AAE7D,MAAM,eAAe,GAAG;IACtB,IAAI,EAAE,QAAiB;IACvB,UAAU,EAAE;QACV,OAAO,EAAE;YACP,IAAI,EAAE,SAAkB;YACxB,WAAW,EAAE,qDAAqD;SACnE;QACD,WAAW,EAAE;YACX,IAAI,EAAE,QAAiB;YACvB,WAAW,EAAE,oCAAoC;SAClD;KACF;IACD,QAAQ,EAAE,CAAC,SAAS,EAAE,aAAa,CAAU;IAC7C,oBAAoB,EAAE,KAAK;CAC5B,CAAC;AAEF,MAAa,cAAc;IACjB,MAAM,CAAS;IAEvB,YAAoB,MAAc;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAe;QACjC,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACjD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,oDAAoD;gBAClD,0GAA0G,CAC7G,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc;QACxB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,cAAc,EAAE;YAC3C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACvC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,aAAa;gBACpB,iBAAiB,EAAE,IAAI;gBACvB,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC1C,IAAI,EAAE;oBACJ,MAAM,EAAE;wBACN,IAAI,EAAE,aAAa;wBACnB,IAAI,EAAE,UAAU;wBAChB,MAAM,EAAE,IAAI;wBACZ,MAAM,EAAE,eAAe;qBACxB;iBACF;aACF,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CAAC,CAAC;QACrF,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAElC,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QAElD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA8C,CAAC;QAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;IACtE,CAAC;CACF;AAzDD,wCAyDC"}
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/providers/openai.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,9 @@
1
1
  export type ModelName = "claude-haiku-4-5" | "gemini-3-flash-preview" | "gpt-5-nano";
2
+ export type ImageMediaType = "image/jpeg" | "image/png" | "image/gif" | "image/webp";
3
+ export interface ImageData {
4
+ base64: string;
5
+ mediaType: ImageMediaType;
6
+ }
2
7
  export interface ApiKeys {
3
8
  anthropic?: string;
4
9
  google?: string;
@@ -10,7 +15,12 @@ export interface JestFuzzyConfig {
10
15
  }
11
16
  export interface SemanticMatchOptions {
12
17
  threshold?: "strict" | "loose";
13
- context?: string;
18
+ additionalContext?: string;
19
+ }
20
+ export interface VisualMatchOptions {
21
+ threshold?: "strict" | "loose";
22
+ additionalContext?: string;
23
+ mimeType?: ImageMediaType;
14
24
  }
15
25
  export interface JudgmentResult {
16
26
  verdict: boolean;
@@ -18,6 +28,7 @@ export interface JudgmentResult {
18
28
  }
19
29
  export interface LLMProvider {
20
30
  judge(prompt: string): Promise<JudgmentResult>;
31
+ judgeImage(imageData: ImageData, prompt: string): Promise<JudgmentResult>;
21
32
  }
22
33
  export interface MatcherResult {
23
34
  pass: boolean;
@@ -28,6 +39,7 @@ declare global {
28
39
  interface Matchers<R> {
29
40
  toSemanticallyMatch(expected: string, options?: SemanticMatchOptions): Promise<R>;
30
41
  toSatisfy(criteria: string): Promise<R>;
42
+ toVisuallyMatch(description: string, options?: VisualMatchOptions): Promise<R>;
31
43
  }
32
44
  }
33
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GACjB,kBAAkB,GAClB,wBAAwB,GACxB,YAAY,CAAC;AAEjB,MAAM,WAAW,OAAO;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,MAAM,CAAC;CACvB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,IAAI,CAAC;QACb,UAAU,QAAQ,CAAC,CAAC;YAClB,mBAAmB,CACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,CAAC,CAAC,CAAC;YACd,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;SACzC;KACF;CACF"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GACjB,kBAAkB,GAClB,wBAAwB,GACxB,YAAY,CAAC;AAEjB,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;AAErF,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,cAAc,CAAC;CAC3B;AAED,MAAM,WAAW,OAAO;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC/C,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,MAAM,CAAC;CACvB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,IAAI,CAAC;QACb,UAAU,QAAQ,CAAC,CAAC;YAClB,mBAAmB,CACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,CAAC,CAAC,CAAC;YACd,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACxC,eAAe,CACb,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,CAAC,CAAC,CAAC;SACf;KACF;CACF"}
@@ -0,0 +1,8 @@
1
+ import type { ImageMediaType, ImageData } from "../types.js";
2
+ export declare function isUrl(input: string): boolean;
3
+ export declare function isFilePath(input: string): boolean;
4
+ export declare function detectMimeTypeFromBase64(base64: string): ImageMediaType | null;
5
+ export declare function isBase64Image(input: string): boolean;
6
+ export declare function detectMimeTypeFromExtension(path: string): ImageMediaType | null;
7
+ export declare function normalizeImageInput(input: string | Buffer, mimeTypeOverride?: ImageMediaType): Promise<ImageData>;
8
+ //# sourceMappingURL=imageUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imageUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/imageUtils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7D,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAO5C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjD;AASD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAK9E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAe/E;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,gBAAgB,CAAC,EAAE,cAAc,GAChC,OAAO,CAAC,SAAS,CAAC,CAoCpB"}