Skip to content
This repository was archived by the owner on Mar 5, 2022. It is now read-only.

Commit dce046b

Browse files
committed
add more examples from React tutorial
1 parent a7e7b38 commit dce046b

File tree

6 files changed

+209
-1
lines changed

6 files changed

+209
-1
lines changed

cypress.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"video": false,
55
"projectId": "z9dxah",
66
"mountMode": true,
7-
"ignoreTestFiles": "*.css",
7+
"testFiles": "**/*spec.js",
88
"env": {
99
"cypress-react-unit-test": {
1010
"react": "node_modules/react/umd/react.development.js",
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
React tutorial from https://reactjs.org/tutorial/tutorial.html
2+
3+
Just following the tutorial and writing Cypress component tests
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference types="cypress" />
2+
import React from 'react'
3+
import { mount } from "cypress-react-unit-tests";
4+
import ShoppingList from './shopping-list.jsx'
5+
6+
describe('Shopping list', () => {
7+
beforeEach(() => {
8+
cy.viewport(600, 600)
9+
})
10+
it('shows FB list', () => {
11+
mount(<ShoppingList name="Facebook" />)
12+
cy.get('li').should('have.length', 3)
13+
})
14+
})
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from "react";
2+
3+
export default class ShoppingList extends React.Component {
4+
render() {
5+
return (
6+
<div className="shopping-list">
7+
<h1>Shopping List for {this.props.name}</h1>
8+
<ul>
9+
<li>Instagram</li>
10+
<li>WhatsApp</li>
11+
<li>Oculus</li>
12+
</ul>
13+
</div>
14+
);
15+
}
16+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/// <reference types="cypress" />
2+
import React from 'react'
3+
import { mount } from "cypress-react-unit-tests";
4+
5+
// let's put React component right in the spec file
6+
class Square extends React.Component {
7+
constructor(props) {
8+
super(props);
9+
this.state = {
10+
value: null,
11+
};
12+
}
13+
14+
render() {
15+
return (
16+
<button
17+
className="square"
18+
onClick={() => this.setState({value: 'X'})}
19+
>
20+
{this.state.value}
21+
</button>
22+
);
23+
}
24+
}
25+
26+
describe('Square', () => {
27+
it('changes value on click', () => {
28+
const selector = 'button.square'
29+
mount(<Square />)
30+
// initially button is blank
31+
cy.get(selector).should('have.text', '')
32+
// but it changes text on click
33+
cy.get(selector).click().should('have.text', 'X')
34+
})
35+
})
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// entire game from the tutorial inside the spec for simplicity
2+
// the code taken from https://codepen.io/gaearon/pen/LyyXgK
3+
/// <reference types="cypress" />
4+
import React from 'react'
5+
import { mount } from "cypress-react-unit-tests";
6+
7+
// TODO add styles somehow
8+
9+
function calculateWinner(squares) {
10+
const lines = [
11+
[0, 1, 2],
12+
[3, 4, 5],
13+
[6, 7, 8],
14+
[0, 3, 6],
15+
[1, 4, 7],
16+
[2, 5, 8],
17+
[0, 4, 8],
18+
[2, 4, 6],
19+
];
20+
for (let i = 0; i < lines.length; i++) {
21+
const [a, b, c] = lines[i];
22+
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
23+
return squares[a];
24+
}
25+
}
26+
return null;
27+
}
28+
29+
function Square(props) {
30+
return (
31+
<button className="square" onClick={props.onClick}>
32+
{props.value}
33+
</button>
34+
);
35+
}
36+
37+
class Board extends React.Component {
38+
constructor(props) {
39+
super(props);
40+
this.state = {
41+
squares: Array(9).fill(null),
42+
xIsNext: true,
43+
};
44+
}
45+
46+
handleClick(i) {
47+
const squares = this.state.squares.slice();
48+
if (calculateWinner(squares) || squares[i]) {
49+
return;
50+
}
51+
squares[i] = this.state.xIsNext ? 'X' : 'O';
52+
this.setState({
53+
squares: squares,
54+
xIsNext: !this.state.xIsNext,
55+
});
56+
}
57+
58+
renderSquare(i) {
59+
return (
60+
<Square
61+
value={this.state.squares[i]}
62+
onClick={() => this.handleClick(i)}
63+
/>
64+
);
65+
}
66+
67+
render() {
68+
const winner = calculateWinner(this.state.squares);
69+
let status;
70+
if (winner) {
71+
status = 'Winner: ' + winner;
72+
} else {
73+
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
74+
}
75+
76+
return (
77+
<div>
78+
<div className="status">{status}</div>
79+
<div className="board-row">
80+
{this.renderSquare(0)}
81+
{this.renderSquare(1)}
82+
{this.renderSquare(2)}
83+
</div>
84+
<div className="board-row">
85+
{this.renderSquare(3)}
86+
{this.renderSquare(4)}
87+
{this.renderSquare(5)}
88+
</div>
89+
<div className="board-row">
90+
{this.renderSquare(6)}
91+
{this.renderSquare(7)}
92+
{this.renderSquare(8)}
93+
</div>
94+
</div>
95+
);
96+
}
97+
}
98+
99+
class Game extends React.Component {
100+
render() {
101+
return (
102+
<div className="game">
103+
<div className="game-board">
104+
<Board />
105+
</div>
106+
<div className="game-info">
107+
<div>{/* status */}</div>
108+
<ol>{/* TODO */}</ol>
109+
</div>
110+
</div>
111+
);
112+
}
113+
}
114+
115+
describe('Tic Tac Toe', () => {
116+
/**
117+
* Clicks on a square, give
118+
* @param {number} row 0 based
119+
* @param {number} column 0 based
120+
*/
121+
const clickSquare = (row, column) =>
122+
cy.get('.square').eq(row * 3 + column)
123+
124+
beforeEach(() => {
125+
cy.viewport(200, 200)
126+
})
127+
it('starts and lets X win', () => {
128+
mount(<Game />)
129+
cy.contains('.status', 'Next player: X')
130+
clickSquare(0, 0).click()
131+
cy.contains('.status', 'Next player: O')
132+
clickSquare(0, 1).click()
133+
134+
clickSquare(1, 0).click()
135+
clickSquare(1, 1).click()
136+
137+
clickSquare(2, 0).click()
138+
cy.contains('.status', 'Winner: X')
139+
})
140+
})

0 commit comments

Comments
 (0)