Repository: enzymejs/enzyme Branch: master Commit: 61e1b47c4bdc Files: 403 Total size: 1.3 MB Directory structure: gitextract_ky2tl6yi/ ├── .babelrc ├── .eslintrc ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── Bug_report.md │ │ └── Feature_request.md │ └── workflows/ │ ├── node-pretest.yml │ ├── node.yml │ ├── rebase.yml │ └── require-allow-edits.yml ├── .gitignore ├── .lgtm ├── .npmrc ├── .nycrc ├── CHANGELOG.md ├── CONTRIBUTING.md ├── INTHEWILD.md ├── LICENSE.md ├── MAINTAINERS ├── README.md ├── SUMMARY.md ├── book.json ├── docs/ │ ├── GLOSSARY.md │ ├── api/ │ │ ├── README.md │ │ ├── ReactWrapper/ │ │ │ ├── at.md │ │ │ ├── childAt.md │ │ │ ├── children.md │ │ │ ├── closest.md │ │ │ ├── contains.md │ │ │ ├── containsAllMatchingElements.md │ │ │ ├── containsAnyMatchingElements.md │ │ │ ├── containsMatchingElement.md │ │ │ ├── context.md │ │ │ ├── debug.md │ │ │ ├── detach.md │ │ │ ├── equals.md │ │ │ ├── every.md │ │ │ ├── everyWhere.md │ │ │ ├── exists.md │ │ │ ├── filter.md │ │ │ ├── filterWhere.md │ │ │ ├── find.md │ │ │ ├── findWhere.md │ │ │ ├── first.md │ │ │ ├── forEach.md │ │ │ ├── get.md │ │ │ ├── getDOMNode.md │ │ │ ├── getElement.md │ │ │ ├── getElements.md │ │ │ ├── getWrappingComponent.md │ │ │ ├── hasClass.md │ │ │ ├── hostNodes.md │ │ │ ├── html.md │ │ │ ├── instance.md │ │ │ ├── invoke.md │ │ │ ├── is.md │ │ │ ├── isEmpty.md │ │ │ ├── isEmptyRender.md │ │ │ ├── key.md │ │ │ ├── last.md │ │ │ ├── length.md │ │ │ ├── map.md │ │ │ ├── matchesElement.md │ │ │ ├── mount.md │ │ │ ├── name.md │ │ │ ├── not.md │ │ │ ├── parent.md │ │ │ ├── parents.md │ │ │ ├── prop.md │ │ │ ├── props.md │ │ │ ├── reduce.md │ │ │ ├── reduceRight.md │ │ │ ├── ref.md │ │ │ ├── render.md │ │ │ ├── renderProp.md │ │ │ ├── setContext.md │ │ │ ├── setProps.md │ │ │ ├── setState.md │ │ │ ├── simulate.md │ │ │ ├── simulateError.md │ │ │ ├── slice.md │ │ │ ├── some.md │ │ │ ├── someWhere.md │ │ │ ├── state.md │ │ │ ├── tap.md │ │ │ ├── text.md │ │ │ ├── type.md │ │ │ ├── unmount.md │ │ │ └── update.md │ │ ├── ShallowWrapper/ │ │ │ ├── at.md │ │ │ ├── childAt.md │ │ │ ├── children.md │ │ │ ├── closest.md │ │ │ ├── contains.md │ │ │ ├── containsAllMatchingElements.md │ │ │ ├── containsAnyMatchingElements.md │ │ │ ├── containsMatchingElement.md │ │ │ ├── context.md │ │ │ ├── debug.md │ │ │ ├── dive.md │ │ │ ├── equals.md │ │ │ ├── every.md │ │ │ ├── everyWhere.md │ │ │ ├── exists.md │ │ │ ├── filter.md │ │ │ ├── filterWhere.md │ │ │ ├── find.md │ │ │ ├── findWhere.md │ │ │ ├── first.md │ │ │ ├── forEach.md │ │ │ ├── get.md │ │ │ ├── getElement.md │ │ │ ├── getElements.md │ │ │ ├── getWrappingComponent.md │ │ │ ├── hasClass.md │ │ │ ├── hostNodes.md │ │ │ ├── html.md │ │ │ ├── instance.md │ │ │ ├── invoke.md │ │ │ ├── is.md │ │ │ ├── isEmpty.md │ │ │ ├── isEmptyRender.md │ │ │ ├── key.md │ │ │ ├── last.md │ │ │ ├── length.md │ │ │ ├── map.md │ │ │ ├── matchesElement.md │ │ │ ├── name.md │ │ │ ├── not.md │ │ │ ├── parent.md │ │ │ ├── parents.md │ │ │ ├── prop.md │ │ │ ├── props.md │ │ │ ├── reduce.md │ │ │ ├── reduceRight.md │ │ │ ├── render.md │ │ │ ├── renderProp.md │ │ │ ├── setContext.md │ │ │ ├── setProps.md │ │ │ ├── setState.md │ │ │ ├── shallow.md │ │ │ ├── simulate.md │ │ │ ├── simulateError.md │ │ │ ├── slice.md │ │ │ ├── some.md │ │ │ ├── someWhere.md │ │ │ ├── state.md │ │ │ ├── tap.md │ │ │ ├── text.md │ │ │ ├── type.md │ │ │ ├── unmount.md │ │ │ └── update.md │ │ ├── mount.md │ │ ├── render.md │ │ ├── selector.md │ │ └── shallow.md │ ├── common-issues.md │ ├── future.md │ ├── guides/ │ │ ├── browserify.md │ │ ├── jest.md │ │ ├── jsdom.md │ │ ├── karma.md │ │ ├── lab.md │ │ ├── migration-from-2-to-3.md │ │ ├── mocha.md │ │ ├── react-native.md │ │ ├── systemjs.md │ │ ├── tape-ava.md │ │ └── webpack.md │ ├── guides.md │ └── installation/ │ ├── README.md │ ├── react-013.md │ ├── react-014.md │ ├── react-15.md │ └── react-16.md ├── env.js ├── install-relevant-react.sh ├── karma.conf.js ├── lerna.json ├── package.json ├── packages/ │ ├── enzyme/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── ReactWrapper.js │ │ ├── ShallowWrapper.js │ │ ├── mount.js │ │ ├── package.json │ │ ├── render.js │ │ ├── shallow.js │ │ ├── src/ │ │ │ ├── Debug.js │ │ │ ├── EnzymeAdapter.js │ │ │ ├── RSTTraversal.js │ │ │ ├── ReactWrapper.js │ │ │ ├── ShallowWrapper.js │ │ │ ├── Utils.js │ │ │ ├── configuration.js │ │ │ ├── getAdapter.js │ │ │ ├── index.js │ │ │ ├── mount.js │ │ │ ├── render.js │ │ │ ├── selectors.js │ │ │ ├── shallow.js │ │ │ └── validateAdapter.js │ │ └── withDom.js │ ├── enzyme-adapter-react-13/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── package.json │ │ └── src/ │ │ ├── ReactThirteenAdapter.js │ │ ├── ReactThirteenElementToTree.js │ │ ├── ReactThirteenMapNativeEventNames.js │ │ └── index.js │ ├── enzyme-adapter-react-14/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── package.json │ │ └── src/ │ │ ├── ReactFourteenAdapter.js │ │ └── index.js │ ├── enzyme-adapter-react-15/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── package.json │ │ └── src/ │ │ ├── ReactFifteenAdapter.js │ │ └── index.js │ ├── enzyme-adapter-react-15.4/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── package.json │ │ └── src/ │ │ ├── ReactFifteenFourAdapter.js │ │ └── index.js │ ├── enzyme-adapter-react-16/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── package.json │ │ └── src/ │ │ ├── ReactSixteenAdapter.js │ │ ├── detectFiberTags.js │ │ ├── findCurrentFiberUsingSlowPath.js │ │ └── index.js │ ├── enzyme-adapter-react-16.1/ │ │ ├── .babelrc │ │ ├── .eslintignore │ │ ├── .eslintrc │ │ ├── .npmrc │ │ ├── package.json │ │ └── src/ │ │ ├── ReactSixteenOneAdapter.js │ │ └── index.js │ ├── enzyme-adapter-react-16.2/ │ │ ├── .babelrc │ │ ├── .eslintignore │ │ ├── .eslintrc │ │ ├── .npmrc │ │ ├── package.json │ │ └── src/ │ │ ├── ReactSixteenTwoAdapter.js │ │ └── index.js │ ├── enzyme-adapter-react-16.3/ │ │ ├── .babelrc │ │ ├── .eslintignore │ │ ├── .eslintrc │ │ ├── .npmrc │ │ ├── package.json │ │ └── src/ │ │ ├── ReactSixteenThreeAdapter.js │ │ └── index.js │ ├── enzyme-adapter-react-helper/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── package.json │ │ └── src/ │ │ ├── enzyme-adapter-react-install.js │ │ ├── getAdapterForReactVersion.js │ │ ├── ifReact.js │ │ ├── index.js │ │ └── safeSFC.jsx │ ├── enzyme-adapter-utils/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── package.json │ │ └── src/ │ │ ├── RootFinder.jsx │ │ ├── Utils.js │ │ ├── createMountWrapper.jsx │ │ ├── createRenderWrapper.jsx │ │ ├── index.js │ │ └── wrapWithSimpleWrapper.jsx │ ├── enzyme-example-mocha/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── .gitignore │ │ ├── .nycrc │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── Foo.jsx │ │ │ └── Foo.spec.jsx │ │ └── test/ │ │ ├── .setup.js │ │ └── mocha.opts │ ├── enzyme-shallow-equal/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── README.md │ │ ├── package.json │ │ └── src/ │ │ └── index.js │ └── enzyme-test-suite/ │ ├── .babelrc │ ├── .eslintrc │ ├── package.json │ └── test/ │ ├── Adapter-spec.jsx │ ├── Debug-spec.jsx │ ├── RSTTraversal-spec.jsx │ ├── ReactWrapper-spec.jsx │ ├── ShallowWrapper-spec.jsx │ ├── Utils-spec.jsx │ ├── _helpers/ │ │ ├── adapter.js │ │ ├── beforeEach.js │ │ ├── describeHooks.js │ │ ├── describeLifecycles.js │ │ ├── describeMethods.js │ │ ├── getLoadedLazyComponent.js │ │ ├── index.jsx │ │ ├── react-compat.js │ │ ├── realArrowFunction.js │ │ ├── selectors.js │ │ ├── setupAdapters.js │ │ ├── untranspiledArrowFunction.js │ │ ├── untranspiledSloppyReturnThis.js │ │ └── version.js │ ├── adapter-utils-spec.jsx │ ├── enzyme-adapter-react-install-spec.js │ ├── enzyme-shallow-equal-spec.js │ ├── selector-spec.jsx │ ├── shared/ │ │ ├── hooks/ │ │ │ ├── _hook.template │ │ │ ├── custom.jsx │ │ │ ├── useCallback.jsx │ │ │ ├── useContext.jsx │ │ │ ├── useDebugValue.jsx │ │ │ ├── useEffect.jsx │ │ │ ├── useImperativeHandle.jsx │ │ │ ├── useLayoutEffect.jsx │ │ │ ├── useMemo.jsx │ │ │ ├── useReducer.jsx │ │ │ ├── useRef.jsx │ │ │ └── useState.jsx │ │ ├── lifecycles/ │ │ │ ├── componentDidCatch.jsx │ │ │ ├── componentDidMount.jsx │ │ │ ├── componentDidUpdate.jsx │ │ │ ├── componentWillUnmount.jsx │ │ │ ├── getDerivedStateFromError.jsx │ │ │ ├── getDerivedStateFromProps.jsx │ │ │ ├── getSnapshotBeforeUpdate.jsx │ │ │ └── misc.jsx │ │ └── methods/ │ │ ├── @@iterator.jsx │ │ ├── _method.template │ │ ├── at.jsx │ │ ├── childAt.jsx │ │ ├── children.jsx │ │ ├── closest.jsx │ │ ├── contains.jsx │ │ ├── containsAllMatchingElements.jsx │ │ ├── containsAnyMatchingElements.jsx │ │ ├── containsMatchingElement.jsx │ │ ├── context.jsx │ │ ├── debug.jsx │ │ ├── deprecatedInstanceProperties.jsx │ │ ├── equals.jsx │ │ ├── every.jsx │ │ ├── everyWhere.jsx │ │ ├── exists.jsx │ │ ├── filter.jsx │ │ ├── filterWhere.jsx │ │ ├── find.jsx │ │ ├── findWhere.jsx │ │ ├── first.jsx │ │ ├── flatMap.jsx │ │ ├── forEach.jsx │ │ ├── get.jsx │ │ ├── getElement.jsx │ │ ├── getElements.jsx │ │ ├── getNode.jsx │ │ ├── getNodes.jsx │ │ ├── getWrappingComponent.jsx │ │ ├── hasClass.jsx │ │ ├── hostNodes.jsx │ │ ├── html.jsx │ │ ├── instance.jsx │ │ ├── invoke.jsx │ │ ├── is.jsx │ │ ├── isEmpty.jsx │ │ ├── isEmptyRender.jsx │ │ ├── key.jsx │ │ ├── last.jsx │ │ ├── map.jsx │ │ ├── matchesElement.jsx │ │ ├── name.jsx │ │ ├── not.jsx │ │ ├── parent.jsx │ │ ├── parents.jsx │ │ ├── prop.jsx │ │ ├── props.jsx │ │ ├── reduce.jsx │ │ ├── reduceRight.jsx │ │ ├── render.jsx │ │ ├── renderProp.jsx │ │ ├── root.jsx │ │ ├── setContext.jsx │ │ ├── setProps.jsx │ │ ├── setState.jsx │ │ ├── simulate.jsx │ │ ├── simulateError.jsx │ │ ├── single.jsx │ │ ├── slice.jsx │ │ ├── some.jsx │ │ ├── someWhere.jsx │ │ ├── state.jsx │ │ ├── tap.jsx │ │ ├── text.jsx │ │ ├── unmount.jsx │ │ └── wrap.jsx │ └── staticRender-spec.jsx ├── since.js ├── tea.yaml └── test/ └── mocha.opts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .babelrc ================================================ { "presets": ["airbnb"], "plugins": [ ["transform-replace-object-assign", { "moduleSpecifier": "object.assign" }], ["add-module-exports"], ], "ignore": [ "packages/enzyme-test-suite/test/_helpers/untranspiled*", ], "sourceMaps": "both", } ================================================ FILE: .eslintrc ================================================ { "extends": "airbnb", "root": true, "env": { "node": true, }, "parser": "@babel/eslint-parser", "ignorePatterns": [ "/build", "_book", "packages/*/build/", // Temporarily copied "packages/*/LICENSE.md", "packages/enzyme/README.md", "packages/enzyme-adapter-react-*/README.md", "packages/enzyme-adapter-utils*/README.md", ], "rules": { "id-length": 0, "react/no-find-dom-node": 1, "import/first": 0, "max-len": 0, }, "overrides": [ { // things that run in older envs, without babel "files": [ "env.js", "karma.conf.js", "since.js", ], "rules": { "import/no-extraneous-dependencies": [2, { "devDependencies": true, }], "comma-dangle": [2, { "arrays": "always-multiline", "objects": "always-multiline", "imports": "always-multiline", "exports": "always-multiline", "functions": "ignore", }], "strict": [2, "safe"], "prefer-destructuring": 0, "prefer-template": 0, }, "parserOptions": { "sourceType": "script", }, }, { "files": [ "**/*.md", "**/*.md/**" ], "extends": ["plugin:markdown/recommended"], "rules": { "class-methods-use-this": 0, "import/extensions": 0, "import/no-extraneous-dependencies": 0, "import/no-unresolved": 0, "import/prefer-default-export": 0, "max-len": 0, "no-console": 0, "no-undef": 0, "no-unused-vars": 0, "react/jsx-filename-extension": 0, "react/jsx-fragments": 0, "react/jsx-no-undef": 0, "react/jsx-no-useless-fragment": 0, "react/jsx-one-expression-per-line": 0, "react/no-multi-comp": 0, "react/no-unknown-property": 0, "react/no-unused-class-component-methods": 0, "react/react-in-jsx-scope": 0, }, }, ], } ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [ljharb] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: npm/enzyme community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] ================================================ FILE: .github/ISSUE_TEMPLATE/Bug_report.md ================================================ --- name: 🐛 Bug report about: Create a report to help us improve --- Thanks for reporting an issue to us! We're glad you are using and invested in Enzyme. Before submitting, please read over our commonly reported issues to prevent duplicates! ### All common issues * [common issues](../blob/master/docs/common-issues.md) ### Notoriously common issues * [Webpack build issues](../blob/master/docs/common-issues.md#webpack-build-issues) * [Cannot find module 'react-dom/lib/ReactTestUtils'](../blob/master/docs/common-issues.md#error-cannot-find-module-react-domlibreacttestutils) * [Query Selector fails](../blob/master/docs/common-issues.md#query-selector-fails) * [Testing third party libraries](../blob/master/docs/common-issues.md#testing-third-party-libraries) If you haven't found any duplicated issues, please report it with your environment! ### Current behavior ### Expected behavior ### Your environment #### API - [ ] shallow - [ ] mount - [ ] render #### Version | library | version | ------------------- | ------- | enzyme | | react | | react-dom | | react-test-renderer | | adapter (below) | #### Adapter - [ ] enzyme-adapter-react-16 - [ ] enzyme-adapter-react-16.3 - [ ] enzyme-adapter-react-16.2 - [ ] enzyme-adapter-react-16.1 - [ ] enzyme-adapter-react-15 - [ ] enzyme-adapter-react-15.4 - [ ] enzyme-adapter-react-14 - [ ] enzyme-adapter-react-13 - [ ] enzyme-adapter-react-helper - [ ] others ( ) ================================================ FILE: .github/ISSUE_TEMPLATE/Feature_request.md ================================================ --- name: 🙏 Feature request about: Suggest an idea for this project --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. e.g. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/workflows/node-pretest.yml ================================================ name: 'Tests: pretest/posttest' on: [pull_request, push] jobs: pretest: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ljharb/actions/node/install@main with: skip-ls-check: true - run: sh install-relevant-react.sh - run: npx lerna bootstrap - run: npm run build - run: npm run pretest # posttest: # runs-on: ubuntu-latest # steps: # - uses: actions/checkout@v3 # - uses: ljharb/actions/node/install@main # - run: npm run build # - run: npm run posttest ================================================ FILE: .github/workflows/node.yml ================================================ name: 'Tests: node.js' on: [pull_request, push] jobs: build: name: 'install deps and build' runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ljharb/actions/node/install@main with: skip-ls-check: true - run: npx lerna bootstrap - run: npm run build - uses: actions/cache@v3 with: path: | packages/*/build node_modules packages/*/node_modules key: enzyme-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }} karma-matrix: needs: [build] name: 'karma tests' runs-on: ubuntu-latest continue-on-error: true strategy: fail-fast: false matrix: react: - '16' - '16.3' - '16.2' - '16.1' - '15' - '15.4' - '0.14' - '0.13' steps: - uses: actions/checkout@v3 - uses: actions/cache@v3 with: path: | packages/*/build node_modules packages/*/node_modules key: enzyme-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }} - run: sudo chmod -R a+w . - uses: ljharb/actions/node/install@main with: node-version: 'lts/*' skip-install: true after_install: '(nvm install node && REACT=${{ matrix.react }} TRAVIS=1 sh install-relevant-react.sh)' skip-ls-check: true - run: npm run test:karma -- --single-run continue-on-error: true env: CHROME_BIN: chromium-browser DISPLAY: 99.0 - run: echo 'karma tests expected to fail' tests: needs: [build] name: 'tests' runs-on: ubuntu-latest continue-on-error: ${{ matrix.continue-on-error == 'true' }} strategy: fail-fast: false matrix: node-version: - '18' - '4' react: - '16.14' - '16.13' - '16.12' - '16.11' - '16.10' - '16.9' - '16.8' - '16.7' - '16.6' - '16.5' - '16.4' - '16.3' - '16.2' - '16.1' - '16.0' - '15.5' - '15.4' - '15.3' - '15.2' - '15.1' - '15.0' - '0.14' - '0.13' include: - node-version: '16' react: '16' - node-version: '14' react: '16' - node-version: '12' react: '16' - node-version: '10' react: '16' - node-version: '8' react: '16' - node-version: '6' react: '16' - node-version: 'lts/*' react: '16.8.3' - node-version: 'lts/*' react: '16.8.5' env: RENDERER: '16.8.5' - node-version: 'lts/*' react: '16.8.5' env: RENDERER: '16.8.3' - node-version: 'lts/*' react: '16.3' env: ADAPTER: '16' - node-version: 'lts/*' react: '16.8' env: RENDERER: '16.7' - node-version: 'lts/*' react: '16.7' env: RENDERER: '16.8' - node-version: 'lts/*' react: '16.7' env: RENDERER: '16.7' steps: - uses: actions/checkout@v3 - uses: actions/cache@v3 with: path: | packages/*/build node_modules packages/*/node_modules key: enzyme-${{ github.workflow }}-${{ github.action }}-${{ github.run_id }} - run: sudo chmod -R a+w . - uses: ljharb/actions/node/install@main with: node-version: ${{ matrix.node-version || 'lts/* '}} skip-install: true after_install: '(nvm install node && sh install-relevant-react.sh)' skip-ls-check: true env: REACT: ${{ matrix.react }} - run: npm run travis - uses: codecov/codecov-action@v3 node: name: 'node + react' needs: [tests] runs-on: ubuntu-latest steps: - run: 'echo tests completed' karma: name: 'node + react + karma' needs: [karma-matrix] runs-on: ubuntu-latest steps: - run: 'echo tests completed' ================================================ FILE: .github/workflows/rebase.yml ================================================ name: Automatic Rebase on: [pull_request_target] jobs: _: name: "Automatic Rebase" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ljharb/rebase@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/require-allow-edits.yml ================================================ name: Require “Allow Edits” on: [pull_request_target] jobs: _: name: "Require “Allow Edits”" runs-on: ubuntu-latest steps: - uses: ljharb/require-allow-edits@main ================================================ FILE: .gitignore ================================================ # Logs logs *.log # Runtime data pids *.pid *.seed # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage .nyc_output # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directory # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git node_modules # Jetbrains IDEs .idea /build _book # Only apps should have lockfiles npm-shrinkwrap.json package-lock.json yarn.lock .DS_Store ._.DS_Store packages/*/build/ # Temporarily copied packages/*/LICENSE.md packages/enzyme/README.md packages/enzyme-adapter-react-*/README.md packages/enzyme-adapter-utils*/README.md .npmignore ================================================ FILE: .lgtm ================================================ approvals = 1 pattern = "(?i):shipit:|:\\+1:|LGTM" ================================================ FILE: .npmrc ================================================ package-lock=false update-notifier=false legacy-peer-deps=true ================================================ FILE: .nycrc ================================================ { "extension": [ ".js", ".jsx" ], "include": [ "*", "packages/*/*", "packages/*/src" ], "exclude": [ "packages/enzyme-test-suite", "_book", "coverage", "packages/*/node_modules" ], "require": [ ], "reporter": [ "text", "html", "json", "lcov" ], "all": false, "check-coverage": false, "statements": 100, "branches": 100, "lines": 100, "functions": 100, "sourceMap": true, "instrument": true } ================================================ FILE: CHANGELOG.md ================================================ # Change Log ## 3.11.0 ### New Stuff - `render`: handle Fiber strings and numbers (#2221) ### Fixes - `shallow`: Share child context logic between `shallow` and `dive` (#2296) - `mount`: `children`: include text nodes ($2269) - `mount`: `invoke`: use adapter’s `wrapInvoke` if present (#2158) ### Docs - `mount`/`shallow`: `closest`/`parent`: Add missing arguments description (#2264) - `mount`/`shallow`: fix pluralization of “exist” (#2262) - `shallow`/`mount`: `simulate`: added functional component example to simulate doc (#2248) - `mount`: `debug`: add missing verbose option flag (#2184) - `mount`/`shallow`: `update`: fix semantics description (#2194) - add missing backticks to linked method names (#2170) - `invoke`: Add missing backticks to end of codeblock (#2160) - `invoke`: Fix typo (#2167) - Explicit React CSS selector syntax description (#2178) ### Meta Stuff - [meta] add `funding` field - [meta] Update airbnb.io URLs to use https (#2222) - [deps] update `is-boolean-object`, `is-callable`, `is-number-object`, `is-string`, `enzyme-shallow-equal`, `array.prototype.flat`, `function.prototype.name`, `html-element-map`, `is-regex`, `object-inspect`, `object-is`, `object.entries`, `object.vales`, `raf`, `string.prototype.trim` - [dev deps] update `eslint`, `eslint-plugin-import`, `eslint-plugin-markdown`, `eslint-plugin-react`, `safe-publish-latest`, `eslint-config-airbnb`, `rimraf`, `safe-publish-latest`, `karma-firefox-launcher`, `babel-preset-airbnb`, `glob-gitignore`, `semver`, `eslint-plugin-jsx-a11y` ## 3.10.0 ### New Stuff - `shallow` add `suspenseFallback` option; support `Suspense`/`Lazy` (#1975) - `shallow`/`mount`: add `invoke(propName)(...args)` (#1856, #945) - `shallow`: Support rendering and `dive()`ing `createContext()` providers and consumers (#1966) - `mount`/`shallow`: add `getWrappingComponent` (#1960) - `Utils`: add `isCustomComponent` (#1960) - `Utils`: add `stub` argument to `spyMethod` - `EnzymeAdapter`: add `matchesElementType` (#2146) - `RSTTraversal`: add `getHTMLFromHostNodes` ### Fixes - `selectors`: unwrap `memo` elements - in both directions (#2146) - `shallow`: properly determine "should render" for `PureComponent`s (#2096) - `mount`/`shallow`: `renderProp`: improve error messages (#2070) - `mount`: `setContext`: use proper wrapper name in error message - `shallow`: `.contains()`: clean up error message - `shallow`/`mount`: `hasClass`: avoid a crash with a non-string argument (#2057) - `mount`: properly handle HTML of multiple nodes (#2052) - `shallow`: ensure that if gDSFP exists, cDU is called. (#2027) - `shallow`: Mock sCU if gDSFP defined in shallow renderer rerender (#1981) - `mount`: `.state()`: allow getting state from stateful children of a stateless root (#2043) - `mount`: `.text()`: properly recurse through fragments and arrays (#2028) ### Refactors - `ReactWrapper`/`ShallowWrapper`: ensure calling an adapter‘s nodeToElement preserves the receiver - `mount`: use `getHTMLFromHostNodes` ### Docs - explain why need to re-call .find() after update (#2140) - `shallow`: fix childAt (#2134) - Update v2 -> v3 migration guide re props after a stage change (#1300) - `debug`: Added documentation for `verbose` flag (#2104) - Add on the fly JSDOM include example (#2072) - `reduce`/`reduceRight`: fix example code (#2066, #2065, #2064) - update `simulateError` with `getDerivedStateFromError` (#2036) - `shallow`: `.hasClass`: fix use of `mount` - add link to Cheerio API and another example (#756) - `jest`: Update deprecated jest config key (#2024) ## 3.9.0 ### New Stuff - `shallow`: `isEmptyRender`: allow on multiple elements (#1924) - `mount`: support `:focus` selector (#1965) - `shallow`: Support `getChildContext()` (#1971) - `shallow`/`mount`: `.find`: find HTML elements by their constructor (#1933) - `shallow`/`mount`: `selectors`: support universal selector (#1945) - `mount`/`shallow`: add regex support to `.hasClass` (#1987) ### Fixes - `mount`/`shallow`: `.text`/`.html`: handle an array of nodes properly (#2001) - `shallow`: `.setProps()`: only call cDU once (#2007) - `mount`: ensure `findWhere` doesn‘t abort early on an empty string (#1995) - `mount`: `findWhere`: avoid passing empty wrappers to predicate - `mount`: `text()` via `findWhere`: return the string for a wrapper around a string - `mount`/`shallow`: Fix .exists not accepting any EnzymeSelector (#1934) - `mount`: Recursive `isEmptyRender` (#1924) - `mount`: `setState`: allow setting state on a class child of an SFC root ### Documentation - [jest] update Jest to setupFilesAfterEnv (#2015) - [jest] Change deprecated `setupTestFrameworkScriptFile` to `setupFilesAfterEnv` (#2013) - `mount`: `setState`: note that you can now call it on "not the root" (#2010) - general improvements (#1947) - Fix typos (#1992) - Added missing pages: `isEmptyRender`, `renderProp`, `equals`, SystemJS guide (#1984, #1985) - Fix link to .shallow() (#1951) - update jsdoc to use "EnzymeSelector" where applicable ### Meta Stuff - add "directory" field to package.json ## 3.8.0 ### New Stuff - `shallow`/`mount`: add `renderProp` (#1863, #1891) ### Fixes - `shallow`/`mount`: improve error message for "single node" assertion (#1904) - `shallow`: shallow compare, not deep compare, state and props to determine rerendering (#1915) ### Documentation - `shallow`: `dive`: add a note about throwing an error (#1905) - `selectors: update re `displayName` (#1932) - `shallow`: `get`: fixed wrong `props()` usage (#1921) - `shallow`: `html`: shallow renders full tree (#1912) - Updated broken link for “.hostNodes()” in migration guide from enzyme 2 to 3 (#1909) - Add tape example project link (#1898) - `prop`: fix typo (#1883) - Document full support for attribute selectors (#1881) - Documentation update for testing React Native with jsdom (#1873) - Update JSDOM docs to include {request|cancel}AnimationFrame polyfills (#1867) - `mount`: `ref`: use correct type (#1865) ## 3.7.0 ### New Stuff - `mount`: `.state()`/`.setState()`: allow calling on children ([#1802](https://github.com/enzymejs/enzyme/pull/1802), @ljharb) - `configuration`: add `reset` ([commit](https://github.com/enzymejs/enzyme/commit/d91d95b8da8900c8f4b7090d2256422a82398ca9)) ### Fixes - `makeOptions`: ensure that config-level `attachTo`/`hydrateIn` are inherited into wrapper options ([#1836](https://github.com/enzymejs/enzyme/issues/1836), @ljharb) - `shallow`/`Utils`: call into adapter’s `isCustomComponentElement` if present ([#1832](https://github.com/enzymejs/enzyme/pull/1832), @SinHouse) - `shallow`/`mount`: throw an explicit error when state is null/undefined ([commit](https://github.com/enzymejs/enzyme/commit/9ea33d7667a93885d6f1d6e12b0c2661d6d47cd1)) - freeze `ROOT_NODES` for child wrappers ([#1811](https://github.com/enzymejs/enzyme/pull/1811), @jgzuke) - `shallow`: `.parents`: ensure that one `.find` call does not affect another ([#1781](https://github.com/enzymejs/enzyme/pull/1781), @ljharb) - `mount`: update after `simulateError` ([#1812](https://github.com/enzymejs/enzyme/pull/1812), @jgzuke) ### Refactors - `mount`/`shallow`: `getElement`: use `this.single` ([commit](https://github.com/enzymejs/enzyme/commit/6b63db3b002a419076c82d34554916400ef392fa)) ## 3.6.0 ### New Stuff - `shallow`/`mount`: add `simulateError` ([#1797](https://github.com/enzymejs/enzyme/pull/1797), @ljharb) ## 3.5.1 ### Fixes - `shallow`/`mount`: `containsMatchingElement`: trim whitespace ([commit](https://github.com/enzymejs/enzyme/commit/171e952), [#636](https://github.com/enzymejs/enzyme/issues/636)) - `debug`: inspect objects instead of showing them as `` ([commit](https://github.com/enzymejs/enzyme/commit/a7b6e78)) ### Documentation - `mount`: `ref`: Update docs to be consistent with v3 ([#1242](https://github.com/enzymejs/enzyme/pull/1242), @adam-golab) ### Refactors - `shallow`/`mount`: make tests and method ordering more consistent ([commit](https://github.com/enzymejs/enzyme/commit/d0fccaf)) - RSTTraversal: remove unnecessary `adapter` truthiness check ([commit](https://github.com/enzymejs/enzyme/commit/394a327)) ## 3.5.0 ### New Stuff - Add forwardRef support ([#1592](https://github.com/enzymejs/enzyme/pull/1592), @jquense) - Add Portal support ([#1760](https://github.com/enzymejs/enzyme/pull/1760), [#1761](https://github.com/enzymejs/enzyme/pull/1760), [#1772](https://github.com/enzymejs/enzyme/pull/1772), [#1774](https://github.com/enzymejs/enzyme/pull/1774), @jgzuke) - Add pointer events support ([#1753](https://github.com/enzymejs/enzyme/pull/1753), @ljharb) ### Fixes - preemptively fix compat with React v16.4.3 ([#1790](https://github.com/enzymejs/enzyme/pull/1790), [#1778](https://github.com/enzymejs/enzyme/pull/1778), @gaearon, @aweary) - `shallow`: prevent rerenders with PureComponents ([#1786](https://github.com/enzymejs/enzyme/pull/1786), @koba04) - `shallow`: skip updates when nextState is `null` or `undefined` ([#1785](https://github.com/enzymejs/enzyme/pull/1785), @koba04) - `shallow`: `setState` after `setProps` calls `componentWillReceiveProps` ([#1779](https://github.com/enzymejs/enzyme/pull/1779), @peanutenthusiast) - `mount`/`shallow`: be stricter on the wrapper’s setState/setProps callback ([commit](https://github.com/enzymejs/enzyme/commit/ff11d2219da575d09ca8edfa19df42b8f78b506f)) - `shallow`/`mount`: improve error message when wrapping invalid elements ([#1759](https://github.com/enzymejs/enzyme/pull/1759), @jgzuke) ### Refactors - remove most uses of lodash ([commit](https://github.com/enzymejs/enzyme/commit/89b39b6f1c59aa771f4452a27b159f7aa2616e84)) ### Meta Stuff - ensure a license and readme is present in all packages when published ## 3.4.4 ### Fixes - @koba04: `shallow`: fix unexpected call to componentDidMount ([#1768](https://github.com/enzymejs/enzyme/pull/1768)) ## 3.4.3 ### Fixes - @ljharb/@koba04: `shallow`: `.setState()`: stub out `setState` on non-root code paths as well ([#1763](https://github.com/enzymejs/enzyme/pull/1763)) - @ljharb: `shallow`/`mount`: restore fallback when adapter lacks `invokeSetStateCallback` ([commit](https://github.com/enzymejs/enzyme/commit/093b2edb98d3abfe6b61d800503e04aac08e7496)) - @ljharb: `mount`: `setState`: invoke callback with the proper receiver ([commit](https://github.com/enzymejs/enzyme/commit/ec3beef3ba86c4352fe6e9ab2848b3b4f61ac1da)) - @ljharb: `mount`: `state` and `setState` should throw an explicit error message when called on an SFC ([commit](https://github.com/enzymejs/enzyme/commit/8feee5a89e9091636e9ec0ec3814d287ced20136)) ## 3.4.2 ### Fixes - @koba04: `shallow`: call cDU when an instance calls setState ([#1742](https://github.com/enzymejs/enzyme/pull/1742)) - @ReactiveRaven: `selectors`: fix descendant selector ([#1680](https://github.com/enzymejs/enzyme/pull/1680)) ## 3.4.1 ### Fixes - @ljharb: `shallow`: `setProps`: merge instead of replace props ([commit](https://github.com/enzymejs/enzyme/commit/9b4d0276f57e54be06aca6c3636120b3c4053310)) ### Documentation - @koba04: Fix an adapter table style in README.md and a migration guide ([#1734](https://github.com/enzymejs/enzyme/pull/1734)) ## 3.4.0 ### New Stuff - @madicap: `shallow`/`mount`: account for React.Fragment nodes ([#1733](https://github.com/enzymejs/enzyme/pull/1733)) - @jquense: Debug: `debugNode` now returns `[function]` for function children ([commit](https://github.com/enzymejs/enzyme/commit/9745de0bf25e826186be07e7846f4ecd7c685592)) - @ljharb: `mount`: add `hydrateIn` option ([#1707](https://github.com/enzymejs/enzyme/pull/1707)) - @ljharb: `shallow`: add “lifecycles” adapter option ([#1696](https://github.com/enzymejs/enzyme/pull/1696)) - @krawaller: `shallow`/`mount`: allow `.exists()` to take an optional selector ([#1695](https://github.com/enzymejs/enzyme/pull/1695)) - @koba04: `shallow`: Add getSnapshotBeforeUpdate support ([#1657](https://github.com/enzymejs/enzyme/pull/1657)) - @jquense: `shallow`/`mount`: Add support for some pseudo selectors ([#1537](https://github.com/enzymejs/enzyme/pull/1537)) - @blainekasten: `debug`: Implement verbose debug output ([#1547](https://github.com/enzymejs/enzyme/pull/1547)) - @jquense/@ljharb: `Debug`: `typeName` now calls the adapter’s `displayNameOfNode` if available ([#1701](https://github.com/enzymejs/enzyme/pull/1701)) - @jquense/@ljharb: `mount`/`shallow`: `.name()`: call into adapter’s `displayNameOfNode`, if present ([#1701](https://github.com/enzymejs/enzyme/pull/1701)) - @jquense/@ljharb: `Utils`: `nodeHasType`: call into adapter’s `displayNameOfNode`, if present ([#1701](https://github.com/enzymejs/enzyme/pull/1701)) - @jquense/@ljharb: `selectors`: `buildPredicate`: call into adapter’s `isValidElementType`, if present ([#1701](https://github.com/enzymejs/enzyme/pull/1701)) - @emuraton/@ljharb: `shallow`: `setProps()`: Add callback argument ([#1721](https://github.com/enzymejs/enzyme/pull/1721)) - @ljharb: `mount`: add `.equals()` ([commit](https://github.com/enzymejs/enzyme/commit/dcc8ab10fde06a963364f6cc79b89aa967d9bef2)) - @madicap: Extract `getAdapter` from `Utils` into its own file ([#1732](https://github.com/enzymejs/enzyme/pull/1732)) ### Fixes - @ljharb: `shallow`/`mount`: `matchesElement`/`containsMatchingElement`: get adapter with options ([commit](https://github.com/enzymejs/enzyme/commit/e954e4610d1ad89ae94b8f7c7baa8835cd331662)) - @ljharb: `RSTTraversal`: remove `nodeHasProperty` export; broken since #1157 ([commit](https://github.com/enzymejs/enzyme/commit/edabb1b6b4648fb6469da43feb1d15c1b55666f7)) - @ljharb/@KordonDev: `shallow`: `.at()`: return an empty wrapper when an index does not exist ([#1478](https://github.com/enzymejs/enzyme/pull/1478)) - @ljharb: `shallow`: `.equals()`: flatten children when comparing ([commit](https://github.com/enzymejs/enzyme/commit/18de4ed2e68c25f9fff9983d996b024704183801)) - @ljharb: `mount`/`shallow`: do not dedupe in flatMap ([commit](https://github.com/enzymejs/enzyme/commit/72341740e1e650b16ca2e377fa4e3e144b35a558)) - @ljharb: `shallow`: `.closest()`: ensure an empty wrapper is returned for no match ([commit](https://github.com/enzymejs/enzyme/commit/ce1e1132d080948265567e88417dface9c0c45e7)) - @krawaller: `selectors`: make general sibling not throw on root ([#1698](https://github.com/enzymejs/enzyme/pull/1698)) - @ljharb/@angelikatyborska : `mount`: `text()`: null nodes return null ([#1582](https://github.com/enzymejs/enzyme/pull/1582)) - @ljharb: `shallow`: `simulate`: ensure it returns itself ([commit](https://github.com/enzymejs/enzyme/commit/1c2c58b4e554f3b0c5f862f8de79f15a62bef5cf)) - @koba04: `shallow`: ShallowWrapper calls update() automatically ([#1499](https://github.com/enzymejs/enzyme/pull/1499)) - @bdwain: `mount`/`shallow`: return null for missing keys ([#1536](https://github.com/enzymejs/enzyme/pull/1536)) - @vsiao: Fix ShallowWrapper for array-rendering components ([#1498](https://github.com/enzymejs/enzyme/pull/1498)) - @koba04: Call `setState` callback after finishing the render ([#1453](https://github.com/enzymejs/enzyme/pull/1453)) - @eddyerburgh: Convert nodes to RST nodes before comparing ([#1423](https://github.com/enzymejs/enzyme/pull/1423)) - @ljharb: improve "bad adapter" error message ([#1477](https://github.com/enzymejs/enzyme/pull/1477)) - @ljharb: `shallow`/`mount`: default iterator should be iterable ([commit](https://github.com/enzymejs/enzyme/commit/cfc5a3e47efa812f7a2c4fa5ad2b0687daacd280)) ### Refactors - @ReactiveRaven: `selectors`: fix typos; avoid reusing variable unnecessarily ([#1681](https://github.com/enzymejs/enzyme/pull/1681)) - @koba04/@ljharb: `shallow`: Use `spyMethod` to inspect the result of `shouldComponentUpdate`/`getSnapshotBeforeUpdate` ([#1192](https://github.com/enzymejs/enzyme/pull/1192)) - @ljharb: `Utils`: `configuration`: change to named exports. ([commit](https://github.com/enzymejs/enzyme/commit/d7f32617e6ea93b739f4e4c3f6228a8e382aeb06)) - @ljharb: use `array.prototype.flat` ([commit](https://github.com/enzymejs/enzyme/commit/e52a02ddac0fab0d1d93fd57d7f073f8bdc850bf)) ### Documentation - @jack-lewin: Clarify dev workflow in CONTRIBUTING.md ([#1207](https://github.com/enzymejs/enzyme/pull/1207)) - @robrichard: Provide migration instructions for `ref(refName)` ([#1470](https://github.com/enzymejs/enzyme/pull/1470)) - @DannyDelott: `shallow`/`mount`: Add callback arg to setProps header ([#1361](https://github.com/enzymejs/enzyme/pull/1361)) - @conor-cafferkey-sociomantic: `mount`: Updated docs for ReactWrapper.instance(); remove docs for v2's `getNode()`/`getNodes()` ([#1714](https://github.com/enzymejs/enzyme/pull/1714)) - @koba04: Make clearer the docs for .mount() ([#1540](https://github.com/enzymejs/enzyme/pull/1540)) - @ialexryan: Update signature of .type() in shallow.md (#1492]([https://github.com/enzymejs/enzyme/pull/1492)) ### Meta Stuff - @ljharb: ensure a license and readme is present in all packages when published - @ljharb: [meta] fix package.json scripts ## 3.3.0 ### New Stuff - @ljharb/@joeldenning: `debug`: handle boxed primitives ([#1450](https://github.com/enzymejs/enzyme/pull/1450)) ### Refactors - @eddyerburgh: Use RSTTraversal childrenOfNode in Utils ([#1381](https://github.com/enzymejs/enzyme/pull/1381)) ### Fixes - @nicoder: Fix typo in error message ([#1379](https://github.com/enzymejs/enzyme/pull/1379)) ## 3.2.0 ### New Stuff - @aweary: Support all attribute selector operators ([#1157](https://github.com/enzymejs/enzyme/pull/1157)) ### Fixes - @idanilt: Change ShallowWrapper.text() trim spaces with same behavior as ReactWrapper.text() ([#1350](https://github.com/enzymejs/enzyme/pull/1350)) ## 3.1.1 ### Fixes - @koba04: Fix to call componentDidUpdate on setState of React v16 ([#1261](https://github.com/enzymejs/enzyme/pull/1261)) ## 3.1.0 ### New Stuff - @FezVrasta: Added hostNodes method to ReactWrapper ([#1179](https://github.com/enzymejs/enzyme/pull/1179)) ### Fixes - @lelandrichardson: Add an npmignore file to all packages ([#1204](https://github.com/enzymejs/enzyme/pull/1204)) - @neoziro: Fix node resolving in React 16 adapter ([#100](https://github.com/enzymejs/enzyme/pull/100)) - @graingert: upgrade to rst-selector-parser@^2.2.2 ([#1146](https://github.com/enzymejs/enzyme/pull/1146)) ### Documentation - @lelandrichardson: Symlink readme to all packages ([#1205](https://github.com/enzymejs/enzyme/pull/1205)) - @AndersDJohnson: fix some typos ([#1165](https://github.com/enzymejs/enzyme/pull/1165)) - @dubbha: ES5 setup file correction ([#1194](https://github.com/enzymejs/enzyme/pull/1194)) - @morrowr08: updated component name being used in example ([#1180](https://github.com/enzymejs/enzyme/pull/1180)) - @apandichi: Fixing a few typos... ([#1171](https://github.com/enzymejs/enzyme/pull/1171)) - @nuc: Fix typo ([#1142](https://github.com/enzymejs/enzyme/pull/1142)) ## 3.0.0 ### Breaking Changes Enzyme has several breaking changes from v2 to v3. Please check out our [migration guide](/docs/guides/migration-from-2-to-3.md) for more info. Since there was a rewrite of the core library from v2 to v3, it is hard to categorize changes in terms of sem - @lelandrichardson: Refactor enzyme to use Adapters, initial React 16 support ([#1007](https://github.com/enzymejs/enzyme/pull/1007)) - @lelandrichardson: Make private properties more private and harder to use ([#1083](https://github.com/enzymejs/enzyme/pull/1083)) - @ljharb: [breaking] update `cheerio` to v1 ([#1093](https://github.com/enzymejs/enzyme/pull/1093)) - @aweary: Integrate with a CSS parser for selector parsing ([#1086](https://github.com/enzymejs/enzyme/pull/1086)) - @vadimdemedes: Skip undefined props when comparing nodes ([#662](https://github.com/enzymejs/enzyme/pull/662)) - @koba04: Breaking: lifecycleExperimental by default ([#1140](https://github.com/enzymejs/enzyme/pull/1140)) ### New Stuff - @lelandrichardson: Move to lerna repo structure, multiple modules ([#1074](https://github.com/enzymejs/enzyme/pull/1074)) - @lelandrichardson: Remove all React dependencies from enzyme ([#1084](https://github.com/enzymejs/enzyme/pull/1084)) - @lelandrichardson: Add public root method ([#1127](https://github.com/enzymejs/enzyme/pull/1127)) ### Fixes - @aweary: Remove isFunctionalComponent, use nodeType instead ([#1076](https://github.com/enzymejs/enzyme/pull/1076)) - @LarsHassler: props not merged when shallow rendering in lifecycleExperimental ([#1088](https://github.com/enzymejs/enzyme/pull/1088)) - @ljharb: [Fix] `mount`: do not mutate `Component.contextTypes` ([#1099](https://github.com/enzymejs/enzyme/pull/1099)) - @ljharb: [Fix] `reduce`/`reduceRight`: follow `Array#reduce` when omitting initialValue ([#673](https://github.com/enzymejs/enzyme/pull/673)) - @koba04: Fix componentDidUpdate when updating by setState on v16 ([#1133](https://github.com/enzymejs/enzyme/pull/1133)) - @koba04: Fix componentDidUpdate no longer receives prevContext on React v16 ([#1139](https://github.com/enzymejs/enzyme/pull/1139)) ### Documentation - @ghost: added sinon to mocha guide ([#1075](https://github.com/enzymejs/enzyme/pull/1075)) - @samit4me: Update to GitBook 3 ([#1039](https://github.com/enzymejs/enzyme/pull/1039)) - @therewillbecode: Removed extraneous brackets from example in readme ([#1117](https://github.com/enzymejs/enzyme/pull/1117)) - @silvenon: Add note that mount() requires cleanup ([#1043](https://github.com/enzymejs/enzyme/pull/1043)) - @lelandrichardson: Add docs reflecting v3 ([#1121](https://github.com/enzymejs/enzyme/pull/1121)) ## 2.9.1 ### Fixes - [Deps] Require uuid at least 3.0.1 ([#1001](https://github.com/enzymejs/enzyme/pull/1001)) ## 2.9.0 ### New Stuff - `mount`/`shallow`: `debug`: add `ignoreProps` option ([#960](https://github.com/enzymejs/enzyme/pull/960)) ### Fixes - `shallow`: debug: fix indentation ([#926](https://github.com/enzymejs/enzyme/pull/926)) - react-compat: Make sure dependency error reporting always work ([#929](https://github.com/enzymejs/enzyme/pull/929)) - react-compat: correct error message ([#904](https://github.com/enzymejs/enzyme/pull/904)) ### Documentation - lint our markdown ([#988](https://github.com/enzymejs/enzyme/pull/988)) - correct `nvm` install instructions (never install it with homebrew) ([#988](https://github.com/enzymejs/enzyme/pull/988)) - fix typos ([#979](https://github.com/enzymejs/enzyme/pull/979)), ([#983](https://github.com/enzymejs/enzyme/pull/983)) - Added missing isEmptyRender() docs - update jsdom guides for v10 and later ([#921](https://github.com/enzymejs/enzyme/pull/921)) ### Refactors - `shallow`/`mount`: Make all references to the wrapper `class` call into `this.wrap` - update `uuid` from v2 to v3 ([#998](https://github.com/enzymejs/enzyme/pull/998)) ## 2.8.2 ### Fixes - Loosen react-compat implicit dependency logic for React 15.4 ([#896](https://github.com/enzymejs/enzyme/pull/896)) ### Documentation - Update docs to use `prop-types` ([#894](https://github.com/enzymejs/enzyme/pull/894), [#890](https://github.com/enzymejs/enzyme/issues/890)) ## 2.8.1 ### Fixes - support React@15.5 ([#876](https://github.com/enzymejs/enzyme/pull/876)) - no longer depend on `React.createClass` ([#877](https://github.com/enzymejs/enzyme/pull/877)) - Throw for malformed compound selectors ([#868](https://github.com/enzymejs/enzyme/pull/868)) ## 2.8.0 ### New Stuff - add disableLifecycleMethods for shallow ([#789](https://github.com/enzymejs/enzyme/pull/789)) - Match children before and after interpolation ([#512](https://github.com/enzymejs/enzyme/pull/512)) - Supporting passing context to static rendering ([#429](https://github.com/enzymejs/enzyme/pull/429)) ### Fixes - Fix an issue w/ cleaning up global.document ([#855](https://github.com/enzymejs/enzyme/pull/855)) - Update props when shouldComponentUpdate returns `false` and `lifecycleExperimental` is on ([#807](https://github.com/enzymejs/enzyme/pull/807)) - Properly pass along options in `dive` ([#771](https://github.com/enzymejs/enzyme/pull/771)) ## 2.7.1 (January 22, 2017) ### Fixes - `mount`: Fix bug from ([#677](https://github.com/enzymejs/enzyme/pull/677) ([#680](https://github.com/enzymejs/enzyme/pull/680)) - `mount`: ignore text nodes in childrenOfInst ([#604](https://github.com/enzymejs/enzyme/pull/604)) ### Documentation - Update Docs for .getNode and .getNodes ([#743](https://github.com/enzymejs/enzyme/pull/743)) - Add a link for `ShallowWrapper#dive()` ([#759](https://github.com/enzymejs/enzyme/pull/759) - Fix alphabetical order of API lists ([#761](https://github.com/enzymejs/enzyme/pull/761)) ## 2.7.0 (December 21, 2016) ### New Stuff - `shallow`/`mount`: Add `.slice()` method ([#661](https://github.com/enzymejs/enzyme/pull/661)) - `mount`: implement ReactWrapper#getDOMNode ([#679](https://github.com/enzymejs/enzyme/pull/679)) - `shallow`/`mount`: Add `exists`; deprecate isEmpty() ([#722](https://github.com/enzymejs/enzyme/pull/722)) ### Fixes - `mount`: extract MountedTraversal.hasClassName from MountedTraversal.instHasClassName, which allows ReactWrapper.hasClass to bypass the !isDOMComponent(inst) call ([#677](https://github.com/enzymejs/enzyme/pull/677)) - `withDom`: Display a useful error when `withDom` fails to find "jsdom" ([#686](https://github.com/enzymejs/enzyme/pull/686)) - `mount`: ensure that `react-text` comment nodes don’t break `.find` ([#691](https://github.com/enzymejs/enzyme/pull/691)) - `mount`: `.parents()` now filters out sibling path trees ([#713](https://github.com/enzymejs/enzyme/pull/713)) ## 2.6.0 (November 9, 2016) ### New Stuff - ensure ShallowWrapper render output can't get stale ([#490](https://github.com/enzymejs/enzyme/pull/490)) ### Fixes - Use shim to detect constructor function name ([#659](https://github.com/enzymejs/enzyme/pull/659)) - `mount`/`shallow`: fix ID selectors ([#670](https://github.com/enzymejs/enzyme/pull/670)) ## 2.5.2 (November 9, 2016) ### Fixes - Use shim to detect constructor function name ([#659](https://github.com/enzymejs/enzyme/pull/659)) - `mount`/`shallow`: fix ID selectors ([#670](https://github.com/enzymejs/enzyme/pull/670)) ## 2.5.1 (October 17, 2016) ### Patches - continue to support one-argument `single` ([#632](https://github.com/enzymejs/enzyme/pull/632)) ## 2.5.0 (October 17, 2016) ### Minor Changes - pass callback on setState and setProps ([#617](https://github.com/enzymejs/enzyme/pull/617)) - Make ReactWrapper and ShallowWrapper iterable ([#594](https://github.com/enzymejs/enzyme/pull/594)) - add `.dive()` method to `shallow` ([#618](https://github.com/enzymejs/enzyme/pull/618)) ### Patches - Warn if selector contains a pseudo-class ([#591](https://github.com/enzymejs/enzyme/pull/591)) - change isCompoundSelector to not match prop selector ([#595](https://github.com/enzymejs/enzyme/pull/595)) - fixed hasClassName in case className is not a string and has toString method ([#518](https://github.com/enzymejs/enzyme/pull/518)) - Throw if some() is called on a root wrapper ([#523](https://github.com/enzymejs/enzyme/pull/523)) - Fix valid + falsy propvalues ([#563](https://github.com/enzymejs/enzyme/pull/563)) ## 2.4.2 (November 9, 2016) ### Fixes - Use shim to detect constructor function name ([#659](https://github.com/enzymejs/enzyme/pull/659)) - `mount`/`shallow`: fix ID selectors ([#670](https://github.com/enzymejs/enzyme/pull/670)) ## 2.4.1 (July 8, 2016) ### Patches - Fix backwards incompatible `shouldComponentUpdate` call ([#491](https://github.com/enzymejs/enzyme/pull/491)) ## 2.4.0 (July 7, 2016) ### Minor Changes - Support all Component Lifecycle methods in ShallowRenderer (behind an experimental flag) ([#318](https://github.com/enzymejs/enzyme/pull/318)) - Add an `isEmptyRender()` method to both `ShallowWrapper` and `ReactWrapper` ([#339](https://github.com/enzymejs/enzyme/pull/339)) - Add support for batched updates with `ShallowRender.simulate` ([#342](https://github.com/enzymejs/enzyme/pull/342)) ### Patches - Switch to using classList instead of className ([#448](https://github.com/enzymejs/enzyme/pull/448)) - fixes mount().debug() output with mixed children ([#476](https://github.com/enzymejs/enzyme/pull/476)) - Support additional characters in attribute selectors ([#412](https://github.com/enzymejs/enzyme/pull/412)) - fix id selector not working when combined with a tag selector ([#387](https://github.com/enzymejs/enzyme/pull/387)) - Support spaces in attribute selector values ([#427](https://github.com/enzymejs/enzyme/pull/427)) ## 2.3.0 (May 9, 2016) ### Minor Changes - add `.tap()` method to `ShallowWrapper` and `ReactWrapper` ([#299](https://github.com/enzymejs/enzyme/pull/299)) - add `.key()` method to `ShallowWrapper` and `ReactWrapper` ([#327](https://github.com/enzymejs/enzyme/pull/327)) - add support for descendent selectors, `>`, `~` and `+` ([#217](https://github.com/enzymejs/enzyme/pull/217)) - new `containsMatchingElement`, `containsAllMatchingElements`, and `containsAnyMatchingElements` APIs ([#362](https://github.com/enzymejs/enzyme/pull/362)) - new `.name()` method ([#335](https://github.com/enzymejs/enzyme/pull/335)) ### Patches - add `dblclick` to eventType map for simulate ([#317](https://github.com/enzymejs/enzyme/pull/317)) - fix `pathToNode` bug with child-containing children ([#296](https://github.com/enzymejs/enzyme/pull/296)) - prioritize `displayName` over `name` for consistency in `.debug()` ([#332](https://github.com/enzymejs/enzyme/pull/332)) - handle insignificant whitespace in className ([#348](https://github.com/enzymejs/enzyme/pull/348)) - fix handling of SFC components and `.instance()` ([#359](https://github.com/enzymejs/enzyme/pull/359)) - reduce false positives by using argument validation for `.contains` ([#259](https://github.com/enzymejs/enzyme/pull/259)) - fix equality algorithm so that non-renderable nodes are equivalent ([#192](https://github.com/enzymejs/enzyme/pull/192)) - add better error handling for `state`, `setState`, and `context` ([#373](https://github.com/enzymejs/enzyme/pull/373)) ## 2.2.0 (March 21, 2016) ### Minor Changes - add `options` param to `ShallowWrapper::shallow` ([#275](https://github.com/enzymejs/enzyme/pull/275)) ### Patches - make enzyme compatible with all React 15 RCs ([#272](https://github.com/enzymejs/enzyme/pull/272)) - increase coverage for Stateless Functional Components ([#267](https://github.com/enzymejs/enzyme/pull/267)) - improve context support for Stateless Functional Components ([#256](https://github.com/enzymejs/enzyme/pull/256)) - fix tree traversal for Stateless Functional Components ([#257](https://github.com/enzymejs/enzyme/pull/257)) - fix `.find` for nested Stateless Functional Components ([#274](https://github.com/enzymejs/enzyme/pull/274)) - fix `.props()` and `.debug()` methods for Stateless Functional Components ([#255](https://github.com/enzymejs/enzyme/pull/255)) - prevent falsy nodes from being counted as children ([#251](https://github.com/enzymejs/enzyme/pull/251)) ## 2.1.0 (March 10, 2016) ### Minor Changes - add support for React 15.0.0-rc.1 ([#240](https://github.com/enzymejs/enzyme/pull/240)) - add `.unmount()` method for ShallowWrapper ([#215](https://github.com/enzymejs/enzyme/pull/215)) - add direct imports for `mount`, `shallow`, and `render` ([#198](https://github.com/enzymejs/enzyme/pull/198)) - add a `.childAt(n)` shorthand method ([#187](https://github.com/enzymejs/enzyme/pull/187)) ### Patches - fix bug in .contains() for matching sub-arrays ([#226](https://github.com/enzymejs/enzyme/pull/226)) - fix bug in matching by type displayName ([#230](https://github.com/enzymejs/enzyme/pull/230)) - add more useful warnings for missing implicit dependencies ([#228](https://github.com/enzymejs/enzyme/pull/228)) - improve SFC support for `.type()` ([#196](https://github.com/enzymejs/enzyme/pull/196)) - fix null handling for `.html()` and `.render()` ([#196](https://github.com/enzymejs/enzyme/pull/196)) - moved from `underscore` to `lodash` ([#189](https://github.com/enzymejs/enzyme/pull/189)) ## 2.0.0 (February 10, 2016) ### Major Changes (breaking) - removed `describeWithDOM` utility ([#159](https://github.com/enzymejs/enzyme/pull/159)) - removed `useSinon`, `spyPrototype` and `spyLifecycle` utilities ([#159](https://github.com/enzymejs/enzyme/pull/159)) - removed `sinon` dependency ([#159](https://github.com/enzymejs/enzyme/pull/159)) - removed `jsdom` dependency ([#159](https://github.com/enzymejs/enzyme/pull/159)) ## 1.6.0 (February 10, 2016) ### Minor Changes - add option for childContextTypes of `ReactWrapper` ([#171](https://github.com/enzymejs/enzyme/pull/171)) ### Patches - Prevent null or false nodes from being passed into tree traversal ([#174](https://github.com/enzymejs/enzyme/pull/174)) - setProps no longer swallows exceptions ([#170](https://github.com/enzymejs/enzyme/pull/170)) - `.type()` and `.props()` should not fail on null now ([#162](https://github.com/enzymejs/enzyme/pull/162)) ## 1.5.0 (February 2, 2016) ### Minor Changes - Add `attachTo` option to `mount` to mount to a specific element ([#160](https://github.com/enzymejs/enzyme/pull/160)) - Add `.debug()` method to `ReactWrapper` ([#158](https://github.com/enzymejs/enzyme/pull/158)) - Add `.mount()` and `.unmount()` APIs to `ReactWrapper` ([#155](https://github.com/enzymejs/enzyme/pull/155)) - Add `.render()` method to `ReactWrapper` ([#156](https://github.com/enzymejs/enzyme/pull/156)) - Allow `.contains()` to accept an array of nodes ([#154](https://github.com/enzymejs/enzyme/pull/154)) - Add `.context()` method to `ReactWrapper` and `ShallowWrapper` ([#152](https://github.com/enzymejs/enzyme/pull/152)) ### Patches - Fixed some behavior with `.contains()` matching on strings ([#148](https://github.com/enzymejs/enzyme/pull/148)) - Fixed `.debug()`'s output for numeric children ([#149](https://github.com/enzymejs/enzyme/pull/149)) - Documentation fixes - Update versions of dependencies ## 1.4.1 (January 24, 2016) ### Patches - Upgrade to babel 6 ([#81](https://github.com/enzymejs/enzyme/pull/81)) - Fix event naming bug in ShallowWrapper ([#135](https://github.com/enzymejs/enzyme/pull/135)) - Documentation fixes ## 1.4.0 (January 21, 2016) ### Minor Changes - `describeWithDOM` enhancement ([#126](https://github.com/enzymejs/enzyme/pull/126)) - add `.equals()` method to `ShallowWrapper` ([#124](https://github.com/enzymejs/enzyme/pull/124)) - add object selector syntax ([#110](https://github.com/enzymejs/enzyme/pull/110)) ### Patches - Fixed confusing behavior of prop selector syntax ([#130](https://github.com/enzymejs/enzyme/pull/130)) - Documentation fixes ## 1.3.1 (January 15, 2016) ### Patches - Fix setProps not passing old context ([#121](https://github.com/enzymejs/enzyme/pull/121)) - Map lowercase mouse events in simulate ([#77](https://github.com/enzymejs/enzyme/pull/77)) ## 1.3.0 (January 13, 2016) ### Minor Changes - Added `.html()` method to `ReactWrapper` ([#71](https://github.com/enzymejs/enzyme/pull/71)) - Support property selector (i.e. `[prop="foo"]`) ([#70](https://github.com/enzymejs/enzyme/pull/70)) - jsdom dependency now allows a range of supported versions ([#95](https://github.com/enzymejs/enzyme/pull/95)) ### Patches - Normalized `setProps()` behavior between `mount`/`shallow` to merge props ([#103](https://github.com/enzymejs/enzyme/pull/103)) - Exclude `_book` from published package ([#85](https://github.com/enzymejs/enzyme/pull/85)) - Various documentation, tests, and style changes ## 1.2.0 (December 10, 2015) ### Minor Changes - Support for context ([#62](https://github.com/enzymejs/enzyme/pull/62)) ### Patches - `nodeHasId` fix for some 0.14 corner cases ([#65](https://github.com/enzymejs/enzyme/pull/65)) ## 1.1.0 (December 7, 2015) ### Minor Changes - Support for Stateless Functional Components ([#53](https://github.com/enzymejs/enzyme/pull/53)) ### Patches - Tweak `describeWithDOM` messaging ([#48](https://github.com/enzymejs/enzyme/pull/48)) - Documentation Fixes ## 1.0.0 (December 3, 2015) - Official Release! ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing Guide Contributions are welcome and are greatly appreciated! Every little bit helps, and credit will always be given. ## Setting up your environment After forking enzyme to your own github org, do the following steps to get started: ```bash # clone your fork to your local machine git clone https://github.com/enzymejs/enzyme.git # step into local repo cd enzyme # install dependencies (use `react 13` if you want to use React 0.13) npm install # install react version # accepts `13` for v0.13, `14` for v0.14, and for versions 15+, # accepts either a major (`15`, `16`) or a minor (`15.4`, `16.8`) npm run react 16 ``` ### Switching between React 16, React 15, React 0.14 and React 0.13 ```bash # switch to React 0.13 npm run react 13 ``` ```bash # switch to React 0.14 npm run react 14 ``` ```bash # switch to React 15 npm run react 15 ``` ```bash # switch to React 16 npm run react 16 ``` Specific versions can also be specified ```bash # switch to React 16.5 npm run react 16.5 ``` ### Running Tests The test suite runs on *built* Enzyme. ```bash # build Enzyme locally before testing npm run build # run tests on whatever version of React is currently installed npm test ``` ```bash # run tests on all supported versions of React npm run test:all ``` If you are actively developing, Enzyme will always need to be built with the latest changes. For this, the recommended workflow is to have the build and tests watching for changes in separate terminals. This should provide you with ~realtime feedback: ```bash # build Enzyme locally upon save npm run build:watch # faster feedback for TDD npm run test:watch ``` ### Tests for functionality shared between `shallow` and `mount` Tests for a method "foo" are stored in `packages/enzyme-test-suite/test/shared/methods/foo`. The file default exports a function that receives an injected object argument, containing the following properties: - `Wrap`: e.g. `shallow`, `mount` - `WrapRendered`: this abstracts around the differences between `shallow` and `mount` - e.g., that the root of a shallow wrapper around `Foo` is what `Foo` *renders*, where the root of a mount wrapper around `Foo` is `Foo` itself. Thus, this function produces a wrapper around what `Foo` renders, regardless of the `Wrap` method used. - `Wrapper`: e.g. `ShallowWrapper`, `ReactWrapper` - `WrapperName`: e.g. `"ShallowWrapper"`, `"ReactWrapper"` - `isShallow`: true if `shallow`. note: needing to use this is a code smell, please avoid. - `isMount`: true if `mount`. note: needing to use this is a code smell, please avoid. - `makeDOMElement`: in `mount`, makes a real DOM element; in `shallow`, makes a mock object. These tests are ran via an explicit list in a `describeMethods` call in the ReactWrapper and ShallowWrapper test files. If you add a new test file for a shared method, you'll need to add its name to both calls. ### Style & Linting This codebase adheres to the [Airbnb Styleguide](https://github.com/airbnb/javascript) and is enforced using [ESLint](https://eslint.org). As with the test suite, the linter will not fully pass unless it is running on *built* Enzyme. This is because the ESLint `import/*` rules rely on finding the target files in the filesystem (which won't be there unless they've been built). It is recommended that you install an ESLint plugin for your editor of choice when working on this codebase, however you can always check to see if the source code is compliant by running: ```bash # build Enzyme locally before linting npm run build npm run lint ``` ### Publishing Enzyme uses [lerna](https://github.com/lerna/lerna) to structure its repo, and has multiple packages to publish out of this one repo. We use lerna's "independent" mode, which means that the versioning of each package in the repo is versioned independently. We are waiting on [this issue](https://github.com/lerna/lerna/issues/955) to be fixed, so that `peerDependencies` do not get updated with patch updates. Until this issue is fixed, we will publish each package manually instead of with `lerna publish`. In order to do this, we will: For enzyme: ```bash # ... update version in enzyme/package.json, make changes to CHANGELOG, etc. cd packages/enzyme git commit -m v{version} git tag -a -m v{version} git push --follow-tags npm publish ``` For other packages ```bash # ... update version in {package}/package.json, make changes to CHANGELOG, etc. cd packages/{package} git commit -m "{package}: v{version}" git tag -a -m "{package}: v{version}" git push --follow-tags npm publish ``` Once we are able to use `lerna publish`, the process will be as follows: Lerna by default will only publish packages that have changed since the last release. It will also create a tagged commit for each release. To publish, run: ```bash lerna publish -m "{tag name}" ``` The tag name is determined by the `-m` CLI option. If `enzyme` is one of the packages that has updates, we default to just using that version as the tag name. For instance, when publishing `enzyme@3.1.1` and `enzyme-adapter-react-16@1.2.3` we would run: ```bash lerna publish -m "v3.1.1" ``` If `enzyme` is *not* one of the packages being updated, use the other package's name and the version: ```bash lerna publish -m "enzyme-adapter-react-16: v1.2.3" ``` The `lerna publish` command will present interactive prompts asking which version to use for each package independently. Just choose whichever ### Building Docs Building the docs locally is extremely simple. First execute the following command: ```bash npm run docs:watch ``` After this, you can open up your browser to the specified port (usually http://localhost:4000 ) The browser will automatically refresh when there are changes to any of the source files. ## Pull Request Guidelines Before you submit a pull request from your forked repo, check that it meets these guidelines: 1. If the pull request fixes a bug, it should include tests that fail without the changes, and pass with them. 1. If the pull request adds functionality, the docs should be updated as part of the same PR. 1. The pull request should work for React 15, React 0.14 and React 0.13. The CI server should run the tests in all versions automatically when you push the PR, but if you'd like to check locally, you can do so (see above). 1. Please rebase and resolve all conflicts before submitting. ================================================ FILE: INTHEWILD.md ================================================ Please use [pull requests](https://github.com/enzymejs/enzyme/pull/new/master) to add your organization and/or project to this document! Organizations ---------- - [Airbnb](https://github.com/airbnb) - [Cerner](https://github.com/cerner) - [OpenGov](https://github.com/opengov) - [Pinterest](https://github.com/pinterest) - [Product Hunt](https://github.com/producthunt) - [Walmart Labs](https://github.com/walmartlabs) - [Hudl](http://hudl.github.io/) - [NET-A-PORTER](https://github.com/NET-A-PORTER) - [Rangle.io](https://github.com/rangle) - [GoDaddy](https://github.com/godaddy) - [Airware](https://github.com/airware) - [Flatiron School](https://github.com/flatiron-labs) - [Outreach.io](https://github.com/getoutreach) - [crowdSPRING](https://crowdspring.com) - [nteract](https://nteract.io) - [Brave](https://brave.com) - [Simple](https://github.com/simplefinance) - [Grab](https://github.com/grab) - [Megalytic](https://megalytic.com/) - [Chroma](https://www.chromatic.com) - [Mavens](https://github.com/mavens) - [Cucumber](https://cucumber.io) - [Genoa Telepsychiatry](https://genoatelepsychiatry.com) - [IBM X-Force Exchange](https://exchange.xforce.ibmcloud.com) - [Zendesk](https://zendesk.com/) - [idealo](https://www.idealo.de/) - [LendingHome](https://www.lendinghome.com) - [Diffia](https://diffia.com) - [MinuteMedia](https://www.minutemedia.com) - [Webex Teams](https://www.webex.com/team-collaboration.html) - [reformma](https://www.reformma.com) Projects ---------- - [Rheostat](https://github.com/airbnb/rheostat) - [React Boilerplate](https://github.com/mxstbr/react-boilerplate/tree/v3.0.0) - [Reactstrap](https://github.com/reactstrap/reactstrap) - [Recompose](https://github.com/acdlite/recompose) - [Reapop](https://github.com/LouisBarranqueiro/reapop) - [React Dates](https://github.com/airbnb/react-dates) - [nteract notebook](https://github.com/nteract/nteract) ================================================ FILE: LICENSE.md ================================================ The MIT License (MIT) Copyright (c) 2015 Airbnb, Inc. and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: MAINTAINERS ================================================ ljharb lelandrichardson blainekasten Aweary nfcampos ================================================ FILE: README.md ================================================ Enzyme ======= [![Join the chat at https://gitter.im/enzymejs/enzyme](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/enzymejs/enzyme?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![npm Version](https://img.shields.io/npm/v/enzyme.svg)](https://www.npmjs.com/package/enzyme) [![License](https://img.shields.io/npm/l/enzyme.svg)](https://github.com/enzymejs/enzyme/blob/master/LICENSE.md) [![Build Status](https://travis-ci.org/enzymejs/enzyme.svg)](https://travis-ci.org/enzymejs/enzyme) [![Coverage Status](https://codecov.io/gh/enzymejs/enzyme/branch/master/graph/badge.svg)](https://codecov.io/gh/enzymejs/enzyme/branch/master) Enzyme is a JavaScript Testing utility for React that makes it easier to test your React Components' output. You can also manipulate, traverse, and in some ways simulate runtime given the output. Enzyme's API is meant to be intuitive and flexible by mimicking jQuery's API for DOM manipulation and traversal. Upgrading from Enzyme 2.x or React < 16 =========== Are you here to check whether or not Enzyme is compatible with React 16? Are you currently using Enzyme 2.x? Great! Check out our [migration guide](/docs/guides/migration-from-2-to-3.md) for help moving on to Enzyme v3 where React 16 is supported. ### [Installation](/docs/installation/README.md) To get started with enzyme, you can simply install it via npm. You will need to install enzyme along with an Adapter corresponding to the version of react (or other UI Component library) you are using. For instance, if you are using enzyme with React 16, you can run: ```bash npm i --save-dev enzyme enzyme-adapter-react-16 ``` Each adapter may have additional peer dependencies which you will need to install as well. For instance, `enzyme-adapter-react-16` has peer dependencies on `react` and `react-dom`. At the moment, Enzyme has adapters that provide compatibility with `React 16.x`, `React 15.x`, `React 0.14.x` and `React 0.13.x`. The following adapters are officially provided by enzyme, and have the following compatibility with React: | Enzyme Adapter Package | React semver compatibility | | --- | --- | | `enzyme-adapter-react-16` | `^16.4.0-0` | | `enzyme-adapter-react-16.3` | `~16.3.0-0` | | `enzyme-adapter-react-16.2` | `~16.2` | | `enzyme-adapter-react-16.1` | ~16.0.0-0 || ~16.1 | | `enzyme-adapter-react-15` | `^15.5.0` | | `enzyme-adapter-react-15.4` | `15.0.0-0 - 15.4.x` | | `enzyme-adapter-react-14` | `^0.14.0` | | `enzyme-adapter-react-13` | `^0.13.0` | Finally, you need to configure enzyme to use the adapter you want it to use. To do this, you can use the top level `configure(...)` API. ```js import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({ adapter: new Adapter() }); ``` 3rd Party Adapters ============= It is possible for the community to create additional (non-official) adapters that will make enzyme work with other libraries. If you have made one and it's not included in the list below, feel free to make a PR to this README and add a link to it! The known 3rd party adapters are: | Adapter Package | For Library | Status | | --- | --- | --- | | [`enzyme-adapter-preact-pure`](https://github.com/preactjs/enzyme-adapter-preact-pure) | [`preact`](https://github.com/developit/preact) | (stable) | |[`enzyme-adapter-inferno`](https://github.com/bbc/enzyme-adapter-inferno)|[`inferno`](https://github.com/infernojs/inferno)|(work in progress)| Running Enzyme Tests =========== Enzyme is unopinionated regarding which test runner or assertion library you use, and should be compatible with all major test runners and assertion libraries out there. The documentation and examples for enzyme use [Mocha](https://mochajs.org) and [Chai](https://chaijs.com), but you should be able to extrapolate to your framework of choice. If you are interested in using enzyme with custom assertions and convenience functions for testing your React components, you can consider using: * [`chai-enzyme`](https://github.com/producthunt/chai-enzyme) with Mocha/Chai. * [`jasmine-enzyme`](https://github.com/FormidableLabs/enzyme-matchers/tree/master/packages/jasmine-enzyme) with Jasmine. * [`jest-enzyme`](https://github.com/FormidableLabs/enzyme-matchers/tree/master/packages/jest-enzyme) with Jest. * [`should-enzyme`](https://github.com/rkotze/should-enzyme) for should.js. * [`expect-enzyme`](https://github.com/PsychoLlama/expect-enzyme) for expect. [Using Enzyme with Mocha](/docs/guides/mocha.md) [Using Enzyme with Karma](/docs/guides/karma.md) [Using Enzyme with Browserify](/docs/guides/browserify.md) [Using Enzyme with SystemJS](/docs/guides/systemjs.md) [Using Enzyme with Webpack](/docs/guides/webpack.md) [Using Enzyme with JSDOM](/docs/guides/jsdom.md) [Using Enzyme with React Native](/docs/guides/react-native.md) [Using Enzyme with Jest](/docs/guides/jest.md) [Using Enzyme with Lab](/docs/guides/lab.md) [Using Enzyme with Tape and AVA](/docs/guides/tape-ava.md) Basic Usage =========== ## [Shallow Rendering](/docs/api/shallow.md) ```javascript import React from 'react'; import { expect } from 'chai'; import { shallow } from 'enzyme'; import sinon from 'sinon'; import MyComponent from './MyComponent'; import Foo from './Foo'; describe('', () => { it('renders three components', () => { const wrapper = shallow(); expect(wrapper.find(Foo)).to.have.lengthOf(3); }); it('renders an `.icon-star`', () => { const wrapper = shallow(); expect(wrapper.find('.icon-star')).to.have.lengthOf(1); }); it('renders children when passed in', () => { const wrapper = shallow((
)); expect(wrapper.contains(
)).to.equal(true); }); it('simulates click events', () => { const onButtonClick = sinon.spy(); const wrapper = shallow(); wrapper.find('button').simulate('click'); expect(onButtonClick).to.have.property('callCount', 1); }); }); ``` Read the full [API Documentation](/docs/api/shallow.md) ## [Full DOM Rendering](/docs/api/mount.md) ```javascript import React from 'react'; import sinon from 'sinon'; import { expect } from 'chai'; import { mount } from 'enzyme'; import Foo from './Foo'; describe('', () => { it('allows us to set props', () => { const wrapper = mount(); expect(wrapper.props().bar).to.equal('baz'); wrapper.setProps({ bar: 'foo' }); expect(wrapper.props().bar).to.equal('foo'); }); it('simulates click events', () => { const onButtonClick = sinon.spy(); const wrapper = mount(( )); wrapper.find('button').simulate('click'); expect(onButtonClick).to.have.property('callCount', 1); }); it('calls componentDidMount', () => { sinon.spy(Foo.prototype, 'componentDidMount'); const wrapper = mount(); expect(Foo.prototype.componentDidMount).to.have.property('callCount', 1); Foo.prototype.componentDidMount.restore(); }); }); ``` Read the full [API Documentation](/docs/api/mount.md) ## [Static Rendered Markup](/docs/api/render.md) ```javascript import React from 'react'; import { expect } from 'chai'; import { render } from 'enzyme'; import Foo from './Foo'; describe('', () => { it('renders three `.foo-bar`s', () => { const wrapper = render(); expect(wrapper.find('.foo-bar')).to.have.lengthOf(3); }); it('renders the title', () => { const wrapper = render(); expect(wrapper.text()).to.contain('unique'); }); }); ``` Read the full [API Documentation](/docs/api/render.md) ### React Hooks support Enzyme supports [react hooks](https://reactjs.org/docs/hooks-intro.html) with some limitations in [`.shallow()`](https://enzymejs.github.io/enzyme/docs/api/shallow.html) due to upstream issues in React's shallow renderer: * `useEffect()` and `useLayoutEffect()` don't get called in the React shallow renderer. [Related issue](https://github.com/facebook/react/issues/15275) * `useCallback()` doesn't memoize callback in React shallow renderer. [Related issue](https://github.com/facebook/react/issues/15774) #### [`ReactTestUtils.act()`](https://reactjs.org/docs/test-utils.html#act) wrap If you're using React 16.8+ and `.mount()`, Enzyme will wrap apis including [`.simulate()`](https://enzymejs.github.io/enzyme/docs/api/ReactWrapper/simulate.html), [`.setProps()`](https://enzymejs.github.io/enzyme/docs/api/ReactWrapper/setProps.html), [`.setContext()`](https://enzymejs.github.io/enzyme/docs/api/ReactWrapper/setContext.html), [`.invoke()`](https://enzymejs.github.io/enzyme/docs/api/ReactWrapper/invoke.html) with [`ReactTestUtils.act()`](https://reactjs.org/docs/test-utils.html#act) so you don't need to manually wrap it. A common pattern to trigger handlers with `.act()` and assert is: ```javascript const wrapper = mount(); act(() => wrapper.prop('handler')()); wrapper.update(); expect(/* ... */); ``` We cannot wrap the result of `.prop()` (or `.props()`) with `.act()` in Enzyme internally since it will break the equality of the returned value. However, you could use `.invoke()` to simplify the code: ```javascript const wrapper = mount(); wrapper.invoke('handler')(); expect(/* ... */); ``` ### Future [Enzyme Future](/docs/future.md) ### Contributing See the [Contributors Guide](/CONTRIBUTING.md) ### In the wild Organizations and projects using `enzyme` can list themselves [here](INTHEWILD.md). ### License [MIT](/LICENSE.md) ================================================ FILE: SUMMARY.md ================================================ ## Table of Contents * [Introduction](/README.md) * [Guides](/docs/guides.md) * [Migration from 2.x to 3.x](/docs/guides/migration-from-2-to-3.md) * [Browserify](/docs/guides/browserify.md) * [SystemJS](/docs/guides/systemjs.md) * [Webpack](/docs/guides/webpack.md) * [JSDOM](/docs/guides/jsdom.md) * [Jest](/docs/guides/jest.md) * [Karma](/docs/guides/karma.md) * [Mocha](/docs/guides/mocha.md) * [React Native](/docs/guides/react-native.md) * [Lab](/docs/guides/lab.md) * [Tape and AVA](/docs/guides/tape-ava.md) * [Installation](/docs/installation/README.md) * [Working with React 16.x](/docs/installation/react-16.md) * [Working with React 15.x](/docs/installation/react-15.md) * [Working with React 0.14.x](/docs/installation/react-014.md) * [Working with React 0.13.x](/docs/installation/react-013.md) * [API Reference](/docs/api/README.md) * [Shallow Rendering](/docs/api/shallow.md) * [at(index)](/docs/api/ShallowWrapper/at.md) * [childAt()](/docs/api/ShallowWrapper/childAt.md) * [children()](/docs/api/ShallowWrapper/children.md) * [closest(selector)](/docs/api/ShallowWrapper/closest.md) * [contains(nodeOrNodes)](/docs/api/ShallowWrapper/contains.md) * [containsAllMatchingElements(nodes)](/docs/api/ShallowWrapper/containsAllMatchingElements.md) * [containsAnyMatchingElements(nodes)](/docs/api/ShallowWrapper/containsAnyMatchingElements.md) * [containsMatchingElement(node)](/docs/api/ShallowWrapper/containsMatchingElement.md) * [context([key])](/docs/api/ShallowWrapper/context.md) * [debug()](/docs/api/ShallowWrapper/debug.md) * [dive()](/docs/api/ShallowWrapper/dive.md) * [equals(node)](/docs/api/ShallowWrapper/equals.md) * [every(selector)](/docs/api/ShallowWrapper/every.md) * [everyWhere(predicate)](/docs/api/ShallowWrapper/everyWhere.md) * [exists([selector])](/docs/api/ShallowWrapper/exists.md) * [filter(selector)](/docs/api/ShallowWrapper/filter.md) * [filterWhere(predicate)](/docs/api/ShallowWrapper/filterWhere.md) * [find(selector)](/docs/api/ShallowWrapper/find.md) * [findWhere(predicate)](/docs/api/ShallowWrapper/findWhere.md) * [first()](/docs/api/ShallowWrapper/first.md) * [forEach(fn)](/docs/api/ShallowWrapper/forEach.md) * [get(index)](/docs/api/ShallowWrapper/get.md) * [getWrappingComponent()](/docs/api/ShallowWrapper/getWrappingComponent.md) * [getElement(index)](/docs/api/ShallowWrapper/getElement.md) * [getElements(index)](/docs/api/ShallowWrapper/getElements.md) * [hasClass(className)](/docs/api/ShallowWrapper/hasClass.md) * [hostNodes()](/docs/api/ShallowWrapper/hostNodes.md) * [html()](/docs/api/ShallowWrapper/html.md) * [instance()](/docs/api/ShallowWrapper/instance.md) * [invoke(propName)](/docs/api/ShallowWrapper/invoke.md) * [is(selector)](/docs/api/ShallowWrapper/is.md) * [isEmpty()](/docs/api/ShallowWrapper/isEmpty.md) * [isEmptyRender()](/docs/api/ShallowWrapper/isEmptyRender.md) * [key()](/docs/api/ShallowWrapper/key.md) * [last()](/docs/api/ShallowWrapper/last.md) * [map(fn)](/docs/api/ShallowWrapper/map.md) * [matchesElement(node)](/docs/api/ShallowWrapper/matchesElement.md) * [name()](/docs/api/ShallowWrapper/name.md) * [not(selector)](/docs/api/ShallowWrapper/not.md) * [parent()](/docs/api/ShallowWrapper/parent.md) * [parents()](/docs/api/ShallowWrapper/parents.md) * [prop(key)](/docs/api/ShallowWrapper/prop.md) * [props()](/docs/api/ShallowWrapper/props.md) * [reduce(fn[, initialValue])](/docs/api/ShallowWrapper/reduce.md) * [reduceRight(fn[, initialValue])](/docs/api/ShallowWrapper/reduceRight.md) * [render()](/docs/api/ShallowWrapper/render.md) * [renderProp(key)](/docs/api/ShallowWrapper/renderProp.md) * [setContext(context)](/docs/api/ShallowWrapper/setContext.md) * [setProps(nextProps)](/docs/api/ShallowWrapper/setProps.md) * [setState(nextState[, callback])](/docs/api/ShallowWrapper/setState.md) * [shallow([options])](/docs/api/ShallowWrapper/shallow.md) * [simulate(event[, data])](/docs/api/ShallowWrapper/simulate.md) * [simulateError(error)](/docs/api/ShallowWrapper/simulateError.md) * [slice([begin[, end]])](/docs/api/ShallowWrapper/slice.md) * [some(selector)](/docs/api/ShallowWrapper/some.md) * [someWhere(predicate)](/docs/api/ShallowWrapper/someWhere.md) * [state([key])](/docs/api/ShallowWrapper/state.md) * [tap(intercepter)](/docs/api/ShallowWrapper/tap.md) * [text()](/docs/api/ShallowWrapper/text.md) * [type()](/docs/api/ShallowWrapper/type.md) * [unmount()](/docs/api/ShallowWrapper/unmount.md) * [update()](/docs/api/ShallowWrapper/update.md) * [Full DOM Rendering](/docs/api/mount.md) * [at(index)](/docs/api/ReactWrapper/at.md) * [childAt()](/docs/api/ReactWrapper/childAt.md) * [children()](/docs/api/ReactWrapper/children.md) * [contains(nodeOrNodes)](/docs/api/ReactWrapper/contains.md) * [containsAllMatchingElements(nodes)](/docs/api/ReactWrapper/containsAllMatchingElements.md) * [containsAnyMatchingElements(nodes)](/docs/api/ReactWrapper/containsAnyMatchingElements.md) * [containsMatchingElement(node)](/docs/api/ReactWrapper/containsMatchingElement.md) * [closest(selector)](/docs/api/ReactWrapper/closest.md) * [context([key])](/docs/api/ReactWrapper/context.md) * [debug()](/docs/api/ReactWrapper/debug.md) * [detach()](/docs/api/ReactWrapper/detach.md) * [equals(node)](/docs/api/ReactWrapper/equals.md) * [every(selector)](/docs/api/ReactWrapper/every.md) * [everyWhere(predicate)](/docs/api/ReactWrapper/everyWhere.md) * [exists([selector])](/docs/api/ReactWrapper/exists.md) * [filter(selector)](/docs/api/ReactWrapper/filter.md) * [filterWhere(predicate)](/docs/api/ReactWrapper/filterWhere.md) * [find(selector)](/docs/api/ReactWrapper/find.md) * [findWhere(predicate)](/docs/api/ReactWrapper/findWhere.md) * [first()](/docs/api/ReactWrapper/first.md) * [forEach(fn)](/docs/api/ReactWrapper/forEach.md) * [get(index)](/docs/api/ReactWrapper/get.md) * [getDOMNode()](/docs/api/ReactWrapper/getDOMNode.md) * [getWrappingComponent()](/docs/api/ReactWrapper/getWrappingComponent.md) * [hasClass(className)](/docs/api/ReactWrapper/hasClass.md) * [hostNodes()](/docs/api/ReactWrapper/hostNodes.md) * [html()](/docs/api/ReactWrapper/html.md) * [instance()](/docs/api/ReactWrapper/instance.md) * [invoke(propName)](/docs/api/ReactWrapper/invoke.md) * [is(selector)](/docs/api/ReactWrapper/is.md) * [isEmpty()](/docs/api/ReactWrapper/isEmpty.md) * [isEmptyRender()](/docs/api/ReactWrapper/isEmptyRender.md) * [key()](/docs/api/ReactWrapper/key.md) * [last()](/docs/api/ReactWrapper/last.md) * [map(fn)](/docs/api/ReactWrapper/map.md) * [matchesElement(node)](/docs/api/ReactWrapper/matchesElement.md) * [mount()](/docs/api/ReactWrapper/mount.md) * [name()](/docs/api/ReactWrapper/name.md) * [not(selector)](/docs/api/ReactWrapper/not.md) * [parent()](/docs/api/ReactWrapper/parent.md) * [parents()](/docs/api/ReactWrapper/parents.md) * [prop(key)](/docs/api/ReactWrapper/prop.md) * [props()](/docs/api/ReactWrapper/props.md) * [reduce(fn[, initialValue])](/docs/api/ReactWrapper/reduce.md) * [reduceRight(fn[, initialValue])](/docs/api/ReactWrapper/reduceRight.md) * [ref(refName)](/docs/api/ReactWrapper/ref.md) * [render()](/docs/api/ReactWrapper/render.md) * [renderProp(key)](/docs/api/ReactWrapper/renderProp.md) * [setContext(context)](/docs/api/ReactWrapper/setContext.md) * [setProps(nextProps[, callback])](/docs/api/ReactWrapper/setProps.md) * [setState(nextState[, callback])](/docs/api/ReactWrapper/setState.md) * [simulate(event[, data])](/docs/api/ReactWrapper/simulate.md) * [simulateError(error)](/docs/api/ReactWrapper/simulateError.md) * [slice([begin[, end]])](/docs/api/ReactWrapper/slice.md) * [some(selector)](/docs/api/ReactWrapper/some.md) * [someWhere(predicate)](/docs/api/ReactWrapper/someWhere.md) * [state([key])](/docs/api/ReactWrapper/state.md) * [tap(intercepter)](/docs/api/ReactWrapper/tap.md) * [text()](/docs/api/ReactWrapper/text.md) * [type()](/docs/api/ReactWrapper/type.md) * [unmount()](/docs/api/ReactWrapper/unmount.md) * [update()](/docs/api/ReactWrapper/update.md) * [Static Rendering](/docs/api/render.md) * [Selectors](/docs/api/selector.md) * [Change Log](/CHANGELOG.md) * [Future](/docs/future.md) * [Contributing Guide](/CONTRIBUTING.md) ================================================ FILE: book.json ================================================ { "gitbook": "3.2.2", "title": "Enzyme", "description": "React Testing", "plugins": [ "edit-link", "github", "-search", "codeblock-disable-glossary", "collapsible-menu", "anchors" ], "pluginsConfig": { "edit-link": { "base": "https://github.com/enzymejs/enzyme/tree/master", "label": "Edit This Page" }, "github": { "url": "https://github.com/enzymejs/enzyme/" } } } ================================================ FILE: docs/GLOSSARY.md ================================================ # selector A Selector in enzyme is similar to a CSS selector, but can be a number of other things as well in order to easily specify a criteria by which you want to find nodes in an enzyme wrapper. See the [Selector page](/docs/api/selector.md) for more information. # wrapper A wrapper refers to the enzyme wrapper class that provides the API. # predicate A function that returns true or false ================================================ FILE: docs/api/README.md ================================================ # API Reference ### [Shallow Rendering](shallow.md) ```jsx import { shallow } from 'enzyme'; const wrapper = shallow(); // ... ``` ### [Full Rendering](mount.md) ```jsx import { mount } from 'enzyme'; const wrapper = mount(); // ... ``` ### [Static Rendering](render.md) ```jsx import { render } from 'enzyme'; const wrapper = render(); // ... ``` ================================================ FILE: docs/api/ReactWrapper/at.md ================================================ # `.at(index) => ReactWrapper` Returns a wrapper around the node at a given index of the current wrapper. #### Arguments 1. `index` (`Number`): A zero-based integer indicating which node to retrieve. #### Returns `ReactWrapper`: A new wrapper that wraps the retrieved node. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find(Foo).at(0).props().foo).to.equal('bar'); ``` #### Related Methods - [`.get(index) => ReactElement`](get.md) - same, but returns the React node itself, with no wrapper. - [`.first() => ReactWrapper`](first.md) - same as at(0) - [`.last() => ReactWrapper`](last.md) ================================================ FILE: docs/api/ReactWrapper/childAt.md ================================================ # `.childAt(index) => ReactWrapper` Returns a new wrapper with child at the specified index. #### Arguments 1. `index` (`number`): A zero-based integer indicating which node to retrieve. #### Returns `ReactWrapper`: A new wrapper that wraps the resulting node. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find('ul').childAt(0).type()).to.equal('li'); ``` #### Related Methods - [`.parents([selector]) => ReactWrapper`](parents.md) - [`.parent() => ReactWrapper`](parent.md) - [`.closest(selector) => ReactWrapper`](closest.md) - [`.children([selector]) => ReactWrapper`](children.md) ================================================ FILE: docs/api/ReactWrapper/children.md ================================================ # `.children([selector]) => ReactWrapper` Returns a new wrapper with all of the children of the node(s) in the current wrapper. Optionally, a selector can be provided and it will filter the children by this selector #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md) [optional]): A selector to filter the children by. #### Returns `ReactWrapper`: A new wrapper that wraps the resulting nodes. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find('ul').children()).to.have.lengthOf(items.length); ``` #### Related Methods - [`.parents([selector]) => ReactWrapper`](parents.md) - [`.parent() => ReactWrapper`](parent.md) - [`.closest(selector) => ReactWrapper`](closest.md) ================================================ FILE: docs/api/ReactWrapper/closest.md ================================================ # `.closest(selector) => ReactWrapper` Returns a wrapper of the first element that matches the selector by traversing up through the wrapped node's ancestors in the tree, starting with itself. It must be a single-node wrapper. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `ReactWrapper`: A new wrapper that wraps the resulting node. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find(Foo).closest('.bar')).to.have.lengthOf(1); ``` #### Related Methods - [`.children([selector]) => ReactWrapper`](children.md) - [`.parent() => ReactWrapper`](parent.md) - [`.parents([selector]) => ReactWrapper`](parents.md) ================================================ FILE: docs/api/ReactWrapper/contains.md ================================================ # `.contains(nodeOrNodes) => Boolean` Returns whether or not all given react elements match elements in the render tree. It will determine if an element in the wrapper matches the expected element by checking if the expected element has the same props as the wrapper's element and share the same values. #### Arguments 1. `nodeOrNodes` (`ReactElement|Array`): The node or array of nodes whose presence you are detecting in the current instance's render tree. #### Returns `Boolean`: whether or not the current wrapper has nodes anywhere in its render tree that match the ones passed in. #### Example ```jsx const wrapper = mount((
Hello
)); expect(wrapper.contains(
Hello
)).to.equal(true); expect(wrapper.contains(
Hello
)).to.equal(false); expect(wrapper.contains(
Hello
)).to.equal(false); expect(wrapper.contains(
Hello
)).to.equal(false); expect(wrapper.contains(
)).to.equal(false); ``` ```jsx const wrapper = mount((
Hello
Goodbye
Again
)); expect(wrapper.contains([ Hello,
Goodbye
, ])).to.equal(true); expect(wrapper.contains([ Hello,
World
, ])).to.equal(false); ``` #### Common Gotchas - `.contains()` expects a ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with a ReactElement or a JSX expression. - Keep in mind that this method determines equality based on the equality of the node's children as well. - Every attribute of the wrapped element must be matched by the element you're checking. To permit (and ignore) additional attributes on the wrapped element, use containsMatchingElement() instead. ================================================ FILE: docs/api/ReactWrapper/containsAllMatchingElements.md ================================================ # `.containsAllMatchingElements(patternNodes) => Boolean` Returns whether or not all of the given react elements in `patternNodes` match an element in the wrapper's render tree. Every single element of `patternNodes` must be matched one or more times. Matching follows the rules for `containsMatchingElement`. #### Arguments 1. `patternNodes` (`Array`): The array of nodes whose presence you are detecting in the current instance's render tree. #### Returns `Boolean`: whether or not the current wrapper has nodes anywhere in its render tree that looks like the nodes passed in. #### Example ```jsx const style = { fontSize: 13 }; const wrapper = mount((
Hello
Goodbye
Again
)); expect(wrapper.containsAllMatchingElements([ Hello,
Goodbye
, ])).to.equal(true); ``` #### Common Gotchas - `.containsAllMatchingElements()` expects an array of ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with an array of ReactElement or a JSX expression. - Keep in mind that this method determines matching based on the matching of the node's children as well. #### Related Methods - [`.matchesElement() => ReactWrapper`](matchesElement.md) - rules for matching each node - [`.containsMatchingElement() => ReactWrapper`](containsMatchingElement.md) - rules for matching whole wrapper - [`.containsAnyMatchingElements() => ReactWrapper`](containsAnyMatchingElements.md) - must match at least one in patternNodes ================================================ FILE: docs/api/ReactWrapper/containsAnyMatchingElements.md ================================================ # `.containsAnyMatchingElements(patternNodes) => Boolean` Returns whether or not at least one of the given react elements in `patternNodes` matches an element in the wrapper's render tree. One or more elements of `patternNodes` must be matched one or more times. Matching follows the rules for `containsMatchingElement`. #### Arguments 1. `patternNodes` (`Array`): The array of nodes whose presence you are detecting in the current instance's render tree. #### Returns `Boolean`: whether or not the current wrapper has a node anywhere in its render tree that looks like one of the array passed in. #### Example ```jsx const style = { fontSize: 13 }; const wrapper = mount((
Hello
Goodbye
Again
)); expect(wrapper.containsAnyMatchingElements([ Bonjour,
Goodbye
, ])).to.equal(true); ``` #### Common Gotchas - `.containsAnyMatchingElements()` expects an array of ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with an array ReactElement or a JSX expression. - Keep in mind that this method determines equality based on the equality of the node's children as well. #### Related Methods - [`.matchesElement() => ReactWrapper`](matchesElement.md) - rules for matching each node - [`.containsMatchingElement() => ReactWrapper`](containsMatchingElement.md) - rules for matching whole wrapper - [`.containsAllMatchingElements() => ReactWrapper`](containsAllMatchingElements.md) - must match all nodes in patternNodes ================================================ FILE: docs/api/ReactWrapper/containsMatchingElement.md ================================================ # `.containsMatchingElement(patternNode) => Boolean` Returns whether or not a `patternNode` react element matches any element in the render tree. * the matches can happen anywhere in the wrapper's contents * the wrapper can contain more than one node; all are searched Otherwise, the match follows the same rules as `matchesElement`. #### Arguments 1. `patternNode` (`ReactElement`): The node whose presence you are detecting in the current instance's render tree. #### Returns `Boolean`: whether or not the current wrapper has a node anywhere in its render tree that matches the one passed in. #### Example ```jsx const wrapper = mount((
Hello
)); expect(wrapper.containsMatchingElement(
Hello
)).to.equal(true); expect(wrapper.containsMatchingElement(
Hello
)).to.equal(true); expect(wrapper.containsMatchingElement(
Hello
)).to.equal(false); expect(wrapper.containsMatchingElement(
Hello
)).to.equal(false); expect(wrapper.containsMatchingElement(
)).to.equal(false); ``` #### Common Gotchas - `.containsMatchingElement()` expects a ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with a ReactElement or a JSX expression. - Keep in mind that this method determines equality based on the equality of the node's children as well. #### Related Methods - [`.containsAllMatchingElements() => ReactWrapper`](containsAllMatchingElements.md) - must match all nodes in patternNodes - [`.containsAnyMatchingElements() => ReactWrapper`](containsAnyMatchingElements.md) - must match at least one in patternNodes ================================================ FILE: docs/api/ReactWrapper/context.md ================================================ # `.context([key]) => Any` Returns the context hash for the root node of the wrapper. Optionally pass in a prop name and it will return just that value. #### Arguments 1. `key` (`String` [optional]): If provided, the return value will be the `this.context[key]` of the root component instance. #### Example ```jsx const wrapper = mount( , { context: { foo: 10 } }, ); expect(wrapper.context().foo).to.equal(10); expect(wrapper.context('foo')).to.equal(10); ``` #### Related Methods - [`.state([key]) => Any`](state.md) - [`.props() => Object`](props.md) - [`.prop(key) => Any`](prop.md) ================================================ FILE: docs/api/ReactWrapper/debug.md ================================================ # `.debug([options]) => String` Returns an HTML-like string of the wrapper for debugging purposes. Useful to print out to the console when tests are not passing when you expect them to. #### Arguments `options` (`Object` [optional]): - `options.ignoreProps`: (`Boolean` [optional]): Whether props should be omitted in the resulting string. Props are included by default. - `options.verbose`: (`Boolean` [optional]): Whether arrays and objects passed as props should be verbosely printed. #### Returns `String`: The resulting string. #### Examples Say we have the following components: ```jsx function Foo() { return (
Foo
); } function Bar() { return (
Non-Foo
); } ``` In this case, running: ```jsx console.log(mount().debug()); ``` Would output the following to the console: ```text
Non-Foo
Foo
``` Likewise, running: ```jsx console.log(mount().find(Foo).debug()); ``` Would output the following to the console: ```text
Foo
``` and: ```jsx console.log(mount().find(Foo).debug({ ignoreProps: true })); ``` Would output the following to the console: ```text
Foo
``` and: ```jsx console.log(mount().find(Foo).debug({ verbose: true })); ``` Would output the following to the console: ```text
Foo
``` ================================================ FILE: docs/api/ReactWrapper/detach.md ================================================ # `.detach() => void` Detaches the react tree from the DOM. Runs `ReactDOM.unmountComponentAtNode()` under the hood. This method will most commonly be used as a "cleanup" method if you decide to use the `attachTo` or `hydrateIn` option in `mount(node, options)`. The method is intentionally not "fluent" (in that it doesn't return `this`) because you should not be doing anything with this wrapper after this method is called. Using `attachTo`/`hydrateIn` is not generally recommended unless it is absolutely necessary to test something. It is your responsibility to clean up after yourself at the end of the test if you do decide to use it, though. #### Examples With the `attachTo` option, you can mount components to attached DOM elements: ```jsx // render a component directly into document.body const wrapper = mount(, { attachTo: document.body }); // Or, with the `hydrateIn` option, you can mount components on top of existing DOM elements: // hydrate a component directly onto document.body const hydratedWrapper = mount(, { hydrateIn: document.body }); // we can see that the component is rendered into the document expect(wrapper.find('.in-bar')).to.have.lengthOf(1); expect(document.body.childNodes).to.have.lengthOf(1); // detach it to clean up after yourself wrapper.detach(); // now we can see that expect(document.body.childNodes).to.have.lengthOf(0); ``` Similarly, if you want to create some one-off elements for your test to mount into: ```jsx // create a div in the document to mount into const div = global.document.createElement('div'); global.document.body.appendChild(div); // div is empty. body has the div attached. expect(document.body.childNodes).to.have.lengthOf(1); expect(div.childNodes).to.have.lengthOf(0); // mount a component passing div into the `attachTo` option const wrapper = mount(, { attachTo: div }); // or, mount a component passing div into the `hydrateIn` option const hydratedWrapper = mount(, { hydrateIn: div }); // we can see now the component is rendered into the document expect(wrapper.find('.in-foo')).to.have.lengthOf(1); expect(document.body.childNodes).to.have.lengthOf(1); expect(div.childNodes).to.have.lengthOf(1); // call detach to clean up wrapper.detach(); // div is now empty, but still attached to the document expect(document.body.childNodes).to.have.lengthOf(1); expect(div.childNodes).to.have.lengthOf(0); // remove div if you want global.document.body.removeChild(div); expect(document.body.childNodes).to.have.lengthOf(0); expect(div.childNodes).to.have.lengthOf(0); ``` ================================================ FILE: docs/api/ReactWrapper/equals.md ================================================ # `.equals(node) => Boolean` Returns whether or not the current wrapper root node render tree looks like the one passed in. #### Arguments 1. `node` (`ReactElement`): The node whose presence you are detecting in the current instance's render tree. #### Returns `Boolean`: whether or not the current wrapper has a node anywhere in it's render tree that looks like the one passed in. #### Example ```jsx function MyComponent() { return
; } const wrapper = mount().childAt(0); expect(wrapper.equals(
)).to.equal(true); ``` #### Common Gotchas - `.equals()` expects a ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with a ReactElement or a JSX expression. - Keep in mind that this method determines equality based on the equality of the node's children as well. - Following React's behavior, `.equals()` ignores properties whose values are `undefined`. ================================================ FILE: docs/api/ReactWrapper/every.md ================================================ # `.every(selector) => Boolean` Returns whether or not all of the nodes in the wrapper match the provided selector. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `Boolean`: True if every node in the current wrapper matched the provided selector. #### Examples ```jsx const wrapper = mount((
)); expect(wrapper.find('.foo').every('.foo')).to.equal(true); expect(wrapper.find('.foo').every('.qoo')).to.equal(false); expect(wrapper.find('.foo').every('.bar')).to.equal(false); ``` #### Related Methods - [`.someWhere(predicate) => Boolean`](someWhere.md) - [`.everyWhere(predicate) => Boolean`](everyWhere.md) ================================================ FILE: docs/api/ReactWrapper/everyWhere.md ================================================ # `.everyWhere(fn) => Boolean` Returns whether or not all of the nodes in the wrapper pass the provided predicate function. #### Arguments 1. `predicate` (`ReactWrapper => Boolean`): A predicate function to match the nodes. #### Returns `Boolean`: True if every node in the current wrapper passed the predicate function. #### Example ```jsx const wrapper = mount((
)); expect(wrapper.find('.foo').everyWhere((n) => n.hasClass('foo'))).to.equal(true); expect(wrapper.find('.foo').everyWhere((n) => n.hasClass('qoo'))).to.equal(false); expect(wrapper.find('.foo').everyWhere((n) => n.hasClass('bar'))).to.equal(false); ``` #### Related Methods - [`.some(selector) => Boolean`](some.md) - [`.every(selector) => Boolean`](every.md) ================================================ FILE: docs/api/ReactWrapper/exists.md ================================================ # `.exists([selector]) => Boolean` Returns whether or not any nodes exist in the wrapper. Or, if a selector is passed in, whether that selector has any matches in the wrapper. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md) [optional]): The selector to check existence for. #### Returns `Boolean`: whether or not any nodes are on the list, or the selector had any matches. #### Example ```jsx const wrapper = mount(
); expect(wrapper.exists('.some-class')).to.equal(true); expect(wrapper.find('.other-class').exists()).to.equal(false); ``` ================================================ FILE: docs/api/ReactWrapper/filter.md ================================================ # `.filter(selector) => ReactWrapper` Returns a new wrapper with only the nodes of the current wrapper that match the provided selector. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `ReactWrapper`: A new wrapper that wraps the filtered nodes. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find('.foo').filter('.bar')).to.have.lengthOf(1); ``` #### Related Methods - [`.filterWhere(predicate) => ReactWrapper`](filterWhere.md) ================================================ FILE: docs/api/ReactWrapper/filterWhere.md ================================================ # `.filterWhere(fn) => ReactWrapper` Returns a new wrapper with only the nodes of the current wrapper that, when passed into the provided predicate function, return true. #### Arguments 1. `predicate` (`ReactWrapper => Boolean`): A predicate function that is passed a wrapped node. #### Returns `ReactWrapper`: A new wrapper that wraps the filtered nodes. #### Example ```jsx const wrapper = mount(); const complexComponents = wrapper.find('.foo').filterWhere((n) => typeof n.type() !== 'string'); expect(complexComponents).to.have.lengthOf(4); ``` #### Related Methods - [`.filter(selector) => ReactWrapper`](filter.md) ================================================ FILE: docs/api/ReactWrapper/find.md ================================================ # `.find(selector) => ReactWrapper` Finds every node in the render tree of the current wrapper that matches the provided selector. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `ReactWrapper`: A new wrapper that wraps the found nodes. #### Examples CSS Selectors: ```jsx const wrapper = mount(); expect(wrapper.find('.foo')).to.have.lengthOf(1); expect(wrapper.find('.bar')).to.have.lengthOf(3); // compound selector expect(wrapper.find('div.some-class')).to.have.lengthOf(3); // CSS id selector expect(wrapper.find('#foo')).to.have.lengthOf(1); // property selector expect(wrapper.find('[htmlFor="checkbox"]')).to.have.lengthOf(1); ``` Component Constructors: ```jsx import Foo from '../components/Foo'; const wrapper = mount(); expect(wrapper.find(Foo)).to.have.lengthOf(1); ``` Component Display Name: ```jsx const wrapper = mount(); expect(wrapper.find('Foo')).to.have.lengthOf(1); ``` Object Property Selector: ```jsx const wrapper = mount(); expect(wrapper.find({ prop: 'value' })).to.have.lengthOf(1); ``` #### Related Methods - [`.findWhere(predicate) => ReactWrapper`](findWhere.md) ================================================ FILE: docs/api/ReactWrapper/findWhere.md ================================================ # `.findWhere(fn) => ReactWrapper` Finds every node in the render tree that returns true for the provided predicate function. #### Arguments 1. `predicate` (`ReactWrapper => Boolean`): A predicate function called with the passed in wrapped nodes. #### Returns `ReactWrapper`: A new wrapper that wraps the found nodes. #### Example ```jsx const wrapper = mount(); const complexComponents = wrapper.findWhere((n) => typeof n.type() !== 'string'); expect(complexComponents).to.have.lengthOf(8); ``` #### Related Methods - [`.find(selector) => ReactWrapper`](find.md) ================================================ FILE: docs/api/ReactWrapper/first.md ================================================ # `.first() => ReactWrapper` Reduce the set of matched nodes to the first in the set, just like `.at(0)`. #### Returns `ReactWrapper`: A new wrapper that wraps the first node in the set. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find(Foo).first().props().foo).to.equal('bar'); ``` #### Related Methods - [`.at(index) => ReactWrapper`](at.md) - retrieve a wrapper node at given index - [`.last() => ReactWrapper`](last.md) ================================================ FILE: docs/api/ReactWrapper/forEach.md ================================================ # `.forEach(fn) => Self` Iterates through each node of the current wrapper and executes the provided function with a wrapper around the corresponding node passed in as the first argument. #### Arguments 1. `fn` (`Function ( ReactWrapper node, Number index )`): A callback to be run for every node in the collection. Should expect a ReactWrapper as the first argument, and will be run with a context of the original instance. #### Returns `ReactWrapper`: Returns itself. #### Example ```jsx const wrapper = mount((
)); wrapper.find('.foo').forEach((node) => { expect(node.hasClass('foo')).to.equal(true); }); ``` #### Related Methods - [`.map(fn) => ReactWrapper`](map.md) ================================================ FILE: docs/api/ReactWrapper/get.md ================================================ # `.get(index) => ReactElement` Returns the node at a given index of the current wrapper. #### Arguments 1. `index` (`Number`): A zero-based integer indicating which node to retrieve. #### Returns `ReactElement`: The retrieved node. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find(Foo).get(0).props.foo).to.equal('bar'); ``` #### Related Methods - [`.at(index) => ReactWrapper`](at.md) - same, but returns the React node in a single-node wrapper. ================================================ FILE: docs/api/ReactWrapper/getDOMNode.md ================================================ # `.getDOMNode() => DOMComponent` Returns the outer most DOMComponent of the current wrapper. Notes: - can only be called on a wrapper of a single node. - will raise if called on a wrapper of a stateless functional component. #### Returns `DOMComponent`: The retrieved DOM component. #### Examples ```jsx const wrapper = mount(); expect(wrapper.getDOMNode()).to.have.property('className'); ``` ================================================ FILE: docs/api/ReactWrapper/getElement.md ================================================ # `.getElement() => ReactElement` Returns the wrapped ReactElement. If the current wrapper is wrapping the root component, returns the root component's latest render output. #### Returns `ReactElement`: The retrieved ReactElement. #### Examples ```jsx const element = (
); function MyComponent() { return element; } const wrapper = mount(); expect(wrapper.getElement()).to.equal(element); ``` #### Related Methods - [`.getElements() => Array`](getElements.md) ================================================ FILE: docs/api/ReactWrapper/getElements.md ================================================ # `.getElements() => Array` Returns the wrapped ReactElements If the current wrapper is wrapping the root component, returns the root component's latest render output wrapped in an array. #### Returns `Array`: The retrieved ReactElements. #### Examples ```jsx const one = ; const two = ; function Test() { return (
{one} {two}
); } const wrapper = mount(); expect(wrapper.find('span').getElements()).to.deep.equal([one, two]); ``` #### Related Methods - [`.getElement() => ReactElement`](getElement.md) ================================================ FILE: docs/api/ReactWrapper/getWrappingComponent.md ================================================ # `.getWrappingComponent() => ReactWrapper` If a `wrappingComponent` was passed in `options`, this methods returns a `ReactWrapper` around the rendered `wrappingComponent`. This `ReactWrapper` can be used to update the `wrappingComponent`'s props, state, etc. #### Returns `ReactWrapper`: A `ReactWrapper` around the rendered `wrappingComponent` #### Examples ```jsx import { Provider } from 'react-redux'; import { Router } from 'react-router'; import store from './my/app/store'; import mockStore from './my/app/mockStore'; function MyProvider(props) { const { children, customStore } = props; return ( {children} ); } MyProvider.propTypes = { children: PropTypes.node, customStore: PropTypes.shape({}), }; MyProvider.defaultProps = { children: null, customStore: null, }; const wrapper = mount(, { wrappingComponent: MyProvider, }); const provider = wrapper.getWrappingComponent(); provider.setProps({ customStore: mockStore }); ``` ================================================ FILE: docs/api/ReactWrapper/hasClass.md ================================================ # `.hasClass(className) => Boolean` Returns whether or not the wrapped node has a `className` prop including the passed in class name. It must be a single-node wrapper. #### Arguments 1. `className` (`String` | `RegExp`): A single class name or a regex expression. #### Returns `Boolean`: whether or not the wrapped node has found the class name. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find('.my-button').hasClass('disabled')).to.equal(true); ``` ```jsx // Searching using RegExp works fine when classes were injected by a jss decorator const wrapper = mount(); expect(wrapper.find('.my-button').hasClass(/(ComponentName)-(other)-(\d+)/)).to.equal(true); ``` ### Common Gotchas - `.hasClass()` expects a class name, NOT a CSS selector. `.hasClass('.foo')` should be `.hasClass('foo')` ================================================ FILE: docs/api/ReactWrapper/hostNodes.md ================================================ # `.hostNodes() => ReactWrapper` Returns a new wrapper with only host nodes. When using `react-dom`, host nodes are HTML elements rather than custom React components, e.g. `
` versus ``. #### Returns `ReactWrapper`: A new wrapper that wraps the filtered nodes. #### Examples The following code takes a wrapper with two nodes, one a `` React component, and the other a ``, and filters out the React component. ```jsx const wrapper = mount((
)); const twoNodes = wrapper.find('.foo'); expect(twoNodes.hostNodes()).to.have.lengthOf(1); ``` ================================================ FILE: docs/api/ReactWrapper/html.md ================================================ # `.html() => String` Returns a string of the rendered HTML markup of the current render tree. See also [`.debug()`](debug.md) Note: can only be called on a wrapper of a single node. #### Returns `String`: The resulting HTML string #### Examples ```jsx function Foo() { return (
); } ``` ```jsx function Bar() { return (
); } ``` ```jsx const wrapper = mount(); expect(wrapper.html()).to.equal('
'); expect(wrapper.find(Foo).html()).to.equal('
'); ``` ```jsx const wrapper = mount(
important
); expect(wrapper.html()).to.equal('
important
'); ``` #### Related Methods [`.text() => String`](text.md) ================================================ FILE: docs/api/ReactWrapper/instance.md ================================================ # `.instance() => ReactComponent` Returns the single-node wrapper's node's underlying class instance; `this` in its methods. It must be a single-node wrapper. NOTE: can only be called on a wrapper instance that is also the root instance. With React `16` and above, `instance()` returns `null` for functional components, regardless of [hooks](https://reactjs.org/docs/hooks-intro.html) usage. #### Returns `ReactComponent|DOMComponent`: The retrieved instance. #### Example ```jsx function SFC() { return
MyFunction
; } class Stateful extends React.Component { render() { return
MyClass
; } } ``` #### React 16.x ```jsx test('wrapper instance is null', () => { const wrapper = mount(); const instance = wrapper.instance(); expect(instance).to.equal(null); }); test('wrapper instance is not null', () => { const wrapper = mount(); const instance = wrapper.instance(); expect(instance).to.be.instanceOf(MyCStatefullass); }); ``` #### React 15.x ```jsx test('wrapper instance is not null', () => { const wrapper = mount(); const instance = wrapper.instance(); expect(instance).to.be.instanceOf(SFC); }); test('wrapper instance is not null', () => { const wrapper = mount(); const instance = wrapper.instance(); expect(instance).to.be.instanceOf(Stateful); }); ``` ================================================ FILE: docs/api/ReactWrapper/invoke.md ================================================ # `.invoke(propName)(...args) => Any` Invokes a function prop. Note that in React 16.8+, `.invoke` will wrap your handler with [`ReactTestUtils.act`](https://reactjs.org/docs/test-utils.html#act) and call `.update()` automatically. #### Arguments 1. `propName` (`String`): The function prop that is invoked 2. `...args` (`Any` [optional]): Arguments that is passed to the prop function #### Returns `Any`: Returns the value from the prop function #### Example ```jsx class Foo extends React.Component { loadData() { return fetch(); } render() { return (
); } } const wrapper = mount(); wrapper.find('button').invoke('onClick')().then(() => { // expect() }); ``` ================================================ FILE: docs/api/ReactWrapper/is.md ================================================ # `.is(selector) => Boolean` Returns whether or not the single wrapped node matches the provided selector. It must be a single-node wrapper. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `Boolean`: whether or not the wrapped node matches the provided selector. #### Example ```jsx const wrapper = mount(
); expect(wrapper.is('.some-class')).to.equal(true); ``` ================================================ FILE: docs/api/ReactWrapper/isEmpty.md ================================================ # `.isEmpty() => Boolean` **Deprecated**: Use [`.exists()`](exists.md) instead. Returns whether or not the wrapper is empty. #### Returns `Boolean`: whether or not the wrapper is empty. #### Example ```jsx const wrapper = mount(
); expect(wrapper.find('.other-class').isEmpty()).to.equal(true); ``` ================================================ FILE: docs/api/ReactWrapper/isEmptyRender.md ================================================ # `.isEmptyRender() => Boolean` Returns whether or not the wrapper would ultimately render only the allowed falsy values: `false` or `null`. #### Returns `Boolean`: whether the return is falsy #### Example ```jsx function Foo() { return null; } const wrapper = mount(); expect(wrapper.isEmptyRender()).to.equal(true); ``` ================================================ FILE: docs/api/ReactWrapper/key.md ================================================ # `.key() => String` Returns the key value for the node of the current wrapper. It must be a single-node wrapper. #### Example ```jsx const wrapper = mount((
    {['foo', 'bar'].map((s) =>
  • {s}
  • )}
)).find('li'); expect(wrapper.at(0).key()).to.equal('foo'); expect(wrapper.at(1).key()).to.equal('bar'); ``` ================================================ FILE: docs/api/ReactWrapper/last.md ================================================ # `.last() => ReactWrapper` Reduce the set of matched nodes to the last in the set, just like `.at(length - 1)`. #### Returns `ReactWrapper`: A new wrapper that wraps the last node in the set. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find(Foo).last().props().foo).to.equal('bar'); ``` #### Related Methods - [`.at(index) => ReactWrapper`](at.md) - retrieve a wrapper node by index - [`.first() => ReactWrapper`](first.md) ================================================ FILE: docs/api/ReactWrapper/length.md ================================================ # `.length => number` Returns the number of React nodes enclosed in this wrapper. #### Returns `Number`: count of nodes in the list in this wrapper. #### Example ```jsx const wrapper = mount(
); expect(wrapper.length).to.equal(1); ``` ================================================ FILE: docs/api/ReactWrapper/map.md ================================================ # `.map(fn) => Array` Maps the current array of nodes to another array. Each node is passed in as a `ReactWrapper` to the map function. #### Arguments 1. `fn` (`Function ( ReactWrapper node, Number index ) => Any`): A mapping function to be run for every node in the collection, the results of which will be mapped to the returned array. Should expect a ReactWrapper as the first argument, and will be run with a context of the original instance. #### Returns `Array`: Returns an array of the returned values from the mapping function.. #### Example ```jsx const wrapper = mount((
bax
bar
baz
)); const texts = wrapper.find('.foo').map((node) => node.text()); expect(texts).to.eql(['bax', 'bar', 'baz']); ``` #### Related Methods - [`.forEach(fn) => ReactWrapper`](forEach.md) - [`.reduce(fn[, initialValue]) => Any`](reduce.md) - [`.reduceRight(fn[, initialValue]) => Any`](reduceRight.md) ================================================ FILE: docs/api/ReactWrapper/matchesElement.md ================================================ # `.matchesElement(patternNode) => Boolean` Returns whether or not a given react element `patternNode` matches the wrapper's render tree. It must be a single-node wrapper, and only the root node is checked. The `patternNode` acts like a wildcard. For it to match a node in the wrapper: * tag names must match * contents must match: In text nodes, leading and trailing spaces are ignored, but not space in the middle. Child elements must match according to these rules, recursively. * `patternNode` props (attributes) must appear in the wrapper's nodes, but not the other way around. Their values must match if they do appear. * `patternNode` style CSS properties must appear in the wrapper's node's style, but not the other way around. Their values must match if they do appear. #### Arguments 1. `patternNode` (`ReactElement`): The node whose presence you are detecting in the wrapper's single node. #### Returns `Boolean`: whether or not the current wrapper match the one passed in. #### Example ```jsx class MyComponent extends React.Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick() { // ... } render() { return ( ); } } const wrapper = mount().childAt(0); expect(wrapper.matchesElement()).to.equal(true); expect(wrapper.matchesElement()).to.equal(true); ``` #### Common Gotchas - `.matchesElement()` expects a ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with a ReactElement or a JSX expression. - Keep in mind that this method determines matching based on the matching of the node's children as well. #### Related Methods - [`.containsMatchingElement() => ReactWrapper`](containsMatchingElement.md) - searches all nodes in the wrapper, and searches their entire depth ================================================ FILE: docs/api/ReactWrapper/mount.md ================================================ # `.mount() => Self` A method that re-mounts the component, if it is not currently mounted. This can be used to simulate a component going through an unmount/mount lifecycle. No equivalent for ShallowWrappers. #### Returns `ReactWrapper`: Returns itself. #### Example ```jsx import PropTypes from 'prop-types'; import sinon from 'sinon'; const willMount = sinon.spy(); const didMount = sinon.spy(); const willUnmount = sinon.spy(); class Foo extends React.Component { constructor(props) { super(props); this.componentWillUnmount = willUnmount; this.componentWillMount = willMount; this.componentDidMount = didMount; } render() { const { id } = this.props; return (
{id}
); } } Foo.propTypes = { id: PropTypes.string.isRequired, }; const wrapper = mount(); expect(willMount).to.have.property('callCount', 1); expect(didMount).to.have.property('callCount', 1); expect(willUnmount).to.have.property('callCount', 0); wrapper.unmount(); expect(willMount).to.have.property('callCount', 1); expect(didMount).to.have.property('callCount', 1); expect(willUnmount).to.have.property('callCount', 1); wrapper.mount(); expect(willMount).to.have.property('callCount', 2); expect(didMount).to.have.property('callCount', 2); expect(willUnmount).to.have.property('callCount', 1); ``` #### Related Methods - [`.unmount() => Self`](unmount.md) ================================================ FILE: docs/api/ReactWrapper/name.md ================================================ # `.name() => String|null` Returns the name of the current node of this wrapper. If it's a composite component, this will be the name of the component. If it's a native DOM node, it will be a string of the tag name. If it's `null`, it will be `null`. The order of precedence on returning the name is: `type.displayName` -> `type.name` -> `type`. Note: can only be called on a wrapper of a single node. #### Returns `String|null`: The name of the current node #### Examples ```jsx const wrapper = mount(
); expect(wrapper.name()).to.equal('div'); ``` ```jsx const wrapper = mount(); expect(wrapper.name()).to.equal('Foo'); ``` ```jsx Foo.displayName = 'A cool custom name'; const wrapper = mount(); expect(wrapper.name()).to.equal('A cool custom name'); ``` ================================================ FILE: docs/api/ReactWrapper/not.md ================================================ # `.not(selector) => ReactWrapper` Returns a new wrapper with only the nodes of the current wrapper that don't match the provided selector. This method is effectively the negation or inverse of [`filter`](filter.md). #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `ReactWrapper`: A new wrapper that wraps the filtered nodes. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find('.foo').not('.bar')).to.have.lengthOf(1); ``` #### Related Methods - [`.filterWhere(predicate) => ReactWrapper`](filterWhere.md) - [`.filter(selector) => ReactWrapper`](filter.md) ================================================ FILE: docs/api/ReactWrapper/parent.md ================================================ # `.parent() => ReactWrapper` Returns a wrapper with the direct parent of the node in the current wrapper. #### Returns `ReactWrapper`: A new wrapper that wraps the resulting nodes. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find('ul').parent().is('div')).to.equal(true); ``` #### Related Methods - [`.parents([selector]) => ReactWrapper`](parents.md) - [`.children([selector]) => ReactWrapper`](children.md) - [`.closest(selector) => ReactWrapper`](closest.md) ================================================ FILE: docs/api/ReactWrapper/parents.md ================================================ # `.parents([selector]) => ReactWrapper` Returns a wrapper around all of the parents/ancestors of the single node in the wrapper. Does not include the node itself. Optionally, a selector can be provided and it will filter the parents by this selector. It must be a single-node wrapper. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md) [optional]): The selector to filter the parents by. #### Returns `ReactWrapper`: A new wrapper that wraps the resulting nodes. #### Examples ```jsx const wrapper = mount(); expect(wrapper.find('ul').parents()).to.have.lengthOf(2); ``` #### Related Methods - [`.children([selector]) => ReactWrapper`](children.md) - [`.parent() => ReactWrapper`](parent.md) - [`.closest(selector) => ReactWrapper`](closest.md) ================================================ FILE: docs/api/ReactWrapper/prop.md ================================================ # `.prop(key) => Any` Returns the prop value for the root node of the wrapper with the provided key. It must be a single-node wrapper. #### Arguments 1. `key` (`String`): The prop name, that is, `this.props[key]` or `props[key]` for the root node of the wrapper. #### Example ```jsx const wrapper = mount(); expect(wrapper.prop('foo')).to.equal(10); ``` #### Related Methods - [`.props() => Object`](props.md) - [`.state([key]) => Any`](state.md) - [`.context([key]) => Any`](context.md) ================================================ FILE: docs/api/ReactWrapper/props.md ================================================ # `.props() => Object` Returns the props object for the root node of the wrapper. It must be a single-node wrapper. This method is a reliable way of accessing the props of a node; `wrapper.instance().props` will work as well, but in React 16+, stateless functional components do not have an instance. See [`.instance() => ReactComponent`](instance.md) #### Example ```jsx import PropTypes from 'prop-types'; function MyComponent(props) { const { includedProp } = props; return (
Hello
); } MyComponent.propTypes = { includedProp: PropTypes.string.isRequired, }; const wrapper = mount(); expect(wrapper.props().includedProp).to.equal('Success!'); // Warning: .props() only returns props that are passed to the root node, // which does not include excludedProp in this example. // See the note above about wrapper.instance().props. console.log(wrapper.props()); // {children: "Hello", className: "foo bar", includedProp="Success!"} console.log(wrapper.instance().props); // React 15.x - working as expected // {children: "Hello", className: "foo bar", includedProp:"Success!", excludedProp: "I'm not included"} console.log(wrapper.instance().props); // React 16.* - Uncaught TypeError: Cannot read property 'props' of null ``` #### Related Methods - [`.prop(key) => Any`](prop.md) - [`.state([key]) => Any`](state.md) - [`.context([key]) => Any`](context.md) ================================================ FILE: docs/api/ReactWrapper/reduce.md ================================================ # `.reduce(fn[, initialValue]) => Any` Applies the provided reducing function to every node in the wrapper to reduce to a single value. Each node is passed in as a `ReactWrapper`, and is processed from left to right. #### Arguments 1. `fn` (`Function`): A reducing function to be run for every node in the collection, with the following arguments: - `value` (`T`): The value returned by the previous invocation of this function - `node` (`ReactWrapper`): A wrapper around the node being processed - `index` (`Number`): The index of the node being processed 2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the first invocation of the reducing function. If omitted, the first `node` will be provided and the iteration will begin on the second node in the collection. #### Returns `T`: Returns an array of the returned values from the mapping function... #### Example ```jsx function Foo() { return (
); } ``` ```jsx const wrapper = mount(); const total = wrapper.find(Bar).reduce((amount, n) => amount + n.prop('amount'), 0); expect(total).to.equal(14); ``` #### Related Methods - [`.reduceRight(fn[, initialValue]) => Any`](reduceRight.md) - [`.forEach(fn) => ReactWrapper`](forEach.md) - [`.map(fn) => Array`](map.md) ================================================ FILE: docs/api/ReactWrapper/reduceRight.md ================================================ # `.reduceRight(fn[, initialValue]) => Any` Applies the provided reducing function to every node in the wrapper to reduce to a single value. Each node is passed in as a `ReactWrapper`, and is processed from right to left. #### Arguments 1. `fn` (`Function`): A reducing function to be run for every node in the collection, with the following arguments: - `value` (`T`): The value returned by the previous invocation of this function - `node` (`ReactWrapper`): A single-node wrapper around the node being processed - `index` (`Number`): The index of the node being processed 2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the first invocation of the reducing function. If omitted, the first `node` will be provided and the iteration will begin on the second node in the collection. #### Returns `T`: Returns an array of the returned values from the mapping function... #### Example ```jsx function Foo() { return (
); } ``` ```jsx const wrapper = mount(); const total = wrapper.find(Bar).reduceRight((amount, n) => amount + n.prop('amount'), 0); expect(total).to.equal(14); ``` #### Related Methods - [`.reduce(fn[, initialValue]) => Any`](reduce.md) - [`.forEach(fn) => ReactWrapper`](forEach.md) - [`.map(fn) => Array`](map.md) ================================================ FILE: docs/api/ReactWrapper/ref.md ================================================ # `.ref(refName) => ReactComponent | HTMLElement` Returns the node that matches the provided reference name. NOTE: can only be called on a wrapper instance that is also the root instance. #### Arguments 1. `refName` (`String`): The ref attribute of the node #### Returns `ReactComponent | HTMLElement`: The node that matches the provided reference name. This can be a react component instance, or an HTML element instance. #### Examples ```jsx class Foo extends React.Component { render() { return (
First Second Third
); } } ``` ```jsx const wrapper = mount(); expect(wrapper.ref('secondRef').innerText).to.equal('Second'); ``` #### Related Methods - [`.find(selector) => ReactWrapper`](find.md) - [`.findWhere(predicate) => ReactWrapper`](findWhere.md) ================================================ FILE: docs/api/ReactWrapper/render.md ================================================ # `.render() => CheerioWrapper` Returns a CheerioWrapper around the rendered HTML of the single node's subtree. It must be a single-node wrapper. #### Returns `CheerioWrapper`: The resulting Cheerio object #### Examples ```jsx function Foo() { return (
); } ``` ```jsx function Bar() { return (
); } ``` ```jsx const wrapper = mount(); expect(wrapper.find('.in-foo')).to.have.lengthOf(1); expect(wrapper.render().find('.in-foo')).to.have.lengthOf(1); ``` ================================================ FILE: docs/api/ReactWrapper/renderProp.md ================================================ # `.renderProp(propName)(...args) => ReactWrapper` Returns a function that, when called with arguments `args`, will return a new wrapper based on the render prop in the original wrapper's prop `propName`. NOTE: can only be called on wrapper of a single non-DOM component element node. #### Arguments 1. `propName` (`String`): 1. `...args` (`Array`): This essentially calls `wrapper.prop(propName)(...args)`. #### Returns `ReactWrapper`: A new wrapper that wraps the node returned from the render prop. #### Examples ##### Test Setup ```jsx class Mouse extends React.Component { constructor() { super(); this.state = { x: 0, y: 0 }; } render() { const { render } = this.props; return (
{ this.setState({ x: event.clientX, y: event.clientY, }); }} > {render(this.state)}
); } } Mouse.propTypes = { render: PropTypes.func.isRequired, }; ``` ```jsx function App() { return (
(

The mouse position is ({x}, {y})

)} />
); } ``` ##### Testing with no arguments ```jsx const wrapper = mount() .find(Mouse) .renderProp('render')(); expect(wrapper.equals(

The mouse position is 0, 0

)).to.equal(true); ``` ##### Testing with multiple arguments ```jsx const wrapper = mount() .find(Mouse) .renderProp('render')(10, 20); expect(wrapper.equals(

The mouse position is 10, 20

)).to.equal(true); ``` ================================================ FILE: docs/api/ReactWrapper/setContext.md ================================================ # `.setContext(context) => Self` A method that sets the context of the root component, and re-renders. Useful for when you are wanting to test how the component behaves over time with changing contexts. NOTE: can only be called on a wrapper instance that is also the root instance. #### Arguments 1. `context` (`Object`): An object containing new props to merge in with the current state #### Returns `ReactWrapper`: Returns itself. #### Example ```jsx import React from 'react'; import PropTypes from 'prop-types'; function SimpleComponent(props, context) { const { name } = context; return
{name}
; } SimpleComponent.contextTypes = { name: PropTypes.string, }; ``` ```jsx const context = { name: 'foo' }; const wrapper = mount(, { context }); expect(wrapper.text()).to.equal('foo'); wrapper.setContext({ name: 'bar' }); expect(wrapper.text()).to.equal('bar'); wrapper.setContext({ name: 'baz' }); expect(wrapper.text()).to.equal('baz'); ``` #### Common Gotchas - `.setContext()` can only be used on a wrapper that was initially created with a call to `mount()` that includes a `context` specified in the options argument. - The root component you are rendering must have a `contextTypes` static property. #### Related Methods - [`.setState(state[, callback]) => Self`](setState.md) - [`.setProps(props[, callback]) => Self`](setProps.md) ================================================ FILE: docs/api/ReactWrapper/setProps.md ================================================ # `.setProps(nextProps[, callback]) => Self` A method that sets the props of the root component, and re-renders. Useful for when you are wanting to test how the component behaves over time with changing props. Calling this, for instance, will call the `componentWillReceiveProps` lifecycle method. Similar to `setState`, this method accepts a props object and will merge it in with the already existing props. NOTE: can only be called on a wrapper instance that is also the root instance. #### Arguments 1. `nextProps` (`Object`): An object containing new props to merge in with the current props 2. `callback` (`Function` [optional]): If provided, the callback function will be executed once setProps has completed #### Returns `ReactWrapper`: Returns itself. #### Example ```jsx import React from 'react'; import PropTypes from 'prop-types'; function Foo({ name }) { return (
); } Foo.propTypes = { name: PropTypes.string.isRequired, }; ``` ```jsx const wrapper = mount(); expect(wrapper.find('.foo')).to.have.lengthOf(1); expect(wrapper.find('.bar')).to.have.lengthOf(0); wrapper.setProps({ name: 'bar' }); expect(wrapper.find('.foo')).to.have.lengthOf(0); expect(wrapper.find('.bar')).to.have.lengthOf(1); ``` ```jsx import sinon from 'sinon'; const spy = sinon.spy(MyComponent.prototype, 'componentWillReceiveProps'); const wrapper = mount(); expect(spy).to.have.property('callCount', 0); wrapper.setProps({ foo: 'foo' }); expect(spy).to.have.property('callCount', 1); ``` #### Related Methods - [`.setState(state) => Self`](setState.md) - [`.setContext(context) => Self`](setContext.md) ================================================ FILE: docs/api/ReactWrapper/setState.md ================================================ # `.setState(nextState[, callback]) => Self` A method to invoke `setState()` on the root component instance, similar to how you might in the methods of the component, and re-renders. This method is useful for testing your component in hard-to-achieve states, however should be used sparingly. If possible, you should utilize your component's external API (which is often accessible via [`.instance()`](instance.md)) in order to get it into whatever state you want to test, in order to be as accurate of a test as possible. This is not always practical, however. NOTE: Prior to v3.8.0 of enzyme, can only be called on a wrapper instance that is also the root instance. #### Arguments 1. `nextState` (`Object`): An object containing new state to merge in with the current state 2. `callback` (`Function` [optional]): If provided, the callback function will be executed once setState has completed #### Returns `ReactWrapper`: Returns itself. #### Example ```jsx class Foo extends React.Component { constructor(props) { super(props); this.state = { name: 'foo' }; } render() { const { name } = this.state; return (
); } } ``` ```jsx const wrapper = mount(); expect(wrapper.find('.foo')).to.have.lengthOf(1); expect(wrapper.find('.bar')).to.have.lengthOf(0); wrapper.setState({ name: 'bar' }); expect(wrapper.find('.foo')).to.have.lengthOf(0); expect(wrapper.find('.bar')).to.have.lengthOf(1); ``` #### Related Methods - [`.setProps(props[, callback]) => Self`](setProps.md) - [`.setContext(context) => Self`](setContext.md) ================================================ FILE: docs/api/ReactWrapper/simulate.md ================================================ # `.simulate(event[, mock]) => Self` Simulate events on the root node in the wrapper. It must be a single-node wrapper. #### Arguments 1. `event` (`String`): The event name to be simulated 2. `mock` (`Object` [optional]): A mock event object that will be merged with the event object passed to the handlers. #### Returns `ReactWrapper`: Returns itself. #### Example `class component` ```jsx class Foo extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { const { count } = this.state; return ( ); } } const wrapper = mount(); expect(wrapper.find('.clicks-0').length).to.equal(1); wrapper.find('a').simulate('click'); expect(wrapper.find('.clicks-1').length).to.equal(1); ``` #### Example `functional component` ```jsx function Foo({ width, height, onChange }) { return (
); } Foo.propTypes = { width: PropTypes.number.isRequired, height: PropTypes.number.isRequired, onChange: PropTypes.func.isRequired, }; const testState = { width: 10, height: 20 }; const wrapper = mount(( { testState[e.target.name] = e.target.value; }} /> )); expect(wrapper.find('input').at(0).props().value).to.equal(10); expect(wrapper.find('input').at(1).props().value).to.equal(20); wrapper.find('input').at(0).simulate('change', { target: { name: 'width', value: 50 } }); wrapper.find('input').at(1).simulate('change', { target: { name: 'height', value: 70 } }); expect(testState.width).to.equal(50); expect(testState.height).to.equal(70); ``` #### Common Gotchas - As noted in the function signature above passing a mock event is optional. It is worth noting that `ReactWrapper` will pass a `SyntheticEvent` object to the event handler in your code. Keep in mind that if the code you are testing uses properties that are not included in the `SyntheticEvent`, for instance `event.target.value`, you will need to provide a mock event like so `.simulate("change", { target: { value: "foo" }})` for it to work. ================================================ FILE: docs/api/ReactWrapper/simulateError.md ================================================ # `.simulateError(error) => Self` Simulate a component throwing an error as part of its rendering lifecycle. This is particularly useful in combination with React 16 error boundaries (ie, the `componentDidCatch` and `static getDerivedStateFromError` lifecycle methods). #### Arguments 1. `error` (`Any`): The error to throw. #### Returns `ReactWrapper`: Returns itself. #### Example ```jsx function Something() { // this is just a placeholder return null; } class ErrorBoundary extends React.Component { static getDerivedStateFromError(error) { return { hasError: true, }; } constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { const { spy } = this.props; spy(error, info); } render() { const { children } = this.props; const { hasError } = this.state; return ( {hasError ? 'Error' : children} ); } } ErrorBoundary.propTypes = { children: PropTypes.node.isRequired, spy: PropTypes.func.isRequired, }; const spy = sinon.spy(); const wrapper = mount(); const error = new Error('hi!'); wrapper.find(Something).simulateError(error); expect(wrapper.state()).to.have.property('hasError', true); expect(spy).to.have.property('callCount', 1); expect(spy.args).to.deep.equal([ error, { componentStack: ` in Something (created by ErrorBoundary) in ErrorBoundary (created by WrapperComponent) in WrapperComponent`, }, ]); ``` ================================================ FILE: docs/api/ReactWrapper/slice.md ================================================ # `.slice([begin[, end]]) => ReactWrapper` Returns a new wrapper with a subset of the nodes of the original wrapper, according to the rules of `Array#slice`. #### Arguments 1. `begin` (`Number` [optional]): Index from which to slice (defaults to `0`). If negative, this is treated as `length+begin`. 1. `end` (`Number` [optional]): Index at which to end slicing (defaults to `length`). If negative, this is treated as `length+end`. #### Returns `ReactWrapper`: A new wrapper with the subset of nodes specified. #### Examples ```jsx const wrapper = mount((
)); expect(wrapper.find('.foo').slice(1)).to.have.lengthOf(2); expect(wrapper.find('.foo').slice(1).at(0).hasClass('bar')).to.equal(true); expect(wrapper.find('.foo').slice(1).at(1).hasClass('baz')).to.equal(true); ``` ```jsx const wrapper = mount((
)); expect(wrapper.find('.foo').slice(1, 2)).to.have.lengthOf(1); expect(wrapper.find('.foo').slice(1, 2).at(0).hasClass('bar')).to.equal(true); ``` ================================================ FILE: docs/api/ReactWrapper/some.md ================================================ # `.some(selector) => Boolean` Returns whether or not any of the nodes in the wrapper match the provided selector. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `Boolean`: True if at least one of the nodes in the current wrapper matched the provided selector. #### Examples ```jsx const wrapper = mount((
)); expect(wrapper.find('.foo').some('.qoo')).to.equal(true); expect(wrapper.find('.foo').some('.foo')).to.equal(true); expect(wrapper.find('.foo').some('.bar')).to.equal(false); ``` #### Related Methods - [`.someWhere(predicate) => Boolean`](someWhere.md) - [`.every(selector) => Boolean`](every.md) - [`.everyWhere(predicate) => Boolean`](everyWhere.md) ================================================ FILE: docs/api/ReactWrapper/someWhere.md ================================================ # `.someWhere(fn) => Boolean` Returns whether or not any of the nodes in the wrapper pass the provided predicate function. #### Arguments 1. `predicate` (`ReactWrapper => Boolean`): A predicate function to match the nodes. #### Returns `Boolean`: True if at least one of the nodes in the current wrapper passed the predicate function. #### Example ```jsx const wrapper = mount((
)); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('qoo'))).to.equal(true); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('foo'))).to.equal(true); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('bar'))).to.equal(false); ``` #### Related Methods - [`.some(selector) => Boolean`](some.md) - [`.every(selector) => Boolean`](every.md) - [`.everyWhere(predicate) => Boolean`](everyWhere.md) ================================================ FILE: docs/api/ReactWrapper/state.md ================================================ # `.state([key]) => Any` Returns the state hash for the root node of the wrapper. Optionally pass in a prop name and it will return just that value. #### Arguments 1. `key` (`String` [optional]): If provided, the return value will be the `this.state[key]` of the root component instance. #### Example ```jsx const wrapper = mount(); expect(wrapper.state().foo).to.equal(10); expect(wrapper.state('foo')).to.equal(10); ``` #### Related Methods - [`.props() => Object`](props.md) - [`.prop(key) => Any`](prop.md) - [`.context([key]) => Any`](context.md) ================================================ FILE: docs/api/ReactWrapper/tap.md ================================================ # `.tap(intercepter) => Self` Invokes intercepter and returns itself. intercepter is called with itself. This is helpful when debugging nodes in method chains. #### Arguments 1. `intercepter` (`Self`): the current ReactWrapper instance. #### Returns `Self`: the current ReactWrapper instance. #### Example ```jsx const result = mount((
  • xxx
  • yyy
  • zzz
)).find('li') .tap((n) => console.log(n.debug())) .map((n) => n.text()); ``` ================================================ FILE: docs/api/ReactWrapper/text.md ================================================ # `.text() => String` Returns a string of the rendered text of the current render tree. This function should be looked at with skepticism if being used to test what the actual HTML output of the component will be. If that is what you would like to test, use enzyme's `render` function instead. Note: can only be called on a wrapper of a single node. #### Returns `String`: The resulting string #### Examples ```jsx const wrapper = mount(
important
); expect(wrapper.text()).to.equal('important'); ``` ```jsx function Foo() { return
This is
; } const wrapper = mount(
really important
); expect(wrapper.text()).to.equal('This is really important'); ``` #### Related Methods [`.html() => String`](html.md) ================================================ FILE: docs/api/ReactWrapper/type.md ================================================ # `.type() => String | Function | null` Returns the type of the only node of this wrapper. If it's a React component, this will be the component constructor. If it's a native DOM node, it will be a string with the tag name. If it's `null`, it will be `null`. It must be a single-node wrapper. #### Returns `String | Function | null`: The type of the node #### Examples ```jsx function Foo() { return
; } const wrapper = mount().childAt(0); expect(wrapper.type()).to.equal('div'); ``` ```jsx function Foo() { return (
); } const wrapper = mount(); expect(wrapper.find('.btn').type()).to.equal('button'); ``` ```jsx function Foo() { return ; } const wrapper = mount(); expect(wrapper.type()).to.equal(Foo); expect(wrapper.childAt(0).type()).to.equal(Bar); ``` ```jsx function Null() { return null; } const wrapper = mount(); expect(wrapper.type()).to.equal(null); ``` ================================================ FILE: docs/api/ReactWrapper/unmount.md ================================================ # `.unmount() => Self` A method that unmounts the component. This can be used to simulate a component going through an unmount/mount lifecycle. #### Returns `ReactWrapper`: Returns itself. #### Example ```jsx import PropTypes from 'prop-types'; import sinon from 'sinon'; const willMount = sinon.spy(); const didMount = sinon.spy(); const willUnmount = sinon.spy(); class Foo extends React.Component { constructor(props) { super(props); this.componentWillUnmount = willUnmount; this.componentWillMount = willMount; this.componentDidMount = didMount; } render() { const { id } = this.props; return (
{id}
); } } Foo.propTypes = { id: PropTypes.string.isRequired, }; const wrapper = mount(); expect(willMount).to.have.property('callCount', 1); expect(didMount).to.have.property('callCount', 1); expect(willUnmount).to.have.property('callCount', 0); wrapper.unmount(); expect(willMount).to.have.property('callCount', 1); expect(didMount).to.have.property('callCount', 1); expect(willUnmount).to.have.property('callCount', 1); ``` #### Related Methods - [`.mount() => Self`](mount.md) ================================================ FILE: docs/api/ReactWrapper/update.md ================================================ # `.update() => Self` Syncs the enzyme component tree snapshot with the react component tree. Useful to run before checking the render output if something external may be updating the state of the component somewhere. NOTE: no matter what instance this is called on, it will always update the root. NOTE: only updates Enzyme's representation of rendered tree. NOTE: this does not force a re-render. Use `wrapper.setProps({})` to force a re-render. #### Returns `ReactWrapper`: Returns itself. #### Example ```jsx class UpdateEnzyme extends React.Component { constructor(props) { super(props); this.state = { count: 0, }; this.increment = this.increment.bind(this); } increment() { const { count } = this.state; this.setState({ count: count + 1 }); } render() { const { count } = this.state; return ; } } ``` ```jsx const wrapper = mount(); expect(wrapper.find('button.increment').text()).to.equal('0'); wrapper.instance().increment(); // Update Enzyme's view of output wrapper.update(); expect(wrapper.find('button.increment').text()).to.equal('1'); ``` ================================================ FILE: docs/api/ShallowWrapper/at.md ================================================ # `.at(index) => ShallowWrapper` Returns a wrapper around the node at a given index of the current wrapper. #### Arguments 1. `index` (`Number`): A zero-based integer indicating which node to retrieve. #### Returns `ShallowWrapper`: A new wrapper that wraps the retrieved node. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find(Foo).at(0).props().foo).to.equal('bar'); ``` #### Related Methods - [`.get(index) => ReactElement`](get.md) - same, but returns the React node itself, with no wrapper. - [`.first() => ShallowWrapper`](first.md) - same as at(0) - [`.last() => ShallowWrapper`](last.md) ================================================ FILE: docs/api/ShallowWrapper/childAt.md ================================================ # `.childAt(index) => ShallowWrapper` Returns a new wrapper with child at the specified index. #### Arguments 1. `index` (`number`): A zero-based integer indicating which node to retrieve. #### Returns `ShallowWrapper`: A new wrapper that wraps the resulting node. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find('ul').childAt(0).type()).to.equal('li'); ``` #### Related Methods - [`.parents([selector]) => ShallowWrapper`](parents.md) - [`.parent() => ShallowWrapper`](parent.md) - [`.closest(selector) => ShallowWrapper`](closest.md) - [`.children([selector]) => ShallowWrapper`](children.md) ================================================ FILE: docs/api/ShallowWrapper/children.md ================================================ # `.children([selector]) => ShallowWrapper` Returns a new wrapper with all of the children of the node(s) in the current wrapper. Optionally, a selector can be provided and it will filter the children by this selector #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md) [optional]): A selector to filter the children by. #### Returns `ShallowWrapper`: A new wrapper that wraps the resulting nodes. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find('ul').children()).to.have.lengthOf(items.length); ``` #### Related Methods - [`.parents([selector]) => ShallowWrapper`](parents.md) - [`.parent() => ShallowWrapper`](parent.md) - [`.closest(selector) => ShallowWrapper`](closest.md) ================================================ FILE: docs/api/ShallowWrapper/closest.md ================================================ # `.closest(selector) => ShallowWrapper` Returns a wrapper of the first element that matches the selector by traversing up through the wrapped node's ancestors in the tree, starting with itself. It must be a single-node wrapper. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `ShallowWrapper`: A new wrapper that wraps the resulting node. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find(Foo).closest('.bar')).to.have.lengthOf(1); ``` #### Related Methods - [`.children([selector]) => ShallowWrapper`](children.md) - [`.parent() => ShallowWrapper`](parent.md) - [`.parents([selector]) => ShallowWrapper`](parents.md) ================================================ FILE: docs/api/ShallowWrapper/contains.md ================================================ # `.contains(nodeOrNodes) => Boolean` Returns whether or not all given react elements match elements in the render tree. It will determine if an element in the wrapper matches the expected element by checking if the expected element has the same props as the wrapper's element and share the same values. #### Arguments 1. `nodeOrNodes` (`ReactElement|Array`): The node or array of nodes whose presence you are detecting in the current instance's render tree. #### Returns `Boolean`: whether or not the current wrapper has nodes anywhere in its render tree that match the ones passed in. #### Example ```jsx const wrapper = shallow((
Hello
)); expect(wrapper.contains(
Hello
)).to.equal(true); expect(wrapper.contains(
Hello
)).to.equal(false); expect(wrapper.contains(
Hello
)).to.equal(false); expect(wrapper.contains(
Hello
)).to.equal(false); expect(wrapper.contains(
)).to.equal(false); ``` ```jsx const wrapper = shallow((
Hello
Goodbye
Again
)); expect(wrapper.contains([ Hello,
Goodbye
, ])).to.equal(true); expect(wrapper.contains([ Hello,
World
, ])).to.equal(false); ``` ```jsx const calculatedValue = 2 + 2; const wrapper = shallow((
{calculatedValue}
)); expect(wrapper.contains(
{4}
)).to.equal(true); ``` #### Common Gotchas - `.contains()` expects a ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with a ReactElement or a JSX expression. - Keep in mind that this method determines equality based on the equality of the node's children as well. ================================================ FILE: docs/api/ShallowWrapper/containsAllMatchingElements.md ================================================ # `.containsAllMatchingElements(patternNodes) => Boolean` Returns whether or not all of the given react elements in `patternNodes` match an element in the wrapper's render tree. Every single element of `patternNodes` must be matched one or more times. Matching follows the rules for `containsMatchingElement`. #### Arguments 1. `patternNodes` (`Array`): The array of nodes whose presence you are detecting in the current instance's render tree. #### Returns `Boolean`: whether or not the current wrapper has nodes anywhere in its render tree that looks like the nodes passed in. #### Example ```jsx const style = { fontSize: 13 }; const wrapper = shallow((
Hello
Goodbye
Again
)); expect(wrapper.containsAllMatchingElements([ Hello,
Goodbye
, ])).to.equal(true); ``` #### Common Gotchas - `.containsAllMatchingElements()` expects an array of ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with an array of ReactElement or a JSX expression. - Keep in mind that this method determines matching based on the matching of the node's children as well. #### Related Methods - [`.matchesElement() => ShallowWrapper`](matchesElement.md) - rules for matching each node - [`.containsMatchingElement() => ShallowWrapper`](containsMatchingElement.md) - rules for matching whole wrapper - [`.containsAnyMatchingElements() => ShallowWrapper`](containsAnyMatchingElements.md) - must match at least one in patternNodes ================================================ FILE: docs/api/ShallowWrapper/containsAnyMatchingElements.md ================================================ # `.containsAnyMatchingElements(patternNodes) => Boolean` Returns whether or not at least one of the given react elements in `patternNodes` matches an element in the wrapper's render tree. One or more elements of `patternNodes` must be matched one or more times. Matching follows the rules for `containsMatchingElement`. #### Arguments 1. `patternNodes` (`Array`): The array of nodes whose presence you are detecting in the current instance's render tree. #### Returns `Boolean`: whether or not the current wrapper has a node anywhere in its render tree that looks like one of the array passed in. #### Example ```jsx const style = { fontSize: 13 }; const wrapper = shallow((
Hello
Goodbye
Again
)); expect(wrapper.containsAnyMatchingElements([ Bonjour,
Goodbye
, ])).to.equal(true); ``` #### Common Gotchas - `.containsAnyMatchingElements()` expects an array of ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with an array ReactElement or a JSX expression. - Keep in mind that this method determines equality based on the equality of the node's children as well. #### Related Methods - [`.matchesElement() => ShallowWrapper`](matchesElement.md) - rules for matching each node - [`.containsMatchingElement() => ShallowWrapper`](containsMatchingElement.md) - rules for matching whole wrapper - [`.containsAllMatchingElements() => ShallowWrapper`](containsAllMatchingElements.md) - must match all nodes in patternNodes ================================================ FILE: docs/api/ShallowWrapper/containsMatchingElement.md ================================================ # `.containsMatchingElement(patternNode) => Boolean` Returns whether or not a `patternNode` react element matches any element in the render tree. * the matches can happen anywhere in the wrapper's contents * the wrapper can contain more than one node; all are searched Otherwise, the match follows the same rules as `matchesElement`. #### Arguments 1. `patternNode` (`ReactElement`): The node whose presence you are detecting in the current instance's render tree. #### Returns `Boolean`: whether or not the current wrapper has a node anywhere in its render tree that matches the one passed in. #### Example ```jsx const wrapper = shallow((
Hello
)); expect(wrapper.containsMatchingElement(
Hello
)).to.equal(true); expect(wrapper.containsMatchingElement(
Hello
)).to.equal(true); expect(wrapper.containsMatchingElement(
Hello
)).to.equal(false); expect(wrapper.containsMatchingElement(
Hello
)).to.equal(false); expect(wrapper.containsMatchingElement(
)).to.equal(false); ``` #### Common Gotchas - `.containsMatchingElement()` expects a ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with a ReactElement or a JSX expression. - Keep in mind that this method determines equality based on the equality of the node's children as well. #### Related Methods - [`.containsAllMatchingElements() => ShallowWrapper`](containsAllMatchingElements.md) - must match all nodes in patternNodes - [`.containsAnyMatchingElements() => ShallowWrapper`](containsAnyMatchingElements.md) - must match at least one in patternNodes ================================================ FILE: docs/api/ShallowWrapper/context.md ================================================ # `.context([key]) => Any` Returns the context hash for the root node of the wrapper. Optionally pass in a prop name and it will return just that value. #### Arguments 1. `key` (`String` [optional]): If provided, the return value will be the `this.context[key]` of the root component instance. #### Example ```jsx const wrapper = shallow( , { context: { foo: 10 } }, ); expect(wrapper.context().foo).to.equal(10); expect(wrapper.context('foo')).to.equal(10); ``` #### Related Methods - [`.props() => Object`](props.md) - [`.prop(key) => Any`](prop.md) - [`.state([key]) => Any`](state.md) ================================================ FILE: docs/api/ShallowWrapper/debug.md ================================================ # `.debug([options]) => String` Returns an HTML-like string of the wrapper for debugging purposes. Useful to print out to the console when tests are not passing when you expect them to. #### Arguments `options` (`Object` [optional]): - `options.ignoreProps`: (`Boolean` [optional]): Whether props should be omitted in the resulting string. Props are included by default. - `options.verbose`: (`Boolean` [optional]): Whether arrays and objects passed as props should be verbosely printed. #### Returns `String`: The resulting string. #### Examples ```jsx function Book({ title, pages }) { return (

{title}

{pages && ( )}
); } Book.propTypes = { title: PropTypes.string.isRequired, pages: PropTypes.number, }; Book.defaultProps = { pages: null, }; ``` ```jsx const wrapper = shallow(); console.log(wrapper.debug()); ``` Outputs to console: ```text

Huckleberry Finn

``` ```jsx const wrapper = shallow(( )); console.log(wrapper.debug()); ``` Outputs to console: ```text

Huckleberry Finn

``` ```jsx const wrapper = shallow(( )); console.log(wrapper.debug({ ignoreProps: true })); ``` Outputs to console: ```text

Huckleberry Finn

``` ```jsx const wrapper = shallow(( )); console.log(wrapper.debug({ verbose: true })); ``` Outputs to console: ```text

Huckleberry Finn

``` ================================================ FILE: docs/api/ShallowWrapper/dive.md ================================================ # `.dive([options]) => ShallowWrapper` Shallow render the one non-DOM child of the current wrapper, and return a wrapper around the result. It must be a single-node wrapper, and the node must be a React component. There is no corresponding `dive` method for ReactWrappers. NOTE: can only be called on a wrapper of a single non-DOM component element node, otherwise it will throw an error. If you have to shallow-wrap a wrapper with multiple child nodes, use [`.shallow()`](shallow.md). #### Arguments 1. `options` (`Object` [optional]): - `options.context`: (`Object` [optional]): Context to be passed into the component #### Returns `ShallowWrapper`: A new wrapper that wraps the current node after it's been shallow rendered. #### Examples ```jsx function Bar() { return (
); } ``` ```jsx function Foo() { return (
); } ``` ```jsx const wrapper = shallow(); expect(wrapper.find('.in-bar')).to.have.lengthOf(0); expect(wrapper.find(Bar)).to.have.lengthOf(1); expect(wrapper.find(Bar).dive().find('.in-bar')).to.have.lengthOf(1); ``` ================================================ FILE: docs/api/ShallowWrapper/equals.md ================================================ # `.equals(node) => Boolean` Returns whether or not the current wrapper root node render tree looks like the one passed in. #### Arguments 1. `node` (`ReactElement`): The node whose presence you are detecting in the current instance's render tree. #### Returns `Boolean`: whether or not the current wrapper has a node anywhere in it's render tree that looks like the one passed in. #### Example ```jsx function MyComponent() { return
; } const wrapper = shallow(); expect(wrapper.equals(
)).to.equal(true); ``` #### Common Gotchas - `.equals()` expects a ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with a ReactElement or a JSX expression. - Keep in mind that this method determines equality based on the equality of the node's children as well. - Following React's behavior, `.equals()` ignores properties whose values are `undefined`. ================================================ FILE: docs/api/ShallowWrapper/every.md ================================================ # `.every(selector) => Boolean` Returns whether or not all of the nodes in the wrapper match the provided selector. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `Boolean`: True if every node in the current wrapper matched the provided selector. #### Examples ```jsx const wrapper = shallow((
)); expect(wrapper.find('.foo').every('.foo')).to.equal(true); expect(wrapper.find('.foo').every('.qoo')).to.equal(false); expect(wrapper.find('.foo').every('.bar')).to.equal(false); ``` #### Related Methods - [`.someWhere(predicate) => Boolean`](someWhere.md) - [`.everyWhere(predicate) => Boolean`](everyWhere.md) ================================================ FILE: docs/api/ShallowWrapper/everyWhere.md ================================================ # `.everyWhere(fn) => Boolean` Returns whether or not all of the nodes in the wrapper pass the provided predicate function. #### Arguments 1. `predicate` (`ShallowWrapper => Boolean`): A predicate function to match the nodes. #### Returns `Boolean`: True if every node in the current wrapper passed the predicate function. #### Example ```jsx const wrapper = shallow((
)); expect(wrapper.find('.foo').everyWhere((n) => n.hasClass('foo'))).to.equal(true); expect(wrapper.find('.foo').everyWhere((n) => n.hasClass('qoo'))).to.equal(false); expect(wrapper.find('.foo').everyWhere((n) => n.hasClass('bar'))).to.equal(false); ``` #### Related Methods - [`.some(selector) => Boolean`](some.md) - [`.every(selector) => Boolean`](every.md) - [`.everyWhere(predicate) => Boolean`](everyWhere.md) ================================================ FILE: docs/api/ShallowWrapper/exists.md ================================================ # `.exists([selector]) => Boolean` Returns whether or not any nodes exist in the wrapper. Or, if a selector is passed in, whether that selector has any matches in the wrapper. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md) [optional]): The selector to check existence for. #### Returns `Boolean`: whether or not any nodes are on the list, or the selector had any matches. #### Example ```jsx const wrapper = shallow(
); expect(wrapper.exists('.some-class')).to.equal(true); expect(wrapper.find('.other-class').exists()).to.equal(false); ``` ================================================ FILE: docs/api/ShallowWrapper/filter.md ================================================ # `.filter(selector) => ShallowWrapper` Returns a new wrapper with only the nodes of the current wrapper that match the provided selector. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `ShallowWrapper`: A new wrapper that wraps the filtered nodes. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find('.foo').filter('.bar')).to.have.lengthOf(1); ``` #### Related Methods - [`.filterWhere(predicate) => ShallowWrapper`](filterWhere.md) ================================================ FILE: docs/api/ShallowWrapper/filterWhere.md ================================================ # `.filterWhere(fn) => ShallowWrapper` Returns a new wrapper with only the nodes of the current wrapper that, when passed into the provided predicate function, return true. #### Arguments 1. `predicate` (`ShallowWrapper => Boolean`): A predicate function that is passed a wrapped node. #### Returns `ShallowWrapper`: A new wrapper that wraps the filtered nodes. #### Example ```jsx const wrapper = shallow(); const complexFoo = wrapper.find('.foo').filterWhere((n) => typeof n.type() !== 'string'); expect(complexFoo).to.have.lengthOf(4); ``` #### Related Methods - [`.filter(selector) => ShallowWrapper`](filter.md) ================================================ FILE: docs/api/ShallowWrapper/find.md ================================================ # `.find(selector) => ShallowWrapper` Finds every node in the render tree of the current wrapper that matches the provided selector. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `ShallowWrapper`: A new wrapper that wraps the found nodes. #### Examples CSS Selectors: ```jsx const wrapper = shallow(); expect(wrapper.find('.foo')).to.have.lengthOf(1); expect(wrapper.find('.bar')).to.have.lengthOf(3); // compound selector expect(wrapper.find('div.some-class')).to.have.lengthOf(3); // CSS id selector expect(wrapper.find('#foo')).to.have.lengthOf(1); ``` Component Constructors: ```jsx import Foo from '../components/Foo'; const wrapper = shallow(); expect(wrapper.find(Foo)).to.have.lengthOf(1); ``` Component Display Name: ```jsx const wrapper = shallow(); expect(wrapper.find('Foo')).to.have.lengthOf(1); ``` Object Property Selector: ```jsx const wrapper = shallow(); expect(wrapper.find({ prop: 'value' })).to.have.lengthOf(1); ``` #### Related Methods - [`.findWhere(predicate) => ShallowWrapper`](findWhere.md) ================================================ FILE: docs/api/ShallowWrapper/findWhere.md ================================================ # `.findWhere(fn) => ShallowWrapper` Finds every node in the render tree that returns true for the provided predicate function. #### Arguments 1. `predicate` (`ShallowWrapper => Boolean`): A predicate function called with the passed in wrapped nodes. #### Returns `ShallowWrapper`: A new wrapper that wraps the found nodes. #### Example ```jsx const wrapper = shallow(); const complexComponents = wrapper.findWhere((n) => n.type() !== 'string'); expect(complexComponents).to.have.lengthOf(8); ``` #### Related Methods - [`.find(selector) => ShallowWrapper`](find.md) ================================================ FILE: docs/api/ShallowWrapper/first.md ================================================ # `.first() => ShallowWrapper` Reduce the set of matched nodes to the first in the set, just like `.at(0)`. #### Returns `ShallowWrapper`: A new wrapper that wraps the first node in the set. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find(Foo).first().props().foo).to.equal('bar'); ``` #### Related Methods - [`.at(index) => ShallowWrapper`](at.md) - retrieve a wrapper node at given index - [`.last() => ShallowWrapper`](last.md) ================================================ FILE: docs/api/ShallowWrapper/forEach.md ================================================ # `.forEach(fn) => Self` Iterates through each node of the current wrapper and executes the provided function with a wrapper around the corresponding node passed in as the first argument. #### Arguments 1. `fn` (`Function ( ShallowWrapper node, Number index )`): A callback to be run for every node in the collection. Should expect a ShallowWrapper as the first argument, and will be run with a context of the original instance. #### Returns `ShallowWrapper`: Returns itself. #### Example ```jsx const wrapper = shallow((
)); wrapper.find('.foo').forEach((node) => { expect(node.hasClass('foo')).to.equal(true); }); ``` #### Related Methods - [`.map(fn) => ShallowWrapper`](map.md) ================================================ FILE: docs/api/ShallowWrapper/get.md ================================================ # `.get(index) => ReactElement` Returns the node at a given index of the current wrapper. #### Arguments 1. `index` (`Number`): A zero-based integer indicating which node to retrieve. #### Returns `ReactElement`: The retrieved node. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find(Foo).get(0).props.foo).to.equal('bar'); ``` #### Related Methods - [`.at(index) => ShallowWrapper`](at.md) - same, but returns the React node in a single-node wrapper. ================================================ FILE: docs/api/ShallowWrapper/getElement.md ================================================ # `.getElement() => ReactElement` Returns the wrapped ReactElement. If the current wrapper is wrapping the root component, returns the root component's latest render output. #### Returns `ReactElement`: The retrieved ReactElement. #### Examples ```jsx const element = (
); function MyComponent() { return element; } const wrapper = shallow(); expect(wrapper.getElement()).to.equal(element); ``` #### Related Methods - [`.getElements() => Array`](getElements.md) ================================================ FILE: docs/api/ShallowWrapper/getElements.md ================================================ # `.getElements() => Array` Returns the wrapped ReactElements If the current wrapper is wrapping the root component, returns the root component's latest render output wrapped in an array. #### Returns `Array`: The retrieved ReactElements. #### Examples ```jsx const one = ; const two = ; function Test() { return (
{one} {two}
); } const wrapper = shallow(); expect(wrapper.find('span').getElements()).to.deep.equal([one, two]); ``` #### Related Methods - [`.getElement() => ReactElement`](getElement.md) ================================================ FILE: docs/api/ShallowWrapper/getWrappingComponent.md ================================================ # `.getWrappingComponent() => ShallowWrapper` If a `wrappingComponent` was passed in `options`, this methods returns a `ShallowWrapper` around the rendered `wrappingComponent`. This `ShallowWrapper` can be used to update the `wrappingComponent`'s props, state, etc. #### Returns `ShallowWrapper`: A `ShallowWrapper` around the rendered `wrappingComponent` #### Examples ```jsx import { Provider } from 'react-redux'; import { Router } from 'react-router'; import store from './my/app/store'; import mockStore from './my/app/mockStore'; function MyProvider(props) { const { children, customStore } = props; return ( {children} ); } MyProvider.propTypes = { children: PropTypes.node, customStore: PropTypes.shape({}), }; MyProvider.defaultProps = { children: null, customStore: null, }; const wrapper = shallow(, { wrappingComponent: MyProvider, }); const provider = wrapper.getWrappingComponent(); provider.setProps({ customStore: mockStore }); ``` ================================================ FILE: docs/api/ShallowWrapper/hasClass.md ================================================ # `.hasClass(className) => Boolean` Returns whether or not the wrapped node has a `className` prop including the passed in class name. It must be a single-node wrapper. #### Arguments 1. `className` (`String` | `RegExp`): A single class name or a regex expression. #### Returns `Boolean`: whether or not the wrapped node has the class. #### Example ```jsx const wrapper = shallow(); expect(wrapper.find('.my-button').hasClass('disabled')).to.equal(true); ``` ```jsx // Searching using RegExp works fine when classes were injected by a jss decorator const wrapper = shallow(); expect(wrapper.find('.my-button').hasClass(/(ComponentName)-(other)-(\d+)/)).to.equal(true); ``` ### Common Gotchas - `.hasClass()` expects a class name, NOT a CSS selector. `.hasClass('.foo')` should be `.hasClass('foo')` ================================================ FILE: docs/api/ShallowWrapper/hostNodes.md ================================================ # `.hostNodes() => ShallowWrapper` Returns a new wrapper with only host nodes. When using `react-dom`, host nodes are HTML elements rather than custom React components, e.g. `
` versus ``. #### Returns `ShallowWrapper`: A new wrapper that wraps the filtered nodes. #### Examples The following code takes a wrapper with two nodes, one a `` React component, and the other a ``, and filters out the React component. ```jsx const wrapper = shallow((
)); const twoNodes = wrapper.find('.foo'); expect(twoNodes.hostNodes()).to.have.lengthOf(1); ``` ================================================ FILE: docs/api/ShallowWrapper/html.md ================================================ # `.html() => String` Returns a string of the rendered HTML markup of the entire current render tree (not just the shallow-rendered part). It uses [static rendering](../render.md) internally. To see only the shallow-rendered part use [`.debug()`](debug.md). Note: can only be called on a wrapper of a single node. #### Returns `String`: The resulting HTML string #### Examples ```jsx function Foo() { return (
); } ``` ```jsx function Bar() { return (
); } ``` ```jsx const wrapper = shallow(); expect(wrapper.html()).to.equal('
'); expect(wrapper.find(Foo).html()).to.equal('
'); ``` ```jsx const wrapper = shallow(
important
); expect(wrapper.html()).to.equal('
important
'); ``` #### Related Methods - [`.text() => String`](text.md) - [`.debug() => String`](debug.md) ================================================ FILE: docs/api/ShallowWrapper/instance.md ================================================ # `.instance() => ReactComponent` Returns the single-node wrapper's node's underlying class instance; `this` in its methods. It must be a single-node wrapper. NOTE: can only be called on a wrapper instance that is also the root instance. With React `16` and above, `instance()` returns `null` for functional components, regardless of [hooks](https://reactjs.org/docs/hooks-intro.html) usage. #### Returns `ReactComponent|DOMComponent`: The retrieved instance. #### Example ```jsx function SFC() { return
MyFunction
; } class Stateful extends React.Component { render() { return
MyClass
; } } ``` #### React 16.x ```jsx test('wrapper instance is null', () => { const wrapper = shallow(); const instance = wrapper.instance(); expect(instance).to.equal(null); }); test('wrapper instance is not null', () => { const wrapper = shallow(); const instance = wrapper.instance(); expect(instance).to.be.instanceOf(MyCStatefullass); }); ``` #### React 15.x ```jsx test('wrapper instance is not null', () => { const wrapper = shallow(); const instance = wrapper.instance(); expect(instance).to.be.instanceOf(SFC); }); test('wrapper instance is not null', () => { const wrapper = shallow(); const instance = wrapper.instance(); expect(instance).to.be.instanceOf(Stateful); }); ``` ================================================ FILE: docs/api/ShallowWrapper/invoke.md ================================================ # `.invoke(invokePropName)(...args) => Any` Invokes a function prop. #### Arguments 1. `propName` (`String`): The function prop that is invoked 2. `...args` (`Any` [optional]): Arguments that is passed to the prop function This essentially calls wrapper.prop(propName)(...args). #### Returns `Any`: Returns the value from the prop function #### Example ```jsx class Foo extends React.Component { loadData() { return fetch(); } render() { return (
); } } const wrapper = shallow(); wrapper.find('button').invoke('onClick')().then(() => { // expect() }); ``` ================================================ FILE: docs/api/ShallowWrapper/is.md ================================================ # `.is(selector) => Boolean` Returns whether or not the single wrapped node matches the provided selector. It must be a single-node wrapper. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `Boolean`: whether or not the wrapped node matches the provided selector. #### Example ```jsx const wrapper = shallow(
); expect(wrapper.is('.some-class')).to.equal(true); ``` ================================================ FILE: docs/api/ShallowWrapper/isEmpty.md ================================================ # `.isEmpty() => Boolean` **Deprecated**: Use [`.exists()`](exists.md) instead. Returns whether or not the wrapper is empty. #### Returns `Boolean`: whether or not the wrapper is empty. #### Example ```jsx const wrapper = shallow(
); expect(wrapper.find('.other-class').isEmpty()).to.equal(true); ``` ================================================ FILE: docs/api/ShallowWrapper/isEmptyRender.md ================================================ # `.isEmptyRender() => Boolean` Returns whether or not the wrapper would ultimately render only the allowed falsy values: `false` or `null`. #### Returns `Boolean`: whether the return is falsy #### Example ```jsx function Foo() { return null; } const wrapper = shallow(); expect(wrapper.isEmptyRender()).to.equal(true); ``` ================================================ FILE: docs/api/ShallowWrapper/key.md ================================================ # `.key() => String` Returns the key value for the node of the current wrapper. It must be a single-node wrapper. #### Example ```jsx const wrapper = shallow((
    {['foo', 'bar'].map((s) =>
  • {s}
  • )}
)).find('li'); expect(wrapper.at(0).key()).to.equal('foo'); expect(wrapper.at(1).key()).to.equal('bar'); ``` ================================================ FILE: docs/api/ShallowWrapper/last.md ================================================ # `.last() => ShallowWrapper` Reduce the set of matched nodes to the last in the set, just like `.at(length - 1)`. #### Returns `ShallowWrapper`: A new wrapper that wraps the last node in the set. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find(Foo).last().props().foo).to.equal('bar'); ``` #### Related Methods - [`.at(index) => ShallowWrapper`](at.md) - retrieve a wrapper node by index - [`.first() => ShallowWrapper`](first.md) ================================================ FILE: docs/api/ShallowWrapper/length.md ================================================ # `.length => number` Returns the number of React nodes enclosed in this wrapper. #### Returns `Number`: count of nodes in the list in this wrapper. #### Example ```jsx const wrapper = shallow(
); expect(wrapper.length).to.equal(1); ``` ================================================ FILE: docs/api/ShallowWrapper/map.md ================================================ # `.map(fn) => Array` Maps the current array of nodes to another array. Each node is passed in as a `ShallowWrapper` to the map function. #### Arguments 1. `fn` (`Function ( ShallowWrapper node, Number index ) => Any`): A mapping function to be run for every node in the collection, the results of which will be mapped to the returned array. Should expect a ShallowWrapper as the first argument, and will be run with a context of the original instance. #### Returns `Array`: Returns an array of the returned values from the mapping function.. #### Example ```jsx const wrapper = shallow((
bax
bar
baz
)); const texts = wrapper.find('.foo').map((node) => node.text()); expect(texts).to.eql(['bax', 'bar', 'baz']); ``` #### Related Methods - [`.forEach(fn) => ShallowWrapper`](forEach.md) - [`.reduce(fn[, initialValue]) => Any`](reduce.md) - [`.reduceRight(fn[, initialValue]) => Any`](reduceRight.md) ================================================ FILE: docs/api/ShallowWrapper/matchesElement.md ================================================ # `.matchesElement(patternNode) => Boolean` Returns whether or not a given react element `patternNode` matches the wrapper's render tree. It must be a single-node wrapper, and only the root node is checked. The `patternNode` acts like a wildcard. For it to match a node in the wrapper: * tag names must match * contents must match: In text nodes, leading and trailing spaces are ignored, but not space in the middle. Child elements must match according to these rules, recursively. * `patternNode` props (attributes) must appear in the wrapper's nodes, but not the other way around. Their values must match if they do appear. * `patternNode` style CSS properties must appear in the wrapper's node's style, but not the other way around. Their values must match if they do appear. #### Arguments 1. `patternNode` (`ReactElement`): The node whose presence you are detecting in the wrapper's single node. #### Returns `Boolean`: whether or not the current wrapper match the one passed in. #### Example ```jsx class MyComponent extends React.Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick() { // ... } render() { return ( ); } } const wrapper = shallow(); expect(wrapper.matchesElement()).to.equal(true); expect(wrapper.matchesElement()).to.equal(true); ``` #### Common Gotchas - `.matchesElement()` expects a ReactElement, not a selector (like many other methods). Make sure that when you are calling it you are calling it with a ReactElement or a JSX expression. - Keep in mind that this method determines matching based on the matching of the node's children as well. #### Related Methods - [`.containsMatchingElement() => ShallowWrapper`](containsMatchingElement.md) - searches all nodes in the wrapper, and searches their entire depth ================================================ FILE: docs/api/ShallowWrapper/name.md ================================================ # `.name() => String|null` Returns the name of the current node of this wrapper. If it's a composite component, this will be the name of the top-most rendered component. If it's a native DOM node, it will be a string of the tag name. If it's `null`, it will be `null`. The order of precedence on returning the name is: `type.displayName` -> `type.name` -> `type`. Note: can only be called on a wrapper of a single node. #### Returns `String|null`: The name of the current node #### Examples ```jsx const wrapper = shallow(
); expect(wrapper.name()).to.equal('div'); ``` ```jsx function SomeWrappingComponent() { return ; } const wrapper = shallow(); expect(wrapper.name()).to.equal('Foo'); ``` ```jsx Foo.displayName = 'A cool custom name'; function SomeWrappingComponent() { return ; } const wrapper = shallow(); expect(wrapper.name()).to.equal('A cool custom name'); ``` ================================================ FILE: docs/api/ShallowWrapper/not.md ================================================ # `.not(selector) => ShallowWrapper` Returns a new wrapper with only the nodes of the current wrapper that don't match the provided selector. This method is effectively the negation or inverse of [`filter`](filter.md). #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `ShallowWrapper`: A new wrapper that wraps the filtered nodes. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find('.foo').not('.bar')).to.have.lengthOf(1); ``` #### Related Methods - [`.filterWhere(predicate) => ShallowWrapper`](filterWhere.md) - [`.filter(selector) => ShallowWrapper`](filter.md) ================================================ FILE: docs/api/ShallowWrapper/parent.md ================================================ # `.parent() => ShallowWrapper` Returns a wrapper with the direct parent of the node in the current wrapper. #### Returns `ShallowWrapper`: A new wrapper that wraps the resulting nodes. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find('ul').parent().is('div')).to.equal(true); ``` #### Related Methods - [`.parents([selector]) => ShallowWrapper`](parents.md) - [`.children([selector]) => ShallowWrapper`](children.md) - [`.closest(selector) => ShallowWrapper`](closest.md) ================================================ FILE: docs/api/ShallowWrapper/parents.md ================================================ # `.parents([selector]) => ShallowWrapper` Returns a wrapper around all of the parents/ancestors of the single node in the wrapper. Does not include the node itself. Optionally, a selector can be provided and it will filter the parents by this selector. It must be a single-node wrapper. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md) [optional]): The selector to filter the parents by. #### Returns `ShallowWrapper`: A new wrapper that wraps the resulting nodes. #### Examples ```jsx const wrapper = shallow(); expect(wrapper.find('ul').parents()).to.have.lengthOf(2); ``` #### Related Methods - [`.children([selector]) => ShallowWrapper`](children.md) - [`.parent() => ShallowWrapper`](parent.md) - [`.closest(selector) => ShallowWrapper`](closest.md) ================================================ FILE: docs/api/ShallowWrapper/prop.md ================================================ # `.prop(key) => Any` Returns the prop value for the root node of the wrapper with the provided key. It must be a single-node wrapper. NOTE: When called on a shallow wrapper, `.prop(key)` will return values for props on the root node that the component *renders*, not the component itself. To return the props for the entire React component, use `wrapper.instance().props`. See [`.instance() => ReactComponent`](instance.md) #### Arguments 1. `key` (`String`): The prop name, that is, `this.props[key]` or `props[key]` for the root node of the wrapper. #### Example ```jsx import PropTypes from 'prop-types'; import ValidateNumberInputComponent from './ValidateNumberInputComponent'; class MyComponent extends React.Component { constructor(...args) { super(...args); this.state = { number: 0, }; this.onValidNumberInput = this.onValidNumberInput.bind(this); } onValidNumberInput(e) { const number = e.target.value; if (!number || typeof number === 'number') { this.setState({ number }); } } render() { const { includedProp } = this.props; const { number } = this.state; return (
); } } MyComponent.propTypes = { includedProp: PropTypes.string.isRequired, }; const wrapper = shallow(); expect(wrapper.prop('includedProp')).to.equal('Success!'); const validInput = 1; wrapper.find('ValidateNumberInputComponent').prop('onChangeHandler')(validInput); expect(wrapper.state('number')).to.equal(validInput); const invalidInput = 'invalid input'; wrapper.find('ValidateNumberInputComponent').prop('onChangeHandler')(invalidInput); expect(wrapper.state('number')).to.equal(0); // Warning: .prop(key) only returns values for props that exist in the root node. // See the note above about wrapper.instance().props to return all props in the React component. console.log(wrapper.prop('includedProp')); // "Success!" console.log(wrapper.prop('excludedProp')); // undefined console.log(wrapper.instance().props.excludedProp); // "I'm not included" ``` #### Related Methods - [`.props() => Object`](props.md) - [`.state([key]) => Any`](state.md) - [`.context([key]) => Any`](context.md) ================================================ FILE: docs/api/ShallowWrapper/props.md ================================================ # `.props() => Object` Returns the props object for the root node of the wrapper. It must be a single-node wrapper. NOTE: When called on a shallow wrapper, `.props()` will return values for props on the root node that the component *renders*, not the component itself. This method is a reliable way of accessing the props of a node; `wrapper.instance().props` will work as well, but in React 16+, stateless functional components do not have an instance. See [`.instance() => ReactComponent`](instance.md) #### Example ```jsx import PropTypes from 'prop-types'; function MyComponent(props) { const { includedProp } = props; return (
Hello
); } MyComponent.propTypes = { includedProp: PropTypes.string.isRequired, }; const wrapper = shallow(); expect(wrapper.props().includedProp).to.equal('Success!'); // Warning: .props() only returns props that are passed to the root node, // which does not include excludedProp in this example. // See the note above about wrapper.instance().props. console.log(wrapper.props()); // {children: "Hello", className: "foo bar", includedProp="Success!"} console.log(wrapper.instance().props); // React 15.x - working as expected // {children: "Hello", className: "foo bar", includedProp:"Success!", excludedProp: "I'm not included"} console.log(wrapper.instance().props); // React 16.* - Uncaught TypeError: Cannot read property 'props' of null ``` #### Related Methods - [`.prop(key) => Any`](prop.md) - [`.state([key]) => Any`](state.md) - [`.context([key]) => Any`](context.md) ================================================ FILE: docs/api/ShallowWrapper/reduce.md ================================================ # `.reduce(fn[, initialValue]) => Any` Applies the provided reducing function to every node in the wrapper to reduce to a single value. Each node is passed in as a `ShallowWrapper`, and is processed from left to right. #### Arguments 1. `fn` (`Function`): A reducing function to be run for every node in the collection, with the following arguments: - `value` (`T`): The value returned by the previous invocation of this function - `node` (`ShallowWrapper`): A wrapper around the node being processed - `index` (`Number`): The index of the node being processed 2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the first invocation of the reducing function. If omitted, the first `node` will be provided and the iteration will begin on the second node in the collection. #### Returns `T`: Returns an array of the returned values from the mapping function... #### Example ```jsx function Foo() { return (
); } ``` ```jsx const wrapper = shallow(); const total = wrapper.find(Bar).reduce((amount, n) => amount + n.prop('amount'), 0); expect(total).to.equal(14); ``` #### Related Methods - [`.reduceRight(fn[, initialValue]) => Any`](reduceRight.md) - [`.forEach(fn) => ShallowWrapper`](forEach.md) - [`.map(fn) => Array`](map.md) ================================================ FILE: docs/api/ShallowWrapper/reduceRight.md ================================================ # `.reduceRight(fn[, initialValue]) => Any` Applies the provided reducing function to every node in the wrapper to reduce to a single value. Each node is passed in as a `ShallowWrapper`, and is processed from right to left. #### Arguments 1. `fn` (`Function`): A reducing function to be run for every node in the collection, with the following arguments: - `value` (`T`): The value returned by the previous invocation of this function - `node` (`ShallowWrapper`): A single-node wrapper around the node being processed - `index` (`Number`): The index of the node being processed 2. `initialValue` (`T` [optional]): If provided, this will be passed in as the first argument to the first invocation of the reducing function. If omitted, the first `node` will be provided and the iteration will begin on the second node in the collection. #### Returns `T`: Returns an array of the returned values from the mapping function... #### Example ```jsx function Foo() { return (
); } ``` ```jsx const wrapper = shallow(); const total = wrapper.find(Bar).reduceRight((amount, n) => amount + n.prop('amount'), 0); expect(total).to.equal(14); ``` #### Related Methods - [`.reduce(fn[, initialValue]) => Any`](reduce.md) - [`.forEach(fn) => ShallowWrapper`](forEach.md) - [`.map(fn) => Array`](map.md) ================================================ FILE: docs/api/ShallowWrapper/render.md ================================================ # `.render() => CheerioWrapper` Returns a CheerioWrapper around the rendered HTML of the single node's subtree. It must be a single-node wrapper. #### Returns `CheerioWrapper`: The resulting Cheerio object #### Examples ```jsx function Foo() { return (
); } ``` ```jsx function Bar() { return (
); } ``` ```jsx const wrapper = shallow(); expect(wrapper.find('.in-foo')).to.have.lengthOf(0); expect(wrapper.render().find('.in-foo')).to.have.lengthOf(1); ``` ================================================ FILE: docs/api/ShallowWrapper/renderProp.md ================================================ # `.renderProp(propName)(...args) => ShallowWrapper` Returns a function that, when called with arguments `args`, will return a new wrapper based on the render prop in the original wrapper's prop `propName`. NOTE: can only be called on wrapper of a single non-DOM component element node. #### Arguments 1. `propName` (`String`): 1. `...args` (`Array`): This essentially calls `wrapper.prop(propName)(...args)`. #### Returns `ShallowWrapper`: A new wrapper that wraps the node returned from the render prop. #### Examples ##### Test Setup ```jsx class Mouse extends React.Component { constructor() { super(); this.state = { x: 0, y: 0 }; } render() { const { render } = this.props; return (
{ this.setState({ x: event.clientX, y: event.clientY, }); }} > {render(this.state)}
); } } Mouse.propTypes = { render: PropTypes.func.isRequired, }; ``` ```jsx function App() { return (
(

The mouse position is ({x}, {y})

)} />
); } ``` ##### Testing with no arguments ```jsx const wrapper = shallow() .find(Mouse) .renderProp('render')(); expect(wrapper.equals(

The mouse position is 0, 0

)).to.equal(true); ``` ##### Testing with multiple arguments ```jsx const wrapper = shallow() .find(Mouse) .renderProp('render')(10, 20); expect(wrapper.equals(

The mouse position is 10, 20

)).to.equal(true); ``` ================================================ FILE: docs/api/ShallowWrapper/setContext.md ================================================ # `.setContext(context) => Self` A method that sets the context of the root component, and re-renders. Useful for when you are wanting to test how the component behaves over time with changing contexts. NOTE: can only be called on a wrapper instance that is also the root instance. #### Arguments 1. `context` (`Object`): An object containing new props to merge in with the current state #### Returns `ShallowWrapper`: Returns itself. #### Example ```jsx import React from 'react'; import PropTypes from 'prop-types'; function SimpleComponent(props, context) { const { name } = context; return
{name}
; } SimpleComponent.contextTypes = { name: PropTypes.string, }; ``` ```jsx const context = { name: 'foo' }; const wrapper = shallow(, { context }); expect(wrapper.text()).to.equal('foo'); wrapper.setContext({ name: 'bar' }); expect(wrapper.text()).to.equal('bar'); wrapper.setContext({ name: 'baz' }); expect(wrapper.text()).to.equal('baz'); ``` #### Common Gotchas - `.setContext()` can only be used on a wrapper that was initially created with a call to `shallow()` that includes a `context` specified in the options argument. - The root component you are rendering must have a `contextTypes` static property. #### Related Methods - [`.setState(state[, callback]) => Self`](setState.md) - [`.setProps(props[, callback]) => Self`](setProps.md) ================================================ FILE: docs/api/ShallowWrapper/setProps.md ================================================ # `.setProps(nextProps[, callback]) => Self` A method that sets the props of the root component, and re-renders. Useful for when you are wanting to test how the component behaves over time with changing props. Calling this, for instance, will call the `componentWillReceiveProps` lifecycle method. Similar to `setState`, this method accepts a props object and will merge it in with the already existing props. NOTE: can only be called on a wrapper instance that is also the root instance. #### Arguments 1. `nextProps` (`Object`): An object containing new props to merge in with the current props 2. `callback` (`Function` [optional]): If provided, the callback function will be executed once setProps has completed #### Returns `ShallowWrapper`: Returns itself. #### Example ```jsx import React from 'react'; import PropTypes from 'prop-types'; function Foo({ name }) { return (
); } Foo.propTypes = { name: PropTypes.string.isRequired, }; ``` ```jsx const wrapper = shallow(); expect(wrapper.find('.foo')).to.have.lengthOf(1); expect(wrapper.find('.bar')).to.have.lengthOf(0); wrapper.setProps({ name: 'bar' }); expect(wrapper.find('.foo')).to.have.lengthOf(0); expect(wrapper.find('.bar')).to.have.lengthOf(1); ``` ```jsx import sinon from 'sinon'; const spy = sinon.spy(MyComponent.prototype, 'componentWillReceiveProps'); const wrapper = shallow(); expect(spy).to.have.property('callCount', 0); wrapper.setProps({ foo: 'foo' }); expect(spy).to.have.property('callCount', 1); ``` #### Related Methods - [`.setState(state) => Self`](setState.md) - [`.setContext(context) => Self`](setContext.md) ================================================ FILE: docs/api/ShallowWrapper/setState.md ================================================ # `.setState(nextState[, callback]) => Self` A method to invoke `setState()` on the root component instance, similar to how you might in the methods of the component, and re-renders. This method is useful for testing your component in hard-to-achieve states, however should be used sparingly. If possible, you should utilize your component's external API (which is often accessible via [`.instance()`](instance.md)) in order to get it into whatever state you want to test, in order to be as accurate of a test as possible. This is not always practical, however. NOTE: can only be called on a wrapper instance that is also the root instance. #### Arguments 1. `nextState` (`Object`): An object containing new state to merge in with the current state 2. `callback` (`Function` [optional]): If provided, the callback function will be executed once setState has completed #### Returns `ShallowWrapper`: Returns itself. #### Example ```jsx class Foo extends React.Component { constructor(props) { super(props); this.state = { name: 'foo' }; } render() { const { name } = this.state; return (
); } } ``` ```jsx const wrapper = shallow(); expect(wrapper.find('.foo')).to.have.lengthOf(1); expect(wrapper.find('.bar')).to.have.lengthOf(0); wrapper.setState({ name: 'bar' }); expect(wrapper.find('.foo')).to.have.lengthOf(0); expect(wrapper.find('.bar')).to.have.lengthOf(1); ``` #### Related Methods - [`.setProps(props[, callback]) => Self`](setProps.md) - [`.setContext(context) => Self`](setContext.md) ================================================ FILE: docs/api/ShallowWrapper/shallow.md ================================================ # `.shallow([options]) => ShallowWrapper` Shallow renders the root node and returns a shallow wrapper around it. It must be a single-node wrapper. #### Arguments 1. `options` (`Object` [optional]): - `options.context`: (`Object` [optional]): Context to be passed into the component - `options.disableLifecycleMethods`: (`Boolean` [optional]): If set to true, `componentDidMount` is not called on the component, and `componentDidUpdate` is not called after [`setProps`](ShallowWrapper/setProps.md) and [`setContext`](ShallowWrapper/setContext.md). Default to `false`. #### Returns `ShallowWrapper`: A new wrapper that wraps the node after it's been shallow rendered. #### Examples ```jsx function Bar() { return (
); } ``` ```jsx function Foo() { return (
); } ``` ```jsx const wrapper = shallow(); expect(wrapper.find('.in-bar')).to.have.lengthOf(0); expect(wrapper.find(Bar)).to.have.lengthOf(1); expect(wrapper.find(Bar).shallow().find('.in-bar')).to.have.lengthOf(1); ``` ================================================ FILE: docs/api/ShallowWrapper/simulate.md ================================================ # `.simulate(event[, ...args]) => Self` Simulate events on the root node in the wrapper. It must be a single-node wrapper. #### Arguments 1. `event` (`String`): The event name to be simulated 2. `...args` (`Any` [optional]): A mock event object that will get passed through to the event handlers. #### Returns `ShallowWrapper`: Returns itself. #### Example `class component` ```jsx class Foo extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { const { count } = this.state; return ( ); } } const wrapper = shallow(); expect(wrapper.find('.clicks-0').length).to.equal(1); wrapper.find('a').simulate('click'); expect(wrapper.find('.clicks-1').length).to.equal(1); ``` #### Example `functional component` ```jsx function Foo({ width, height, onChange }) { return (
); } Foo.propTypes = { width: PropTypes.number.isRequired, height: PropTypes.number.isRequired, onChange: PropTypes.func.isRequired, }; const testState = { width: 10, height: 20 }; const wrapper = shallow(( { testState[e.target.name] = e.target.value; }} /> )); expect(wrapper.find('input').at(0).prop('value')).toEqual(10); expect(wrapper.find('input').at(1).prop('value')).toEqual(20); wrapper.find('input').at(0).simulate('change', { target: { name: 'width', value: 50 } }); wrapper.find('input').at(1).simulate('change', { target: { name: 'height', value: 70 } }); expect(testState.width).toEqual(50); expect(testState.height).toEqual(70); ``` #### Common Gotchas - Currently, event simulation for the shallow renderer does not propagate as one would normally expect in a real environment. As a result, one must call `.simulate()` on the actual node that has the event handler set. - Even though the name would imply this simulates an actual event, `.simulate()` will in fact target the component's prop based on the event you give it. For example, `.simulate('click')` will actually get the `onClick` prop and call it. - As noted in the function signature above passing a mock event is optional. Keep in mind that if the code you are testing uses the event for something like, calling `event.preventDefault()` or accessing any of its properties you must provide a mock event object with the properties your code requires. ================================================ FILE: docs/api/ShallowWrapper/simulateError.md ================================================ # `.simulateError(error) => Self` Simulate a component throwing an error as part of its rendering lifecycle. This is particularly useful in combination with React 16 error boundaries (ie, the `componentDidCatch` and `static getDerivedStateFromError` lifecycle methods). #### Arguments 1. `error` (`Any`): The error to throw. #### Returns `ShallowWrapper`: Returns itself. #### Example ```jsx function Something() { // this is just a placeholder return null; } class ErrorBoundary extends React.Component { static getDerivedStateFromError(error) { return { hasError: true, }; } constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { const { spy } = this.props; spy(error, info); } render() { const { children } = this.props; const { hasError } = this.state; return ( {hasError ? 'Error' : children} ); } } ErrorBoundary.propTypes = { children: PropTypes.node.isRequired, spy: PropTypes.func.isRequired, }; const spy = sinon.spy(); const wrapper = shallow(); const error = new Error('hi!'); wrapper.find(Something).simulateError(error); expect(wrapper.state()).to.have.property('hasError', true); expect(spy).to.have.property('callCount', 1); expect(spy.args).to.deep.equal([ error, { componentStack: ` in Something (created by ErrorBoundary) in ErrorBoundary (created by WrapperComponent) in WrapperComponent`, }, ]); ``` ================================================ FILE: docs/api/ShallowWrapper/slice.md ================================================ # `.slice([begin[, end]]) => ShallowWrapper` Returns a new wrapper with a subset of the nodes of the original wrapper, according to the rules of `Array#slice`. #### Arguments 1. `begin` (`Number` [optional]): Index from which to slice (defaults to `0`). If negative, this is treated as `length+begin`. 1. `end` (`Number` [optional]): Index at which to end slicing (defaults to `length`). If negative, this is treated as `length+end`. #### Returns `ShallowWrapper`: A new wrapper with the subset of nodes specified. #### Examples ```jsx const wrapper = shallow((
)); expect(wrapper.find('.foo').slice(1)).to.have.lengthOf(2); expect(wrapper.find('.foo').slice(1).at(0).hasClass('bar')).to.equal(true); expect(wrapper.find('.foo').slice(1).at(1).hasClass('baz')).to.equal(true); ``` ```jsx const wrapper = shallow((
)); expect(wrapper.find('.foo').slice(1, 2)).to.have.lengthOf(1); expect(wrapper.find('.foo').slice(1, 2).at(0).hasClass('bar')).to.equal(true); ``` ================================================ FILE: docs/api/ShallowWrapper/some.md ================================================ # `.some(selector) => Boolean` Returns whether or not any of the nodes in the wrapper match the provided selector. #### Arguments 1. `selector` ([`EnzymeSelector`](../selector.md)): The selector to match. #### Returns `Boolean`: True if at least one of the nodes in the current wrapper matched the provided selector. #### Examples ```jsx const wrapper = shallow((
)); expect(wrapper.find('.foo').some('.qoo')).to.equal(true); expect(wrapper.find('.foo').some('.foo')).to.equal(true); expect(wrapper.find('.foo').some('.bar')).to.equal(false); ``` #### Related Methods - [`.someWhere(predicate) => Boolean`](someWhere.md) - [`.every(selector) => Boolean`](every.md) - [`.everyWhere(predicate) => Boolean`](everyWhere.md) ================================================ FILE: docs/api/ShallowWrapper/someWhere.md ================================================ # `.someWhere(fn) => Boolean` Returns whether or not any of the nodes in the wrapper pass the provided predicate function. #### Arguments 1. `predicate` (`ShallowWrapper => Boolean`): A predicate function to match the nodes. #### Returns `Boolean`: True if at least one of the nodes in the current wrapper passed the predicate function. #### Example ```jsx const wrapper = shallow((
)); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('qoo'))).to.equal(true); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('foo'))).to.equal(true); expect(wrapper.find('.foo').someWhere((n) => n.hasClass('bar'))).to.equal(false); ``` #### Related Methods - [`.some(selector) => Boolean`](some.md) - [`.every(selector) => Boolean`](every.md) - [`.everyWhere(predicate) => Boolean`](everyWhere.md) ================================================ FILE: docs/api/ShallowWrapper/state.md ================================================ # `.state([key]) => Any` Returns the state hash for the root node of the wrapper. Optionally pass in a prop name and it will return just that value. #### Arguments 1. `key` (`String` [optional]): If provided, the return value will be the `this.state[key]` of the root component instance. #### Example ```jsx const wrapper = shallow(); expect(wrapper.state().foo).to.equal(10); expect(wrapper.state('foo')).to.equal(10); ``` #### Related Methods - [`.props() => Object`](props.md) - [`.prop(key) => Any`](prop.md) - [`.context([key]) => Any`](context.md) ================================================ FILE: docs/api/ShallowWrapper/tap.md ================================================ # `.tap(intercepter) => Self` Invokes intercepter and returns itself. intercepter is called with itself. This is helpful when debugging nodes in method chains. #### Arguments 1. `intercepter` (`Self`): the current ShallowWrapper instance. #### Returns `Self`: the current ShallowWrapper instance. #### Example ```jsx const result = shallow((
  • xxx
  • yyy
  • zzz
)).find('li') .tap((n) => console.log(n.debug())) .map((n) => n.text()); ``` ================================================ FILE: docs/api/ShallowWrapper/text.md ================================================ # `.text() => String` Returns a string of the rendered text of the current render tree. This function should be looked at with skepticism if being used to test what the actual HTML output of the component will be. If that is what you would like to test, use enzyme's `render` function instead. Note: can only be called on a wrapper of a single node. #### Returns `String`: The resulting string #### Examples ```jsx const wrapper = shallow(
important
); expect(wrapper.text()).to.equal('important'); ``` ```jsx const wrapper = shallow(
important
); expect(wrapper.text()).to.equal('important'); ``` #### Related Methods [`.html() => String`](html.md) ================================================ FILE: docs/api/ShallowWrapper/type.md ================================================ # `.type() => String | Function | null` Returns the type of the only node of this wrapper. If it's a React component, this will be the component constructor. If it's a native DOM node, it will be a string with the tag name. If it's `null`, it will be `null`. It must be a single-node wrapper. #### Returns `String | Function | null`: The type of the node #### Examples ```jsx function Foo() { return
; } const wrapper = shallow(); expect(wrapper.type()).to.equal('div'); ``` ```jsx function Foo() { return (
); } const wrapper = shallow(); expect(wrapper.find('.btn').type()).to.equal('button'); ``` ```jsx function Foo() { return ; } const wrapper = shallow(); expect(wrapper.type()).to.equal(Bar); ``` ```jsx function Null() { return null; } const wrapper = shallow(); expect(wrapper.type()).to.equal(null); ``` ================================================ FILE: docs/api/ShallowWrapper/unmount.md ================================================ # `.unmount() => Self` A method that unmounts the component. This can be used to simulate a component going through an unmount/mount lifecycle. #### Returns `ShallowWrapper`: Returns itself. #### Example ```jsx import PropTypes from 'prop-types'; import sinon from 'sinon'; const spy = sinon.spy(); class Foo extends React.Component { constructor(props) { super(props); this.componentWillUnmount = spy; } render() { const { id } = this.props; return (
{id}
); } } Foo.propTypes = { id: PropTypes.string.isRequired, }; const wrapper = shallow(); expect(spy).to.have.property('callCount', 0); wrapper.unmount(); expect(spy).to.have.property('callCount', 1); ``` ================================================ FILE: docs/api/ShallowWrapper/update.md ================================================ # `.update() => Self` Syncs the enzyme component tree snapshot with the react component tree. Useful to run before checking the render output if something external may be updating the state of the component somewhere. NOTE: no matter what instance this is called on, it will always update the root. NOTE: only updates Enzyme's representation of rendered tree. NOTE: this does not force a re-render. Use `wrapper.setProps({})` to force a re-render. #### Returns `ReactWrapper`: Returns itself. #### Example ```jsx class UpdateEnzyme extends React.Component { constructor(props) { super(props); this.state = { count: 0, }; this.increment = this.increment.bind(this); } increment() { const { count } = this.state; this.setState({ count: count + 1 }); } render() { const { count } = this.state; return ; } } ``` ```jsx const wrapper = shallow(); expect(wrapper.find('button.increment').text()).to.equal('0'); wrapper.instance().increment(); // Update Enzyme's view of output wrapper.update(); expect(wrapper.find('button.increment').text()).to.equal('1'); ``` ================================================ FILE: docs/api/mount.md ================================================ # Full Rendering API (`mount(...)`) Full DOM rendering is ideal for use cases where you have components that may interact with DOM APIs or need to test components that are wrapped in higher order components. Full DOM rendering requires that a full DOM API be available at the global scope. This means that it must be run in an environment that at least “looks like” a browser environment. If you do not want to run your tests inside of a browser, the recommended approach to using `mount` is to depend on a library called [jsdom](https://github.com/jsdom/jsdom) which is essentially a headless browser implemented completely in JS. **Note**: unlike shallow or static rendering, full rendering actually mounts the component in the DOM, which means that tests can affect each other if they are all using the same DOM. Keep that in mind while writing your tests and, if necessary, use [`.unmount()`](ReactWrapper/unmount.md) or something similar as cleanup. ```jsx import { mount } from 'enzyme'; import sinon from 'sinon'; import Foo from './Foo'; describe('', () => { it('calls componentDidMount', () => { sinon.spy(Foo.prototype, 'componentDidMount'); const wrapper = mount(); expect(Foo.prototype.componentDidMount).to.have.property('callCount', 1); }); it('allows us to set props', () => { const wrapper = mount(); expect(wrapper.props().bar).to.equal('baz'); wrapper.setProps({ bar: 'foo' }); expect(wrapper.props().bar).to.equal('foo'); }); it('simulates click events', () => { const onButtonClick = sinon.spy(); const wrapper = mount(( )); wrapper.find('button').simulate('click'); expect(onButtonClick).to.have.property('callCount', 1); }); }); ``` ## `mount(node[, options]) => ReactWrapper` #### Arguments 1. `node` (`ReactElement`): The node to render 2. `options` (`Object` [optional]): - `options.context`: (`Object` [optional]): Context to be passed into the component - `options.attachTo`: (`DOMElement` [optional]): DOM Element to attach the component to. - `options.childContextTypes`: (`Object` [optional]): Merged contextTypes for all children of the wrapper. - `options.wrappingComponent`: (`ComponentType` [optional]): A component that will render as a parent of the `node`. It can be used to provide context to the `node`, among other things. See the [`getWrappingComponent()` docs](ReactWrapper/getWrappingComponent.md) for an example. **Note**: `wrappingComponent` _must_ render its children. - `options.wrappingComponentProps`: (`Object` [optional]): Initial props to pass to the `wrappingComponent` if it is specified. #### Returns `ReactWrapper`: The wrapper instance around the rendered output. ## ReactWrapper API #### [`.find(selector) => ReactWrapper`](ReactWrapper/find.md) Find every node in the render tree that matches the provided selector. #### [`.findWhere(predicate) => ReactWrapper`](ReactWrapper/findWhere.md) Find every node in the render tree that returns true for the provided predicate function. #### [`.filter(selector) => ReactWrapper`](ReactWrapper/filter.md) Remove nodes in the current wrapper that do not match the provided selector. #### [`.filterWhere(predicate) => ReactWrapper`](ReactWrapper/filterWhere.md) Remove nodes in the current wrapper that do not return true for the provided predicate function. #### [`.hostNodes() => ReactWrapper`](ReactWrapper/hostNodes.md) Removes nodes that are not host nodes; e.g., this will only return HTML nodes. #### [`.contains(nodeOrNodes) => Boolean`](ReactWrapper/contains.md) Returns whether or not a given node or array of nodes exists in the render tree. #### [`.containsMatchingElement(node) => Boolean`](ReactWrapper/containsMatchingElement.md) Returns whether or not a given react element exists in the render tree. #### [`.containsAllMatchingElements(nodes) => Boolean`](ReactWrapper/containsAllMatchingElements.md) Returns whether or not all the given react elements exist in the render tree. #### [`.containsAnyMatchingElements(nodes) => Boolean`](ReactWrapper/containsAnyMatchingElements.md) Returns whether or not one of the given react elements exist in the render tree. #### [`.equals(node) => Boolean`](ReactWrapper/equals.md) Returns whether or not the current wrapper root node render tree looks like the one passed in. #### [`.hasClass(className) => Boolean`](ReactWrapper/hasClass.md) Returns whether or not the current root node has the given class name or not. #### [`.is(selector) => Boolean`](ReactWrapper/is.md) Returns whether or not the current node matches a provided selector. #### [`.exists([selector]) => Boolean`](ReactWrapper/exists.md) Returns whether or not the current node exists, or, if given a selector, whether that selector has any matching results. #### [`.isEmpty() => Boolean`](ReactWrapper/isEmpty.md) *Deprecated*: Use [`.exists()`](ReactWrapper/exists.md) instead. #### [`.isEmptyRender() => Boolean`](ReactWrapper/isEmptyRender.md) Returns whether or not the current component returns a falsy value. #### [`.not(selector) => ReactWrapper`](ReactWrapper/not.md) Remove nodes in the current wrapper that match the provided selector. (inverse of `.filter()`) #### [`.children([selector]) => ReactWrapper`](ReactWrapper/children.md) Get a wrapper with all of the children nodes of the current wrapper. #### [`.childAt(index) => ReactWrapper`](ReactWrapper/childAt.md) Returns a new wrapper with child at the specified index. #### [`.parents([selector]) => ReactWrapper`](ReactWrapper/parents.md) Get a wrapper with all of the parents (ancestors) of the current node. #### [`.parent() => ReactWrapper`](ReactWrapper/parent.md) Get a wrapper with the direct parent of the current node. #### [`.closest(selector) => ReactWrapper`](ReactWrapper/closest.md) Get a wrapper with the first ancestor of the current node to match the provided selector. #### [`.render() => CheerioWrapper`](ReactWrapper/render.md) Returns a CheerioWrapper of the current node's subtree. #### [`.renderProp(key)() => ReactWrapper`](ReactWrapper/renderProp.md) Returns a wrapper of the node rendered by the provided render prop. #### [`.text() => String`](ReactWrapper/text.md) Returns a string representation of the text nodes in the current render tree. #### [`.html() => String`](ReactWrapper/html.md) Returns a static HTML rendering of the current node. #### [`.get(index) => ReactElement`](ReactWrapper/get.md) Returns the node at the provided index of the current wrapper. #### [`.getDOMNode() => DOMComponent`](ReactWrapper/getDOMNode.md) Returns the outer most DOMComponent of the current wrapper. #### [`.getElement() => ReactElement`](ReactWrapper/getElement.md) Returns the wrapped ReactElement. #### [`.getElements() => Array`](ReactWrapper/getElements.md) Returns the wrapped ReactElements. #### [`.at(index) => ReactWrapper`](ReactWrapper/at.md) Returns a wrapper of the node at the provided index of the current wrapper. #### [`.first() => ReactWrapper`](ReactWrapper/first.md) Returns a wrapper of the first node of the current wrapper. #### [`.last() => ReactWrapper`](ReactWrapper/last.md) Returns a wrapper of the last node of the current wrapper. #### [`.state([key]) => Any`](ReactWrapper/state.md) Returns the state of the root component. #### [`.context([key]) => Any`](ReactWrapper/context.md) Returns the context of the root component. #### [`.props() => Object`](ReactWrapper/props.md) Returns the props of the root component. #### [`.prop(key) => Any`](ReactWrapper/prop.md) Returns the named prop of the root component. #### [`.invoke(propName)(...args) => Any`](ReactWrapper/invoke.md) Invokes a prop function on the current node and returns the function's return value. #### [`.key() => String`](ReactWrapper/key.md) Returns the key of the root component. #### [`.simulate(event[, mock]) => ReactWrapper`](ReactWrapper/simulate.md) Simulates an event on the current node. #### [`.setState(nextState) => ReactWrapper`](ReactWrapper/setState.md) Manually sets state of the root component. #### [`.setProps(nextProps[, callback]) => ReactWrapper`](ReactWrapper/setProps.md) Manually sets props of the root component. #### [`.setContext(context) => ReactWrapper`](ReactWrapper/setContext.md) Manually sets context of the root component. #### [`.instance() => ReactComponent|DOMComponent`](ReactWrapper/instance.md) Returns the wrapper's underlying instance. #### [`.getWrappingComponent() => ReactWrapper`](ReactWrapper/getWrappingComponent.md) Returns a wrapper representing the `wrappingComponent`, if one was passed. #### [`.unmount() => ReactWrapper`](ReactWrapper/unmount.md) A method that un-mounts the component. #### [`.mount() => ReactWrapper`](ReactWrapper/mount.md) A method that re-mounts the component. #### [`.update() => ReactWrapper`](ReactWrapper/update.md) Syncs the enzyme component tree snapshot with the react component tree. #### [`.debug() => String`](ReactWrapper/debug.md) Returns a string representation of the current render tree for debugging purposes. #### [`.type() => String|Function`](ReactWrapper/type.md) Returns the type of the current node of the wrapper. #### [`.name() => String`](ReactWrapper/name.md) Returns the name of the current node of the wrapper. #### [`.forEach(fn) => ReactWrapper`](ReactWrapper/forEach.md) Iterates through each node of the current wrapper and executes the provided function #### [`.map(fn) => Array`](ReactWrapper/map.md) Maps the current array of nodes to another array. #### [`.matchesElement(node) => Boolean`](ReactWrapper/matchesElement.md) Returns whether or not a given react element matches the current render tree. #### [`.reduce(fn[, initialValue]) => Any`](ReactWrapper/reduce.md) Reduces the current array of nodes to a value #### [`.reduceRight(fn[, initialValue]) => Any`](ReactWrapper/reduceRight.md) Reduces the current array of nodes to a value, from right to left. #### [`.slice([begin[, end]]) => ReactWrapper`](ReactWrapper/slice.md) Returns a new wrapper with a subset of the nodes of the original wrapper, according to the rules of `Array#slice`. #### [`.tap(intercepter) => Self`](ReactWrapper/tap.md) Taps into the wrapper method chain. Helpful for debugging. #### [`.some(selector) => Boolean`](ReactWrapper/some.md) Returns whether or not any of the nodes in the wrapper match the provided selector. #### [`.someWhere(predicate) => Boolean`](ReactWrapper/someWhere.md) Returns whether or not any of the nodes in the wrapper pass the provided predicate function. #### [`.every(selector) => Boolean`](ReactWrapper/every.md) Returns whether or not all of the nodes in the wrapper match the provided selector. #### [`.everyWhere(predicate) => Boolean`](ReactWrapper/everyWhere.md) Returns whether or not all of the nodes in the wrapper pass the provided predicate function. #### [`.ref(refName) => ReactComponent | HTMLElement`](ReactWrapper/ref.md) Returns the node that matches the provided reference name. #### [`.detach() => void`](ReactWrapper/detach.md) Unmount the component from the DOM node it's attached to. ================================================ FILE: docs/api/render.md ================================================ # Static Rendering API Use enzyme's `render` function to generate HTML from your React tree, and analyze the resulting HTML structure. `render` returns a wrapper very similar to the other renderers in enzyme, [`mount`](mount.md) and [`shallow`](shallow.md); however, `render` uses a third party HTML parsing and traversal library [Cheerio](https://cheerio.js.org). We believe that Cheerio handles parsing and traversing HTML extremely well, and duplicating this functionality ourselves would be a disservice. For the purposes of this documentation, we will refer to Cheerio's constructor as `CheerioWrapper`, which is to say that it is analogous to our `ReactWrapper` and `ShallowWrapper` constructors. You can reference the [Cheerio API docs](https://github.com/cheeriojs/cheerio#api) for methods available on a `CheerioWrapper` instance. ### Example Usage ```jsx import React from 'react'; import { render } from 'enzyme'; import PropTypes from 'prop-types'; describe('', () => { it('renders three `.foo-bar`s', () => { const wrapper = render(); expect(wrapper.find('.foo-bar')).to.have.lengthOf(3); }); it('rendered the title', () => { const wrapper = render(); expect(wrapper.text()).to.contain('unique'); }); it('renders a div', () => { const wrapper = render(
); expect(wrapper.html()).to.contain('div'); }); it('can pass in context', () => { function SimpleComponent(props, context) { const { name } = context; return
{name}
; } SimpleComponent.contextTypes = { name: PropTypes.string, }; const context = { name: 'foo' }; const wrapper = render(, { context }); expect(wrapper.text()).to.equal('foo'); }); }); ``` ================================================ FILE: docs/api/selector.md ================================================ # enzyme Selectors Many methods in enzyme’s API accept a *selector* as an argument. You can select several different ways: ### 1. A Valid CSS Selector enzyme supports a subset of valid CSS selectors to find nodes inside a render tree. Support is as follows: - class syntax (`.foo`, `.foo-bar`, etc.) - element tag name syntax (`input`, `div`, `span`, etc.) - id syntax (`#foo`, `#foo-bar`, etc.) - attribute syntax (`[href="foo"]`, `[type="text"]`, and the other attribute selectors listed [here](https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Attribute_selectors).) - universal syntax (`*`) - React component name and props (`Button`, `Button[type="submit"]`, etc) - however, please note that it is strongly encouraged to find by component constructor/function and not by display name. The attribute syntax also works by value, rather than by string. Strings, numbers, and boolean property values are supported. Example: ```js const wrapper = mount((
)); ``` The selector `[anum=3]` will select the first but not the second, because there's no quotes surrounding the 3. The selector `[anum="3"]` will select the second, because it's explicitly looking for a string because of the quotes surrounding 3. The same goes for the boolean; [abool=false] will select the first but not the second, etc. Further, enzyme supports combining any of those supported syntaxes together, as with CSS: ```css div.foo.bar input#input-name a[href="foo"] .foo .bar .foo > .bar .foo + .bar .foo ~ .bar .foo input ``` **React Key and Ref Props** While in most cases, any React prop can be used, there are exceptions. The `key` and `ref` props will never work; React uses these props internally. **Want more CSS support?** PRs implementing more support for CSS selectors will be accepted and is an area of development for enzyme that will likely be focused on in the future. ### 2. A React Component Constructor enzyme allows you to find React components based on their constructor. You can pass in the reference to the component’s constructor. Of course, this kind of selector only checks the component type; it ignores props and children. ```jsx function MyComponent() { return
; } // find instances of MyComponent const myComponents = wrapper.find(MyComponent); ``` ### 3. A React Component’s displayName enzyme allows you to find components based on a component’s `displayName`. If a component exists in a render tree where its `displayName` is set and has its first character as a capital letter, you can use a string to find it: ```jsx function MyComponent() { return
; } MyComponent.displayName = 'My Component'; // find instances of MyComponent const myComponents = wrapper.find('My Component'); ``` NOTE: This will *only* work if the selector (and thus the component’s `displayName`) is a string starting with a capital letter. Strings starting with lower case letters will be assumed to be a CSS selector (therefore a tag name). Selecting a HOC-wrapped component, or a component with a custom `displayName`, even with lowercase letters (for example, `withHOC(MyComponent)`) will work as well. ### 4. Object Property Selector enzyme allows you to find components and nodes based on a subset of their properties: ```jsx const wrapper = mount((
)); wrapper.find({ foo: 3 }); wrapper.find({ bar: false }); wrapper.find({ title: 'baz' }); ``` **Undefined Properties** Undefined properties are not allowed in the object property selector and will cause an error: ```jsx wrapper.find({ foo: 3, bar: undefined }); // => TypeError: Enzyme::Props can't have 'undefined' values. Try using 'findWhere()' instead. ``` If you have to search by `undefined` property value, use [`.findWhere()`](ShallowWrapper/findWhere.md). ================================================ FILE: docs/api/shallow.md ================================================ # Shallow Rendering API Shallow rendering is useful to constrain yourself to testing a component as a unit, and to ensure that your tests aren't indirectly asserting on behavior of child components. As of Enzyme v3, the `shallow` API does call React lifecycle methods such as `componentDidMount` and `componentDidUpdate`. You can read more about this in the [version 3 migration guide](../guides/migration-from-2-to-3.md#lifecycle-methods). ```jsx import { shallow } from 'enzyme'; import sinon from 'sinon'; import Foo from './Foo'; describe('', () => { it('renders three components', () => { const wrapper = shallow(); expect(wrapper.find(Foo)).to.have.lengthOf(3); }); it('renders an `.icon-star`', () => { const wrapper = shallow(); expect(wrapper.find('.icon-star')).to.have.lengthOf(1); }); it('renders children when passed in', () => { const wrapper = shallow((
)); expect(wrapper.contains(
)).to.equal(true); }); it('simulates click events', () => { const onButtonClick = sinon.spy(); const wrapper = shallow(); wrapper.find('button').simulate('click'); expect(onButtonClick).to.have.property('callCount', 1); }); }); ``` ## `shallow(node[, options]) => ShallowWrapper` #### Arguments 1. `node` (`ReactElement`): The node to render 2. `options` (`Object` [optional]): - `options.context`: (`Object` [optional]): Context to be passed into the component - `options.disableLifecycleMethods`: (`Boolean` [optional]): If set to true, `componentDidMount` is not called on the component, and `componentDidUpdate` is not called after [`setProps`](ShallowWrapper/setProps.md) and [`setContext`](ShallowWrapper/setContext.md). Default to `false`. - `options.wrappingComponent`: (`ComponentType` [optional]): A component that will render as a parent of the `node`. It can be used to provide context to the `node`, among other things. See the [`getWrappingComponent()` docs](ShallowWrapper/getWrappingComponent.md) for an example. **Note**: `wrappingComponent` _must_ render its children. - `options.wrappingComponentProps`: (`Object` [optional]): Initial props to pass to the `wrappingComponent` if it is specified. - `options.suspenseFallback`: (`Boolean` [optional]): If set to true, when rendering `Suspense` enzyme will replace all the lazy components in children with `fallback` element prop. Otherwise it won't handle fallback of lazy component. Default to `true`. Note: not supported in React < 16.6. #### Returns `ShallowWrapper`: The wrapper instance around the rendered output. ## ShallowWrapper API #### [`.find(selector) => ShallowWrapper`](ShallowWrapper/find.md) Find every node in the render tree that matches the provided selector. #### [`.findWhere(predicate) => ShallowWrapper`](ShallowWrapper/findWhere.md) Find every node in the render tree that returns true for the provided predicate function. #### [`.filter(selector) => ShallowWrapper`](ShallowWrapper/filter.md) Remove nodes in the current wrapper that do not match the provided selector. #### [`.filterWhere(predicate) => ShallowWrapper`](ShallowWrapper/filterWhere.md) Remove nodes in the current wrapper that do not return true for the provided predicate function. #### [`.hostNodes() => ShallowWrapper`](ShallowWrapper/hostNodes.md) Removes nodes that are not host nodes; e.g., this will only return HTML nodes. #### [`.contains(nodeOrNodes) => Boolean`](ShallowWrapper/contains.md) Returns whether or not a given node or array of nodes is somewhere in the render tree. #### [`.containsMatchingElement(node) => Boolean`](ShallowWrapper/containsMatchingElement.md) Returns whether or not a given react element exists in the shallow render tree. #### [`.containsAllMatchingElements(nodes) => Boolean`](ShallowWrapper/containsAllMatchingElements.md) Returns whether or not all the given react elements exist in the shallow render tree. #### [`.containsAnyMatchingElements(nodes) => Boolean`](ShallowWrapper/containsAnyMatchingElements.md) Returns whether or not one of the given react elements exists in the shallow render tree. #### [`.equals(node) => Boolean`](ShallowWrapper/equals.md) Returns whether or not the current render tree is equal to the given node, based on the expected value. #### [`.matchesElement(node) => Boolean`](ShallowWrapper/matchesElement.md) Returns whether or not a given react element matches the shallow render tree. #### [`.hasClass(className) => Boolean`](ShallowWrapper/hasClass.md) Returns whether or not the current node has the given class name or not. #### [`.is(selector) => Boolean`](ShallowWrapper/is.md) Returns whether or not the current node matches a provided selector. #### [`.exists([selector]) => Boolean`](ShallowWrapper/exists.md) Returns whether or not the current node exists, or, if given a selector, whether that selector has any matching results. #### [`.isEmpty() => Boolean`](ShallowWrapper/isEmpty.md) *Deprecated*: Use [`.exists()`](ShallowWrapper/exists.md) instead. #### [`.isEmptyRender() => Boolean`](ShallowWrapper/isEmptyRender.md) Returns whether or not the current component returns a falsy value. #### [`.not(selector) => ShallowWrapper`](ShallowWrapper/not.md) Remove nodes in the current wrapper that match the provided selector. (inverse of `.filter()`) #### [`.children([selector]) => ShallowWrapper`](ShallowWrapper/children.md) Get a wrapper with all of the children nodes of the current wrapper. #### [`.childAt(index) => ShallowWrapper`](ShallowWrapper/childAt.md) Returns a new wrapper with child at the specified index. #### [`.parents([selector]) => ShallowWrapper`](ShallowWrapper/parents.md) Get a wrapper with all of the parents (ancestors) of the current node. #### [`.parent() => ShallowWrapper`](ShallowWrapper/parent.md) Get a wrapper with the direct parent of the current node. #### [`.closest(selector) => ShallowWrapper`](ShallowWrapper/closest.md) Get a wrapper with the first ancestor of the current node to match the provided selector. #### [`.shallow([options]) => ShallowWrapper`](ShallowWrapper/shallow.md) Shallow renders the current node and returns a shallow wrapper around it. #### [`.render() => CheerioWrapper`](ShallowWrapper/render.md) Returns a CheerioWrapper of the current node's subtree. #### [`.renderProp(key)() => ShallowWrapper`](ShallowWrapper/renderProp.md) Returns a wrapper of the node rendered by the provided render prop. #### [`.unmount() => ShallowWrapper`](ShallowWrapper/unmount.md) A method that un-mounts the component. #### [`.text() => String`](ShallowWrapper/text.md) Returns a string representation of the text nodes in the current render tree. #### [`.html() => String`](ShallowWrapper/html.md) Returns a static HTML rendering of the current node. #### [`.get(index) => ReactElement`](ShallowWrapper/get.md) Returns the node at the provided index of the current wrapper. #### [`.getElement() => ReactElement`](ShallowWrapper/getElement.md) Returns the wrapped ReactElement. #### [`.getElements() => Array`](ShallowWrapper/getElements.md) Returns the wrapped ReactElements. #### [`.at(index) => ShallowWrapper`](ShallowWrapper/at.md) Returns a wrapper of the node at the provided index of the current wrapper. #### [`.first() => ShallowWrapper`](ShallowWrapper/first.md) Returns a wrapper of the first node of the current wrapper. #### [`.last() => ShallowWrapper`](ShallowWrapper/last.md) Returns a wrapper of the last node of the current wrapper. #### [`.state([key]) => Any`](ShallowWrapper/state.md) Returns the state of the root component. #### [`.context([key]) => Any`](ShallowWrapper/context.md) Returns the context of the root component. #### [`.props() => Object`](ShallowWrapper/props.md) Returns the props of the current node. #### [`.prop(key) => Any`](ShallowWrapper/prop.md) Returns the named prop of the current node. #### [`.key() => String`](ShallowWrapper/key.md) Returns the key of the current node. #### [`.invoke(propName)(...args) => Any`](ShallowWrapper/invoke.md) Invokes a prop function on the current node and returns the function's return value. #### [`.simulate(event[, data]) => ShallowWrapper`](ShallowWrapper/simulate.md) Simulates an event on the current node. #### [`.setState(nextState) => ShallowWrapper`](ShallowWrapper/setState.md) Manually sets state of the root component. #### [`.setProps(nextProps[, callback]) => ShallowWrapper`](ShallowWrapper/setProps.md) Manually sets props of the root component. #### [`.setContext(context) => ShallowWrapper`](ShallowWrapper/setContext.md) Manually sets context of the root component. #### [`.getWrappingComponent() => ShallowWrapper`](ShallowWrapper/getWrappingComponent.md) Returns a wrapper representing the `wrappingComponent`, if one was passed. #### [`.instance() => ReactComponent`](ShallowWrapper/instance.md) Returns the instance of the root component. #### [`.update() => ShallowWrapper`](ShallowWrapper/update.md) Syncs the enzyme component tree snapshot with the react component tree. #### [`.debug() => String`](ShallowWrapper/debug.md) Returns a string representation of the current shallow render tree for debugging purposes. #### [`.type() => String|Function|null`](ShallowWrapper/type.md) Returns the type of the current node of the wrapper. #### [`.name() => String`](ShallowWrapper/name.md) Returns the name of the current node of the wrapper. #### [`.forEach(fn) => ShallowWrapper`](ShallowWrapper/forEach.md) Iterates through each node of the current wrapper and executes the provided function #### [`.map(fn) => Array`](ShallowWrapper/map.md) Maps the current array of nodes to another array. #### [`.reduce(fn[, initialValue]) => Any`](ShallowWrapper/reduce.md) Reduces the current array of nodes to a value #### [`.reduceRight(fn[, initialValue]) => Any`](ShallowWrapper/reduceRight.md) Reduces the current array of nodes to a value, from right to left. #### [`.slice([begin[, end]]) => ShallowWrapper`](ShallowWrapper/slice.md) Returns a new wrapper with a subset of the nodes of the original wrapper, according to the rules of `Array#slice`. #### [`.tap(intercepter) => Self`](ShallowWrapper/tap.md) Taps into the wrapper method chain. Helpful for debugging. #### [`.some(selector) => Boolean`](ShallowWrapper/some.md) Returns whether or not any of the nodes in the wrapper match the provided selector. #### [`.someWhere(predicate) => Boolean`](ShallowWrapper/someWhere.md) Returns whether or not any of the nodes in the wrapper pass the provided predicate function. #### [`.every(selector) => Boolean`](ShallowWrapper/every.md) Returns whether or not all of the nodes in the wrapper match the provided selector. #### [`.everyWhere(predicate) => Boolean`](ShallowWrapper/everyWhere.md) Returns whether or not all of the nodes in the wrapper pass the provided predicate function. #### [`.dive([options]) => ShallowWrapper`](ShallowWrapper/dive.md) Shallow render the one non-DOM child of the current wrapper, and return a wrapper around the result. ================================================ FILE: docs/common-issues.md ================================================ # Common Issues This list aims to be comprehensive. If you find an issue that has been frequently brought up in GitHub *Issues* that is not here, please open a PR to add it. ### Query Selector fails ###### Reason This could be due to a regression, or the feature is not yet implemented. If you are wanting to use a certain query syntax, make sure it is implemented first before raising an issue. Here is the list of selectors we currently support: https://github.com/enzymejs/enzyme/blob/master/docs/api/selector.md ### Nested component may not be updated after wrapper updates Assume we have a simple component with an `` and a `
); } } ``` This is a basic "counter" component in React. Here our resulting markup is a function of `this.state.count`, which can get updated by the `increment` and `decrement` functions. Let's take a look at what some enzyme tests with this component might look like, and when we do or don't have to call `update()`. ```js const wrapper = shallow(); wrapper.find('.count').text(); // => "Count: 0" ``` As we can see, we can easily assert on the text and the count of this component. But we haven't caused any state changes yet. Let's see what it looks like when we simulate a `click` event on the increment and decrement buttons: ```js const wrapper = shallow(); wrapper.find('.count').text(); // => "Count: 0" wrapper.find('.inc').simulate('click'); wrapper.find('.count').text(); // => "Count: 1" wrapper.find('.inc').simulate('click'); wrapper.find('.count').text(); // => "Count: 2" wrapper.find('.dec').simulate('click'); wrapper.find('.count').text(); // => "Count: 1" ``` In this case enzyme will automatically check for updates after an event simulation takes place, as it knows that this is a very common place for state changes to occur. In this case there is no difference between v2 and v3. Let's consider a different way this test could have been written. ```js const wrapper = shallow(); wrapper.find('.count').text(); // => "Count: 0" wrapper.instance().increment(); wrapper.find('.count').text(); // => "Count: 0" (would have been "Count: 1" in v2) wrapper.instance().increment(); wrapper.find('.count').text(); // => "Count: 0" (would have been "Count: 2" in v2) wrapper.instance().decrement(); wrapper.find('.count').text(); // => "Count: 0" (would have been "Count: 1" in v2) ``` The problem here is that once we grab the instance using `wrapper.instance()`, enzyme has no way of knowing if you are going to execute something that will cause a state transition, and thus does not know when to ask for an updated render tree from React. As a result, `.text()` never changes value. The fix here is to use enzyme's `wrapper.update()` method after a state change has occurred: ```js const wrapper = shallow(); wrapper.find('.count').text(); // => "Count: 0" wrapper.instance().increment(); wrapper.update(); wrapper.find('.count').text(); // => "Count: 1" wrapper.instance().increment(); wrapper.update(); wrapper.find('.count').text(); // => "Count: 2" wrapper.instance().decrement(); wrapper.update(); wrapper.find('.count').text(); // => "Count: 1" ``` In practice we have found that this isn't actually needed that often, and when it is it is not difficult to add. Additionally, having the enzyme wrapper automatically update alongside the real render tree can result in flaky tests when writing asynchronous tests. This breaking change was worth the architectural benefits of the new adapter system in v3, and we believe is a better choice for an assertion library to take. ## `ref(refName)` now returns the actual ref instead of a wrapper In enzyme v2, the wrapper returned from `mount(...)` had a prototype method on it `ref(refName)` that returned a wrapper around the actual element of that ref. This has now been changed to return the actual ref, which we believe is a more intuitive API. Consider the following simple react component: ```js class Box extends React.Component { render() { return
Hello
; } } ``` In this case we can call `.ref('abc')` on a wrapper of `Box`. In this case it will return a wrapper around the rendered div. To demonstrate, we can see that both `wrapper` and the result of `ref(...)` share the same constructor: ```js const wrapper = mount(); // this is what would happen with enzyme v2 expect(wrapper.ref('abc')).toBeInstanceOf(wrapper.constructor); ``` In v3, the contract is slightly changed. The ref is exactly what React would assign as the ref. In this case, it would be a DOM Element: ```js const wrapper = mount(); // this is what happens with enzyme v3 expect(wrapper.ref('abc')).toBeInstanceOf(Element); ``` Similarly, if you have a ref on a composite component, the `ref(...)` method will return an instance of that element: ```js class Bar extends React.Component { render() { return ; } } ``` ```js const wrapper = mount(); expect(wrapper.ref('abc')).toBeInstanceOf(Box); ``` In our experience, this is most often what people would actually want and expect out of the `.ref(...)` method. To get the wrapper that was returned by enzyme 2: ```js const wrapper = mount(); const refWrapper = wrapper.findWhere((n) => n.instance() === wrapper.ref('abc')); ``` ## With `mount`, `.instance()` can be called at any level of the tree enzyme now allows for you to grab the `instance()` of a wrapper at any level of the render tree, not just at the root. This means that you can `.find(...)` a specific component, then grab its instance and call `.setState(...)` or any other methods on the instance that you'd like. ## With `mount`, `.getNode()` should not be used. `.instance()` does what it used to. For `mount` wrappers, the `.getNode()` method used to return the actual component instance. This method no longer exists, but `.instance()` is functionally equivalent to what `.getNode()` used to be. ## With `shallow`, `.getNode()` should be replaced with `getElement()` For shallow wrappers, if you were previously using `.getNode()`, you will want to replace those calls with `.getElement()`, which is now functionally equivalent to what `.getNode()` used to do. One caveat is that previously `.getNode()` would return the actual element instance that was created in the `render` function of the component you were testing, but now it will be a structurally equal react element, but not referentially equal. Your tests will need to be updated to account for this. ## Private properties and methods have been removed There are several properties that are on an enzyme "wrapper" that were considered to be private and were undocumented as a result. Despite being undocumented, people may have been relying on them. In an effort to make making changes less likely to be accidentally breaking in the future, we have decided to make these properties properly "private". The following properties will no longer be accessible on enzyme `shallow` or `mount` instances: - `.node` - `.nodes` - `.renderer` - `.unrendered` - `.root` - `.options` ## Cheerio has been updated, thus `render(...)` has been updated as well enzyme's top level `render` API returns a [Cheerio](https://github.com/cheeriojs/cheerio) object. The version of Cheerio that we use has been upgraded to 1.0.0. For debugging issues across enzyme v2.x and v3.x with the `render` API, we recommend checking out [Cheerio's Changelog](https://github.com/cheeriojs/cheerio/blob/48eae25c93702a29b8cd0d09c4a2dce2f912d1f4/History.md) and posting an issue on that repo instead of enzyme's unless you believe it is a bug in enzyme's use of the library. ## CSS Selector enzyme v3 now uses a real CSS selector parser rather than its own incomplete parser implementation. This is done with [rst-selector-parser](https://github.com/aweary/rst-selector-parser) a fork of [scalpel](https://github.com/gajus/scalpel/) which is a CSS parser implemented with [nearley](https://nearley.js.org/). We don't think this should cause any breakages across enzyme v2.x to v3.x, but if you believe you have found something that did indeed break, please file an issue with us. Thank you to [Brandon Dail](https://github.com/aweary) for making this happen! ## CSS Selector results and `hostNodes()` enzyme v3 now returns **all** nodes in the result set and not just html nodes. Consider this example: ```js function HelpLink({ text, ...rest }) { return {text}; } function HelpLinkContainer({ text, ...rest }) { return ; } const wrapper = mount(); ``` In enzyme v3, the expression `wrapper.find("[aria-expanded=true]").length)` will return 3 and not 1 as in previous versions. A closer look using [`debug`](../api/ReactWrapper/debug.md) reveals: ```jsx // console.log(wrapper.find('[aria-expanded="true"]').debug()); foo foo foo ``` To return only the html nodes use the [`hostNodes()`](../api/ReactWrapper/hostNodes.md) function. `wrapper.find("[aria-expanded=true]").hostNodes().debug()` will now return: ```jsx foo; ``` ## Node Equality now ignores `undefined` values We have updated enzyme to consider node "equality" in a semantically identical way to how react treats nodes. More specifically, we've updated enzyme's algorithms to treat `undefined` props as equivalent to the absence of a prop. Consider the following example: ```js class Foo extends React.Component { render() { const { foo, bar } = this.props; return
; } } ``` With this component, the behavior in enzyme v2.x the behavior would have been like: ```js const wrapper = shallow(); wrapper.equals(
); // => false wrapper.equals(
); // => true ``` With enzyme v3, the behavior is now as follows: ```js const wrapper = shallow(); wrapper.equals(
); // => true wrapper.equals(
); // => true ``` ## Lifecycle methods enzyme v2.x had an optional flag that could be passed in to all `shallow` calls which would make it so that more of the component's lifecycle methods were called (such as `componentDidMount` and `componentDidUpdate`). With enzyme v3, we have now turned on this mode by default, instead of making it opt-in. It is now possible to *opt-out* instead. Additionally, you can now opt-out at a global level. If you'd like to opt out globally, you can run the following: ```js import Enzyme from 'enzyme'; Enzyme.configure({ disableLifecycleMethods: true }); ``` This will default enzyme back to the previous behavior globally. If instead you'd only like to opt enzyme to the previous behavior for a specific test, you can do the following: ```js import { shallow } from 'enzyme'; // ... const wrapper = shallow(, { disableLifecycleMethods: true }); ``` ================================================ FILE: docs/guides/mocha.md ================================================ # Using enzyme with Mocha enzyme was originally designed to work with Mocha, so getting it up and running with Mocha should be no problem at all. Simply install it and start using it: ```bash npm i --save-dev enzyme ``` ```jsx import React from 'react'; import { expect } from 'chai'; import { mount } from 'enzyme'; import { spy } from 'sinon'; import Foo from './src/Foo'; spy(Foo.prototype, 'componentDidMount'); describe('', () => { it('calls componentDidMount', () => { const wrapper = mount(); expect(Foo.prototype.componentDidMount).to.have.property('callCount', 1); }); }); ``` ================================================ FILE: docs/guides/react-native.md ================================================ # Using enzyme to Test Components in React Native As of v0.18, React Native uses React as a dependency rather than a forked version of the library, which means it is now possible to use enzyme's `shallow` with React Native components. Unfortunately, React Native has many environmental dependencies that can be hard to simulate without a host device. This can be difficult when you want your test suite to run with typical Continuous Integration servers such as Travis. To use enzyme to test React Native, you currently need to configure an adapter, and load an emulated DOM. ## Configuring an Adapter While a React Native adapter is [in discussion](https://github.com/enzymejs/enzyme/issues/1436), a standard adapter may be used, such as 'enzyme-adapter-react-16': ```jsx import Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({ adapter: new Adapter() }); ``` ## Loading an emulated DOM with JSDOM To use enzyme's `mount` until a React Native adapter exists, an emulated DOM must be loaded. While some have had success with [react-native-mock-renderer](https://github.com/Root-App/react-native-mock-render), the recommended approach is to use [JSDOM](https://github.com/jsdom/jsdom), as documented for enzyme at the [JSDOM](https://enzymejs.github.io/enzyme/docs/guides/jsdom.html) documentation page. JSDOM will allow all of the `enzyme` behavior you would expect. While Jest snapshot testing can be used with this approach as well, it isn't encouraged and is only supported through `wrapper.debug()`. ## Using enzyme's find when lacking className props It is worth noting that React Native allows for a [testID](https://facebook.github.io/react-native/docs/view#testid) prop, that can be used a selector similar to `className` in standard React: ```jsx {todo.title} ``` ```jsx expect(wrapper.findWhere((node) => node.prop('testID') === 'todo-item')).toExist(); ``` ## Default example configuration for Jest and JSDOM replacement To perform the necessary configuration in your testing framework, it is recommended to use a setup script, such as with Jest's `setupFilesAfterEnv` setting. Create or update a `jest.config.js` file at the root of your project to include the `setupFilesAfterEnv` setting: ```jsx // jest.config.js module.exports = { // Load setup-tests.js before test execution setupFilesAfterEnv: 'setup-tests.js', // ... }; ``` Then create or update the file specified in `setupFilesAfterEnv`, in this case `setup-tests.js` in the project root: ```jsx // setup-tests.js import 'react-native'; import 'jest-enzyme'; import Adapter from 'enzyme-adapter-react-16'; import Enzyme from 'enzyme'; /** * Set up DOM in node.js environment for Enzyme to mount to */ const { JSDOM } = require('jsdom'); const jsdom = new JSDOM(''); const { window } = jsdom; function copyProps(src, target) { Object.defineProperties(target, { ...Object.getOwnPropertyDescriptors(src), ...Object.getOwnPropertyDescriptors(target), }); } global.window = window; global.document = window.document; global.navigator = { userAgent: 'node.js', }; copyProps(window, global); /** * Set up Enzyme to mount to DOM, simulate events, * and inspect the DOM in tests. */ Enzyme.configure({ adapter: new Adapter() }); ``` ## Configure enzyme with other test libraries and include JSDOM on the fly Update the file specified in `setupFilesAfterEnv`, in this case `setup-tests.js` in the project root: ```jsx import 'react-native'; import 'jest-enzyme'; import Adapter from 'enzyme-adapter-react-16'; import Enzyme from 'enzyme'; /** * Set up Enzyme to mount to DOM, simulate events, * and inspect the DOM in tests. */ Enzyme.configure({ adapter: new Adapter() }); ``` ### Create a separate test file Create a file prefixed with enzyme.test.ts for example `component.enzyme.test.js`: ```jsx /** * @jest-environment jsdom */ import React from 'react'; import { mount } from 'enzyme'; import { Text } from '../../../component/text'; describe('Component tested with enzyme', () => { test('App mount with enzyme', () => { const wrapper = mount(); // other tests operations }); }); ``` **The most important part is to ensure that the test runs with the `jestEnvironment` set to `jsdom`** - one way is to include a `/* @jest-environment jsdom */` comment at the top of the file. Then you should then be able to start writing tests! Note that you may want to perform some additional mocking around native components, or if you want to perform snapshot testing against React Native components. Notice how you may need to mock React Navigation's `KeyGenerator` in this case, to avoid random React keys that will cause snapshots to always fail. ```jsx import React from 'react'; import renderer from 'react-test-renderer'; import { mount, ReactWrapper } from 'enzyme'; import { Provider } from 'mobx-react'; import { Text } from 'native-base'; import { TodoItem } from './todo-item'; import { TodoList } from './todo-list'; import { todoStore } from '../../stores/todo-store'; // https://github.com/react-navigation/react-navigation/issues/2269 // React Navigation generates random React keys, which makes // snapshot testing fail. Mock the randomness to keep from failing. jest.mock('react-navigation/src/routers/KeyGenerator', () => ({ generateKey: jest.fn(() => 123), })); describe('todo-list', () => { describe('enzyme tests', () => { it('can add a Todo with Enzyme', () => { const wrapper = mount( , ); const newTodoText = 'I need to do something...'; const newTodoTextInput = wrapper.find('Input').first(); const addTodoButton = wrapper .find('Button') .findWhere((w) => w.text() === 'Add Todo') .first(); newTodoTextInput.props().onChangeText(newTodoText); // Enzyme usually allows wrapper.simulate() alternatively, but this doesn't support 'press' events. addTodoButton.props().onPress(); // Make sure to call update if external events (e.g. Mobx state changes) // result in updating the component props. wrapper.update(); // You can either check for a testID prop, similar to className in React: expect( wrapper.findWhere((node) => node.prop('testID') === 'todo-item'), ).toExist(); // Or even just find a component itself, if you broke the JSX out into its own component: expect(wrapper.find(TodoItem)).toExist(); // You can even do snapshot testing, // if you pull in enzyme-to-json and configure // it in snapshotSerializers in package.json expect(wrapper.find(TodoList)).toMatchSnapshot(); }); }); }); ``` ================================================ FILE: docs/guides/systemjs.md ================================================ # Using enzyme with SystemJS If you are using a test runner that runs code in a browser-based environment, you may be using [SystemJS]() in order to bundle your React code. Prior to enzyme 3.0 there were some issues with conditional requires that were used to maintain backwards compatibility with React versions. With enzyme 3.0+, this should no longer be an issue. If it is, please file a GitHub issue or make a PR to this documentation with instructions on how to set it up. ================================================ FILE: docs/guides/tape-ava.md ================================================ # Using enzyme with Tape and AVA enzyme works well with [Tape](https://github.com/substack/tape) and [AVA](https://github.com/avajs/ava). Simply install it and start using it: ```bash npm i --save-dev enzyme enzyme-adapter-react-16 ``` ## Tape ```jsx import test from 'tape'; import React from 'react'; import { shallow, mount, configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import Foo from '../path/to/foo'; configure({ adapter: new Adapter() }); test('shallow', (t) => { const wrapper = shallow(); t.equal(wrapper.contains(Foo), true); }); test('mount', (t) => { const wrapper = mount(); const fooInner = wrapper.find('.foo-inner'); t.equal(fooInner.is('.foo-inner'), true); }); ``` ## AVA ```jsx import test from 'ava'; import React from 'react'; import { shallow, mount, configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import Foo from '../path/to/foo'; configure({ adapter: new Adapter() }); test('shallow', (t) => { const wrapper = shallow(); t.is(wrapper.contains(Foo), true); }); test('mount', (t) => { const wrapper = mount(); const fooInner = wrapper.find('.foo-inner'); t.is(fooInner.is('.foo-inner'), true); }); ``` ## Example Projects - [enzyme-example-tape](https://github.com/TaeKimJR/enzyme-example-tape) - [enzyme-example-ava](https://github.com/mikenikles/enzyme-example-ava) ================================================ FILE: docs/guides/webpack.md ================================================ # Using enzyme with Webpack If you are using a test runner that runs code in a browser-based environment, you may be using [webpack](https://webpack.js.org/) in order to bundle your React code. Prior to enzyme 3.0 there were some issues with conditional requires that were used to maintain backwards compatibility with React versions. With enzyme 3.0+, this should no longer be an issue. If it is, please file a GitHub issue or make a PR to this documentation with instructions on how to set it up. ================================================ FILE: docs/guides.md ================================================ # enzyme Guides - [*Using enzyme with Browserify*](guides/browserify.md) - [*Using enzyme with Webpack*](guides/webpack.md) - [*Using enzyme with JSDOM*](guides/jsdom.md) - [*Using enzyme with Jest*](guides/jest.md) - [*Using enzyme with Karma*](guides/karma.md) - [*Using enzyme with Mocha*](guides/mocha.md) - [*Using enzyme with React Native*](guides/react-native.md) - [*Using enzyme with Lab*](guides/lab.md) - [*Using enzyme with Tape and AVA*](guides/tape-ava.md) ================================================ FILE: docs/installation/README.md ================================================ # Installation enzyme should be installed using npm: ```bash npm i --save-dev enzyme ``` enzyme can be used with your test runner of choice. All examples in the documentation will be provided using [mocha](https://mochajs.org/) and [BDD style chai](http://chaijs.com/api/bdd/), although neither library is a dependency of enzyme. {% include "./react-16.md" %} {% include "./react-15.md" %} {% include "./react-014.md" %} {% include "./react-013.md" %} ================================================ FILE: docs/installation/react-013.md ================================================ # Working with React 0.13 If you are wanting to use enzyme with React 0.13, but don't already have React 0.13 installed, you should do so: ```bash npm i react@0.13 --save ``` Next, to get started with enzyme, you can simply install it with npm: ```bash npm i --save-dev enzyme enzyme-adapter-react-13 ``` And then you're ready to go! In your test files you can simply `require` or `import` enzyme: ES6: ```js // setup file import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-13'; configure({ adapter: new Adapter() }); ``` ```js // test file import { shallow, mount, render } from 'enzyme'; const wrapper = shallow(); ``` ES5: ```js // setup file var enzyme = require('enzyme'); var Adapter = require('enzyme-adapter-react-13'); enzyme.configure({ adapter: new Adapter() }); ``` ```js // test file var enzyme = require('enzyme'); var wrapper = enzyme.shallow(); ``` ================================================ FILE: docs/installation/react-014.md ================================================ # Working with React 0.14 If you are wanting to use Enzyme with React 0.14, but don't already have React 0.14 and react-dom installed, you should do so: ```bash npm i --save react@0.14 react-dom@0.14 ``` Further, enzyme with React 0.14 requires the test utilities addon be installed: ```bash npm i --save-dev react-addons-test-utils@0.14 ``` Next, to get started with enzyme, you can simply install it with npm: ```bash npm i --save-dev enzyme enzyme-adapter-react-14 ``` And then you're ready to go! In your test files you can simply `require` or `import` enzyme: ES6: ```js // setup file import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-14'; configure({ adapter: new Adapter() }); ``` ```js // test file import { shallow, mount, render } from 'enzyme'; const wrapper = shallow(); ``` ES5: ```js // setup file var enzyme = require('enzyme'); var Adapter = require('enzyme-adapter-react-14'); enzyme.configure({ adapter: new Adapter() }); ``` ```js // test file var enzyme = require('enzyme'); var wrapper = enzyme.shallow(); ``` ================================================ FILE: docs/installation/react-15.md ================================================ # Working with React 15 If you are wanting to use Enzyme with React 15, but don't already have React 15 and react-dom installed, you should do so: ```bash npm i --save react@15 react-dom@15 ``` Further, enzyme requires the test utilities addon be installed: ```bash npm i --save-dev react-test-renderer@15 ``` Next, to get started with enzyme, you can simply install it with npm: ```bash npm i --save-dev enzyme enzyme-adapter-react-15 ``` And then you're ready to go! In your test files you can simply `require` or `import` enzyme: ES6: ```js // setup file import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-15'; configure({ adapter: new Adapter() }); ``` ```js // test file import { shallow, mount, render } from 'enzyme'; const wrapper = shallow(); ``` ES5: ```js // setup file var enzyme = require('enzyme'); var Adapter = require('enzyme-adapter-react-15'); enzyme.configure({ adapter: new Adapter() }); ``` ```js // test file var enzyme = require('enzyme'); var wrapper = enzyme.shallow(); ``` ================================================ FILE: docs/installation/react-16.md ================================================ # Working with React 16 If you are wanting to use enzyme with React 16, but don't already have React 16 and react-dom installed, you should do so: ```bash npm i --save react@16 react-dom@16 ``` Next, to get started with enzyme, you can simply install it with npm: ```bash npm i --save-dev enzyme enzyme-adapter-react-16 ``` And then you're ready to go! In your test files you can simply `require` or `import` enzyme: ES6: ```js // setup file import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; configure({ adapter: new Adapter() }); ``` ```js // test file import { shallow, mount, render } from 'enzyme'; const wrapper = shallow(); ``` ES5: ```js // setup file var enzyme = require('enzyme'); var Adapter = require('enzyme-adapter-react-16'); enzyme.configure({ adapter: new Adapter() }); ``` ```js // test file var enzyme = require('enzyme'); var wrapper = enzyme.shallow(); ``` ================================================ FILE: env.js ================================================ 'use strict'; const path = require('path'); const fs = require('fs'); const spawn = require('child_process').spawn; const rimraf = require('rimraf'); const semver = require('semver'); const promisify = (fn) => new Promise((res, rej) => { const done = (err, val) => (err ? rej(err) : res(val)); fn(done); }); const getFile = (fpath) => promisify((cb) => fs.readFile(fpath, 'utf8', cb)); // const getFiles = fpath => promisify(cb => fs.readdir(fpath, cb)); const getJSON = (fpath) => getFile(fpath).then((json) => JSON.parse(json)); const writeFile = (fpath, src) => promisify((cb) => { console.log('writeFile', fpath, src); if (process.env.DEBUG) { cb(); } else { fs.writeFile(fpath, src, cb); } }); const writeJSON = (fpath, json, pretty = false) => writeFile( fpath, (pretty ? JSON.stringify(json, null, 2) : JSON.stringify(json)) + '\n' ); const primraf = (fpath) => promisify((cb) => { console.log('rimraf', fpath); if (process.env.DEBUG) { cb(); } else { rimraf(fpath, cb); } }); const run = (cmd, ...args) => promisify((cb) => { console.log(cmd + ' ' + args.join(' ')); const child = spawn( process.env.DEBUG ? 'echo' : cmd, process.env.DEBUG ? [cmd].concat(args) : args, { stdio: 'inherit' } ); child.on('exit', cb); }); // This script is executed with a single argument, indicating the version of // react and adapters etc. that we want to set ourselves up for testing. // should be "14" for "enzyme-adapter-react-14", "15.4" for "enzyme-adapter-react-15.4", etc. const version = process.argv[2]; // This script will do the following: // // 1. remove / uninstall all relevant modules // 2. find the adapter for the passed in version // 3. get the package.json for the adapter // 4. add the adapter to the dev-deps for enzyme-test-suite package // 5. call lerna bootstrap to link all the packages // 6. install all of the package's peer deps at the top level const root = process.cwd(); function getAdapter(reactVersion) { if (semver.intersects(reactVersion, '0.13.x')) { return '13'; } if (semver.intersects(reactVersion, '0.14.x')) { return '14'; } if (semver.intersects(reactVersion, '^15.0.0-0')) { if (semver.intersects(reactVersion, '>= 15.5')) { return '15'; } return '15.4'; } if (semver.intersects(reactVersion, '^16.0.0-0')) { if (semver.intersects(reactVersion, '>= 16.4')) { return '16'; } if (semver.intersects(reactVersion, '~16.3')) { return '16.3'; } if (semver.intersects(reactVersion, '~16.2')) { return '16.2'; } if (semver.intersects(reactVersion, '~16.0 || ~16.1')) { return '16.1'; } } return null; } const reactVersion = version < 15 ? '0.' + version : version; const adapterVersion = process.env.ADAPTER || getAdapter(reactVersion) || version; const adapterName = `enzyme-adapter-react-${adapterVersion}`; const adapterPackageJsonPath = path.join(root, 'packages', adapterName, 'package.json'); const testPackageJsonPath = path.join(root, 'packages', 'enzyme-test-suite', 'package.json'); if (!fs.statSync(adapterPackageJsonPath)) { throw new Error('Adapter not found: "' + adapterName + '"'); } const packagesToRemove = [ 'react', 'react-dom', 'react-addons-test-utils', 'react-test-renderer', 'create-react-class', ].map((s) => `./node_modules/${s}`); const additionalDirsToRemove = [ ]; const rmrfs = [] .concat(packagesToRemove) .concat(additionalDirsToRemove); Promise.resolve() .then(() => Promise.all(rmrfs.map((s) => primraf(s)))) .then(() => run('npm', 'i')) .then(() => Promise.all([ getJSON(adapterPackageJsonPath), getJSON(testPackageJsonPath), ])) .then(([adapterJson, testJson]) => { const peerDeps = adapterJson.peerDependencies; const installs = Object.keys(peerDeps) .filter((key) => !key.startsWith('enzyme')) .map((key) => `${key}@${key.startsWith('react') ? reactVersion : peerDeps[key]}`); if (process.env.RENDERER) { // eslint-disable-next-line no-param-reassign adapterJson.dependencies['react-test-renderer'] = process.env.RENDERER; } // eslint-disable-next-line no-param-reassign testJson.dependencies[adapterName] = adapterJson.version; return writeJSON(adapterPackageJsonPath, adapterJson, true).then(() => Promise.all([ // npm install the peer deps at the root run('npm', 'i', '--no-save', ...installs), // add the adapter to the dependencies of the test suite writeJSON(testPackageJsonPath, testJson, true), ])); }) .then(() => run('lerna', 'bootstrap', '--hoist=\'react*\'')) .then(() => getJSON(testPackageJsonPath)) .then((testJson) => { // now that we've lerna bootstrapped, we can remove the adapter from the // package.json so there is no diff // eslint-disable-next-line no-param-reassign delete testJson.dependencies[adapterName]; return writeJSON(testPackageJsonPath, testJson, true); }) .catch((err) => console.error(err)); ================================================ FILE: install-relevant-react.sh ================================================ #!/bin/sh REACT="${REACT:-${1:-16}}" echo "installing React $REACT" if [ "$REACT" = "0.13" ]; then npm run env: -- 13 elif [ "$REACT" = "0.14" ]; then npm run env: -- 14 else npm run env: -- "${REACT}" fi ================================================ FILE: karma.conf.js ================================================ /* eslint-disable no-var,prefer-arrow-callback,vars-on-top, import/no-extraneous-dependencies */ 'use strict'; require('@babel/register'); var IgnorePlugin = require('webpack').IgnorePlugin; var is = require('./packages/enzyme-test-suite/build/_helpers/version').is; function getPlugins() { const adapter13 = new IgnorePlugin(/enzyme-adapter-react-13$/); const adapter14 = new IgnorePlugin(/enzyme-adapter-react-14$/); const adapter154 = new IgnorePlugin(/enzyme-adapter-react-15\.4$/); const adapter15 = new IgnorePlugin(/enzyme-adapter-react-15$/); const adapter161 = new IgnorePlugin(/enzyme-adapter-react-16.1$/); const adapter162 = new IgnorePlugin(/enzyme-adapter-react-16.2$/); const adapter163 = new IgnorePlugin(/enzyme-adapter-react-16.3$/); const adapter16 = new IgnorePlugin(/enzyme-adapter-react-16$/); var plugins = [ adapter13, adapter14, adapter154, adapter15, adapter16, ]; function not(x) { return function notPredicate(y) { return y !== x; }; } // we want to ignore all of the adapters *except* the one we are currently using if (is('0.13.x')) { plugins = plugins.filter(not(adapter13)); } else if (is('0.14.x')) { plugins = plugins.filter(not(adapter14)); } else if (is('^15.5.0')) { plugins = plugins.filter(not(adapter15)); } else if (is('^15.0.0-0')) { plugins = plugins.filter(not(adapter154)); } else if (is('~16.0.0-0 || ~16.1')) { plugins = plugins.filter(not(adapter161)); } else if (is('~16.2')) { plugins = plugins.filter(not(adapter162)); } else if (is('~16.3.0-0')) { plugins = plugins.filter(not(adapter163)); } else if (is('^16.4.0-0')) { plugins = plugins.filter(not(adapter16)); } return plugins; } module.exports = function karma(config) { config.set({ basePath: '.', plugins: [ 'karma-chrome-launcher', 'karma-firefox-launcher', 'karma-mocha', 'karma-webpack', 'karma-sourcemap-loader', ], customLaunchers: { Chrome_travis: { base: 'Chrome', flags: ['--no-sandbox'], }, }, frameworks: ['mocha'], reporters: ['dots'], files: [ 'packages/enzyme-test-suite/build/*.js', ], exclude: [ 'packages/enzyme-test-suite/build/_helpers/index.js', ], browsers: [ process.env.TRAVIS ? 'Chrome_travis' : 'Chrome', 'Firefox', ], preprocessors: { 'packages/enzyme-test-suite/build/*.js': ['webpack', 'sourcemap'], }, webpack: { devtool: 'inline-source-map', resolve: { extensions: ['', '.js', '.jsx', '.json'], alias: { // dynamic require calls in sinon confuse webpack so we ignore it sinon: 'sinon/pkg/sinon', }, }, module: { noParse: [ // dynamic require calls in sinon confuse webpack so we ignore it /node_modules\/sinon\//, ], loaders: [ { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader', }, { test: /\.json$/, loader: 'json-loader', }, ], }, plugins: getPlugins(), }, webpackServer: { noInfo: true, }, }); }; ================================================ FILE: lerna.json ================================================ { "lerna": "2.0.0", "packages": [ "packages/*" ], "version": "independent", "independent": true } ================================================ FILE: package.json ================================================ { "name": "enzyme", "private": true, "version": "0.0.1", "description": "JavaScript Testing utilities for React", "homepage": "https://enzymejs.github.io/enzyme/", "scripts": { "clean-node-modules": "rm -rf node_modules/{*,.bin,.package-lock.json} && rm -rf packages/*/node_modules/{*,.bin,.package-lock.json}", "postinstall": "[ -n \"${TRAVIS-}\" ] || (npm link npm && lerna bootstrap)", "preversion": "npm run clean && npm run check", "postversion": "git push && git push --tags && npm run clean && npm run docs:publish", "version": "lerna run build", "clean": "lerna run clean", "prelint": "npm run lint:root", "lint": "lerna exec --parallel 'npm run lint -- --quiet'", "lint:root": "eslint . --ext=js,md,jsx --ignore-pattern=packages/", "check": "lerna run lint && npm run test:all", "prebuild": "npm run clean", "build": "lerna run build", "build:watch": "lerna run --parallel watch", "pretest": "lerna run lint", "test": "npm run test:only", "pretest:only": "npm run build", "test:only": "mocha --recursive packages/enzyme-test-suite/build", "test:single": "mocha --watch", "test:watch": "npm run test:only -- --watch", "pretest:karma": "npm run build", "test:karma": "karma start", "test:all": "npm run react 13 && npm run test:only && npm run react 14 && npm run test:only && npm run react 15 && npm run test:only && npm run react 15.4 && npm run test:only && npm run react 15.5 && npm run test:only && npm run react 16 && npm run test:only && npm run react 16.1 && npm run test:only && npm run react 16.2 && npm run test:only && npm run react 16.3 && npm run test:only && npm run react 16.4 && npm run test:only && npm run react 16.5 && npm run test:only && npm run react 16.8 && npm run test:only", "react": "sh install-relevant-react.sh", "env:": "babel-node ./env.js", "docs:clean": "rimraf _book", "docs:prepare": "gitbook install", "docs:build": "npm run docs:prepare && gitbook build", "docs:watch": "npm run docs:prepare && gitbook serve", "docs:publish": "npm run docs:clean && npm run docs:build && cd _book && git init && git commit --allow-empty -m 'update book' && git fetch git@github.com:enzymejs/enzyme.git gh-pages && git checkout -b gh-pages && git add . && git commit -am 'update book' && git push git@github.com:enzymejs/enzyme.git gh-pages --force", "travis": "nyc mocha --recursive packages/enzyme-test-suite/build", "since": "node since" }, "repository": { "type": "git", "url": "https://github.com/enzymejs/enzyme.git" }, "keywords": [ "javascript", "shallow rendering", "shallowRender", "test", "reactjs", "react", "flux", "testing", "test utils", "assertion helpers", "tdd", "mocha" ], "author": "Jordan Harband ", "license": "MIT", "devDependencies": { "@babel/cli": "^7.28.3", "@babel/core": "^7.28.4", "@babel/eslint-parser": "^7.28.4", "@babel/node": "~7.24.8", "@babel/register": "^7.28.3", "@babel/runtime": "^7.28.4", "babel-loader": "^8.2.2", "babel-plugin-add-module-exports": "^1.0.4", "babel-plugin-transform-replace-object-assign": "^2.0.0", "babel-preset-airbnb": "^4.5.0", "chai": "^4.3.4", "eslint": "^8.56.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-markdown": "^3.0.1", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^4.6.0", "gitbook-cli": "^1.0.1", "gitbook-plugin-anchors": "^0.7.1", "gitbook-plugin-codeblock-disable-glossary": "0.0.1", "gitbook-plugin-collapsible-menu": "^1.0.3", "gitbook-plugin-edit-link": "^2.0.2", "gitbook-plugin-github": "^2.0.0", "glob-gitignore": "^1.0.14", "in-publish": "^2.0.1", "json-loader": "^0.5.7", "karma": "^1.3.0", "karma-chrome-launcher": "^1.0.1", "karma-firefox-launcher": "^1.3.0", "karma-mocha": "^1.3.0", "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^1.8.1", "lerna": "^2.11.0", "mocha": "^3.5.3", "mocha-lcov-reporter": "^1.3.0", "npm": "gist:9cdb687f3806f8e6cb8a365d0b7840eb", "nyc": "^10.3.2", "prop-types": "^15.8.1", "rimraf": "^2.7.1", "safe-publish-latest": "^2.0.0", "semver": "^6.3.1", "webpack": "^2.7.0" }, "greenkeeper": { "ignore": [ "mocha", "nyc", "semver", "webpack" ] } } ================================================ FILE: packages/enzyme/.babelrc ================================================ { "presets": [ ["airbnb", { "transformRuntime": false }], ], "plugins": [ ["transform-replace-object-assign", { "moduleSpecifier": "object.assign" }], ["add-module-exports"], ], "sourceMaps": "both", } ================================================ FILE: packages/enzyme/.eslintrc ================================================ { "extends": "airbnb", "parser": "@babel/eslint-parser", "root": true, "ignorePatterns": ["build/"], "env": { "node": true, "mocha": true }, "rules": { "id-length": 0, "max-classes-per-file": 0, "new-cap": [2, { "capIsNewExceptions": ["AND"] }], "react/jsx-pascal-case": [2, { "allowAllCaps": true }], "react/no-find-dom-node": 1, "import/first": 0, "no-underscore-dangle": [2, { "allowAfterThis": true, "allow": [ "_context", "_currentElement", "_instance", "_reactInternalComponent", "_reactInternalInstance", "_renderedChildren", "_renderedComponent", "_renderedNodeType", "_state", "_store", "_stringText", ], }], } } ================================================ FILE: packages/enzyme/ReactWrapper.js ================================================ module.exports = require('./build/ReactWrapper'); ================================================ FILE: packages/enzyme/ShallowWrapper.js ================================================ module.exports = require('./build/ShallowWrapper'); ================================================ FILE: packages/enzyme/mount.js ================================================ module.exports = require('./build/mount'); ================================================ FILE: packages/enzyme/package.json ================================================ { "name": "enzyme", "version": "3.11.0", "description": "JavaScript Testing utilities for React", "homepage": "https://enzymejs.github.io/enzyme/", "main": "build", "scripts": { "prepack": "npmignore --auto --commentLines=autogenerated --gitignore=../../.gitignore && cp ../../{LICENSE,README}.md ./ && npm run build", "prepublishOnly": "safe-publish-latest", "prepublish": "not-in-publish || npm run prepublishOnly", "clean": "rimraf build", "lint": "eslint --ext js,jsx .", "pretest": "npm run lint", "prebuild": "npm run clean", "build": "babel --source-maps=both src --out-dir build", "watch": "npm run build -- -w" }, "repository": { "type": "git", "url": "https://github.com/enzymejs/enzyme.git", "directory": "packages/enzyme" }, "keywords": [ "javascript", "shallow rendering", "shallowRender", "test", "reactjs", "react", "flux", "testing", "test utils", "assertion helpers", "tdd", "mocha" ], "author": "Jordan Harband ", "funding": { "url": "https://github.com/sponsors/ljharb" }, "license": "MIT", "dependencies": { "array.prototype.flat": "^1.3.3", "cheerio": "=1.0.0-rc.3", "enzyme-shallow-equal": "^1.0.7", "function.prototype.name": "^1.1.8", "hasown": "^2.0.2", "html-element-map": "^1.3.1", "is-boolean-object": "^1.2.2", "is-callable": "^1.2.7", "is-number-object": "^1.1.1", "is-regex": "^1.2.1", "is-string": "^1.1.1", "is-subset": "^0.1.1", "lodash.escape": "^4.0.1", "lodash.isequal": "^4.5.0", "object-inspect": "^1.13.4", "object-is": "^1.1.6", "object.assign": "^4.1.7", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "raf": "^3.4.1", "rst-selector-parser": "^2.2.3", "string.prototype.trim": "^1.2.10" }, "devDependencies": { "@babel/cli": "^7.28.3", "@babel/core": "^7.28.4", "@babel/eslint-parser": "^7.28.4", "babel-plugin-add-module-exports": "^1.0.4", "babel-plugin-transform-replace-object-assign": "^2.0.0", "babel-preset-airbnb": "^4.5.0", "eslint": "^8.56.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^4.6.0", "in-publish": "^2.0.1", "jsdom": "^6.5.1", "npmignore": "^0.3.1", "rimraf": "^2.7.1", "safe-publish-latest": "^2.0.0" }, "publishConfig": { "ignore": [ "!build" ] } } ================================================ FILE: packages/enzyme/render.js ================================================ module.exports = require('./build/render'); ================================================ FILE: packages/enzyme/shallow.js ================================================ module.exports = require('./build/shallow'); ================================================ FILE: packages/enzyme/src/Debug.js ================================================ import escape from 'lodash.escape'; import functionName from 'function.prototype.name'; import isString from 'is-string'; import isNumber from 'is-number-object'; import isCallable from 'is-callable'; import isBoolean from 'is-boolean-object'; import inspect from 'object-inspect'; import hasOwn from 'hasown'; import { propsOfNode, childrenOfNode, } from './RSTTraversal'; import getAdapter from './getAdapter'; const booleanValue = Function.bind.call(Function.call, Boolean.prototype.valueOf); export function typeName(node) { const adapter = getAdapter(); if (adapter.displayNameOfNode) { return getAdapter().displayNameOfNode(node) || 'Component'; } return typeof node.type === 'function' ? (node.type.displayName || functionName(node.type) || 'Component') : node.type; } export function spaces(n) { return Array(n + 1).join(' '); } export function indent(depth, string) { return string.split('\n').map((x) => `${spaces(depth)}${x}`).join('\n'); } function propString(prop, options) { if (isString(prop)) { return inspect(String(prop), { quoteStyle: 'double' }); } if (isNumber(prop)) { return `{${inspect(Number(prop))}}`; } if (isBoolean(prop)) { return `{${inspect(booleanValue(prop))}}`; } if (isCallable(prop)) { return `{${inspect(prop)}}`; } if (typeof prop === 'object') { if (options.verbose) { return `{${inspect(prop)}}`; } return '{{...}}'; } return `{[${inspect(prop)}]}`; } function propsString(node, options) { const props = propsOfNode(node); const keys = Object.keys(props).filter((x) => x !== 'children'); return keys.map((key) => `${key}=${propString(props[key], options)}`).join(' '); } function indentChildren(childrenStrs, indentLength) { return childrenStrs.length ? `\n${childrenStrs.map((x) => indent(indentLength, x)).join('\n')}\n` : ''; } function isRSTNodeLike(node) { return hasOwn(node, 'nodeType') && typeof node.nodeType === 'string' && hasOwn(node, 'type') && hasOwn(node, 'key') && hasOwn(node, 'ref') && hasOwn(node, 'instance') && hasOwn(node, 'rendered'); } export function debugNode(node, indentLength = 2, options = {}) { if (typeof node === 'string' || typeof node === 'number') return escape(node); if (typeof node === 'function') { const name = functionName(node); return `[function${name ? ` ${name}` : ''}]`; } if (!node) return ''; const adapter = getAdapter(); if (!adapter.isValidElement(node) && !isRSTNodeLike(node)) { return `{${inspect(node)}}`; } const childrenStrs = childrenOfNode(node) .map((n) => debugNode(n, indentLength, options)) .filter(Boolean); const type = typeName(node); const props = options.ignoreProps ? '' : propsString(node, options); const beforeProps = props ? ' ' : ''; const afterProps = childrenStrs.length ? '>' : ' '; const childrenIndented = indentChildren(childrenStrs, indentLength); const nodeClose = childrenStrs.length ? `` : '/>'; return `<${type}${beforeProps}${props}${afterProps}${childrenIndented}${nodeClose}`; } export function debugNodes(nodes, options = {}) { return nodes.map((node) => debugNode(node, undefined, options)).join('\n\n\n'); } ================================================ FILE: packages/enzyme/src/EnzymeAdapter.js ================================================ function unimplementedError(methodName, classname) { return new Error(`${methodName} is a required method of ${classname}, but was not implemented.`); } class EnzymeAdapter { constructor() { this.options = {}; } // Provided a bag of options, return an `EnzymeRenderer`. Some options can be implementation // specific, like `attach` etc. for React, but not part of this interface explicitly. // eslint-disable-next-line class-methods-use-this, no-unused-vars createRenderer(options) { throw unimplementedError('createRenderer', 'EnzymeAdapter'); } // converts an RSTNode to the corresponding JSX Pragma Element. This will be needed // in order to implement the `Wrapper.mount()` and `Wrapper.shallow()` methods, but should // be pretty straightforward for people to implement. // eslint-disable-next-line class-methods-use-this, no-unused-vars nodeToElement(node) { throw unimplementedError('nodeToElement', 'EnzymeAdapter'); } // eslint-disable-next-line class-methods-use-this matchesElementType(node, matchingType) { if (!node) { return node; } const { type } = node; return type === matchingType; } // eslint-disable-next-line class-methods-use-this, no-unused-vars isValidElement(element) { throw unimplementedError('isValidElement', 'EnzymeAdapter'); } // eslint-disable-next-line class-methods-use-this, no-unused-vars createElement(type, props, ...children) { throw unimplementedError('createElement', 'EnzymeAdapter'); } // eslint-disable-next-line class-methods-use-this invokeSetStateCallback(instance, callback) { callback.call(instance); } } EnzymeAdapter.MODES = { STRING: 'string', MOUNT: 'mount', SHALLOW: 'shallow', }; export default EnzymeAdapter; ================================================ FILE: packages/enzyme/src/RSTTraversal.js ================================================ import flat from 'array.prototype.flat'; import entries from 'object.entries'; import fromEntries from 'object.fromentries'; import isSubset from 'is-subset'; import functionName from 'function.prototype.name'; import isRegex from 'is-regex'; import getAdapter from './getAdapter'; export function propsOfNode(node) { return (node && node.props) || {}; } export function childrenOfNode(node) { if (!node) return []; const adapter = getAdapter(); const adapterHasIsFragment = adapter.isFragment && typeof adapter.isFragment === 'function'; const renderedArray = Array.isArray(node.rendered) ? flat(node.rendered, 1) : [node.rendered]; // React adapters before 16 will not have isFragment if (!adapterHasIsFragment) { return renderedArray; } return flat(renderedArray.map((currentChild) => { // If the node is a Fragment, we want to return its children, not the fragment itself if (adapter.isFragment(currentChild)) { return childrenOfNode(currentChild); } return currentChild; }), 1); } export function hasClassName(node, className) { let classes = propsOfNode(node).className || ''; classes = String(classes).replace(/\s/g, ' '); if (isRegex(className)) return className.test(classes); return ` ${classes} `.indexOf(` ${className} `) > -1; } export function treeForEach(tree, fn) { if (tree) { fn(tree); } childrenOfNode(tree).forEach((node) => treeForEach(node, fn)); } export function treeFilter(tree, fn) { const results = []; treeForEach(tree, (node) => { if (fn(node)) { results.push(node); } }); return results; } /** * To support sibling selectors we need to be able to find * the siblings of a node. The easiest way to do that is find * the parent of the node and access its children. * * This would be unneeded if the RST spec included sibling pointers * such as node.nextSibling and node.prevSibling * @param {*} root * @param {*} targetNode */ export function findParentNode(root, targetNode) { const results = treeFilter( root, (node) => { if (!node.rendered) { return false; } return childrenOfNode(node).indexOf(targetNode) !== -1; }, ); return results[0] || null; } function pathFilter(path, fn) { return path.filter((tree) => treeFilter(tree, fn).length !== 0); } export function pathToNode(node, root) { const queue = [root]; const path = []; const hasNode = (testNode) => node === testNode; while (queue.length) { const current = queue.pop(); const children = childrenOfNode(current); if (current === node) return pathFilter(path, hasNode); path.push(current); if (children.length === 0) { // leaf node. if it isn't the node we are looking for, we pop. path.pop(); } queue.push(...children); } return null; } export function parentsOfNode(node, root) { return (pathToNode(node, root) || []).reverse(); } export function nodeHasId(node, id) { return propsOfNode(node).id === id; } const CAN_NEVER_MATCH = {}; function replaceUndefined(v) { return typeof v !== 'undefined' ? v : CAN_NEVER_MATCH; } function replaceUndefinedValues(obj) { const newEntries = entries(obj).map(([k, v]) => [k, replaceUndefined(v)]); return fromEntries(newEntries); } export function nodeMatchesObjectProps(node, props) { return isSubset(propsOfNode(node), replaceUndefinedValues(props)); } function getTextFromHostNode(hostNode) { if (typeof hostNode === 'string') { return String(hostNode || ''); } if (!hostNode) { return ''; } return hostNode.textContent || ''; } function getTextFromRSTNode(node, { getCustom, handleHostNodes, recurse, nullRenderReturnsNull = false, }) { if (node == null) { return ''; } if (typeof node === 'string' || typeof node === 'number') { return String(node); } if (getCustom && node.type && typeof node.type === 'function') { return getCustom(node); } if (handleHostNodes && node.nodeType === 'host') { return handleHostNodes(node); } if (node.rendered == null && nullRenderReturnsNull) { return null; } return childrenOfNode(node).map(recurse).join(''); } export function getTextFromNode(node) { return getTextFromRSTNode(node, { recurse: getTextFromNode, getCustom({ type }) { return `<${type.displayName || functionName(type)} />`; }, }); } export function getTextFromHostNodes(node, adapter) { return getTextFromRSTNode(node, { recurse(item) { return getTextFromHostNodes(item, adapter); }, handleHostNodes(item) { const nodes = [].concat(adapter.nodeToHostNode(item, true)); return nodes.map(getTextFromHostNode).join(''); }, }); } function getHTMLFromHostNode(hostNode) { if (hostNode == null) { return null; } return hostNode.outerHTML.replace(/\sdata-(reactid|reactroot)+="([^"]*)+"/g, ''); } export function getHTMLFromHostNodes(node, adapter) { return getTextFromRSTNode(node, { recurse(item) { return getHTMLFromHostNodes(item, adapter); }, handleHostNodes(item) { const nodes = [].concat(adapter.nodeToHostNode(item, true)); return nodes.map(getHTMLFromHostNode).join(''); }, nullRenderReturnsNull: true, }); } ================================================ FILE: packages/enzyme/src/ReactWrapper.js ================================================ import flat from 'array.prototype.flat'; import hasOwn from 'hasown'; import trim from 'string.prototype.trim'; import { containsChildrenSubArray, typeOfNode, displayNameOfNode, ITERATOR_SYMBOL, nodeEqual, nodeMatches, makeOptions, sym, privateSet, cloneElement, renderedDive, isCustomComponent, loadCheerioRoot, } from './Utils'; import getAdapter from './getAdapter'; import { debugNodes } from './Debug'; import { propsOfNode, hasClassName, childrenOfNode, parentsOfNode, treeFilter, getTextFromHostNodes, getHTMLFromHostNodes, } from './RSTTraversal'; import { buildPredicate, reduceTreesBySelector } from './selectors'; const NODE = sym('__node__'); const NODES = sym('__nodes__'); const RENDERER = sym('__renderer__'); const UNRENDERED = sym('__unrendered__'); const ROOT = sym('__root__'); const OPTIONS = sym('__options__'); const ROOT_NODES = sym('__rootNodes__'); const WRAPPING_COMPONENT = sym('__wrappingComponent__'); const LINKED_ROOTS = sym('__linkedRoots__'); const UPDATED_BY = sym('__updatedBy__'); /** * Finds all nodes in the current wrapper nodes' render trees that match the provided predicate * function. * * @param {ReactWrapper} wrapper * @param {Function} predicate * @param {Function} filter * @returns {ReactWrapper} */ function findWhereUnwrapped(wrapper, predicate, filter = treeFilter) { return wrapper.flatMap((n) => filter(n.getNodeInternal(), predicate)); } /** * Returns a new wrapper instance with only the nodes of the current wrapper instance that match * the provided predicate function. * * @param {ReactWrapper} wrapper * @param {Function} predicate * @returns {ReactWrapper} */ function filterWhereUnwrapped(wrapper, predicate) { return wrapper.wrap(wrapper.getNodesInternal().filter(predicate).filter(Boolean)); } function getRootNodeInternal(wrapper) { if (wrapper[ROOT].length !== 1) { throw new Error('getRootNodeInternal(wrapper) can only be called when wrapper wraps one node'); } if (wrapper[ROOT] !== wrapper) { return wrapper[ROOT_NODES][0]; } return wrapper[ROOT][NODE]; } function nodeParents(wrapper, node) { return parentsOfNode(node, getRootNodeInternal(wrapper)); } function privateSetNodes(wrapper, nodes) { if (!nodes) { privateSet(wrapper, NODE, null); privateSet(wrapper, NODES, []); } else if (!Array.isArray(nodes)) { privateSet(wrapper, NODE, nodes); privateSet(wrapper, NODES, [nodes]); } else { privateSet(wrapper, NODE, nodes[0]); privateSet(wrapper, NODES, nodes); } privateSet(wrapper, 'length', wrapper[NODES].length); } /** * @class ReactWrapper */ class ReactWrapper { constructor(nodes, root, passedOptions = {}) { if (!global.window && !global.document) { throw new Error('It looks like you called `mount()` without a global document being loaded.'); } const options = makeOptions(passedOptions); if (!root) { const adapter = getAdapter(options); if (!adapter.isValidElement(nodes)) { throw new TypeError('ReactWrapper can only wrap valid elements'); } const renderer = adapter.createRenderer({ mode: 'mount', ...options }); privateSet(this, RENDERER, renderer); renderer.render(nodes, options.context); privateSet(this, ROOT, this); privateSetNodes(this, this[RENDERER].getNode()); privateSet(this, OPTIONS, options); privateSet(this, LINKED_ROOTS, []); if (isCustomComponent(options.wrappingComponent, adapter)) { if (typeof this[RENDERER].getWrappingComponentRenderer !== 'function') { throw new TypeError('your adapter does not support `wrappingComponent`. Try upgrading it!'); } privateSet( this, WRAPPING_COMPONENT, // eslint-disable-next-line no-use-before-define new WrappingComponentWrapper(this, this[RENDERER].getWrappingComponentRenderer()), ); this[LINKED_ROOTS].push(this[WRAPPING_COMPONENT]); } } else { privateSet(this, RENDERER, root[RENDERER]); privateSet(this, ROOT, root); privateSetNodes(this, nodes); privateSet(this, ROOT_NODES, root[NODES]); privateSet(this, OPTIONS, root[OPTIONS]); privateSet(this, LINKED_ROOTS, []); } privateSet(this, UNRENDERED, nodes); privateSet(this, UPDATED_BY, null); } /** * Returns the root wrapper * * @return {ReactWrapper} */ root() { return this[ROOT]; } /** * Returns the wrapped component. * * @return {ReactComponent} */ getNodeInternal() { if (this.length !== 1) { throw new Error('ReactWrapper::getNode() can only be called when wrapping one node'); } return this[NODES][0]; } /** * Returns the the wrapped components. * * @return {Array} */ getNodesInternal() { return this[NODES]; } /** * Returns the wrapped ReactElement. * * @return {ReactElement} */ getElement() { return this.single('getElement', () => getAdapter(this[OPTIONS]).nodeToElement(this[NODE])); } /** * Returns the wrapped ReactElements. * * @return {Array} */ getElements() { return this[NODES].map((n) => getAdapter(this[OPTIONS]).nodeToElement(n)); } // eslint-disable-next-line class-methods-use-this getNode() { throw new Error('ReactWrapper::getNode() is no longer supported. Use ReactWrapper::instance() instead'); } // eslint-disable-next-line class-methods-use-this getNodes() { throw new Error('ReactWrapper::getNodes() is no longer supported.'); } /** * Returns the outer most DOMComponent of the current wrapper. * * NOTE: can only be called on a wrapper of a single node. * * @returns {DOMComponent} */ getDOMNode() { const adapter = getAdapter(this[OPTIONS]); return this.single('getDOMNode', (n) => adapter.nodeToHostNode(n, true)); } /** * If the root component contained a ref, you can access it here and get the relevant * react component instance or HTML element instance. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {String} refname * @returns {ReactComponent | HTMLElement} */ ref(refname) { if (this[ROOT] !== this) { throw new Error('ReactWrapper::ref(refname) can only be called on the root'); } return this.instance().refs[refname]; } /** * Returns the wrapper's underlying instance. * * Example: * ``` * const wrapper = mount(); * const inst = wrapper.instance(); * expect(inst).to.be.instanceOf(MyComponent); * ``` * @returns {ReactComponent|DOMComponent} */ instance() { return this.single('instance', () => this[NODE].instance); } /** * If a `wrappingComponent` was passed in `options`, this methods returns a `ReactWrapper` around * the rendered `wrappingComponent`. This `ReactWrapper` can be used to update the * `wrappingComponent`'s props, state, etc. * * @returns ReactWrapper */ getWrappingComponent() { if (this[ROOT] !== this) { throw new Error('ReactWrapper::getWrappingComponent() can only be called on the root'); } if (!this[OPTIONS].wrappingComponent) { throw new Error('ReactWrapper::getWrappingComponent() can only be called on a wrapper that was originally passed a `wrappingComponent` option'); } return this[WRAPPING_COMPONENT]; } /** * Forces a re-render. Useful to run before checking the render output if something external * may be updating the state of the component somewhere. * * NOTE: no matter what instance this is called on, it will always update the root. * * @returns {ReactWrapper} */ update() { const root = this[ROOT]; if (this !== root) { return root.update(); } privateSetNodes(this, this[RENDERER].getNode()); this[LINKED_ROOTS].forEach((linkedRoot) => { if (linkedRoot !== this[UPDATED_BY]) { /* eslint-disable no-param-reassign */ // Only update a linked it root if it is not the originator of our update(). // This is needed to prevent infinite recursion when there is a bi-directional // link between two roots. linkedRoot[UPDATED_BY] = this; try { linkedRoot.update(); } finally { linkedRoot[UPDATED_BY] = null; } } }); return this; } /** * A method that unmounts the component. This can be used to simulate a component going through * and unmount/mount lifecycle. * * @returns {ReactWrapper} */ unmount() { if (this[ROOT] !== this) { throw new Error('ReactWrapper::unmount() can only be called on the root'); } this.single('unmount', () => { this[RENDERER].unmount(); this.update(); }); return this; } /** * A method that re-mounts the component, if it is not currently mounted. * This can be used to simulate a component going through * an unmount/mount lifecycle. * * @returns {ReactWrapper} */ mount() { if (this[ROOT] !== this) { throw new Error('ReactWrapper::mount() can only be called on the root'); } this[RENDERER].render(this[UNRENDERED], this[OPTIONS].context, () => this.update()); return this; } /** * A method that sets the props of the root component, and re-renders. Useful for when you are * wanting to test how the component behaves over time with changing props. Calling this, for * instance, will call the `componentWillReceiveProps` lifecycle method. * * Similar to `setState`, this method accepts a props object and will merge it in with the already * existing props. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {Object} props object * @param {Function} cb - callback function * @returns {ReactWrapper} */ setProps(props, callback = undefined) { if (this[ROOT] !== this) { throw new Error('ReactWrapper::setProps() can only be called on the root'); } if (arguments.length > 1 && typeof callback !== 'function') { throw new TypeError('ReactWrapper::setProps() expects a function as its second argument'); } const adapter = getAdapter(this[OPTIONS]); this[UNRENDERED] = cloneElement(adapter, this[UNRENDERED], props); this[RENDERER].render(this[UNRENDERED], null, () => { this.update(); if (callback) { callback(); } }); return this; } /** * A method to invoke `setState` on the root component instance similar to how you might in the * definition of the component, and re-renders. This method is useful for testing your component * in hard to achieve states, however should be used sparingly. If possible, you should utilize * your component's external API in order to get it into whatever state you want to test, in order * to be as accurate of a test as possible. This is not always practical, however. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {Object} state to merge * @param {Function} cb - callback function * @returns {ReactWrapper} */ setState(state, callback = undefined) { if (this.instance() === null || this.getNodeInternal().nodeType !== 'class') { throw new Error('ReactWrapper::setState() can only be called on class components'); } if (arguments.length > 1 && typeof callback !== 'function') { throw new TypeError('ReactWrapper::setState() expects a function as its second argument'); } this.instance().setState(state, () => { this.update(); if (callback) { const adapter = getAdapter(this[OPTIONS]); const instance = this.instance(); if (adapter.invokeSetStateCallback) { adapter.invokeSetStateCallback(instance, callback); } else { callback.call(instance); } } }); return this; } /** * A method that sets the context of the root component, and re-renders. Useful for when you are * wanting to test how the component behaves over time with changing contexts. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {Object} context object * @returns {ReactWrapper} */ setContext(context) { if (this[ROOT] !== this) { throw new Error('ReactWrapper::setContext() can only be called on the root'); } if (!this[OPTIONS].context) { throw new Error('ReactWrapper::setContext() can only be called on a wrapper that was originally passed a context option'); } this[RENDERER].render(this[UNRENDERED], context, () => this.update()); return this; } /** * Whether or not a given react element exists in the mount render tree. * * Example: * ``` * const wrapper = mount(); * expect(wrapper.contains(
)).to.equal(true); * ``` * * @param {ReactElement|Array} nodeOrNodes * @returns {Boolean} */ contains(nodeOrNodes) { const adapter = getAdapter(this[OPTIONS]); const predicate = Array.isArray(nodeOrNodes) ? (other) => containsChildrenSubArray( nodeEqual, other, nodeOrNodes.map((node) => adapter.elementToNode(node)), ) : (other) => nodeEqual(adapter.elementToNode(nodeOrNodes), other); return findWhereUnwrapped(this, predicate).length > 0; } /** * Whether or not a given react element exists in the current render tree. * It will determine if one of the wrappers element "looks like" the expected * element by checking if all props of the expected element are present * on the wrappers element and equals to each other. * * Example: * ``` * // MyComponent outputs
Hello
* const wrapper = mount(); * expect(wrapper.containsMatchingElement(
Hello
)).to.equal(true); * ``` * * @param {ReactElement} node * @returns {Boolean} */ containsMatchingElement(node) { const rstNode = getAdapter(this[OPTIONS]).elementToNode(node); const predicate = (other) => nodeMatches(rstNode, other, (a, b) => a <= b); return findWhereUnwrapped(this, predicate).length > 0; } /** * Whether or not all the given react elements exist in the current render tree. * It will determine if one of the wrappers element "looks like" the expected * element by checking if all props of the expected element are present * on the wrappers element and equals to each other. * * Example: * ``` * const wrapper = mount(); * expect(wrapper.containsAllMatchingElements([ *
Hello
, *
Goodbye
, * ])).to.equal(true); * ``` * * @param {Array} nodes * @returns {Boolean} */ containsAllMatchingElements(nodes) { if (!Array.isArray(nodes)) { throw new TypeError('nodes should be an Array'); } return nodes.every((node) => this.containsMatchingElement(node)); } /** * Whether or not one of the given react elements exists in the current render tree. * It will determine if one of the wrappers element "looks like" the expected * element by checking if all props of the expected element are present * on the wrappers element and equals to each other. * * Example: * ``` * const wrapper = mount(); * expect(wrapper.containsAnyMatchingElements([ *
Hello
, *
Goodbye
, * ])).to.equal(true); * ``` * * @param {Array} nodes * @returns {Boolean} */ containsAnyMatchingElements(nodes) { return Array.isArray(nodes) && nodes.some((node) => this.containsMatchingElement(node)); } /** * Whether or not a given react element exists in the render tree. * * Example: * ``` * const wrapper = mount(); * expect(wrapper.contains(
)).to.equal(true); * ``` * * @param {ReactElement} node * @returns {Boolean} */ equals(node) { return this.single('equals', () => nodeEqual(this.getNodeInternal(), node)); } /** * Whether or not a given react element matches the render tree. * Match is based on the expected element and not on wrapper root node. * It will determine if the wrapper root node "looks like" the expected * element by checking if all props of the expected element are present * on the wrapper root node and equals to each other. * * Example: * ``` * // MyComponent outputs
Hello
* const wrapper = mount(); * expect(wrapper.matchesElement(
Hello
)).to.equal(true); * ``` * * @param {ReactElement} node * @returns {Boolean} */ matchesElement(node) { return this.single('matchesElement', () => { const adapter = getAdapter(this[OPTIONS]); const rstNode = adapter.elementToNode(node); return nodeMatches(rstNode, this.getNodeInternal(), (a, b) => a <= b); }); } /** * Finds every node in the render tree of the current wrapper that matches the provided selector. * * @param {EnzymeSelector} selector * @returns {ReactWrapper} */ find(selector) { return this.wrap(reduceTreesBySelector(selector, this.getNodesInternal())); } /** * Returns whether or not current node matches a provided selector. * * NOTE: can only be called on a wrapper of a single node. * * @param {EnzymeSelector} selector * @returns {boolean} */ is(selector) { const predicate = buildPredicate(selector); return this.single('is', (n) => predicate(n)); } /** * Returns true if the component rendered nothing, i.e., null or false. * * @returns {boolean} */ isEmptyRender() { const nodes = this.getNodesInternal(); return nodes.every((node) => renderedDive(node)); } /** * Returns a new wrapper instance with only the nodes of the current wrapper instance that match * the provided predicate function. * * @param {Function} predicate * @returns {ReactWrapper} */ filterWhere(predicate) { return filterWhereUnwrapped(this, (n) => predicate(this.wrap(n))); } /** * Returns a new wrapper instance with only the nodes of the current wrapper instance that match * the provided selector. * * @param {EnzymeSelector} selector * @returns {ReactWrapper} */ filter(selector) { const predicate = buildPredicate(selector); return filterWhereUnwrapped(this, predicate); } /** * Returns a new wrapper instance with only the nodes of the current wrapper that did not match * the provided selector. Essentially the inverse of `filter`. * * @param {EnzymeSelector} selector * @returns {ReactWrapper} */ not(selector) { const predicate = buildPredicate(selector); return filterWhereUnwrapped(this, (n) => !predicate(n)); } /** * Returns a string of the rendered text of the current render tree. This function should be * looked at with skepticism if being used to test what the actual HTML output of the component * will be. If that is what you would like to test, use enzyme's `render` function instead. * * NOTE: can only be called on a wrapper of a single node. * * @returns {String} */ text() { const adapter = getAdapter(this[OPTIONS]); return this.single('text', (n) => getTextFromHostNodes(n, adapter)); } /** * Returns the HTML of the node. * * NOTE: can only be called on a wrapper of a single node. * * @returns {String} */ html() { const adapter = getAdapter(this[OPTIONS]); return this.single('html', (n) => getHTMLFromHostNodes(n, adapter)); } /** * Returns the current node rendered to HTML and wrapped in a CheerioWrapper. * * NOTE: can only be called on a wrapper of a single node. * * @returns {CheerioWrapper} */ render() { const html = this.html(); return loadCheerioRoot(html); } /** * Used to simulate events. Pass an eventname and (optionally) event arguments. This method of * testing events should be met with some skepticism. * * @param {String} event * @param {Object} mock (optional) * @returns {ReactWrapper} */ simulate(event, mock = {}) { return this.single('simulate', (n) => { this[RENDERER].simulateEvent(n, event, mock); this[ROOT].update(); return this; }); } /** * Used to simulate throwing a rendering error. Pass an error to throw. * * @param {String} error * @returns {ReactWrapper} */ simulateError(error) { if (this[ROOT] === this) { throw new Error('ReactWrapper::simulateError() may not be called on the root'); } return this.single('simulateError', (thisNode) => { if (thisNode.nodeType === 'host') { throw new Error('ReactWrapper::simulateError() can only be called on custom components'); } const renderer = this[RENDERER]; if (typeof renderer.simulateError !== 'function') { throw new TypeError('your adapter does not support `simulateError`. Try upgrading it!'); } const rootNode = getRootNodeInternal(this); const nodeHierarchy = [thisNode].concat(nodeParents(this, thisNode)); renderer.simulateError(nodeHierarchy, rootNode, error); this[ROOT].update(); return this; }); } /** * Returns the props hash for the root node of the wrapper. * * NOTE: can only be called on a wrapper of a single node. * * @returns {Object} */ props() { return this.single('props', propsOfNode); } /** * Returns the state hash for the root node of the wrapper. Optionally pass in a prop name and it * will return just that value. * * NOTE: can only be called on a wrapper of a single node. * * @param {String} name (optional) * @returns {*} */ state(name) { const thisNode = this[ROOT] === this ? this[RENDERER].getNode() : this.getNodeInternal(); if (this.instance() === null || thisNode.nodeType !== 'class') { throw new Error('ReactWrapper::state() can only be called on class components'); } const _state = this.single('state', () => this.instance().state); if (typeof name !== 'undefined') { if (_state == null) { throw new TypeError(`ReactWrapper::state("${name}") requires that \`state\` not be \`null\` or \`undefined\``); } return _state[name]; } return _state; } /** * Returns the context hash for the root node of the wrapper. * Optionally pass in a prop name and it will return just that value. * * NOTE: can only be called on a wrapper of a single node. * * @param {String} name (optional) * @returns {*} */ context(name) { if (this[ROOT] !== this) { throw new Error('ReactWrapper::context() can only be called on the root'); } const instance = this.single('context', () => this.instance()); if (instance === null) { throw new Error('ReactWrapper::context() can only be called on wrapped nodes that have a non-null instance'); } const _context = instance.context; if (typeof name !== 'undefined') { return _context[name]; } return _context; } /** * Returns a new wrapper with all of the children of the current wrapper. * * @param {EnzymeSelector} [selector] * @returns {ReactWrapper} */ children(selector) { const allChildren = this.flatMap((n) => childrenOfNode(n.getNodeInternal())); return selector ? allChildren.filter(selector) : allChildren; } /** * Returns a new wrapper with a specific child * * @param {Number} [index] * @returns {ReactWrapper} */ childAt(index) { return this.single('childAt', () => this.children().at(index)); } /** * Returns a wrapper around all of the parents/ancestors of the wrapper. Does not include the node * in the current wrapper. * * NOTE: can only be called on a wrapper of a single node. * * @param {EnzymeSelector} [selector] * @returns {ReactWrapper} */ parents(selector) { return this.single('parents', (n) => { const allParents = this.wrap(nodeParents(this, n)); return selector ? allParents.filter(selector) : allParents; }); } /** * Returns a wrapper around the immediate parent of the current node. * * @returns {ReactWrapper} */ parent() { return this.flatMap((n) => [n.parents().get(0)]); } /** * * @param {EnzymeSelector} selector * @returns {ReactWrapper} */ closest(selector) { if (this.is(selector)) { return this; } const matchingAncestors = this.parents().filter(selector); return matchingAncestors.length > 0 ? matchingAncestors.first() : this.findWhere(() => false); } /** * Returns the value of prop with the given name of the root node. * * @param {String} propName * @returns {*} */ prop(propName) { return this.props()[propName]; } /** * Used to invoke a function prop. * Will invoke an function prop and return its value. * * @param {String} propName * @returns {Any} */ invoke(propName) { return this.single('invoke', () => { const handler = this.prop(propName); if (typeof handler !== 'function') { throw new TypeError('ReactWrapper::invoke() requires the name of a prop whose value is a function'); } return (...args) => { const response = typeof this[RENDERER].wrapInvoke === 'function' ? this[RENDERER].wrapInvoke(() => handler(...args)) : handler(...args); this[ROOT].update(); return response; }; }); } /** * Returns a wrapper of the node rendered by the provided render prop. * * @param {String} propName * @returns {Function} */ renderProp(propName) { const adapter = getAdapter(this[OPTIONS]); if (typeof adapter.wrap !== 'function') { throw new RangeError('your adapter does not support `wrap`. Try upgrading it!'); } return this.single('renderProp', (n) => { if (n.nodeType === 'host') { throw new TypeError('ReactWrapper::renderProp() can only be called on custom components'); } if (typeof propName !== 'string') { throw new TypeError('ReactWrapper::renderProp(): `propName` must be a string'); } const props = this.props(); if (!hasOwn(props, propName)) { throw new Error(`ReactWrapper::renderProp(): no prop called “${propName}“ found`); } const propValue = props[propName]; if (typeof propValue !== 'function') { throw new TypeError(`ReactWrapper::renderProp(): expected prop “${propName}“ to contain a function, but it holds “${typeof propValue}“`); } return (...args) => { const element = propValue(...args); const wrapped = adapter.wrap(element); return this.wrap(wrapped, null, this[OPTIONS]); }; }); } /** * Returns the key assigned to the current node. * * @returns {String} */ key() { return this.single('key', (n) => (n.key === undefined ? null : n.key)); } /** * Returns the type of the root node of this wrapper. If it's a composite component, this will be * the component constructor. If it's native DOM node, it will be a string. * * @returns {String|Function} */ type() { return this.single('type', (n) => typeOfNode(n)); } /** * Returns the name of the root node of this wrapper. * * In order of precedence => type.displayName -> type.name -> type. * * @returns {String} */ name() { const adapter = getAdapter(this[OPTIONS]); return this.single('name', (n) => ( adapter.displayNameOfNode ? adapter.displayNameOfNode(n) : displayNameOfNode(n) )); } /** * Returns whether or not the current root node has the given class name or not. * * NOTE: can only be called on a wrapper of a single node. * * @param {String} className * @returns {Boolean} */ hasClass(className) { if (typeof className === 'string' && className.indexOf('.') !== -1) { // eslint-disable-next-line no-console console.warn('It looks like you\'re calling `ReactWrapper::hasClass()` with a CSS selector. hasClass() expects a class name, not a CSS selector.'); } return this.single('hasClass', (n) => hasClassName(n, className)); } /** * Iterates through each node of the current wrapper and executes the provided function with a * wrapper around the corresponding node passed in as the first argument. * * @param {Function} fn * @returns {ReactWrapper} */ forEach(fn) { this.getNodesInternal().forEach((n, i) => fn.call(this, this.wrap(n), i)); return this; } /** * Maps the current array of nodes to another array. Each node is passed in as a `ReactWrapper` * to the map function. * * @param {Function} fn * @returns {Array} */ map(fn) { return this.getNodesInternal().map((n, i) => fn.call(this, this.wrap(n), i)); } /** * Reduces the current array of nodes to another array. * Each node is passed in as a `ShallowWrapper` to the reducer function. * * @param {Function} fn - the reducer function * @param {*} initialValue - the initial value * @returns {*} */ reduce(fn, initialValue = undefined) { if (arguments.length > 1) { return this.getNodesInternal().reduce( (accum, n, i) => fn.call(this, accum, this.wrap(n), i), initialValue, ); } return this.getNodesInternal().reduce((accum, n, i) => fn.call( this, i === 1 ? this.wrap(accum) : accum, this.wrap(n), i, )); } /** * Reduces the current array of nodes to another array, from right to left. Each node is passed * in as a `ShallowWrapper` to the reducer function. * * @param {Function} fn - the reducer function * @param {*} initialValue - the initial value * @returns {*} */ reduceRight(fn, initialValue = undefined) { if (arguments.length > 1) { return this.getNodesInternal().reduceRight( (accum, n, i) => fn.call(this, accum, this.wrap(n), i), initialValue, ); } return this.getNodesInternal().reduceRight((accum, n, i) => fn.call( this, i === 1 ? this.wrap(accum) : accum, this.wrap(n), i, )); } /** * Returns a new wrapper with a subset of the nodes of the original wrapper, according to the * rules of `Array#slice`. * * @param {Number} begin * @param {Number} end * @returns {ShallowWrapper} */ slice(begin, end) { return this.wrap(this.getNodesInternal().slice(begin, end)); } /** * Returns whether or not any of the nodes in the wrapper match the provided selector. * * @param {EnzymeSelector} selector * @returns {Boolean} */ some(selector) { if (this[ROOT] === this) { throw new Error('ReactWrapper::some() can not be called on the root'); } const predicate = buildPredicate(selector); return this.getNodesInternal().some(predicate); } /** * Returns whether or not any of the nodes in the wrapper pass the provided predicate function. * * @param {Function} predicate * @returns {Boolean} */ someWhere(predicate) { return this.getNodesInternal().some((n, i) => predicate.call(this, this.wrap(n), i)); } /** * Returns whether or not all of the nodes in the wrapper match the provided selector. * * @param {EnzymeSelector} selector * @returns {Boolean} */ every(selector) { const predicate = buildPredicate(selector); return this.getNodesInternal().every(predicate); } /** * Returns whether or not any of the nodes in the wrapper pass the provided predicate function. * * @param {Function} predicate * @returns {Boolean} */ everyWhere(predicate) { return this.getNodesInternal().every((n, i) => predicate.call(this, this.wrap(n), i)); } /** * Utility method used to create new wrappers with a mapping function that returns an array of * nodes in response to a single node wrapper. The returned wrapper is a single wrapper around * all of the mapped nodes flattened (and de-duplicated). * * @param {Function} fn * @returns {ReactWrapper} */ flatMap(fn) { const nodes = this.getNodesInternal().map((n, i) => fn.call(this, this.wrap(n), i)); const flattened = flat(nodes, 1); return this.wrap(flattened.filter(Boolean)); } /** * Finds all nodes in the current wrapper nodes' render trees that match the provided predicate * function. * * @param {Function} predicate * @returns {ReactWrapper} */ findWhere(predicate) { return findWhereUnwrapped(this, (n) => { const node = this.wrap(n); return node.length > 0 && predicate(node); }); } /** * Returns the node at a given index of the current wrapper. * * @param {Number} index * @returns {ReactElement} */ get(index) { return this.getElements()[index]; } /** * Returns a wrapper around the node at a given index of the current wrapper. * * @param {Number} index * @returns {ReactWrapper} */ at(index) { const nodes = this.getNodesInternal(); if (index < nodes.length) { return this.wrap(nodes[index]); } return this.wrap([]); } /** * Returns a wrapper around the first node of the current wrapper. * * @returns {ReactWrapper} */ first() { return this.at(0); } /** * Returns a wrapper around the last node of the current wrapper. * * @returns {ReactWrapper} */ last() { return this.at(this.length - 1); } /** * Delegates to exists() * * @returns {boolean} */ isEmpty() { // eslint-disable-next-line no-console console.warn('Enzyme::Deprecated method isEmpty() called, use exists() instead.'); return !this.exists(); } /** * Returns true if the current wrapper has nodes. False otherwise. * If called with a selector it returns `.find(selector).exists()` instead. * * @param {EnzymeSelector} selector (optional) * @returns {boolean} */ exists(selector = null) { return arguments.length > 0 ? this.find(selector).exists() : this.length > 0; } /** * Utility method that throws an error if the current instance has a length other than one. * This is primarily used to enforce that certain methods are only run on a wrapper when it is * wrapping a single node. * * @param {Function} fn * @returns {*} */ single(name, fn) { const fnName = typeof name === 'string' ? name : 'unknown'; const callback = typeof fn === 'function' ? fn : name; if (this.length !== 1) { throw new Error(`Method “${fnName}” is meant to be run on 1 node. ${this.length} found instead.`); } return callback.call(this, this.getNodeInternal()); } /** * Helpful utility method to create a new wrapper with the same root as the current wrapper, with * any nodes passed in as the first parameter automatically wrapped. * * @param {ReactWrapper|ReactElement|Array} node * @returns {ReactWrapper} */ wrap(node, root = this[ROOT], ...args) { if (node instanceof ReactWrapper) { return node; } return new ReactWrapper(node, root, ...args); } /** * Returns an HTML-like string of the shallow render for debugging purposes. * * @param {Object} [options] - Property bag of additional options. * @param {boolean} [options.ignoreProps] - if true, props are omitted from the string. * @param {boolean} [options.verbose] - if true, arrays and objects to be verbosely printed. * @returns {String} */ debug(options = {}) { return debugNodes(this.getNodesInternal(), options); } /** * Invokes intercepter and returns itself. intercepter is called with itself. * This is helpful when debugging nodes in method chains. * @param fn * @returns {ReactWrapper} */ tap(intercepter) { intercepter(this); return this; } /** * Detaches the react tree from the DOM. Runs `ReactDOM.unmountComponentAtNode()` under the hood. * * This method will most commonly be used as a "cleanup" method if you decide to use the * `attachTo` option in `mount(node, options)`. * * The method is intentionally not "fluent" (in that it doesn't return `this`) because you should * not be doing anything with this wrapper after this method is called. */ detach() { if (this[ROOT] !== this) { throw new Error('ReactWrapper::detach() can only be called on the root'); } if (!this[OPTIONS].attachTo) { throw new Error('ReactWrapper::detach() can only be called on when the `attachTo` option was passed into `mount()`.'); } this[RENDERER].unmount(); } /** * Strips out all the not host-nodes from the list of nodes * * This method is useful if you want to check for the presence of host nodes * (actually rendered HTML elements) ignoring the React nodes. */ hostNodes() { return this.filterWhere((n) => typeof n.type() === 'string'); } } /** * A *special* "root" wrapper that represents the component passed as `wrappingComponent`. * It is linked to the primary root such that updates to it will update the primary, * and vice versa. * * @class WrappingComponentWrapper */ class WrappingComponentWrapper extends ReactWrapper { /* eslint-disable class-methods-use-this */ constructor(root, renderer) { super(renderer.getNode(), root); privateSet(this, ROOT, this); privateSet(this, RENDERER, renderer); this[LINKED_ROOTS].push(root); } getWrappingComponent() { throw new TypeError('ReactWrapper::getWrappingComponent() can only be called on the root'); } } if (ITERATOR_SYMBOL) { Object.defineProperty(ReactWrapper.prototype, ITERATOR_SYMBOL, { configurable: true, value: function iterator() { const iter = this[NODES][ITERATOR_SYMBOL](); const adapter = getAdapter(this[OPTIONS]); return { [ITERATOR_SYMBOL]() { return this; }, next() { const next = iter.next(); if (next.done) { return { done: true }; } return { done: false, value: adapter.nodeToElement(next.value), }; }, }; }, }); } function privateWarning(prop, extraMessage) { Object.defineProperty(ReactWrapper.prototype, prop, { get() { throw new Error(trim(` Attempted to access ReactWrapper::${prop}, which was previously a private property on Enzyme ReactWrapper instances, but is no longer and should not be relied upon. ${extraMessage} `)); }, enumerable: false, configurable: false, }); } privateWarning('node', 'Consider using the getElement() method instead.'); privateWarning('nodes', 'Consider using the getElements() method instead.'); privateWarning('renderer', ''); privateWarning('options', ''); privateWarning('complexSelector', ''); export default ReactWrapper; ================================================ FILE: packages/enzyme/src/ShallowWrapper.js ================================================ import flat from 'array.prototype.flat'; import hasOwn from 'hasown'; import shallowEqual from 'enzyme-shallow-equal'; import trim from 'string.prototype.trim'; import { nodeEqual, nodeMatches, containsChildrenSubArray, withSetStateAllowed, typeOfNode, isReactElementAlike, displayNameOfNode, isCustomComponent, isCustomComponentElement, ITERATOR_SYMBOL, makeOptions, sym, privateSet, cloneElement, spyMethod, isEmptyValue, loadCheerioRoot, } from './Utils'; import getAdapter from './getAdapter'; import { debugNodes } from './Debug'; import { propsOfNode, getTextFromNode, hasClassName, childrenOfNode, parentsOfNode, treeFilter, } from './RSTTraversal'; import { buildPredicate, reduceTreesBySelector } from './selectors'; const NODE = sym('__node__'); const NODES = sym('__nodes__'); const RENDERER = sym('__renderer__'); const UNRENDERED = sym('__unrendered__'); const ROOT = sym('__root__'); const OPTIONS = sym('__options__'); const SET_STATE = sym('__setState__'); const ROOT_NODES = sym('__rootNodes__'); const CHILD_CONTEXT = sym('__childContext__'); const WRAPPING_COMPONENT = sym('__wrappingComponent__'); const PRIMARY_WRAPPER = sym('__primaryWrapper__'); const ROOT_FINDER = sym('__rootFinder__'); const PROVIDER_VALUES = sym('__providerValues__'); /** * Finds all nodes in the current wrapper nodes' render trees that match the provided predicate * function. * * @param {ShallowWrapper} wrapper * @param {Function} predicate * @param {Function} filter * @returns {ShallowWrapper} */ function findWhereUnwrapped(wrapper, predicate, filter = treeFilter) { return wrapper.flatMap((n) => filter(n.getNodeInternal(), predicate)); } /** * Returns a new wrapper instance with only the nodes of the current wrapper instance that match * the provided predicate function. * * @param {ShallowWrapper} wrapper * @param {Function} predicate * @returns {ShallowWrapper} */ function filterWhereUnwrapped(wrapper, predicate) { return wrapper.wrap(wrapper.getNodesInternal().filter(predicate).filter(Boolean)); } /** * Ensure options passed to ShallowWrapper are valid. Throws otherwise. * @param {Object} options */ function validateOptions(options) { const { lifecycleExperimental, disableLifecycleMethods, enableComponentDidUpdateOnSetState, supportPrevContextArgumentOfComponentDidUpdate, lifecycles = {}, } = options; if (typeof lifecycleExperimental !== 'undefined' && typeof lifecycleExperimental !== 'boolean') { throw new Error('lifecycleExperimental must be either true or false if provided'); } if (typeof disableLifecycleMethods !== 'undefined' && typeof disableLifecycleMethods !== 'boolean') { throw new Error('disableLifecycleMethods must be either true or false if provided'); } if ( lifecycleExperimental != null && disableLifecycleMethods != null && lifecycleExperimental === disableLifecycleMethods ) { throw new Error('lifecycleExperimental and disableLifecycleMethods cannot be set to the same value'); } if ( typeof enableComponentDidUpdateOnSetState !== 'undefined' && lifecycles.componentDidUpdate && lifecycles.componentDidUpdate.onSetState !== enableComponentDidUpdateOnSetState ) { throw new TypeError('the legacy enableComponentDidUpdateOnSetState option should be matched by `lifecycles: { componentDidUpdate: { onSetState: true } }`, for compatibility'); } if ( typeof supportPrevContextArgumentOfComponentDidUpdate !== 'undefined' && lifecycles.componentDidUpdate && lifecycles.componentDidUpdate.prevContext !== supportPrevContextArgumentOfComponentDidUpdate ) { throw new TypeError('the legacy supportPrevContextArgumentOfComponentDidUpdate option should be matched by `lifecycles: { componentDidUpdate: { prevContext: true } }`, for compatibility'); } } function getAdapterLifecycles({ options }) { const { lifecycles = {}, enableComponentDidUpdateOnSetState, supportPrevContextArgumentOfComponentDidUpdate, } = options; const hasLegacySetStateArg = typeof enableComponentDidUpdateOnSetState !== 'undefined'; const hasLegacyPrevContextArg = typeof supportPrevContextArgumentOfComponentDidUpdate !== 'undefined'; const componentDidUpdate = hasLegacySetStateArg || hasLegacyPrevContextArg ? { ...(hasLegacySetStateArg && { onSetState: !!enableComponentDidUpdateOnSetState, }), ...(hasLegacyPrevContextArg && { prevContext: !!supportPrevContextArgumentOfComponentDidUpdate, }), } : null; const { getDerivedStateFromProps: originalGDSFP } = lifecycles; const getDerivedStateFromProps = originalGDSFP ? { hasShouldComponentUpdateBug: !!originalGDSFP.hasShouldComponentUpdateBug, } : false; return { ...lifecycles, setState: { ...lifecycles.setState, }, getChildContext: { calledByRenderer: true, ...lifecycles.getChildContext, }, ...(componentDidUpdate && { componentDidUpdate }), getDerivedStateFromProps, }; } function getRootNode(node) { if (node.nodeType === 'host') { return node; } return node.rendered; } function getRootNodeInternal(wrapper) { if (wrapper[ROOT].length !== 1) { throw new Error('getRootNodeInternal(wrapper) can only be called when wrapper wraps one node'); } if (wrapper[ROOT] !== wrapper) { return wrapper[ROOT_NODES][0]; } return wrapper[ROOT][NODE]; } function nodeParents(wrapper, node) { return parentsOfNode(node, getRootNodeInternal(wrapper)); } function privateSetNodes(wrapper, nodes) { if (!Array.isArray(nodes)) { privateSet(wrapper, NODE, nodes); privateSet(wrapper, NODES, [nodes]); } else { privateSet(wrapper, NODE, nodes[0]); privateSet(wrapper, NODES, nodes); } privateSet(wrapper, 'length', wrapper[NODES].length); } function pureComponentShouldComponentUpdate(prevProps, props, prevState, state) { return !shallowEqual(prevProps, props) || !shallowEqual(prevState, state); } function isPureComponent(instance) { return instance && instance.isPureReactComponent; } function getChildContext(node, hierarchy, renderer) { const { instance, type: Component } = node; const componentName = displayNameOfNode(node); // Warn like react if childContextTypes is not defined: // https://github.com/facebook/react/blob/1454a8be03794f5e0b23a7e7696cbbbdcf8b0f5d/packages/react-dom/src/server/ReactPartialRenderer.js#L639-L646 if (typeof Component.childContextTypes !== 'object') { // eslint-disable-next-line no-console console.warn( `${componentName}.getChildContext(): childContextTypes must be defined in order to use getChildContext().`, ); return {}; } // Check childContextTypes like react: // https://github.com/facebook/react/blob/1454a8be03794f5e0b23a7e7696cbbbdcf8b0f5d/packages/react-dom/src/server/ReactPartialRenderer.js#L630-L637 const childContext = instance.getChildContext(); Object.keys(childContext).forEach((key) => { if (!(key in Component.childContextTypes)) { throw new Error( `${componentName}.getChildContext(): key "${key}" is not defined in childContextTypes.`, ); } }); if (typeof renderer.checkPropTypes === 'function') { renderer.checkPropTypes(Component.childContextTypes, childContext, 'child context', hierarchy); } return childContext; } function spyOnGetChildContextInitialRender(nodes, adapter) { if ( !isCustomComponentElement(nodes, adapter) || !nodes.type.prototype || typeof nodes.type.prototype.getChildContext !== 'function' ) { return null; } return spyMethod(nodes.type.prototype, 'getChildContext'); } function privateSetChildContext(adapter, wrapper, instance, renderedNode, getChildContextSpy) { const renderer = wrapper[RENDERER]; // We only support parent-based context. if (adapter.options.legacyContextMode !== 'parent') { return; } if (getChildContextSpy) { privateSet(wrapper, CHILD_CONTEXT, getChildContextSpy.getLastReturnValue()); getChildContextSpy.restore(); } else if (typeof instance.getChildContext === 'function') { // If there's no spy but getChildContext is a function, that means our renderer // is not going to call it for us, so we need to call it ourselves. const nodeHierarchy = [wrapper[NODE]].concat(nodeParents(wrapper, wrapper[NODE])); const childContext = getChildContext(renderedNode, nodeHierarchy, renderer); privateSet(wrapper, CHILD_CONTEXT, childContext); } else { privateSet(wrapper, CHILD_CONTEXT, null); } } function mockSCUIfgDSFPReturnNonNull(node, state) { const { getDerivedStateFromProps } = node.type; if (typeof getDerivedStateFromProps === 'function') { // we try to fix a React shallow renderer bug here. // (facebook/react#14607, which has been fixed in react 16.8): // when gDSFP return derived state, it will set instance state in shallow renderer before SCU, // this will cause `this.state` in sCU be the updated state, which is wrong behavior. // so we have to wrap sCU to pass the old state to original sCU. const { instance } = node; const { restore } = spyMethod( instance, 'shouldComponentUpdate', (originalSCU) => function shouldComponentUpdate(...args) { instance.state = state; const sCUResult = originalSCU.apply(instance, args); const [, nextState] = args; instance.state = nextState; restore(); return sCUResult; }, ); } } /** * Recursively dive()s every custom component in a wrapper until * the target component is found. * * @param {ShallowWrapper} wrapper A ShallowWrapper to search * @param {ComponentType} target A react custom component that, when found, will end recursion * @param {Adapter} adapter An Enzyme adapter * @returns {ShallowWrapper|undefined} A ShallowWrapper for the target, or * undefined if it can't be found */ function deepRender(wrapper, target, adapter) { const node = wrapper[NODE]; const element = node && adapter.nodeToElement(node); if (wrapper.type() === target) { return wrapper.dive(); } if (element && isCustomComponentElement(element, adapter)) { return deepRender(wrapper.dive(), target, adapter); } const children = wrapper.children(); for (let i = 0; i < children.length; i += 1) { const found = deepRender(children.at(i), target, adapter); if (typeof found !== 'undefined') { return found; } } return undefined; } /** * Deep-renders the `wrappingComponent` and returns the context that should * be accessible to the primary wrapper. * * @param {WrappingComponentWrapper} wrapper The `WrappingComponentWrapper` for a * `wrappingComponent` * @param {Adapter} adapter An Enzyme adapter * @returns {object} An object containing an object of legacy context values and a Map of * `createContext()` Provider values. */ function getContextFromWrappingComponent(wrapper, adapter) { const rootFinder = deepRender(wrapper, wrapper[ROOT_FINDER], adapter); if (!rootFinder) { throw new Error('`wrappingComponent` must render its children!'); } return { legacyContext: rootFinder[OPTIONS].context, providerValues: rootFinder[PROVIDER_VALUES], }; } /** * Makes options specifically for `ShallowWrapper`. Most of the logic here is around rendering * a `wrappingComponent` (if one was provided) and adding the child context of that component * to `options.context`. * * @param {ReactElement} nodes the nodes passed to `ShallowWrapper` * @param {ShallowWrapper} root this `ShallowWrapper`'s parent. If this is passed, options are * not transformed. * @param {*} passedOptions the options passed to `ShallowWrapper`. * @param {*} wrapper the `ShallowWrapper` itself * @returns {Object} the decorated and transformed options */ function makeShallowOptions(nodes, root, passedOptions, wrapper) { const options = makeOptions(passedOptions); const adapter = getAdapter(passedOptions); privateSet(options, PROVIDER_VALUES, passedOptions[PROVIDER_VALUES]); if (root || !isCustomComponent(options.wrappingComponent, adapter)) { return options; } if (typeof adapter.wrapWithWrappingComponent !== 'function') { throw new TypeError('your adapter does not support `wrappingComponent`. Try upgrading it!'); } const { node: wrappedNode, RootFinder } = adapter.wrapWithWrappingComponent(nodes, options); // eslint-disable-next-line no-use-before-define const wrappingComponent = new WrappingComponentWrapper(wrappedNode, wrapper, RootFinder); const { legacyContext: wrappingComponentLegacyContext, providerValues: wrappingComponentProviderValues, } = getContextFromWrappingComponent(wrappingComponent, adapter); privateSet(wrapper, WRAPPING_COMPONENT, wrappingComponent); return { ...options, context: { ...options.context, ...wrappingComponentLegacyContext, }, [PROVIDER_VALUES]: wrappingComponentProviderValues, }; } function makeInheritedChildOptions(wrapper, options = {}) { const childOptions = { ...wrapper[OPTIONS], ...options, context: options.context || { ...wrapper[OPTIONS].context, ...wrapper[ROOT][CHILD_CONTEXT], }, }; privateSet(childOptions, PROVIDER_VALUES, wrapper[ROOT][PROVIDER_VALUES]); return childOptions; } /** * @class ShallowWrapper */ class ShallowWrapper { constructor(nodes, root, passedOptions = {}) { validateOptions(passedOptions); const options = makeShallowOptions(nodes, root, passedOptions, this); const adapter = getAdapter(options); const lifecycles = getAdapterLifecycles(adapter); // mounting a ShallowRender component if (!root) { if (!adapter.isValidElement(nodes)) { throw new TypeError('ShallowWrapper can only wrap valid elements'); } const getChildContextSpy = lifecycles.getChildContext.calledByRenderer ? spyOnGetChildContextInitialRender(nodes, adapter) : null; privateSet(this, ROOT, this); privateSet(this, UNRENDERED, nodes); const renderer = adapter.createRenderer({ mode: 'shallow', ...options }); privateSet(this, RENDERER, renderer); const providerValues = new Map(options[PROVIDER_VALUES] || []); this[RENDERER].render(nodes, options.context, { providerValues }); const renderedNode = this[RENDERER].getNode(); privateSetNodes(this, getRootNode(renderedNode)); privateSet(this, OPTIONS, options); privateSet(this, PROVIDER_VALUES, providerValues); const { instance } = renderedNode; if (instance && !options.disableLifecycleMethods) { // Ensure to call componentDidUpdate when instance.setState is called if (lifecycles.componentDidUpdate.onSetState && !instance[SET_STATE]) { privateSet(instance, SET_STATE, instance.setState); instance.setState = (updater, callback = undefined) => this.setState( ...(callback == null ? [updater] : [updater, callback]), ); } if (typeof instance.componentDidMount === 'function') { this[RENDERER].batchedUpdates(() => { instance.componentDidMount(); }); } privateSetChildContext(adapter, this, instance, renderedNode, getChildContextSpy); } // creating a child component through enzyme's ShallowWrapper APIs. } else { privateSet(this, ROOT, root); privateSet(this, UNRENDERED, null); privateSet(this, RENDERER, root[RENDERER]); privateSetNodes(this, nodes); privateSet(this, OPTIONS, root[OPTIONS]); privateSet(this, ROOT_NODES, root[NODES]); privateSet(this, PROVIDER_VALUES, null); } } /** * Returns the root wrapper * * @return {ShallowWrapper} */ root() { return this[ROOT]; } /** * Returns the wrapped component. * * @return {ReactComponent} */ getNodeInternal() { if (this.length !== 1) { throw new Error('ShallowWrapper::getNode() can only be called when wrapping one node'); } if (this[ROOT] === this) { this.update(); } return this[NODE]; } /** * Returns the the wrapped components. * * @return {Array} */ getNodesInternal() { if (this[ROOT] === this && this.length === 1) { this.update(); } return this[NODES]; } /** * Returns the wrapped ReactElement. * * @return {ReactElement} */ getElement() { return this.single('getElement', (n) => getAdapter(this[OPTIONS]).nodeToElement(n)); } /** * Returns the wrapped ReactElements. * * @return {Array} */ getElements() { return this.getNodesInternal().map((n) => getAdapter(this[OPTIONS]).nodeToElement(n)); } // eslint-disable-next-line class-methods-use-this getNode() { throw new Error('ShallowWrapper::getNode() is no longer supported. Use ShallowWrapper::getElement() instead'); } // eslint-disable-next-line class-methods-use-this getNodes() { throw new Error('ShallowWrapper::getNodes() is no longer supported. Use ShallowWrapper::getElements() instead'); } /** * Gets the instance of the component being rendered as the root node passed into `shallow()`. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * Example: * ``` * const wrapper = shallow(); * const inst = wrapper.instance(); * expect(inst).to.be.instanceOf(MyComponent); * ``` * @returns {ReactComponent} */ instance() { if (this[ROOT] !== this) { throw new Error('ShallowWrapper::instance() can only be called on the root'); } return this[RENDERER].getNode().instance; } /** * If a `wrappingComponent` was passed in `options`, this methods returns a `ShallowWrapper` * around the rendered `wrappingComponent`. This `ShallowWrapper` can be used to update the * `wrappingComponent`'s props, state, etc. * * @returns ShallowWrapper */ getWrappingComponent() { if (this[ROOT] !== this) { throw new Error('ShallowWrapper::getWrappingComponent() can only be called on the root'); } if (!this[OPTIONS].wrappingComponent) { throw new Error('ShallowWrapper::getWrappingComponent() can only be called on a wrapper that was originally passed a `wrappingComponent` option'); } return this[WRAPPING_COMPONENT]; } /** * Forces a re-render. Useful to run before checking the render output if something external * may be updating the state of the component somewhere. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @returns {ShallowWrapper} */ update() { if (this[ROOT] !== this) { throw new Error('ShallowWrapper::update() can only be called on the root'); } if (this.length !== 1) { throw new Error('ShallowWrapper::update() can only be called when wrapping one node'); } privateSetNodes(this, getRootNode(this[RENDERER].getNode())); return this; } /** * A method that unmounts the component. This can be used to simulate a component going through * and unmount/mount lifecycle. * @returns {ShallowWrapper} */ unmount() { this[RENDERER].unmount(); if (this[ROOT][WRAPPING_COMPONENT]) { this[ROOT][WRAPPING_COMPONENT].unmount(); } return this; } /** * A method is for re-render with new props and context. * This calls componentDidUpdate method if disableLifecycleMethods is not enabled. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {Object} props * @param {Object} context * @returns {ShallowWrapper} */ rerender(props, context) { const adapter = getAdapter(this[OPTIONS]); this.single('rerender', () => { withSetStateAllowed(() => { // NOTE(lmr): In react 16, instances will be null for SFCs, but // rerendering with props/context is still a valid thing to do. In // this case, state will be undefined, but props/context will exist. const node = this[RENDERER].getNode(); const instance = node.instance || {}; const type = node.type || {}; const { state } = instance; const prevProps = instance.props || this[UNRENDERED].props; const prevContext = instance.context || this[OPTIONS].context; const nextContext = context || prevContext; if (context) { this[OPTIONS] = { ...this[OPTIONS], context: nextContext }; } this[RENDERER].batchedUpdates(() => { // When shouldComponentUpdate returns false we shouldn't call componentDidUpdate. // so we spy shouldComponentUpdate to get the result. const lifecycles = getAdapterLifecycles(adapter); let shouldRender = true; let shouldComponentUpdateSpy; let getChildContextSpy; if ( !this[OPTIONS].disableLifecycleMethods && instance ) { if (typeof instance.shouldComponentUpdate === 'function') { const { getDerivedStateFromProps: gDSFP } = lifecycles; if (gDSFP && gDSFP.hasShouldComponentUpdateBug) { mockSCUIfgDSFPReturnNonNull(node, state); } shouldComponentUpdateSpy = spyMethod(instance, 'shouldComponentUpdate'); } if ( lifecycles.getChildContext.calledByRenderer && typeof instance.getChildContext === 'function' ) { getChildContextSpy = spyMethod(instance, 'getChildContext'); } } if (!shouldComponentUpdateSpy && isPureComponent(instance)) { shouldRender = pureComponentShouldComponentUpdate( prevProps, props, state, instance.state, ); } if (props) this[UNRENDERED] = cloneElement(adapter, this[UNRENDERED], props); this[RENDERER].render(this[UNRENDERED], nextContext, { providerValues: this[PROVIDER_VALUES], }); if (shouldComponentUpdateSpy) { shouldRender = shouldComponentUpdateSpy.getLastReturnValue(); shouldComponentUpdateSpy.restore(); } if ( shouldRender && !this[OPTIONS].disableLifecycleMethods && instance ) { privateSetChildContext(adapter, this, instance, node, getChildContextSpy); if (lifecycles.getSnapshotBeforeUpdate) { let snapshot; if (typeof instance.getSnapshotBeforeUpdate === 'function') { snapshot = instance.getSnapshotBeforeUpdate(prevProps, state); } if ( lifecycles.componentDidUpdate && typeof instance.componentDidUpdate === 'function' && ( !state || shallowEqual(state, this.instance().state) || typeof type.getDerivedStateFromProps === 'function' ) ) { instance.componentDidUpdate(prevProps, state, snapshot); } } else if ( lifecycles.componentDidUpdate && typeof instance.componentDidUpdate === 'function' ) { if (lifecycles.componentDidUpdate.prevContext) { instance.componentDidUpdate(prevProps, state, prevContext); } else if (!state || shallowEqual(this.instance().state, state)) { instance.componentDidUpdate(prevProps, state); } } // If it doesn't need to rerender, update only its props. } else if (!shallowEqual(props, instance.props)) { instance.props = (Object.freeze || Object)({ ...instance.props, ...props }); } this.update(); }); }); }); return this; } /** * A method that sets the props of the root component, and re-renders. Useful for when you are * wanting to test how the component behaves over time with changing props. Calling this, for * instance, will call the `componentWillReceiveProps` lifecycle method. * * Similar to `setState`, this method accepts a props object and will merge it in with the already * existing props. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {Object} props object * @param {Function} cb - callback function * @returns {ShallowWrapper} */ setProps(props, callback = undefined) { if (this[ROOT] !== this) { throw new Error('ShallowWrapper::setProps() can only be called on the root'); } if (arguments.length > 1 && typeof callback !== 'function') { throw new TypeError('ReactWrapper::setProps() expects a function as its second argument'); } this.rerender(props); if (callback) { callback(); } return this; } /** * A method to invoke `setState` on the root component instance similar to how you might in the * definition of the component, and re-renders. This method is useful for testing your component * in hard to achieve states, however should be used sparingly. If possible, you should utilize * your component's external API in order to get it into whatever state you want to test, in order * to be as accurate of a test as possible. This is not always practical, however. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {Object} state to merge * @param {Function} cb - callback function * @returns {ShallowWrapper} */ setState(state, callback = undefined) { if (this[ROOT] !== this) { throw new Error('ShallowWrapper::setState() can only be called on the root'); } if (this.instance() === null || this[RENDERER].getNode().nodeType !== 'class') { throw new Error('ShallowWrapper::setState() can only be called on class components'); } if (arguments.length > 1 && typeof callback !== 'function') { throw new TypeError('ReactWrapper::setState() expects a function as its second argument'); } this.single('setState', () => { withSetStateAllowed(() => { const adapter = getAdapter(this[OPTIONS]); const lifecycles = getAdapterLifecycles(adapter); const node = this[RENDERER].getNode(); const { instance } = node; const prevProps = instance.props; const prevState = instance.state; const prevContext = instance.context; const statePayload = typeof state === 'function' ? state.call(instance, prevState, prevProps) : state; // returning null or undefined prevents the update in React 16+ // https://github.com/facebook/react/pull/12756 const maybeHasUpdate = !lifecycles.setState.skipsComponentDidUpdateOnNullish || statePayload != null; // When shouldComponentUpdate returns false we shouldn't call componentDidUpdate. // so we spy shouldComponentUpdate to get the result. let shouldComponentUpdateSpy; let getChildContextSpy; let shouldRender = true; if ( !this[OPTIONS].disableLifecycleMethods && instance ) { if ( lifecycles.componentDidUpdate && lifecycles.componentDidUpdate.onSetState && typeof instance.shouldComponentUpdate === 'function' ) { const { getDerivedStateFromProps: gDSFP } = lifecycles; if (gDSFP && gDSFP.hasShouldComponentUpdateBug) { mockSCUIfgDSFPReturnNonNull(node, state); } shouldComponentUpdateSpy = spyMethod(instance, 'shouldComponentUpdate'); } if ( lifecycles.getChildContext.calledByRenderer && typeof instance.getChildContext === 'function' ) { getChildContextSpy = spyMethod(instance, 'getChildContext'); } } if (!shouldComponentUpdateSpy && isPureComponent(instance)) { shouldRender = pureComponentShouldComponentUpdate( prevProps, instance.props, prevState, { ...prevState, ...statePayload }, ); } // We don't pass the setState callback here // to guarantee to call the callback after finishing the render if (instance[SET_STATE]) { instance[SET_STATE](statePayload); } else { instance.setState(statePayload); } if (shouldComponentUpdateSpy) { shouldRender = shouldComponentUpdateSpy.getLastReturnValue(); shouldComponentUpdateSpy.restore(); } if ( maybeHasUpdate && shouldRender && !this[OPTIONS].disableLifecycleMethods ) { privateSetChildContext(adapter, this, instance, node, getChildContextSpy); if ( lifecycles.componentDidUpdate && lifecycles.componentDidUpdate.onSetState ) { if ( lifecycles.getSnapshotBeforeUpdate && typeof instance.getSnapshotBeforeUpdate === 'function' ) { const snapshot = instance.getSnapshotBeforeUpdate(prevProps, prevState); if (typeof instance.componentDidUpdate === 'function') { instance.componentDidUpdate(prevProps, prevState, snapshot); } } else if (typeof instance.componentDidUpdate === 'function') { if (lifecycles.componentDidUpdate.prevContext) { instance.componentDidUpdate(prevProps, prevState, prevContext); } else { instance.componentDidUpdate(prevProps, prevState); } } } } this.update(); // call the setState callback if (callback) { if (adapter.invokeSetStateCallback) { adapter.invokeSetStateCallback(instance, callback); } else { callback.call(instance); } } }); }); return this; } /** * A method that sets the context of the root component, and re-renders. Useful for when you are * wanting to test how the component behaves over time with changing contexts. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {Object} context object * @returns {ShallowWrapper} */ setContext(context) { if (this[ROOT] !== this) { throw new Error('ShallowWrapper::setContext() can only be called on the root'); } if (!this[OPTIONS].context) { throw new Error('ShallowWrapper::setContext() can only be called on a wrapper that was originally passed a context option'); } return this.rerender(null, context); } /** * Whether or not a given react element exists in the shallow render tree. * * Example: * ``` * const wrapper = shallow(); * expect(wrapper.contains(
)).to.equal(true); * ``` * * @param {ReactElement|Array} nodeOrNodes * @returns {Boolean} */ contains(nodeOrNodes) { const adapter = getAdapter(this[OPTIONS]); if (!isReactElementAlike(nodeOrNodes, adapter)) { throw new Error('ShallowWrapper::contains() can only be called with a ReactElement (or an array of them), a string, or a number as an argument.'); } const predicate = Array.isArray(nodeOrNodes) ? (other) => containsChildrenSubArray( nodeEqual, other, nodeOrNodes.map((node) => adapter.elementToNode(node)), ) : (other) => nodeEqual(adapter.elementToNode(nodeOrNodes), other); return findWhereUnwrapped(this, predicate).length > 0; } /** * Whether or not a given react element exists in the shallow render tree. * Match is based on the expected element and not on wrappers element. * It will determine if one of the wrappers element "looks like" the expected * element by checking if all props of the expected element are present * on the wrappers element and equals to each other. * * Example: * ``` * // MyComponent outputs
Hello
* const wrapper = shallow(); * expect(wrapper.containsMatchingElement(
Hello
)).to.equal(true); * ``` * * @param {ReactElement} node * @returns {Boolean} */ containsMatchingElement(node) { const adapter = getAdapter(this[OPTIONS]); const rstNode = adapter.elementToNode(node); const predicate = (other) => nodeMatches(rstNode, other, (a, b) => a <= b); return findWhereUnwrapped(this, predicate).length > 0; } /** * Whether or not all the given react elements exist in the shallow render tree. * Match is based on the expected element and not on wrappers element. * It will determine if one of the wrappers element "looks like" the expected * element by checking if all props of the expected element are present * on the wrappers element and equals to each other. * * Example: * ``` * const wrapper = shallow(); * expect(wrapper.containsAllMatchingElements([ *
Hello
, *
Goodbye
, * ])).to.equal(true); * ``` * * @param {Array} nodes * @returns {Boolean} */ containsAllMatchingElements(nodes) { if (!Array.isArray(nodes)) { throw new TypeError('nodes should be an Array'); } return nodes.every((node) => this.containsMatchingElement(node)); } /** * Whether or not one of the given react elements exists in the shallow render tree. * Match is based on the expected element and not on wrappers element. * It will determine if one of the wrappers element "looks like" the expected * element by checking if all props of the expected element are present * on the wrappers element and equals to each other. * * Example: * ``` * const wrapper = shallow(); * expect(wrapper.containsAnyMatchingElements([ *
Hello
, *
Goodbye
, * ])).to.equal(true); * ``` * * @param {Array} nodes * @returns {Boolean} */ containsAnyMatchingElements(nodes) { return Array.isArray(nodes) && nodes.some((node) => this.containsMatchingElement(node)); } /** * Whether or not a given react element exists in the render tree. * * Example: * ``` * const wrapper = shallow(); * expect(wrapper.contains(
)).to.equal(true); * ``` * * @param {ReactElement} node * @returns {Boolean} */ equals(node) { return this.single('equals', () => nodeEqual(this.getNodeInternal(), node)); } /** * Whether or not a given react element matches the render tree. * Match is based on the expected element and not on wrapper root node. * It will determine if the wrapper root node "looks like" the expected * element by checking if all props of the expected element are present * on the wrapper root node and equals to each other. * * Example: * ``` * // MyComponent outputs
Hello
* const wrapper = shallow(); * expect(wrapper.matchesElement(
Hello
)).to.equal(true); * ``` * * @param {ReactElement} node * @returns {Boolean} */ matchesElement(node) { return this.single('matchesElement', () => { const adapter = getAdapter(this[OPTIONS]); const rstNode = adapter.elementToNode(node); return nodeMatches(rstNode, this.getNodeInternal(), (a, b) => a <= b); }); } /** * Finds every node in the render tree of the current wrapper that matches the provided selector. * * @param {EnzymeSelector} selector * @returns {ShallowWrapper} */ find(selector) { return this.wrap(reduceTreesBySelector(selector, this.getNodesInternal())); } /** * Returns whether or not current node matches a provided selector. * * NOTE: can only be called on a wrapper of a single node. * * @param {EnzymeSelector} selector * @returns {boolean} */ is(selector) { const predicate = buildPredicate(selector); return this.single('is', (n) => predicate(n)); } /** * Returns true if the component rendered nothing, i.e., null or false. * * @returns {boolean} */ isEmptyRender() { const nodes = this.getNodesInternal(); return nodes.every((n) => isEmptyValue(n)); } /** * Returns a new wrapper instance with only the nodes of the current wrapper instance that match * the provided predicate function. The predicate should receive a wrapped node as its first * argument. * * @param {Function} predicate * @returns {ShallowWrapper} */ filterWhere(predicate) { return filterWhereUnwrapped(this, (n) => predicate(this.wrap(n))); } /** * Returns a new wrapper instance with only the nodes of the current wrapper instance that match * the provided selector. * * @param {EnzymeSelector} selector * @returns {ShallowWrapper} */ filter(selector) { const predicate = buildPredicate(selector); return filterWhereUnwrapped(this, predicate); } /** * Returns a new wrapper instance with only the nodes of the current wrapper that did not match * the provided selector. Essentially the inverse of `filter`. * * @param {EnzymeSelector} selector * @returns {ShallowWrapper} */ not(selector) { const predicate = buildPredicate(selector); return filterWhereUnwrapped(this, (n) => !predicate(n)); } /** * Returns a string of the rendered text of the current render tree. This function should be * looked at with skepticism if being used to test what the actual HTML output of the component * will be. If that is what you would like to test, use enzyme's `render` function instead. * * NOTE: can only be called on a wrapper of a single node. * * @returns {String} */ text() { return this.single('text', getTextFromNode); } /** * Returns the HTML of the node. * * NOTE: can only be called on a wrapper of a single node. * * @returns {String} */ html() { return this.single('html', (n) => { if (this.type() === null) return null; const adapter = getAdapter(this[OPTIONS]); const renderer = adapter.createRenderer({ ...this[OPTIONS], mode: 'string' }); return renderer.render(adapter.nodeToElement(n)); }); } /** * Returns the current node rendered to HTML and wrapped in a CheerioWrapper. * * NOTE: can only be called on a wrapper of a single node. * * @returns {CheerioWrapper} */ render() { const html = this.html(); return loadCheerioRoot(html); } /** * Used to simulate events. Pass an eventname and (optionally) event arguments. This method of * testing events should be met with some skepticism. * * @param {String} event * @param {Array} args * @returns {ShallowWrapper} */ simulate(event, ...args) { return this.single('simulate', (n) => { this[RENDERER].simulateEvent(n, event, ...args); this[ROOT].update(); return this; }); } /** * Used to simulate throwing a rendering error. Pass an error to throw. * * @param {String} error * @returns {ShallowWrapper} */ simulateError(error) { // in shallow, the "root" is the "rendered" thing. return this.single('simulateError', (thisNode) => { if (thisNode.nodeType === 'host') { throw new TypeError('ShallowWrapper::simulateError() can only be called on custom components'); } const renderer = this[RENDERER]; if (typeof renderer.simulateError !== 'function') { throw new TypeError('your adapter does not support `simulateError`. Try upgrading it!'); } const rootNode = getRootNodeInternal(this); const nodeHierarchy = [thisNode].concat(nodeParents(this, thisNode)); renderer.simulateError(nodeHierarchy, rootNode, error); return this; }); } /** * Returns the props hash for the current node of the wrapper. * * NOTE: can only be called on a wrapper of a single node. * * @returns {Object} */ props() { return this.single('props', propsOfNode); } /** * Returns the state hash for the root node of the wrapper. Optionally pass in a prop name and it * will return just that value. * * NOTE: can only be called on a wrapper of a single node. * * @param {String} name (optional) * @returns {*} */ state(name) { if (this[ROOT] !== this) { throw new Error('ShallowWrapper::state() can only be called on the root'); } if (this.instance() === null || this[RENDERER].getNode().nodeType !== 'class') { throw new Error('ShallowWrapper::state() can only be called on class components'); } const _state = this.single('state', () => this.instance().state); if (typeof name !== 'undefined') { if (_state == null) { throw new TypeError(`ShallowWrapper::state("${name}") requires that \`state\` not be \`null\` or \`undefined\``); } return _state[name]; } return _state; } /** * Returns the context hash for the root node of the wrapper. * Optionally pass in a prop name and it will return just that value. * * NOTE: can only be called on a wrapper of a single node. * * @param {String} name (optional) * @returns {*} */ context(name) { if (this[ROOT] !== this) { throw new Error('ShallowWrapper::context() can only be called on the root'); } if (!this[OPTIONS].context) { throw new Error('ShallowWrapper::context() can only be called on a wrapper that was originally passed a context option'); } if (this.instance() === null) { throw new Error('ShallowWrapper::context() can only be called on wrapped nodes that have a non-null instance'); } const _context = this.single('context', () => this.instance().context); if (name) { return _context[name]; } return _context; } /** * Returns a new wrapper with all of the children of the current wrapper. * * @param {EnzymeSelector} [selector] * @returns {ShallowWrapper} */ children(selector) { const allChildren = this.flatMap((n) => childrenOfNode(n.getNodeInternal())); return selector ? allChildren.filter(selector) : allChildren; } /** * Returns a new wrapper with a specific child * * @param {Number} [index] * @returns {ShallowWrapper} */ childAt(index) { return this.single('childAt', () => this.children().at(index)); } /** * Returns a wrapper around all of the parents/ancestors of the wrapper. Does not include the node * in the current wrapper. * * NOTE: can only be called on a wrapper of a single node. * * @param {EnzymeSelector} [selector] * @returns {ShallowWrapper} */ parents(selector) { return this.single('parents', (n) => { const allParents = this.wrap(nodeParents(this, n)); return selector ? allParents.filter(selector) : allParents; }); } /** * Returns a wrapper around the immediate parent of the current node. * * @returns {ShallowWrapper} */ parent() { return this.flatMap((n) => [n.parents().get(0)]); } /** * * @param {EnzymeSelector} selector * @returns {ShallowWrapper} */ closest(selector) { if (this.is(selector)) { return this; } const matchingAncestors = this.parents().filter(selector); return matchingAncestors.length > 0 ? matchingAncestors.first() : this.findWhere(() => false); } /** * Shallow renders the current node and returns a shallow wrapper around it. * * NOTE: can only be called on wrapper of a single node. * * @param {Object} options * @returns {ShallowWrapper} */ shallow(options = {}) { return this.single('shallow', (n) => { const childOptions = makeInheritedChildOptions(this, options); return this.wrap(getAdapter(this[OPTIONS]).nodeToElement(n), null, childOptions); }); } /** * Returns the value of prop with the given name of the current node. * * @param propName * @returns {*} */ prop(propName) { return this.props()[propName]; } /** * Used to invoke a function prop. * Will invoke an function prop and return its value. * * @param {String} propName * @returns {Any} */ invoke(propName) { return this.single('invoke', () => { const handler = this.prop(propName); if (typeof handler !== 'function') { throw new TypeError('ShallowWrapper::invoke() requires the name of a prop whose value is a function'); } return (...args) => { const response = handler(...args); this[ROOT].update(); return response; }; }); } /** * Returns a wrapper of the node rendered by the provided render prop. * * @param {String} propName * @returns {Function} */ renderProp(propName) { const adapter = getAdapter(this[OPTIONS]); if (typeof adapter.wrap !== 'function') { throw new RangeError('your adapter does not support `wrap`. Try upgrading it!'); } return this.single('renderProp', (n) => { if (n.nodeType === 'host') { throw new TypeError('ShallowWrapper::renderProp() can only be called on custom components'); } if (typeof propName !== 'string') { throw new TypeError('ShallowWrapper::renderProp(): `propName` must be a string'); } const props = this.props(); if (!hasOwn(props, propName)) { throw new Error(`ShallowWrapper::renderProp(): no prop called “${propName}“ found`); } const propValue = props[propName]; if (typeof propValue !== 'function') { throw new TypeError(`ShallowWrapper::renderProp(): expected prop “${propName}“ to contain a function, but it holds “${typeof propValue}“`); } return (...args) => { const element = propValue(...args); const wrapped = adapter.wrap(element); return this.wrap(wrapped, null, this[OPTIONS]); }; }); } /** * Returns the key assigned to the current node. * * @returns {String} */ key() { return this.single('key', (n) => (n.key === undefined ? null : n.key)); } /** * Returns the type of the current node of this wrapper. If it's a composite component, this will * be the component constructor. If it's a native DOM node, it will be a string of the tag name. * If it's null, it will be null. * * @returns {String|Function|null} */ type() { return this.single('type', (n) => typeOfNode(n)); } /** * Returns the name of the current node of this wrapper. * * In order of precedence => type.displayName -> type.name -> type. * * @returns {String} */ name() { const adapter = getAdapter(this[OPTIONS]); return this.single('name', (n) => ( adapter.displayNameOfNode ? adapter.displayNameOfNode(n) : displayNameOfNode(n) )); } /** * Returns whether or not the current node has the given class name or not. * * NOTE: can only be called on a wrapper of a single node. * * @param className * @returns {Boolean} */ hasClass(className) { if (typeof className === 'string' && className.indexOf('.') !== -1) { // eslint-disable-next-line no-console console.warn('It looks like you\'re calling `ShallowWrapper::hasClass()` with a CSS selector. hasClass() expects a class name, not a CSS selector.'); } return this.single('hasClass', (n) => hasClassName(n, className)); } /** * Iterates through each node of the current wrapper and executes the provided function with a * wrapper around the corresponding node passed in as the first argument. * * @param {Function} fn * @returns {ShallowWrapper} */ forEach(fn) { this.getNodesInternal().forEach((n, i) => fn.call(this, this.wrap(n), i)); return this; } /** * Maps the current array of nodes to another array. Each node is passed in as a `ShallowWrapper` * to the map function. * * @param {Function} fn * @returns {Array} */ map(fn) { return this.getNodesInternal().map((n, i) => fn.call(this, this.wrap(n), i)); } /** * Reduces the current array of nodes to a value. Each node is passed in as a `ShallowWrapper` * to the reducer function. * * @param {Function} fn - the reducer function * @param {*} initialValue - the initial value * @returns {*} */ reduce(fn, initialValue = undefined) { if (arguments.length > 1) { return this.getNodesInternal().reduce( (accum, n, i) => fn.call(this, accum, this.wrap(n), i), initialValue, ); } return this.getNodesInternal().reduce((accum, n, i) => fn.call( this, i === 1 ? this.wrap(accum) : accum, this.wrap(n), i, )); } /** * Reduces the current array of nodes to another array, from right to left. Each node is passed * in as a `ShallowWrapper` to the reducer function. * * @param {Function} fn - the reducer function * @param {*} initialValue - the initial value * @returns {*} */ reduceRight(fn, initialValue = undefined) { if (arguments.length > 1) { return this.getNodesInternal().reduceRight( (accum, n, i) => fn.call(this, accum, this.wrap(n), i), initialValue, ); } return this.getNodesInternal().reduceRight((accum, n, i) => fn.call( this, i === 1 ? this.wrap(accum) : accum, this.wrap(n), i, )); } /** * Returns a new wrapper with a subset of the nodes of the original wrapper, according to the * rules of `Array#slice`. * * @param {Number} begin * @param {Number} end * @returns {ShallowWrapper} */ slice(begin, end) { return this.wrap(this.getNodesInternal().slice(begin, end)); } /** * Returns whether or not any of the nodes in the wrapper match the provided selector. * * @param {EnzymeSelector} selector * @returns {Boolean} */ some(selector) { if (this[ROOT] === this) { throw new Error('ShallowWrapper::some() can not be called on the root'); } const predicate = buildPredicate(selector); return this.getNodesInternal().some(predicate); } /** * Returns whether or not any of the nodes in the wrapper pass the provided predicate function. * * @param {Function} predicate * @returns {Boolean} */ someWhere(predicate) { return this.getNodesInternal().some((n, i) => predicate.call(this, this.wrap(n), i)); } /** * Returns whether or not all of the nodes in the wrapper match the provided selector. * * @param {EnzymeSelector} selector * @returns {Boolean} */ every(selector) { const predicate = buildPredicate(selector); return this.getNodesInternal().every(predicate); } /** * Returns whether or not any of the nodes in the wrapper pass the provided predicate function. * * @param {Function} predicate * @returns {Boolean} */ everyWhere(predicate) { return this.getNodesInternal().every((n, i) => predicate.call(this, this.wrap(n), i)); } /** * Utility method used to create new wrappers with a mapping function that returns an array of * nodes in response to a single node wrapper. The returned wrapper is a single wrapper around * all of the mapped nodes flattened (and de-duplicated). * * @param {Function} fn * @returns {ShallowWrapper} */ flatMap(fn) { const nodes = this.getNodesInternal().map((n, i) => fn.call(this, this.wrap(n), i)); const flattened = flat(nodes, 1); return this.wrap(flattened.filter(Boolean)); } /** * Finds all nodes in the current wrapper nodes' render trees that match the provided predicate * function. The predicate function will receive the nodes inside a ShallowWrapper as its * first argument. * * @param {Function} predicate * @returns {ShallowWrapper} */ findWhere(predicate) { return findWhereUnwrapped(this, (n) => { const node = this.wrap(n); return node.length > 0 && predicate(node); }); } /** * Returns the node at a given index of the current wrapper. * * @param index * @returns {ReactElement} */ get(index) { return this.getElements()[index]; } /** * Returns a wrapper around the node at a given index of the current wrapper. * * @param index * @returns {ShallowWrapper} */ at(index) { const nodes = this.getNodesInternal(); if (index < nodes.length) { return this.wrap(nodes[index]); } return this.wrap([]); } /** * Returns a wrapper around the first node of the current wrapper. * * @returns {ShallowWrapper} */ first() { return this.at(0); } /** * Returns a wrapper around the last node of the current wrapper. * * @returns {ShallowWrapper} */ last() { return this.at(this.length - 1); } /** * Delegates to exists() * * @returns {boolean} */ isEmpty() { // eslint-disable-next-line no-console console.warn('Enzyme::Deprecated method isEmpty() called, use exists() instead.'); return !this.exists(); } /** * Returns true if the current wrapper has nodes. False otherwise. * If called with a selector it returns `.find(selector).exists()` instead. * * @param {EnzymeSelector} selector (optional) * @returns {boolean} */ exists(selector = null) { return arguments.length > 0 ? this.find(selector).exists() : this.length > 0; } /** * Utility method that throws an error if the current instance has a length other than one. * This is primarily used to enforce that certain methods are only run on a wrapper when it is * wrapping a single node. * * @param fn * @returns {*} */ single(name, fn) { const fnName = typeof name === 'string' ? name : 'unknown'; const callback = typeof fn === 'function' ? fn : name; if (this.length !== 1) { throw new Error(`Method “${fnName}” is meant to be run on 1 node. ${this.length} found instead.`); } return callback.call(this, this.getNodeInternal()); } /** * Helpful utility method to create a new wrapper with the same root as the current wrapper, with * any nodes passed in as the first parameter automatically wrapped. * * @param node * @returns {ShallowWrapper} */ wrap(node, root = this[ROOT], ...args) { if (node instanceof ShallowWrapper) { return node; } return new ShallowWrapper(node, root, ...args); } /** * Returns an HTML-like string of the shallow render for debugging purposes. * * @param {Object} [options] - Property bag of additional options. * @param {boolean} [options.ignoreProps] - if true, props are omitted from the string. * @param {boolean} [options.verbose] - if true, arrays and objects to be verbosely printed. * @returns {String} */ debug(options = {}) { return debugNodes(this.getNodesInternal(), options); } /** * Invokes intercepter and returns itself. intercepter is called with itself. * This is helpful when debugging nodes in method chains. * @param fn * @returns {ShallowWrapper} */ tap(intercepter) { intercepter(this); return this; } /** * Primarily useful for HOCs (higher-order components), this method may only be * run on a single, non-DOM node, and will return the node, shallow-rendered. * * @param {Object} options * @returns {ShallowWrapper} */ dive(options = {}) { const adapter = getAdapter(this[OPTIONS]); const name = 'dive'; return this.single(name, (n) => { if (n && n.nodeType === 'host') { throw new TypeError(`ShallowWrapper::${name}() can not be called on Host Components`); } const el = getAdapter(this[OPTIONS]).nodeToElement(n); if (!isCustomComponentElement(el, adapter)) { throw new TypeError(`ShallowWrapper::${name}() can only be called on components`); } const childOptions = makeInheritedChildOptions(this, options); return this.wrap(el, null, childOptions); }); } /** * Strips out all the not host-nodes from the list of nodes * * This method is useful if you want to check for the presence of host nodes * (actually rendered HTML elements) ignoring the React nodes. */ hostNodes() { return this.filterWhere((n) => typeof n.type() === 'string'); } } /** * Updates the context of the primary wrapper when the * `wrappingComponent` re-renders. */ function updatePrimaryRootContext(wrappingComponent) { const adapter = getAdapter(wrappingComponent[OPTIONS]); const primaryWrapper = wrappingComponent[PRIMARY_WRAPPER]; const primaryRenderer = primaryWrapper[RENDERER]; const primaryNode = primaryRenderer.getNode(); const { legacyContext, providerValues, } = getContextFromWrappingComponent(wrappingComponent, adapter); const prevProviderValues = primaryWrapper[PROVIDER_VALUES]; primaryWrapper.setContext({ ...wrappingComponent[PRIMARY_WRAPPER][OPTIONS].context, ...legacyContext, }); primaryWrapper[PROVIDER_VALUES] = new Map([...prevProviderValues, ...providerValues]); if (typeof adapter.isContextConsumer === 'function' && adapter.isContextConsumer(primaryNode.type)) { const Consumer = primaryNode.type; // Adapters with an `isContextConsumer` method will definitely have a `getProviderFromConsumer` // method. const Provider = adapter.getProviderFromConsumer(Consumer); const newValue = providerValues.get(Provider); const oldValue = prevProviderValues.get(Provider); // Use referential comparison like React if (newValue !== oldValue) { primaryWrapper.rerender(); } } } /** * A *special* "root" wrapper that represents the component passed as `wrappingComponent`. * It is linked to the primary root such that updates to it will update the primary. * * @class WrappingComponentWrapper */ class WrappingComponentWrapper extends ShallowWrapper { constructor(nodes, root, RootFinder) { super(nodes); privateSet(this, PRIMARY_WRAPPER, root); privateSet(this, ROOT_FINDER, RootFinder); } /** * Like rerender() on ShallowWrapper, except it also does a "full render" of * itself and updates the primary ShallowWrapper's context. */ rerender(...args) { const result = super.rerender(...args); updatePrimaryRootContext(this); return result; } /** * Like setState() on ShallowWrapper, except it also does a "full render" of * itself and updates the primary ShallowWrapper's context. */ setState(...args) { const result = super.setState(...args); updatePrimaryRootContext(this); return result; } // eslint-disable-next-line class-methods-use-this getWrappingComponent() { throw new Error('ShallowWrapper::getWrappingComponent() can only be called on the root'); } } if (ITERATOR_SYMBOL) { Object.defineProperty(ShallowWrapper.prototype, ITERATOR_SYMBOL, { configurable: true, value: function iterator() { const iter = this.getNodesInternal()[ITERATOR_SYMBOL](); const adapter = getAdapter(this[OPTIONS]); return { [ITERATOR_SYMBOL]() { return this; }, next() { const next = iter.next(); if (next.done) { return { done: true }; } return { done: false, value: adapter.nodeToElement(next.value), }; }, }; }, }); } function privateWarning(prop, extraMessage) { Object.defineProperty(ShallowWrapper.prototype, prop, { get() { throw new Error(trim(` Attempted to access ShallowWrapper::${prop}, which was previously a private property on Enzyme ShallowWrapper instances, but is no longer and should not be relied upon. ${extraMessage} `)); }, enumerable: false, configurable: false, }); } privateWarning('node', 'Consider using the getElement() method instead.'); privateWarning('nodes', 'Consider using the getElements() method instead.'); privateWarning('renderer', ''); privateWarning('options', ''); privateWarning('complexSelector', ''); export default ShallowWrapper; ================================================ FILE: packages/enzyme/src/Utils.js ================================================ /* eslint no-use-before-define: 0 */ import isEqual from 'lodash.isequal'; import is from 'object-is'; import entries from 'object.entries'; import fromEntries from 'object.fromentries'; import functionName from 'function.prototype.name'; import hasOwn from 'hasown'; import flat from 'array.prototype.flat'; import trim from 'string.prototype.trim'; import cheerio from 'cheerio'; import { isHtml } from 'cheerio/lib/utils'; import { get } from './configuration'; import { childrenOfNode } from './RSTTraversal'; import realGetAdapter from './getAdapter'; import validateAdapter from './validateAdapter'; export const ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; export function getAdapter(options = {}) { console.warn('getAdapter from Utils is deprecated; please use ./getAdapter instead'); return realGetAdapter(options); } function validateMountOptions(attachTo, hydrateIn) { if (attachTo && hydrateIn && attachTo !== hydrateIn) { throw new TypeError('If both the `attachTo` and `hydrateIn` options are provided, they must be === (for backwards compatibility)'); } } export function makeOptions(options) { const { attachTo: configAttachTo, hydrateIn: configHydrateIn, ...config } = get(); validateMountOptions(configAttachTo, configHydrateIn); const { attachTo, hydrateIn } = options; validateMountOptions(attachTo, hydrateIn); // neither present: both undefined // only attachTo present: attachTo set, hydrateIn undefined // only hydrateIn present: both set to hydrateIn // both present (and ===, per above): both set to hydrateIn const finalAttachTo = hydrateIn || configHydrateIn || configAttachTo || attachTo || undefined; const finalHydrateIn = hydrateIn || configHydrateIn || undefined; const mountTargets = { ...(finalAttachTo && { attachTo: finalAttachTo }), ...(finalHydrateIn && { hydrateIn: finalHydrateIn }), }; return { ...config, ...options, ...mountTargets, }; } export function isCustomComponent(component, adapter) { validateAdapter(adapter); if (adapter.isCustomComponent) { return !!adapter.isCustomComponent(component); } return typeof component === 'function'; } export function isCustomComponentElement(inst, adapter) { if (adapter.isCustomComponentElement) { return !!adapter.isCustomComponentElement(inst); } return !!inst && adapter.isValidElement(inst) && typeof inst.type === 'function'; } export function propsOfNode(node) { const newEntries = entries((node && node.props) || {}) .filter(([, value]) => typeof value !== 'undefined'); return fromEntries(newEntries); } export function typeOfNode(node) { return node ? node.type : null; } export function nodeHasType(node, type) { if (!type || !node) return false; const adapter = realGetAdapter(); if (adapter.displayNameOfNode) { const displayName = adapter.displayNameOfNode(node); return displayName === type; } if (!node.type) return false; if (typeof node.type === 'string') return node.type === type; return ( typeof node.type === 'function' ? functionName(node.type) === type : node.type.name === type ) || node.type.displayName === type; } function internalChildrenCompare(a, b, lenComp, isLoose) { const nodeCompare = isLoose ? nodeMatches : nodeEqual; if (a === b) return true; if (!Array.isArray(a) && !Array.isArray(b)) { return nodeCompare(a, b, lenComp); } const flatA = flat(a, Infinity); const flatB = flat(b, Infinity); if (flatA.length !== flatB.length) return false; if (flatA.length === 0 && flatB.length === 0) return true; for (let i = 0; i < flatA.length; i += 1) { if (!nodeCompare(flatA[i], flatB[i], lenComp)) return false; } return true; } function childrenMatch(a, b, lenComp) { return internalChildrenCompare(a, b, lenComp, true); } function childrenEqual(a, b, lenComp) { return internalChildrenCompare(a, b, lenComp, false); } function removeNullaryReducer(acc, [key, value]) { const addition = value == null ? {} : { [key]: value }; return { ...acc, ...addition }; } function internalNodeCompare(a, b, lenComp, isLoose) { if (a === b) return true; if (!a || !b) return false; if (a.type !== b.type) return false; let left = propsOfNode(a); let right = propsOfNode(b); if (isLoose) { left = entries(left).reduce(removeNullaryReducer, {}); right = entries(right).reduce(removeNullaryReducer, {}); } const leftKeys = Object.keys(left); for (let i = 0; i < leftKeys.length; i += 1) { const prop = leftKeys[i]; // we will check children later if (prop === 'children') { // continue; } else if (!(prop in right)) { return false; } else if (right[prop] === left[prop]) { // continue; } else if (typeof right[prop] === typeof left[prop] && typeof left[prop] === 'object') { if (!isEqual(left[prop], right[prop])) return false; } else { return false; } } const leftHasChildren = 'children' in left; const rightHasChildren = 'children' in right; const childCompare = isLoose ? childrenMatch : childrenEqual; if (leftHasChildren || rightHasChildren) { if (!childCompare( childrenToSimplifiedArray(left.children, isLoose), childrenToSimplifiedArray(right.children, isLoose), lenComp, )) { return false; } } if (!isTextualNode(a)) { const rightKeys = Object.keys(right); return lenComp(leftKeys.length - leftHasChildren, rightKeys.length - rightHasChildren); } return false; } export function nodeMatches(a, b, lenComp = is) { return internalNodeCompare(a, b, lenComp, true); } export function nodeEqual(a, b, lenComp = is) { return internalNodeCompare(a, b, lenComp, false); } export function containsChildrenSubArray(match, node, subArray) { const children = childrenOfNode(node); const checker = (_, i) => arraysEqual(match, children.slice(i, i + subArray.length), subArray); return children.some(checker); } function arraysEqual(match, left, right) { return left.length === right.length && left.every((el, i) => match(el, right[i])); } function childrenToArray(children) { const result = []; const push = (el) => { if (el === null || el === false || typeof el === 'undefined') return; result.push(el); }; if (Array.isArray(children)) { children.forEach(push); } else { push(children); } return result; } export function childrenToSimplifiedArray(nodeChildren, isLoose = false) { const childrenArray = childrenToArray(nodeChildren); const simplifiedArray = []; for (let i = 0; i < childrenArray.length; i += 1) { const child = childrenArray[i]; const previousChild = simplifiedArray.pop(); if (typeof previousChild === 'undefined') { simplifiedArray.push(child); } else if (isTextualNode(child) && isTextualNode(previousChild)) { simplifiedArray.push(previousChild + child); } else { simplifiedArray.push(previousChild); simplifiedArray.push(child); } } if (isLoose) { return simplifiedArray.map((x) => (typeof x === 'string' ? trim(x) : x)); } return simplifiedArray; } function isTextualNode(node) { return typeof node === 'string' || typeof node === 'number'; } export function isReactElementAlike(arg, adapter) { return adapter.isValidElement(arg) || isTextualNode(arg) || Array.isArray(arg); } // TODO(lmr): can we get rid of this outside of the adapter? export function withSetStateAllowed(fn) { // NOTE(lmr): // this is currently here to circumvent a React bug where `setState()` is // not allowed without global being defined. let cleanup = false; if (typeof global.document === 'undefined') { cleanup = true; global.document = {}; } fn(); if (cleanup) { // This works around a bug in node/jest in that developers aren't able to // delete things from global when running in a node vm. global.document = undefined; delete global.document; } } // TODO, semver-major: remove this export function AND(fns) { const fnsReversed = fns.slice().reverse(); return (x) => fnsReversed.every((fn) => fn(x)); } export function displayNameOfNode(node) { if (!node) return null; const { type } = node; if (!type) return null; return type.displayName || (typeof type === 'function' ? functionName(type) : type.name || type); } export function sym(s) { return typeof Symbol === 'function' ? Symbol.for(`enzyme.${s}`) : s; } export function privateSet(obj, prop, value) { Object.defineProperty(obj, prop, { value, enumerable: false, writable: true, }); } export function cloneElement(adapter, el, props) { return adapter.createElement( el.type, { ...el.props, ...props }, ); } export function spyMethod(instance, methodName, getStub = () => {}) { let lastReturnValue; const originalMethod = instance[methodName]; const hasOwnProp = hasOwn(instance, methodName); let descriptor; if (hasOwnProp) { descriptor = Object.getOwnPropertyDescriptor(instance, methodName); } Object.defineProperty(instance, methodName, { configurable: true, enumerable: !descriptor || !!descriptor.enumerable, value: getStub(originalMethod) || function spied(...args) { const result = originalMethod.apply(this, args); lastReturnValue = result; return result; }, }); return { restore() { if (hasOwnProp) { if (descriptor) { Object.defineProperty(instance, methodName, descriptor); } else { /* eslint-disable no-param-reassign */ instance[methodName] = originalMethod; /* eslint-enable no-param-reassign */ } } else { /* eslint-disable no-param-reassign */ delete instance[methodName]; /* eslint-enable no-param-reassign */ } }, getLastReturnValue() { return lastReturnValue; }, }; } export function spyProperty(instance, propertyName, handlers = {}) { const originalValue = instance[propertyName]; const hasOwnProp = hasOwn(instance, propertyName); let descriptor; if (hasOwnProp) { descriptor = Object.getOwnPropertyDescriptor(instance, propertyName); } let wasAssigned = false; let holder = originalValue; const getV = handlers.get ? () => { const value = descriptor && descriptor.get ? descriptor.get.call(instance) : holder; return handlers.get.call(instance, value); } : () => holder; const set = handlers.set ? (newValue) => { wasAssigned = true; const handlerNewValue = handlers.set.call(instance, holder, newValue); holder = handlerNewValue; if (descriptor && descriptor.set) { descriptor.set.call(instance, holder); } } : (v) => { wasAssigned = true; holder = v; }; Object.defineProperty(instance, propertyName, { configurable: true, enumerable: !descriptor || !!descriptor.enumerable, get: getV, set, }); return { restore() { if (hasOwnProp) { if (descriptor) { Object.defineProperty(instance, propertyName, descriptor); } else { /* eslint-disable no-param-reassign */ instance[propertyName] = holder; /* eslint-enable no-param-reassign */ } } else { /* eslint-disable no-param-reassign */ delete instance[propertyName]; /* eslint-enable no-param-reassign */ } }, wasAssigned() { return wasAssigned; }, }; } export { default as shallowEqual } from 'enzyme-shallow-equal'; export function isEmptyValue(renderedValue) { return renderedValue === null || renderedValue === false; } export function renderedDive(nodes) { if (isEmptyValue(nodes)) { return true; } return [].concat(nodes).every((n) => { if (n) { const { rendered } = n; return isEmptyValue(rendered) || renderedDive(rendered); } return isEmptyValue(n); }); } export function loadCheerioRoot(html) { if (!html) { return cheerio.root(); } if (!isHtml(html)) { // use isDocument=false to create fragment return cheerio.load(html, null, false).root(); } return cheerio.load('')(html); } ================================================ FILE: packages/enzyme/src/configuration.js ================================================ import validateAdapter from './validateAdapter'; let configuration = {}; export function get() { return { ...configuration }; } export function merge(extra) { if (extra.adapter) { validateAdapter(extra.adapter); } Object.assign(configuration, extra); } export function reset(replacementConfig = {}) { configuration = {}; merge(replacementConfig); } ================================================ FILE: packages/enzyme/src/getAdapter.js ================================================ import validateAdapter from './validateAdapter'; import { get } from './configuration'; export default function getAdapter(options = {}) { if (options.adapter) { validateAdapter(options.adapter); return options.adapter; } const { adapter } = get(); validateAdapter(adapter); return adapter; } ================================================ FILE: packages/enzyme/src/index.js ================================================ export { default as ReactWrapper } from './ReactWrapper'; export { default as ShallowWrapper } from './ShallowWrapper'; export { default as EnzymeAdapter } from './EnzymeAdapter'; export { default as mount } from './mount'; export { default as shallow } from './shallow'; export { default as render } from './render'; export { merge as configure } from './configuration'; ================================================ FILE: packages/enzyme/src/mount.js ================================================ import ReactWrapper from './ReactWrapper'; /** * Mounts and renders a react component into the document and provides a testing wrapper around it. * * @param node * @returns {ReactWrapper} */ export default function mount(node, options) { return new ReactWrapper(node, null, options); } ================================================ FILE: packages/enzyme/src/render.js ================================================ import getAdapter from './getAdapter'; import { loadCheerioRoot } from './Utils'; /** * Renders a react component into static HTML and provides a cheerio wrapper around it. This is * somewhat asymmetric with `mount` and `shallow`, which don't use any external libraries, but * Cheerio's API is pretty close to what we actually want and has a significant amount of utility * that would be recreating the wheel if we didn't use it. * * I think there are a lot of good use cases to use `render` instead of `shallow` or `mount`, and * thus I'd like to keep this API in here even though it's not really "ours". * * @param node * @param options * @returns {Cheerio} */ export default function render(node, options = {}) { const adapter = getAdapter(options); const renderer = adapter.createRenderer({ mode: 'string', ...options }); const html = renderer.render(node, options.context); return loadCheerioRoot(html); } ================================================ FILE: packages/enzyme/src/selectors.js ================================================ import { createParser } from 'rst-selector-parser'; import values from 'object.values'; import flat from 'array.prototype.flat'; import is from 'object-is'; import hasOwn from 'hasown'; import elementsByConstructor from 'html-element-map/byConstructor'; import { treeFilter, nodeHasId, findParentNode, nodeMatchesObjectProps, childrenOfNode, hasClassName, } from './RSTTraversal'; import { nodeHasType, propsOfNode } from './Utils'; import getAdapter from './getAdapter'; // our CSS selector parser instance const parser = createParser(); // Combinators that allow you to chance selectors const CHILD = 'childCombinator'; const ADJACENT_SIBLING = 'adjacentSiblingCombinator'; const GENERAL_SIBLING = 'generalSiblingCombinator'; const DESCENDANT = 'descendantCombinator'; // Selectors for targeting elements const SELECTOR = 'selector'; const TYPE_SELECTOR = 'typeSelector'; const CLASS_SELECTOR = 'classSelector'; const ID_SELECTOR = 'idSelector'; const UNIVERSAL_SELECTOR = 'universalSelector'; const ATTRIBUTE_PRESENCE = 'attributePresenceSelector'; const ATTRIBUTE_VALUE = 'attributeValueSelector'; // @TODO we dont support these, throw if they are used const PSEUDO_CLASS = 'pseudoClassSelector'; const PSEUDO_ELEMENT = 'pseudoElementSelector'; const EXACT_ATTRIBUTE_OPERATOR = '='; const WHITELIST_ATTRIBUTE_OPERATOR = '~='; const HYPHENATED_ATTRIBUTE_OPERATOR = '|='; const PREFIX_ATTRIBUTE_OPERATOR = '^='; const SUFFIX_ATTRIBUTE_OPERATOR = '$='; const SUBSTRING_ATTRIBUTE_OPERATOR = '*='; function unique(arr) { return [...new Set(arr)]; } /** * Calls reduce on a array of nodes with the passed * function, returning only unique results. * @param {Function} fn * @param {Array} nodes */ function uniqueReduce(fn, nodes) { return unique(nodes.reduce(fn, [])); } /** * Takes a CSS selector and returns a set of tokens parsed * by scalpel. * @param {String} selector */ function safelyGenerateTokens(selector) { try { return parser.parse(selector); } catch (err) { throw new Error(`Failed to parse selector: ${selector}`); } } function matchAttributeSelector(node, token) { const { operator, value, name } = token; const nodeProps = propsOfNode(node); const descriptor = Object.getOwnPropertyDescriptor(nodeProps, name); if (descriptor && descriptor.get) { return false; } const nodePropValue = nodeProps[name]; if (typeof nodePropValue === 'undefined') { return false; } if (token.type === ATTRIBUTE_PRESENCE) { return hasOwn(nodeProps, token.name); } // Only the exact value operator ("=") can match non-strings if (typeof nodePropValue !== 'string' || typeof value !== 'string') { if (operator !== EXACT_ATTRIBUTE_OPERATOR) { return false; } } switch (operator) { /** * Represents an element with the att attribute whose value is exactly "val". * @example * [attr="val"] matches attr="val" */ case EXACT_ATTRIBUTE_OPERATOR: return is(nodePropValue, value); /** * Represents an element with the att attribute whose value is a whitespace-separated * list of words, one of which is exactly * @example * [rel~="copyright"] matches rel="copyright other" */ case WHITELIST_ATTRIBUTE_OPERATOR: return nodePropValue.split(' ').indexOf(value) !== -1; /** * Represents an element with the att attribute, its value either being exactly the * value or beginning with the value immediately followed by "-" * @example * [hreflang|="en"] matches hreflang="en-US" */ case HYPHENATED_ATTRIBUTE_OPERATOR: return nodePropValue === value || nodePropValue.startsWith(`${value}-`); /** * Represents an element with the att attribute whose value begins with the prefix value. * If the value is the empty string then the selector does not represent anything. * @example * [type^="image"] matches type="imageobject" */ case PREFIX_ATTRIBUTE_OPERATOR: return value === '' ? false : nodePropValue.slice(0, value.length) === value; /** * Represents an element with the att attribute whose value ends with the suffix value. * If the value is the empty string then the selector does not represent anything. * @example * [type$="image"] matches type="imageobject" */ case SUFFIX_ATTRIBUTE_OPERATOR: return value === '' ? false : nodePropValue.slice(-value.length) === value; /** * Represents an element with the att attribute whose value contains at least one * instance of the value. If value is the empty string then the * selector does not represent anything. * @example * [title*="hello"] matches title="well hello there" */ case SUBSTRING_ATTRIBUTE_OPERATOR: return value === '' ? false : nodePropValue.indexOf(value) !== -1; default: throw new Error(`Enzyme::Selector: Unknown attribute selector operator "${operator}"`); } } function matchPseudoSelector(node, token, root) { const { name, parameters } = token; if (name === 'not') { // eslint-disable-next-line no-use-before-define return parameters.every((selector) => reduceTreeBySelector(selector, node).length === 0); } if (name === 'empty') { return treeFilter(node, (n) => n !== node).length === 0; } if (name === 'first-child') { const { rendered } = findParentNode(root, node); const [firstChild] = rendered; return firstChild === node; } if (name === 'last-child') { const { rendered } = findParentNode(root, node); return rendered[rendered.length - 1] === node; } if (name === 'focus') { if (typeof document === 'undefined') { throw new Error('Enzyme::Selector does not support the ":focus" pseudo-element without a global `document`.'); } const adapter = getAdapter(); /* eslint-env browser */ return document.activeElement && adapter.nodeToHostNode(node) === document.activeElement; } throw new TypeError(`Enzyme::Selector does not support the "${token.name}" pseudo-element or pseudo-class selectors.`); } /** * Takes a node and a token and determines if the node * matches the predicate defined by the token. * @param {Node} node * @param {Token} token */ function nodeMatchesToken(node, token, root) { if (node === null || typeof node === 'string') { return false; } switch (token.type) { /** * Match every node * @example '*' matches every node */ case UNIVERSAL_SELECTOR: return true; /** * Match against the className prop * @example '.active' matches
*/ case CLASS_SELECTOR: return hasClassName(node, token.name); /** * Simple type matching * @example 'div' matches
*/ case TYPE_SELECTOR: return nodeHasType(node, token.name); /** * Match against the `id` prop * @example '#nav' matches