React テストの調査
とりあえずこれを読んで見る
以下のライブラリが必要っぽい。
enzymeとJestは別物かな。
jest
ts-jest
react-test-renderer
enzyme enzyme-adapter-react-16
enzyme-to-json
@types/jest
@types/react-test-renderer
@types/enzyme-adapter-react-16
今回使うReactは17系だから、react-16からreact-17に変更した方が良いのかなあ。
と思ったけど、enzyme-adapter-react-17にすると普通にバグる。まだenzyme側で対応して無いっぽいね。
enzymeがよく分からないから、別の記事を実践していくぅ。
今度はこれかな。
普通に動かんわ、なんでやろ。
次はこれを読んでいくぅ
普通にチュートリアルを読みます。
チュートリアルの内容を適当にまとめていくぅ。
npmで以下のようにインストール
npm install --save-dev jest
また、sum.js
ファイルを以下のように作成します。
function sum(a, b) {
return a + b;
}
module.exports = sum;
その後、sum.test.js
というファイルを作成しましょう。
const sum = require('./sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
また、package.json
に以下のようにnpm scriptsを追加します。
{
"scripts": {
"test": "jest"
}
}
npm run test
コマンドを実行すると、以下のようになりました。
> next-template@0.1.0 test
> jest
PASS ./sum.test.js
✓ adds 1 + 2 to equal 3 (1 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.167 s, estimated 1 s
このyoutube見てみよ
const functions = {
add: (num1, num2) => num1 + num2,
}
module.exports = functions
const functions = require("./functions")
test("Adds 2 + 2 to equal 4", () => {
expect(functions.add(2, 2)).toBe(4);
})
test("Adds 2 + 2 to Not equal 5", () => {
expect(functions.add(2, 2)).not.toBe(5);
})
const functions = {
add: (num1, num2) => num1 + num2,
isNull: () => null
}
module.exports = functions
test("Should be null", () => {
expect(functions.isNull()).toBeNull();
})
const functions = {
add: (num1, num2) => num1 + num2,
isNull: () => null,
checkValue: (x) => x
}
module.exports = functions
test("Should be falsy", () => {
expect(functions.checkValue(null)).toBeFalsy();
})
const functions = {
add: (num1, num2) => num1 + num2,
isNull: () => null,
checkValue: (x) => x
}
module.exports = functions
test("Should be falsy", () => {
expect(functions.checkValue(false)).toBeFalsy();
})
これは通らない
const functions = {
add: (num1, num2) => num1 + num2,
isNull: () => null,
checkValue: (x) => x
}
module.exports = functions
test("Should be falsy", () => {
expect(functions.checkValue(2)).toBeFalsy();
})
toBe
はリテラルに対して使用する。
オブジェクトが一致していることをテスト。オブジェクトの一致にはtoEqual
を使用する。
const functions = {
add: (num1, num2) => num1 + num2,
isNull: () => null,
checkValue: (x) => x,
createUser: () => {
const user = { firstName: "Brad" }
user["lastName"] = "Traversy"
return user;
},
}
module.exports = functions
test("User should be Brad Traversy object", () => {
expect(functions.createUser()).toEqual({ firstName: "Brad", lastName: "Traversy" })
})
数値が小さいことをテスト。
test("Should be under 1600", () => {
const load1 = 800
const load2 = 700
expect(load1 + load2).toBeLessThan(1600)
})
正規表現でテスト。
失敗するテスト
test('There is no I in team', () => {
expect("teamI").not.toMatch(/I/)
})
成功するテスト
test('There is no I in team', () => {
expect("teami").not.toMatch(/I/)
})
ケースインセンスティブ(大文字と小文字を区別しない)正規表現パターンにすると失敗する。
test('There is no I in team', () => {
expect("teami").not.toMatch(/I/i)
})
配列があるリテラルを含むかどうかをテスト。
test("Admin should be in usernames", () => {
usernames = ["john", "karen", "admin"]
expect(usernames).toContain("admin")
})
ここにきてaxios
を入れていくぅ。
npm install axios
非同期処理のテストをしていくぅ。
const { default: axios } = require("axios")
const functions = {
add: (num1, num2) => num1 + num2,
isNull: () => null,
checkValue: (x) => x,
createUser: () => {
const user = { firstName: "Brad" }
user["lastName"] = "Traversy"
return user
},
fetchUser: () =>
axios
.get("https://jsonplaceholder.typicode.com/users/1")
.then((res) => res.data)
.catch((err) => "error")
}
module.exports = functions
test("User fetched name should be Leanne Graham", () => {
expect.assertions(1)
return functions.fetchUser().then(data => {
expect(data.name).toEqual("Leanne Graham")
})
})
非同期処理のテストは、最初にexpect.assertions(n)
をすることで、n回のアサーションが起きることを想定する?異常系のときのみ使うっぽい。
returnでPromise
を返せば良い?
以下の記事に目を通そうかな。
assertionsをコメントアウトしても普通に通る。
const { default: axios } = require("axios")
const functions = {
add: (num1, num2) => num1 + num2,
isNull: () => null,
checkValue: (x) => x,
createUser: () => {
const user = { firstName: "Brad" }
user["lastName"] = "Traversy"
return user
},
fetchUser: () =>
axios
.get("https://jsonplaceholder.typicode.com/users/1")
.then((res) => res.data)
.catch((err) => "error")
}
module.exports = functions
test("User fetched name should be Leanne Graham", () => {
// expect.assertions(1)
return functions.fetchUser().then(data => {
expect(data.name).toEqual("Leanne Graham")
})
})
returnを消すと失敗する。
const { default: axios } = require("axios")
const functions = {
add: (num1, num2) => num1 + num2,
isNull: () => null,
checkValue: (x) => x,
createUser: () => {
const user = { firstName: "Brad" }
user["lastName"] = "Traversy"
return user
},
fetchUser: () =>
axios
.get("https://jsonplaceholder.typicode.com/users/1")
.then((res) => res.data)
.catch((err) => "error")
}
module.exports = functions
test("User fetched name should be Leanne Graham", () => {
expect.assertions(1)
functions.fetchUser().then(data => {
expect(data.name).toEqual("Leanne Graham")
})
})
async / awaitを使ってもテストが書けるぞい。
こっちの方が分かりやすいかな。
const { default: axios } = require("axios")
const functions = {
add: (num1, num2) => num1 + num2,
isNull: () => null,
checkValue: (x) => x,
createUser: () => {
const user = { firstName: "Brad" }
user["lastName"] = "Traversy"
return user
},
fetchUser: () =>
axios
.get("https://jsonplaceholder.typicode.com/users/1")
.then((res) => res.data)
.catch((err) => "error")
}
module.exports = functions
test("User fetched name should be Leanne Graham", async () => {
expect.assertions(1)
const data = await functions.fetchUser()
expect(data.name).toEqual("Leanne Graham")
})
真面目な感じのテストコード。こんな感じに書くんだね。
const reverseString = (str) => str.split("").reverse().join("")
module.exports = reverseString;
const reverseString = require("./reversestring")
test("reverseString function exists", () => {
expect(reverseString).toBeDefined()
})
test("String reverses", () => {
expect(reverseString("hello")).toEqual("olleh")
})
ちょっと改造。
const reverseString = (str) => str.toLowerCase().split("").reverse().join("")
module.exports = reverseString
const reverseString = require("./reversestring")
test("reverseString function exists", () => {
expect(reverseString).toBeDefined()
})
test("String reverses", () => {
expect(reverseString("hello")).toEqual("olleh")
})
test("String reverses with uppercase", () => {
expect(reverseString("Hello")).toEqual("olleh")
})
新しい関数を定義してテスト。
const chunkArray = (arr, len) => {
const chunkedArr = []
arr.forEach((val) => {
const last = chunkedArr[chunkedArr.length - 1]
if (!last || last.length === len) {
chunkedArr.push([val])
} else {
last.push(val)
}
})
return chunkedArr
}
module.exports = chunkArray
const chunkArray = require("./chunk")
test("chunkArray function exists", () => {
expect(chunkArray).toBeDefined()
})
test("Chunk an array of 10 values with length of 2", () => {
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const len = 2
const chunkedArr = chunkArray(numbers, len)
expect(chunkedArr).toEqual([
[1, 2],
[3, 4],
[5, 6],
[7, 8],
[9, 10],
])
})
こんなのでもOK
const chunkArray = (arr, len) => {
const chunkedArr = []
arr.forEach((val) => {
const last = chunkedArr[chunkedArr.length - 1]
if (!last || last.length === len) {
chunkedArr.push([val])
} else {
last.push(val)
}
})
return chunkedArr
}
module.exports = chunkArray
test("Chunk an array of 3 values with length of 1", () => {
const numbers = [1, 2, 3]
const len = 1
const chunkedArr = chunkArray(numbers, len)
expect(chunkedArr).toEqual([[1], [2], [3]])
})
アナグラムをテストしていくぅ。
function isAnagram(str1, str2) {
return formatStr(str1) === formatStr(str2)
}
function formatStr(str) {
return str.replace(/[^/w]/g, "").toLowerCase().split("").sort().join("")
}
module.exports = isAnagram
const isAnagram = require("./anagram")
test("isAnagram function exists", () => {
expect(typeof isAnagram).toEqual("function")
})
test('"cinema" is an anagram of "iceman"', () => {
expect(isAnagram("cinema", "iceman")).toBeTruthy()
})
test('"Dormitory" is an anagram of "dirty room##"', () => {
expect(isAnagram("Dormitory", "dirty room##")).toBeTruthy()
})
各々のテストの前と後に処理を仕込みたいときは、beforeEach
とafterEach
を使用すればOK。
データベースからデータの取得を行い、テスト終了後はデータベースとの接続を切断するときとかに便利かも。
beforeEach(() => initDatabase())
afterEach(() => closeDatabase())
const initDatabase = () => console.log('Detabase Initialized...')
const closeDatabase = () => console.log('Database Closed')
すべてのテストの前に一度だけ処理をして、すべてのテストの後に一度だけ処理をしたい場合はbeforeAll
とafterAll
を使用すればOK。
beforeAll(() => initDatabase())
afterAll(() => closeDatabase())
const initDatabase = () => console.log('Detabase Initialized...')
const closeDatabase = () => console.log('Database Closed')
beforeAll(() => initDatabase())
afterAll(() => closeDatabase())
const initDatabase = () => console.log('Detabase Initialized...')
const closeDatabase = () => console.log('Database Closed')
describe
はいくつかの関連するテストをまとめたブロックを作成する。
const nameCheck = () => console.log('Checking Name ...')
describe('Checking Names', () => {
beforeEach(() => nameCheck())
test('User is Jeff', () => {
const user = "Jeff"
expect(user).toBe('Jeff')
})
test('User is Karen', () => {
const user = "Karen"
expect(user).toBe('Karen')
})
})
package.json
に以下を追加。
"scripts": {
"test": "jest",
"testwatch": "jest --watchAll"
}
ずっとテストしてくれるようになるっぽいね。