1. Test Runner 란 ?

Glob 란?

기본 설정

# 예시 
test/
  setup.mjs              # 공통 설정
  setup.unit.mjs         # 유닛 테스트용 설정
  setup.integration.mjs  # 통합 테스트용 설정
  setup.e2e.mjs          # E2E 테스트용 설정

2. 구현체

2-1. 동적 테스트

  1. describe 가 아닌 t.test 를 사용할 것
  2. 흐름
    1. test('Detect OS', ...)

    2. Node가 TestContext(t) 생성

    3. for 문에서 t.test() 호출

      import assert from 'node:assert/strict';
      import { test } from 'node:test';
      
      import { detectOsInUserAgent } from '…';
      
      const userAgents = [
        {
          ua: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.3',
          os: 'WIN',
        },
        // …
      ];
      
      test('Detect OS via user-agent', { concurrency: true }, t => {
        for (const { os, ua } of userAgents) {
          t.test(ua, () => assert.equal(detectOsInUserAgent(ua), os));
        }
      });
      
    4. Promise 추가, 전체 테스트

      import assert from 'node:assert/strict';
      import { test } from 'node:test';
      
      import { getWorkspacePJSONs } from './getWorkspacePJSONs.mjs';
      
      const requiredKeywords = ['node.js', 'sliced bread'];
      
      test('Check package.jsons', { concurrency: true }, async t => {
        const pjsons = await getWorkspacePJSONs();
      
        const cases = pjsons.map(pjson =>
          // ⚠️ `t.test`, NOT `test`
          t.test(`Ensure fields are properly set: ${pjson.name}`, () => {
            assert.partialDeepStrictEqual(pjson.keywords, requiredKeywords);
          })
        );
      
        // Allow the cases to run concurrently.
        await Promise.allSettled(cases);
      });
      
      import { globSync } from 'node:fs';
      import { fileURLToPath } from 'node:url';
      
      // Note: This would be better implemented as an async generator, leveraging fs.glob (instead of fs.globSync);
      // however, generators and especially async generators are much less understood,
      // so this simplified example is provided for easier understanding.
      
      /**
       * Get all the package.json files, by default 1-level deep within ./workspaces/
       */
      export function getWorkspacePJSONs(path = './workspaces/*/package.json') {
        return Promise.all(
          globSync(
            // ⚠️ Passing a file URL string, like from import.meta.resolve, causes glob* to fail silently
            fileURLToPath(import.meta.resolve(path))
          ).map(path => import(path, { with: { type: 'json' } }))
        );
      }
      

2-2. ServiceWorker tests

import { beforeEach } from 'node:test';

import { ServiceWorkerGlobalScope } from './globals/ServiceWorkerGlobalScope.js';

import './setup.mjs'; // 💡

beforeEach(globalSWBeforeEach);
function globalSWBeforeEach() {
  globalThis.self = new ServiceWorkerGlobalScope();
}
import assert from 'node:assert/strict';
import { describe, mock, it } from 'node:test';

import { onActivate } from './onActivate.js';

describe('ServiceWorker::onActivate()', () => {
  const globalSelf = globalThis.self;
  const claim = mock.fn(async function mock__claim() {});
  const matchAll = mock.fn(async function mock__matchAll() {});

  class ActivateEvent extends Event {
    constructor(...args) {
      super('activate', ...args);
    }
  }

  before(() => {
    globalThis.self = {
      clients: { claim, matchAll },
    };
  });
  after(() => {
    global.self = globalSelf;
  });

  it('should claim all clients', async () => {
    await onActivate(new ActivateEvent());

    assert.equal(claim.mock.callCount(), 1);
    assert.equal(matchAll.mock.callCount(), 1);
  });
});

2-3. Snapshot tests