@testivai/witness-playwright 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @testivai/witness-playwright
2
2
 
3
- **Status**: ✅ Production Ready | **Last Updated**: December 21, 2025
3
+ **Status**: ✅ Production Ready | **Last Updated**: January 9, 2026
4
4
 
5
5
  **Project:** @testivai/witness-playwright (MVP - 1 Month Plan)
6
6
 
@@ -16,6 +16,19 @@ This package provides two main exports:
16
16
 
17
17
  To use the reporter, you need to configure it in your `playwright.config.ts` file. You must also provide your API URL and Key via environment variables (`TESTIVAI_API_URL` and `TESTIVAI_API_KEY`).
18
18
 
19
+ **Get Your API Key:**
20
+ 1. Go to your TestivAI dashboard
21
+ 2. Create a new project
22
+ 3. Copy your API key (format: `tstvai-xxxxxxxxxxxx`)
23
+
24
+ **Environment Setup:**
25
+ ```bash
26
+ # Create .env file
27
+ echo "TESTIVAI_API_KEY=tstvai-your-key-here" > .env
28
+ ```
29
+
30
+ **Note:** The SDK automatically uses the production API URL. You only need to set `TESTIVAI_API_KEY`.
31
+
19
32
  ```typescript
20
33
  // playwright.config.ts
21
34
  import { defineConfig } from '@playwright/test';
package/dist/cli/init.js CHANGED
@@ -126,11 +126,17 @@ async function createConfigFile() {
126
126
  console.log('📁 Config file:', configPath);
127
127
  console.log('');
128
128
  console.log('📖 Next steps:');
129
- console.log(' 1. Review and customize the configuration in testivai.config.ts');
130
- console.log(' 2. Update your playwright.config.ts to use TestivAI reporter');
131
- console.log(' 3. Run your tests with: npx playwright test');
129
+ console.log(' 1. Set up your API key:');
130
+ console.log(' TESTIVAI_API_KEY=tstvai-your-key-here');
132
131
  console.log('');
133
- console.log('💡 Need help? Check the comments in testivai.config.ts for examples');
132
+ console.log(' 2. Update your playwright.config.ts to use TestivAI reporter:');
133
+ console.log(' reporter: [[\'@testivai/witness-playwright/reporter\']]');
134
+ console.log('');
135
+ console.log(' 3. Review and customize testivai.config.ts');
136
+ console.log(' 4. Run your tests: npx playwright test');
137
+ console.log('');
138
+ console.log('💡 Get your API key from: https://dashboard-147980626268.us-central1.run.app');
139
+ console.log('💡 The SDK automatically connects to the production API - no URL configuration needed!');
134
140
  }
135
141
  catch (error) {
136
142
  console.error('❌ Failed to create configuration file:', error);
package/dist/index.d.ts CHANGED
@@ -3,5 +3,4 @@ export declare const testivai: {
3
3
  witness: typeof snapshot;
4
4
  };
5
5
  export * from './types';
6
- export * from './reporter';
7
6
  export * from './ci';
package/dist/index.js CHANGED
@@ -20,5 +20,4 @@ exports.testivai = {
20
20
  witness: snapshot_1.snapshot,
21
21
  };
22
22
  __exportStar(require("./types"), exports);
23
- __exportStar(require("./reporter"), exports);
24
23
  __exportStar(require("./ci"), exports);
@@ -0,0 +1,2 @@
1
+ import { TestivAIPlaywrightReporter } from './reporter';
2
+ export = TestivAIPlaywrightReporter;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ // Entry point for Playwright reporter
3
+ // Playwright expects: module.exports = ReporterClass
4
+ const reporter_1 = require("./reporter");
5
+ module.exports = reporter_1.TestivAIPlaywrightReporter;
@@ -13,4 +13,4 @@ export declare class TestivAIPlaywrightReporter implements Reporter {
13
13
  onBegin(config: FullConfig, suite: Suite): Promise<void>;
14
14
  onEnd(result: FullResult): Promise<void>;
15
15
  }
16
- export {};
16
+ export default TestivAIPlaywrightReporter;
package/dist/reporter.js CHANGED
@@ -49,13 +49,14 @@ class TestivAIPlaywrightReporter {
49
49
  this.runId = null;
50
50
  this.tempDir = path.join(process.cwd(), '.testivai', 'temp');
51
51
  this.options = {
52
- apiUrl: options.apiUrl || process.env.TESTIVAI_API_URL,
52
+ apiUrl: options.apiUrl || process.env.TESTIVAI_API_URL || 'https://core-api-147980626268.us-central1.run.app',
53
53
  apiKey: options.apiKey || process.env.TESTIVAI_API_KEY,
54
54
  };
55
55
  }
56
56
  async onBegin(config, suite) {
57
- if (!this.options.apiUrl || !this.options.apiKey) {
58
- console.error('Testivai Reporter: API URL or API Key is not configured. Disabling reporter.');
57
+ if (!this.options.apiKey) {
58
+ console.error('Testivai Reporter: API Key is not configured. Disabling reporter.');
59
+ console.error('Set TESTIVAI_API_KEY environment variable or pass apiKey in reporter options.');
59
60
  this.options.apiUrl = undefined; // Disable reporter
60
61
  return;
61
62
  }
@@ -111,10 +112,23 @@ class TestivAIPlaywrightReporter {
111
112
  const metadata = await fs.readJson(metadataPath);
112
113
  const domPath = metadata.files.dom;
113
114
  const screenshotPath = metadata.files.screenshot;
115
+ // Extract the first selector's layout data (usually 'body')
116
+ const layoutKeys = Object.keys(metadata.layout || {});
117
+ if (layoutKeys.length === 0) {
118
+ console.warn(`Testivai Reporter: No layout data found for ${metadata.snapshotName}, skipping...`);
119
+ continue;
120
+ }
121
+ const firstSelector = layoutKeys[0];
122
+ const layoutData = metadata.layout[firstSelector];
114
123
  const snapshotPayload = {
115
124
  ...metadata,
116
125
  dom: { html: await fs.readFile(domPath, 'utf-8') },
117
- layout: metadata.layout,
126
+ layout: {
127
+ x: layoutData.x,
128
+ y: layoutData.y,
129
+ width: layoutData.width,
130
+ height: layoutData.height
131
+ },
118
132
  testivaiConfig: metadata.testivaiConfig
119
133
  };
120
134
  snapshots.push(snapshotPayload);
@@ -129,9 +143,12 @@ class TestivAIPlaywrightReporter {
129
143
  };
130
144
  // Start batch and get upload URLs
131
145
  const startBatchResponse = await axios_1.default.post(`${this.options.apiUrl}/api/v1/ingest/start-batch`, batchPayload, {
132
- headers: { 'Authorization': `Bearer ${this.options.apiKey}` },
146
+ headers: { 'X-API-KEY': this.options.apiKey },
133
147
  });
134
- const { batchId, uploadInstructions } = startBatchResponse.data;
148
+ console.log('Testivai Reporter: API Response:', JSON.stringify(startBatchResponse.data, null, 2));
149
+ // Handle both snake_case and camelCase response formats
150
+ const batchId = startBatchResponse.data.batch_id || startBatchResponse.data.batchId;
151
+ const uploadInstructions = startBatchResponse.data.upload_instructions || startBatchResponse.data.uploadInstructions;
135
152
  // Upload files
136
153
  const uploadPromises = filesToUpload.map((file, index) => {
137
154
  const instruction = uploadInstructions[index];
@@ -140,7 +157,7 @@ class TestivAIPlaywrightReporter {
140
157
  await Promise.all(uploadPromises);
141
158
  // Finalize batch
142
159
  await axios_1.default.post(`${this.options.apiUrl}/api/v1/ingest/finish-batch/${batchId}`, {}, {
143
- headers: { 'Authorization': `Bearer ${this.options.apiKey}` },
160
+ headers: { 'X-API-KEY': this.options.apiKey },
144
161
  });
145
162
  console.log(`Testivai Reporter: Successfully uploaded ${snapshots.length} snapshots with Batch ID: ${batchId}`);
146
163
  // Clean up temp files
@@ -148,8 +165,14 @@ class TestivAIPlaywrightReporter {
148
165
  console.log('Testivai Reporter: Cleaned up temporary evidence files.');
149
166
  }
150
167
  catch (error) {
151
- console.error('Testivai Reporter: An error occurred during the onEnd hook:', error);
168
+ console.error('Testivai Reporter: An error occurred during the onEnd hook:', error.message);
169
+ console.error('Error stack:', error.stack);
170
+ if (error.response) {
171
+ console.error('Response status:', error.response.status);
172
+ console.error('Response data:', JSON.stringify(error.response.data, null, 2));
173
+ }
152
174
  }
153
175
  }
154
176
  }
155
177
  exports.TestivAIPlaywrightReporter = TestivAIPlaywrightReporter;
178
+ exports.default = TestivAIPlaywrightReporter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testivai/witness-playwright",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Playwright sensor for Testivai Visual Regression Test system",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "exports": {
11
11
  ".": "./dist/index.js",
12
- "./reporter": "./dist/reporter.js",
12
+ "./reporter": "./dist/reporter-entry.js",
13
13
  "./cli": "./dist/cli/init.js"
14
14
  },
15
15
  "scripts": {
package/progress.md CHANGED
@@ -612,9 +612,60 @@ The Playwright SDK provides two main components that are production-ready:
612
612
 
613
613
  ---
614
614
 
615
- **Last Updated**: December 17, 2025
616
- **Status**: 🎉 MVP COMPLETE ✅ - Production ready
615
+ ## NPM Publication & API Key Format Update (January 9, 2026)
616
+
617
+ ### SDK Published to npm ✅ COMPLETE
618
+
619
+ **Goal**: Publish SDK to npm registry for public consumption and update documentation for new API key format.
620
+
621
+ #### Changes Implemented
622
+
623
+ 1. **NPM Publication** ✅
624
+ - Published `@testivai/witness-playwright@0.1.0` to npm registry
625
+ - Package now publicly available: https://www.npmjs.com/package/@testivai/witness-playwright
626
+ - Users can install via: `npm install @testivai/witness-playwright`
627
+
628
+ 2. **Documentation Updates** ✅
629
+ - Updated README.md with new API key format (`tstvai-xxxxxxxxxxxx`)
630
+ - Added "Get Your API Key" section with step-by-step instructions
631
+ - Added environment setup examples
632
+ - Updated all code examples to show correct usage
633
+
634
+ 3. **Integration Tests** ✅
635
+ - Created visual regression tests in `integration-tests/tests/visual/`
636
+ - Tests use published npm package (not local file reference)
637
+ - All 10 visual tests passing
638
+ - Tests capture dashboard snapshots and send to TestivAI backend
639
+
640
+ 4. **Example Usage** ✅
641
+ ```typescript
642
+ import { test } from '@playwright/test';
643
+ import { testivai } from '@testivai/witness-playwright';
644
+
645
+ test('visual test', async ({ page }, testInfo) => {
646
+ await page.goto('https://example.com');
647
+ await testivai.witness(page, testInfo, 'homepage');
648
+ });
649
+ ```
650
+
651
+ #### API Key Format
652
+ - **New Format**: `tstvai-{32-character-secure-random-string}`
653
+ - **Example**: `tstvai-Ml5Ahr4vxHNht9WJPZ0LndDBQIkEfT9OvpXqB-NGjOs`
654
+ - **Masked Display**: `tstvai-**************NGjOs` (last 6 chars visible)
655
+
656
+ #### Files Updated
657
+ - `README.md` - Added API key format and setup instructions
658
+ - `package.json` - Published version 0.1.0 to npm
659
+ - `integration-tests/package.json` - Uses npm package instead of local file
660
+ - `integration-tests/tests/visual/dashboard-visual.spec.ts` - Example visual tests
661
+
662
+ ---
663
+
664
+ **Last Updated**: January 9, 2026
665
+ **Status**: 🎉 PUBLISHED TO NPM ✅ - Publicly available
666
+ **NPM Package**: @testivai/witness-playwright@0.1.0
617
667
  **Core Features**: Evidence capture and batch upload fully functional
618
668
  **Configuration**: ✅ COMPLETE - End-to-end flow working
669
+ **API Key Format**: tstvai-{secure-random-string}
619
670
  **Known Issues**: Minor UX improvements (retry logic, progress reporting)
620
671
  **Blocker**: None - All critical features implemented
package/src/cli/init.ts CHANGED
@@ -96,11 +96,17 @@ async function createConfigFile(): Promise<void> {
96
96
  console.log('📁 Config file:', configPath);
97
97
  console.log('');
98
98
  console.log('📖 Next steps:');
99
- console.log(' 1. Review and customize the configuration in testivai.config.ts');
100
- console.log(' 2. Update your playwright.config.ts to use TestivAI reporter');
101
- console.log(' 3. Run your tests with: npx playwright test');
99
+ console.log(' 1. Set up your API key:');
100
+ console.log(' TESTIVAI_API_KEY=tstvai-your-key-here');
102
101
  console.log('');
103
- console.log('💡 Need help? Check the comments in testivai.config.ts for examples');
102
+ console.log(' 2. Update your playwright.config.ts to use TestivAI reporter:');
103
+ console.log(' reporter: [[\'@testivai/witness-playwright/reporter\']]');
104
+ console.log('');
105
+ console.log(' 3. Review and customize testivai.config.ts');
106
+ console.log(' 4. Run your tests: npx playwright test');
107
+ console.log('');
108
+ console.log('💡 Get your API key from: https://dashboard-147980626268.us-central1.run.app');
109
+ console.log('💡 The SDK automatically connects to the production API - no URL configuration needed!');
104
110
 
105
111
  } catch (error) {
106
112
  console.error('❌ Failed to create configuration file:', error);
package/src/index.ts CHANGED
@@ -5,5 +5,4 @@ export const testivai = {
5
5
  };
6
6
 
7
7
  export * from './types';
8
- export * from './reporter';
9
8
  export * from './ci';
@@ -0,0 +1,6 @@
1
+ // Entry point for Playwright reporter
2
+ // Playwright expects: module.exports = ReporterClass
3
+ import { TestivAIPlaywrightReporter } from './reporter';
4
+
5
+ // This will compile to: module.exports = TestivAIPlaywrightReporter
6
+ export = TestivAIPlaywrightReporter;
package/src/reporter.ts CHANGED
@@ -20,14 +20,15 @@ export class TestivAIPlaywrightReporter implements Reporter {
20
20
 
21
21
  constructor(options: TestivaiReporterOptions = {}) {
22
22
  this.options = {
23
- apiUrl: options.apiUrl || process.env.TESTIVAI_API_URL,
23
+ apiUrl: options.apiUrl || process.env.TESTIVAI_API_URL || 'https://core-api-147980626268.us-central1.run.app',
24
24
  apiKey: options.apiKey || process.env.TESTIVAI_API_KEY,
25
25
  };
26
26
  }
27
27
 
28
28
  async onBegin(config: FullConfig, suite: Suite): Promise<void> {
29
- if (!this.options.apiUrl || !this.options.apiKey) {
30
- console.error('Testivai Reporter: API URL or API Key is not configured. Disabling reporter.');
29
+ if (!this.options.apiKey) {
30
+ console.error('Testivai Reporter: API Key is not configured. Disabling reporter.');
31
+ console.error('Set TESTIVAI_API_KEY environment variable or pass apiKey in reporter options.');
31
32
  this.options.apiUrl = undefined; // Disable reporter
32
33
  return;
33
34
  }
@@ -94,10 +95,24 @@ export class TestivAIPlaywrightReporter implements Reporter {
94
95
  const domPath = metadata.files.dom;
95
96
  const screenshotPath = metadata.files.screenshot;
96
97
 
98
+ // Extract the first selector's layout data (usually 'body')
99
+ const layoutKeys = Object.keys(metadata.layout || {});
100
+ if (layoutKeys.length === 0) {
101
+ console.warn(`Testivai Reporter: No layout data found for ${metadata.snapshotName}, skipping...`);
102
+ continue;
103
+ }
104
+ const firstSelector = layoutKeys[0];
105
+ const layoutData = metadata.layout[firstSelector];
106
+
97
107
  const snapshotPayload: SnapshotPayload = {
98
108
  ...metadata,
99
109
  dom: { html: await fs.readFile(domPath, 'utf-8') },
100
- layout: metadata.layout,
110
+ layout: {
111
+ x: layoutData.x,
112
+ y: layoutData.y,
113
+ width: layoutData.width,
114
+ height: layoutData.height
115
+ },
101
116
  testivaiConfig: metadata.testivaiConfig
102
117
  };
103
118
  snapshots.push(snapshotPayload);
@@ -115,10 +130,14 @@ export class TestivAIPlaywrightReporter implements Reporter {
115
130
 
116
131
  // Start batch and get upload URLs
117
132
  const startBatchResponse = await axios.post(`${this.options.apiUrl}/api/v1/ingest/start-batch`, batchPayload, {
118
- headers: { 'Authorization': `Bearer ${this.options.apiKey}` },
133
+ headers: { 'X-API-KEY': this.options.apiKey },
119
134
  });
120
135
 
121
- const { batchId, uploadInstructions } = startBatchResponse.data;
136
+ console.log('Testivai Reporter: API Response:', JSON.stringify(startBatchResponse.data, null, 2));
137
+
138
+ // Handle both snake_case and camelCase response formats
139
+ const batchId = startBatchResponse.data.batch_id || startBatchResponse.data.batchId;
140
+ const uploadInstructions = startBatchResponse.data.upload_instructions || startBatchResponse.data.uploadInstructions;
122
141
 
123
142
  // Upload files
124
143
  const uploadPromises = filesToUpload.map((file, index) => {
@@ -132,7 +151,7 @@ export class TestivAIPlaywrightReporter implements Reporter {
132
151
 
133
152
  // Finalize batch
134
153
  await axios.post(`${this.options.apiUrl}/api/v1/ingest/finish-batch/${batchId}`, {}, {
135
- headers: { 'Authorization': `Bearer ${this.options.apiKey}` },
154
+ headers: { 'X-API-KEY': this.options.apiKey },
136
155
  });
137
156
 
138
157
  console.log(`Testivai Reporter: Successfully uploaded ${snapshots.length} snapshots with Batch ID: ${batchId}`);
@@ -141,8 +160,15 @@ export class TestivAIPlaywrightReporter implements Reporter {
141
160
  await fs.emptyDir(this.tempDir);
142
161
  console.log('Testivai Reporter: Cleaned up temporary evidence files.');
143
162
 
144
- } catch (error) {
145
- console.error('Testivai Reporter: An error occurred during the onEnd hook:', error);
163
+ } catch (error: any) {
164
+ console.error('Testivai Reporter: An error occurred during the onEnd hook:', error.message);
165
+ console.error('Error stack:', error.stack);
166
+ if (error.response) {
167
+ console.error('Response status:', error.response.status);
168
+ console.error('Response data:', JSON.stringify(error.response.data, null, 2));
169
+ }
146
170
  }
147
171
  }
148
172
  }
173
+
174
+ export default TestivAIPlaywrightReporter;
package/tsconfig.json CHANGED
@@ -7,6 +7,7 @@
7
7
  "outDir": "./dist",
8
8
  "strict": true,
9
9
  "esModuleInterop": true,
10
+ "allowSyntheticDefaultImports": true,
10
11
  "skipLibCheck": true,
11
12
  "forceConsistentCasingInFileNames": true,
12
13
  "resolveJsonModule": true,