Skip to content

Commit afe7ca2

Browse files
Merge pull request #414 from shrinishLT/DOT-3556-D
add customCSS support
2 parents 7c1333c + d28b853 commit afe7ca2

File tree

6 files changed

+332
-3
lines changed

6 files changed

+332
-3
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"json-stringify-safe": "^5.0.1",
4444
"listr2": "^7.0.1",
4545
"node-cache": "^5.1.2",
46+
"postcss": "^8.5.6",
4647
"sharp": "^0.33.4",
4748
"tsup": "^7.2.0",
4849
"uuid": "^11.0.3",

src/lib/ctx.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import logger from './logger.js'
66
import getEnv from './env.js'
77
import httpClient from './httpClient.js'
88
import fs from 'fs'
9+
import { resolveCustomCSS } from './utils.js'
910

1011
export default (options: Record<string, string>): Context => {
1112
let env: Env = getEnv();
@@ -52,6 +53,20 @@ export default (options: Record<string, string>): Context => {
5253
if (!validateConfigFn(config)) {
5354
throw new Error(validateConfigFn.errors[0].message);
5455
}
56+
57+
// Resolve customCSS if provided
58+
if ((config as any).customCSS) {
59+
try {
60+
(config as any).customCSS = resolveCustomCSS(
61+
(config as any).customCSS,
62+
options.config,
63+
logger
64+
);
65+
logger.debug('Successfully resolved and validated customCSS from config');
66+
} catch (error: any) {
67+
throw new Error(`customCSS error: ${error.message}`);
68+
}
69+
}
5570
} else {
5671
logger.info("## No config file provided. Using default config.");
5772
}
@@ -155,7 +170,8 @@ export default (options: Record<string, string>): Context => {
155170
loadDomContent: loadDomContent,
156171
approvalThreshold: config.approvalThreshold,
157172
rejectionThreshold: config.rejectionThreshold,
158-
showRenderErrors: config.showRenderErrors ?? false
173+
showRenderErrors: config.showRenderErrors ?? false,
174+
customCSS: (config as any).customCSS
159175
},
160176
uploadFilePath: '',
161177
webStaticConfig: [],

src/lib/processSnapshot.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { Snapshot, Context, DiscoveryErrors } from "../types.js";
2-
import { scrollToBottomAndBackToTop, getRenderViewports, getRenderViewportsForOptions, validateCoordinates } from "./utils.js"
2+
import { scrollToBottomAndBackToTop, getRenderViewports, getRenderViewportsForOptions, validateCoordinates, resolveCustomCSS, parseCSSFile, validateCSSSelectors, generateCSSInjectionReport } from "./utils.js"
33
import { chromium, Locator } from "@playwright/test"
44
import constants from "./constants.js";
55
import { updateLogContext } from '../lib/logger.js'
66
import NodeCache from 'node-cache';
7+
import chalk from "chalk";
78

89
const globalCache = new NodeCache({ stdTTL: 3600, checkperiod: 600 });
910
const MAX_RESOURCE_SIZE = 15 * (1024 ** 2); // 15MB
@@ -168,6 +169,20 @@ export async function prepareSnapshot(snapshot: Snapshot, ctx: Context): Promise
168169
processedOptions.useExtendedViewport = true;
169170
}
170171

172+
try {
173+
if (options?.customCSS) {
174+
const resolvedCSS = resolveCustomCSS(options.customCSS, '', ctx.log);
175+
processedOptions.customCSS = resolvedCSS;
176+
ctx.log.debug('Using per-snapshot customCSS (overriding config)');
177+
} else if (ctx.config.customCSS) {
178+
processedOptions.customCSS = ctx.config.customCSS;
179+
ctx.log.debug('Using config customCSS');
180+
}
181+
} catch (error: any) {
182+
ctx.log.warn(`customCSS warning: ${error.message}`);
183+
chalk.yellow(`[SmartUI] warning: ${error.message}`);
184+
}
185+
171186
processedOptions.allowedAssets = ctx.config.allowedAssets;
172187
processedOptions.selectors = selectors;
173188

@@ -611,6 +626,19 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
611626
processedOptions.useExtendedViewport = true;
612627
}
613628

629+
try {
630+
if (options?.customCSS) {
631+
const resolvedCSS = resolveCustomCSS(options.customCSS, '', ctx.log);
632+
processedOptions.customCSS = resolvedCSS;
633+
} else if (ctx.config.customCSS) {
634+
processedOptions.customCSS = ctx.config.customCSS;
635+
}
636+
} catch (error: any) {
637+
optionWarnings.add(`${error.message}`);
638+
}
639+
640+
ctx.log.debug(`Processed options: ${JSON.stringify(processedOptions)}`);
641+
614642
// process for every viewport
615643
let navigated: boolean = false;
616644
let previousDeviceType: string | null = null;
@@ -896,6 +924,24 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
896924
await checkPending();
897925
}
898926

927+
// Validate and report CSS injection after selector processing
928+
if (processedOptions.customCSS) {
929+
try {
930+
const cssRules = parseCSSFile(processedOptions.customCSS);
931+
const validationResult = await validateCSSSelectors(page, cssRules, ctx.log);
932+
const report = generateCSSInjectionReport(validationResult, ctx.log);
933+
934+
if (validationResult.failedSelectors.length > 0) {
935+
validationResult.failedSelectors.forEach(selector => {
936+
optionWarnings.add(`customCSS selector not found: ${selector}`);
937+
});
938+
}
939+
} catch (error: any) {
940+
ctx.log.warn(`CSS validation failed: ${error.message}`);
941+
optionWarnings.add(`CSS validation error: ${error.message}`);
942+
}
943+
}
944+
899945

900946
let hasBrowserErrors = false;
901947
for (let browser in discoveryErrors.browsers) {

src/lib/schemaValidation.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ const ConfigSchema = {
284284
type: "boolean",
285285
errorMessage: "Invalid config; loadDomContent must be true/false"
286286
},
287+
customCSS: {
288+
type: "string",
289+
errorMessage: "Invalid config; customCSS must be a string"
290+
},
287291
approvalThreshold: {
288292
type: "number",
289293
minimum: 0,
@@ -594,6 +598,10 @@ const SnapshotSchema: JSONSchemaType<Snapshot> = {
594598
minProperties: 1,
595599
},
596600
errorMessage: "Invalid snapshot options; customCookies must be an array of objects with string properties"
601+
},
602+
customCSS: {
603+
type: "string",
604+
errorMessage: "Invalid snapshot options; customCSS must be a string"
597605
}
598606
},
599607
additionalProperties: false

0 commit comments

Comments
 (0)