visual-ai-assertions 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -205,7 +205,8 @@ const result = await ai.compare(before, after, {
205
205
  instructions: ["Ignore date/time differences"],
206
206
  });
207
207
 
208
- // With AI-generated diff image (supported only by gemini-3-flash-preview)
208
+ // With AI-generated diff image (supported by gemini-3-flash-preview and gemini-3.5-flash;
209
+ // only gemini-3-flash-preview auto-enables it — pass diffImage: true explicitly for 3.5-flash)
209
210
  const result = await ai.compare(before, after, {
210
211
  diffImage: true,
211
212
  });
@@ -253,10 +254,10 @@ await ai.elementsVisible(screenshot, ["Submit button", "Nav bar", "Footer"]);
253
254
  // Check that UI elements are hidden
254
255
  await ai.elementsHidden(screenshot, ["Loading spinner", "Error modal"]);
255
256
 
256
- // Accessibility checks (contrast, readability, interactive visibility)
257
+ // Accessibility checks (contrast, readability, interactive visibility, color blindness, color-alone meaning)
257
258
  await ai.accessibility(screenshot);
258
259
  await ai.accessibility(screenshot, {
259
- checks: [Accessibility.CONTRAST, Accessibility.READABILITY],
260
+ checks: [Accessibility.CONTRAST, Accessibility.COLOR_BLINDNESS, Accessibility.COLOR_ALONE],
260
261
  });
261
262
 
262
263
  // Layout checks (overlap, overflow, alignment)
@@ -526,6 +527,7 @@ All listed models support image/vision input. Pass any model ID to the `model` c
526
527
 
527
528
  | Model | Model ID | Input $/MTok | Output $/MTok | Notes |
528
529
  | --------------------- | ------------------------------- | ------------ | ------------- | --------------------------------- |
530
+ | Gemini 3.5 Flash | `gemini-3.5-flash` | $1.50 | $9 | Strongest agentic & coding model |
529
531
  | Gemini 3.1 Pro | `gemini-3.1-pro-preview` | $2 | $12 | Preview — most advanced reasoning |
530
532
  | Gemini 3.1 Flash Lite | `gemini-3.1-flash-lite-preview` | $0.25 | $1.50 | Preview — lightweight and cheap |
531
533
  | Gemini 3 Flash | `gemini-3-flash-preview` | $0.50 | $3 | **Default** — fast and capable |
package/dist/index.cjs CHANGED
@@ -95,6 +95,7 @@ var Model = {
95
95
  GPT_5_MINI: "gpt-5-mini"
96
96
  },
97
97
  Google: {
98
+ GEMINI_3_5_FLASH: "gemini-3.5-flash",
98
99
  GEMINI_3_1_PRO_PREVIEW: "gemini-3.1-pro-preview",
99
100
  GEMINI_3_1_FLASH_LITE_PREVIEW: "gemini-3.1-flash-lite-preview",
100
101
  GEMINI_3_FLASH_PREVIEW: "gemini-3-flash-preview"
@@ -142,7 +143,11 @@ var Accessibility = {
142
143
  /** Detects text that is cut off, overlapping, too small, or obscured */
143
144
  READABILITY: "readability",
144
145
  /** Detects interactive elements that are not visually distinct */
145
- INTERACTIVE_VISIBILITY: "interactive-visibility"
146
+ INTERACTIVE_VISIBILITY: "interactive-visibility",
147
+ /** Detects color choices likely to be indistinguishable to viewers with common color vision deficiencies */
148
+ COLOR_BLINDNESS: "color-blindness",
149
+ /** Detects information conveyed by color alone, without a non-color cue (icon, text, pattern, position) */
150
+ COLOR_ALONE: "color-alone"
146
151
  };
147
152
 
148
153
  // src/errors.ts
@@ -467,12 +472,16 @@ var ALL_CHECKS = Object.values(Accessibility);
467
472
  var ACCESSIBILITY_ROLE = "Evaluate this screenshot for visual accessibility. Focus on what you can actually perceive \u2014 apparent contrast levels, text legibility, and visual distinctiveness of interactive elements.";
468
473
  var ACCESSIBILITY_EDGE_RULES = [
469
474
  "Do not state specific contrast ratios. Describe contrast as 'appears sufficient' or 'appears low'.",
470
- "Dark mode and light mode themes are both valid. Do not flag a valid dark theme as a contrast issue."
475
+ "Dark mode and light mode themes are both valid. Do not flag a valid dark theme as a contrast issue.",
476
+ "Purely decorative color (branding, backgrounds, gradients) is not a color-blindness or color-alone issue \u2014 only flag color usage that carries meaning a user must perceive to use the interface.",
477
+ "Only evaluate color cues that are visible in the screenshot. Do not assume hover/focus state colors exist if they are not shown."
471
478
  ];
472
479
  var CHECK_STATEMENTS = {
473
480
  [Accessibility.CONTRAST]: "All text and interactive elements appear to have sufficient color contrast \u2014 text is clearly readable against its background",
474
481
  [Accessibility.READABILITY]: "All text is readable \u2014 no text is cut off, overlapping, too small to read, or obscured by background images",
475
- [Accessibility.INTERACTIVE_VISIBILITY]: "All interactive elements (buttons, links, inputs) are clearly identifiable and visually distinct from non-interactive content"
482
+ [Accessibility.INTERACTIVE_VISIBILITY]: "All interactive elements (buttons, links, inputs) are clearly identifiable and visually distinct from non-interactive content",
483
+ [Accessibility.COLOR_BLINDNESS]: "Information conveyed by color remains distinguishable to viewers with common color vision deficiencies \u2014 status indicators, chart series, and other meaningful color pairings do not rely on hue combinations that are commonly confused (e.g., red/green, blue/purple)",
484
+ [Accessibility.COLOR_ALONE]: "Information conveyed by color is also conveyed through at least one non-color cue \u2014 text labels, icons, shapes, patterns, underlines, or position accompany any color-based meaning (e.g., required fields, error states, chart legends, link styling)"
476
485
  };
477
486
  function buildAccessibilityPrompt(options) {
478
487
  const checks = options?.checks ?? [...ALL_CHECKS];
@@ -993,6 +1002,10 @@ var PRICING_TABLE = {
993
1002
  inputPricePerToken: 0.25 / PER_MILLION,
994
1003
  outputPricePerToken: 2 / PER_MILLION
995
1004
  },
1005
+ [`${Provider.GOOGLE}:${Model.Google.GEMINI_3_5_FLASH}`]: {
1006
+ inputPricePerToken: 1.5 / PER_MILLION,
1007
+ outputPricePerToken: 9 / PER_MILLION
1008
+ },
996
1009
  [`${Provider.GOOGLE}:${Model.Google.GEMINI_3_1_PRO_PREVIEW}`]: {
997
1010
  inputPricePerToken: 2 / PER_MILLION,
998
1011
  outputPricePerToken: 12 / PER_MILLION
@@ -1079,15 +1092,19 @@ async function timedSendMessage(driver, images, prompt, options) {
1079
1092
 
1080
1093
  // src/core/diff.ts
1081
1094
  var import_sharp = __toESM(require("sharp"), 1);
1095
+ var DIFF_ALLOWED_MODELS = /* @__PURE__ */ new Set([
1096
+ Model.Google.GEMINI_3_FLASH_PREVIEW,
1097
+ Model.Google.GEMINI_3_5_FLASH
1098
+ ]);
1082
1099
  async function generateAiDiff(imgA, imgB, model, driver) {
1083
1100
  if (!driver.generateImage) {
1084
1101
  throw new VisualAIConfigError(
1085
1102
  "AI-generated diff images require a provider that supports image generation. Currently only the Google (Gemini) provider supports this."
1086
1103
  );
1087
1104
  }
1088
- if (model !== Model.Google.GEMINI_3_FLASH_PREVIEW) {
1105
+ if (!DIFF_ALLOWED_MODELS.has(model)) {
1089
1106
  throw new VisualAIConfigError(
1090
- "Annotated diff images are only supported when visualAI is configured with the Google model gemini-3-flash-preview."
1107
+ `Annotated diff images are only supported with these Google models: ${[...DIFF_ALLOWED_MODELS].join(", ")}.`
1091
1108
  );
1092
1109
  }
1093
1110
  const response = await driver.generateImage([imgA, imgB], buildAiDiffPrompt(), {