UNPKG

creevey

Version:

Cross-browser screenshot testing tool for Storybook with fancy UI Runner

282 lines (233 loc) 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.withCreevey = withCreevey; var _coreEvents = _interopRequireDefault(require("@storybook/core-events")); var _addons = require("@storybook/addons"); var _types = require("../../types"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } if ((typeof process === "undefined" ? "undefined" : _typeof(process)) != 'object' || typeof process.version != 'string') { // NOTE If you don't use babel-polyfill or any other polyfills that add EventSource for IE11 // You don't get hot reload in IE11. So put polyfill for that to better UX // Don't load in nodejs environment // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment var _require = require('event-source-polyfill'), NativeEventSource = _require.NativeEventSource, EventSourcePolyfill = _require.EventSourcePolyfill; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment window.EventSource = NativeEventSource || EventSourcePolyfill; } var disableAnimationsStyles = "\n*,\n*:hover,\n*::before,\n*::after {\n animation-delay: -0.0001ms !important;\n animation-duration: 0s !important;\n animation-play-state: paused !important;\n cursor: none !important;\n caret-color: transparent !important;\n transition: 0s !important;\n}\n"; function resetCurrentStory(_x) { return _resetCurrentStory.apply(this, arguments); } function _resetCurrentStory() { _resetCurrentStory = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(channel) { return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: setTimeout(function () { return channel.emit(_coreEvents.default.SET_CURRENT_STORY, { storyId: true, name: '', kind: '' }); }, 0); return _context3.abrupt("return", new Promise(function (resolve) { return channel.once(_coreEvents.default.STORY_MISSING, resolve); })); case 2: case "end": return _context3.stop(); } } }, _callee3); })); return _resetCurrentStory.apply(this, arguments); } function catchRenderError(channel) { var rejectCallback; var promise = new Promise(function (_resolve, reject) { return rejectCallback = reject; }); function errorHandler(_ref) { var title = _ref.title, description = _ref.description; rejectCallback({ message: title, stack: description }); } function exceptionHandler(exception) { rejectCallback(exception); } function removeHandlers() { channel.off(_coreEvents.default.STORY_ERRORED, errorHandler); channel.off(_coreEvents.default.STORY_THREW_EXCEPTION, errorHandler); } channel.once(_coreEvents.default.STORY_ERRORED, errorHandler); channel.once(_coreEvents.default.STORY_THREW_EXCEPTION, exceptionHandler); return Object.assign(promise, { cancel: removeHandlers }); } function waitForStoryRendered(channel) { var resolveCallback; var promise = new Promise(function (resolve) { return resolveCallback = resolve; }); function renderHandler() { resolveCallback(); } function removeHandlers() { channel.off(_coreEvents.default.STORY_RENDERED, renderHandler); } channel.once(_coreEvents.default.STORY_RENDERED, renderHandler); return Object.assign(promise, { cancel: removeHandlers }); } function waitForFontsLoaded() { if (!document.fonts) return; var areFontsLoading = Array.from(document.fonts).some(function (font) { return font.status == 'loading'; }); if (areFontsLoading) { return new Promise(function (resolve) { var fontsLoadedHandler = function fontsLoadedHandler() { document.fonts.removeEventListener('loadingdone', fontsLoadedHandler); resolve(); }; document.fonts.addEventListener('loadingdone', fontsLoadedHandler); }); } } function withCreevey() { var currentStory = ''; var isAnimationDisabled = false; function disableAnimation() { isAnimationDisabled = true; var style = document.createElement('style'); var textNode = document.createTextNode(disableAnimationsStyles); style.setAttribute('type', 'text/css'); style.appendChild(textNode); document.head.appendChild(style); } function selectStory(_x2, _x3, _x4, _x5, _x6) { return _selectStory.apply(this, arguments); } function _selectStory() { _selectStory = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(storyId, kind, name, shouldWaitForReady, callback) { var channel, waitForReady, renderPromise, errorPromise, _reason$stack, errorMessage; return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (!isAnimationDisabled) disableAnimation(); channel = _addons.addons.getChannel(); waitForReady = shouldWaitForReady ? new Promise(function (resolve) { return window.__CREEVEY_SET_READY_FOR_CAPTURE__ = resolve; }) : Promise.resolve(); if (!(storyId == currentStory)) { _context2.next = 8; break; } _context2.next = 6; return resetCurrentStory(channel); case 6: _context2.next = 9; break; case 8: currentStory = storyId; case 9: renderPromise = waitForStoryRendered(channel); errorPromise = catchRenderError(channel); setTimeout(function () { return channel.emit(_coreEvents.default.SET_CURRENT_STORY, { storyId: storyId, name: name, kind: kind }); }, 0); _context2.prev = 12; _context2.next = 15; return Promise.race([_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() { return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.next = 2; return waitForStoryRendered(channel); case 2: _context.next = 4; return waitForFontsLoaded(); case 4: _context.next = 6; return waitForReady; case 6: case "end": return _context.stop(); } } }, _callee); }))(), errorPromise]); case 15: callback(); _context2.next = 22; break; case 18: _context2.prev = 18; _context2.t0 = _context2["catch"](12); // NOTE Event `STORY_THREW_EXCEPTION` triggered only in react and vue frameworks and return Error instance // NOTE Event `STORY_ERRORED` return error-like object without `name` field errorMessage = _context2.t0 instanceof Error ? (_reason$stack = _context2.t0.stack) !== null && _reason$stack !== void 0 ? _reason$stack : _context2.t0.message : (0, _types.isObject)(_context2.t0) ? "".concat(_context2.t0.message, "\n ").concat(_context2.t0.stack) : _context2.t0; callback(errorMessage); case 22: _context2.prev = 22; renderPromise.cancel(); errorPromise.cancel(); return _context2.finish(22); case 26: case "end": return _context2.stop(); } } }, _callee2, null, [[12, 18, 22, 26]]); })); return _selectStory.apply(this, arguments); } function updateGlobals(globals) { _addons.addons.getChannel().emit(_coreEvents.default.UPDATE_GLOBALS, { globals: globals }); } function insertIgnoreStyles(ignoreSelectors) { var stylesElement = document.createElement('style'); stylesElement.setAttribute('type', 'text/css'); document.head.appendChild(stylesElement); ignoreSelectors.forEach(function (selector) { stylesElement.innerHTML += "\n ".concat(selector, " {\n background: #000 !important;\n box-shadow: none !important;\n text-shadow: none !important;\n outline: 0 !important;\n color: rgba(0,0,0,0) !important;\n }\n ").concat(selector, " *, ").concat(selector, "::before, ").concat(selector, "::after {\n visibility: hidden !important;\n }\n "); }); return stylesElement; } function removeIgnoreStyles(ignoreStyles) { var _ignoreStyles$parentN; (_ignoreStyles$parentN = ignoreStyles.parentNode) === null || _ignoreStyles$parentN === void 0 ? void 0 : _ignoreStyles$parentN.removeChild(ignoreStyles); } window.__CREEVEY_SELECT_STORY__ = selectStory; window.__CREEVEY_UPDATE_GLOBALS__ = updateGlobals; window.__CREEVEY_INSERT_IGNORE_STYLES__ = insertIgnoreStyles; window.__CREEVEY_REMOVE_IGNORE_STYLES__ = removeIgnoreStyles; window.__CREEVEY_SET_READY_FOR_CAPTURE__ = _types.noop; return (0, _addons.makeDecorator)({ name: 'withCreevey', parameterName: 'creevey', wrapper: function wrapper(getStory, context) { return getStory(context); } }); }