@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 +14 -1
- package/dist/cli/init.js +10 -4
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/reporter-entry.d.ts +2 -0
- package/dist/reporter-entry.js +5 -0
- package/dist/reporter.d.ts +1 -1
- package/dist/reporter.js +31 -8
- package/package.json +2 -2
- package/progress.md +53 -2
- package/src/cli/init.ts +10 -4
- package/src/index.ts +0 -1
- package/src/reporter-entry.ts +6 -0
- package/src/reporter.ts +35 -9
- package/tsconfig.json +1 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @testivai/witness-playwright
|
|
2
2
|
|
|
3
|
-
**Status**: ✅ Production Ready | **Last Updated**:
|
|
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.
|
|
130
|
-
console.log('
|
|
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('
|
|
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
package/dist/index.js
CHANGED
package/dist/reporter.d.ts
CHANGED
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.
|
|
58
|
-
console.error('Testivai Reporter: API
|
|
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:
|
|
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: { '
|
|
146
|
+
headers: { 'X-API-KEY': this.options.apiKey },
|
|
133
147
|
});
|
|
134
|
-
|
|
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: { '
|
|
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.
|
|
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
|
-
|
|
616
|
-
|
|
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.
|
|
100
|
-
console.log('
|
|
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('
|
|
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
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.
|
|
30
|
-
console.error('Testivai Reporter: API
|
|
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:
|
|
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: { '
|
|
133
|
+
headers: { 'X-API-KEY': this.options.apiKey },
|
|
119
134
|
});
|
|
120
135
|
|
|
121
|
-
|
|
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: { '
|
|
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;
|