-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
style(tests): refactor tests (#1501)
- Loading branch information
1 parent
d0a54fb
commit 7562368
Showing
13 changed files
with
1,143 additions
and
1,086 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import _ from 'lodash' | ||
import React, { createElement } from 'react' | ||
|
||
import { consoleUtil } from 'test/utils' | ||
|
||
export const classNamePropValueBeforePropName = (Component, propKey, propValues, options = {}) => { | ||
const { className = propKey, requiredProps = {} } = options | ||
|
||
propValues.forEach(propVal => { | ||
it(`adds "${propVal} ${className}" to className`, () => { | ||
shallow(createElement(Component, { ...requiredProps, [propKey]: propVal })) | ||
.should.have.className(`${propVal} ${className}`) | ||
}) | ||
}) | ||
} | ||
|
||
export const noClassNameFromBoolProps = (Component, propKey, propValues, options = {}) => { | ||
const { className = propKey, requiredProps = {} } = options | ||
|
||
_.each([true, false], bool => it(`does not add any className when ${bool}`, () => { | ||
consoleUtil.disableOnce() | ||
|
||
const wrapper = shallow(createElement(Component, { ...requiredProps, [propKey]: bool })) | ||
|
||
wrapper.should.not.have.className(className) | ||
wrapper.should.not.have.className('true') | ||
wrapper.should.not.have.className('false') | ||
|
||
propValues.forEach(propVal => wrapper.should.not.have.className(propVal.toString())) | ||
})) | ||
} | ||
|
||
export const noDefaultClassNameFromProp = (Component, propKey, propValues, options = {}) => { | ||
const { defaultProps = {} } = Component | ||
const { className = propKey, requiredProps = {} } = options | ||
// required props may include a prop that creates a className | ||
// if so, we cannot assert that it doesn't exist by default because it is required to exist | ||
// skip assertions for required props | ||
if (propKey in defaultProps) return | ||
if (propKey in requiredProps) return | ||
|
||
it('is not included in className when not defined', () => { | ||
const wrapper = shallow(<Component {...requiredProps} />) | ||
wrapper.should.not.have.className(className) | ||
|
||
// ensure that none of the prop option values are in className | ||
// SUI classes ought to be built up using a declarative component API | ||
propValues.forEach(propValue => wrapper.should.not.have.className(propValue.toString())) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
export default (testName, Component) => { | ||
const throwError = msg => { | ||
throw new Error(`${testName}: ${msg} \n Component: ${Component && Component.name}`) | ||
} | ||
|
||
const assertRequired = (required, description) => { | ||
return required || throwError(`Required ${description}, got: ${required} (${typeof required})`) | ||
} | ||
|
||
return { | ||
assertRequired, | ||
throwError, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import _ from 'lodash' | ||
import path from 'path' | ||
import React from 'react' | ||
import ReactDOMServer from 'react-dom/server' | ||
|
||
import { META } from 'src/lib' | ||
import helpers from './commonHelpers' | ||
|
||
const componentCtx = require.context( | ||
'../../../src/', | ||
true, | ||
/(addons|collections|elements|modules|views).\w+.(?!index)\w+.js/ | ||
) | ||
|
||
const componentInfo = componentCtx.keys().map(key => { | ||
const Component = componentCtx(key).default | ||
const componentType = typeof Component | ||
const { throwError } = helpers('componentInfo', Component) | ||
|
||
if (componentType !== 'function') { | ||
throwError([ | ||
`${key} is not properly exported.`, | ||
`Components should export a class or function, got: ${componentType}.`, | ||
].join(' ')) | ||
} | ||
|
||
const { _meta, prototype } = Component | ||
|
||
if (!_meta) { | ||
throwError([ | ||
'Component is missing a static _meta object property. This should help identify it:', | ||
`Rendered:\n${ReactDOMServer.renderToStaticMarkup(<Component />)}`, | ||
].join('\n')) | ||
} | ||
|
||
const constructorName = prototype.constructor.name | ||
const filePath = key | ||
const filename = path.basename(key) | ||
const filenameWithoutExt = path.basename(key, '.js') | ||
const subComponentName = _.has(_meta, 'parent') && _.has(_meta, 'name') | ||
? _meta.name.replace(_meta.parent, '') | ||
: null | ||
|
||
// name of the component, sub component, or plural parent for sub component groups | ||
const componentClassName = ( | ||
META.isChild(Component) | ||
? subComponentName.replace(/Group$/, `${_meta.parent}s`) | ||
: _meta.name | ||
).toLowerCase() | ||
|
||
return { | ||
_meta, | ||
Component, | ||
constructorName, | ||
componentClassName, | ||
subComponentName, | ||
filePath, | ||
filename, | ||
filenameWithoutExt, | ||
} | ||
}) | ||
|
||
export default componentInfo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import _ from 'lodash' | ||
|
||
/** | ||
* Assert a component exposes other components as (static properties). | ||
* @param {React.Component|Function} Component The Component. | ||
* @param {React.Component[]} subComponents Array of components that should exist on Component. | ||
*/ | ||
export default (Component, subComponents) => { | ||
const staticValues = _.values(Component) | ||
|
||
_.each(subComponents, subComponent => { | ||
it(`has sub component ${subComponent._meta.name}`, () => { | ||
staticValues.should.contain(subComponent) | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import React from 'react' | ||
import helpers from './commonHelpers' | ||
|
||
/** | ||
* Assert a component adds the Semantic UI "ui" className. | ||
* @param {React.Component|Function} Component The Component. | ||
* @param {Object} [options={}] | ||
* @param {Object} [options.requiredProps={}] Props required to render the component. | ||
*/ | ||
export default (Component, options = {}) => { | ||
const { requiredProps = {} } = options | ||
const { assertRequired } = helpers('hasUIClassName', Component) | ||
|
||
it('has the "ui" className', () => { | ||
assertRequired(Component, 'a `Component`') | ||
|
||
shallow(<Component {...requiredProps} />) | ||
.should.have.className('ui') | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import { createElement } from 'react' | ||
import _ from 'lodash' | ||
|
||
import { consoleUtil } from 'test/utils' | ||
import { | ||
classNamePropValueBeforePropName, | ||
noClassNameFromBoolProps, | ||
noDefaultClassNameFromProp, | ||
} from './classNameHelpers' | ||
import helpers from './commonHelpers' | ||
|
||
/** | ||
* Assert that a Component prop's name and value are required to create a className. | ||
* @param {React.Component|Function} Component The component to test. | ||
* @param {String} propKey A props key. | ||
* @param {array} propValues Array of possible values of prop. | ||
* @param {Object} [options={}] | ||
* @param {Object} [options.requiredProps={}] Props required to render the component. | ||
* @param {Object} [options.className=propKey] The className to assert exists. | ||
*/ | ||
export const propKeyAndValueToClassName = (Component, propKey, propValues, options = {}) => { | ||
const { assertRequired } = helpers('propKeyAndValueToClassName', Component) | ||
|
||
describe(`${propKey} (common)`, () => { | ||
assertRequired(Component, 'a `Component`') | ||
assertRequired(propKey, 'a `propKey`') | ||
|
||
classNamePropValueBeforePropName(Component, propKey, propValues, options) | ||
noDefaultClassNameFromProp(Component, propKey, propValues, options) | ||
noClassNameFromBoolProps(Component, propKey, propValues, options) | ||
}) | ||
} | ||
|
||
/** | ||
* Assert that only a Component prop's name is converted to className. | ||
* @param {React.Component|Function} Component The component to test. | ||
* @param {String} propKey A props key. | ||
* @param {Object} [options={}] | ||
* @param {Object} [options.requiredProps={}] Props required to render the component. | ||
* @param {Object} [options.className=propKey] The className to assert exists. | ||
*/ | ||
export const propKeyOnlyToClassName = (Component, propKey, options = {}) => { | ||
const { className = propKey, requiredProps = {} } = options | ||
const { assertRequired } = helpers('propKeyOnlyToClassName', Component) | ||
|
||
describe(`${propKey} (common)`, () => { | ||
assertRequired(Component, 'a `Component`') | ||
assertRequired(propKey, 'a `propKey`') | ||
|
||
noDefaultClassNameFromProp(Component, propKey, [], options) | ||
|
||
it('adds prop name to className', () => { | ||
shallow(createElement(Component, { ...requiredProps, [propKey]: true })) | ||
.should.have.className(className) | ||
}) | ||
|
||
it('does not add prop value to className', () => { | ||
consoleUtil.disableOnce() | ||
|
||
const value = 'foo-bar-baz' | ||
shallow(createElement(Component, { ...requiredProps, [propKey]: value })) | ||
.should.not.have.className(value) | ||
}) | ||
}) | ||
} | ||
|
||
/** | ||
* Assert that a Component prop name or value convert to a className. | ||
* @param {React.Component|Function} Component The component to test. | ||
* @param {String} propKey A props key. | ||
* @param {array} propValues Array of possible values of prop. | ||
* @param {Object} [options={}] | ||
* @param {Object} [options.requiredProps={}] Props required to render the component. | ||
* @param {Object} [options.className=propKey] The className to assert exists. | ||
*/ | ||
export const propKeyOrValueAndKeyToClassName = (Component, propKey, propValues, options = {}) => { | ||
const { className = propKey, requiredProps = {} } = options | ||
const { assertRequired } = helpers('propKeyOrValueAndKeyToClassName', Component) | ||
|
||
describe(`${propKey} (common)`, () => { | ||
assertRequired(Component, 'a `Component`') | ||
assertRequired(propKey, 'a `propKey`') | ||
|
||
noDefaultClassNameFromProp(Component, propKey, propValues, options) | ||
classNamePropValueBeforePropName(Component, propKey, propValues, options) | ||
|
||
beforeEach(() => { | ||
consoleUtil.disableOnce() | ||
}) | ||
|
||
it('adds only the name to className when true', () => { | ||
shallow(createElement(Component, { ...requiredProps, [propKey]: true })) | ||
.should.have.className(className) | ||
}) | ||
|
||
it('adds no className when false', () => { | ||
const wrapper = shallow(createElement(Component, { ...requiredProps, [propKey]: false })) | ||
|
||
wrapper.should.not.have.className(className) | ||
wrapper.should.not.have.className('true') | ||
wrapper.should.not.have.className('false') | ||
|
||
_.each(propValues, propVal => { | ||
wrapper.should.not.have.className(propVal) | ||
}) | ||
}) | ||
}) | ||
} | ||
|
||
/** | ||
* Assert that only a Component prop's value is converted to className. | ||
* @param {React.Component|Function} Component The component to test. | ||
* @param {String} propKey A props key. | ||
* @param {array} propValues Array of possible props values. | ||
* @param {Object} [options={}] | ||
* @param {Object} [options.requiredProps={}] Props required to render the component. | ||
* @param {Object} [options.className=propKey] The className to assert exists. | ||
*/ | ||
export const propValueOnlyToClassName = (Component, propKey, propValues, options = {}) => { | ||
const { requiredProps = {} } = options | ||
const { assertRequired } = helpers('propValueOnlyToClassName', Component) | ||
|
||
describe(`${propKey} (common)`, () => { | ||
assertRequired(Component, 'a `Component`') | ||
assertRequired(propKey, 'a `propKey`') | ||
|
||
noClassNameFromBoolProps(Component, propKey, propValues, options) | ||
noDefaultClassNameFromProp(Component, propKey, propValues, options) | ||
|
||
it('adds prop value to className', () => { | ||
propValues.forEach(propValue => { | ||
shallow(createElement(Component, { ...requiredProps, [propKey]: propValue })) | ||
.should.have.className(propValue) | ||
}) | ||
}) | ||
|
||
it('does not add prop name to className', () => { | ||
consoleUtil.disableOnce() | ||
|
||
propValues.forEach(propValue => { | ||
shallow(createElement(Component, { ...requiredProps, [propKey]: propValue })) | ||
.should.not.have.className(propKey) | ||
}) | ||
}) | ||
}) | ||
} |
Oops, something went wrong.