Skip to content

Commit 5e456d0

Browse files
Merge pull request #222 from sushobhit-lt/DOT-4599
implement browser queries option using capture
2 parents e0f5dde + 1c13504 commit 5e456d0

File tree

5 files changed

+70
-15
lines changed

5 files changed

+70
-15
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@lambdatest/smartui-cli",
3-
"version": "4.0.22",
3+
"version": "4.1.0",
44
"description": "A command line interface (CLI) to run SmartUI tests on LambdaTest",
55
"files": [
66
"dist/**/*"

src/commander/capture.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,21 @@ command
3434
}
3535
try {
3636
ctx.webStaticConfig = JSON.parse(fs.readFileSync(file, 'utf8'));
37-
if (!validateWebStaticConfig(ctx.webStaticConfig)) throw new Error(validateWebStaticConfig.errors[0].message);
37+
if (!validateWebStaticConfig(ctx.webStaticConfig)){
38+
39+
ctx.log.debug(JSON.stringify(validateWebStaticConfig.errors, null, 2));
40+
// Iterate and add warning for "additionalProperties"
41+
validateWebStaticConfig.errors?.forEach(error => {
42+
if (error.keyword === "additionalProperties") {
43+
ctx.log.warn(`Additional property "${error.params.additionalProperty}" is not allowed.`)
44+
} else {
45+
const validationError = error.message;
46+
throw new Error(validationError || 'Invalid Web Static config found in file : ' + file);
47+
}
48+
});
49+
throw new Error(validateWebStaticConfig.errors[0]?.message);
50+
}
51+
3852
if(ctx.webStaticConfig && ctx.webStaticConfig.length === 0) {
3953
ctx.log.error(`No URLs found in the specified config file -> ${file}`);
4054
return;

src/lib/logger.ts

+14-11
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import getEnv from './env.js'
55
import chalk from 'chalk'
66

77
interface LogContext {
8-
task?: string;
8+
task?: string;
99
}
1010

1111
let logContext: LogContext = {};
@@ -16,26 +16,29 @@ export function updateLogContext(newContext: LogContext) {
1616
}
1717

1818
const logLevel = (): string => {
19-
let env: Env = getEnv();
20-
return (env.LT_SDK_DEBUG) ? 'debug' : 'info';
19+
let env: Env = getEnv();
20+
return (env.LT_SDK_DEBUG) ? 'debug' : 'info';
2121
}
2222

2323
// Create a Winston logger
2424
const logger = createLogger({
25-
format: format.combine(
26-
format.timestamp(),
27-
format.printf(info => {
25+
format: format.combine(
26+
format.timestamp(),
27+
format.printf(info => {
2828
let contextString = Object.values(logContext).join(' | ');
29-
let message = (typeof info.message === 'object') ? JSON.stringify(info.message).trim() : info.message.trim();
29+
let message = (typeof info.message === 'object') ? JSON.stringify(info.message).trim() : info.message.trim();
3030
switch (info.level) {
3131
case 'warn':
3232
message = chalk.yellow(message);
3333
break;
34+
case 'error':
35+
message = chalk.red(message);
36+
break;
3437
}
35-
return (info.level === 'info') ? message : `[${contextString}:${info.level}] ` + message;
36-
})
37-
),
38-
transports: [
38+
return (info.level === 'info') ? message : `[${contextString}:${info.level}] ` + message;
39+
})
40+
),
41+
transports: [
3942
new transports.Console({
4043
level: logLevel()
4144
}),

src/lib/schemaValidation.ts

+11
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,17 @@ const WebStaticConfigSchema: JSONSchemaType<WebStaticConfig> = {
185185
maximum: 30000,
186186
errorMessage: "waitForTimeout must be > 0 and <= 30000"
187187
},
188+
execute: {
189+
type: "object",
190+
properties: {
191+
afterNavigation : {
192+
type: "string",
193+
},
194+
beforeSnapshot: {
195+
type: "string",
196+
}
197+
}
198+
},
188199
},
189200
required: ["name", "url"],
190201
additionalProperties: false

src/lib/screenshot.ts

+29-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@ import sharp from 'sharp';
1010
async function captureScreenshotsForConfig(
1111
ctx: Context,
1212
browsers: Record<string, Browser>,
13-
{name, url, waitForTimeout}: Record<string, any>,
13+
urlConfig : Record<string, any>,
1414
browserName: string,
1515
renderViewports: Array<Record<string,any>>
1616
): Promise<void> {
17+
ctx.log.debug(`*** urlConfig ${JSON.stringify(urlConfig)}`);
18+
19+
let {name, url, waitForTimeout, execute} = urlConfig;
20+
let afterNavigationScript = execute?.afterNavigation;
21+
let beforeSnapshotScript = execute?.beforeSnapshot;
22+
1723
let pageOptions = { waitUntil: process.env.SMARTUI_PAGE_WAIT_UNTIL_EVENT || 'load', timeout: ctx.config.waitForPageRender || constants.DEFAULT_PAGE_LOAD_TIMEOUT };
1824
let ssId = name.toLowerCase().replace(/\s/g, '_');
1925
let context: BrowserContext;
@@ -30,11 +36,15 @@ async function captureScreenshotsForConfig(
3036
page = await context?.newPage();
3137

3238
await page?.goto(url.trim(), pageOptions);
39+
await executeDocumentScripts(ctx, page, "afterNavigation", afterNavigationScript)
40+
3341
for (let { viewport, viewportString, fullPage } of renderViewports) {
3442
let ssPath = `screenshots/${ssId}/${`${browserName}-${viewport.width}x${viewport.height}`}-${ssId}.png`;
3543
await page?.setViewportSize({ width: viewport.width, height: viewport.height || constants.MIN_VIEWPORT_HEIGHT });
3644
if (fullPage) await page?.evaluate(utils.scrollToBottomAndBackToTop);
3745
await page?.waitForTimeout(waitForTimeout || 0);
46+
await executeDocumentScripts(ctx, page, "beforeSnapshot", beforeSnapshotScript)
47+
3848
await page?.screenshot({ path: ssPath, fullPage });
3949

4050
await ctx.client.uploadScreenshot(ctx.build, ssPath, name, browserName, viewportString, ctx.log);
@@ -126,7 +136,7 @@ export async function captureScreenshots(ctx: Context): Promise<Record<string,a
126136
ctx.task.output = output;
127137
capturedScreenshots++;
128138
} catch (error) {
129-
ctx.log.debug(`screenshot capture failed for ${JSON.stringify(staticConfig)}; error: ${error}`);
139+
ctx.log.debug(`captureScreenshots failed for ${JSON.stringify(staticConfig)}; error: ${error}`);
130140
output += `${chalk.gray(staticConfig.name)} ${chalk.red('\u{2717}')}\n`;
131141
ctx.task.output = output;
132142
}
@@ -343,4 +353,21 @@ async function processChunk(ctx: Context, urlConfig: Array<Record<string, any>>)
343353

344354
await utils.closeBrowsers(browsers);
345355
return { capturedScreenshots, finalOutput };
356+
}
357+
358+
async function executeDocumentScripts(ctx: Context, page: Page, actionType: string, script: string) {
359+
try {
360+
if (!page) {
361+
throw new Error("Page instance not available");
362+
}
363+
364+
if (script !== "") {
365+
await page.evaluate((script) => {
366+
new Function(script)();
367+
}, script);
368+
}
369+
} catch (error) {
370+
ctx.log.error(`Error executing script for action ${actionType}: `, error);
371+
throw error;
372+
}
346373
}

0 commit comments

Comments
 (0)