creevey
Version:
Cross-browser screenshot testing tool for Storybook with fancy UI Runner
282 lines (233 loc) • 10.8 kB
JavaScript
;
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);
}
});
}