Skip to content

Commit 61418c3

Browse files
committed
feat(recipes): add recipe for "testing derived state"
1 parent e6802c0 commit 61418c3

12 files changed

Lines changed: 241 additions & 3 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Here are some recipes that will show you how **simplux** can make life simple fo
2020
- [getting started](recipes/basics/getting-started#readme)
2121
- [testing state changes](recipes/basics/testing-state-changes#readme)
2222
- [computing derived state](recipes/basics/computing-derived-state#readme)
23-
- [testing derived state](recipes/basics/testing-derived-state#readme) (work-in-progress)
23+
- [testing derived state](recipes/basics/testing-derived-state#readme)
2424
- [simplifying state changes](recipes/basics/simplifying-state-changes#readme) (work-in-progress)
2525

2626
### Advanced

recipes/basics/testing-derived-state/README.md

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,89 @@
22

33
This recipe shows how simple it is to test your derived state with **simplux**.
44

5-
If you are new to **simplux** there is [a recipe](../getting-started#readme) that will help you get started before you follow this recipe.
5+
If you are new to computing derived state with **simplux** there is [a recipe](../computing-derived-state#readme) that will help you get started before you follow this recipe.
66

77
> You can play with the code for this recipe in this [code sandbox](https://codesandbox.io/s/github/MrWolfZ/simplux/tree/master/recipes/basics/testing-derived-state).
88
9-
This recipe is still a work-in-progress.
9+
Before we start let's install all the packages we need.
10+
11+
```sh
12+
npm i @simplux/core @simplux/selectors redux -S
13+
```
14+
15+
We also need to activate the selectors extension by importing the package. You can either add this import to every test file or do it once globally with the mechanism your test framework provides. This recipe uses [Jest](https://jestjs.io/) which allows us to specify a global setup file.
16+
17+
```ts
18+
// in jest.setup.ts
19+
import '@simplux/selectors'
20+
```
21+
22+
```js
23+
// in jest.config.js
24+
module.exports = {
25+
setupFiles: ['<rootDir>/jest.setup.ts'],
26+
// + any other config you need
27+
}
28+
```
29+
30+
Now we're ready to go.
31+
32+
Computing derived state for **simplux** modules is done with _selectors_. Selectors are very simple to test as you will see. For this recipe we use a simple counter module with two selectors.
33+
34+
```ts
35+
import { createSimpluxModule } from '@simplux/core'
36+
37+
const { setState, createSelectors } = createSimpluxModule({
38+
name: 'counter',
39+
initialState: {
40+
counter: 0,
41+
},
42+
})
43+
44+
const { plusOne, plus } = createSelectors({
45+
plusOne: ({ counter }) => counter + 1,
46+
plus: ({ counter }, amount: number) => counter + amount,
47+
})
48+
```
49+
50+
Let's start by testing our `plusOne` selector. The recommended approach is to test the selector in isolation by calling it directly.
51+
52+
```ts
53+
describe('plusOne', () => {
54+
it('returns the counter plus one', () => {
55+
const result = plusOne({ counter: 10 })
56+
expect(result).toBe(11)
57+
})
58+
})
59+
```
60+
61+
However, in certain scenarios it may be useful to test the selector with the module's latest state. To achieve this we can use `withLatestModuleState` after setting the module's state to the required value.
62+
63+
```ts
64+
describe('plusOne', () => {
65+
it('returns the counter plus one', () => {
66+
setState({ counter: 20 })
67+
const result = plusOne.withLatestModuleState()
68+
expect(result).toBe(21)
69+
})
70+
})
71+
```
72+
73+
Both of these approaches also work with selectors that take arguments.
74+
75+
```ts
76+
describe('plus', () => {
77+
it('returns the sum of the counter and the amount', () => {
78+
const result1 = plus({ counter: 10 }, 5)
79+
expect(result1).toBe(15)
80+
81+
setState({ counter: 20 })
82+
const result2 = plus.withLatestModuleState(5)
83+
expect(result2).toBe(25)
84+
})
85+
})
86+
```
87+
88+
And that is all you need for testing your derived state with **simplux**.
89+
90+
By now you are certainly curious how **simplux** can help you in more complex scenarios. Our [other recipes](../../../../..#recipes) are an excellent starting point for this.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!DOCTYPE html>
2+
<html lang="">
3+
<head>
4+
<meta charset="UTF-8" />
5+
</head>
6+
<body></body>
7+
</html>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
roots: ['<rootDir>/src', '<rootDir>'],
3+
moduleFileExtensions: ['js', 'ts'],
4+
transform: {
5+
'^.+\\.ts': 'ts-jest',
6+
},
7+
testMatch: ['<rootDir>/src/**/*.spec.ts'],
8+
testPathIgnorePatterns: ['node_modules'],
9+
setupFiles: ['<rootDir>/jest.setup.ts'],
10+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import '@simplux/selectors'
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"name": "@simplux/recipes.basics.testing-derived-state",
3+
"version": "0.3.0-alpha.3",
4+
"description": "This recipe shows how simple it is to test your derived state with simplux",
5+
"main": "src/index.ts",
6+
"scripts": {
7+
"start": "webpack-dev-server --mode development --progress --color",
8+
"test": "jest --forceExit --verbose --detectOpenHandles --no-cache --colors --runInBand --config=./jest.config.js"
9+
},
10+
"repository": {
11+
"type": "git",
12+
"url": "git+https://github.com/MrWolfZ/simplux.git"
13+
},
14+
"bugs": {
15+
"url": "https://github.com/MrWolfZ/simplux/issues"
16+
},
17+
"homepage": "https://github.com/MrWolfZ/simplux/tree/master/recipes/testing-derived-state#readme",
18+
"keywords": [
19+
"recipe",
20+
"redux",
21+
"simplux",
22+
"typescript"
23+
],
24+
"author": "Jonathan Ziller <jonathan.ziller@gmail.com> (https://www.github.com/MrWolfZ)",
25+
"license": "MIT",
26+
"private": true,
27+
"dependencies": {
28+
"@simplux/core": "0.3.0-alpha.3",
29+
"@simplux/selectors": "0.3.0-alpha.3",
30+
"redux": "^4.0.1"
31+
},
32+
"devDependencies": {
33+
"@types/jest": "^24.0.13",
34+
"html-webpack-plugin": "^3.2.0",
35+
"jest": "^24.8.0",
36+
"ts-jest": "^24.0.2",
37+
"ts-loader": "^6.0.2",
38+
"typescript": "^3.5.1",
39+
"webpack": "^4.32.2",
40+
"webpack-cli": "^3.3.2",
41+
"webpack-dev-server": "^3.5.1"
42+
}
43+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"infiniteLoopProtection": true,
3+
"hardReloadOnChange": false,
4+
"view": "tests"
5+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// this code is part of the simplux recipe "testing state changes":
2+
// https://github.com/MrWolfZ/simplux/tree/master/recipes/basics/testing-state-changes
3+
4+
import { plus, plusOne, setCounterState } from './counter.module'
5+
6+
describe('counter module', () => {
7+
describe('selectors', () => {
8+
describe('plusOne', () => {
9+
it('returns the counter plus one', () => {
10+
// to test your selector just call it directly
11+
const result1 = plusOne({ counter: 10 })
12+
expect(result1).toBe(11)
13+
14+
// if you prefer, you can also test the selector by setting
15+
// the module state and executing the selector bound to the
16+
// module's state
17+
setCounterState({ counter: 20 })
18+
const result2 = plusOne.withLatestModuleState()
19+
expect(result2).toBe(21)
20+
})
21+
})
22+
23+
describe('plus', () => {
24+
it('returns the sum of the counter and the amount', () => {
25+
// of course you can also provide arguments to your selectors;
26+
// either by calling it directly with state and arguments
27+
const result1 = plus({ counter: 10 }, 5)
28+
expect(result1).toBe(15)
29+
30+
// or by setting the module state and calling the selector bound
31+
// to the module's state
32+
setCounterState({ counter: 20 })
33+
const result2 = plus.withLatestModuleState(5)
34+
expect(result2).toBe(25)
35+
})
36+
})
37+
})
38+
})
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// this code is part of the simplux recipe "testing derived state":
2+
// https://github.com/MrWolfZ/simplux/tree/master/recipes/basics/testing-derived-state
3+
4+
import { createSimpluxModule } from '@simplux/core'
5+
6+
const { getState, setState, createSelectors } = createSimpluxModule({
7+
name: 'counter',
8+
initialState: {
9+
counter: 0,
10+
},
11+
})
12+
13+
export const getCounterState = getState
14+
export const setCounterState = setState
15+
16+
export const { plusOne, plus } = createSelectors({
17+
plusOne: ({ counter }) => counter + 1,
18+
plus: ({ counter }, amount: number) => counter + amount,
19+
})
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// this code is part of the simplux recipe "testing derived state":
2+
// https://github.com/MrWolfZ/simplux/tree/master/recipes/basics/testing-derived-state
3+
import '@simplux/selectors'
4+
import { getCounterState } from './counter.module'
5+
6+
console.log(`counter module state:`, getCounterState())

0 commit comments

Comments
 (0)