@rettangoli/vt 0.0.9 → 0.0.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rettangoli/vt",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "Rettangoli Visual Testing",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -9,9 +9,8 @@ import {
9
9
  readYaml,
10
10
  } from "../common.js";
11
11
 
12
- const libraryTemplatesPath = new URL('./templates', import.meta.url).pathname;
13
- const libraryStaticPath = new URL('./static', import.meta.url).pathname;
14
-
12
+ const libraryTemplatesPath = new URL("./templates", import.meta.url).pathname;
13
+ const libraryStaticPath = new URL("./static", import.meta.url).pathname;
15
14
 
16
15
  /**
17
16
  * Main function that orchestrates the entire process
@@ -21,14 +20,14 @@ async function main(options) {
21
20
  skipScreenshots = false,
22
21
  vtPath = "./vt",
23
22
  screenshotWaitTime = 0,
24
- port = 3001
23
+ port = 3001,
25
24
  } = options;
26
25
 
27
26
  const specsPath = join(vtPath, "specs");
28
27
  const mainConfigPath = "rettangoli.config.yaml";
29
28
  const siteOutputPath = join(".rettangoli", "vt", "_site");
30
29
  const candidatePath = join(siteOutputPath, "candidate");
31
-
30
+
32
31
  // Read VT config from main rettangoli.config.yaml
33
32
  let configData = {};
34
33
  try {
@@ -38,32 +37,30 @@ async function main(options) {
38
37
  console.log("Main config file not found, using defaults");
39
38
  }
40
39
 
40
+ const configUrl = configData.url;
41
+
41
42
  // Clear candidate directory
42
43
  await rm(candidatePath, { recursive: true, force: true });
43
44
  await new Promise((resolve) => setTimeout(resolve, 100));
44
45
 
45
46
  // Copy static files from library to site directory
46
47
  await cp(libraryStaticPath, siteOutputPath, { recursive: true });
47
-
48
+
48
49
  // Copy user's static files if they exist
49
50
  const userStaticPath = join(vtPath, "static");
50
51
  if (existsSync(userStaticPath)) {
51
52
  await cp(userStaticPath, siteOutputPath, { recursive: true });
52
53
  }
53
54
 
54
- // Check for local templates first, fallback to library templates
55
+ // Resolve template paths
55
56
  const localTemplatesPath = join(vtPath, "templates");
56
-
57
57
  const defaultTemplatePath = existsSync(join(localTemplatesPath, "default.html"))
58
- ? join(localTemplatesPath, "default.html")
59
- : join(libraryTemplatesPath, "default.html");
60
-
61
- // Resolve index template path
58
+ ? join(localTemplatesPath, "default.html")
59
+ : join(libraryTemplatesPath, "default.html");
62
60
  const indexTemplatePath = existsSync(join(localTemplatesPath, "index.html"))
63
- ? join(localTemplatesPath, "index.html")
64
- : join(libraryTemplatesPath, "index.html");
61
+ ? join(localTemplatesPath, "index.html")
62
+ : join(libraryTemplatesPath, "index.html");
65
63
 
66
- // Build template configuration for per-file/section templates
67
64
  const templateConfig = {
68
65
  defaultTemplate: defaultTemplatePath,
69
66
  vtPath: vtPath,
@@ -74,40 +71,36 @@ async function main(options) {
74
71
  specsPath,
75
72
  defaultTemplatePath,
76
73
  candidatePath,
77
- templateConfig
74
+ templateConfig,
78
75
  );
79
76
 
80
- // Generate overview page with all files
77
+ // Generate overview page
81
78
  generateOverview(
82
79
  generatedFiles,
83
80
  indexTemplatePath,
84
81
  join(siteOutputPath, "index.html"),
85
- configData
82
+ configData,
86
83
  );
87
84
 
85
+ // Take screenshots
88
86
  if (!skipScreenshots) {
89
- // Start web server from site output path to serve both /public and /candidate
90
- const server = startWebServer(
91
- siteOutputPath,
92
- vtPath,
93
- port
94
- );
87
+ const server = configUrl ? null : startWebServer(siteOutputPath, vtPath, port);
95
88
  try {
96
- // Take screenshots with specified concurrency
97
89
  await takeScreenshots(
98
90
  generatedFiles,
99
91
  `http://localhost:${port}`,
100
92
  candidatePath,
101
93
  24,
102
- screenshotWaitTime
94
+ screenshotWaitTime,
95
+ configUrl,
103
96
  );
104
97
  } finally {
105
- // Stop server
106
- server.close();
107
- console.log("Server stopped");
98
+ if (server) {
99
+ server.close();
100
+ console.log("Server stopped");
101
+ }
108
102
  }
109
103
  }
110
-
111
104
  }
112
105
 
113
106
  export default main;
package/src/common.js CHANGED
@@ -83,9 +83,8 @@ function getAllFiles(dirPath, arrayOfFiles = []) {
83
83
  * Extract frontmatter from content
84
84
  */
85
85
  function extractFrontMatter(content) {
86
- const frontMatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n/;
86
+ const frontMatterRegex = /^---\s*\n([\s\S]*?)\n---\s*(\r?\n|$)/;
87
87
  const match = content.match(frontMatterRegex);
88
-
89
88
  if (!match) {
90
89
  return {
91
90
  content: content,
@@ -180,7 +179,6 @@ function startWebServer(artifactsDir, staticDir, port) {
180
179
  const server = http.createServer((req, res) => {
181
180
  const url = new URL(req.url, `http://localhost:${port}`);
182
181
  let path = url.pathname;
183
-
184
182
  // Default to index.html for root path
185
183
  if (path === "/") {
186
184
  path = "/index.html";
@@ -249,7 +247,8 @@ async function takeScreenshots(
249
247
  serverUrl,
250
248
  screenshotsDir,
251
249
  concurrency = 8,
252
- waitTime = 0
250
+ waitTime = 0,
251
+ configUrl = undefined,
253
252
  ) {
254
253
  // Ensure screenshots directory exists
255
254
  ensureDirectoryExists(screenshotsDir);
@@ -258,13 +257,13 @@ async function takeScreenshots(
258
257
  console.log("Launching browser to take screenshots...");
259
258
  const browser = await chromium.launch();
260
259
 
261
- const takeAndSaveScreenshot = async (page, basePath, suffix = '') => {
260
+ const takeAndSaveScreenshot = async (page, basePath, suffix = "") => {
262
261
  const finalPath = suffix ? `${basePath}-${suffix}` : basePath;
263
262
  const tempPngPath = join(screenshotsDir, `${finalPath}.png`);
264
263
  const screenshotPath = join(screenshotsDir, `${finalPath}.webp`);
265
264
  ensureDirectoryExists(dirname(screenshotPath));
266
265
 
267
- await page.screenshot({ path: tempPngPath, fullPage: true});
266
+ await page.screenshot({ path: tempPngPath, fullPage: true });
268
267
  await sharp(tempPngPath).webp({ quality: 85 }).toFile(screenshotPath);
269
268
 
270
269
  if (existsSync(tempPngPath)) {
@@ -288,10 +287,13 @@ async function takeScreenshots(
288
287
  let screenshotIndex = 0;
289
288
 
290
289
  try {
291
- // Construct URL from file path (add /candidate prefix since server serves from parent)
292
- const fileUrl = convertToHtmlExtension(
293
- `${serverUrl}/candidate/${file.path.replace(/\\/g, '/')}`
290
+ const frontMatterUrl = file.frontMatter?.url;
291
+ const constructedUrl = convertToHtmlExtension(
292
+ `${serverUrl}/candidate/${file.path.replace(/\\/g, "/")}`,
294
293
  );
294
+ const url = frontMatterUrl ?? configUrl ?? constructedUrl;
295
+ const fileUrl = url.startsWith("http") ? url : new URL(url, serverUrl).href;
296
+
295
297
  console.log(`Navigating to ${fileUrl}`);
296
298
  await page.goto(fileUrl, { waitUntil: "networkidle" });
297
299
  if (waitTime > 0) {
@@ -300,7 +302,7 @@ async function takeScreenshots(
300
302
  const baseName = removeExtension(file.path);
301
303
 
302
304
  const initialScreenshotPath = await takeAndSaveScreenshot(page, baseName);
303
- console.log(`Initial screenshot saved: ${initialScreenshotPath}`);
305
+ console.log(`Screenshot saved: ${initialScreenshotPath}`);
304
306
 
305
307
  const stepContext = {
306
308
  baseName,
@@ -48,6 +48,10 @@ async function move(page, args) {
48
48
  await page.mouse.move(Number(args[0]), Number(args[1]));
49
49
  }
50
50
 
51
+ async function scroll(page, args){
52
+ await page.mouse.wheel(Number(args[0]), Number(args[1]));
53
+ }
54
+
51
55
  async function rclick(page, args, context, selectedElement) {
52
56
  if (selectedElement) {
53
57
  await selectedElement.click({ button: 'right' });
@@ -106,6 +110,7 @@ export function createSteps(page, context) {
106
110
  mouseUp,
107
111
  move,
108
112
  rclick,
113
+ scroll,
109
114
  rMouseDown,
110
115
  rMouseUp,
111
116
  screenshot,