Skip to content

Commit 7f43281

Browse files
authored
Merge pull request #407 from LambdaTest/stage
Release Version 4.1.38
2 parents 209cc54 + 1fc0265 commit 7f43281

File tree

7 files changed

+71
-8
lines changed

7 files changed

+71
-8
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.38-beta.1",
3+
"version": "4.1.38",
44
"description": "A command line interface (CLI) to run SmartUI tests on LambdaTest",
55
"files": [
66
"dist/**/*"

src/lib/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export default {
126126
MOBILE_ORIENTATION_LANDSCAPE: 'landscape',
127127

128128
// build status
129+
BUILD_RUNNING: 'running',
129130
BUILD_COMPLETE: 'completed',
130131
BUILD_ERROR: 'error',
131132

src/lib/processSnapshot.ts

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,22 @@ const globalCache = new NodeCache({ stdTTL: 3600, checkperiod: 600 });
99
const MAX_RESOURCE_SIZE = 15 * (1024 ** 2); // 15MB
1010
var ALLOWED_RESOURCES = ['document', 'stylesheet', 'image', 'media', 'font', 'other'];
1111
const ALLOWED_STATUSES = [200, 201];
12-
const REQUEST_TIMEOUT = 1800000;
12+
const REQUEST_TIMEOUT = 180000;
1313
const MIN_VIEWPORT_HEIGHT = 1080;
14+
const MAX_WAIT_FOR_REQUEST_CALL = 30000;
15+
16+
const normalizeSameSite = (value) => {
17+
if (!value) return 'Lax';
18+
19+
const normalized = value.trim().toLowerCase();
20+
const mapping = {
21+
'lax': 'Lax',
22+
'strict': 'Strict',
23+
'none': 'None'
24+
};
25+
26+
return mapping[normalized] || value;
27+
};
1428

1529
export async function prepareSnapshot(snapshot: Snapshot, ctx: Context): Promise<Record<string, any>> {
1630
let processedOptions: Record<string, any> = {};
@@ -257,11 +271,11 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
257271
return false;
258272
}
259273

260-
if (cookie.sameSite && !['Strict', 'Lax', 'None'].includes(cookie.sameSite)) {
274+
const sameSiteValue = normalizeSameSite(cookie.sameSite);
275+
if (!['Strict', 'Lax', 'None'].includes(sameSiteValue)) {
261276
ctx.log.debug(`Skipping invalid custom cookie: invalid sameSite value '${cookie.sameSite}'`);
262277
return false;
263278
}
264-
265279
return true;
266280
}).map(cookie => ({
267281
name: cookie.name,
@@ -270,7 +284,7 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
270284
path: cookie.path || '/',
271285
httpOnly: cookie.httpOnly || false,
272286
secure: cookie.secure || false,
273-
sameSite: cookie.sameSite || 'Lax'
287+
sameSite: normalizeSameSite(cookie.sameSite)
274288
}));
275289

276290
if (validCustomCookies.length > 0) {
@@ -299,6 +313,8 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
299313
}
300314
}
301315

316+
const pendingRequests = new Set<string>();
317+
302318
// Use route to intercept network requests and discover resources
303319
await page.route('**/*', async (route, request) => {
304320
const requestUrl = request.url()
@@ -357,8 +373,14 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
357373
body = globalCache.get(requestUrl).body;
358374
} else {
359375
ctx.log.debug(`Resource not found in cache or global cache ${requestUrl} fetching from server`);
376+
if(ctx.build.checkPendingRequests){
377+
pendingRequests.add(requestUrl);
378+
}
360379
response = await page.request.fetch(request, requestOptions);
361380
body = await response.body();
381+
if(ctx.build.checkPendingRequests){
382+
pendingRequests.delete(requestUrl);
383+
}
362384
}
363385

364386
// handle response
@@ -386,15 +408,26 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
386408

387409
let responseOfRetry, bodyOfRetry
388410
ctx.log.debug(`Resource had a disallowed status ${requestUrl} fetching from server again`);
411+
if(ctx.build.checkPendingRequests){
412+
pendingRequests.add(requestUrl);
413+
}
389414
responseOfRetry = await page.request.fetch(request, requestOptions);
390415
bodyOfRetry = await responseOfRetry.body();
391-
416+
if(ctx.build.checkPendingRequests){
417+
pendingRequests.delete(requestUrl);
418+
}
392419
if (responseOfRetry && responseOfRetry.status() && ALLOWED_STATUSES.includes(responseOfRetry.status())) {
393420
ctx.log.debug(`Handling request after retry ${requestUrl}\n - content-type ${responseOfRetry.headers()['content-type']}`);
394421
cache[requestUrl] = {
395422
body: bodyOfRetry.toString('base64'),
396423
type: responseOfRetry.headers()['content-type']
397424
}
425+
if (ctx.config.useGlobalCache) {
426+
globalCache.set(requestUrl, {
427+
body: bodyOfRetry.toString('base64'),
428+
type: responseOfRetry.headers()['content-type']
429+
});
430+
}
398431
route.fulfill({
399432
status: responseOfRetry.status(),
400433
headers: responseOfRetry.headers(),
@@ -445,6 +478,7 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
445478
}
446479
}
447480

481+
448482
// Continue the request with the fetched response
449483
route.fulfill({
450484
status: response.status(),
@@ -650,6 +684,7 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
650684
} catch (error) {
651685
ctx.log.debug(`Network idle failed due to ${error}`);
652686
}
687+
653688

654689

655690
if (ctx.config.allowedAssets && ctx.config.allowedAssets.length) {
@@ -839,6 +874,28 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
839874
ctx.log.debug(`Processed options: ${JSON.stringify(processedOptions)}`);
840875
}
841876

877+
// Wait for pending requests to complete
878+
const checkPending = async () => {
879+
let startTime = Date.now();
880+
ctx.log.debug(`${pendingRequests.size} Pending requests before wait for ${snapshot.name}: ${Array.from(pendingRequests)}`);
881+
while (pendingRequests.size > 0) {
882+
const elapsedTime = Date.now() - startTime;
883+
if (elapsedTime >= MAX_WAIT_FOR_REQUEST_CALL) {
884+
ctx.log.debug(`Timeout reached (${MAX_WAIT_FOR_REQUEST_CALL/1000}s). Stopping wait for pending requests.`);
885+
ctx.log.debug(`${pendingRequests.size} Pending requests after wait for ${snapshot.name}: ${Array.from(pendingRequests)}`);
886+
break;
887+
}
888+
await new Promise(resolve => setTimeout(resolve, 1000));
889+
}
890+
if(pendingRequests.size === 0) {
891+
ctx.log.debug(`No pending requests for ${snapshot.name}.`);
892+
}
893+
};
894+
895+
if (ctx.build.checkPendingRequests) {
896+
await checkPending();
897+
}
898+
842899

843900
let hasBrowserErrors = false;
844901
for (let browser in discoveryErrors.browsers) {

src/lib/utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ export function startPdfPolling(ctx: Context) {
545545
try {
546546
const response = await ctx.client.fetchPdfResults(ctx);
547547

548-
if (response.screenshots && response.build?.build_status === constants.BUILD_COMPLETE) {
548+
if (response.screenshots && response.build?.build_status !== constants.BUILD_RUNNING) {
549549
clearInterval(interval);
550550

551551
const pdfGroups = groupScreenshotsByPdf(response.screenshots);
@@ -758,12 +758,14 @@ export async function listenToSmartUISSE(
758758
const abortController = new AbortController();
759759

760760
try {
761+
const cookieKey = baseURL === 'https://server-events.lambdatest.com' ? 'accessToken' : 'stageAccessToken';
762+
761763
const response = await fetch(url, {
762764
method: 'GET',
763765
headers: {
764766
'Accept': 'text/event-stream',
765767
'Cache-Control': 'no-cache',
766-
'Cookie': `stageAccessToken=Basic ${accessToken}`
768+
'Cookie': `${cookieKey}=Basic ${accessToken}`
767769
},
768770
signal: abortController.signal
769771
});

src/tasks/createBuild.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default (ctx: Context): ListrTask<Context, ListrRendererFactory, ListrRen
1818
url: resp.data.buildURL,
1919
baseline: resp.data.baseline,
2020
useKafkaFlow: resp.data.useKafkaFlow || false,
21+
checkPendingRequests: resp.data.checkPendingRequests || false,
2122
}
2223
process.env.SMARTUI_BUILD_ID = resp.data.buildId;
2324
process.env.SMARTUI_BUILD_NAME = resp.data.buildName;

src/tasks/createBuildExec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export default (ctx: Context): ListrTask<Context, ListrRendererFactory, ListrRen
2020
url: resp.data.buildURL,
2121
baseline: resp.data.baseline,
2222
useKafkaFlow: resp.data.useKafkaFlow || false,
23+
checkPendingRequests: resp.data.checkPendingRequests || false,
2324
}
2425
process.env.SMARTUI_BUILD_ID = resp.data.buildId;
2526
process.env.SMARTUI_BUILD_NAME = resp.data.buildName;

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ export interface Build {
201201
useKafkaFlow: boolean;
202202
hasDiscoveryError: boolean;
203203
projectId?: string;
204+
checkPendingRequests: boolean;
204205
}
205206

206207
export interface WebConfig {

0 commit comments

Comments
 (0)