Skip to content

Instantly share code, notes, and snippets.

@Shelob9
Last active July 31, 2018 00:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Shelob9/fb3f32fb836aaf0fa4739ccced573ec5 to your computer and use it in GitHub Desktop.
Save Shelob9/fb3f32fb836aaf0fa4739ccced573ec5 to your computer and use it in GitHub Desktop.
let posts = [
{
id: 22,
title: 'Hi Roy'
},
{
id: 23,
title: 'Also, Hi Roy'
},
];
const updatePostTitle = (postId, title ) => {
posts.find( post => postId === post.id ).title = title;
};
import React from 'react';
export class Post extends React.Component {
constructor(props){
super(props);
//Copy props to state is a bad smell!
this.state = {
post: {
title: {
rendered: ''
},
content: {
rendered: ''
}
}
}
}
componentDidMount(){
//Fetch the post, also make testing a pain.
fetch( '/wp-json/v2/posts/22' ).then( response => {
this.setState({
post: response.json()
})
});
}
render(){
//The concern of loading message now belongs to this component
if( ! this.state.post.content.rendered ){
return(
<div>Loading...</div>
)
}
//Finally the actual concern of this component
return(
<div>
<h3>
{this.state.post.title.rendered}
</h3>
<div>
{this.state.post.content.rendered}
</div>
</div>
)
}
};
import React from 'react';
import {Post} from "./Post";
import renderer from 'react-test-renderer';
describe( 'Post component', () => {
/** Mock WordPress post to test with**/
const post = {
title: {
rendered: 'Hi Roy'
},
content: {
rendered: 'Lorem ipsum, etc.'
}
};
it( 'Matches snapshot with basic props', () => {
const component = renderer.create(
<Post
post={post}
/>
);
expect( component.toJSON() ).toMatchSnapshot();
});
});
import React from 'react';
export const Post = (props) => {
return(
<div
className={props.className}
>
<h3>
{props.post.title.rendered}
</h3>
<div>
{props.post.content.rendered}
</div>
</div>
);
};
it( 'Applies className to outermost element', () => {
const component = renderer.create(
<Post
post={post}
className={'food'}
/>
);
expect( component.toJSON() ).toMatchSnapshot();
});
npm i prop-types && yarn
import React from 'react';
import PropTypes from 'prop-types';
export const Post = (props) => {
return(
<div
className={props.className}
>
<h3>
{props.post.title.rendered}
</h3>
<div>
{props.post.content.rendered}
</div>
</div>
);
};
Post.propTypes = {
className: PropTypes.string
};
Post.propTypes = {
className: PropTypes.string.isRequired
};
Post.propTypes = {
className: PropTypes.string.isRequired
};
Post.defaultProps = {
className: 'post-wrapper'
};
const updatePostTitle = (postId, title, posts ) => {
posts.find( post => postId === post.id ).title = title;
return posts;
};
<div>
<h3>
{props.title.rendered}
</h3>
<div>
{props.content.rendered}
</div>
</div>
Post.propTypes = {
className: PropTypes.string.isRequired,
post: PropTypes.shape({
title: PropTypes.shape({
rendered: PropTypes.string,
}).isRequired,
content: PropTypes.shape({
rendered: PropTypes.string,
}).isRequired,
}).isRequired
};
npm install -g generact
describe( 'updatePostTitle', () => {
let posts = [
{
id: 22,
title: 'Hi Roy'
},
{
id: 23,
title: 'Also, Hi Roy'
},
];
it( 'updates the correct post title', () => {
expect( updatePostTitle( 23, 'Hello Roy', posts )[1].title ).toEqual( 'Hello Roy' );
});
});
import React from 'react';
import PropTypes from 'prop-types';
export const Posts = (props) => {
return(
<div
className={props.className}
>
<p>Hi Roy</p>
</div>
);
};
Posts.propTypes = {
className: PropTypes.string.isRequired,
posts: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.shape({
rendered: PropTypes.string,
}).isRequired,
content: PropTypes.shape({
rendered: PropTypes.string,
}).isRequired,
}).isRequired
)
};
Posts.defaultProps = {
className: 'post-list-wrapper'
};
import React from 'react';
import {Posts} from "./Posts";
import renderer from 'react-test-renderer';
describe('Posts component', () => {
/** Mock WordPress post to test with**/
const posts = [
{
title: {
rendered: 'Hi Roy'
},
content: {
rendered: 'Lorem ipsum, etc.'
}
},
{
title: {
rendered: 'Hi Mike'
},
content: {
rendered: 'Lorem ipsum, etc.'
}
},
];
it('Matches snapshot with basic props', () => {
const component = renderer.create(
<Posts
posts={posts}
/>
);
expect(component.toJSON()).toMatchSnapshot();
});
it('Applies className to outermost element', () => {
const component = renderer.create(
<Posts
posts={posts}
className={'food'}
/>
);
expect(component.toJSON()).toMatchSnapshot();
});
});
{props.posts.map( post => {
return <Post
key={post.ID}
post={post}
/>
})};
import React from 'react';
import PropTypes from 'prop-types';
import {Post} from "../Post/Post";
export const Posts = (props) => {
return(
<div
className={props.className}
>
{props.posts.map( post => {
return <Post
key={post.ID}
post={post}
/>
})};
</div>
);
};
Posts.propTypes = {
className: PropTypes.string.isRequired,
posts: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.shape({
rendered: PropTypes.string,
}).isRequired,
content: PropTypes.shape({
rendered: PropTypes.string,
}).isRequired,
}).isRequired
)
};
Posts.defaultProps = {
className: 'post-list-wrapper'
};
import PropTypes from 'prop-types';
export const postShape =
PropTypes.shape({
ID: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]),
title: PropTypes.shape({
rendered: PropTypes.string,
}).isRequired,
content: PropTypes.shape({
rendered: PropTypes.string,
}).isRequired,
}).isRequired;
import {postShape} from "./postShape";
Post.propTypes = {
className: PropTypes.string.isRequired,
post: postShape
};
import {postShape} from "../Post/postShape";
Posts.propTypes = {
className: PropTypes.string.isRequired,
posts: PropTypes.arrayOf(
postShape
)
};
PostEdit.propTypes = {
className: PropTypes.string.isRequired,
post: postShape,
onChange: PropTypes.func.isRequired
};
import React from 'react';
import {PostEdit} from "./PostEdit";
import renderer from 'react-test-renderer';
describe( 'PostEdit component', () => {
/** Mock WordPress post to test with**/
const post = {
title: {
rendered: 'Hi Roy'
},
content: {
rendered: 'Lorem ipsum, etc.'
}
};
const mockHandler = () => {};
it( 'Matches snapshot with basic props', () => {
const component = renderer.create(
<PostEdit
onChange={mockHandler}
post={post}
/>
);
expect( component.toJSON() ).toMatchSnapshot();
});
it( 'Applies className to outermost element', () => {
const component = renderer.create(
<PostEdit
onChange={mockHandler}
post={post}
className={'food'}
/>
);
expect( component.toJSON() ).toMatchSnapshot();
});
});
yarn add enzyme enzyme-adapter-react-16
npx create-react-app wp-client # create app
cd wp-client # switch to app
yarn start # start dev server
import {shallow,mount} from 'enzyme';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter: new Adapter()});
import React from 'react';
import {PostEdit} from "./PostEdit";
import {shallow} from 'enzyme';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter: new Adapter()});
describe( 'PostEdit component', () => {
/** Mock WordPress post to test with**/
const post = {
title: {
rendered: 'Hi Roy'
},
content: {
rendered: 'Lorem ipsum, etc.'
}
};
describe( 'Change events', () => {
it( 'Updates the post title', () => {
let updatedPost = {};
const component = shallow(
<PostEdit
onChange={(newValue) => {
updatedPost = newValue;
}}
post={post}
className={'food'}
/>
);
component.find( 'input' ).simulate( 'change', {
target: { value: 'New Title'}
});
expect( updatedPost.title.rendered ).toEqual( 'New Title' );
});
});
});
component.find( 'input' ).simulate( 'change', {
target: { value: 'New Title'}
});
const onChange = (update) => {
props.onChange({
...props.post,
...update
})
};
yarn test
<h3>
<input
type={'text'}
value={props.post.title.rendered}
onChange={(event) => {
onChange({
title: {
rendered: event.target.value
}
})
}}
/>
</h3>
import React from 'react';
import PropTypes from 'prop-types';
import {postShape} from "../Post/postShape";
export const PostEdit = (props) => {
const onChange = (update) => {
props.onChange({
...props.post,
...update
})
};
return (
<div
className={props.className}
>
<h3>
<input
type={'text'}
value={props.post.title.rendered}
onChange={(event) => {
onChange({
title: {
rendered: event.target.value
}
})
}}
/>
</h3>
<div>
{props.post.content.rendered}
</div>
</div>
);
};
PostEdit.propTypes = {
className: PropTypes.string.isRequired,
post: postShape,
onChange: PropTypes.func.isRequired
};
PostEdit.defaultProps = {
className: 'post-wrapper'
};
describe( 'Posts in loop', () => {
it('Renders the right number of children', () => {
const component = mount(
<Posts
posts={posts}
className={'post-list-wrapper'}
/>
);
expect(component.find('.post-list-wrapper').length).toEqual(2);
});
});
npm install jest -g
npm install jest-cli -g
constructor(props) {
super(props);
this.state = {
posts: []
};
}
<div>
{this.state.posts.length &&
<Posts
posts={this.state.posts}
/>
}
</div>
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import {Posts} from './components/Posts/Posts';
class App extends Component {
constructor(props) {
super(props);
this.state = {
posts: []
};
}
render() {
return (
<div className="App">
<header className="App-header">
<img
src={logo}
className="App-logo"
alt="logo"
/>
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<div>
{this.state.posts.length &&
<Posts
posts={this.state.posts}
/>
}
</div>
</div>
);
}
}
export default App;
describe( 'Rendering posts in app', () => {
it( 'Shows the posts', () => {
const component = mount(
<App/>
);
component.setState({posts: posts});
expect(component.find('.post-list-wrapper').length).toEqual(2);
});
});
class App extends Component {
constructor(props) {
super(props);
this.state = {
posts: [],
postToEdit: 0,
};
this.getEditPost = this.getEditPost.bind(this);
}
getEditPost() {
return this.state.posts.find(post => this.state.postToEdit === post.ID);
}
}
this.getEditPost = this.getEditPost.bind(this);
it('Finds the post to edit ', () => {
const component = mount(
<App/>
);
component.setState({posts: posts});
component.setState({postToEdit: '2'});
expect(component.instance().getEditPost().ID).toEqual('2');
});
it('Shows the editor', () => {
const component = mount(
<App/>
);
component.setState({posts: posts});
component.setState({postToEdit: '2'});
expect(component.find('.main-editor').length).toBe(2);
});
it('Does not show the editor', () => {
const component = mount(
<App/>
);
component.setState({posts: posts});
expect(component.find('.main-editor').length).toBe(0);
});
describe( 'Basic math', () => {
it( 'Adds numbers', () => {
expect( 1 + 1 ).toEqual(2);
});
});
updatePostToEdit(postToEdit){
this.setState(postToEdit)
}
it('updates the edit post', () => {
const component = mount(
<App/>
);
component.instance().updatePostToEdit(5);
expect(component.state('postToEdit')).toBe(5);
});
componentDidMount(){
//Fetch the post, also make testing a pain.
fetch( '/wp-json/v2/posts/22' ).then( response => {
this.setState({
post: response.json()
})
});
}
yarn add --dev react-test-renderer
import React from 'react';
export const Post = (props) => {
return(
<div>
<h3>
{props.post.title.rendered}
</h3>
<div>
{props.post.content.rendered}
</div>
</div>
)
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment