diff --git a/.eslintrc b/.eslintrc index 06dc1920..33105a65 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,16 +3,26 @@ "es6": true, "browser": true }, - "extends": "airbnb", + "parser": "babel-eslint", "parserOptions": { "ecmaVersion": 7, "ecmaFeatures": { - "experimentalObjectRestSpread": true, "jsx": true }, "sourceType": "module" }, - "parser": "babel-eslint", + "settings": { + "react": { + "createClass": "createReactClass", + "pragma": "React", + "version": "15.0" + }, + "propWrapperFunctions": [ "forbidExtraProps" ] + }, + "extends": ["eslint:recommended", "plugin:react/recommended"], + "globals": { + "process": true + }, "rules": { "quotes": [0], "comma-dangle": [2, "only-multiline"], @@ -23,12 +33,9 @@ "func-names": [0], "arrow-parens": [0], "space-before-function-paren": [0], - "import/no-extraneous-dependencies": [2, {"devDependencies": true}], "jsx-a11y/no-static-element-interactions": [0], "react/no-find-dom-node": [0], "react/jsx-closing-bracket-location": [0], - "react/jsx-filename-extension": ["error", {"extensions": [".js"]}], - "react/forbid-prop-types": [1, {"forbid": ["any"]}], "react/require-default-props": 0 } } diff --git a/karma.conf.js b/karma.conf.js index 023f7cab..b9e1cd14 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,34 +1,33 @@ -const browsers = [process.env.CONTINUOUS_INTEGRATION ? 'Firefox' : 'Chrome']; +let browsers = ['Chrome']; +let coverageType = 'text'; + +if (process.env.CONTINUOUS_INTEGRATION) { + browsers = ['Firefox']; + coverageType = 'lcovonly'; +} module.exports = function(config) { config.set({ - - basePath: '', - frameworks: ['mocha'], - files: [ - 'specs/spec_index.js' - ], - preprocessors: { - 'specs/spec_index.js': ['webpack', 'sourcemap'] + './src/*.js': ['coverage'], + './src/**/*.js': ['coverage'], + './specs/index.js': ['webpack', 'sourcemap'] }, + files: ['./specs/index.js'], + webpack: require('./webpack.test.config'), - webpackMiddleware: { - stats: 'errors-only' - }, + webpackMiddleware: { stats: 'errors-only' }, reporters: ['mocha', 'coverage'], - mochaReporter: { - showDiff: true - }, + mochaReporter: { showDiff: true }, coverageReporter: { - type : 'lcov', + type : coverageType, dir : 'coverage/', subdir: '.' }, diff --git a/package.json b/package.json index 13b04ac0..eeef8456 100644 --- a/package.json +++ b/package.json @@ -15,51 +15,44 @@ "scripts": { "start": "./node_modules/.bin/webpack-dev-server --inline --host 127.0.0.1 --content-base examples/", "test": "cross-env NODE_ENV=test karma start", - "lint": "eslint src/" + "lint": "eslint src/ spec/" }, "authors": [ "Ryan Florence" ], "license": "MIT", "devDependencies": { - "babel-cli": "^6.24.1", "babel-core": "^6.25.0", - "babel-eslint": "^7.1.1", - "babel-loader": "^6.2.4", + "babel-eslint": "^8.0.0", + "babel-loader": "^7.1.2", "babel-plugin-add-module-exports": "^0.2.1", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "babel-preset-stage-2": "^6.24.1", - "codeclimate-test-reporter": "^0.4.0", "coveralls": "^2.13.1", "cross-env": "^5.0.1", - "envify": "^3.4.1", - "eslint": "^3.19.0", - "eslint-config-airbnb": "^15.0.1", - "eslint-plugin-import": "^2.3.0", - "eslint-plugin-jsx-a11y": "^5.0.3", + "eslint": "^4.7.1", + "eslint-plugin-jsx-a11y": "^6.0.2", "eslint-plugin-react": "^7.1.0", - "expect": "^1.20.2", "gitbook-cli": "^2.3.0", - "istanbul-instrumenter-loader": "0.2.0", + "istanbul-instrumenter-loader": "^3.0.0", "karma": "^1.3.0", - "karma-chrome-launcher": "2.0.0", - "karma-cli": "1.0.1", + "karma-chrome-launcher": "2.2.0", "karma-coverage": "^1.1.1", - "karma-firefox-launcher": "1.0.0", + "karma-firefox-launcher": "1.0.1", "karma-mocha": "^1.3.0", "karma-mocha-reporter": "^2.2.1", "karma-sourcemap-loader": "^0.3.7", - "karma-webpack": "^1.8.1", - "mocha": "3.2.0", - "npm-run-all": "^3.1.2", + "karma-webpack": "^2.0.4", + "mocha": "3.5.3", + "npm-run-all": "^4.1.1", "react": "^15.6.1", "react-dom": "^15.6.1", - "rf-release": "0.4.0", + "should": "^13.1.0", "sinon": "next", - "uglify-js": "2.4.24", - "webpack": "^1.12.14", - "webpack-dev-server": "1.11.0" + "uglify-js": "3.1.1", + "webpack": "^3.6.0", + "webpack-dev-server": "2.8.2" }, "dependencies": { "exenv": "^1.2.0", diff --git a/specs/Modal.events.spec.js b/specs/Modal.events.spec.js index cf353a9b..7d31aa66 100644 --- a/specs/Modal.events.spec.js +++ b/specs/Modal.events.spec.js @@ -1,41 +1,41 @@ /* eslint-env mocha */ +import 'should'; import sinon from 'sinon'; -import expect from 'expect'; import React from 'react'; import ReactDOM from 'react-dom'; import TestUtils from 'react-dom/test-utils'; -import Modal from '../src/components/Modal'; +import Modal from '../src/components/Modal.js'; import { moverlay, mcontent, clickAt, mouseDownAt, mouseUpAt, escKeyDown, tabKeyDown, renderModal, emptyDOM } from './helper'; -describe('Events', () => { +export default () => { afterEach('Unmount modal', emptyDOM); it('should trigger the onAfterOpen callback', () => { const afterOpenCallback = sinon.spy(); renderModal({ isOpen: true, onAfterOpen: afterOpenCallback }); - expect(afterOpenCallback.called).toBeTruthy(); + afterOpenCallback.called.should.be.ok(); }); it('keeps focus inside the modal when child has no tabbable elements', () => { let tabPrevented = false; const modal = renderModal({ isOpen: true }, 'hello'); const content = mcontent(modal); - expect(document.activeElement).toEqual(content); + document.activeElement.should.be.eql(content); tabKeyDown(content, { preventDefault() { tabPrevented = true; } }); - expect(tabPrevented).toEqual(true); + tabPrevented.should.be.eql(true); }); it('handles case when child has no tabbable elements', () => { const modal = renderModal({ isOpen: true }, 'hello'); const content = mcontent(modal); tabKeyDown(content); - expect(document.activeElement).toEqual(content); + document.activeElement.should.be.eql(content); }); it('should close on Esc key event', () => { @@ -46,10 +46,10 @@ describe('Events', () => { onRequestClose: requestCloseCallback }); escKeyDown(mcontent(modal)); - expect(requestCloseCallback.called).toBeTruthy(); + requestCloseCallback.called.should.be.ok(); // Check if event is passed to onRequestClose callback. - const event = requestCloseCallback.getCall(0).args[0]; - expect(event).toExist(); + const ev = requestCloseCallback.getCall(0).args[0]; + ev.should.be.ok(); }); describe('shouldCloseOnoverlayClick', () => { @@ -61,7 +61,7 @@ describe('Events', () => { }); const overlay = moverlay(modal); clickAt(overlay); - expect(!requestCloseCallback.called).toBeTruthy(); + requestCloseCallback.called.should.not.be.ok(); }); it('when true, click on overlay must close', () => { @@ -72,7 +72,7 @@ describe('Events', () => { onRequestClose: requestCloseCallback }); clickAt(moverlay(modal)); - expect(requestCloseCallback.called).toBeTruthy(); + requestCloseCallback.called.should.be.ok(); }); it('overlay mouse down and content mouse up, should not close', () => { @@ -84,7 +84,7 @@ describe('Events', () => { }); mouseDownAt(moverlay(modal)); mouseUpAt(mcontent(modal)); - expect(!requestCloseCallback.called).toBeTruthy(); + requestCloseCallback.called.should.not.be.ok(); }); it('content mouse down and overlay mouse up, should not close', () => { @@ -96,7 +96,7 @@ describe('Events', () => { }); mouseDownAt(mcontent(modal)); mouseUpAt(moverlay(modal)); - expect(!requestCloseCallback.called).toBeTruthy(); + requestCloseCallback.called.should.not.be.ok(); }); }); @@ -110,7 +110,7 @@ describe('Events', () => { hasPropagated = true; }); moverlay(modal).dispatchEvent(new MouseEvent('click', { bubbles: true })); - expect(hasPropagated).toBeTruthy(); + hasPropagated.should.be.ok(); }); it('verify event passing on overlay click', () => { @@ -125,9 +125,9 @@ describe('Events', () => { // Used to test that this was the event received fakeData: 'ABC' }); - expect(requestCloseCallback.called).toBeTruthy(); + requestCloseCallback.called.should.be.ok(); // Check if event is passed to onRequestClose callback. const event = requestCloseCallback.getCall(0).args[0]; - expect(event).toExist(); + event.should.be.ok(); }); -}); +}; diff --git a/specs/Modal.spec.js b/specs/Modal.spec.js index 38248c82..f9861b45 100644 --- a/specs/Modal.spec.js +++ b/specs/Modal.spec.js @@ -1,10 +1,11 @@ /* eslint-env mocha */ -import expect from 'expect'; +import 'should'; +import should from 'should'; import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import TestUtils from 'react-dom/test-utils'; -import Modal from '../src/components/Modal'; -import * as ariaAppHider from '../src/helpers/ariaAppHider'; +import Modal from 'react-modal'; +import * as ariaAppHider from 'react-modal/helpers/ariaAppHider'; import { isBodyWithReactModalOpenClass, contentAttribute, @@ -13,7 +14,7 @@ import { renderModal, unmountModal, emptyDOM } from './helper'; -describe('State', () => { +export default () => { afterEach('check if test cleaned up rendered modals', emptyDOM); it('scopes tab navigation to the modal'); @@ -22,29 +23,29 @@ describe('State', () => { it('can be open initially', () => { const modal = renderModal({ isOpen: true }, 'hello'); - expect(mcontent(modal)).toExist(); + mcontent(modal).should.be.ok(); }); it('can be closed initially', () => { const modal = renderModal({}, 'hello'); - expect(ReactDOM.findDOMNode(mcontent(modal))).toNotExist(); + should(ReactDOM.findDOMNode(mcontent(modal))).not.be.ok(); }); it('doesn\'t render the portal if modal is closed', () => { const modal = renderModal({}, 'hello'); - expect(ReactDOM.findDOMNode(modal.portal)).toNotExist(); - }) + should(ReactDOM.findDOMNode(modal.portal)).not.be.ok(); + }); it('has default props', () => { const node = document.createElement('div'); Modal.setAppElement(document.createElement('div')); const modal = ReactDOM.render(, node); const props = modal.props; - expect(props.isOpen).toBe(false); - expect(props.ariaHideApp).toBe(true); - expect(props.closeTimeoutMS).toBe(0); - expect(props.shouldFocusAfterRender).toBe(true); - expect(props.shouldCloseOnOverlayClick).toBe(true); + props.isOpen.should.not.be.ok(); + props.ariaHideApp.should.be.ok(); + props.closeTimeoutMS.should.be.eql(0); + props.shouldFocusAfterRender.should.be.ok(); + props.shouldCloseOnOverlayClick.should.be.ok(); ReactDOM.unmountComponentAtNode(node); ariaAppHider.resetForTesting(); Modal.setAppElement(document.body); // restore default @@ -56,7 +57,7 @@ describe('State', () => { ReactDOM.render(( ), node); - expect(el.getAttribute('aria-hidden')).toEqual('true'); + el.getAttribute('aria-hidden').should.be.eql('true'); ReactDOM.unmountComponentAtNode(node); }); @@ -75,9 +76,9 @@ describe('State', () => { } Modal.setAppElement(node); ReactDOM.render(, node); - expect( - document.body.querySelector('.ReactModalPortal').parentNode - ).toEqual( + document.body.querySelector( + '.ReactModalPortal' + ).parentNode.should.be.eql( document.body ); ReactDOM.unmountComponentAtNode(node); @@ -85,13 +86,13 @@ describe('State', () => { it ('default parentSelector should be document.body.', () => { const modal = renderModal({ isOpen: true }); - expect(modal.props.parentSelector()).toEqual(document.body); + modal.props.parentSelector().should.be.eql(document.body); }); it('renders the modal content with a dialog aria role when provided ', () => { const child = 'I am a child of Modal, and he has sent me here...'; const modal = renderModal({ isOpen: true, role: 'dialog' }, child); - expect(contentAttribute(modal, 'role')).toEqual('dialog'); + contentAttribute(modal, 'role').should.be.eql('dialog'); }); it('sets aria-label based on the contentLabel prop', () => { @@ -100,15 +101,14 @@ describe('State', () => { isOpen: true, contentLabel: 'Special Modal' }, child); - expect( - contentAttribute(modal, 'aria-label') - ).toEqual('Special Modal'); + + contentAttribute(modal, 'aria-label').should.be.eql('Special Modal'); }); it('removes the portal node', () => { const modal = renderModal({ isOpen: true }, 'hello'); unmountModal(); - expect(document.querySelector('.ReactModalPortal')).toNotExist(); + should(document.querySelector('.ReactModalPortal')).not.be.ok(); }); it('removes the portal node after closeTimeoutMS', done => { @@ -117,7 +117,7 @@ describe('State', () => { function checkDOM(count) { const portal = document.querySelectorAll('.ReactModalPortal'); - expect(portal.length).toBe(count); + portal.length.should.be.eql(count); } unmountModal(); @@ -134,12 +134,12 @@ describe('State', () => { it('focuses the modal content by default', () => { const modal = renderModal({ isOpen: true }, null); - expect(document.activeElement).toBe(mcontent(modal)); + document.activeElement.should.be.eql(mcontent(modal)); }); it('does not focus the modal content when shouldFocusAfterRender is false', () => { const modal = renderModal({ isOpen: true, shouldFocusAfterRender: false }, null); - expect(document.activeElement).toNotBe(mcontent(modal)); + document.activeElement.should.not.be.eql(mcontent(modal)); }); it('give back focus to previous element or modal.', done => { @@ -154,16 +154,16 @@ describe('State', () => { }, null); const modalContent = mcontent(modalA); - expect(document.activeElement).toEqual(modalContent); + document.activeElement.should.be.eql(modalContent); const modalB = renderModal({ isOpen: true, className: 'modal-b', onRequestClose() { const modalContent = mcontent(modalB); - expect(document.activeElement).toEqual(mcontent(modalA)); + document.activeElement.should.be.eql(mcontent(modalA)); escKeyDown(modalContent); - expect(document.activeElement).toEqual(modalContent); + document.activeElement.should.be.eql(modalContent); } }, null); @@ -176,7 +176,7 @@ describe('State', () => { { el && el.focus(); content = el; }} /> ); renderModal({ isOpen: true }, input, () => { - expect(document.activeElement).toEqual(content); + document.activeElement.should.be.eql(content); }); }); @@ -185,14 +185,12 @@ describe('State', () => { isOpen: true, portalClassName: 'myPortalClass' }); - expect(modal.node.className.includes('myPortalClass')).toBeTruthy(); + modal.node.className.includes('myPortalClass').should.be.ok(); }); it('supports custom className', () => { const modal = renderModal({ isOpen: true, className: 'myClass' }); - expect( - mcontent(modal).className.includes('myClass') - ).toBeTruthy(); + mcontent(modal).className.includes('myClass').should.be.ok(); }); it('supports overlayClassName', () => { @@ -200,9 +198,7 @@ describe('State', () => { isOpen: true, overlayClassName: 'myOverlayClass' }); - expect( - moverlay(modal).className.includes('myOverlayClass') - ).toBeTruthy(); + moverlay(modal).className.includes('myOverlayClass').should.be.ok(); }); it('overrides content classes with custom object className', () => { @@ -214,9 +210,7 @@ describe('State', () => { beforeClose: 'myClass_before-close' } }); - expect( - mcontent(modal).className - ).toEqual( + mcontent(modal).className.should.be.eql( 'myClass myClass_after-open' ); unmountModal(); @@ -231,9 +225,7 @@ describe('State', () => { beforeClose: 'myOverlayClass_before-close' } }); - expect( - moverlay(modal).className - ).toEqual( + moverlay(modal).className.should.be.eql( 'myOverlayClass myOverlayClass_after-open' ); unmountModal(); @@ -244,37 +236,35 @@ describe('State', () => { isOpen: true, bodyOpenClassName: 'custom-modal-open' }); - expect( - document.body.className.indexOf('custom-modal-open') > -1 - ).toBeTruthy(); + (document.body.className.indexOf('custom-modal-open') > -1).should.be.ok(); }); it('don\'t append class to document.body if modal is not open', () => { renderModal({ isOpen: false }); - expect(!isBodyWithReactModalOpenClass()).toBeTruthy(); + isBodyWithReactModalOpenClass().should.not.be.ok(); unmountModal(); }); it('append class to document.body if modal is open', () => { renderModal({ isOpen: true }); - expect(isBodyWithReactModalOpenClass()).toBeTruthy(); + isBodyWithReactModalOpenClass().should.be.ok(); unmountModal(); }); it('removes class from document.body when unmounted without closing', () => { renderModal({ isOpen: true }); unmountModal(); - expect(!isBodyWithReactModalOpenClass()).toBeTruthy(); + isBodyWithReactModalOpenClass().should.not.be.ok(); }); it('remove class from document.body when no modals opened', () => { renderModal({ isOpen: true }); renderModal({ isOpen: true }); - expect(isBodyWithReactModalOpenClass()).toBeTruthy(); + isBodyWithReactModalOpenClass().should.be.ok(); unmountModal(); - expect(isBodyWithReactModalOpenClass()).toBeTruthy(); + isBodyWithReactModalOpenClass().should.be.ok(); unmountModal(); - expect(!isBodyWithReactModalOpenClass()).toBeTruthy(); + isBodyWithReactModalOpenClass().should.not.be.ok(); }); it('supports adding/removing multiple document.body classes', () => { @@ -282,9 +272,9 @@ describe('State', () => { isOpen: true, bodyOpenClassName: 'A B C' }); - expect(document.body.classList.contains('A', 'B', 'C')).toBeTruthy(); + document.body.classList.contains('A', 'B', 'C').should.be.ok(); unmountModal(); - expect(!document.body.classList.contains('A', 'B', 'C')).toBeTruthy(); + document.body.classList.contains('A', 'B', 'C').should.not.be.ok(); }); it('does not remove shared classes if more than one modal is open', () => { @@ -297,38 +287,36 @@ describe('State', () => { bodyOpenClassName: 'A B' }); - expect(isBodyWithReactModalOpenClass('A B')).toBeTruthy(); + isBodyWithReactModalOpenClass('A B').should.be.ok(); unmountModal(); - expect(!isBodyWithReactModalOpenClass('A B')).toBeTruthy(); - expect(isBodyWithReactModalOpenClass('A')).toBeTruthy(); + isBodyWithReactModalOpenClass('A B').should.not.be.ok(); + isBodyWithReactModalOpenClass('A').should.be.ok(); unmountModal(); - expect(!isBodyWithReactModalOpenClass('A')).toBeTruthy(); + isBodyWithReactModalOpenClass('A').should.not.be.ok(); }); it('should not add classes to document.body for unopened modals', () => { renderModal({ isOpen: true }); - expect(isBodyWithReactModalOpenClass()).toBeTruthy(); + isBodyWithReactModalOpenClass().should.be.ok(); renderModal({ isOpen: false, bodyOpenClassName: 'testBodyClass' }); - expect(!isBodyWithReactModalOpenClass('testBodyClass')).toBeTruthy() + isBodyWithReactModalOpenClass('testBodyClass').should.not.be.ok(); }); it('should not remove classes from document.body when rendering unopened modal', () => { renderModal({ isOpen: true }); - expect(isBodyWithReactModalOpenClass()).toBeTruthy(); + isBodyWithReactModalOpenClass().should.be.ok(); renderModal({ isOpen: false, bodyOpenClassName: 'testBodyClass' }); renderModal({ isOpen: false }); - expect(!isBodyWithReactModalOpenClass('testBodyClass')).toBeTruthy() - expect(isBodyWithReactModalOpenClass()).toBeTruthy(); + isBodyWithReactModalOpenClass('testBodyClass').should.not.be.ok(); + isBodyWithReactModalOpenClass().should.be.ok(); renderModal({ isOpen: false }); renderModal({ isOpen: false }); - expect(isBodyWithReactModalOpenClass()).toBeTruthy(); + isBodyWithReactModalOpenClass().should.be.ok(); }); it('additional aria attributes', () => { const modal = renderModal({ isOpen: true, aria: { labelledby: "a" }}, 'hello'); - expect( - mcontent(modal).getAttribute('aria-labelledby') - ).toEqual("a"); + mcontent(modal).getAttribute('aria-labelledby').should.be.eql("a"); unmountModal(); }); @@ -338,13 +326,13 @@ describe('State', () => { ReactDOM.render(( ), node); - expect(document.body.getAttribute('aria-hidden')).toEqual('true'); + document.body.getAttribute('aria-hidden').should.be.eql('true'); ReactDOM.unmountComponentAtNode(node); - expect(document.body.getAttribute('aria-hidden')).toEqual(null); + should(document.body.getAttribute('aria-hidden')).not.be.ok(); }); it('raise an exception if appElement is a selector and no elements were found.', () => { - expect(() => ariaAppHider.setElement('.test')).toThrow(); + should(() => ariaAppHider.setElement('.test')).throw(); }); it('removes aria-hidden from appElement when unmounted w/o closing', () => { @@ -353,16 +341,16 @@ describe('State', () => { ReactDOM.render(( ), node); - expect(el.getAttribute('aria-hidden')).toEqual('true'); + el.getAttribute('aria-hidden').should.be.eql('true'); ReactDOM.unmountComponentAtNode(node); - expect(el.getAttribute('aria-hidden')).toEqual(null); + should(el.getAttribute('aria-hidden')).not.be.ok(); }); it('adds --after-open for animations', () => { const modal = renderModal({ isOpen: true }); const rg = /--after-open/i; - expect(rg.test(mcontent(modal).className)).toBeTruthy(); - expect(rg.test(moverlay(modal).className)).toBeTruthy(); + rg.test(mcontent(modal).className).should.be.ok(); + rg.test(moverlay(modal).className).should.be.ok(); }); it('adds --before-close for animations', () => { @@ -374,8 +362,8 @@ describe('State', () => { modal.portal.closeWithTimeout(); const rg = /--before-close/i; - expect(rg.test(moverlay(modal).className)).toBeTruthy(); - expect(rg.test(mcontent(modal).className)).toBeTruthy(); + rg.test(moverlay(modal).className).should.be.ok(); + rg.test(mcontent(modal).className).should.be.ok(); modal.portal.closeWithoutTimeout(); }); @@ -389,18 +377,18 @@ describe('State', () => { modal.portal.closeWithTimeout(); modal.portal.open(); modal.portal.closeWithoutTimeout(); - expect(!modal.portal.state.isOpen).toBeTruthy(); + modal.portal.state.isOpen.should.not.be.ok(); }); it('verify default prop of shouldCloseOnOverlayClick', () => { const modal = renderModal({ isOpen: true }); - expect(modal.props.shouldCloseOnOverlayClick).toBeTruthy(); + modal.props.shouldCloseOnOverlayClick.should.be.ok(); }); it('verify prop of shouldCloseOnOverlayClick', () => { const modalOpts = { isOpen: true, shouldCloseOnOverlayClick: false }; const modal = renderModal(modalOpts); - expect(!modal.props.shouldCloseOnOverlayClick).toBeTruthy(); + modal.props.shouldCloseOnOverlayClick.should.not.be.ok(); }); it('keeps the modal in the DOM until closeTimeoutMS elapses', done => { @@ -412,8 +400,8 @@ describe('State', () => { function checkDOM(count) { const overlay = document.querySelectorAll('.ReactModal__Overlay'); const content = document.querySelectorAll('.ReactModal__Content'); - expect(overlay.length).toBe(count); - expect(content.length).toBe(count); + overlay.length.should.be.eql(count); + content.length.should.be.eql(count); } // content is still mounted after modal is gone @@ -454,7 +442,7 @@ describe('State', () => { document.body.appendChild(currentDiv); const mount = () => ReactDOM.render(, currentDiv); - expect(mount).toNotThrow(); + mount.should.not.throw(); document.body.removeChild(currentDiv); }); @@ -470,7 +458,7 @@ describe('State', () => { } componentDidMount() { - expect(modal.node.className).toEqual('myPortalClass'); + modal.node.className.should.be.eql('myPortalClass'); this.setState({ testHasChanged: true @@ -478,7 +466,7 @@ describe('State', () => { } componentDidUpdate() { - expect(modal.node.className).toEqual('myPortalClass-modifier'); + modal.node.className.should.be.eql('myPortalClass-modifier'); } render() { @@ -501,4 +489,4 @@ describe('State', () => { Modal.setAppElement(node); ReactDOM.render(, node); }); -}); +}; diff --git a/specs/Modal.style.spec.js b/specs/Modal.style.spec.js index 68302338..59a8ddf5 100644 --- a/specs/Modal.style.spec.js +++ b/specs/Modal.style.spec.js @@ -1,21 +1,21 @@ /* eslint-env mocha */ -import expect from 'expect'; +import 'should'; import React from 'react'; import ReactDOM from 'react-dom'; import TestUtils from 'react-dom/test-utils'; -import Modal from '../src/components/Modal'; -import * as ariaAppHider from '../src/helpers/ariaAppHider'; +import Modal from 'react-modal'; +import * as ariaAppHider from 'react-modal/helpers/ariaAppHider'; import { mcontent, moverlay, renderModal, emptyDOM } from './helper'; -describe('Style', () => { +export default () => { afterEach('Unmount modal', emptyDOM); it('overrides the default styles when a custom classname is used', () => { const modal = renderModal({ isOpen: true, className: 'myClass' }); - expect(mcontent(modal).style.top).toEqual(''); + mcontent(modal).style.top.should.be.eql(''); }); it('overrides the default styles when a custom overlayClassName is used', @@ -24,32 +24,32 @@ describe('Style', () => { isOpen: true, overlayClassName: 'myOverlayClass' }); - expect(moverlay(modal).style.backgroundColor).toEqual(''); + moverlay(modal).style.backgroundColor.should.be.eql(''); } ); it('supports adding style to the modal contents', () => { const style = { content: { width: '20px' } }; const modal = renderModal({ isOpen: true, style }); - expect(mcontent(modal).style.width).toEqual('20px'); + mcontent(modal).style.width.should.be.eql('20px'); }); it('supports overriding style on the modal contents', () => { const style = { content: { position: 'static' } }; const modal = renderModal({ isOpen: true, style }); - expect(mcontent(modal).style.position).toEqual('static'); + mcontent(modal).style.position.should.be.eql('static'); }); it('supports adding style on the modal overlay', () => { const style = { overlay: { width: '75px' } }; const modal = renderModal({ isOpen: true, style }); - expect(moverlay(modal).style.width).toEqual('75px'); + moverlay(modal).style.width.should.be.eql('75px'); }); it('supports overriding style on the modal overlay', () => { const style = { overlay: { position: 'static' } }; const modal = renderModal({ isOpen: true, style }); - expect(moverlay(modal).style.position).toEqual('static'); + moverlay(modal).style.position.should.be.eql('static'); }); it('supports overriding the default styles', () => { @@ -59,7 +59,7 @@ describe('Style', () => { const newStyle = previousStyle === 'relative' ? 'static' : 'relative'; Modal.defaultStyles.content.position = newStyle; const modal = renderModal({ isOpen: true }); - expect(modal.portal.content.style.position).toEqual(newStyle); + modal.portal.content.style.position.should.be.eql(newStyle); Modal.defaultStyles.content.position = previousStyle; }); -}); +}; diff --git a/specs/index.js b/specs/index.js new file mode 100644 index 00000000..9fdd1f47 --- /dev/null +++ b/specs/index.js @@ -0,0 +1,9 @@ +/* eslint-env mocha */ + +import ModalState from './Modal.spec'; +import ModalEvents from './Modal.events.spec'; +import ModalStyle from './Modal.style.spec'; + +describe('State', ModalState); +describe('Style', ModalStyle); +describe('Events', ModalEvents); diff --git a/specs/spec_index.js b/specs/spec_index.js deleted file mode 100644 index 2d24be84..00000000 --- a/specs/spec_index.js +++ /dev/null @@ -1,19 +0,0 @@ -const testsContext = require.context('.', true, /spec$/); -testsContext.keys().forEach((path) => { - try { - testsContext(path); - } catch (err) { - console.error(`[ERROR] WITH SPEC FILE: ${path}`); - console.error(err); - } -}); - -const componentsContext = require.context('../src', true, /\.js$/); -componentsContext.keys().forEach((path) => { - try { - componentsContext(path); - } catch (err) { - console.error(`[ERROR] WITH LIB FILE: ${path}`); - console.error(err); - } -}); diff --git a/webpack.config.js b/webpack.config.js index 28c1fb08..9faa5d97 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -34,8 +34,8 @@ module.exports = { }, module: { - loaders: [ - { test: /\.js$/, exclude: /node_modules/, loader: 'babel' } + rules: [ + { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] }, @@ -46,7 +46,8 @@ module.exports = { }, plugins: [ - new webpack.optimize.CommonsChunkPlugin('shared.js') + new webpack.optimize.CommonsChunkPlugin('shared.js'), + new webpack.LoaderOptionsPlugin({ debug: true }) ] }; diff --git a/webpack.test.config.js b/webpack.test.config.js index 85302c6a..b5652f6e 100644 --- a/webpack.test.config.js +++ b/webpack.test.config.js @@ -2,17 +2,14 @@ const path = require('path'); const commonConfig = require('./webpack.config'); commonConfig.plugins = []; -commonConfig.entry = undefined; -commonConfig.debug = true; +commonConfig.entry = './specs/index.js'; commonConfig.devtool = 'inline-source-map'; -if (process.env.CONTINUOUS_INTEGRATION || process.env.COVERAGE) { - commonConfig.module.postLoaders = commonConfig.module.postLoaders || []; - commonConfig.module.postLoaders.push({ - test: /\.js$/, - include: path.resolve('src'), - loader: 'istanbul-instrumenter' - }); -} +commonConfig.module.rules.unshift({ + test: /\.js$/, + use: { loader: 'istanbul-instrumenter-loader' }, + enforce: 'post', + include: path.resolve(__dirname, './src') +}); module.exports = commonConfig;