Upgrade to Pro — share decks privately, control downloads, hide ads and more …

node:test will replace Jest?

jiko21
May 09, 2023
51

node:test will replace Jest?

関西Node学園 10時限目の登壇資料です。

jiko21

May 09, 2023
Tweet

Transcript

  1. γϯϓϧͳςετίʔυ 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ͯ͘͠ΕΔ
  2. 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') }); });
  3. ϑΝΠϧ໊Λࢦఆ͠ͳ͔ͬͨ৔߹ • ҎԼͷϧʔϧʹै࣮ͬͯߦ͞ΕΔ 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΋ࣗಈͰ࣮ߦ
  4. 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); }); });
  5. 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ͷݺ͹Εͨճ਺΋֬ೝՄೳ
  6. 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ͷҾ਺ͷݕূ΋Մೳ
  7. 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); }); });
  8. contextͷ஫ҙ఺ • t.before͸ଘࡏ͠ͳ͍ • test suite಺Ͱॱ൪ʹ࣮ߦ͞ΕΔ͔Βͦ͜Ͱ୲อͰ͖Δ • t.test͸promiseΛฦ͢ • await͠ͳ͍ͱ਌test͕ઌʹऴΘͬͯΤϥʔʹ

    • ςετέʔε਺ͷΧ΢ϯτ͕บ͋Γ • #{rootͷςετ}+#{t.testͷݸ਺} • લϖʔδͩͱ̏ςετέʔε • contextͷςετ͕མͪΔͱ਌ςετ΋མͪͨ͜ͱʹͳΔ
  9. ςετϨϙʔτͷΧελϚΠζ 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;
  10. ςετର৅ // 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;