npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@dannysir/js-te

v0.3.1

Published

JavaScript test library

Readme

js-te

Jest에서 영감을 받아 만든 가벼운 JavaScript 테스트 프레임워크입니다.

📎 최근 업데이트 0.3.0v

mock 이후 import를 해야하는 문제 해결

  • 문제 : 기존의 경우 모킹 기능 이용시 반드시 동적 import문을 mock 다음에 작성해야 했음
  • 해결
    • 기존 mockStore를 직접 비교하여 import하는 방식에서 wrapper 패턴을 이용하도록 적용
    • 모듈을 새로운 함수로 만들어 함수를 실행할 때마다 mockStore와 비교하여 값을 리턴하도록 수정

모듈 변환 최적화

  • 문제 : 앞선 변경으로 인해 모든 파일의 모듈들이 사용될 때마다 mockStore와 비교하는 로직이 실행됨
  • 해결
    • cli로직에 mock을 미리 검사하여 mock 경로를 미리 저장하는 로직을 추가
    • 미리 확인한 mock 경로를 이용해 import문이 만약 저장된 경로일 때만 babel 변환

설치

npm install --save-dev @dannysir/js-te

빠른 시작

1. 테스트 파일 만들기

*.test.js 파일을 만들면 자동으로 찾아서 실행합니다.

별도의 import문 없이 describetest, expect 로직이 사용 가능합니다.

// math.test.js
describe('[단순 연산 테스트]', () => {
  test('더하기 테스트', () => {
    expect(1 + 2).toBe(3);
  });
});

2. 테스트 실행

package.json에 추가.

  • ~~type을 module로 설정해주세요.~~

✅ 0.2.1 버전부터 common js 방식을 지원합니다.

{
  "type": "module", // 0.2.1 버전부터 common js도 사용 가능
  "scripts": {
    "test": "js-te"
  }
}

실행:

npm test

예시 출력 화면

API

테스트 작성

test(설명, 함수)

테스트 하나를 정의합니다.

test('배열 길이 확인', () => {
  expect([1, 2, 3].length).toBe(3);
});

describe(이름, 함수)

테스트를 그룹으로 묶습니다. 중첩도 됩니다.

describe('계산기', () => {
  describe('더하기', () => {
    test('양수 더하기', () => {
      expect(2 + 3).toBe(5);
    });
  });
  
  describe('빼기', () => {
    test('양수 빼기', () => {
      expect(5 - 3).toBe(2);
    });
  });
});

Matcher

expect(값).toBe(기댓값)

===로 비교합니다. 숫자, 문자열 같은 원시값 비교할 때 사용.

expect(5).toBe(5);
expect('안녕').toBe('안녕');

expect(값).toEqual(기댓값)

객체나 배열의 내용을 비교합니다.

expect({ name: '철수' }).toEqual({ name: '철수' });
expect([1, 2, 3]).toEqual([1, 2, 3]);

expect(함수).toThrow(에러메시지)

함수가 에러를 던지는지 확인합니다.

expect(() => {
  throw new Error('에러 발생');
}).toThrow('에러');

expect(값).toBeTruthy() / expect(값).toBeFalsy()

참/거짓 여부를 확인합니다.

expect(true).toBeTruthy();
expect(0).toBeFalsy();

Mocking

동작 원리

Babel을 사용해서 import/require 구문을 변환하여 mock 함수를 가져오도록 했습니다.

  1. 테스트 파일 찾기
    1. mock(path, mockObj) 선언 확인
    2. path를 key로 이용해 Map에 저장
  2. Babel로 코드 변환
// 0.3.0 버전 이후
const _original = await import('./random.js');
const random = (...args) => {
  const module = mockStore.has('/path/to/random.js')
    ? { ..._original, ...mockStore.get('/path/to/random.js') }
    : _original;
  return module.random(...args);
};

// 0.3.0 버전 이전
const _original = await import('./random.js');
const _module = mockStore.has('/path/to/random.js')
  ? { ..._original, ...mockStore.get('/path/to/random.js') }
  : _original;
const {random1, random2} = _module;
  1. 테스트 실행
  2. 원본 파일 복구

mock(모듈 절대 경로), mock객체)

모듈을 모킹합니다. import 하기 전에 호출해야 합니다.

🚨 주의사항

  1. 반드시 경로는 절대 경로로 입력해주세요.
    • babel이 import문에서 절대 경로로 변환하여 확인을 하기 때문에 반드시 절대 경로로 등록해주세요.
  2. ~~import문을 반드시 mocking 이후에 선언해주세요.~~
    • ~~mocking 전에 import를 하게 되면 mocking되기 전의 모듈을 가져오게 됩니다.~~

0.3.0 버전부터 import문을 mock선언 이후에 하지 않아도 됩니다.

💡 부분 모킹(Partial Mocking)

0.2.1 버전부터 모듈의 일부 함수만 모킹하고 나머지는 원본을 사용할 수 있습니다.

// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;

// math.test.js
const { add, multiply } = import('./math.js'); // 0.3.0 버전부터는 최상단에 선언 가능

test('부분 모킹 예제', async () => {
  mock('/Users/san/untitled/index.js', {
    multiply: () => 100
  });
  
  expect(add(2, 3)).toBe(5);        // 원본 함수 사용
  expect(subtract(5, 3)).toBe(2);   // 원본 함수 사용
  expect(multiply(2, 3)).toBe(100); // 모킹된 함수 사용
});

📦 모듈 시스템 지원

ESM(import)과 CommonJS(require) 모두 지원합니다.

// ESM 방식
import { random } from './random.js';

// CommonJS 방식
const { random } = require('./random.js');
// random.js
export const random = () => Math.random();

// game.js
import { random } from './random.js'; // 자유롭게 import하면 babel에서 절대 경로로 변환하여 판단합니다.
// 또는 CommonJS 방식도 지원
// const { random } = require('./random.js');

export const play = () => random() * 10;

// game.test.js
import {play} from './game.js';

test('랜덤 함수 모킹', async () => {
  // 1. 먼저 모킹
  mock('/Users/san/Js-Te/test-helper/random.js', { // 반드시 절대 경로로 등록
    random: () => 0.5
  });
  
  // 2. 모킹된 값 사용
  expect(play()).toBe(5);
});

clearAllMocks()

등록된 모든 mock을 제거합니다.

unmock(모듈경로)

특정 mock만 제거합니다.

isMocked(모듈경로)

mock이 등록되어 있는지 확인합니다.

each(cases)

cases를 배열로 받아 순차적으로 테스트 진행

🚨 주의 사항

cases는 반드시 Array 타입으로 받아야 합니다.

플레이스 홀더

  • %s - 문자열/숫자
  • %o - 객체 (JSON.stringify)
test.each([
  [1, 2, 3, 6],
  [3, 4, 5, 12],
  [10, 20, 13, 43],
  [10, 12, 13, 35],
])('[each test] - input : %s, %s, %s, %s', (a, b, c, result) => {
  expect(a + b + c).toBe(result);
});

/* 출력 결과
✓ [each test] - input : 1, 2, 3, 6
✓ [each test] - input : 3, 4, 5, 12
✓ [each test] - input : 10, 20, 13, 43
✓ [each test] - input : 10, 12, 13, 35
 */

test.each([
  [{ name : 'dannysir', age : null}],
])('[each test placeholder] - input : %o', (arg) => {
  expect(arg.name).toBe('dannysir');
});

/* 출력 결과
✓ [each test placeholder] - input : {"name":"dannysir","age":null}
 */

beforeEach(함수)

각 테스트가 진행되기 전에 실행할 함수를 선언합니다.

중첩된 describe에서의 beforeEach는 상위 describe의 beforeEach를 모두 실행한 후, 자신의 beforeEach를 실행합니다.

describe('카운터 테스트', () => {
  let counter;
  
  beforeEach(() => {
    counter = 0;
  });
  
  test('카운터 증가', () => {
    counter++;
    expect(counter).toBe(1);
  });
  
  test('카운터는 0부터 시작', () => {
    expect(counter).toBe(0);
  });
  
  describe('중첩된 describe', () => {
    beforeEach(() => {
      counter = 10;
    });
    
    test('카운터는 10', () => {
      expect(counter).toBe(10);
    });
  });
});

테스트 파일 찾기 규칙

자동으로 다음 파일들을 찾아서 실행합니다:

  1. *.test.js 파일
  2. test/ 폴더 안의 모든 .js 파일
프로젝트/
├── src/
│   ├── utils.js
│   └── utils.test.js       ✅
├── test/
│   ├── integration.js      ✅
│   └── e2e.js              ✅
└── calculator.test.js      ✅

예제

기본 테스트

describe('문자열 테스트', () => {
  test('문자열 합치기', () => {
    const result = 'hello' + ' ' + 'world';
    expect(result).toBe('hello world');
  });
  
  test('대문자 변환', () => {
    expect('hello'.toUpperCase()).toBe('HELLO');
  });
});

모킹 예제

전체 모킹

// mocking.test.js
import {random} from '../src/test-helper/game.js'; // 0.2.4 버전부터 import문 상단 배치 가능

test('[mocking] - mocking random function', async () => {
  mock('/Users/san/Js-Te/test-helper/random.js', {
    random: () => 3,
  });
  // 0.3.0 버전 이전까지는 반드시 mock 이후 동적 import문 작성
  // const {play} = await import('../src/test-helper/game.js');
  expect(play()).toBe(30);
});

// game.js
import {random} from '/test-helper/random.js'

export const play = () => {
  return random() * 10;
};

// random.js
export const random = () => Math.random();

부분 모킹

// calculator.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;

// calculator.test.js
test('[partial mocking] - mock only multiply', async () => {
  // multiply만 모킹, add와 subtract는 원본 사용
  mock('/Users/san/Js-Te/calculator.js', {
    multiply: (a, b) => 999
  });
  
  const { add, subtract, multiply } = await import('./calculator.js');
  
  expect(add(2, 3)).toBe(5);        
  expect(subtract(5, 2)).toBe(3);   
  expect(multiply(2, 3)).toBe(999); 
});

링크

만든 이유

Jest를 사용하며 JavaScript 테스트 라이브러리의 구조가 궁금하여 만들게 되었습니다.

라이선스

ISC