This repository was archived by the owner on Mar 5, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 78
add examples for setState from enzyme #384
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
42c7d3c
add examples for setState from enzyme
bahmutov 13b97f7
add more examples
bahmutov 46d0b50
add context section
bahmutov ecab2e4
finish context
bahmutov cd75599
link example to the root README
bahmutov db68a75
Update cypress/component/basic/enzyme/README.md
bahmutov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| # Enzyme examples | ||
|
|
||
| This folder shows several examples from [Enzyme docs](https://enzymejs.github.io/enzyme/). | ||
|
|
||
| In general if you are migrating from Enzyme to `cypress-react-unit-test`: | ||
|
|
||
| - there is no shallow mounting, only the full mounting. Thus `cypress-react-unit-test` has `mount` which is similar to the Enzyme's `render`. It renders the full HTML and CSS output of your component. | ||
| - you can mock [children components](https://github.com/bahmutov/cypress-react-unit-test/tree/main/cypress/component/advanced/mocking-component) if you want to avoid running "expensive" components during tests | ||
| - the test is running as a "mini" web application. Thus if you want to set a context around component, then set the [context around the component](https://github.com/bahmutov/cypress-react-unit-test/tree/main/cypress/component/advanced/context) | ||
|
|
||
| ## setState | ||
|
|
||
| If you want to change the component's internal state, use the component reference. You can get it by using the special property `ref` when mounting. | ||
|
|
||
| ```js | ||
| // get the component reference using "ref" prop | ||
| // and place it into the object for Cypress to "wait" for it | ||
| let c = {} | ||
| mount(<Foo id="foo" foo="initial" ref={i => (c.instance = i)} />) | ||
| cy.wrap(c) | ||
| .its('instance') | ||
| .invoke('setState', { count: 10 }) | ||
| ``` | ||
|
|
||
| See [state-spec.js](state-spec.js) file. | ||
|
|
||
| ## setProps | ||
|
|
||
| There is no direct implementation of `setProps`. If you want to see how the component behaves with different props: | ||
|
|
||
| ```js | ||
| it('mounts component with new props', () => { | ||
| mount(<Foo id="foo" foo="initial" />) | ||
| cy.contains('initial').should('be.visible') | ||
|
|
||
| mount(<Foo id="foo" foo="second" />) | ||
| cy.contains('second').should('be.visible') | ||
| }) | ||
| ``` | ||
|
|
||
| If you want to reuse properties, you can even clone the component | ||
|
|
||
| ```js | ||
| it('mounts cloned component', () => { | ||
| const cmp = <Foo id="foo" foo="initial" /> | ||
| mount(cmp) | ||
| cy.contains('initial').should('be.visible') | ||
|
|
||
| const cloned = Cypress._.cloneDeep(cmp) | ||
bahmutov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // change a property, leaving the rest unchanged | ||
| cloned.props.foo = 'second' | ||
| mount(cloned) | ||
| cy.contains('.foo', 'second').should('be.visible') | ||
| }) | ||
| ``` | ||
|
|
||
| See [props-spec.js](props-spec.js) file. | ||
|
|
||
| ## context | ||
|
|
||
| Enzyme's `mount` method allows passing the [React context](https://reactjs.org/docs/context.html) as the second argument to the JSX component like `SimpleComponent` below. | ||
|
|
||
| ```js | ||
| function SimpleComponent(props, context) { | ||
| const { name } = context | ||
| return <div>{name || 'not set'}</div> | ||
| } | ||
| ``` | ||
|
|
||
| Since the above syntax is [deprecated](https://reactjs.org/docs/legacy-context.html), `cypress-react-unit-test` does not support it. Instead use `createContext` and `Context.Provider` to surround the mounted component, just like you would do in a regular application code. | ||
|
|
||
| ```js | ||
| mount( | ||
| <SimpleContext.Provider value={{ name: 'test context' }}> | ||
| <SimpleComponent /> | ||
| </SimpleContext.Provider>, | ||
| ) | ||
| ``` | ||
|
|
||
| Instead of setting a new context, mount the same component but surround it with a different context provider | ||
|
|
||
| ```js | ||
| const cmp = <SimpleComponent id="0x123" /> | ||
| mount( | ||
| <SimpleContext.Provider value={{ name: 'first context' }}> | ||
| {cmp} | ||
| </SimpleContext.Provider>, | ||
| ) | ||
|
|
||
| // same component, different provider | ||
| mount( | ||
| <SimpleContext.Provider value={{ name: 'second context' }}> | ||
| {cmp} | ||
| </SimpleContext.Provider>, | ||
| ) | ||
| ``` | ||
|
|
||
| See [context-spec.js](context-spec.js) for more examples. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| /// <reference types="cypress" /> | ||
| import React from 'react' | ||
| import { mount } from 'cypress-react-unit-test' | ||
| import { SimpleContext } from './simple-context' | ||
| import { SimpleComponent } from './simple-component.jsx' | ||
|
|
||
| // testing components that use Context React API | ||
| // https://reactjs.org/docs/context.html | ||
| describe('Enzyme', () => { | ||
| context('setContext', () => { | ||
| it('does not provide the context', () => { | ||
| mount(<SimpleComponent />) | ||
| cy.contains('context not set').should('be.visible') | ||
| }) | ||
|
|
||
| it('provides the context', () => { | ||
| // surround the component with the real provider but | ||
| // set the value prop to whatever the test requires | ||
| mount( | ||
| <SimpleContext.Provider value={{ name: 'test context' }}> | ||
| <SimpleComponent /> | ||
| </SimpleContext.Provider>, | ||
| ) | ||
| cy.contains('test context').should('be.visible') | ||
| }) | ||
|
|
||
| it('mounts new context', () => { | ||
| // instead of setting the context from the test | ||
| // just mount the component again with a different provider around it | ||
| const cmp = <SimpleComponent id="0x123" /> | ||
|
|
||
| mount( | ||
| <SimpleContext.Provider value={{ name: 'first context' }}> | ||
| {cmp} | ||
| </SimpleContext.Provider>, | ||
| ) | ||
| cy.contains('first context').should('be.visible') | ||
| cy.contains('.id', '0x123').should('be.visible') | ||
|
|
||
| // same component, different provider | ||
| mount( | ||
| <SimpleContext.Provider value={{ name: 'second context' }}> | ||
| {cmp} | ||
| </SimpleContext.Provider>, | ||
| ) | ||
| cy.contains('second context').should('be.visible') | ||
| cy.contains('.id', '0x123').should('be.visible') | ||
| }) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| /// <reference types="cypress" /> | ||
| import React from 'react' | ||
| import { mount } from 'cypress-react-unit-test' | ||
|
|
||
| class Foo extends React.Component { | ||
| constructor(props) { | ||
| super(props) | ||
|
|
||
| this.state = { | ||
| count: 0, | ||
| } | ||
| } | ||
|
|
||
| componentDidMount() { | ||
| console.log('componentDidMount called') | ||
| } | ||
|
|
||
| componentDidUpdate() { | ||
| console.log('componentDidUpdate called') | ||
| } | ||
|
|
||
| render() { | ||
| const { id, foo } = this.props | ||
| return ( | ||
| <div className={id}> | ||
| {foo} count {this.state.count} | ||
| </div> | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| describe('Enzyme', () => { | ||
| // example test copied from | ||
| // https://github.com/enzymejs/enzyme/blob/master/packages/enzyme-test-suite/test/shared/methods/setProps.jsx | ||
|
|
||
| context('setProps', () => { | ||
| it('gets props from the component', () => { | ||
| mount(<Foo id="foo" foo="initial" />) | ||
| cy.contains('initial').should('be.visible') | ||
|
|
||
| cy.get('@Foo') | ||
| .its('props') | ||
| .then(props => { | ||
| console.log('current props', props) | ||
| expect(props).to.deep.equal({ | ||
| id: 'foo', | ||
| foo: 'initial', | ||
| }) | ||
| // you can get current props of the component | ||
| // but not change them - they are read-only | ||
| expect(() => { | ||
| props.foo = 'change 1' | ||
| }).to.throw() | ||
| }) | ||
| }) | ||
|
|
||
| it('mounts component with new props', () => { | ||
| mount(<Foo id="foo" foo="initial" />) | ||
| cy.contains('initial').should('be.visible') | ||
|
|
||
| mount(<Foo id="foo" foo="second" />) | ||
| cy.contains('second').should('be.visible') | ||
| }) | ||
|
|
||
| it('mounts cloned component', () => { | ||
| const cmp = <Foo id="foo" foo="initial" /> | ||
| mount(cmp) | ||
| cy.contains('initial').should('be.visible') | ||
|
|
||
| const cloned = Cypress._.cloneDeep(cmp) | ||
| // change a property, leaving the rest unchanged | ||
| cloned.props.foo = 'second' | ||
| mount(cloned) | ||
| cy.contains('.foo', 'second').should('be.visible') | ||
| }) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import React from 'react' | ||
| import { SimpleContext } from './simple-context' | ||
|
|
||
| export class SimpleComponent extends React.Component { | ||
| constructor(props) { | ||
| super(props) | ||
| this.state = { | ||
| id: props.id || 'unknown id', | ||
| } | ||
| } | ||
|
|
||
| render() { | ||
| console.log('context %o', this.context) | ||
| return ( | ||
| <> | ||
| <div>{this.context.name || 'context not set'}</div> | ||
| <div className="id">{this.state.id}</div> | ||
| </> | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| SimpleComponent.contextType = SimpleContext |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| // https://reactjs.org/docs/context.html | ||
| import { createContext } from 'react' | ||
| export const SimpleContext = createContext({ name: '' }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| /// <reference types="cypress" /> | ||
| import React from 'react' | ||
| import { mount } from 'cypress-react-unit-test' | ||
|
|
||
| class Foo extends React.Component { | ||
| constructor(props) { | ||
| super(props) | ||
|
|
||
| this.state = { | ||
| count: 0, | ||
| } | ||
| } | ||
|
|
||
| componentDidMount() { | ||
| console.log('componentDidMount called') | ||
| } | ||
|
|
||
| componentDidUpdate() { | ||
| console.log('componentDidUpdate called') | ||
| } | ||
|
|
||
| render() { | ||
| const { id, foo } = this.props | ||
| return ( | ||
| <div className={id}> | ||
| {foo} count {this.state.count} | ||
| </div> | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| describe('Enzyme', () => { | ||
| context('setState', () => { | ||
| it('sets component state', () => { | ||
| // get the component reference using "ref" prop | ||
| // and place it into the object for Cypress to "wait" for it | ||
| let c = {} | ||
| mount(<Foo id="foo" foo="initial" ref={i => (c.instance = i)} />) | ||
| cy.contains('initial').should('be.visible') | ||
|
|
||
| cy.log('**check state**') | ||
| cy.wrap(c) | ||
| .its('instance.state') | ||
| .should('deep.equal', { count: 0 }) | ||
|
|
||
| cy.log('**setState**') | ||
| cy.wrap(c) | ||
| .its('instance') | ||
| .invoke('setState', { count: 10 }) | ||
| cy.wrap(c) | ||
| .its('instance.state') | ||
| .should('deep.equal', { count: 10 }) | ||
| cy.contains('initial count 10') | ||
| }) | ||
| }) | ||
| }) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.