@reshotdev/screenshot 0.0.1-beta.11 → 0.0.1-beta.13

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 (66) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +84 -51
  3. package/package.json +20 -16
  4. package/src/commands/auth.js +38 -8
  5. package/src/commands/capture-dom.js +50 -0
  6. package/src/commands/compose.js +220 -0
  7. package/src/commands/doctor-target.js +36 -4
  8. package/src/commands/drifts.js +13 -1
  9. package/src/commands/publish.js +137 -12
  10. package/src/commands/pull.js +13 -8
  11. package/src/commands/refresh.js +166 -0
  12. package/src/commands/setup-wizard.js +35 -2
  13. package/src/commands/status.js +22 -2
  14. package/src/commands/variation.js +194 -0
  15. package/src/index.js +189 -47
  16. package/src/lib/api-client.js +61 -35
  17. package/src/lib/auto-update/refresh.js +598 -0
  18. package/src/lib/auto-update/scene-runtime.compose.tsx +73 -0
  19. package/src/lib/auto-update/spec.js +89 -0
  20. package/src/lib/capture-engine.js +73 -0
  21. package/src/lib/capture-script-runner.js +280 -134
  22. package/src/lib/certification.js +23 -1
  23. package/src/lib/compose-context.js +156 -0
  24. package/src/lib/compose-pack.js +42 -0
  25. package/src/lib/compose-runtime.js +34 -0
  26. package/src/lib/compose-upload.js +142 -0
  27. package/src/lib/config.js +5 -5
  28. package/src/lib/dom-capture.js +64 -0
  29. package/src/lib/output-path-template.js +3 -3
  30. package/src/lib/record-clip.js +83 -3
  31. package/src/lib/record-config.js +0 -4
  32. package/src/lib/resolve-targets.js +60 -0
  33. package/src/lib/run-manifest.js +45 -0
  34. package/src/lib/storage-providers.js +1 -1
  35. package/src/lib/style-engine.js +5 -5
  36. package/src/lib/ui-api-helpers.js +118 -0
  37. package/src/lib/ui-api.js +28 -820
  38. package/src/lib/ui-asset-cleanup.js +62 -0
  39. package/src/lib/ui-output-versions.js +165 -0
  40. package/src/lib/ui-recorder-routes.js +341 -0
  41. package/src/lib/ui-scenario-metadata.js +161 -0
  42. package/vendor/compose/dist/auto-update.cjs +5544 -0
  43. package/vendor/compose/dist/auto-update.mjs +5518 -0
  44. package/vendor/compose/dist/capture.cjs +1450 -0
  45. package/vendor/compose/dist/capture.mjs +1416 -0
  46. package/vendor/compose/dist/eligibility.cjs +5331 -0
  47. package/vendor/compose/dist/eligibility.mjs +5313 -0
  48. package/vendor/compose/dist/index.cjs +2046 -0
  49. package/vendor/compose/dist/index.mjs +1997 -0
  50. package/vendor/compose/dist/jsx-dev-runtime.cjs +55 -0
  51. package/vendor/compose/dist/jsx-dev-runtime.mjs +27 -0
  52. package/vendor/compose/dist/jsx-runtime.cjs +58 -0
  53. package/vendor/compose/dist/jsx-runtime.mjs +31 -0
  54. package/vendor/compose/dist/render.cjs +558 -0
  55. package/vendor/compose/dist/render.mjs +515 -0
  56. package/vendor/compose/dist/verify-cli.cjs +3806 -0
  57. package/vendor/compose/dist/verify-cli.mjs +3812 -0
  58. package/vendor/compose/dist/verify.cjs +3880 -0
  59. package/vendor/compose/dist/verify.mjs +3858 -0
  60. package/web/manager/dist/assets/{index-D2qqcFNN.js → index-D0S2otug.js} +56 -56
  61. package/web/manager/dist/index.html +1 -1
  62. package/src/commands/ci-run.js +0 -178
  63. package/src/commands/ci-setup.js +0 -288
  64. package/src/commands/ingest.js +0 -458
  65. package/src/commands/setup.js +0 -165
  66. package/src/lib/playwright-runner.js +0 -252
@@ -1,252 +0,0 @@
1
- // playwright-runner.js - Generic Playwright runner for executing steps
2
- const { chromium } = require("playwright");
3
- const path = require("path");
4
- const fs = require("fs-extra");
5
- const { buildLaunchOptions } = require("./ci-detect");
6
- const { resolveSecretsInObject } = require("./secrets");
7
-
8
- /**
9
- * Wait for element with retries and fallbacks
10
- * @param {Page} page - Playwright page
11
- * @param {string} selector - CSS selector
12
- * @param {Object} options - Options
13
- * @returns {Promise<Locator>}
14
- */
15
- async function waitForElement(page, selector, options = {}) {
16
- const { timeout = 10000, action = "interact" } = options;
17
-
18
- // First, wait for the page to be stable (no network activity)
19
- try {
20
- await page.waitForLoadState("networkidle", { timeout: 5000 });
21
- } catch (e) {
22
- // Continue even if networkidle times out
23
- }
24
-
25
- // Try the selector directly
26
- const locator = page.locator(selector);
27
-
28
- try {
29
- await locator.first().waitFor({ state: "visible", timeout });
30
- return locator.first();
31
- } catch (e) {
32
- // If selector fails, try some fallback strategies
33
- console.log(
34
- ` ⚠ Selector "${selector}" not immediately found, trying fallbacks...`
35
- );
36
-
37
- // Strategy 1: Wait a bit longer for dynamic content
38
- await page.waitForTimeout(1000);
39
-
40
- try {
41
- await locator.first().waitFor({ state: "visible", timeout: 3000 });
42
- return locator.first();
43
- } catch (e2) {
44
- // Strategy 2: Try scrolling to make element visible
45
- try {
46
- await page.evaluate(() =>
47
- window.scrollTo(0, document.body.scrollHeight / 2)
48
- );
49
- await page.waitForTimeout(500);
50
- await locator.first().waitFor({ state: "visible", timeout: 2000 });
51
- return locator.first();
52
- } catch (e3) {
53
- // Give up with helpful error
54
- const count = await locator.count();
55
- if (count === 0) {
56
- throw new Error(
57
- `Element not found: "${selector}" - no matching elements on page`
58
- );
59
- } else {
60
- throw new Error(
61
- `Element "${selector}" exists (${count} matches) but not visible/clickable`
62
- );
63
- }
64
- }
65
- }
66
- }
67
- }
68
-
69
- /**
70
- * Run a sequence of steps with Playwright
71
- * Based on test/persona-injection/generic_runner.js and test/capturing-target/element_runner.js
72
- *
73
- * @param {Object} options - Run options
74
- * @param {string} options.url - URL to navigate to
75
- * @param {Array} options.steps - Array of step objects
76
- * @param {string} options.outputDir - Directory to save output files
77
- * @param {Object} options.context - Context object for variable resolution
78
- */
79
- async function runSteps({ url, steps, outputDir, context }) {
80
- const browser = await chromium.launch(buildLaunchOptions({ headless: true }));
81
- const page = await browser.newPage();
82
-
83
- // Set viewport for consistent rendering
84
- await page.setViewportSize({ width: 1280, height: 720 });
85
-
86
- // Set a reasonable default timeout
87
- page.setDefaultTimeout(20000); // 20 seconds
88
-
89
- try {
90
- console.log(` Navigating to ${url}`);
91
- await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 });
92
-
93
- // Wait for initial page load
94
- await page
95
- .waitForLoadState("networkidle", { timeout: 10000 })
96
- .catch(() => {});
97
-
98
- for (let index = 0; index < steps.length; index++) {
99
- const step = steps[index];
100
- console.log(
101
- ` Executing step ${index + 1}/${steps.length}: ${step.action} ${
102
- step.selector || ""
103
- }`
104
- );
105
-
106
- // Resolve secrets in all step fields
107
- const resolvedStep = resolveSecretsInObject(step);
108
-
109
- try {
110
- switch (resolvedStep.action) {
111
- case "goto":
112
- await page.goto(resolvedStep.url || url, {
113
- waitUntil: "domcontentloaded",
114
- });
115
- await page
116
- .waitForLoadState("networkidle", { timeout: 10000 })
117
- .catch(() => {});
118
- break;
119
-
120
- case "type":
121
- case "input": {
122
- const inputElement = await waitForElement(
123
- page,
124
- resolvedStep.selector,
125
- { action: "fill" }
126
- );
127
- await inputElement.fill(resolvedStep.text || "");
128
- break;
129
- }
130
-
131
- case "click": {
132
- const clickElement = await waitForElement(
133
- page,
134
- resolvedStep.selector,
135
- { action: "click" }
136
- );
137
- await clickElement.click();
138
- // Small delay after click to let page react
139
- await page.waitForTimeout(300);
140
- break;
141
- }
142
-
143
- case "hover": {
144
- const hoverElement = await waitForElement(
145
- page,
146
- resolvedStep.selector,
147
- { action: "hover" }
148
- );
149
- await hoverElement.hover();
150
- break;
151
- }
152
-
153
- case "waitForSelector":
154
- await waitForElement(page, resolvedStep.selector);
155
- break;
156
-
157
- case "wait":
158
- await page.waitForTimeout(
159
- resolvedStep.ms || resolvedStep.duration || 1000
160
- );
161
- break;
162
-
163
- case "screenshot":
164
- await handleScreenshot(page, resolvedStep, outputDir, index);
165
- break;
166
-
167
- default:
168
- console.warn(` ⚠ Unknown action: ${resolvedStep.action}`);
169
- }
170
-
171
- console.log(` ✓ Step ${index + 1} completed`);
172
- } catch (stepError) {
173
- // Enhanced error message for selector failures
174
- const selectorInfo = resolvedStep.selector
175
- ? ` (selector: "${resolvedStep.selector}")`
176
- : "";
177
- console.error(
178
- ` ❌ Step ${index + 1} failed: ${step.action}${selectorInfo}`
179
- );
180
- console.error(` Error: ${stepError.message}`);
181
-
182
- // Take a screenshot for debugging
183
- try {
184
- const debugPath = path.join(
185
- outputDir || ".",
186
- `debug-step-${index + 1}-failure.png`
187
- );
188
- await page.screenshot({ path: debugPath, fullPage: true });
189
- console.error(` Debug screenshot saved: ${debugPath}`);
190
- } catch (ssError) {
191
- // Ignore screenshot errors
192
- }
193
-
194
- // Re-throw to stop execution
195
- throw new Error(
196
- `Step ${index + 1} (${step.action}) failed: ${stepError.message}`
197
- );
198
- }
199
- }
200
-
201
- console.log(` ✔ All ${steps.length} steps completed successfully`);
202
- } finally {
203
- await browser.close();
204
- }
205
- }
206
-
207
- /**
208
- * Handle screenshot step
209
- * Based on test/capturing-target/element_runner.js
210
- */
211
- function resolveScreenshotPath(step, index) {
212
- if (step.path) {
213
- return step.path;
214
- }
215
-
216
- const baseName = step.captureKey || step.key;
217
- if (baseName) {
218
- return path.extname(baseName) ? baseName : `${baseName}.png`;
219
- }
220
-
221
- return `step-${(index ?? 0) + 1}.png`;
222
- }
223
-
224
- async function handleScreenshot(page, step, outputDir, index) {
225
- const relativePath = resolveScreenshotPath(step, index);
226
- const finalPath = path.join(outputDir, relativePath);
227
- fs.ensureDirSync(path.dirname(finalPath));
228
-
229
- if (step.selector) {
230
- // Capture specific element
231
- const element = await page.locator(step.selector).first();
232
- await element.screenshot({ path: finalPath });
233
- console.log(` ✔ Captured element and saved to ${finalPath}`);
234
- } else {
235
- // Capture full page
236
- const screenshotOptions = {
237
- path: finalPath,
238
- fullPage: !step.clip,
239
- };
240
-
241
- if (step.clip) {
242
- screenshotOptions.clip = step.clip;
243
- }
244
-
245
- await page.screenshot(screenshotOptions);
246
- console.log(` ✔ Captured full page and saved to ${finalPath}`);
247
- }
248
- }
249
-
250
- module.exports = {
251
- runSteps,
252
- };