Skip to content

Commit ff52ef6

Browse files
authored
Add react-redux tests (#3)
1 parent f8d5f50 commit ff52ef6

File tree

5 files changed

+147
-3
lines changed

5 files changed

+147
-3
lines changed

CONTRIBUTING.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ If you'd like to add a library to this project, follow these steps:
3939

4040
**Using JSX**
4141

42-
If using JSX to build your app, you need to import the `createElement` function directly. When using React, it is common for developers to rely on React's default export: `import React from "react";`. In order for our website to work however, that import statment needs to look like `import React, { createElement } from "react";`. We require this syntax in this website because it allows the components in the `shared` folder to be written once and used in bundles that don't include the `React.createElement` function.
42+
If using JSX to build your app, you need to import the `createElement` function directly. When using React, it is common for developers to rely on React's default export: `import React from "react";`. In order for our website to work however, that import statement needs to look like `import React, { createElement } from "react";`. We require this syntax in this website because it allows the components in the `shared` folder to be written once and used in bundles that don't include the `React.createElement` function.
4343

4444
**Styling**
4545

@@ -100,6 +100,10 @@ If you need to debug the code in your test, i.e. you want to set a breakpoint in
100100

101101
If you want to debug what your app is doing in the browser while the tests are running, Add `jestPuppeteer.debug()` anywhere in your tests where you want the browser to break. Then run the `npm run test:debug <library>` command (replacing `<library>` with the library you are testing). This command will cause Chromium to not run headless and will suspend the browser wherever you put the `jestPuppeteer.debug()` call.
102102

103+
> Note: it appears `jestPuppeteer.debug()` works best when you put it as the first line in your test, as well as wherever you want the test to pause. In order to resume test execution, first resume execution in the Chromium (F8 on windows), then press `Enter` in whatever terminal jest is running in.
104+
>
105+
> If all else fails, a good 'ol `console.log()` can sometimes do the trick
106+
103107
## File issues for bugs in sample apps
104108

105109
If you see a bug in how a sample app is built, open an issue describing what the problem is and what you would expect instead. Use our "Bug report" issue template.

src/full-compat/react-redux/components/AddTodo.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@ class AddTodo extends React.Component {
2222
return (
2323
<div>
2424
<input
25+
id="add-todo-input"
2526
onChange={e => this.updateInput(e.target.value)}
2627
value={this.state.input}
2728
/>
28-
<button className={styles["add-todo"]} onClick={this.handleAddTodo}>
29+
<button
30+
id="add-todo-btn"
31+
className={styles["add-todo"]}
32+
onClick={this.handleAddTodo}
33+
>
2934
Add Todo
3035
</button>
3136
</div>

src/full-compat/react-redux/components/TodoList.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { getTodosByVisibilityFilter } from "../redux/selectors";
77
import styles from "../styles.css";
88

99
const TodoList = ({ todos }) => (
10-
<ul className={styles["todo-list"]}>
10+
<ul id="todo-list" className={styles["todo-list"]}>
1111
{todos && todos.length
1212
? todos.map((todo, index) => {
1313
return <Todo key={`todo-${todo.id}`} todo={todo} />;

src/full-compat/react-redux/components/VisibilityFilters.js

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const VisibilityFilters = ({ activeFilter, setFilter }) => {
1212
const currentFilter = VISIBILITY_FILTERS[filterKey];
1313
return (
1414
<span
15+
id={`filter-${currentFilter}`}
1516
key={`visibility-filter-${currentFilter}`}
1617
className={cx(
1718
styles["filter"],

tests/full-compat/react-redux.test.js

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import { goToLibraryPage } from "../util";
2+
3+
describe("react-redux", () => {
4+
const emptyListText = "No todos, yay!";
5+
const completeSign = "👌";
6+
const incompleteSign = "👋";
7+
8+
const inputSel = "#add-todo-input";
9+
const addTodoBtnSel = "#add-todo-btn";
10+
const todoListSel = "#todo-list";
11+
const todoSel = "#todo-list li[class*=todo-item]";
12+
const allFilterSel = "#filter-all";
13+
const completedFilterSel = "#filter-completed";
14+
const incompleteFilterSel = "#filter-incomplete";
15+
16+
const mockTodos = ["Todo 1", "Todo 2", "Todo 3"];
17+
18+
function getTodos() {
19+
return page.$$eval(todoSel, elements => elements.map(e => e.textContent));
20+
}
21+
22+
async function addTodo(todoText) {
23+
await page.type(inputSel, todoText);
24+
await page.click(addTodoBtnSel);
25+
}
26+
27+
function markTodoCompleted(index) {
28+
return page.click(todoSel + `:nth-child(${index + 1})`);
29+
}
30+
31+
function todoItemText(todoText, completed = false) {
32+
return `${completed ? completeSign : incompleteSign} ${todoText}`;
33+
}
34+
35+
async function verifyListIsEmpty() {
36+
const todoContents = await page.$eval(todoListSel, e => e.textContent);
37+
expect(todoContents).toBe(emptyListText);
38+
}
39+
40+
/**
41+
* @param {string[]} all
42+
* @param {string[]} complete
43+
* @param {string[]} incomplete
44+
*/
45+
async function verifyFilters(all, complete, incomplete) {
46+
await page.click(allFilterSel);
47+
if (all.length) {
48+
expect(await getTodos()).toEqual(all);
49+
} else {
50+
await verifyListIsEmpty();
51+
}
52+
53+
await page.click(completedFilterSel);
54+
if (complete.length) {
55+
expect(await getTodos()).toEqual(complete);
56+
} else {
57+
await verifyListIsEmpty();
58+
}
59+
60+
await page.click(incompleteFilterSel);
61+
if (incomplete.length) {
62+
expect(await getTodos()).toEqual(incomplete);
63+
} else {
64+
await verifyListIsEmpty();
65+
}
66+
67+
// Reset list to "all"
68+
await page.click(allFilterSel);
69+
}
70+
71+
beforeEach(async () => {
72+
await goToLibraryPage("react-redux");
73+
});
74+
75+
it("should render", async () => {
76+
const contents = await page.content();
77+
expect(contents).toMatch(/Todo List/);
78+
});
79+
80+
it("should add todos to the list", async () => {
81+
const todoContents = await page.$eval(todoListSel, e => e.textContent);
82+
expect(todoContents).toBe(emptyListText);
83+
84+
await addTodo(mockTodos[0]);
85+
expect(await getTodos()).toEqual([todoItemText(mockTodos[0])]);
86+
87+
await addTodo(mockTodos[1]);
88+
expect(await getTodos()).toEqual([
89+
todoItemText(mockTodos[0]),
90+
todoItemText(mockTodos[1])
91+
]);
92+
93+
await addTodo(mockTodos[2]);
94+
expect(await getTodos()).toEqual(mockTodos.map(todo => todoItemText(todo)));
95+
});
96+
97+
it("should mark todos as completed", async () => {
98+
await addTodo(mockTodos[0]);
99+
expect(await getTodos()).toEqual([todoItemText(mockTodos[0])]);
100+
101+
await markTodoCompleted(0);
102+
expect(await getTodos()).toEqual([todoItemText(mockTodos[0], true)]);
103+
});
104+
105+
it("should properly filter todos", async () => {
106+
await addTodo(mockTodos[0]);
107+
await verifyFilters(
108+
[todoItemText(mockTodos[0])],
109+
[],
110+
[todoItemText(mockTodos[0])]
111+
);
112+
113+
await markTodoCompleted(0);
114+
await verifyFilters(
115+
[todoItemText(mockTodos[0], true)],
116+
[todoItemText(mockTodos[0], true)],
117+
[]
118+
);
119+
120+
await addTodo(mockTodos[1]);
121+
await verifyFilters(
122+
[todoItemText(mockTodos[0], true), todoItemText(mockTodos[1])],
123+
[todoItemText(mockTodos[0], true)],
124+
[todoItemText(mockTodos[1])]
125+
);
126+
127+
await markTodoCompleted(1);
128+
await verifyFilters(
129+
[todoItemText(mockTodos[0], true), todoItemText(mockTodos[1], true)],
130+
[todoItemText(mockTodos[0], true), todoItemText(mockTodos[1], true)],
131+
[]
132+
);
133+
});
134+
});

0 commit comments

Comments
 (0)