├── .babelrc ├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── .nvmrc ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src └── index.js ├── tests ├── SelfFocus.test.js └── setupTests.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react", 4 | "env", 5 | "stage-0" 6 | ] 7 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [anubhavsrivastava] 4 | patreon: theanubhav 5 | open_collective: onlyanubhav 6 | ko_fi: theanubhav 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://donorbox.org/theanubhav', 'https://www.buymeacoffee.com/theanubhav','https://paypal.me/onlyanubhav', 'https://theanubhav.com/sponsor'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | #build directory 40 | dist/ 41 | 42 | # TypeScript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # Yarn Integrity file 58 | .yarn-integrity 59 | 60 | # dotenv environment variables file 61 | .env 62 | 63 | # next.js build output 64 | .next 65 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | .nvmrc 3 | .babelrc 4 | webpack.config.js -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v9.10.1 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '11.10.1' 4 | cache: 5 | directories: 6 | - node_modules 7 | before_install: 8 | - npm update 9 | install: 10 | - npm install 11 | script: 12 | - npm test 13 | - npx react-selffocus-element || true 14 | - npm run coveralls 15 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at anubhav.srivastava00@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Anubhav Srivastava 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-selffocus-element ![A project badge featuring the A11Y logo and the text "Built for Accessibility"](https://img.shields.io/badge/-Built_for_Accessibility-_.svg?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDI0IDUxMiI+PGRlZnM+PHN0eWxlPi5he2ZpbGw6I2ZmZjt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPmxvZ28td2hpdGU8L3RpdGxlPjxwYXRoIGNsYXNzPSJhIiBkPSJNMjYyLjYsMjYyLjc3cTE1LTEuODEsMjEuNzctNC41NywxMi4wOC00Ljc1LDE0LjI3LTE0LjgyLDIuNTctMTIuMjUtNC45NC0xNi45M3QtMjQtNC42NnEtMTguNDgsMC0yOC4xOCw5LjE1LTYuNzcsNi43Ni0xMS4xNiwxOC4yOUgxODAuMDhxNy4zMi0yNi4xNiwyMy43OC00MywyNi4zNS0yNi4zNiw3Ni42Ny0yNi4zNSwzMi43NSwwLDU1LjQ0LDEzdDE1LDQ5TDMzMS4zOSwzMzMuNHEtMiw5LjUxLTQuMzksMjMuMDUtMS42NSwxMC4yNC4wOSwxMy45MWExMy41NCwxMy41NCwwLDAsMCw2LjMxLDZsLTEuNDYsNy42OEgyNzUuMjJhNTIuNzcsNTIuNzcsMCwwLDEtLjkxLTExLjM0cS4xOC01LjMxLDEuMDktMTIuMDhhMTQ3Ljk0LDE0Ny45NCwwLDAsMS0yOS4wOSwxOS45NCw4Ny40LDg3LjQsMCwwLDEtNDAuMjUsOS43cS0yNy4wOCwwLTQxLjQ0LTE1LjQ2VDE1Ni4yOSwzMzFxNy44OC0zNi43OCwzOS43MS01My4yNCwxNy4zNy05LDQ4LjQ4LTEyLjgxWm0yNi41MywyNC4zNGE2Ny44LDY3LjgsMCwwLDEtMTEsNSw5OS4zMiw5OS4zMiwwLDAsMS0xNC42NCwzLjU3bC0xMi4wNywyLjE5cS0xNy4yLDIuOTQtMjUuMjUsNy4xNGEzMSwzMSwwLDAsMC0xNi42NSwyMi4xNHEtMi45NCwxMy4zNSwzLjIsMTkuM3QxNi43NCw1Ljk1cTE2LjgzLDAsMzMuMTItOS44OHQyMi41LTM2LjA1Wk03MjkuNCw0MjguNTJsNi41OC4zNmE4My41LDgzLjUsMCwwLDAsMTQuNjQtLjU1LDMyLjE1LDMyLjE1LDAsMCwwLDEyLjYzLTQuMjFxNS4yOS0zLjExLDExLjM0LTEzYzQtNi41OCw5Ljg2LTE2LjgsOS42MS0xOC4yN0w3NTUuMywxODQuNjVoNThsMTIuMjYsMTQ3LjFMODk4LDE4NC42NWg1NS40NEw4NDMuMywzODAuNzljLTIxLjIyLDM3LjgxLTQwLjU3LDY3LjQ2LTUwLjE0LDc2LjU0Uzc2Ny4yNyw0NzEsNzQ0LjIyLDQ3MXEtNywwLTExLjE2LS4wOXQtMTIuNDUtLjY0Wk01MzIsMzQ4SDQ4Mi4wNmw0OC42OS0yMjkuMjNINDg3LjM5cS0uNzQsMy40OC00LjM5LDEwLjYxYTU4LjMyLDU4LjMyLDAsMCwxLTE0LjI4LDE5LDYyLjYsNjIuNiwwLDAsMS0yOC41NCwxMy45cS0xMC4yNCwyLjItMzUuMzEsMy4zbC03LjUsMzUuNDloNjIuMzlMNDI4LjYyLDM0OEgzNzkuMzVsLTcuODgsMzYuMDVINDIxdjBINDc0LjR2MGg0OS43MVptMTgxLjkzLS4wOEg2NjRsNDguNjktMjI5LjcxSDY2OS4zMnEtLjc0LDMuNS00LjM5LDEwLjY0YTU4LjYyLDU4LjYyLDAsMCwxLTE0LjI3LDE5LjA3LDYyLjY4LDYyLjY4LDAsMCwxLTI4LjU1LDEzLjkzcS0xMC4yNSwyLjItMzUuMzEsMy4zbC03LjUsMzUuNTdoNjIuMzlsLTMxLjE0LDE0Ny4ySDU2MS4yOGwtNy44OCwzNi4xM2g0OS41MXYwaDUzLjQzdjBINzA2WiIvPjxwYXRoIGNsYXNzPSJhIiBkPSJNOTQ3LjEyLDgzLjI4bDE5LjcxLTM2LjA1SDEzMy40OWEzMi4yOCwzMi4yOCwwLDAsMC0zMS41OCwyNS42M0wyNi40OSw0MzEuMzJhMzIuMjgsMzIuMjgsMCwwLDAsMzEuNTksMzguOTJINjY1LjQ5bDcuODgtMzYuMDVINjMuMDZMMTM2Ljg5LDgzLjI4WiIvPjwvc3ZnPg==&logoWidth=28&colorA=20c997&colorB=343a40&style=flat) 2 | 3 | [![Build Status](https://travis-ci.org/anubhavsrivastava/react-selffocus-element.svg?branch=master)](https://travis-ci.org/anubhavsrivastava/react-selffocus-element) 4 | [![Coverage Status](https://coveralls.io/repos/github/anubhavsrivastava/react-selffocus-element/badge.svg?branch=master)](https://coveralls.io/github/anubhavsrivastava/react-selffocus-element?branch=master) 5 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) 6 | [![GitHub issues](https://img.shields.io/github/issues/anubhavsrivastava/react-selffocus-element.svg?style=flat-square)](https://github.com/anubhavsrivastava/react-selffocus-element/issues) 7 | 8 | [![NPM](https://nodei.co/npm/react-selffocus-element.png?downloads=true&stars=true)](https://nodei.co/npm/react-selffocus-element/) 9 | 10 | A React component to focus on an element when it is mounted. This is essential for seeking attention on a particular element. This can also help in getting attention of screen readers like VoiceOver, JAWS, NVDA, and friends. 11 | 12 | ## Purpose 13 | 14 | As soon there is some user event (e.g click) which cause rendering of a section on React app. For eg, a `nav` link may cause a subsection to be mounted. At few instances and to help a11y, that particular section might require focus to seek user attention. 15 | 16 | In case of a11y, for section that are not role=`document` and do not contain `heading` section fail to get screen-reader's attention and are ignored until user manually tabs over them. 17 | Such case required a user focus, `react-selffocus-element` helps in solving this for react based apps. 18 | 19 | For few scenarios, `aria-live` or `alert` does not make sense to seek attention for screen reader because that may not be same control. e.g. Seeking a focus on `list` or `tree` item helps them navigate as their respective roles without making them `alert`. 20 | 21 | ## Install 22 | 23 | ``` 24 | $ npm install react-selffocus-element --save 25 | ``` 26 | 27 | or 28 | 29 | ``` 30 | yarn add react-selffocus-element 31 | ``` 32 | 33 | ## Example 34 | 35 | 1. `` 36 | 37 | import SelfFocus from 'react-selffocus-element'; 38 | 39 | ... 40 | render(){ 41 | return ( 42 | 43 | This will only be content that will be focused on component mount. 44 | 45 | ) 46 | } 47 | ... 48 | 49 | This is render `div`(by default) tag with autofocus. This element will also be focus-able by default. 50 | 51 | `Rendered DOM` 52 | 53 |
This will only be content that will be focused on component mount.
54 | 55 | 2. With Custom Tag and TabIndex 56 | 57 | 58 | import SelfFocus from 'react-selffocus-element'; 59 | 60 | ... 61 | render(){ 62 | return ( 63 | 64 | This will only be content for custom tag and will be focused on component mount. 65 | 66 | ) 67 | } 68 | ... 69 | 70 | This is render `p`(`tag` prop) tag with autofocus. This element will be focus-able based on tabIndex prop. It is recommended that value of this prop should be 0 (natural tab order) or -1 (not tabbable). 71 | 72 | `Rendered DOM ` 73 | 74 |

This will only be content for custom tag and will be focused on component mount. 75 | 76 | ## APIs 77 | 78 | ### `SelfFocus` Component 79 | 80 | #### Import mechanism 81 | 82 | import SelfFocus from 'react-selffocus-element' 83 | 84 | #### Properties 85 | 86 | | prop | type | description | default value | 87 | | ------------------ | --------------- | ------------------------------------------- | ------------- | 88 | | children (default) | -- | Inner children for selfFocus Component | `null` | 89 | | tag | htmlTag(String) | Component/Node to be rendered for focussing | `div` | 90 | | className | string | additional Classname for particular div | `` | 91 | | tabIndex | string/number | tabbable order - 0/-1 | `0` | 92 | 93 | ## FAQ 94 | 95 | #### 1. I do not see focused element with outline. How can it be controlled? 96 | 97 | One should use additional custom css to achieve outline, which is normally in this form, 98 | 99 | *:focus { 100 | outline-style: auto !important; 101 | outline: auto !important; 102 | outline-color: #2793f8 !important; 103 | } 104 | 105 | Also note that outline behavior for screen reader will also rely on screen reader and browser ( for eg, on electron running on window will be default render yellow border unless overwritten by css) 106 | 107 | #### 2. Should I use it for form input tag? 108 | 109 | This component can be used for input tags but default `autoFocus` prop support provided by React should be used in conjunction with input tags. This will help browser functionalities to work as per focus specifications. 110 | 111 | #### 3. What about `role` and `aria-\*` attributes for that elements 112 | 113 | You can specify `role` and all `aria-*` attributes on SelfFocus component and would be available on parent element. 114 | 115 | e.g. 116 | 117 | 118 | 119 | This will render a `p` tag with `role` as `alert` 120 | 121 | #### 4. What about other props that my component requires? 122 | 123 | You can pass any key-value prop to `SelfFocus` and it will be rendered on main parent element. This is also how `aria-*` and `role` is supported. 124 | 125 | #### 5. Does this work on ComponentDidUpdate? 126 | 127 | No. There is no use case of focusing again on element after some state/prop change. In addition, there may be `componentDidUpdate` function triggered when it does not require focusing. Hence, it is currently not supported. 128 | 129 | ## License 130 | 131 | [![Open Source Love](https://badges.frapsoft.com/os/mit/mit.svg?v=102)](LICENSE) 132 | 133 | Refer `LICENSE` file in this repository. 134 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-selffocus-element", 3 | "version": "1.0.0", 4 | "description": "A react component to focus on an element for accessibility.", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test": "jest", 8 | "test:watch": "jest --watch", 9 | "test:coverage": "jest --coverage", 10 | "coveralls": "jest --coverage && cat ./coverage/lcov.info | coveralls", 11 | "start": "webpack --watch", 12 | "build": "webpack" 13 | }, 14 | "jest": { 15 | "setupFiles": [ 16 | "./tests/setupTests.js" 17 | ] 18 | }, 19 | "peerDependencies": { 20 | "react": ">15.0.0" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/anubhavsrivastava/react-selffocus-a11y.git" 25 | }, 26 | "keywords": [ 27 | "a11y", 28 | "accessbility", 29 | "web-accessibility", 30 | "react-a11y", 31 | "react-accessibility", 32 | "a11y-focus" 33 | ], 34 | "author": { 35 | "name": "Anubhav Srivastava", 36 | "email": "anubhav.srivastava00@gmail.com" 37 | }, 38 | "license": "MIT", 39 | "bugs": { 40 | "url": "https://github.com/anubhavsrivastava/react-selffocus-a11y/issues" 41 | }, 42 | "homepage": "https://github.com/anubhavsrivastava/react-selffocus-a11y#readme", 43 | "devDependencies": { 44 | "babel-cli": "^6.26.0", 45 | "babel-core": "^6.26.3", 46 | "babel-loader": "^7.0.0", 47 | "babel-preset-env": "^1.6.1", 48 | "babel-preset-react": "^6.16.0", 49 | "babel-preset-stage-0": "^6.24.1", 50 | "coveralls": "^3.0.2", 51 | "enzyme": "^3.7.0", 52 | "enzyme-adapter-react-16": "^1.6.0", 53 | "jest": "^23.6.0", 54 | "react": "^16.6.0", 55 | "react-dom": "^16.6.0", 56 | "react-test-renderer": "^16.6.0", 57 | "webpack": "^4.23.1", 58 | "webpack-cli": "^3.1.2" 59 | }, 60 | "dependencies": { 61 | "prop-types": "^15.6.2" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const defaultProps = { 5 | tag: 'div', 6 | className: '', 7 | tabIndex: 0 8 | }; 9 | 10 | const propTypes = { 11 | tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), 12 | className: PropTypes.string, 13 | tabIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) 14 | }; 15 | 16 | class SelfFocus extends PureComponent { 17 | componentDidMount() { 18 | this.focusTag.focus(); 19 | } 20 | render() { 21 | let { className, tag: Tag, children, tabIndex, ...rest } = this.props; 22 | return ( 23 | { 26 | this.focusTag = focusTag; 27 | }} 28 | tabIndex={tabIndex} 29 | className={className}> 30 | {children} 31 | 32 | ); 33 | } 34 | } 35 | 36 | SelfFocus.propTypes = propTypes; 37 | SelfFocus.defaultProps = defaultProps; 38 | 39 | export default SelfFocus; 40 | -------------------------------------------------------------------------------- /tests/SelfFocus.test.js: -------------------------------------------------------------------------------- 1 | import SelfFocus from '../src/index'; 2 | import React from 'react'; 3 | 4 | describe('check isElectron detection to be correct', () => { 5 | it('should render without crashing', () => { 6 | const wrapper = mount(); 7 | expect(wrapper.children().length).toEqual(1); 8 | expect(wrapper.find('div').length).toEqual(1); 9 | }); 10 | 11 | it('should render as element with provided tag', () => { 12 | const wrapper = mount(); 13 | expect(wrapper.children().length).toEqual(1); 14 | expect(wrapper.find('div').length).toEqual(0); 15 | expect(wrapper.find('p').length).toEqual(1); 16 | }); 17 | 18 | it('should provide default tabIndex for focusing', () => { 19 | const wrapper = mount(); 20 | expect(wrapper.children().length).toEqual(1); 21 | expect(wrapper.find('div').prop('tabIndex')).toEqual(0); 22 | }); 23 | 24 | it('should render using tabIndex as per prop', () => { 25 | const wrapper = mount(); 26 | expect(wrapper.children().length).toEqual(1); 27 | expect(wrapper.find('div').prop('tabIndex')).toEqual(45); 28 | }); 29 | 30 | it('should render SelfFocus with additional classnames', () => { 31 | const wrapper = mount(); 32 | expect(wrapper.find('div').hasClass('class-name1')).toBe(true); 33 | expect(wrapper.find('div').hasClass('class-name2')).toBe(true); 34 | }); 35 | 36 | it('should render children of node', () => { 37 | const wrapper = mount( 38 | 39 |

some nest p

40 |
41 | ); 42 | expect(wrapper.children().length).toEqual(1); 43 | expect(wrapper.find('div').children().length).toBe(1); 44 | expect(wrapper.find('div p').length).toBe(1); 45 | expect(wrapper.find('div p').text()).toBe('some nest p'); 46 | }); 47 | 48 | it('should render using other props in the root node', () => { 49 | const wrapper = mount(); 50 | expect(wrapper.children().length).toEqual(1); 51 | expect(wrapper.find('div').prop('someprop1')).toEqual(1); 52 | expect(wrapper.find('div').prop('someprop2')).toEqual('2'); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /tests/setupTests.js: -------------------------------------------------------------------------------- 1 | import Enzyme, { shallow, render, mount } from 'enzyme'; 2 | import Adapter from 'enzyme-adapter-react-16'; 3 | // React 16 Enzyme adapter 4 | Enzyme.configure({ adapter: new Adapter() }); 5 | 6 | // Make Enzyme functions available in all test files without importing 7 | global.shallow = shallow; 8 | global.render = render; 9 | global.mount = mount; 10 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | module.exports = { 3 | mode: 'production', 4 | entry: './src/index.js', 5 | output: { 6 | path: path.resolve(__dirname, 'dist'), 7 | filename: 'index.js', 8 | libraryTarget: 'commonjs2' 9 | }, 10 | module: { 11 | rules: [ 12 | { 13 | test: /\.js$/, 14 | include: path.resolve(__dirname, 'src'), 15 | exclude: /(node_modules|bower_components|build)/, 16 | use: { 17 | loader: 'babel-loader', 18 | options: { 19 | presets: ['env'] 20 | } 21 | } 22 | } 23 | ] 24 | }, 25 | externals: { 26 | react: 'commonjs react' // this line is just to use the React dependency of our parent-testing-project instead of using our own React. 27 | } 28 | }; 29 | --------------------------------------------------------------------------------