UNPKG

@testplane/storybook

Version:

Testplane plugin that enables runtime screenshot storybook tests autogeneration

270 lines (269 loc) 11.7 kB
"use strict"; var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var g = generator.apply(thisArg, _arguments || []), i, q = []; return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } function fulfill(value) { resume("next", value); } function reject(value) { resume("throw", value); } function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.extendStoriesFromStoryFile = void 0; const module_1 = __importDefault(require("module")); const inheritable_values_1 = require("./inheritable-values"); const Module = module_1.default; // eslint-disable-line @typescript-eslint/no-explicit-any const MockedModuleProxySymbol = Symbol("@testplane/storybook:mocked-module-proxy"); let loggedStoryFileRequireError = Boolean(process.env.TESTPLANE_STORYBOOK_DISABLE_STORY_REQUIRE_WARNING); function extendStoriesFromStoryFile(stories, { requireFn = require } = {}) { var _a, _b; const storiesMap = getStoriesMap(stories); const storyPath = stories[0].absolutePath; const storyFile = getStoryFile(storyPath, { requireFn }); const withStoryFileExtendedStories = stories; const storyExtendedBaseConfig = { skip: false, browserIds: null, assertViewOpts: {}, autoScreenshots: null, autoscreenshotSelector: null, autoScreenshotStorybookGlobals: {}, extraTests: null, }; if (!storyFile) { return withStoryFileExtendedStories.map(story => Object.assign(story, storyExtendedBaseConfig)); } const storyTestplaneDefaultConfigs = ((_a = storyFile.default) === null || _a === void 0 ? void 0 : _a.testplaneConfig) || ((_b = storyFile.default) === null || _b === void 0 ? void 0 : _b.testplane) || {}; for (const storyName of Object.keys(storyFile)) { if (storyName === "default") { continue; } const storyMapKey = getStoryNameId(storyName); if (!storiesMap.has(storyMapKey)) { continue; } const storyContents = removeNestedMockedPropertiesPaths(storyFile[storyName]); const storyTestlaneConfigs = storyContents.testplaneConfig || {}; const story = storiesMap.get(storyMapKey); Object.assign(story, storyExtendedBaseConfig, storyTestplaneDefaultConfigs, storyTestlaneConfigs, { extraTests: storyContents.testplane || null, }); story.assertViewOpts = (0, inheritable_values_1.extractInheritedValue)((0, inheritable_values_1.inheritValue)(storyTestplaneDefaultConfigs.assertViewOpts, storyTestlaneConfigs.assertViewOpts), storyExtendedBaseConfig.assertViewOpts); story.autoScreenshotStorybookGlobals = (0, inheritable_values_1.inheritValue)(storyExtendedBaseConfig.autoScreenshotStorybookGlobals, storyTestplaneDefaultConfigs.autoScreenshotStorybookGlobals, storyTestlaneConfigs.autoScreenshotStorybookGlobals) || {}; } for (const story of withStoryFileExtendedStories) { for (const essentialProperty in storyExtendedBaseConfig) { if (!Object.hasOwn(story, essentialProperty)) { Object.assign(story, { [essentialProperty]: storyExtendedBaseConfig[essentialProperty], }); } } } return withStoryFileExtendedStories; } exports.extendStoriesFromStoryFile = extendStoriesFromStoryFile; function getStoriesMap(stories) { const storiesMap = new Map(); stories.forEach(story => { storiesMap.set(getStoryNameId(story.name), story); }); return storiesMap; } function getStoryNameId(storyName) { // https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L166 // eslint-disable-next-line no-control-regex const nonAsciiWordRegExp = /[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; return storyName.replace(nonAsciiWordRegExp, "").toLowerCase(); } function getStoryFile(storyPath, { requireFn = require } = {}) { const unmockFn = mockLoaders({ except: storyPath }); const disableWarningsMessage = [ "There could be other story files.", "Set 'TESTPLANE_STORYBOOK_DISABLE_STORY_REQUIRE_WARNING' environment variable to hide this warning", ].join("\n"); let storyFile; try { storyFile = requireFn(storyPath); } catch (error) { if (!loggedStoryFileRequireError) { loggedStoryFileRequireError = true; const warningMessage = [ `Testplane custom section is ignored in storyfile "${storyPath}",`, `because the file could not be read:\n${error}\n${disableWarningsMessage}`, ].join(" "); console.warn(warningMessage); } } unmockFn(); const isStoryFileFailedToLoad = !storyFile || isMockedModuleProxy(storyFile); if (isStoryFileFailedToLoad) { return null; } const ignoredProperties = getStoryFilMockedeNestedPropertiesPaths(storyFile); if (ignoredProperties.length && !loggedStoryFileRequireError) { loggedStoryFileRequireError = true; const warningMessage = [ `Following Testplane custom properties are ignored in storyfile "${storyPath}":\n`, ...ignoredProperties.map(property => `- ${property}\n`), "Reason: Testplane couldn't handle imports in this file.\n", disableWarningsMessage, ].join(""); console.warn(warningMessage); } return storyFile; } function mockLoaders(opts) { const unmockModuleCbs = [".css", ".scss", ".svg", ".png", ".ico", ".jpg", ".jpeg", ".gif", ".yml"].map(mockModule); const unmockFailedModuleCbs = [".js", ".ts", ".jsx", ".tsx", ".mjs", ".mts"].map(ext => mockFailedModule(ext, opts)); const unmockCb = () => unmockModuleCbs.concat(unmockFailedModuleCbs).forEach(unmock => unmock()); return unmockCb; } function mockModule(extension) { const originalModule = Module._extensions[extension]; Module._extensions[extension] = () => void 0; return () => { Module._extensions[extension] = originalModule; }; } function isMockedModuleProxy(obj) { return Boolean(obj && obj[MockedModuleProxySymbol] === true); } function getStoryFilMockedeNestedPropertiesPaths(storyFile) { const results = []; const customProperties = ["testplane", "testplaneConfig"]; for (const exportName in storyFile) { if (isMockedModuleProxy(storyFile[exportName])) { results.push(exportName); } else { for (const customProperty of customProperties) { const customMockedProperties = getNestedMockedPropertiesPaths(storyFile[exportName][customProperty], `${exportName}.${customProperty}`); if (customMockedProperties) { results.push(...customMockedProperties); } } } } return results; } function getNestedMockedPropertiesPaths(obj, parentProperty = "") { if (!obj || (typeof obj !== "object" && typeof obj !== "function")) { return null; } if (isMockedModuleProxy(obj)) { return [parentProperty]; } const results = []; for (const property in obj) { const nestedValue = obj[property]; const nestedKey = parentProperty + "." + property; const nestedResults = getNestedMockedPropertiesPaths(nestedValue, nestedKey); if (nestedResults) { results.push(...nestedResults); } } return results.length ? results : null; } function removeNestedMockedPropertiesPaths(obj) { if (isMockedModuleProxy(obj)) { return {}; } if (!obj || typeof obj !== "object" || Array.isArray(obj)) { return obj; } const result = {}; for (const prop in obj) { const property = prop; if (!isMockedModuleProxy(obj[property])) { result[property] = removeNestedMockedPropertiesPaths(obj[property]); } } return result; } function mockFailedModule(extension, { except }) { const originalModule = Module._extensions[extension]; const getMockedModuleProxy = () => // eslint-disable-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-empty-function new Proxy(function () { }, { get: (_, prop) => { switch (prop) { // string conversion case "toString": case "valueOf": case Symbol.toPrimitive: return () => "[proxy Object]"; case Symbol.toStringTag: return "Proxy"; // iterators case Symbol.iterator: // eslint-disable-next-line @typescript-eslint/no-empty-function return function* () { }; case Symbol.asyncIterator: // eslint-disable-next-line @typescript-eslint/no-empty-function return function () { return __asyncGenerator(this, arguments, function* () { }); }; // string methods case Symbol.match: return false; case Symbol.matchAll: return () => null; case Symbol.search: return () => -1; case Symbol.split: return (str) => str; case Symbol.hasInstance: return () => false; case MockedModuleProxySymbol: return true; default: return getMockedModuleProxy(); } }, // traps apply: getMockedModuleProxy, construct: getMockedModuleProxy, // inspection getPrototypeOf: () => null, has: () => false, ownKeys: () => [], getOwnPropertyDescriptor: () => void 0, // extensibility checks isExtensible: () => true, preventExtensions: () => false, // mutation set: () => true, defineProperty: () => true, deleteProperty: () => true, setPrototypeOf: () => true, }); const applyMock = (filename) => { require.cache[filename].loaded = true; require.cache[filename].exports = getMockedModuleProxy(); }; Module._extensions[extension] = (m, filename) => { if (filename === except) { return originalModule(m, filename); } if (filename.includes("/node_modules/@storybook/")) { return applyMock(filename); } try { return originalModule(m, filename); } catch (e) { applyMock(filename); } }; return () => { Module._extensions[extension] = originalModule; }; } //# sourceMappingURL=extend-stories.js.map