@reshotdev/screenshot 0.0.1-beta.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/LICENSE +190 -0
- package/README.md +388 -0
- package/package.json +64 -0
- package/src/commands/auth.js +259 -0
- package/src/commands/chrome.js +140 -0
- package/src/commands/ci-run.js +123 -0
- package/src/commands/ci-setup.js +288 -0
- package/src/commands/drifts.js +423 -0
- package/src/commands/import-tests.js +309 -0
- package/src/commands/ingest.js +458 -0
- package/src/commands/init.js +633 -0
- package/src/commands/publish.js +1721 -0
- package/src/commands/pull.js +303 -0
- package/src/commands/record.js +94 -0
- package/src/commands/run.js +476 -0
- package/src/commands/setup-wizard.js +740 -0
- package/src/commands/setup.js +137 -0
- package/src/commands/status.js +275 -0
- package/src/commands/sync.js +621 -0
- package/src/commands/ui.js +248 -0
- package/src/commands/validate-docs.js +529 -0
- package/src/index.js +462 -0
- package/src/lib/api-client.js +815 -0
- package/src/lib/capture-engine.js +1623 -0
- package/src/lib/capture-script-runner.js +3120 -0
- package/src/lib/ci-detect.js +137 -0
- package/src/lib/config.js +1240 -0
- package/src/lib/diff-engine.js +642 -0
- package/src/lib/hash.js +74 -0
- package/src/lib/image-crop.js +396 -0
- package/src/lib/matrix.js +89 -0
- package/src/lib/output-path-template.js +318 -0
- package/src/lib/playwright-runner.js +252 -0
- package/src/lib/polished-clip.js +553 -0
- package/src/lib/privacy-engine.js +408 -0
- package/src/lib/progress-tracker.js +142 -0
- package/src/lib/record-browser-injection.js +654 -0
- package/src/lib/record-cdp.js +612 -0
- package/src/lib/record-clip.js +343 -0
- package/src/lib/record-config.js +623 -0
- package/src/lib/record-screenshot.js +360 -0
- package/src/lib/record-terminal.js +123 -0
- package/src/lib/recorder-service.js +781 -0
- package/src/lib/secrets.js +51 -0
- package/src/lib/selector-strategies.js +859 -0
- package/src/lib/standalone-mode.js +400 -0
- package/src/lib/storage-providers.js +569 -0
- package/src/lib/style-engine.js +684 -0
- package/src/lib/ui-api.js +4677 -0
- package/src/lib/ui-assets.js +373 -0
- package/src/lib/ui-executor.js +587 -0
- package/src/lib/variant-injector.js +591 -0
- package/src/lib/viewport-presets.js +454 -0
- package/src/lib/worker-pool.js +118 -0
- package/web/cropper/index.html +436 -0
- package/web/manager/dist/assets/index--ZgioErz.js +507 -0
- package/web/manager/dist/assets/index-n468W0Wr.css +1 -0
- package/web/manager/dist/index.html +27 -0
- package/web/subtitle-editor/index.html +295 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
// import-tests.js - Import existing Playwright tests into Reshot configuration
|
|
2
|
+
// This command scans Playwright tests and creates journey mappings
|
|
3
|
+
|
|
4
|
+
const chalk = require("chalk");
|
|
5
|
+
const fs = require("fs-extra");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const inquirer = require("inquirer");
|
|
8
|
+
const config = require("../lib/config");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse Playwright test file to extract test structure
|
|
12
|
+
*/
|
|
13
|
+
function parsePlaywrightTestFile(filePath) {
|
|
14
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
15
|
+
const tests = [];
|
|
16
|
+
|
|
17
|
+
// Extract journey key from file header comment if present
|
|
18
|
+
const journeyMatch = content.match(/Journey\s*Key:\s*["']?([^"'\n]+)["']?/i);
|
|
19
|
+
const fileJourneyKey = journeyMatch ? journeyMatch[1].trim() : null;
|
|
20
|
+
|
|
21
|
+
// Extract test.describe blocks
|
|
22
|
+
const describeRegex = /test\.describe\s*\(\s*["'`]([^"'`]+)["'`]/g;
|
|
23
|
+
let describeMatch;
|
|
24
|
+
while ((describeMatch = describeRegex.exec(content)) !== null) {
|
|
25
|
+
tests.push({
|
|
26
|
+
type: "describe",
|
|
27
|
+
name: describeMatch[1],
|
|
28
|
+
index: describeMatch.index,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Extract individual tests
|
|
33
|
+
const testRegex = /(?<!\.describe\s*\()test\s*\(\s*["'`]([^"'`]+)["'`]/g;
|
|
34
|
+
let testMatch;
|
|
35
|
+
while ((testMatch = testRegex.exec(content)) !== null) {
|
|
36
|
+
tests.push({
|
|
37
|
+
type: "test",
|
|
38
|
+
name: testMatch[1],
|
|
39
|
+
index: testMatch.index,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Sort by position in file
|
|
44
|
+
tests.sort((a, b) => a.index - b.index);
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
filePath,
|
|
48
|
+
fileJourneyKey,
|
|
49
|
+
tests,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Generate a journey key from test/describe name
|
|
55
|
+
*/
|
|
56
|
+
function generateJourneyKey(fileName, testName, describeName = null) {
|
|
57
|
+
// Clean up the file name to get a prefix
|
|
58
|
+
const filePrefix = fileName
|
|
59
|
+
.replace(/^\d+-/, "") // Remove leading numbers like "01-"
|
|
60
|
+
.replace(/\.spec\.(ts|js)$/, "")
|
|
61
|
+
.replace(/\.test\.(ts|js)$/, "")
|
|
62
|
+
.replace(/[^a-z0-9]+/gi, "-")
|
|
63
|
+
.toLowerCase();
|
|
64
|
+
|
|
65
|
+
// Clean up test name
|
|
66
|
+
const testSuffix = testName
|
|
67
|
+
.replace(/^should\s+/i, "")
|
|
68
|
+
.replace(/[^a-z0-9]+/gi, "-")
|
|
69
|
+
.toLowerCase()
|
|
70
|
+
.slice(0, 30);
|
|
71
|
+
|
|
72
|
+
return `${filePrefix}/${testSuffix}`
|
|
73
|
+
.replace(/-+/g, "-")
|
|
74
|
+
.replace(/^-|-$/g, "");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Discover all Playwright test files
|
|
79
|
+
*/
|
|
80
|
+
function discoverTestFiles(testDir) {
|
|
81
|
+
const testFiles = [];
|
|
82
|
+
|
|
83
|
+
if (!fs.existsSync(testDir)) {
|
|
84
|
+
return testFiles;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function walkDir(dir) {
|
|
88
|
+
const items = fs.readdirSync(dir);
|
|
89
|
+
|
|
90
|
+
for (const item of items) {
|
|
91
|
+
const fullPath = path.join(dir, item);
|
|
92
|
+
const stat = fs.statSync(fullPath);
|
|
93
|
+
|
|
94
|
+
if (stat.isDirectory()) {
|
|
95
|
+
if (item !== "node_modules" && !item.startsWith(".")) {
|
|
96
|
+
walkDir(fullPath);
|
|
97
|
+
}
|
|
98
|
+
} else if (
|
|
99
|
+
item.endsWith(".spec.ts") ||
|
|
100
|
+
item.endsWith(".spec.js") ||
|
|
101
|
+
item.endsWith(".test.ts") ||
|
|
102
|
+
item.endsWith(".test.js")
|
|
103
|
+
) {
|
|
104
|
+
testFiles.push(fullPath);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
walkDir(testDir);
|
|
110
|
+
return testFiles;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Find Playwright config and extract test directory
|
|
115
|
+
*/
|
|
116
|
+
function findPlaywrightConfig() {
|
|
117
|
+
const configFiles = [
|
|
118
|
+
"playwright.config.ts",
|
|
119
|
+
"playwright.config.js",
|
|
120
|
+
"playwright.config.mjs",
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
for (const file of configFiles) {
|
|
124
|
+
const fullPath = path.join(process.cwd(), file);
|
|
125
|
+
if (fs.existsSync(fullPath)) {
|
|
126
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
127
|
+
|
|
128
|
+
// Try to extract testDir
|
|
129
|
+
const testDirMatch = content.match(/testDir:\s*["'`]([^"'`]+)["'`]/);
|
|
130
|
+
const testDir = testDirMatch ? testDirMatch[1] : "./tests";
|
|
131
|
+
|
|
132
|
+
// Try to extract output directory
|
|
133
|
+
const outputDirMatch = content.match(/outputDir:\s*["'`]([^"'`]+)["'`]/);
|
|
134
|
+
const outputDir = outputDirMatch ? outputDirMatch[1] : "./test-results";
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
configFile: file,
|
|
138
|
+
testDir,
|
|
139
|
+
outputDir,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Main import-tests command
|
|
149
|
+
*/
|
|
150
|
+
async function importTestsCommand(options = {}) {
|
|
151
|
+
const { interactive = true, dryRun = false } = options;
|
|
152
|
+
|
|
153
|
+
console.log(chalk.cyan.bold("\n📋 Import Playwright Tests\n"));
|
|
154
|
+
|
|
155
|
+
// Find Playwright configuration
|
|
156
|
+
const pwConfig = findPlaywrightConfig();
|
|
157
|
+
|
|
158
|
+
if (!pwConfig) {
|
|
159
|
+
console.error(chalk.red("✖ No Playwright configuration found."));
|
|
160
|
+
console.log(
|
|
161
|
+
chalk.gray(
|
|
162
|
+
" Make sure you have a playwright.config.ts or playwright.config.js file.",
|
|
163
|
+
),
|
|
164
|
+
);
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.log(chalk.gray(`Found: ${pwConfig.configFile}`));
|
|
169
|
+
console.log(chalk.gray(`Test directory: ${pwConfig.testDir}`));
|
|
170
|
+
console.log(chalk.gray(`Output directory: ${pwConfig.outputDir}\n`));
|
|
171
|
+
|
|
172
|
+
// Discover test files
|
|
173
|
+
const testDir = path.resolve(process.cwd(), pwConfig.testDir);
|
|
174
|
+
const testFiles = discoverTestFiles(testDir);
|
|
175
|
+
|
|
176
|
+
if (testFiles.length === 0) {
|
|
177
|
+
console.log(
|
|
178
|
+
chalk.yellow("⚠ No test files found in"),
|
|
179
|
+
chalk.cyan(pwConfig.testDir),
|
|
180
|
+
);
|
|
181
|
+
process.exit(0);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log(chalk.green(`Found ${testFiles.length} test file(s):\n`));
|
|
185
|
+
|
|
186
|
+
// Parse all test files
|
|
187
|
+
const allTests = [];
|
|
188
|
+
for (const filePath of testFiles) {
|
|
189
|
+
const relativePath = path.relative(process.cwd(), filePath);
|
|
190
|
+
const parsed = parsePlaywrightTestFile(filePath);
|
|
191
|
+
|
|
192
|
+
console.log(chalk.white(` ${relativePath}`));
|
|
193
|
+
if (parsed.fileJourneyKey) {
|
|
194
|
+
console.log(chalk.gray(` └─ Journey Key: ${parsed.fileJourneyKey}`));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
for (const test of parsed.tests) {
|
|
198
|
+
if (test.type === "describe") {
|
|
199
|
+
console.log(chalk.gray(` ├─ describe: "${test.name}"`));
|
|
200
|
+
} else {
|
|
201
|
+
console.log(chalk.gray(` │ └─ test: "${test.name}"`));
|
|
202
|
+
|
|
203
|
+
allTests.push({
|
|
204
|
+
file: relativePath,
|
|
205
|
+
fileName: path.basename(filePath),
|
|
206
|
+
describeName: null, // TODO: Track describe context
|
|
207
|
+
testName: test.name,
|
|
208
|
+
fileJourneyKey: parsed.fileJourneyKey,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
console.log();
|
|
215
|
+
|
|
216
|
+
// Generate journey mappings
|
|
217
|
+
const journeyMappings = {};
|
|
218
|
+
|
|
219
|
+
for (const test of allTests) {
|
|
220
|
+
// Use file-level journey key if available, otherwise generate
|
|
221
|
+
const journeyKey =
|
|
222
|
+
test.fileJourneyKey || generateJourneyKey(test.fileName, test.testName);
|
|
223
|
+
|
|
224
|
+
// Create a test-results path pattern for this test
|
|
225
|
+
// Playwright creates folders like: test-results/test-name-chromium/
|
|
226
|
+
const testResultPattern = test.testName
|
|
227
|
+
.toLowerCase()
|
|
228
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
229
|
+
.slice(0, 50);
|
|
230
|
+
|
|
231
|
+
journeyMappings[testResultPattern] = journeyKey;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Show proposed mappings
|
|
235
|
+
console.log(chalk.cyan("━━━ Proposed Journey Mappings ━━━\n"));
|
|
236
|
+
|
|
237
|
+
for (const [pattern, journeyKey] of Object.entries(journeyMappings)) {
|
|
238
|
+
console.log(chalk.white(` ${pattern}`));
|
|
239
|
+
console.log(chalk.gray(` → ${journeyKey}\n`));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (dryRun) {
|
|
243
|
+
console.log(chalk.yellow("\n✓ Dry run complete. No changes made.\n"));
|
|
244
|
+
return { journeyMappings };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Confirm save
|
|
248
|
+
if (interactive) {
|
|
249
|
+
const { confirm } = await inquirer.prompt([
|
|
250
|
+
{
|
|
251
|
+
type: "confirm",
|
|
252
|
+
name: "confirm",
|
|
253
|
+
message: "Save these mappings to docsync.config.json?",
|
|
254
|
+
default: true,
|
|
255
|
+
},
|
|
256
|
+
]);
|
|
257
|
+
|
|
258
|
+
if (!confirm) {
|
|
259
|
+
console.log(chalk.gray("\nCancelled."));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Update docsync.config.json
|
|
265
|
+
let docSyncConfig;
|
|
266
|
+
try {
|
|
267
|
+
// Try to read existing config (use readDocSyncConfig which is less strict)
|
|
268
|
+
docSyncConfig = config.readDocSyncConfig();
|
|
269
|
+
} catch {
|
|
270
|
+
// Create new config with minimal required fields
|
|
271
|
+
docSyncConfig = {
|
|
272
|
+
$schema: "https://reshot.dev/schemas/docsync-config.json",
|
|
273
|
+
version: "2.0",
|
|
274
|
+
scenarios: [],
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Add visuals section with trace mappings
|
|
279
|
+
docSyncConfig.visuals = {
|
|
280
|
+
...docSyncConfig.visuals,
|
|
281
|
+
traceDir: pwConfig.outputDir,
|
|
282
|
+
journeyMappings,
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// Ensure scenarios array exists for config.readConfig() compatibility
|
|
286
|
+
if (!docSyncConfig.scenarios) {
|
|
287
|
+
docSyncConfig.scenarios = [];
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
config.writeConfig(docSyncConfig);
|
|
291
|
+
|
|
292
|
+
console.log(
|
|
293
|
+
chalk.green("\n✓ Updated docsync.config.json with journey mappings"),
|
|
294
|
+
);
|
|
295
|
+
console.log(chalk.gray("\nNext steps:"));
|
|
296
|
+
console.log(
|
|
297
|
+
chalk.gray(" 1. Run your Playwright tests:"),
|
|
298
|
+
chalk.cyan("npx playwright test"),
|
|
299
|
+
);
|
|
300
|
+
console.log(
|
|
301
|
+
chalk.gray(" 2. Sync traces to Reshot:"),
|
|
302
|
+
chalk.cyan("reshot sync"),
|
|
303
|
+
);
|
|
304
|
+
console.log(chalk.gray(" 3. View results:"), chalk.cyan("reshot status\n"));
|
|
305
|
+
|
|
306
|
+
return { journeyMappings };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
module.exports = importTestsCommand;
|