From 40eaf292403c853c770bbc75a9646a4e0ca18029 Mon Sep 17 00:00:00 2001 From: Josh Kruder Date: Mon, 3 Aug 2015 00:59:59 -0400 Subject: [PATCH 1/3] Start of unit test framework --- .gitignore | 1 + .npmignore | 3 +- karma.conf.js | 59 ++++++ package.json | 20 +- src/checkbox.jsx | 5 +- test/checkbox-spec.js | 30 +++ test/fixtures/react-parent-context-patch.js | 191 ++++++++++++++++++++ test/fixtures/theme-container.jsx | 42 +++++ test/mocha.opts | 3 + 9 files changed, 349 insertions(+), 5 deletions(-) create mode 100644 karma.conf.js create mode 100644 test/checkbox-spec.js create mode 100644 test/fixtures/react-parent-context-patch.js create mode 100644 test/fixtures/theme-container.jsx create mode 100644 test/mocha.opts diff --git a/.gitignore b/.gitignore index 544f1daf6b545f..104f8c4d5e2a13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules npm-debug.log build +coverage # Exclude compiled files lib diff --git a/.npmignore b/.npmignore index 5082f42df029b1..e6f5b877516aa2 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,5 @@ build +coverage docs example -icon-builder \ No newline at end of file +icon-builder diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 00000000000000..54d0e130a9b0b5 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,59 @@ +// Karma configuration +module.exports = function(config) { + config.set({ + + basePath: '', + + frameworks: [ 'browserify', 'mocha', 'chai-sinon' ], + + files: [ + 'node_modules/babel/node_modules/babel-core/browser-polyfill.js', +// 'test/fixtures/react-parent-context-patch.js', + 'test/**/*spec.js' + ], + + preprocessors: { +// 'test/fixtures/react-parent-context-patch.js': [ 'browserify' ], + 'test/**/*spec.js': [ 'browserify' ] + }, + + browserify: { + debug: true, + extensions: [ '.js', '.jsx' ], + paths: [ './node_modules', './src' ], + transform: [ + ['babelify', { + stage: 1, + sourceMap: 'inline' + }], + 'browserify-istanbul' + ] + }, + + reporters: ['mocha', 'coverage'], + + coverageReporter: { + dir: 'coverage', + + subdir: function(browser) { + return browser.toLowerCase().split(/[ /-]/)[0]; + }, + + reporters: [ + // Uncomment when 'TypeError: Cannot read property 'text' of undefined' has been addressed in Istanbul. +// { type: 'html', subdir: '.' }, + { type: 'lcovonly', subdir: '.', file: 'lcov.info' }, + { type: 'text', subdir: '.', file: 'text.txt' }, + { type: 'text-summary', subdir: '.' } + ] + }, + + port: 9876, + colors: true, + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + autoWatch: false, + singleRun: false, + browsers: [ 'PhantomJS' ] + }) +} diff --git a/package.json b/package.json index 7c41b35510f38b..ae5b571a2bdf86 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "description": "Material Design UI components built with React", "main": "./lib", "scripts": { - "test": "echo \"No test implemented\" && exit 0", + "test": "npm run test-base -- --single-run", + "test-watch": "npm run test-base -- --auto-watch", + "test-base": "./node_modules/.bin/karma start", "prebuild": "rm -rf lib", "eslint": "gulp eslint", "build": "npm run eslint && babel --stage 1 ./src --out-dir ./lib", @@ -38,11 +40,25 @@ "devDependencies": { "babel": "^5.4.3", "babel-eslint": "^3.1.17", + "babelify": "^6.1.3", + "browserify-istanbul": "^0.2.1", + "chai": "^3.2.0", "eslint": "^0.23.0", "eslint-plugin-react": "^2.5.2", "gulp": "^3.9.0", "gulp-eslint": "^0.15.0", + "karma": "^0.13.3", + "karma-browserify": "^4.2.1", + "karma-chai-sinon": "^0.1.5", + "karma-coverage": "^0.4.2", + "karma-mocha": "^0.2.0", + "karma-mocha-reporter": "^1.0.4", + "karma-phantomjs-launcher": "^0.2.0", + "mocha": "^2.2.5", + "phantomjs": "^1.9.17", "react-router": "^0.13.3", - "react-tap-event-plugin": "^0.1.6" + "react-tap-event-plugin": "^0.1.6", + "sinon": "^1.15.4", + "sinon-chai": "^2.8.0" } } diff --git a/src/checkbox.jsx b/src/checkbox.jsx index f7b811c5e27c32..e569720c4c07a0 100644 --- a/src/checkbox.jsx +++ b/src/checkbox.jsx @@ -15,10 +15,12 @@ let Checkbox = React.createClass({ }, propTypes: { + checked: React.PropTypes.bool, + checkedIcon: React.PropTypes.element, + defaultChecked: React.PropTypes.bool, iconStyle: React.PropTypes.object, labelStyle: React.PropTypes.object, onCheck: React.PropTypes.func, - checkedIcon: React.PropTypes.element, unCheckedIcon: React.PropTypes.element, }, @@ -90,7 +92,6 @@ let Checkbox = React.createClass({ unCheckedIcon, ...other, } = this.props; - let styles = this.getStyles(); let boxStyles = this.mergeAndPrefix( diff --git a/test/checkbox-spec.js b/test/checkbox-spec.js new file mode 100644 index 00000000000000..a40c0194b732ce --- /dev/null +++ b/test/checkbox-spec.js @@ -0,0 +1,30 @@ +import React from 'react/addons'; +import Checkbox from 'checkbox'; +import ThemeContainer from './fixtures/theme-container'; +import stubContext from 'react-stub-context'; + +import ThemeManager from 'styles/theme-manager'; + +const TestUtils = React.addons.TestUtils; +const Manager = new ThemeManager(); + + +describe('Checkbox', () => { + let checkboxComponent; + + it('should display checkmark when checked by default', () => { +// checkboxComponent = TestUtils.renderIntoDocument( +// +// +// +// ).getBaseComponent() + + let NewCheckbox = stubContext(Checkbox, {muiTheme: Manager.getCurrentTheme()}); + checkboxComponent = TestUtils.renderIntoDocument(); + console.log(TestUtils.scryRenderedComponentsWithType(checkboxComponent, 'Checkbox')); + +// console.log(Object.keys(checkboxComponent._wrappedElement)); +// console.log(checkboxComponent.getWrappedElement().isChecked() !== undefined); + //expect(checkboxComponent.isChecked()).to.be.true; + }); +}); diff --git a/test/fixtures/react-parent-context-patch.js b/test/fixtures/react-parent-context-patch.js new file mode 100644 index 00000000000000..8f741004359663 --- /dev/null +++ b/test/fixtures/react-parent-context-patch.js @@ -0,0 +1,191 @@ +var ReactInstanceMap = require("react/lib/ReactInstanceMap"); +var ReactLifeCycle = require("react/lib/ReactLifeCycle"); +var ReactNativeComponent = require("react/lib/ReactNativeComponent"); +var ReactReconciler = require("react/lib/ReactReconciler"); + +var emptyObject = require("react/lib/emptyObject"); +var invariant = require("react/lib/invariant"); +var warning = require("react/lib/warning"); + +var ReactCompositeComponentMixin = require('react/lib/ReactCompositeComponent').Mixin; + +var {mountComponent, updateComponent} = ReactCompositeComponentMixin; +var nextMountID = 1; + + +ReactCompositeComponentMixin.mountComponent = function(rootID, transaction, context) { + this._context = context; + this._mountOrder = nextMountID++; + this._rootNodeID = rootID; + + var publicProps = this._processProps(this._currentElement.props); + var publicContext = this._processContext(context); + + var Component = ReactNativeComponent.getComponentClassForElement( + this._currentElement + ); + + // Initialize the public class + var inst = new Component(publicProps, publicContext); + // These should be set up in the constructor, but as a convenience for + // simpler class abstractions, we set them up after the fact. + inst.props = publicProps; + inst.context = publicContext; + inst.refs = emptyObject; + + this._instance = inst; + + // Store a reference from the instance back to the internal representation + ReactInstanceMap.set(inst, this); + + if ("production" !== process.env.NODE_ENV) { + // Since plain JS classes are defined without any special initialization + // logic, we can not catch common errors early. Therefore, we have to + // catch them here, at initialization time, instead. + ("production" !== process.env.NODE_ENV ? warning( + !inst.getInitialState || + inst.getInitialState.isReactClassApproved, + 'getInitialState was defined on %s, a plain JavaScript class. ' + + 'This is only supported for classes created using React.createClass. ' + + 'Did you mean to define a state property instead?', + this.getName() || 'a component' + ) : null); + ("production" !== process.env.NODE_ENV ? warning( + !inst.propTypes, + 'propTypes was defined as an instance property on %s. Use a static ' + + 'property to define propTypes instead.', + this.getName() || 'a component' + ) : null); + ("production" !== process.env.NODE_ENV ? warning( + !inst.contextTypes, + 'contextTypes was defined as an instance property on %s. Use a ' + + 'static property to define contextTypes instead.', + this.getName() || 'a component' + ) : null); + ("production" !== process.env.NODE_ENV ? warning( + typeof inst.componentShouldUpdate !== 'function', + '%s has a method called ' + + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + + 'The name is phrased as a question because the function is ' + + 'expected to return a value.', + (this.getName() || 'A component') + ) : null); + } + + var initialState = inst.state; + if (initialState === undefined) { + inst.state = initialState = null; + } + ("production" !== process.env.NODE_ENV ? invariant( + typeof initialState === 'object' && !Array.isArray(initialState), + '%s.state: must be set to an object or null', + this.getName() || 'ReactCompositeComponent' + ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState))); + + this._pendingStateQueue = null; + this._pendingReplaceState = false; + this._pendingForceUpdate = false; + + var renderedElement; + + var previouslyMounting = ReactLifeCycle.currentlyMountingInstance; + ReactLifeCycle.currentlyMountingInstance = this; + try { + if (inst.componentWillMount) { + inst.componentWillMount(); + // When mounting, calls to `setState` by `componentWillMount` will set + // `this._pendingStateQueue` without triggering a re-render. + if (this._pendingStateQueue) { + inst.state = this._processPendingState(inst.props, inst.context); + } + } + + renderedElement = this._renderValidatedComponent(); + } finally { + ReactLifeCycle.currentlyMountingInstance = previouslyMounting; + } + + this._renderedComponent = this._instantiateReactComponent( + renderedElement, + this._currentElement.type // The wrapping type + ); + + var markup = ReactReconciler.mountComponent( + this._renderedComponent, + rootID, + transaction, + this._processChildContext(context) + ); + if (inst.componentDidMount) { + transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); + } + + return markup; +}; + +ReactCompositeComponentMixin.updateComponent = function( + transaction, + prevParentElement, + nextParentElement, + prevUnmaskedContext, + nextUnmaskedContext +) { + var inst = this._instance; + + var nextContext = inst.context; + var nextProps = inst.props; + + // Distinguish between a props update versus a simple state update + if (prevParentElement !== nextParentElement) { + nextContext = this._processContext(nextUnmaskedContext); + nextProps = this._processProps(nextParentElement.props); + + // An update here will schedule an update but immediately set + // _pendingStateQueue which will ensure that any state updates gets + // immediately reconciled instead of waiting for the next batch. + + if (inst.componentWillReceiveProps) { + inst.componentWillReceiveProps(nextProps, nextContext); + } + } + + var nextState = this._processPendingState(nextProps, nextContext); + + var shouldUpdate = + this._pendingForceUpdate || + !inst.shouldComponentUpdate || + inst.shouldComponentUpdate(nextProps, nextState, nextContext); + + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + typeof shouldUpdate !== 'undefined', + '%s.shouldComponentUpdate(): Returned undefined instead of a ' + + 'boolean value. Make sure to return true or false.', + this.getName() || 'ReactCompositeComponent' + ) : null); + } + + if (shouldUpdate) { + this._pendingForceUpdate = false; + // Will set `this.props`, `this.state` and `this.context`. + this._performComponentUpdate( + nextParentElement, + nextProps, + nextState, + nextContext, + transaction, + nextUnmaskedContext + ); + } else { + // If it's determined that a component should not update, we still want + // to set props and state but we shortcut the rest of the update. + this._currentElement = nextParentElement; + this._context = nextUnmaskedContext; + inst.props = nextProps; + inst.state = nextState; + inst.context = nextContext; + } +}; + + +console.warn('Applied react-parent-context-patch!'); diff --git a/test/fixtures/theme-container.jsx b/test/fixtures/theme-container.jsx new file mode 100644 index 00000000000000..b2daa9d38f079f --- /dev/null +++ b/test/fixtures/theme-container.jsx @@ -0,0 +1,42 @@ +import React from 'react/addons'; +import ThemeManager from 'styles/theme-manager'; + +const TestUtils = React.addons.TestUtils; +const Manager = new ThemeManager(); + + +class ThemeContainer extends React.Component { + getChildContext() { + return { + muiTheme: Manager.getCurrentTheme() + }; + } + + render() { + console.log('container'); + console.log(this.getChildContext()); + return
{React.cloneElement(React.Children.only(this.props.children), { ref: 'base' })}
; + } + + getBaseComponent() { + return this.refs.base; + } +} + +ThemeContainer.childContextTypes = { + muiTheme: React.PropTypes.object +}; + + +function renderIntoDocumentWithTheme(component) { + return TestUtils.renderIntoDocument({component}).getBaseComponent(); +} + +module.exports = ThemeContainer; +/* + +module.exports = { + renderIntoDocumentWithTheme: renderIntoDocumentWithTheme, + ThemeManager: Manager, +}; +*/ diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 00000000000000..63d9c8ae556a71 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,3 @@ +--require chai +--reporter html +--ui bdd From 9620b36e9d2d5dceb94b385487804912b488e135 Mon Sep 17 00:00:00 2001 From: Josh Kruder Date: Tue, 4 Aug 2015 01:15:13 -0400 Subject: [PATCH 2/3] Updated checkbox tests. --- karma.conf.js | 2 - test/checkbox-spec.js | 87 +++++++-- test/fixtures/inject-theme.jsx | 12 ++ test/fixtures/react-parent-context-patch.js | 191 -------------------- test/fixtures/theme-container.jsx | 42 ----- 5 files changed, 80 insertions(+), 254 deletions(-) create mode 100644 test/fixtures/inject-theme.jsx delete mode 100644 test/fixtures/react-parent-context-patch.js delete mode 100644 test/fixtures/theme-container.jsx diff --git a/karma.conf.js b/karma.conf.js index 54d0e130a9b0b5..545cfc45ad66e3 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -8,12 +8,10 @@ module.exports = function(config) { files: [ 'node_modules/babel/node_modules/babel-core/browser-polyfill.js', -// 'test/fixtures/react-parent-context-patch.js', 'test/**/*spec.js' ], preprocessors: { -// 'test/fixtures/react-parent-context-patch.js': [ 'browserify' ], 'test/**/*spec.js': [ 'browserify' ] }, diff --git a/test/checkbox-spec.js b/test/checkbox-spec.js index a40c0194b732ce..2f2df381ee3528 100644 --- a/test/checkbox-spec.js +++ b/test/checkbox-spec.js @@ -1,30 +1,79 @@ import React from 'react/addons'; import Checkbox from 'checkbox'; -import ThemeContainer from './fixtures/theme-container'; -import stubContext from 'react-stub-context'; - -import ThemeManager from 'styles/theme-manager'; +import injectTheme from './fixtures/inject-theme'; const TestUtils = React.addons.TestUtils; -const Manager = new ThemeManager(); describe('Checkbox', () => { - let checkboxComponent; + const CHECKMARK_PATH = 'M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z'; + let ThemedCheckbox; + + + beforeEach(() => { + ThemedCheckbox = injectTheme(Checkbox); + }); + it('should display checkmark when checked by default', () => { -// checkboxComponent = TestUtils.renderIntoDocument( -// -// -// -// ).getBaseComponent() - - let NewCheckbox = stubContext(Checkbox, {muiTheme: Manager.getCurrentTheme()}); - checkboxComponent = TestUtils.renderIntoDocument(); - console.log(TestUtils.scryRenderedComponentsWithType(checkboxComponent, 'Checkbox')); - -// console.log(Object.keys(checkboxComponent._wrappedElement)); -// console.log(checkboxComponent.getWrappedElement().isChecked() !== undefined); - //expect(checkboxComponent.isChecked()).to.be.true; + let render = TestUtils.renderIntoDocument(); + let input = TestUtils.findRenderedDOMComponentWithTag(render, 'input'); + let svgs = TestUtils.scryRenderedDOMComponentsWithTag(render, 'svg'); + let checkMarkNode = svgs[1].getDOMNode(); + + expect(input.getDOMNode().hasAttribute('checked')).to.be.true; + expect(checkMarkNode.style.opacity).to.equal('1'); + expect(checkMarkNode.firstChild.getAttribute('d')).to.equal(CHECKMARK_PATH); + }); + + + it('should NOT display checkmark when not checked by default', () => { + let render = TestUtils.renderIntoDocument(); + let input = TestUtils.findRenderedDOMComponentWithTag(render, 'input'); + let svgs = TestUtils.scryRenderedDOMComponentsWithTag(render, 'svg'); + let checkMarkNode = svgs[1].getDOMNode(); + + expect(input.getDOMNode().hasAttribute('checked')).to.be.false; + expect(checkMarkNode.style.opacity).to.equal('0'); + expect(checkMarkNode.firstChild.getAttribute('d')).to.equal(CHECKMARK_PATH); + }); + + + describe('when initially unchecked', () => { + let renderedCheckbox; + + + beforeEach(() => { + renderedCheckbox = TestUtils.renderIntoDocument(); + }); + + + it('should display checkmark when clicked once', () => { + let input = TestUtils.findRenderedDOMComponentWithTag(renderedCheckbox, 'input'); + let inputNode = input.getDOMNode(); + inputNode.checked = !inputNode.checked; + TestUtils.Simulate.change(input); + + let svgs = TestUtils.scryRenderedDOMComponentsWithTag(renderedCheckbox, 'svg'); + let checkMarkNode = svgs[1].getDOMNode(); + expect(checkMarkNode.style.opacity).to.equal('1'); + expect(checkMarkNode.firstChild.getAttribute('d')).to.equal(CHECKMARK_PATH); + }); + + + it('should NOT display checkmark when clicked twice', () => { + let input = TestUtils.findRenderedDOMComponentWithTag(renderedCheckbox, 'input'); + let inputNode = input.getDOMNode(); + // Simulate events + inputNode.checked = !inputNode.checked; + TestUtils.Simulate.change(input); + inputNode.checked = !inputNode.checked; + TestUtils.Simulate.change(input); + + let svgs = TestUtils.scryRenderedDOMComponentsWithTag(renderedCheckbox, 'svg'); + let checkMarkNode = svgs[1].getDOMNode(); + expect(checkMarkNode.style.opacity).to.equal('0'); + expect(checkMarkNode.firstChild.getAttribute('d')).to.equal(CHECKMARK_PATH); + }); }); }); diff --git a/test/fixtures/inject-theme.jsx b/test/fixtures/inject-theme.jsx new file mode 100644 index 00000000000000..44b959d5d97b80 --- /dev/null +++ b/test/fixtures/inject-theme.jsx @@ -0,0 +1,12 @@ +import stubContext from 'react-stub-context'; +import ThemeManager from 'styles/theme-manager'; + +const Manager = new ThemeManager(); + + +function injectTheme(Component, theme) { + let injectedTheme = theme || Manager.getCurrentTheme(); + return stubContext(Component, {muiTheme: injectedTheme}); +} + +module.exports = injectTheme; diff --git a/test/fixtures/react-parent-context-patch.js b/test/fixtures/react-parent-context-patch.js deleted file mode 100644 index 8f741004359663..00000000000000 --- a/test/fixtures/react-parent-context-patch.js +++ /dev/null @@ -1,191 +0,0 @@ -var ReactInstanceMap = require("react/lib/ReactInstanceMap"); -var ReactLifeCycle = require("react/lib/ReactLifeCycle"); -var ReactNativeComponent = require("react/lib/ReactNativeComponent"); -var ReactReconciler = require("react/lib/ReactReconciler"); - -var emptyObject = require("react/lib/emptyObject"); -var invariant = require("react/lib/invariant"); -var warning = require("react/lib/warning"); - -var ReactCompositeComponentMixin = require('react/lib/ReactCompositeComponent').Mixin; - -var {mountComponent, updateComponent} = ReactCompositeComponentMixin; -var nextMountID = 1; - - -ReactCompositeComponentMixin.mountComponent = function(rootID, transaction, context) { - this._context = context; - this._mountOrder = nextMountID++; - this._rootNodeID = rootID; - - var publicProps = this._processProps(this._currentElement.props); - var publicContext = this._processContext(context); - - var Component = ReactNativeComponent.getComponentClassForElement( - this._currentElement - ); - - // Initialize the public class - var inst = new Component(publicProps, publicContext); - // These should be set up in the constructor, but as a convenience for - // simpler class abstractions, we set them up after the fact. - inst.props = publicProps; - inst.context = publicContext; - inst.refs = emptyObject; - - this._instance = inst; - - // Store a reference from the instance back to the internal representation - ReactInstanceMap.set(inst, this); - - if ("production" !== process.env.NODE_ENV) { - // Since plain JS classes are defined without any special initialization - // logic, we can not catch common errors early. Therefore, we have to - // catch them here, at initialization time, instead. - ("production" !== process.env.NODE_ENV ? warning( - !inst.getInitialState || - inst.getInitialState.isReactClassApproved, - 'getInitialState was defined on %s, a plain JavaScript class. ' + - 'This is only supported for classes created using React.createClass. ' + - 'Did you mean to define a state property instead?', - this.getName() || 'a component' - ) : null); - ("production" !== process.env.NODE_ENV ? warning( - !inst.propTypes, - 'propTypes was defined as an instance property on %s. Use a static ' + - 'property to define propTypes instead.', - this.getName() || 'a component' - ) : null); - ("production" !== process.env.NODE_ENV ? warning( - !inst.contextTypes, - 'contextTypes was defined as an instance property on %s. Use a ' + - 'static property to define contextTypes instead.', - this.getName() || 'a component' - ) : null); - ("production" !== process.env.NODE_ENV ? warning( - typeof inst.componentShouldUpdate !== 'function', - '%s has a method called ' + - 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + - 'The name is phrased as a question because the function is ' + - 'expected to return a value.', - (this.getName() || 'A component') - ) : null); - } - - var initialState = inst.state; - if (initialState === undefined) { - inst.state = initialState = null; - } - ("production" !== process.env.NODE_ENV ? invariant( - typeof initialState === 'object' && !Array.isArray(initialState), - '%s.state: must be set to an object or null', - this.getName() || 'ReactCompositeComponent' - ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState))); - - this._pendingStateQueue = null; - this._pendingReplaceState = false; - this._pendingForceUpdate = false; - - var renderedElement; - - var previouslyMounting = ReactLifeCycle.currentlyMountingInstance; - ReactLifeCycle.currentlyMountingInstance = this; - try { - if (inst.componentWillMount) { - inst.componentWillMount(); - // When mounting, calls to `setState` by `componentWillMount` will set - // `this._pendingStateQueue` without triggering a re-render. - if (this._pendingStateQueue) { - inst.state = this._processPendingState(inst.props, inst.context); - } - } - - renderedElement = this._renderValidatedComponent(); - } finally { - ReactLifeCycle.currentlyMountingInstance = previouslyMounting; - } - - this._renderedComponent = this._instantiateReactComponent( - renderedElement, - this._currentElement.type // The wrapping type - ); - - var markup = ReactReconciler.mountComponent( - this._renderedComponent, - rootID, - transaction, - this._processChildContext(context) - ); - if (inst.componentDidMount) { - transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); - } - - return markup; -}; - -ReactCompositeComponentMixin.updateComponent = function( - transaction, - prevParentElement, - nextParentElement, - prevUnmaskedContext, - nextUnmaskedContext -) { - var inst = this._instance; - - var nextContext = inst.context; - var nextProps = inst.props; - - // Distinguish between a props update versus a simple state update - if (prevParentElement !== nextParentElement) { - nextContext = this._processContext(nextUnmaskedContext); - nextProps = this._processProps(nextParentElement.props); - - // An update here will schedule an update but immediately set - // _pendingStateQueue which will ensure that any state updates gets - // immediately reconciled instead of waiting for the next batch. - - if (inst.componentWillReceiveProps) { - inst.componentWillReceiveProps(nextProps, nextContext); - } - } - - var nextState = this._processPendingState(nextProps, nextContext); - - var shouldUpdate = - this._pendingForceUpdate || - !inst.shouldComponentUpdate || - inst.shouldComponentUpdate(nextProps, nextState, nextContext); - - if ("production" !== process.env.NODE_ENV) { - ("production" !== process.env.NODE_ENV ? warning( - typeof shouldUpdate !== 'undefined', - '%s.shouldComponentUpdate(): Returned undefined instead of a ' + - 'boolean value. Make sure to return true or false.', - this.getName() || 'ReactCompositeComponent' - ) : null); - } - - if (shouldUpdate) { - this._pendingForceUpdate = false; - // Will set `this.props`, `this.state` and `this.context`. - this._performComponentUpdate( - nextParentElement, - nextProps, - nextState, - nextContext, - transaction, - nextUnmaskedContext - ); - } else { - // If it's determined that a component should not update, we still want - // to set props and state but we shortcut the rest of the update. - this._currentElement = nextParentElement; - this._context = nextUnmaskedContext; - inst.props = nextProps; - inst.state = nextState; - inst.context = nextContext; - } -}; - - -console.warn('Applied react-parent-context-patch!'); diff --git a/test/fixtures/theme-container.jsx b/test/fixtures/theme-container.jsx deleted file mode 100644 index b2daa9d38f079f..00000000000000 --- a/test/fixtures/theme-container.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react/addons'; -import ThemeManager from 'styles/theme-manager'; - -const TestUtils = React.addons.TestUtils; -const Manager = new ThemeManager(); - - -class ThemeContainer extends React.Component { - getChildContext() { - return { - muiTheme: Manager.getCurrentTheme() - }; - } - - render() { - console.log('container'); - console.log(this.getChildContext()); - return
{React.cloneElement(React.Children.only(this.props.children), { ref: 'base' })}
; - } - - getBaseComponent() { - return this.refs.base; - } -} - -ThemeContainer.childContextTypes = { - muiTheme: React.PropTypes.object -}; - - -function renderIntoDocumentWithTheme(component) { - return TestUtils.renderIntoDocument({component}).getBaseComponent(); -} - -module.exports = ThemeContainer; -/* - -module.exports = { - renderIntoDocumentWithTheme: renderIntoDocumentWithTheme, - ThemeManager: Manager, -}; -*/ From ff8f1cb2487413304837aa258e9a0f179b6b8e35 Mon Sep 17 00:00:00 2001 From: Josh Kruder Date: Wed, 5 Aug 2015 20:55:59 -0400 Subject: [PATCH 3/3] Added missing dep. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index ae5b571a2bdf86..772182d93157df 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "mocha": "^2.2.5", "phantomjs": "^1.9.17", "react-router": "^0.13.3", + "react-stub-context": "^0.3.0", "react-tap-event-plugin": "^0.1.6", "sinon": "^1.15.4", "sinon-chai": "^2.8.0"