@testivai/witness 1.0.1 → 1.0.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 (92) hide show
  1. package/README.md +44 -13
  2. package/dist/baselines/index.d.ts +6 -0
  3. package/dist/baselines/index.d.ts.map +1 -0
  4. package/dist/baselines/index.js +9 -0
  5. package/dist/baselines/index.js.map +1 -0
  6. package/dist/baselines/store.d.ts +100 -0
  7. package/dist/baselines/store.d.ts.map +1 -0
  8. package/dist/baselines/store.js +298 -0
  9. package/dist/baselines/store.js.map +1 -0
  10. package/dist/bin/testivai.js +2 -0
  11. package/dist/bin/testivai.js.map +1 -1
  12. package/dist/browser/binding.d.ts.map +1 -1
  13. package/dist/browser/binding.js +173 -42
  14. package/dist/browser/binding.js.map +1 -1
  15. package/dist/browser/capture.d.ts.map +1 -1
  16. package/dist/browser/capture.js +7 -4
  17. package/dist/browser/capture.js.map +1 -1
  18. package/dist/commands/approve.d.ts +3 -0
  19. package/dist/commands/approve.d.ts.map +1 -0
  20. package/dist/commands/approve.js +94 -0
  21. package/dist/commands/approve.js.map +1 -0
  22. package/dist/commands/init.d.ts.map +1 -1
  23. package/dist/commands/init.js +53 -0
  24. package/dist/commands/init.js.map +1 -1
  25. package/dist/commands/run.d.ts.map +1 -1
  26. package/dist/commands/run.js +98 -0
  27. package/dist/commands/run.js.map +1 -1
  28. package/dist/config/index.d.ts +6 -0
  29. package/dist/config/index.d.ts.map +1 -0
  30. package/dist/config/index.js +14 -0
  31. package/dist/config/index.js.map +1 -0
  32. package/dist/config/local-config.d.ts +54 -0
  33. package/dist/config/local-config.d.ts.map +1 -0
  34. package/dist/config/local-config.js +130 -0
  35. package/dist/config/local-config.js.map +1 -0
  36. package/dist/diff/diff.d.ts +27 -0
  37. package/dist/diff/diff.d.ts.map +1 -0
  38. package/dist/diff/diff.js +216 -0
  39. package/dist/diff/diff.js.map +1 -0
  40. package/dist/diff/dom-diff.d.ts +85 -0
  41. package/dist/diff/dom-diff.d.ts.map +1 -0
  42. package/dist/diff/dom-diff.js +291 -0
  43. package/dist/diff/dom-diff.js.map +1 -0
  44. package/dist/diff/ignore.d.ts +22 -0
  45. package/dist/diff/ignore.d.ts.map +1 -0
  46. package/dist/diff/ignore.js +43 -0
  47. package/dist/diff/ignore.js.map +1 -0
  48. package/dist/diff/index.d.ts +18 -0
  49. package/dist/diff/index.d.ts.map +1 -0
  50. package/dist/diff/index.js +25 -0
  51. package/dist/diff/index.js.map +1 -0
  52. package/dist/diff/minimap.d.ts +23 -0
  53. package/dist/diff/minimap.d.ts.map +1 -0
  54. package/dist/diff/minimap.js +43 -0
  55. package/dist/diff/minimap.js.map +1 -0
  56. package/dist/diff/regions.d.ts +23 -0
  57. package/dist/diff/regions.d.ts.map +1 -0
  58. package/dist/diff/regions.js +129 -0
  59. package/dist/diff/regions.js.map +1 -0
  60. package/dist/diff/resize.d.ts +27 -0
  61. package/dist/diff/resize.d.ts.map +1 -0
  62. package/dist/diff/resize.js +82 -0
  63. package/dist/diff/resize.js.map +1 -0
  64. package/dist/diff/types.d.ts +79 -0
  65. package/dist/diff/types.d.ts.map +1 -0
  66. package/dist/diff/types.js +10 -0
  67. package/dist/diff/types.js.map +1 -0
  68. package/dist/index.d.ts +8 -0
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +23 -2
  71. package/dist/index.js.map +1 -1
  72. package/dist/report/compare.d.ts +18 -0
  73. package/dist/report/compare.d.ts.map +1 -0
  74. package/dist/report/compare.js +193 -0
  75. package/dist/report/compare.js.map +1 -0
  76. package/dist/report/generator.d.ts +31 -0
  77. package/dist/report/generator.d.ts.map +1 -0
  78. package/dist/report/generator.js +123 -0
  79. package/dist/report/generator.js.map +1 -0
  80. package/dist/report/index.d.ts +10 -0
  81. package/dist/report/index.d.ts.map +1 -0
  82. package/dist/report/index.js +13 -0
  83. package/dist/report/index.js.map +1 -0
  84. package/dist/report/results.d.ts +56 -0
  85. package/dist/report/results.d.ts.map +1 -0
  86. package/dist/report/results.js +8 -0
  87. package/dist/report/results.js.map +1 -0
  88. package/dist/report/template.d.ts +14 -0
  89. package/dist/report/template.d.ts.map +1 -0
  90. package/dist/report/template.js +275 -0
  91. package/dist/report/template.js.map +1 -0
  92. package/package.json +58 -15
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
18
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.VERSION = exports.compressionHelper = exports.CompressionHelper = exports.getOutputDir = exports.configExists = exports.loadConfig = exports.findConfigFile = exports.isAuthenticated = exports.getApiKey = exports.deleteCredentials = exports.loadCredentials = exports.saveCredentials = exports.DEFAULT_CORE_API_URL = exports.CoreApiClient = exports.witnessCommand = exports.runCommand = exports.initCommand = exports.authCommand = exports.FrameworkDetector = exports.commandExists = exports.setupSignalHandlers = exports.spawnProcess = exports.ProcessManager = exports.isSafeFilename = exports.sanitizeTestName = exports.extractNameFromUrl = exports.generateUniqueFilename = exports.toSafeFilename = exports.createLogger = exports.logger = exports.BrowserDiscoveryError = exports.BrowserDiscovery = exports.BrowserBinding = exports.BrowserCapture = exports.BrowserClient = void 0;
21
+ exports.VERSION = exports.compressionHelper = exports.CompressionHelper = exports.getOutputDir = exports.configExists = exports.loadConfig = exports.findConfigFile = exports.isAuthenticated = exports.getApiKey = exports.deleteCredentials = exports.loadCredentials = exports.saveCredentials = exports.DEFAULT_CORE_API_URL = exports.CoreApiClient = exports.approveCommand = exports.witnessCommand = exports.runCommand = exports.initCommand = exports.authCommand = exports.renderHtml = exports.compareAll = exports.generateReport = exports.getDefaultConfig = exports.getConfigPath = exports.isLocalMode = exports.localConfigExists = exports.createDefaultConfig = exports.loadLocalConfig = exports.BaselineStore = exports.FrameworkDetector = exports.commandExists = exports.setupSignalHandlers = exports.spawnProcess = exports.ProcessManager = exports.isSafeFilename = exports.sanitizeTestName = exports.extractNameFromUrl = exports.generateUniqueFilename = exports.toSafeFilename = exports.createLogger = exports.logger = exports.BrowserDiscoveryError = exports.BrowserDiscovery = exports.BrowserBinding = exports.BrowserCapture = exports.BrowserClient = void 0;
22
22
  // Export types
23
23
  __exportStar(require("./types"), exports);
24
24
  // Export browser modules
@@ -48,6 +48,24 @@ Object.defineProperty(exports, "setupSignalHandlers", { enumerable: true, get: f
48
48
  Object.defineProperty(exports, "commandExists", { enumerable: true, get: function () { return process_1.commandExists; } });
49
49
  var framework_detect_1 = require("./utils/framework-detect");
50
50
  Object.defineProperty(exports, "FrameworkDetector", { enumerable: true, get: function () { return framework_detect_1.FrameworkDetector; } });
51
+ // Export diff engine
52
+ __exportStar(require("./diff"), exports);
53
+ // Export baselines
54
+ var baselines_1 = require("./baselines");
55
+ Object.defineProperty(exports, "BaselineStore", { enumerable: true, get: function () { return baselines_1.BaselineStore; } });
56
+ // Export local config
57
+ var config_1 = require("./config");
58
+ Object.defineProperty(exports, "loadLocalConfig", { enumerable: true, get: function () { return config_1.loadLocalConfig; } });
59
+ Object.defineProperty(exports, "createDefaultConfig", { enumerable: true, get: function () { return config_1.createDefaultConfig; } });
60
+ Object.defineProperty(exports, "localConfigExists", { enumerable: true, get: function () { return config_1.localConfigExists; } });
61
+ Object.defineProperty(exports, "isLocalMode", { enumerable: true, get: function () { return config_1.isLocalMode; } });
62
+ Object.defineProperty(exports, "getConfigPath", { enumerable: true, get: function () { return config_1.getConfigPath; } });
63
+ Object.defineProperty(exports, "getDefaultConfig", { enumerable: true, get: function () { return config_1.getDefaultConfig; } });
64
+ // Export report generator
65
+ var report_1 = require("./report");
66
+ Object.defineProperty(exports, "generateReport", { enumerable: true, get: function () { return report_1.generateReport; } });
67
+ Object.defineProperty(exports, "compareAll", { enumerable: true, get: function () { return report_1.compareAll; } });
68
+ Object.defineProperty(exports, "renderHtml", { enumerable: true, get: function () { return report_1.renderHtml; } });
51
69
  // Export commands (for programmatic use)
52
70
  var auth_1 = require("./commands/auth");
53
71
  Object.defineProperty(exports, "authCommand", { enumerable: true, get: function () { return auth_1.authCommand; } });
@@ -57,6 +75,8 @@ var run_1 = require("./commands/run");
57
75
  Object.defineProperty(exports, "runCommand", { enumerable: true, get: function () { return run_1.runCommand; } });
58
76
  var capture_2 = require("./commands/capture");
59
77
  Object.defineProperty(exports, "witnessCommand", { enumerable: true, get: function () { return capture_2.witnessCommand; } });
78
+ var approve_1 = require("./commands/approve");
79
+ Object.defineProperty(exports, "approveCommand", { enumerable: true, get: function () { return approve_1.approveCommand; } });
60
80
  // Re-export common utilities
61
81
  var common_1 = require("@testivai/common");
62
82
  Object.defineProperty(exports, "CoreApiClient", { enumerable: true, get: function () { return common_1.CoreApiClient; } });
@@ -73,5 +93,6 @@ Object.defineProperty(exports, "getOutputDir", { enumerable: true, get: function
73
93
  Object.defineProperty(exports, "CompressionHelper", { enumerable: true, get: function () { return common_1.CompressionHelper; } });
74
94
  Object.defineProperty(exports, "compressionHelper", { enumerable: true, get: function () { return common_1.compressionHelper; } });
75
95
  // Version
76
- exports.VERSION = require('../../package.json').version;
96
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
97
+ exports.VERSION = require('../package.json').version;
77
98
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;AAEH,eAAe;AACf,0CAAwB;AAExB,yBAAyB;AACzB,2CAAiD;AAAxC,uGAAA,aAAa,OAAA;AACtB,6CAAmD;AAA1C,yGAAA,cAAc,OAAA;AACvB,6CAAmD;AAA1C,yGAAA,cAAc,OAAA;AACvB,iDAA8E;AAArE,6GAAA,gBAAgB,OAAA;AAAE,kHAAA,qBAAqB,OAAA;AAEhD,mBAAmB;AACnB,yCAAsD;AAA7C,gGAAA,MAAM,OAAA;AAAE,sGAAA,YAAY,OAAA;AAC7B,mDAAmI;AAA1H,6GAAA,cAAc,OAAA;AAAE,qHAAA,sBAAsB,OAAA;AAAE,iHAAA,kBAAkB,OAAA;AAAE,+GAAA,gBAAgB,OAAA;AAAE,6GAAA,cAAc,OAAA;AACrG,2CAAmG;AAA1F,yGAAA,cAAc,OAAA;AAAE,uGAAA,YAAY,OAAA;AAAE,8GAAA,mBAAmB,OAAA;AAAE,wGAAA,aAAa,OAAA;AACzE,6DAA6D;AAApD,qHAAA,iBAAiB,OAAA;AAE1B,yCAAyC;AACzC,wCAA8C;AAArC,mGAAA,WAAW,OAAA;AACpB,wCAA8C;AAArC,mGAAA,WAAW,OAAA;AACpB,sCAA4C;AAAnC,iGAAA,UAAU,OAAA;AACnB,8CAAoD;AAA3C,yGAAA,cAAc,OAAA;AAEvB,6BAA6B;AAC7B,2CAc0B;AAbxB,uGAAA,aAAa,OAAA;AACb,8GAAA,oBAAoB,OAAA;AACpB,yGAAA,eAAe,OAAA;AACf,yGAAA,eAAe,OAAA;AACf,2GAAA,iBAAiB,OAAA;AACjB,mGAAA,SAAS,OAAA;AACT,yGAAA,eAAe,OAAA;AACf,wGAAA,cAAc,OAAA;AACd,oGAAA,UAAU,OAAA;AACV,sGAAA,YAAY,OAAA;AACZ,sGAAA,YAAY,OAAA;AACZ,2GAAA,iBAAiB,OAAA;AACjB,2GAAA,iBAAiB,OAAA;AAGnB,UAAU;AACG,QAAA,OAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;AAEH,eAAe;AACf,0CAAwB;AAExB,yBAAyB;AACzB,2CAAiD;AAAxC,uGAAA,aAAa,OAAA;AACtB,6CAAmD;AAA1C,yGAAA,cAAc,OAAA;AACvB,6CAAmD;AAA1C,yGAAA,cAAc,OAAA;AACvB,iDAA8E;AAArE,6GAAA,gBAAgB,OAAA;AAAE,kHAAA,qBAAqB,OAAA;AAEhD,mBAAmB;AACnB,yCAAsD;AAA7C,gGAAA,MAAM,OAAA;AAAE,sGAAA,YAAY,OAAA;AAC7B,mDAAmI;AAA1H,6GAAA,cAAc,OAAA;AAAE,qHAAA,sBAAsB,OAAA;AAAE,iHAAA,kBAAkB,OAAA;AAAE,+GAAA,gBAAgB,OAAA;AAAE,6GAAA,cAAc,OAAA;AACrG,2CAAmG;AAA1F,yGAAA,cAAc,OAAA;AAAE,uGAAA,YAAY,OAAA;AAAE,8GAAA,mBAAmB,OAAA;AAAE,wGAAA,aAAa,OAAA;AACzE,6DAA6D;AAApD,qHAAA,iBAAiB,OAAA;AAE1B,qBAAqB;AACrB,yCAAuB;AAEvB,mBAAmB;AACnB,yCAA4C;AAAnC,0GAAA,aAAa,OAAA;AAGtB,sBAAsB;AACtB,mCAOkB;AANhB,yGAAA,eAAe,OAAA;AACf,6GAAA,mBAAmB,OAAA;AACnB,2GAAA,iBAAiB,OAAA;AACjB,qGAAA,WAAW,OAAA;AACX,uGAAA,aAAa,OAAA;AACb,0GAAA,gBAAgB,OAAA;AAIlB,0BAA0B;AAC1B,mCAAkE;AAAzD,wGAAA,cAAc,OAAA;AAAE,oGAAA,UAAU,OAAA;AAAE,oGAAA,UAAU,OAAA;AAG/C,yCAAyC;AACzC,wCAA8C;AAArC,mGAAA,WAAW,OAAA;AACpB,wCAA8C;AAArC,mGAAA,WAAW,OAAA;AACpB,sCAA4C;AAAnC,iGAAA,UAAU,OAAA;AACnB,8CAAoD;AAA3C,yGAAA,cAAc,OAAA;AACvB,8CAAoD;AAA3C,yGAAA,cAAc,OAAA;AAEvB,6BAA6B;AAC7B,2CAc0B;AAbxB,uGAAA,aAAa,OAAA;AACb,8GAAA,oBAAoB,OAAA;AACpB,yGAAA,eAAe,OAAA;AACf,yGAAA,eAAe,OAAA;AACf,2GAAA,iBAAiB,OAAA;AACjB,mGAAA,SAAS,OAAA;AACT,yGAAA,eAAe,OAAA;AACf,wGAAA,cAAc,OAAA;AACd,oGAAA,UAAU,OAAA;AACV,sGAAA,YAAY,OAAA;AACZ,sGAAA,YAAY,OAAA;AACZ,2GAAA,iBAAiB,OAAA;AACjB,2GAAA,iBAAiB,OAAA;AAGnB,UAAU;AACV,8DAA8D;AACjD,QAAA,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * TestivAI Report — Compare all snapshots
3
+ *
4
+ * Diffs all temp captures against baselines using the Phase 1 diff engine.
5
+ */
6
+ import { SnapshotResult } from './results';
7
+ export interface CompareOptions {
8
+ threshold?: number;
9
+ projectRoot: string;
10
+ reportDir: string;
11
+ }
12
+ /**
13
+ * Compare all temp screenshots against their baselines.
14
+ *
15
+ * @returns Array of SnapshotResult for each snapshot
16
+ */
17
+ export declare function compareAll(options: CompareOptions): SnapshotResult[];
18
+ //# sourceMappingURL=compare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../src/report/compare.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAqB,cAAc,EAAkB,MAAM,WAAW,CAAC;AAE9E,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,CAmEpE"}
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ /**
3
+ * TestivAI Report — Compare all snapshots
4
+ *
5
+ * Diffs all temp captures against baselines using the Phase 1 diff engine.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.compareAll = compareAll;
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ const diff_1 = require("../diff");
45
+ const dom_diff_1 = require("../diff/dom-diff");
46
+ const store_1 = require("../baselines/store");
47
+ /**
48
+ * Compare all temp screenshots against their baselines.
49
+ *
50
+ * @returns Array of SnapshotResult for each snapshot
51
+ */
52
+ function compareAll(options) {
53
+ const { projectRoot, reportDir, threshold = 0.1 } = options;
54
+ const store = new store_1.BaselineStore(projectRoot);
55
+ const tempNames = store.listTemp();
56
+ const results = [];
57
+ const imagesDir = path.join(reportDir, 'images');
58
+ for (const name of tempNames) {
59
+ const snapshotImagesDir = path.join(imagesDir, name);
60
+ fs.mkdirSync(snapshotImagesDir, { recursive: true });
61
+ const tempBuffer = store.readTemp(name);
62
+ if (!tempBuffer)
63
+ continue;
64
+ // Write current image to report
65
+ const currentPath = path.join(snapshotImagesDir, 'current.png');
66
+ fs.writeFileSync(currentPath, tempBuffer);
67
+ if (!store.exists(name)) {
68
+ // New snapshot — no baseline to compare against
69
+ results.push({
70
+ name,
71
+ status: 'new',
72
+ diffPercent: 0,
73
+ diffCount: 0,
74
+ totalPixels: 0,
75
+ currentPath: `images/${name}/current.png`,
76
+ });
77
+ continue;
78
+ }
79
+ // Read baseline
80
+ const baselineBuffer = store.read(name);
81
+ const baselinePath = path.join(snapshotImagesDir, 'baseline.png');
82
+ fs.writeFileSync(baselinePath, baselineBuffer);
83
+ // Parse raw RGBA from PNG buffers
84
+ // For now, we compare raw buffers directly. In a real implementation
85
+ // we'd decode PNGs to RGBA pixel data. Since temp/baseline are raw
86
+ // screenshots from the browser, we need to handle the PNG decoding.
87
+ // For simplicity and zero-dep, we do a byte-level comparison first,
88
+ // then fall back to diff engine for actual pixel data.
89
+ const result = compareBuffers(baselineBuffer, tempBuffer, name, snapshotImagesDir, threshold);
90
+ // DOM-level noise hint. Only meaningful when both sides captured DOM.
91
+ // For 'passed' (pixel-identical) we skip the work — it's already the
92
+ // strongest possible signal.
93
+ if (result.status === 'changed') {
94
+ const baselineDom = store.readDom(name);
95
+ const candidateDom = store.readTempDom(name);
96
+ const domSignal = computeDomSignal(baselineDom, candidateDom);
97
+ if (domSignal) {
98
+ result.dom = domSignal;
99
+ }
100
+ }
101
+ results.push(result);
102
+ }
103
+ return results;
104
+ }
105
+ /**
106
+ * Run DOM diff and turn it into a report-shaped signal.
107
+ *
108
+ * Returns null when DOM data isn't available on either side — we don't
109
+ * want to confuse the user with "DOM unchanged" hints when the adapter
110
+ * never captured DOM in the first place.
111
+ */
112
+ function computeDomSignal(baselineDom, candidateDom) {
113
+ if (!baselineDom || !candidateDom)
114
+ return null;
115
+ const result = (0, dom_diff_1.domDiff)(baselineDom, candidateDom);
116
+ return {
117
+ changed: result.domChanged,
118
+ summary: result.summary,
119
+ // The whole point: pixels differ, DOM does not → likely render noise.
120
+ noiseHint: !result.domChanged,
121
+ };
122
+ }
123
+ /**
124
+ * Compare two PNG buffers.
125
+ *
126
+ * If buffers are identical bytes, returns passed immediately.
127
+ * Otherwise attempts pixel-level diff using the diff engine.
128
+ */
129
+ function compareBuffers(baselineBuffer, candidateBuffer, name, snapshotImagesDir, threshold) {
130
+ // Quick byte-level comparison
131
+ if (baselineBuffer.equals(candidateBuffer)) {
132
+ return {
133
+ name,
134
+ status: 'passed',
135
+ diffPercent: 0,
136
+ diffCount: 0,
137
+ totalPixels: 0,
138
+ baselinePath: `images/${name}/baseline.png`,
139
+ currentPath: `images/${name}/current.png`,
140
+ };
141
+ }
142
+ // Buffers differ — attempt pixel-level diff
143
+ // We assume raw RGBA pixel data with known dimensions
144
+ // In practice, we need to decode PNGs first. For now, treat as raw RGBA.
145
+ // The actual PNG decoding will be added when fast-png is available.
146
+ try {
147
+ // Try to use as raw RGBA data
148
+ // Calculate dimensions assuming square-ish aspect ratio
149
+ const pixelCount = baselineBuffer.length / 4;
150
+ const width = Math.ceil(Math.sqrt(pixelCount));
151
+ const height = Math.ceil(pixelCount / width);
152
+ const expectedLen = width * height * 4;
153
+ // Pad buffers if needed
154
+ const baseline8 = new Uint8ClampedArray(expectedLen);
155
+ baseline8.set(new Uint8ClampedArray(baselineBuffer.buffer, baselineBuffer.byteOffset, Math.min(baselineBuffer.length, expectedLen)));
156
+ const candidate8 = new Uint8ClampedArray(expectedLen);
157
+ candidate8.set(new Uint8ClampedArray(candidateBuffer.buffer, candidateBuffer.byteOffset, Math.min(candidateBuffer.length, expectedLen)));
158
+ const diffOutput = new Uint8ClampedArray(expectedLen);
159
+ const diffResult = (0, diff_1.diff)(baseline8, candidate8, diffOutput, width, height, { threshold });
160
+ // Write diff image (raw RGBA for now)
161
+ const diffPath = path.join(snapshotImagesDir, 'diff.png');
162
+ fs.writeFileSync(diffPath, Buffer.from(diffOutput.buffer));
163
+ // We already know the raw bytes differ (byte-equal returns early above).
164
+ // If the pixel diff still reports identical (sub-threshold), the images
165
+ // are visually equivalent but binary-different — still flag as "changed"
166
+ // so the user is aware.
167
+ const status = 'changed';
168
+ const diffPercent = diffResult.diffPercent > 0 ? diffResult.diffPercent : 0.01;
169
+ return {
170
+ name,
171
+ status,
172
+ diffPercent,
173
+ diffCount: diffResult.diffCount,
174
+ totalPixels: diffResult.totalPixels,
175
+ baselinePath: `images/${name}/baseline.png`,
176
+ currentPath: `images/${name}/current.png`,
177
+ diffPath: `images/${name}/diff.png`,
178
+ };
179
+ }
180
+ catch {
181
+ // If pixel diff fails (e.g., not raw RGBA), fall back to binary comparison
182
+ return {
183
+ name,
184
+ status: 'changed',
185
+ diffPercent: 100,
186
+ diffCount: 0,
187
+ totalPixels: 0,
188
+ baselinePath: `images/${name}/baseline.png`,
189
+ currentPath: `images/${name}/current.png`,
190
+ };
191
+ }
192
+ }
193
+ //# sourceMappingURL=compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/report/compare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * TestivAI Report — Generator
3
+ *
4
+ * Orchestrator: compareAll → build ReportData → write results.json
5
+ * → render HTML → optionally auto-open browser.
6
+ */
7
+ import { ReportData } from './results';
8
+ export interface GenerateReportOptions {
9
+ projectRoot: string;
10
+ /** Directory for report output. Default: 'visual-report' */
11
+ reportDir?: string;
12
+ /** Diff threshold (0-1). Default: 0.1 */
13
+ threshold?: number;
14
+ /** Auto-open browser after generating. Default: true */
15
+ autoOpen?: boolean;
16
+ /** SDK version string for the report header */
17
+ version?: string;
18
+ }
19
+ /**
20
+ * Generate a complete visual regression report.
21
+ *
22
+ * 1. Compare all temp screenshots against baselines
23
+ * 2. Build ReportData with summary
24
+ * 3. Write results.json (machine-readable)
25
+ * 4. Render and write index.html
26
+ * 5. Optionally open in browser
27
+ *
28
+ * @returns The report data
29
+ */
30
+ export declare function generateReport(options: GenerateReportOptions): ReportData;
31
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/report/generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAAE,UAAU,EAAiB,MAAM,WAAW,CAAC;AAGtD,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,UAAU,CAuDzE"}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ /**
3
+ * TestivAI Report — Generator
4
+ *
5
+ * Orchestrator: compareAll → build ReportData → write results.json
6
+ * → render HTML → optionally auto-open browser.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.generateReport = generateReport;
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ const child_process_1 = require("child_process");
46
+ const compare_1 = require("./compare");
47
+ const template_1 = require("./template");
48
+ /**
49
+ * Generate a complete visual regression report.
50
+ *
51
+ * 1. Compare all temp screenshots against baselines
52
+ * 2. Build ReportData with summary
53
+ * 3. Write results.json (machine-readable)
54
+ * 4. Render and write index.html
55
+ * 5. Optionally open in browser
56
+ *
57
+ * @returns The report data
58
+ */
59
+ function generateReport(options) {
60
+ const { projectRoot, reportDir: reportDirRelative = 'visual-report', threshold = 0.1, autoOpen = true, version = '2.0.0', } = options;
61
+ const reportDir = path.isAbsolute(reportDirRelative)
62
+ ? reportDirRelative
63
+ : path.join(projectRoot, reportDirRelative);
64
+ // Ensure report directory exists
65
+ fs.mkdirSync(reportDir, { recursive: true });
66
+ // 1. Compare all snapshots
67
+ const compareOptions = {
68
+ projectRoot,
69
+ reportDir,
70
+ threshold,
71
+ };
72
+ const snapshots = (0, compare_1.compareAll)(compareOptions);
73
+ // 2. Build summary
74
+ const summary = {
75
+ total: snapshots.length,
76
+ passed: snapshots.filter((s) => s.status === 'passed').length,
77
+ changed: snapshots.filter((s) => s.status === 'changed').length,
78
+ newSnapshots: snapshots.filter((s) => s.status === 'new').length,
79
+ };
80
+ // 3. Build report data
81
+ const reportData = {
82
+ version,
83
+ timestamp: new Date().toISOString(),
84
+ summary,
85
+ snapshots,
86
+ };
87
+ // 4. Write results.json
88
+ const resultsPath = path.join(reportDir, 'results.json');
89
+ fs.writeFileSync(resultsPath, JSON.stringify(reportData, null, 2));
90
+ // 5. Render and write HTML
91
+ const html = (0, template_1.renderHtml)(reportData);
92
+ const htmlPath = path.join(reportDir, 'index.html');
93
+ fs.writeFileSync(htmlPath, html);
94
+ // 6. Auto-open browser
95
+ if (autoOpen) {
96
+ openInBrowser(htmlPath);
97
+ }
98
+ return reportData;
99
+ }
100
+ /**
101
+ * Open a file in the default browser.
102
+ * Best-effort — does not throw on failure.
103
+ */
104
+ function openInBrowser(filePath) {
105
+ const url = `file://${filePath}`;
106
+ const platform = process.platform;
107
+ let cmd;
108
+ if (platform === 'darwin') {
109
+ cmd = `open "${url}"`;
110
+ }
111
+ else if (platform === 'win32') {
112
+ cmd = `start "" "${url}"`;
113
+ }
114
+ else {
115
+ cmd = `xdg-open "${url}"`;
116
+ }
117
+ (0, child_process_1.exec)(cmd, (err) => {
118
+ if (err) {
119
+ // Silently ignore — CI environments won't have a browser
120
+ }
121
+ });
122
+ }
123
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/report/generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * TestivAI Report Generator
3
+ */
4
+ export { generateReport } from './generator';
5
+ export type { GenerateReportOptions } from './generator';
6
+ export { compareAll } from './compare';
7
+ export type { CompareOptions } from './compare';
8
+ export { renderHtml } from './template';
9
+ export type { ReportData, ReportSummary, SnapshotResult, SnapshotStatus, SnapshotDomSignal, } from './results';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/report/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,YAAY,EACV,UAAU,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /**
3
+ * TestivAI Report Generator
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.renderHtml = exports.compareAll = exports.generateReport = void 0;
7
+ var generator_1 = require("./generator");
8
+ Object.defineProperty(exports, "generateReport", { enumerable: true, get: function () { return generator_1.generateReport; } });
9
+ var compare_1 = require("./compare");
10
+ Object.defineProperty(exports, "compareAll", { enumerable: true, get: function () { return compare_1.compareAll; } });
11
+ var template_1 = require("./template");
12
+ Object.defineProperty(exports, "renderHtml", { enumerable: true, get: function () { return template_1.renderHtml; } });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/report/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,yCAA6C;AAApC,2GAAA,cAAc,OAAA;AAEvB,qCAAuC;AAA9B,qGAAA,UAAU,OAAA;AAEnB,uCAAwC;AAA/B,sGAAA,UAAU,OAAA"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * TestivAI Report — Result types
3
+ *
4
+ * Machine-readable output for the GitHub Action and other consumers.
5
+ */
6
+ export type SnapshotStatus = 'passed' | 'changed' | 'new';
7
+ export interface SnapshotDomSignal {
8
+ /** True if the DOM differs structurally between baseline and candidate. */
9
+ changed: boolean;
10
+ /** Per-bucket counts; null when changed is false. */
11
+ summary: {
12
+ added: number;
13
+ removed: number;
14
+ attributeChanges: number;
15
+ } | null;
16
+ /**
17
+ * Noise hint: pixel diff is non-zero but DOM is structurally unchanged.
18
+ * Suggests render noise (anti-aliasing, font hinting, sub-pixel layout)
19
+ * rather than a real visual regression.
20
+ */
21
+ noiseHint: boolean;
22
+ }
23
+ export interface SnapshotResult {
24
+ name: string;
25
+ status: SnapshotStatus;
26
+ /** Diff percentage (0-100). 0 for passed/new. */
27
+ diffPercent: number;
28
+ /** Number of changed pixels */
29
+ diffCount: number;
30
+ /** Total pixels compared */
31
+ totalPixels: number;
32
+ /** Relative path to baseline image (if any) */
33
+ baselinePath?: string;
34
+ /** Relative path to current (candidate) image */
35
+ currentPath?: string;
36
+ /** Relative path to diff image (if any) */
37
+ diffPath?: string;
38
+ /**
39
+ * DOM-level signal. Present only when both baseline and candidate
40
+ * captured DOM HTML alongside the screenshot.
41
+ */
42
+ dom?: SnapshotDomSignal;
43
+ }
44
+ export interface ReportSummary {
45
+ total: number;
46
+ passed: number;
47
+ changed: number;
48
+ newSnapshots: number;
49
+ }
50
+ export interface ReportData {
51
+ version: string;
52
+ timestamp: string;
53
+ summary: ReportSummary;
54
+ snapshots: SnapshotResult[];
55
+ }
56
+ //# sourceMappingURL=results.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"results.d.ts","sourceRoot":"","sources":["../../src/report/results.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAC;AAE1D,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAC;IACjB,qDAAqD;IACrD,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7E;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC;IACvB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,GAAG,CAAC,EAAE,iBAAiB,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,aAAa,CAAC;IACvB,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * TestivAI Report — Result types
4
+ *
5
+ * Machine-readable output for the GitHub Action and other consumers.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ //# sourceMappingURL=results.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"results.js","sourceRoot":"","sources":["../../src/report/results.ts"],"names":[],"mappings":";AAAA;;;;GAIG"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * TestivAI Report — HTML Template
3
+ *
4
+ * Single-file HTML with inlined CSS/JS.
5
+ * Dark navy sidebar, cyan accents, summary cards,
6
+ * Changed → New → Passed sections, 3-column diff view,
7
+ * approve command copy button, cloud upgrade CTA, image zoom overlay.
8
+ */
9
+ import { ReportData } from './results';
10
+ /**
11
+ * Render a standalone HTML report from report data.
12
+ */
13
+ export declare function renderHtml(data: ReportData): string;
14
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/report/template.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAkB,MAAM,WAAW,CAAC;AAEvD;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAuLnD"}