UNPKG

testplane

Version:

Tests framework based on mocha and wdio

112 lines 6.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CSSSelectivity = void 0; const lodash_1 = require("lodash"); const node_path_1 = __importDefault(require("node:path")); const node_url_1 = require("node:url"); const constants_1 = require("../../../error-snippets/constants"); const utils_1 = require("./utils"); class CSSSelectivity { constructor(cdp, sessionId, sourceRoot = "") { this._cssOnStyleSheetAddedFn = null; this._stylesSourceMap = {}; this._cdp = cdp; this._sessionId = sessionId; this._sourceRoot = sourceRoot; } _processStyle({ header: { styleSheetId, sourceURL, sourceMapURL } }) { if (!this._sessionId) { return; } if (!sourceURL || !sourceMapURL) { this._stylesSourceMap[styleSheetId] ||= null; return; } this._stylesSourceMap[styleSheetId] ||= (0, utils_1.fetchTextWithBrowserFallback)((0, node_url_1.resolve)(sourceURL, sourceMapURL), this._cdp.runtime, this._sessionId); } async start() { const cssOnStyleSheetAdded = (this._cssOnStyleSheetAddedFn = this._processStyle.bind(this)); this._cdp.css.on("styleSheetAdded", cssOnStyleSheetAdded); await Promise.all([ this._cdp.target.setAutoAttach(this._sessionId, { autoAttach: true, waitForDebuggerOnStart: false }), this._cdp.dom .enable(this._sessionId) .then(() => this._cdp.css.enable(this._sessionId)) .then(() => this._cdp.css.startRuleUsageTracking(this._sessionId)), ]); } /** @param drop only performs cleanup without providing actual deps. Should be "true" if test is failed */ async stop(drop) { if (drop) { this._cssOnStyleSheetAddedFn && this._cdp.css.off("styleSheetAdded", this._cssOnStyleSheetAddedFn); return null; } const coverage = await this._cdp.css.stopRuleUsageTracking(this._sessionId); // If we haven't got "styleSheetAdded" event for the script, pull up styles + source map manually coverage.ruleUsage.forEach(({ styleSheetId }) => { if (Object.hasOwn(this._stylesSourceMap, styleSheetId)) { return; } const scriptSourcePromise = this._cdp.css .getStyleSheetText(this._sessionId, styleSheetId) .then(res => res.text) .catch((err) => err); this._stylesSourceMap[styleSheetId] ||= scriptSourcePromise.then(sourceCode => { if (sourceCode instanceof Error) { return sourceCode; } const sourceMapsStartIndex = sourceCode.lastIndexOf(constants_1.CSS_SOURCE_MAP_URL_COMMENT); const sourceMapsEndIndex = sourceCode.indexOf("*/", sourceMapsStartIndex); if (sourceMapsStartIndex === -1) { return new Error("Source maping url comment is missing"); } const sourceMapURL = sourceMapsEndIndex === -1 ? sourceCode.slice(sourceMapsStartIndex + constants_1.CSS_SOURCE_MAP_URL_COMMENT.length) : sourceCode.slice(sourceMapsStartIndex + constants_1.CSS_SOURCE_MAP_URL_COMMENT.length, sourceMapsEndIndex); const isSourceMapEmbedded = new node_url_1.URL(sourceMapURL).protocol === "data:"; // If we encounter css stylesheet, that was not reported by "styleSheetAdded" // We can only get sourcemaps if they are inlined // Otherwise, we can't resolve actual sourcemaps url because we dont know css styles url itself. if (!isSourceMapEmbedded) { return new Error([ `Missed stylesheet url for stylesheet id ${styleSheetId}.`, "Switching to inline sourcemaps for CSS will help", ].join("\n")); } return (0, utils_1.fetchTextWithBrowserFallback)(sourceMapURL, this._cdp.runtime, this._sessionId); }); }); const totalDependingSourceFiles = new Set(); const grouppedByStyleSheetCoverage = (0, lodash_1.groupBy)(coverage.ruleUsage, "styleSheetId"); const styleSheetIds = Object.keys(grouppedByStyleSheetCoverage); await Promise.all(styleSheetIds.map(async (styleSheetId) => { const sourceMapString = await this._stylesSourceMap[styleSheetId]; if (!sourceMapString) { return; } if (sourceMapString instanceof Error) { throw new Error(`CSS Selectivity: Couldn't load source maps for stylesheet id ${styleSheetId}: ${sourceMapString}`); } const rawSourceMap = (0, utils_1.patchSourceMapSources)(JSON.parse(sourceMapString), this._sourceRoot); // We could check "if stylesheet was used" with utils.extractSourceFilesDeps // But we dont, because if stylesheet was not used, it could be used after change // So its safe to think "if stylesheet was loaded, it was used" rawSourceMap.sources.forEach(sourceFilePath => { // "Each entry is either a string that is a (potentially relative) URL", so we are using posix.jojn // https://tc39.es/ecma426/#sec-source-map-format // Except for file path with protocol ("turbopack://", "file://") const sourceRootBasedPath = (0, utils_1.hasProtocol)(sourceFilePath) ? sourceFilePath : node_path_1.default.posix.join(rawSourceMap.sourceRoot || "", sourceFilePath); totalDependingSourceFiles.add(sourceRootBasedPath); }); })); this._cssOnStyleSheetAddedFn && this._cdp.css.off("styleSheetAdded", this._cssOnStyleSheetAddedFn); return totalDependingSourceFiles; } } exports.CSSSelectivity = CSSSelectivity; //# sourceMappingURL=css-selectivity.js.map