Skip to content

Commit eb9d018

Browse files
Merge pull request #247 from sushobhit-lt/DOT-4883
store discovery errors
2 parents ec280c0 + 685f52b commit eb9d018

File tree

5 files changed

+101
-20
lines changed

5 files changed

+101
-20
lines changed

package.json

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

src/lib/httpClient.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from 'fs';
22
import FormData from 'form-data';
33
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
4-
import { Env, Snapshot, ProcessedSnapshot, Git, Build, Context } from '../types.js';
4+
import { Env, Snapshot, ProcessedSnapshot, Git, Build, Context, DiscoveryErrors } from '../types.js';
55
import constants from './constants.js';
66
import type { Logger } from 'winston'
77
import pkgJSON from './../../package.json'
@@ -91,6 +91,9 @@ export default class httpClient {
9191
if (config && config.data && !config.data.name) {
9292
log.debug(config.data);
9393
}
94+
if (config && config.data && config.data.snapshotUuid) {
95+
log.debug(config.data);
96+
}
9497
return this.axiosInstance.request(config)
9598
.then(resp => {
9699
if (resp) {
@@ -222,7 +225,7 @@ export default class httpClient {
222225
}
223226

224227

225-
uploadSnapshot(ctx: Context, snapshot: ProcessedSnapshot) {
228+
uploadSnapshot(ctx: Context, snapshot: ProcessedSnapshot, discoveryErrors: DiscoveryErrors) {
226229
// Use capsBuildId if provided, otherwise fallback to ctx.build.id
227230
return this.request({
228231
url: `/builds/${ctx.build.id}/snapshot`,
@@ -233,12 +236,13 @@ export default class httpClient {
233236
test: {
234237
type: ctx.testType,
235238
source: 'cli'
236-
}
239+
},
240+
discoveryErrors: discoveryErrors,
237241
}
238242
}, ctx.log)
239243
}
240244

241-
processSnapshot(ctx: Context, snapshot: ProcessedSnapshot, snapshotUuid: string) {
245+
processSnapshot(ctx: Context, snapshot: ProcessedSnapshot, snapshotUuid: string, discoveryErrors: DiscoveryErrors) {
242246
return this.request({
243247
url: `/build/${ctx.build.id}/snapshot`,
244248
method: 'POST',
@@ -252,11 +256,12 @@ export default class httpClient {
252256
source: 'cli'
253257
},
254258
async: false,
259+
discoveryErrors: discoveryErrors,
255260
}
256261
}, ctx.log)
257262
}
258263

259-
processSnapshotCaps(ctx: Context, snapshot: ProcessedSnapshot, snapshotUuid: string, capsBuildId: string, capsProjectToken: string) {
264+
processSnapshotCaps(ctx: Context, snapshot: ProcessedSnapshot, snapshotUuid: string, capsBuildId: string, capsProjectToken: string, discoveryErrors: DiscoveryErrors) {
260265
return this.request({
261266
url: `/build/${capsBuildId}/snapshot`,
262267
method: 'POST',
@@ -273,11 +278,12 @@ export default class httpClient {
273278
source: 'cli'
274279
},
275280
async: false,
281+
discoveryErrors: discoveryErrors,
276282
}
277283
}, ctx.log)
278284
}
279285

280-
uploadSnapshotForCaps(ctx: Context, snapshot: ProcessedSnapshot, capsBuildId: string, capsProjectToken: string) {
286+
uploadSnapshotForCaps(ctx: Context, snapshot: ProcessedSnapshot, capsBuildId: string, capsProjectToken: string, discoveryErrors: DiscoveryErrors) {
281287
// Use capsBuildId if provided, otherwise fallback to ctx.build.id
282288
const buildId = capsBuildId !== '' ? capsBuildId : ctx.build.id;
283289

@@ -293,7 +299,8 @@ export default class httpClient {
293299
test: {
294300
type: ctx.testType,
295301
source: 'cli'
296-
}
302+
},
303+
discoveryErrors: discoveryErrors,
297304
}
298305
}, ctx.log);
299306
}

src/lib/processSnapshot.ts

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Snapshot, Context, ProcessedSnapshot } from "../types.js";
1+
import { Snapshot, Context, DiscoveryErrors } from "../types.js";
22
import { scrollToBottomAndBackToTop, getRenderViewports, getRenderViewportsForOptions } from "./utils.js"
33
import { chromium, Locator } from "@playwright/test"
44
import constants from "./constants.js";
@@ -16,7 +16,16 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
1616
updateLogContext({ task: 'discovery' });
1717
ctx.log.debug(`Processing snapshot ${snapshot.name} ${snapshot.url}`);
1818
const isHeadless = process.env.HEADLESS?.toLowerCase() === 'false' ? false : true;
19-
19+
let discoveryErrors: DiscoveryErrors = {
20+
name: "",
21+
url: "",
22+
timestamp: "",
23+
snapshotUUID: "",
24+
browsers: {}
25+
};
26+
27+
let globalViewport = ""
28+
let globalBrowser = constants.CHROME
2029
let launchOptions: Record<string, any> = {
2130
headless: isHeadless,
2231
args: constants.LAUNCH_ARGS
@@ -84,7 +93,7 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
8493
...constants.REQUEST_HEADERS
8594
}
8695
}
87-
96+
8897
try {
8998
// abort audio/video media requests
9099
if (/\.(mp3|mp4|wav|ogg|webm)$/i.test(request.url())) {
@@ -141,10 +150,29 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
141150
ctx.log.debug(`Handling request ${requestUrl}\n - skipping already cached resource`);
142151
} else if (body.length > MAX_RESOURCE_SIZE) {
143152
ctx.log.debug(`Handling request ${requestUrl}\n - skipping resource larger than 15MB`);
144-
} else if (!ALLOWED_STATUSES.includes(response.status())) {
145-
ctx.log.debug(`Handling request ${requestUrl}\n - skipping disallowed status [${response.status()}]`);
146153
} else if (!ALLOWED_RESOURCES.includes(request.resourceType())) {
147154
ctx.log.debug(`Handling request ${requestUrl}\n - skipping disallowed resource type [${request.resourceType()}]`);
155+
} else if (!ALLOWED_STATUSES.includes(response.status())) {
156+
ctx.log.debug(`${globalViewport} Handling request ${requestUrl}\n - skipping disallowed status [${response.status()}]`);
157+
let data = {
158+
statusCode: `${response.status()}`,
159+
url: requestUrl,
160+
resourceType: request.resourceType(),
161+
}
162+
163+
if (!discoveryErrors.browsers[globalBrowser]){
164+
discoveryErrors.browsers[globalBrowser] = {}; }
165+
166+
// Check if the discoveryErrors.browsers[globalBrowser] exists, and if not, initialize it
167+
if (discoveryErrors.browsers[globalBrowser] && !discoveryErrors.browsers[globalBrowser][globalViewport]) {
168+
discoveryErrors.browsers[globalBrowser][globalViewport] = [];
169+
}
170+
171+
// Dynamically push the data into the correct browser and viewport
172+
if (discoveryErrors.browsers[globalBrowser]) {
173+
discoveryErrors.browsers[globalBrowser][globalViewport]?.push(data);
174+
}
175+
148176
} else {
149177
ctx.log.debug(`Handling request ${requestUrl}\n - content-type ${response.headers()['content-type']}`);
150178

@@ -304,10 +332,19 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
304332

305333
await page.setViewportSize({ width: viewport.width, height: viewport.height || MIN_VIEWPORT_HEIGHT });
306334
ctx.log.debug(`Page resized to ${viewport.width}x${viewport.height || MIN_VIEWPORT_HEIGHT}`);
335+
globalViewport = viewportString;
336+
ctx.log.debug(`globalViewport : ${globalViewport}`);
337+
if (globalViewport.toLowerCase().includes("iphone") || globalViewport.toLowerCase().includes("ipad")) {
338+
globalBrowser = constants.WEBKIT;
339+
} else {
340+
globalBrowser = constants.CHROME;
341+
}
307342

308343
// navigate to snapshot url once
309344
if (!navigated) {
310345
try {
346+
discoveryErrors.url = snapshot.url;
347+
discoveryErrors.name = snapshot.name;
311348
// domcontentloaded event is more reliable than load event
312349
await page.goto(snapshot.url, { waitUntil: "domcontentloaded", timeout: ctx.config.waitForDiscovery });
313350
// adding extra timeout since domcontentloaded event is fired pretty quickly
@@ -399,6 +436,23 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
399436
ctx.log.debug(`Processed options: ${JSON.stringify(processedOptions)}`);
400437
}
401438

439+
440+
let hasBrowserErrors = false;
441+
for (let browser in discoveryErrors.browsers) {
442+
if (discoveryErrors.browsers[browser]) {
443+
for (let viewport in discoveryErrors.browsers[browser]) {
444+
if (discoveryErrors.browsers[browser][viewport].length > 0) {
445+
hasBrowserErrors = true;
446+
break;
447+
}
448+
}
449+
}
450+
}
451+
452+
if (hasBrowserErrors) {
453+
discoveryErrors.timestamp = new Date().toISOString();
454+
ctx.log.error(discoveryErrors);
455+
}
402456
return {
403457
processedSnapshot: {
404458
name: snapshot.name,
@@ -407,6 +461,7 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
407461
resources: cache,
408462
options: processedOptions
409463
},
410-
warnings: [...optionWarnings, ...snapshot.dom.warnings]
464+
warnings: [...optionWarnings, ...snapshot.dom.warnings],
465+
discoveryErrors: discoveryErrors
411466
}
412467
}

src/lib/snapshotQueue.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ export default class Queue {
313313
}
314314

315315
// Process and upload snapshot
316-
let { processedSnapshot, warnings } = await processSnapshot(snapshot, this.ctx);
316+
let { processedSnapshot, warnings, discoveryErrors } = await processSnapshot(snapshot, this.ctx);
317317

318318
if (useCapsBuildId) {
319319
if (useKafkaFlowCaps) {
@@ -322,9 +322,9 @@ export default class Queue {
322322
const uploadUrl = presignedResponse.data.url;
323323

324324
await this.ctx.client.uploadSnapshotToS3Caps(this.ctx, uploadUrl, processedSnapshot, capsProjectToken)
325-
await this.ctx.client.processSnapshotCaps(this.ctx, processedSnapshot, snapshotUuid, capsBuildId, capsProjectToken);
325+
await this.ctx.client.processSnapshotCaps(this.ctx, processedSnapshot, snapshotUuid, capsBuildId, capsProjectToken, discoveryErrors);
326326
} else {
327-
await this.ctx.client.uploadSnapshotForCaps(this.ctx, processedSnapshot, capsBuildId, capsProjectToken);
327+
await this.ctx.client.uploadSnapshotForCaps(this.ctx, processedSnapshot, capsBuildId, capsProjectToken, discoveryErrors);
328328
}
329329

330330
// Increment snapshot count for the specific buildId
@@ -358,9 +358,9 @@ export default class Queue {
358358
const uploadUrl = presignedResponse.data.url;
359359

360360
await this.ctx.client.uploadSnapshotToS3(this.ctx, uploadUrl, processedSnapshot)
361-
await this.ctx.client.processSnapshot(this.ctx, processedSnapshot, snapshotUuid);
361+
await this.ctx.client.processSnapshot(this.ctx, processedSnapshot, snapshotUuid, discoveryErrors);
362362
} else {
363-
await this.ctx.client.uploadSnapshot(this.ctx, processedSnapshot);
363+
await this.ctx.client.uploadSnapshot(this.ctx, processedSnapshot, discoveryErrors);
364364
}
365365
this.ctx.totalSnapshots++;
366366
}

src/types.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,4 +186,23 @@ export interface basicAuth {
186186
export interface FigmaWebConfig {
187187
autoDetectViewports: Array<string>;
188188
configs: Array<{ figma_file_token: string, figma_ids: Array<string>, screenshot_names:Array<string> }>;
189-
}
189+
}
190+
191+
192+
export interface ViewportErrors {
193+
statusCode: "aborted" | "404" | string;
194+
url: string;
195+
resourceType: string;
196+
}
197+
198+
export interface DiscoveryErrors {
199+
name: string;
200+
url: string;
201+
timestamp: string;
202+
snapshotUUID: string;
203+
browsers: {
204+
[browserName: string]: {
205+
[viewport: string]: ViewportErrors[];
206+
};
207+
};
208+
}

0 commit comments

Comments
 (0)