Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
node:test will replace Jest?
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
jiko21
May 09, 2023
120
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
node:test will replace Jest?
関西Node学園 10時限目の登壇資料です。
jiko21
May 09, 2023
More Decks by jiko21
See All by jiko21
型情報を手繰り寄せる技術~TypeScript Compiler APIによる型解析実践~
jiko21
0
1.1k
Creating a Next.js-style Framework with Bun and Hono
jiko21
0
180
Array Grouping will soon be arriving at TypeScript
jiko21
0
170
Copying Array Methods arrived at TypeScript
jiko21
1
870
SSRで動的に OGP画像を生成したい! 〜Cloudflare Workersから@vercel/og移行編〜
jiko21
0
170
どこでも動かすために… TypeScriptでライブラリ開発の すゝめ
jiko21
2
440
NestJS a progressive web framework
jiko21
3
2.3k
レガシーなフロントエンドをリプレイスする
jiko21
5
1.6k
Deep Dive Into Vue Composition API
jiko21
0
3.3k
Featured
See All Featured
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.2k
A designer walks into a library…
pauljervisheath
211
24k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
Between Models and Reality
mayunak
4
330
Unsuck your backbone
ammeep
672
58k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
300
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
360
Building Flexible Design Systems
yeseniaperezcruz
330
40k
Designing for humans not robots
tammielis
254
26k
Facilitating Awesome Meetings
lara
57
6.9k
Transcript
node:test will replace Jest? ؔNodeֶԂ 10࣌ݶ @jiko21
About jiko21… Name: Daiki Kojima (jiko21) Multistack Engineer Love: Guitar,
TypeScript @jiko21 @jiko_21
node:test
nodeʹtest runnerੜ͑ͯ·͢ʂ • ग़ͨͷv18.0.0͔Β(ҰԠv16.17.0)ͰՃ͞Εͨ • ެࣜͰTest runnerͱ͍͏໊લ • ·ͩ·ͩStability: 1(Experimental)
• ͚ͩͬͨͲv20Ͱstableʹ • ొஃωλͷૉৼΓͯ͠ΔλΠϛϯάͰv20ग़ͯ͠·ͬͨ
jestͱൺֱͯ͠ΈΔϙΠϯτ • جຊతͳॻ͖ํɾ࣮ߦํ๏ͳͲ • describe, test, it… • beforeEach, afterEach…
• mock • context • coverage·ΘΓ • ύϑΥʔϚϯε
جຊతͳॻ͖ํ
γϯϓϧͳςετίʔυ import {test} from 'node:test'; import assert from 'node:assert/strict'; test('͜Ε௨Δ',
() => { assert.equal(2 + 2, 4); }); test('͜ΕམͪΔ', () => { assert.equal(2 + 2, 5); }); test('͜ΕམͪΔ', () => { throw new Error('sample error'); }); OPEFUFTUʹUFTUؔͷͷ͕ೖ͍ͬͯΔ BTTFSUܥͷϞδϡʔϧඪ४Ͱ͋Γ ίϨࣗମOPEFWࠒ͔Βଘࡏ͍ͯ͠Δ ͪΌΜͱྫ֎ʹରͯ͠GBJMͯ͘͠ΕΔ
describeͱ͔ͰjestΈ͍ͨʹωετͯ͠ΈΔͱ… import {test, describe} from 'node:test'; import assert from 'node:assert/strict';
describe('sample test', {concurrency: false}, (t) => { test('passing test1', {concurrency: false}, (t) => { console.log('1') assert.equal(1, 2); console.log('OK') }); test('passing test2', {concurrency: false}, (t) => { console.log('2') assert.equal(1, 1); console.log('OK') }); });
࣮ߦͷํ • ҎԼίϚϯυͰ࣮ߦՄೳ • ϑΝΠϧ໊Λࢦఆͯ͠ͷ࣮ߦՄೳ
ϑΝΠϧ໊Λࢦఆ͠ͳ͔ͬͨ߹ • ҎԼͷϧʔϧʹै࣮ͬͯߦ͞ΕΔ 1. cliͰϑΝΠϧ໊Λࢦఆ͞Ε͍ͯͨΒͦΕΛ࣮ߦ 2. ↑ࢦఆ͞Εͯͳ͔ͬͨΒҎԼͷॱংͰ࠶ؼతʹϑΝΠϧΛ୳࣮ͯ͠ߦ 1. node_modulesϢʔβʔ͕ࢦఆͯ͠ͳ͍ݶΓ࣮ߦ͠ͳ͍ 2.
/testσΟϨΫτϦ͕͋Ε࠶ؼతʹ.js, .cjs, .mjsϑΝΠϧΛݟ͚࣮ͭͯߦ 3. ͦΕҎ֎ͷσΟϨΫτϦͰҎԼͷϧʔϧʹैͬͨίʔυ͕ςετίʔτͯ͠ѻΘΕΔ 1. ϑΝΠϧ໊͕testͰશҰக 2. test-hogehoge.jsɺͷΑ͏ʹpre fi x͕test-ͷͷΛ࣮ߦ 3. ϑΝΠϧ໊͕.test,-test,_testͰऴΘΔͷ 4. CLI্Ͱ໌ࣔతʹࣔ͞Ε͍ͯΕɺ.node.jsonࣗಈͰ࣮ߦ
࣮ߦ݁Ռ
࣮ߦ݁Ռ ޭɾࣦഊͱ࣮ߦ͕࣌ؒΘ͔Δ BTTFSU͕͍͍ײ͡ʹΤϥʔग़ͯ͘͠ΕΔ ͷͰΘ͔Γ͍͢
࣮ߦ݁Ռ ςεταϚϦʔͱ͔ग़ͯ͘͠ΕΔ
beforeXXXɺafterXXXΈ͍ͨͳ͜ͱ͍ͨ͠ʂ import {describe, test, before, beforeEach, after, afterEach} from 'node:test';
import assert from 'node:assert/strict'; describe('test', async () => { before(() => { console.log('before'); }) beforeEach(() => { console.log('beforeEach'); }); afterEach(() => { console.log('afterEach'); }) after(() => { console.log('after'); }); test('͜Ε௨Δ', () => { console.log('test1'); assert.equal(2 + 2, 4); }); ɹtest('͜ΕམͪΔ', () => { console.log('test2'); assert.equal(2 + 2, 5); }); });
एׯҧ͏͚Ͳ΄΅ಉ͡ • beforeEachɺafterEachjestͱมΘΒͣ • beforeAllͱafterAll͚ͩAll͕ফ͑ͯbeforeɺafterʹ • v18·ͰdescribeͷԼʹit͕ͳ͍ͱಈ͔ͳ͍(testͩͱಈ͔ͳ͔ͬͨ) • v20Ͱ࣏༷ͬͨ
mock͍ͨ͠ʂ • ϩϯυϯֶ(ͳΔ͚ͩ୯ମͰςετ͢ΔͨΊʹϞοΫ͢Δ)͍͍ͷ ͔ʁٞ͋Δͱࢥ͏͕ɺՄೳɻ • ҎԼํ๏ͰmockՄೳ • import͍ͯ͠ΔobjectࣗମΛmock͢Δύλʔϯ • spy
functionΛͬͯmock͢Δํ๏
import͍ͯ͠ΔobjectࣗମΛmock͢Δύλʔϯ // mocked.mjs const fn = (a, b) => {
return a + b; }; export default { fn, } // mocked.mjs import mocked from './mocked.mjs'; export const someFunc1 = () => { return mocked.fn(1, 2); }; // test.mjs import {describe, test, mock} from 'node:test'; import assert from 'node:assert/strict'; import { someFunc1 } from './mock.mjs'; import { mockFn } from './mockfn.mjs'; import mocked from './mocked.mjs'; describe('mock sample', () => { test('mock already existing object method', () => { mock.method(mocked, 'fn', () => { return 334; }); assert.deepEqual(someFunc1(), 334); assert.strictEqual(mocked.fn.mock.calls.length, 1); }); }); ରͷΦϒδΣΫτͷNFUIPEΛ NPDL NPDLͷݺΕͨճ֬ೝՄೳ
spy functionΛͬͯmock͢Δํ๏ // mock.js export const someFunc2 = (ctx) =>
{ console.log('execute'); ctx.logger('aaa'); console.log('end'); }; // test.js import {describe, test, mock} from 'node:test'; import assert from 'node:assert/strict'; import { someFunc2 } from './mock.mjs'; describe('mock sample', () => { test('use spy function', () => { const ctx = { logger: mock.fn((a) => { console.log(a); }), }; assert.strictEqual(ctx.logger.mock.calls.length, 0); someFunc2(ctx); assert.strictEqual(ctx.logger.mock.calls.length, 1); assert.deepEqual(ctx.logger.mock.calls[0].arguments, ['aaa']); }); }); ςετରͷΦϒδΣΫτͷ ϝιουΛNPDLʹม͑Δ NPDLͷҾͷݕূՄೳ
context
node:testʹcontext͕ଘࡏͯ͠·͢ʂ • test runnerͱΓऔΓ͢ΔͨΊʹɺtest()ͱ͔ʹTestContext͕ ͞Ε͍ͯΔ • GoΈ͍ͨͳײ͡ͰContext͕͑Δ
context(t)ΛͬͯςετΛॻ͍ͨύλʔϯ import {test} from 'node:test'; import assert from 'node:assert/strict'; test('test',
async (t) => { t.beforeEach(() => { console.log('beforeEach'); }); t.afterEach(() => { console.log('afterEach'); }) t.after(() => { console.log('after'); }); await t.test('͜Ε௨Δ', () => { console.log('test1'); assert.equal(2 + 2, 4); }); await t.test('͜ΕམͪΔ', () => { console.log('test2'); assert.equal(2 + 2, 5); }); });
contextͷҙ • t.beforeଘࡏ͠ͳ͍ • test suiteͰॱ൪ʹ࣮ߦ͞ΕΔ͔Βͦ͜Ͱ୲อͰ͖Δ • t.testpromiseΛฦ͢ • await͠ͳ͍ͱtest͕ઌʹऴΘͬͯΤϥʔʹ
• ςετέʔεͷΧϯτ͕บ͋Γ • #{rootͷςετ}+#{t.testͷݸ} • લϖʔδͩͱ̏ςετέʔε • contextͷςετ͕མͪΔͱςετམͪͨ͜ͱʹͳΔ
coverage·ΘΓ
coverage·ΘΓ • ·ͩStability 1(Experimental) • —experimental-test-coverageϑϥάΛ ͚ͯ͋͛Δͱऩूͯ͘͠ΕΔ • ྲྀੴʹjest΄ͲϦονͳݟͨͰͳ͍
• coverageؚΊςετϨϙʔτΛΧελϜ Մೳ
ςετϨϙʔτͷΧελϚΠζ import { Transform } from 'node:stream'; const customReporter =
new Transform({ writableObjectMode: true, transform(event, encoding, callback) { const nest = event.data.nesting; const nestSpace = ' '.repeat(nest * 2); switch (event.type) { case 'test:start': callback(null, `\x1b[39m${nestSpace}test ${event.data.name} started\n`); break; case 'test:pass': callback(null, `\x1b[32m${nestSpace}test ${event.data.name} passed\n`); break; case 'test:fail': callback(null, `\x1b[31m${nestSpace}test ${event.data.name} failed\n`); break; case 'test:plan': callback(null, `\x1b[39m${nestSpace}test plan\n`); break; case 'test:diagnostic': callback(null, `\x1b[39m${nestSpace}${event.data.message}\n`); break; case 'test:coverage': { const { totalLineCount } = event.data.summary.totals; callback(null, `\x1b[39m${nestSpace}total line count: ${totalLineCount}\n`); break; } } }, }); export default customReporter;
ύϑΥʔϚϯε
ςετπʔϧม͑ΔͨΊͷಈػ • ͍͍͔͢ʁ • ඇਪ(or ϝϯςऴྃ)ʹͳ͍ͬͯͳ͍͔ʁ • ͍͔ʁ • CIͷ࣮ߦ͕࣌ؒݮΔͱઅʹͳΔ
• ։ൃऀܦݧతʹخ͍͠
jest vs node:testΛͯ͠ΈΔ • ҎԼͷΑ͏ͳύλʔϯͰjestͱnode:testͷ࣮ߦΛൺֱ • mockΛߦ͏ύλʔϯ • https://github.com/jiko21/node-test-compare •
mockΛߦΘͳ͍ύλʔϯ • https://github.com/jiko21/node-test-compare-without-mock
ςετର // mocked.js const fn = (a, b) => {
return a + b; }; module.exports = { fn, } // mock.js const mocked = require('./mocked'); const someFunc1 = () => { return mocked.fn(1, 2); }; module.exports.someFunc1 = someFunc1;
mockͨ͠߹
mock͠ͳ͍߹
node:testͷ΄͏͕ૣͦ͏ • ͍͢͝γϯϓϧͳྫ͚ͩͲɺ2ഒ΄Ͳ͍ • ͋Μ·Γmock͋Γͳ͠ʹӨڹड͚ͯͳ͍
࣮ϓϩμΫτʹೖͰ͖Δ͔ʁ
ҎԼͷΑ͏ͳϓϩδΣΫτͰݕূ • TypeScriptͰ࡞ͬͨΦϨΦϨOSS • https://github.com/jiko21/ fl av-md • ts-jestͰςετΛ࣮ߦ͍ͯ͠Δ
Ͳ͏ͬͯಈ͔͔͢ʁ • jestͳΒts-jest͕͋Δ͚Ͳɺnode:testʹͦΜͳศརͳͷ (·ͩ)ͳ͍ • ҎԼͷํ๏Λߟ͑ͯΈͨ • ts-nodeͰ࣮ߦ •
શͯtsͰ͔͍ͯtranspileɺnodeͰී௨ʹ࣮ߦ • ςετରΛbuild→ςετϑΝΠϧΛjs
ts-nodeͰ࣮ߦ • ts-nodeͰtranspile࣮ͭͭ͠ߦ
શͯtsͰ͔͍ͯtranspileɺnodeͰී௨ʹ࣮ߦ • tscͰtest fi leΛtranspileɻtranspileͯ͠ੜ͞ΕͨjsΛnodeͰී௨ ʹ࣮ߦ
ςετରΛbuild→ςετϑΝΠϧΛjs • tscͰtest fi leΛtranspileɻtranspileͯ͠ੜ͞ΕͨjsΛnodeͰී௨ ʹ࣮ߦ
Ϗϧυ࣌ؒΛߟྀͯ͠ൺֱͨ݁͠Ռ • jestͳΒts-jest͕͋Δ͚Ͳɺnode:testʹͦΜͳศརͳͷ (·ͩ)ͳ͍ • ҎԼͷํ๏Λߟ͑ͯΈͨ • ts-nodeͰ࣮ߦ •
શͯtsͰ͔͍ͯtranspileɺnodeͰී௨ʹ࣮ߦ • ςετରΛbuild→ςετϑΝΠϧΛjs
࣮ߦ݁Ռ(Ϗϧυൈ͖) • node:testࣗମͷ ͍ • transpile͢Δରม͑ͯ ͦΜͳʹมΘΒͳ͍ •
ts-jest෦తʹtsͷbuild ͢ΔͷͰྲྀੴʹෆެฏ
࣮ߦ݁Ռ(ϏϧυؚΉ) • Ϗϧυ࣌ؒΛೖΕͯ͠·͏ͱ ରͯ͘͠ͳ͍ࣄ͕Θ͔Δ (ଟ͜Ε͕ެฏͳධՁ)
·ͱΊ • node:test͕v20ͰΑ͏͘stableʹͳͬͨʂ • Ұػೳ·ͩexperimental • ҰԠjestΑΓ͍ʂ • ϓϩδΣΫτͰ͑Δ͔ɺͱݴΘΕΔͱ·ͩݫ͍͔͠
ࢀߟ • https://nodejs.org/api/test.html