UNPKG

lucid-ui

Version:

A UI component library from Xandr.

278 lines 16.5 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.mockDate = exports.functionalComponents = exports.controls = exports.passThroughs = exports.icons = exports.common = void 0; var sinon_1 = __importDefault(require("sinon")); var path_1 = require("path"); var react_1 = __importDefault(require("react")); var prop_types_1 = __importDefault(require("prop-types")); var enzyme_1 = require("enzyme"); var assert_1 = __importDefault(require("assert")); var lodash_1 = __importStar(require("lodash")); var glob_1 = __importDefault(require("glob")); var addons_1 = require("@storybook/addons"); var timekeeper_1 = __importDefault(require("timekeeper")); addons_1.addons.setChannel((0, addons_1.mockChannel)()); // Common tests for all our components function common(Component, config) { if (config === void 0) { config = {}; } var _a = config.getDefaultProps, getDefaultProps = _a === void 0 ? lodash_1.default.constant({}) : _a, _b = config.exemptFunctionProps, exemptFunctionProps = _b === void 0 ? [] : _b, _c = config.exemptChildComponents, exemptChildComponents = _c === void 0 ? [] : _c, _d = config.selectRoot, selectRoot = _d === void 0 ? lodash_1.default.identity : _d, _e = config.noExport, noExport = _e === void 0 ? false : _e; function generateDefaultProps(props) { if (props === void 0) { props = {}; } return lodash_1.default.assign({}, getDefaultProps(), props); } describe('[common]', function () { if (!Component) { throw new Error('An undefined component was passed to generic tests.'); } if (Component._isLucidHybridComponent) { throw new Error("You're trying to run generic tests on a hybrid component which is bad and won't work and will make you cry. Check your spec files for ".concat(Component.displayName, " and import the raw component instead of the hybrid version.")); } it('should have a `displayName` defined', function () { (0, assert_1.default)(Component.displayName); }); it('should pass through styles to the root element', function () { var style = { backgroundColor: '#f0f', }; var wrapper = (0, enzyme_1.shallow)(react_1.default.createElement(Component, __assign({}, generateDefaultProps(), { style: style })), { disableLifecycleMethods: true }); var rootWrapper = selectRoot(wrapper).first(); var rootStyle = rootWrapper.prop('style'); (0, assert_1.default)(lodash_1.default.every(style, function (val, key) { return val === rootStyle[key]; }), 'root style must contain passed styles'); }); it('should pass through `className`', function () { var expectedClass = 'rAnDoM'; var wrapper = (0, enzyme_1.shallow)(react_1.default.createElement(Component, __assign({}, generateDefaultProps(), { className: expectedClass })), { disableLifecycleMethods: true }); var rootWrapper = selectRoot(wrapper).first(); var classNames = rootWrapper.prop('className').split(' '); (0, assert_1.default)(lodash_1.default.includes(classNames, expectedClass), "'".concat(classNames, "' should include '").concat(expectedClass, "'")); }); it('should have an application scoped base class', function () { var expectedClass = 'lucid-' + Component.displayName; var wrapper = (0, enzyme_1.shallow)(react_1.default.createElement(Component, __assign({}, generateDefaultProps())), { disableLifecycleMethods: true, }); var rootWrapper = selectRoot(wrapper).first(); var classNames = rootWrapper.prop('className').split(' '); (0, assert_1.default)(lodash_1.default.includes(classNames, expectedClass), "'".concat(classNames, "' should include '").concat(Component.displayName, "'")); }); it('should have only application scoped classes', function () { var wrapper = (0, enzyme_1.shallow)(react_1.default.createElement(Component, __assign({}, generateDefaultProps())), { disableLifecycleMethods: true, }); var rootWrapper = selectRoot(wrapper).first(); var parentClasses = rootWrapper.prop('className').split(' '); var childrenClasses = rootWrapper.children().reduce(function (acc, node) { if (!node.prop('className')) { return acc; } return acc.concat(node.prop('className').split(' ')); }, []); var allClasses = parentClasses.concat(childrenClasses); lodash_1.default.forEach(allClasses, function (className) { (0, assert_1.default)(lodash_1.default.includes(className, "lucid-".concat(Component.displayName)), "".concat(className, " must be scoped")); }); }); describe('function propTypes', function () { var funcProps = lodash_1.default.pickBy(Component.propTypes, function (propType) { return propType === prop_types_1.default.func; }); lodash_1.default.forEach(funcProps, function (propType, propName) { it("".concat(propName, " should only use onX convention for function proptypes"), function () { (0, assert_1.default)(lodash_1.default.startsWith(propName, 'on') || lodash_1.default.includes(exemptFunctionProps, propName), "".concat(propName, " must follow onX convention")); }); }); }); describe('child components', function () { // Child components are all function types which start with a capital letter var childComponents = lodash_1.default.pickBy(Component, function (value, key) { return /^[A-Z]/.test(key) && lodash_1.default.isFunction(value); }); describe('propNames in propTypes', function () { lodash_1.default.flow(function (x) { return lodash_1.default.map(x, 'propName'); }, function (x) { return lodash_1.default.compact(x); }, function (x) { return lodash_1.default.flatMap(x, lodash_1.default.castArray); }, function (x) { return lodash_1.default.reject(x, function (propName) { return lodash_1.default.includes(exemptChildComponents, propName); }); }, function (x) { return lodash_1.default.forEach(x, function (propName) { it("should include ".concat(propName, " in propTypes"), function () { (0, assert_1.default)(Component.propTypes[propName], "must include ".concat(propName, " in propTypes")); }); }); })(childComponents); }); }); describe('example testing', function () { var fileNames = glob_1.default.sync("./src/components/**/".concat(Component.displayName, "/*.stories.@(j|t)sx")); (0, lodash_1.each)(fileNames, function (path) { var lib = require('../../' + path.replace('.tsx', '')); (0, lodash_1.each)((0, lodash_1.omit)(lib, ['default']), function (Story, name) { it("should match snapshot(s) for ".concat(name), function () { var result; try { result = (0, enzyme_1.render)(react_1.default.createElement(Story, __assign({}, Story.args)), { disableLifecycleMethods: true, }); expect(result).toMatchSnapshot(); } catch (err) { expect(err).toMatchSnapshot(); } }); }); }); // Support for older examples var exampleFileNames = glob_1.default.sync("./src/components/**/".concat(Component.displayName, "/examples/*.@(j|t)sx")); lodash_1.default.each(exampleFileNames, function (path) { var lib = require('../../' + path.replace('.tsx', '')); var Example = lib.default; var title = (0, path_1.parse)(path).name; it("should match snapshot(s) for ".concat(title), function () { var shallowExample = (0, enzyme_1.shallow)(react_1.default.createElement(Example, null), { disableLifecycleMethods: true, }); // If the root of the example is an instance of the Component under test, snapshot it. // Otherwise, look under the root for instances of the Component and snapshot those. if (shallowExample.is(Component.displayName)) { expect((0, enzyme_1.shallow)(react_1.default.createElement(Component, __assign({}, shallowExample.props())), { disableLifecycleMethods: true, })).toMatchSnapshot(); } else { shallowExample.find(Component.displayName).forEach(function (example) { expect((0, enzyme_1.shallow)(react_1.default.createElement(Component, __assign({}, example.props())), { disableLifecycleMethods: true, })).toMatchSnapshot(); }); } }); }); }); }); } exports.common = common; function icons(Component, config) { if (config === void 0) { config = {}; } // The default expectation is for every Icon to omit `initailState`, // if it is passed through to the underlying element var _a = config.includeInitialState, includeInitialState = _a === void 0 ? false : _a; describe('[icon]', function () { it('should almost always omit the `initialState` key', function () { var wrapper = (0, enzyme_1.shallow)(react_1.default.createElement(Component, { initialState: { testState: true } })); var rootProps = (0, lodash_1.keys)(wrapper.first().props()); expect((0, lodash_1.includes)(rootProps, 'initialState')).toBe(includeInitialState); }); it('should add the correct class for isClickable', function () { var wrapper = (0, enzyme_1.mount)(react_1.default.createElement(Component, { isClickable: true })); var targetClassName = 'lucid-Icon-is-clickable'; (0, assert_1.default)(wrapper.find('svg').hasClass(targetClassName), "Missing '".concat(targetClassName, "' class")); }); }); } exports.icons = icons; function passThroughs(Component, config) { if (config === void 0) { config = {}; } // The default expectation is for every Component to omit `initialState`, // if it is passed through to the underlying element var _a = config.includeInitialState, includeInitialState = _a === void 0 ? false : _a; describe('pass throughs', function () { it('should almost always omit the `initialState` key', function () { var wrapper = (0, enzyme_1.shallow)(react_1.default.createElement(Component, { initialState: { testState: true } })); var rootElementProps = (0, lodash_1.keys)(wrapper.first().props()); expect((0, lodash_1.includes)(rootElementProps, 'initialState')).toBe(includeInitialState); }); it('should pass through all props not defined in `propTypes` to the root element', function () { var wrapper = (0, enzyme_1.shallow)(react_1.default.createElement(Component, __assign({}, { foo: 1, bar: 2, baz: 3, qux: 4, quux: 5, }))); var rootElementProps = (0, lodash_1.keys)(wrapper.first().props()); // It should pass `foo`, `bar`, `baz`, `qux`, and `quux` // to the root element. (0, lodash_1.forEach)(['foo', 'bar', 'baz', 'qux', 'quux'], function (prop) { expect((0, lodash_1.includes)(rootElementProps, prop)).toBe(true); }); }); }); } exports.passThroughs = passThroughs; // Common tests for all control components function controls(Component, _a) { var callbackName = _a.callbackName, controlSelector = _a.controlSelector, eventType = _a.eventType, _b = _a.additionalProps, additionalProps = _b === void 0 ? {} : _b; // Use DOM tests here since some of our controls use dom events under the hood describe('[control]', function () { it('should callback with `event` and `props`', function () { var _a; var expectedSpecialProp = 32; var props = __assign((_a = { specialprop: expectedSpecialProp }, _a[callbackName] = sinon_1.default.spy(), _a), additionalProps); var wrapper = (0, enzyme_1.mount)(react_1.default.createElement(Component, __assign({}, props))); wrapper.find(controlSelector).first().simulate(eventType); // Last argument should be an object with `uniqueId` and `event` var _b = lodash_1.default.last(props[callbackName].args[0]), specialprop = _b.props.specialprop, event = _b.event; (0, assert_1.default)(event, 'missing event'); assert_1.default.equal(specialprop, expectedSpecialProp, 'incorrect or missing specialProp'); }); }); } exports.controls = controls; // Common tests for all Functional Components // // These tests are intended to help us make sure our FCs are shaped corrected. // They are necessary because there isn't a perfect way to get the defaultProps // to be factored in correctly yet with React/TypeScript: // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30695#issuecomment-474780159 function functionalComponents(FC) { // Use DOM tests here since some of our controls use dom events under the hood describe('[functionalComponent]', function () { it('should have the correct `peek` properties', function () { expect(FC.propName === undefined || typeof FC.propName === 'string').toBe(true); expect(FC._isPrivate === undefined || typeof FC._isPrivate === 'boolean').toBe(true); expect(typeof FC.peek).toBe('object'); expect(typeof FC.peek.description).toBe('string'); expect(FC.peek.extend === undefined || typeof FC.peek.extend === 'string').toBe(true); expect(FC.peek.extend === undefined || typeof FC.peek.extend === 'string').toBe(true); expect(FC.peek.categories === undefined || Array.isArray(FC.peek.categories)).toBe(true); expect(FC.peek.madeFrom === undefined || Array.isArray(FC.peek.madeFrom)).toBe(true); }); }); } exports.functionalComponents = functionalComponents; var mockDate = function (dateString) { timekeeper_1.default.freeze(new Date(dateString)); }; exports.mockDate = mockDate; //# sourceMappingURL=generic-tests.js.map