diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..626c4f3 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +/lib +/node_modules diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..c199225 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,215 @@ +{ + "parser": "babel-eslint", + "plugins": [ + "babel", + "flow-vars", + "react" + ], + "env": { + "browser": true, + "node": true + }, + "globals": { + "Map": false + }, + "rules": { + "no-cond-assign": 1, // disallow assignment in conditional expressions + "no-console": 0, // disallow use of console: should use nuclide-logging instead + "no-constant-condition": 1, // disallow use of constant expressions in conditions + "no-control-regex": 1, // disallow control characters in regular expressions + "no-debugger": 1, // disallow use of debugger + "no-dupe-keys": 1, // disallow duplicate keys when creating object literals + "no-dupe-args": 1, // disallow duplicate arguments in functions + "no-duplicate-case": 1, // disallow a duplicate case label + "no-empty": 0, // disallow empty statements + "no-empty-character-class": 1, // disallow the use of empty character classes in regular expressions + "no-ex-assign": 1, // disallow assigning to the exception in a catch block + "no-extra-boolean-cast": 1, // disallow double-negation boolean casts in a boolean context + "no-extra-semi": 1, // disallow unnecessary semicolons + "no-func-assign": 1, // disallow overwriting functions written as function declarations + "no-inner-declarations": 0, // disallow function or variable declarations in nested blocks + "no-invalid-regexp": 1, // disallow invalid regular expression strings in the RegExp constructor + "no-negated-in-lhs": 1, // disallow negation of the left operand of an in expression + "no-obj-calls": 1, // disallow the use of object properties of the global object (Math and JSON) as functions + "no-regex-spaces": 1, // disallow multiple spaces in a regular expression literal + "no-reserved-keys": 0, // disallow reserved words being used as object literal keys + "no-sparse-arrays": 1, // disallow sparse arrays + "no-unreachable": 1, // disallow unreachable statements after a return, throw, continue, or break statement + "use-isnan": 1, // disallow comparisons with the value NaN + "valid-jsdoc": 0, // Ensure JSDoc comments are valid + "valid-typeof": 1, // Ensure that the results of typeof are compared against a valid string + + // Best Practices (designed to prevent you from making mistakes) + + "block-scoped-var": 0, // treat var statements as if they were block scoped + "complexity": 0, // specify the maximum cyclomatic complexity allowed in a program + "consistent-return": 0, // require return statements to either always or never specify values + "curly": 1, // specify curly brace conventions for all control statements + "default-case": 0, // require default case in switch statements + "dot-notation": 0, // dot notation encouraged except for foreign properties that cannot be renamed (i.e., Closure Compiler rules) + "eqeqeq": [1, "allow-null"], // require the use of === and !== + "guard-for-in": 1, // make sure for-in loops have an if statement + "no-alert": 1, // disallow the use of alert, confirm, and prompt + "no-caller": 1, // disallow use of arguments.caller or arguments.callee + "no-div-regex": 1, // disallow division operators explicitly at beginning of regular expression + "no-else-return": 0, // disallow else after a return in an if + "no-eq-null": 0, // disallow comparisons to null without a type-checking operator + "no-eval": 1, // disallow use of eval() + "no-extend-native": 1, // disallow adding to native types + "no-extra-bind": 1, // disallow unnecessary function binding + "no-fallthrough": 1, // disallow fallthrough of case statements + "no-floating-decimal": 1, // disallow the use of leading or trailing decimal points in numeric literals + "no-implied-eval": 1, // disallow use of eval()-like methods + "no-labels": 1, // disallow use of labeled statements + "no-iterator": 1, // disallow usage of __iterator__ property + "no-lone-blocks": 1, // disallow unnecessary nested blocks + "no-loop-func": 0, // disallow creation of functions within loops + "no-multi-str": 0, // disallow use of multiline strings + "no-native-reassign": 0, // disallow reassignments of native objects + "no-new": 1, // disallow use of new operator when not part of the assignment or comparison + "no-new-func": 1, // disallow use of new operator for Function object + "no-new-wrappers": 1, // disallows creating new instances of String,Number, and Boolean + "no-octal": 1, // disallow use of octal literals + "no-octal-escape": 1, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251"; + "no-proto": 1, // disallow usage of __proto__ property + "no-redeclare": 1, // disallow declaring the same variable more then once + "no-return-assign": 1, // disallow use of assignment in return statement + "no-script-url": 1, // disallow use of javascript: urls. + "no-self-compare": 1, // disallow comparisons where both sides are exactly the same + "no-sequences": 1, // disallow use of comma operator + "no-unused-expressions": 0, // disallow usage of expressions in statement position + "no-void": 1, // disallow use of void operator + "no-warning-comments": 0, // disallow usage of configurable warning terms in comments e.g. TODO or FIXME + "no-with": 1, // disallow use of the with statement + "radix": 1, // require use of the second argument for parseInt() + "vars-on-top": 0, // requires to declare all vars on top of their containing scope + "wrap-iife": 0, // require immediate function invocation to be wrapped in parentheses + "yoda": 1, // require or disallow Yoda conditions + "strict": 0, // this rule conflicts with 'use-babel' so we'll just disable it + + // Variables + + "no-catch-shadow": 1, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment) + "no-delete-var": 1, // disallow deletion of variables + "no-label-var": 1, // disallow labels that share a name with a variable + "no-shadow": 0, // disallow declaration of variables already declared in the outer scope + "no-shadow-restricted-names": 1, // disallow shadowing of names such as arguments + "no-undef": 1, // disallow undeclared variables + "no-undefined": 0, // disallow use of undefined variable + "no-undef-init": 0, // disallow use of undefined when initializing variables + "no-unused-vars": 1, // disallow declaration of variables that are not used in the code + "no-use-before-define": 0, // disallow use of variables before they are defined + + // Node.js + + "handle-callback-err": 1, // enforces error handling in callbacks + "no-mixed-requires": 1, // disallow mixing regular variable and require declarations + "no-new-require": 1, // disallow use of new operator with the require function + "no-path-concat": 1, // disallow string concatenation with __dirname and __filename + "no-process-exit": 0, // disallow process.exit() + "no-restricted-modules": 1, // restrict usage of specified node modules + "no-sync": 0, // disallow use of synchronous methods + + // React (eslint-plugin-react) + + "jsx-quotes": [1, "prefer-double"], // not + "react/jsx-curly-spacing": [ // Enforce or disallow spaces inside of curly braces in JSX attributes + 1, "never" + ], + "react/jsx-no-undef": 1, // Disallow undeclared variables in JSX + "react/jsx-uses-react": 1, // Prevent React to be incorrectly marked as unused + "react/jsx-uses-vars": 1, // Prevent variables used in JSX to be incorrectly marked as unused + "react/no-unknown-property": 1, // Prevent usage of unknown DOM property + "react/prop-types": 1, // Prevent missing props validation in a React component definition + "react/react-in-jsx-scope": 2, // Prevent missing React when using JSX + + // Stylistic (these rules are purely matters of style and are quite subjective) + + "key-spacing": 1, // require space after colon `{a: 1}` + "comma-spacing": 1, // require space after comma `var a, b;` + "no-multi-spaces": 1, // don't allow more spaces than necessary + "brace-style": [ // enforce one true brace style + 1, "1tbs", { + "allowSingleLine": false + } + ], + "camelcase": [ // require camel case names + 1, {"properties": "never"} + ], + "consistent-this": [1, "self"], // enforces consistent naming when capturing the current execution context + "eol-last": 1, // enforce newline at the end of file, with no multiple empty lines + "func-names": 0, // require function expressions to have a name + "func-style": 0, // enforces use of function declarations or expressions + "new-cap": 0, // require a capital letter for constructors + "new-parens": 1, // disallow the omission of parentheses when invoking a constructor with no arguments + "no-nested-ternary": 0, // disallow nested ternary expressions + "no-array-constructor": 1, // disallow use of the Array constructor + "no-lonely-if": 0, // disallow if as the only statement in an else block + "no-new-object": 1, // disallow use of the Object constructor + "no-spaced-func": 1, // disallow space between function identifier and application + "semi-spacing": 1, // disallow space before semicolon + "no-ternary": 0, // disallow the use of ternary operators + "no-trailing-spaces": 1, // disallow trailing whitespace at the end of lines + "no-underscore-dangle": 0, // disallow dangling underscores in identifiers + "no-extra-parens": [1, "functions"], // disallow wrapping of non-IIFE statements in parens + "no-mixed-spaces-and-tabs": 1, // disallow mixed spaces and tabs for indentation + "indent": [1, 4, {"SwitchCase": 1}], // indentation should be four spaces + "quotes": [ // enforce single quotes, allow double to avoid escaping ("don't escape" instead of 'don\'t escape') + 1, "single", "avoid-escape" + ], + "quote-props": [1, "as-needed"], // require quotes around object literal property names + "semi": 1, // require or disallow use of semicolons instead of ASI + "sort-vars": 0, // sort variables within the same declaration block + "keyword-spacing": 1, // require a space around certain keywords + "space-before-blocks": 1, // require a space before blocks + "space-before-function-paren": [ // disallow a space before function parenthesis + 1, "never" + ], + "object-curly-spacing": [ // disallow spaces inside of curly braces in object literals + 1, "never" + ], + "array-bracket-spacing": [ // disallow spaces inside of curly braces in array literals + 1, "never" + ], + "space-in-parens": 1, // require or disallow spaces inside parentheses + "space-infix-ops": 1, // require spaces around operators + "space-unary-ops": 1, // require a space around word operators such as typeof + "max-nested-callbacks": 0, // specify the maximum depth callbacks can be nested + // "one-var": [1, "never"], // allow just one var statement per function + "wrap-regex": 0, // require regex literals to be wrapped in parentheses + + // ECMAScript 6/7 (2015 and above) + "arrow-parens": 1, // require parens in arrow function arguments + "arrow-spacing": 1, // require space before/after arrow function's arrow (fixable) + "constructor-super": 1, // verify calls of super() in constructors + "generator-star-spacing": 0, // enforce spacing around the * in generator functions (fixable) + "no-class-assign": 1, // disallow modifying variables of class declarations + "no-const-assign": 1, // disallow modifying variables that are declared using const + "no-dupe-class-members": 1, // disallow duplicate name in class members + "no-this-before-super": 1, // disallow use of this/super before calling super() in constructors. + "no-var": 0, // require let or const instead of var + "object-shorthand": 0, // require method and property shorthand syntax for object literals + "prefer-arrow-callback": 1, // suggest using arrow functions as callbacks + "prefer-const": 0, // suggest using const declaration for variables that are never modified after declared + "prefer-reflect": 0, // suggest using Reflect methods where applicable + "prefer-spread": 0, // suggest using the spread operator instead of .apply(). + "prefer-template": 0, // suggest using template literals instead of strings concatenation + "require-yield": 0, // disallow generator functions that do not have yield + "babel/no-await-in-loop": 1, // async inside a loop will run operations in serial, when often the desired behavior is to do do in parallel + + // Legacy (included for compatibility with JSHint and JSLint. While the names of the rules may not match up with the JSHint/JSLint counterpart, the functionality is the same) + + "max-depth": 0, // specify the maximum depth that blocks can be nested + //"max-len": [ // specify the maximum length of a line in your program [warning level, max line length, number of characters to treat a tab as] + // 1, 100, 2, { + // "ignoreUrls": true, + // "ignorePattern": "^\\s*(import\\s[^{]+from|(var|const|let)\\s[^{]+=\\s*require\\s*\\()" + // } + //], + "max-params": 0, // limits the number of parameters that can be used in the function declaration. + "max-statements": 0, // specify the maximum number of statement allowed in a function + "no-bitwise": 0, // disallow use of bitwise operators + "no-plusplus": 0 // disallow use of unary operators, ++ and -- + + } +} diff --git a/.gitignore b/.gitignore index cf9c7f9..41ac350 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +lib node_modules coverage dist @@ -7,4 +8,6 @@ dist !.gitignore !.npmignore !.babelrc +!.eslintrc +!.eslintignore !.travis.yml diff --git a/package.json b/package.json index 6a40041..3b01790 100644 --- a/package.json +++ b/package.json @@ -22,17 +22,20 @@ "dependencies": { "es6-map": "^0.1.3", "hoist-non-react-statics": "^1.0.5", - "lodash": "^4.6.1", - "object-unfreeze": "^1.0.2" + "lodash": "^4.6.1" }, "devDependencies": { "chai": "^3.5.0", + "eslint": "^2.12.0", + "eslint-plugin-babel": "^3.2.0", + "eslint-plugin-flow-vars": "^0.4.0", + "eslint-plugin-react": "^5.1.1", "jsdom": "^8.1.0", "pragmatist": "^3.0.21", - "react": "^15.0.0-rc.1", - "react-addons-shallow-compare": "^15.0.0-rc.1", - "react-addons-test-utils": "^15.0.0-rc.1", - "react-dom": "^15.0.0-rc.1" + "react": "^15.1.0", + "react-addons-shallow-compare": "^15.1.0", + "react-addons-test-utils": "^15.1.0", + "react-dom": "^15.1.0" }, "scripts": { "pragmatist": "node ./node_modules/.bin/pragmatist --es5", diff --git a/src/extendReactClass.js b/src/extendReactClass.js deleted file mode 100644 index fd00abd..0000000 --- a/src/extendReactClass.js +++ /dev/null @@ -1,50 +0,0 @@ -/* eslint-disable react/prop-types */ - -import linkClass from './linkClass'; -import React from 'react'; -import _ from 'lodash'; -import hoistNonReactStatics from 'hoist-non-react-statics'; - -/** - * @param {ReactClass} Component - * @param {Object} defaultStyles - * @param {Object} options - * @returns {ReactClass} - */ -export default (Component: Object, defaultStyles: Object, options: Object) => { - const WrappedComponent = class extends Component { - render () { - let propsChanged, - styles; - - propsChanged = false; - - if (this.props.styles) { - styles = this.props.styles; - } else if (_.isObject(defaultStyles)) { - this.props = _.assign({}, this.props, { - styles: defaultStyles - }); - - propsChanged = true; - styles = defaultStyles; - } else { - styles = {}; - } - - const renderResult = super.render(); - - if (propsChanged) { - delete this.props.styles; - } - - if (renderResult) { - return linkClass(renderResult, styles, options); - } - - return React.createElement('noscript'); - } - }; - - return hoistNonReactStatics(WrappedComponent, Component); -}; diff --git a/src/index.js b/src/index.js index 6c1a78c..41cf94d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,38 +1,24 @@ import _ from 'lodash'; -import extendReactClass from './extendReactClass'; -import wrapStatelessFunction from './wrapStatelessFunction'; +import wrapComponent from './wrapComponent'; /** * @see https://github.com/gajus/react-css-modules#options */ type OptionsType = {}; -/** - * Determines if the given object has the signature of a class that inherits React.Component. - */ -const isReactComponent = (maybeReactComponent: any): boolean => { - return 'prototype' in maybeReactComponent && _.isFunction(maybeReactComponent.prototype.render); -}; - /** * When used as a function. */ const functionConstructor = (Component: Function, defaultStyles: Object, options: OptionsType): Function => { - let decoratedClass; - - if (isReactComponent(Component)) { - decoratedClass = extendReactClass(Component, defaultStyles, options); - } else { - decoratedClass = wrapStatelessFunction(Component, defaultStyles, options); - } + let WrappedComponent = wrapComponent(Component, defaultStyles, options); if (Component.displayName) { - decoratedClass.displayName = Component.displayName; + WrappedComponent.displayName = Component.displayName; } else { - decoratedClass.displayName = Component.name; + WrappedComponent.displayName = Component.name; } - return decoratedClass; + return WrappedComponent; }; /** diff --git a/src/isIterable.js b/src/isIterable.js deleted file mode 100644 index ac6dc72..0000000 --- a/src/isIterable.js +++ /dev/null @@ -1,24 +0,0 @@ -import _ from 'lodash'; - -const ITERATOR_SYMBOL = _.isFunction(Symbol) && Symbol.iterator; -const OLD_ITERATOR_SYMBOL = '@@iterator'; - -/** - * @see https://github.com/lodash/lodash/issues/1668 - * @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols - */ -export default (maybeIterable: any): boolean => { - let iterator; - - if (!_.isObject(maybeIterable)) { - return false; - } - - if (ITERATOR_SYMBOL) { - iterator = maybeIterable[ITERATOR_SYMBOL]; - } else { - iterator = maybeIterable[OLD_ITERATOR_SYMBOL]; - } - - return _.isFunction(iterator); -}; diff --git a/src/linkClass.js b/src/linkClass.js deleted file mode 100644 index 2c3c930..0000000 --- a/src/linkClass.js +++ /dev/null @@ -1,75 +0,0 @@ -import _ from 'lodash'; -import React, { - ReactElement -} from 'react'; -import makeConfiguration from './makeConfiguration'; -import isIterable from './isIterable'; -import parseStyleName from './parseStyleName'; -import generateAppendClassName from './generateAppendClassName'; -import objectUnfreeze from 'object-unfreeze'; - -const linkElement = (element: ReactElement, styles: Object, configuration: Object): ReactElement => { - let appendClassName, - elementIsFrozen, - elementShallowCopy; - - elementShallowCopy = element; - - if (Object.isFrozen && Object.isFrozen(elementShallowCopy)) { - elementIsFrozen = true; - - // https://github.com/facebook/react/blob/v0.13.3/src/classic/element/ReactElement.js#L131 - elementShallowCopy = objectUnfreeze(elementShallowCopy); - elementShallowCopy.props = objectUnfreeze(elementShallowCopy.props); - } - - const styleNames = parseStyleName(elementShallowCopy.props.styleName || '', configuration.allowMultiple); - - if (React.isValidElement(elementShallowCopy.props.children)) { - elementShallowCopy.props.children = linkElement(React.Children.only(elementShallowCopy.props.children), styles, configuration); - } else if (_.isArray(elementShallowCopy.props.children) || isIterable(elementShallowCopy.props.children)) { - elementShallowCopy.props.children = React.Children.map(elementShallowCopy.props.children, (node) => { - if (React.isValidElement(node)) { - return linkElement(node, styles, configuration); - } else { - return node; - } - }); - } - - if (styleNames.length) { - appendClassName = generateAppendClassName(styles, styleNames, configuration.errorWhenNotFound); - - if (appendClassName) { - if (elementShallowCopy.props.className) { - appendClassName = elementShallowCopy.props.className + ' ' + appendClassName; - } - - elementShallowCopy.props.className = appendClassName; - elementShallowCopy.props.styleName = null; - } - } - - if (elementIsFrozen) { - Object.freeze(elementShallowCopy.props); - Object.freeze(elementShallowCopy); - } - - return elementShallowCopy; -}; - -/** - * @param {ReactElement} element - * @param {Object} styles CSS modules class map. - * @param {CSSModules~Options} userConfiguration - */ -export default (element: ReactElement, styles = {}, userConfiguration): ReactElement => { - // @see https://github.com/gajus/react-css-modules/pull/30 - if (!_.isObject(element)) { - return element; - } - - const configuration = makeConfiguration(userConfiguration); - - return linkElement(element, styles, configuration); -}; diff --git a/src/wrapComponent.js b/src/wrapComponent.js new file mode 100644 index 0000000..c5d71d8 --- /dev/null +++ b/src/wrapComponent.js @@ -0,0 +1,70 @@ +/* eslint-disable react/prop-types */ + +import generateAppendClassName from './generateAppendClassName'; +import hoistNonReactStatics from 'hoist-non-react-statics'; +import makeConfiguration from './makeConfiguration'; +import parseStyleName from './parseStyleName'; +import React, {Children} from 'react'; + +/** + * @param {ReactElement} element + * @param {Object} styles + * @param {Object} options + * @returns {ReactElement} + */ +function updateProps(element: Object, styles: Object, options: Object) { + if (element == null || typeof element !== 'object') { + return element; + } + let {styleName, className, children} = element.props; + let didUpdate = false; + if (styleName != null) { + let styleNames = parseStyleName(styleName, options.allowMultiple); + let appendClassName = generateAppendClassName(styles, styleNames, options.errorWhenNotFound); + className = className ? className + ' ' + appendClassName : appendClassName; + didUpdate = true; + } + if (children != null) { + let newChildren = []; + let didUpdateChildren = true; + Children.forEach(children, (child) => { + let newChild = updateProps(child, styles, options); + newChildren.push(newChild); + if (newChild !== child) { + didUpdateChildren = true; + } + }); + if (didUpdateChildren) { + children = newChildren; + didUpdate = true; + } + } + if (didUpdate) { + let props = {...element.props, className, children}; + return {...element, props}; + } else { + return element; + } +} + +/** + * @param {Function} Component + * @param {Object} defaultStyles + * @param {Object} options + * @returns {ReactClass} + */ +export default function wrapComponent(Component: Function, defaultStyles: Object = {}, options: Object = {}) { + class WrappedComponent extends React.Component { + render() { + let {props} = this; + let {styles} = props; + if (styles == null) { + styles = defaultStyles; + props = {...props, styles}; + } + let element = React.createElement(Component, props); + return updateProps(element, styles, makeConfiguration(options)); + } + } + return hoistNonReactStatics(WrappedComponent, Component); +} diff --git a/src/wrapStatelessFunction.js b/src/wrapStatelessFunction.js deleted file mode 100644 index 878119a..0000000 --- a/src/wrapStatelessFunction.js +++ /dev/null @@ -1,41 +0,0 @@ -/* eslint-disable react/prop-types */ - -import _ from 'lodash'; -import React from 'react'; -import linkClass from './linkClass'; - -/** - * @see https://facebook.github.io/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components - */ -export default (Component: Function, defaultStyles: Object, options: Object): Function => { - const WrappedComponent = (props = {}, ...args) => { - let styles, - useProps; - - if (props.styles) { - useProps = props; - styles = props.styles; - } else if (_.isObject(defaultStyles)) { - useProps = _.assign({}, props, { - styles: defaultStyles - }); - - styles = defaultStyles; - } else { - useProps = props; - styles = {}; - } - - const renderResult = Component(useProps, ...args); - - if (renderResult) { - return linkClass(renderResult, styles, options); - } - - return React.createElement('noscript'); - }; - - _.assign(WrappedComponent, Component); - - return WrappedComponent; -}; diff --git a/tests/.eslintrc b/tests/.eslintrc new file mode 100644 index 0000000..7eeefc3 --- /dev/null +++ b/tests/.eslintrc @@ -0,0 +1,5 @@ +{ + "env": { + "mocha": true + } +} diff --git a/tests/extendReactClass.js b/tests/extendReactClass.js index 16aed7f..5fc22a7 100644 --- a/tests/extendReactClass.js +++ b/tests/extendReactClass.js @@ -1,150 +1,150 @@ /* eslint-disable max-nested-callbacks, react/prefer-stateless-function, react/prop-types, react/no-multi-comp */ -import { - expect -} from 'chai'; - -import React from 'react'; -import TestUtils from 'react-addons-test-utils'; -import shallowCompare from 'react-addons-shallow-compare'; -import jsdom from 'jsdom'; -import extendReactClass from './../src/extendReactClass'; - -describe('extendReactClass', () => { - beforeEach(() => { - global.document = jsdom.jsdom(''); - - global.window = document.defaultView; - }); - context('using default styles', () => { - it('exposes styles through this.props.styles property', (done) => { - let Component; - - const styles = { - foo: 'foo-1' - }; - - Component = class extends React.Component { - render () { - expect(this.props.styles).to.equal(styles); - done(); - } - }; - - Component = extendReactClass(Component, styles); - - TestUtils.renderIntoDocument(); - }); - it('does not affect the other instance properties', (done) => { - let Component; - - Component = class extends React.Component { - render () { - expect(this.props.bar).to.equal('baz'); - done(); - } - }; - - const styles = { - foo: 'foo-1' - }; - - Component = extendReactClass(Component, styles); - - TestUtils.renderIntoDocument(); - }); - it('does not affect pure-render logic', (done) => { - let Component, - rendered; - - rendered = false; - - const styles = { - foo: 'foo-1' - }; - - Component = class extends React.Component { - shouldComponentUpdate (newProps) { - if (rendered) { - expect(shallowCompare(this.props, newProps)).to.equal(true); - - done(); - } - - return true; - } - - render () { - rendered = true; - } - }; - - Component = extendReactClass(Component, styles); - - const instance = TestUtils.renderIntoDocument(); - - // trigger shouldComponentUpdate - instance.setState({}); - }); - }); - context('overwriting default styles using "styles" property of the extended component', () => { - it('overwrites default styles', (done) => { - let Component; - - const styles = { - foo: 'foo-1' - }; - - Component = class extends React.Component { - render () { - expect(this.props.styles).to.equal(styles); - done(); - } - }; - - Component = extendReactClass(Component, { - bar: 'bar-0', - foo: 'foo-0' - }); - - TestUtils.renderIntoDocument(); - }); - }); - context('rendering Component that returns null', () => { - it('generates