Skip to content

Commit

Permalink
Merge pull request #223 from LambdaTest/stage
Browse files Browse the repository at this point in the history
Release Execute queries in capture command
  • Loading branch information
parthlambdatest authored Feb 22, 2025
2 parents a8cc07b + 5e456d0 commit 33b6be2
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 15 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lambdatest/smartui-cli",
"version": "4.0.22",
"version": "4.1.0",
"description": "A command line interface (CLI) to run SmartUI tests on LambdaTest",
"files": [
"dist/**/*"
Expand Down
16 changes: 15 additions & 1 deletion src/commander/capture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,21 @@ command
}
try {
ctx.webStaticConfig = JSON.parse(fs.readFileSync(file, 'utf8'));
if (!validateWebStaticConfig(ctx.webStaticConfig)) throw new Error(validateWebStaticConfig.errors[0].message);
if (!validateWebStaticConfig(ctx.webStaticConfig)){

ctx.log.debug(JSON.stringify(validateWebStaticConfig.errors, null, 2));
// Iterate and add warning for "additionalProperties"
validateWebStaticConfig.errors?.forEach(error => {
if (error.keyword === "additionalProperties") {
ctx.log.warn(`Additional property "${error.params.additionalProperty}" is not allowed.`)
} else {
const validationError = error.message;
throw new Error(validationError || 'Invalid Web Static config found in file : ' + file);
}
});
throw new Error(validateWebStaticConfig.errors[0]?.message);
}

if(ctx.webStaticConfig && ctx.webStaticConfig.length === 0) {
ctx.log.error(`No URLs found in the specified config file -> ${file}`);
return;
Expand Down
25 changes: 14 additions & 11 deletions src/lib/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import getEnv from './env.js'
import chalk from 'chalk'

interface LogContext {
task?: string;
task?: string;
}

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

const logLevel = (): string => {
let env: Env = getEnv();
return (env.LT_SDK_DEBUG) ? 'debug' : 'info';
let env: Env = getEnv();
return (env.LT_SDK_DEBUG) ? 'debug' : 'info';
}

// Create a Winston logger
const logger = createLogger({
format: format.combine(
format.timestamp(),
format.printf(info => {
format: format.combine(
format.timestamp(),
format.printf(info => {
let contextString = Object.values(logContext).join(' | ');
let message = (typeof info.message === 'object') ? JSON.stringify(info.message).trim() : info.message.trim();
let message = (typeof info.message === 'object') ? JSON.stringify(info.message).trim() : info.message.trim();
switch (info.level) {
case 'warn':
message = chalk.yellow(message);
break;
case 'error':
message = chalk.red(message);
break;
}
return (info.level === 'info') ? message : `[${contextString}:${info.level}] ` + message;
})
),
transports: [
return (info.level === 'info') ? message : `[${contextString}:${info.level}] ` + message;
})
),
transports: [
new transports.Console({
level: logLevel()
}),
Expand Down
11 changes: 11 additions & 0 deletions src/lib/schemaValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,17 @@ const WebStaticConfigSchema: JSONSchemaType<WebStaticConfig> = {
maximum: 30000,
errorMessage: "waitForTimeout must be > 0 and <= 30000"
},
execute: {
type: "object",
properties: {
afterNavigation : {
type: "string",
},
beforeSnapshot: {
type: "string",
}
}
},
},
required: ["name", "url"],
additionalProperties: false
Expand Down
31 changes: 29 additions & 2 deletions src/lib/screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ import sharp from 'sharp';
async function captureScreenshotsForConfig(
ctx: Context,
browsers: Record<string, Browser>,
{name, url, waitForTimeout}: Record<string, any>,
urlConfig : Record<string, any>,
browserName: string,
renderViewports: Array<Record<string,any>>
): Promise<void> {
ctx.log.debug(`*** urlConfig ${JSON.stringify(urlConfig)}`);

let {name, url, waitForTimeout, execute} = urlConfig;
let afterNavigationScript = execute?.afterNavigation;
let beforeSnapshotScript = execute?.beforeSnapshot;

let pageOptions = { waitUntil: process.env.SMARTUI_PAGE_WAIT_UNTIL_EVENT || 'load', timeout: ctx.config.waitForPageRender || constants.DEFAULT_PAGE_LOAD_TIMEOUT };
let ssId = name.toLowerCase().replace(/\s/g, '_');
let context: BrowserContext;
Expand All @@ -30,11 +36,15 @@ async function captureScreenshotsForConfig(
page = await context?.newPage();

await page?.goto(url.trim(), pageOptions);
await executeDocumentScripts(ctx, page, "afterNavigation", afterNavigationScript)

for (let { viewport, viewportString, fullPage } of renderViewports) {
let ssPath = `screenshots/${ssId}/${`${browserName}-${viewport.width}x${viewport.height}`}-${ssId}.png`;
await page?.setViewportSize({ width: viewport.width, height: viewport.height || constants.MIN_VIEWPORT_HEIGHT });
if (fullPage) await page?.evaluate(utils.scrollToBottomAndBackToTop);
await page?.waitForTimeout(waitForTimeout || 0);
await executeDocumentScripts(ctx, page, "beforeSnapshot", beforeSnapshotScript)

await page?.screenshot({ path: ssPath, fullPage });

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

await utils.closeBrowsers(browsers);
return { capturedScreenshots, finalOutput };
}

async function executeDocumentScripts(ctx: Context, page: Page, actionType: string, script: string) {
try {
if (!page) {
throw new Error("Page instance not available");
}

if (script !== "") {
await page.evaluate((script) => {
new Function(script)();
}, script);
}
} catch (error) {
ctx.log.error(`Error executing script for action ${actionType}: `, error);
throw error;
}
}

0 comments on commit 33b6be2

Please sign in to comment.