-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
646bcbb
commit 0e1b153
Showing
7 changed files
with
293 additions
and
0 deletions.
There are no files selected for viewing
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,3 @@ | ||
{ | ||
"presets": ["es2015", "react"] | ||
} |
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,11 @@ | ||
root = true | ||
|
||
[*] | ||
indent_style = space | ||
indent_size = 2 | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
insert_final_newline = true | ||
|
||
[*.md] | ||
trim_trailing_whitespace = false |
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,2 @@ | ||
coverage | ||
__tests__ |
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,5 @@ | ||
language: node_js | ||
node_js: | ||
- 7 | ||
- 6 | ||
after_script: 'cat ./coverage/lcov.info | coveralls' |
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,141 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import chai from 'chai'; | ||
import loading from '../index'; | ||
import reactTestUtils from 'react-dom/test-utils'; | ||
import { shallow, configure } from 'enzyme'; | ||
import Adapter from 'enzyme-adapter-react-16'; | ||
import { exec } from 'child_process'; | ||
|
||
configure({ adapter: new Adapter() }); | ||
|
||
class TestClass extends React.Component { | ||
render() { | ||
return ( | ||
<div> | ||
{ this.renderLoading() } | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
TestClass.propTypes = { | ||
prop: PropTypes.object | ||
}; | ||
|
||
describe('loading-hoc', () => { | ||
test('exports', () => { | ||
chai.assert.isFunction(loading); | ||
}); | ||
|
||
test('doesnt throw', () => { | ||
chai.assert.doesNotThrow(() => loading()()); | ||
}); | ||
|
||
describe('defaults', () => { | ||
const Loading = loading()(TestClass); | ||
|
||
test('creates an element', () => { | ||
chai.assert.ok(reactTestUtils.isElement(<Loading loading />)); | ||
}); | ||
|
||
test('renders it withouth loading', () => { | ||
let wrapper = shallow(<Loading loading={false} />); | ||
chai.expect(wrapper.children()).to.have.length(0); | ||
}); | ||
|
||
test('renders it with loading', () => { | ||
let wrapper = shallow(<Loading loading />); | ||
chai.expect(wrapper.children()).to.have.length(1); | ||
chai.expect(wrapper.html()).to.equal('<div><div>Loading</div></div>'); | ||
}); | ||
|
||
describe('has the proper displayName', () => { | ||
test('by component name', () => { | ||
chai.expect(Loading).to.have.property('displayName', 'TestClass'); | ||
}); | ||
test('by displayName', () => { | ||
class AnotherTest extends React.Component { } | ||
AnotherTest.displayName = '__Test__'; | ||
|
||
chai.expect(loading()(AnotherTest)).to.have.property('displayName', '__Test__'); | ||
}); | ||
}); | ||
}); | ||
|
||
test('custom loading component', () => { | ||
const Loading = loading({ LoadingComponent: () => <span>loading...</span> })(TestClass); | ||
let wrapper = shallow(<Loading loading />); | ||
chai.expect(wrapper.children()).to.have.length(1); | ||
chai.expect(wrapper.html()).to.equal('<div><span>loading...</span></div>'); | ||
}); | ||
|
||
test('className', () => { | ||
const Loading = loading({ | ||
LoadingComponent: ({ className }) => <span className={className}>loading...</span>, | ||
className: '__test_class__' | ||
})(TestClass); | ||
let wrapper = shallow(<Loading loading />); | ||
chai.expect(wrapper.children()).to.have.length(1); | ||
chai.expect(wrapper.html()).to.equal('<div><span class="__test_class__">loading...</span></div>'); | ||
}); | ||
|
||
test('optional propType', () => { | ||
const Loading = loading({ loadingPropOptional: true })(TestClass); | ||
const consoleMock = jest.spyOn(global.console, 'error'); | ||
consoleMock.mockClear(); | ||
shallow(<Loading />); | ||
expect(consoleMock).toHaveBeenCalledTimes(0); | ||
}); | ||
|
||
test('full displayName', () => { | ||
const Loading = loading({ fullDisplayName: true })(TestClass); | ||
chai.expect(Loading).to.have.property('displayName', 'Loading(TestClass)'); | ||
}) | ||
|
||
test('changes default component', () => { | ||
let baseComponentSymbol = Object.getOwnPropertySymbols(loading) | ||
.find(s => s.toString() === 'Symbol(react-loading-hoc/default-base-component)'); | ||
chai.expect(loading[baseComponentSymbol]).not.to.equal(React.Component); | ||
loading.setDefaultBaseComponent(React.Component); | ||
chai.expect(loading[baseComponentSymbol]).to.equal(React.Component); | ||
}); | ||
|
||
test('changes default loading component', () => { | ||
loading.setDefaultLoadingComponent(() => <span>__test__</span>); | ||
const Loading = loading()(TestClass); | ||
let wrapper = shallow(<Loading loading />); | ||
chai.expect(wrapper.html()).to.equal('<div><span>__test__</span></div>'); | ||
}); | ||
|
||
describe('propTypes', () => { | ||
const Loading = loading()(TestClass); | ||
|
||
beforeEach(() => { | ||
// Awfull but necessary hack to prevent React from catching the component | ||
// https://github.com/facebook/react/issues/7047#issuecomment-228614964 | ||
TestClass.displayName = Math.random().toString(); | ||
}); | ||
test('sets propTypes', () => { | ||
chai.expect(Loading.propTypes).to.have.property('loading', PropTypes.bool.isRequired); | ||
}); | ||
|
||
test('propTypes fails', () => { | ||
const consoleMock = jest.spyOn(global.console, 'error'); | ||
consoleMock.mockClear(); | ||
shallow(<Loading />); | ||
expect(consoleMock).toHaveBeenCalledTimes(1); | ||
chai.expect(consoleMock.mock.calls[0][0]) | ||
.to.be.a('string') | ||
.and.have.string('Failed prop type') | ||
.and.have.string('The prop `loading` is marked as required in'); | ||
}); | ||
|
||
test('propTypes does not fail', () => { | ||
const consoleMock = jest.spyOn(global.console, 'error'); | ||
consoleMock.mockClear(); | ||
shallow(<Loading loading={false} />); | ||
expect(consoleMock).toHaveBeenCalledTimes(0); | ||
}); | ||
}); | ||
}); |
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,58 @@ | ||
const React = require('react'); | ||
const PropTypes = require('prop-types'); | ||
|
||
const ownSymbol = key => Symbol(`react-loading-hoc/${key}`); | ||
|
||
const defaultBaseComponent = ownSymbol('default-base-component'); | ||
const defaultLoadingComponent = ownSymbol('default-loading-component'); | ||
|
||
function LoadingHOC( | ||
{ | ||
LoadingComponent, | ||
className, | ||
loadingPropOptional = false, | ||
fullDisplayName = false | ||
} = {} | ||
) { | ||
LoadingComponent = LoadingComponent || LoadingHOC[defaultLoadingComponent]; | ||
|
||
return function(Component = LoadingHOC[defaultBaseComponent]) { | ||
const Loading = class extends Component { | ||
renderLoading(props = {}) { | ||
if (this.props.loading) { | ||
return React.createElement( | ||
LoadingComponent, | ||
Object.assign(props, { className }) | ||
); | ||
} | ||
return undefined; | ||
} | ||
}; | ||
|
||
// Add loading PropType if the base Component uses PropTypes | ||
if (Component.propTypes) { | ||
Loading.propTypes = Object.assign(Component.propTypes, { | ||
loading: loadingPropOptional ? PropTypes.bool : PropTypes.bool.isRequired | ||
}); | ||
} | ||
|
||
// Change the display name | ||
let displayName = Component.displayName || Component.name; | ||
Loading.displayName = fullDisplayName ? `Loading(${displayName})` : displayName; | ||
|
||
return Loading; | ||
}; | ||
} | ||
|
||
LoadingHOC[defaultLoadingComponent] = () => React.createElement('div', null, 'Loading'); | ||
|
||
LoadingHOC[defaultBaseComponent] = React.PureComponent; | ||
|
||
LoadingHOC.setDefaultBaseComponent = function(Component) { | ||
LoadingHOC[defaultBaseComponent] = Component; | ||
}; | ||
LoadingHOC.setDefaultLoadingComponent = function(Component) { | ||
LoadingHOC[defaultLoadingComponent] = Component; | ||
}; | ||
|
||
module.exports = LoadingHOC; |
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,73 @@ | ||
{ | ||
"name": "react-loading-hoc", | ||
"version": "1.0.0", | ||
"description": "HOC for React components that can be loading", | ||
"main": "index.js", | ||
"scripts": { | ||
"prepublish": "nsp check", | ||
"pretest": "eslint . --fix", | ||
"precommit": "lint-staged", | ||
"test": "jest --coverage" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/MarcoScabbiolo/react-loading-hoc.git" | ||
}, | ||
"keywords": ["react", "hoc", "loading"], | ||
"author": "Marco Scabbiolo, scabbiolo.marco@gmail.com", | ||
"license": "Apache-2.0", | ||
"bugs": { | ||
"url": "https://github.com/MarcoScabbiolo/react-loading-hoc/issues" | ||
}, | ||
"homepage": "https://github.com/MarcoScabbiolo/react-loading-hoc#readme", | ||
"dependencies": { | ||
"prop-types": "^15.6.0", | ||
"react": "^16.1.1" | ||
}, | ||
"devDependencies": { | ||
"babel-eslint": "^8.0.2", | ||
"babel-jest": "^21.2.0", | ||
"babel-preset-es2015": "^6.24.1", | ||
"babel-preset-react": "^6.24.1", | ||
"chai": "^4.1.2", | ||
"coveralls": "^3.0.0", | ||
"enzyme": "^3.2.0", | ||
"enzyme-adapter-react-16": "^1.1.0", | ||
"eslint": "^4.11.0", | ||
"eslint-config-prettier": "^2.8.0", | ||
"eslint-config-xo": "^0.19.0", | ||
"eslint-plugin-prettier": "^2.3.1", | ||
"husky": "^0.14.3", | ||
"jest": "^21.2.1", | ||
"lint-staged": "^5.0.0", | ||
"nsp": "^3.1.0", | ||
"prettier": "^1.8.2", | ||
"react-dom": "^16.1.1", | ||
"react-test-renderer": "^16.1.1" | ||
}, | ||
"lint-staged": { | ||
"*.js": ["eslint --fix", "git add"], | ||
"*.json": ["prettier --write", "git add"] | ||
}, | ||
"eslintConfig": { | ||
"parser": "babel-eslint", | ||
"env": { | ||
"jest": true, | ||
"node": true | ||
}, | ||
"extends": ["xo", "prettier"], | ||
"rules": { | ||
"prettier/prettier": [ | ||
"error", | ||
{ | ||
"singleQuote": true, | ||
"printWidth": 90 | ||
} | ||
] | ||
}, | ||
"plugins": ["prettier"] | ||
}, | ||
"jest": { | ||
"testEnvironment": "node" | ||
} | ||
} |