DOM을 직접 조작하는 함수는 버그를 만들기 쉽습니다. 이번 글에서는 jsdom과 간단한 시뮬레이션으로 UI 로직을 검증하는 방법을 소개합니다. 핵심은 “jsdom + 사용자 시나리오 테스트”이고, BrowserMock은 선택 도구입니다.
이번 글에서 새로 나오는 용어
- jsdom: Node.js 환경에서 DOM API를 흉내 내 테스트를 돌릴 수 있게 해 주는 라이브러리입니다.
- 사용자 시나리오 테스트: 실제 사용자가 클릭·입력하는 과정을 코드로 재현해 검증하는 방법입니다.
- data-testid: 테스트에서 요소를 안정적으로 찾기 위해 붙이는
data-속성입니다. - BrowserMock: HTML 문자열만으로 가짜 브라우저 환경을 만들어 주는 경량 도구입니다.
- CI(Continuous Integration): 코드를 머지하기 전에 자동으로 테스트를 실행하는 파이프라인입니다.
핵심 개념
- jsdom(JS DOM, Node용 가짜 브라우저): Node.js 환경에서 DOM API를 흉내 내는 라이브러리입니다. 렌더 함수나 이벤트 핸들러를 테스트할 때 사용합니다.
- 사용자 시나리오 테스트(User Scenario Test, 사용자 행동 재현): 사용자가 버튼을 클릭하고 입력을 제출하는 과정을 코드로 재현합니다.
- BrowserMock/가상 DOM(Virtual DOM Mock, HTML 시뮬레이터): 실제 브라우저 없이도 HTML 구조를 검사할 수 있는 도구입니다.
- 테스트 훅 데이터 속성(Test Hook Data Attribute, 안정적 선택자):
data-testid같은 속성으로 요소를 안정적으로 찾습니다.
코드로 확인하기
먼저 테스트 환경을 구성할 도구를 설치합니다. 설치 전, “테스트가 없다면 무엇이 불편한가?”를 짧게 느껴봅니다.
renderGreeting(root, "민지");
console.log(root.innerHTML);
➡️ 매번 콘솔로 눈으로 확인해야 한다는 사실이 귀찮게 느껴졌다면, 테스트 자동화의 필요성을 이미 체감한 것입니다.
npm install --save-dev vitest jsdom
간단한 렌더 함수를 만들어 테스트 대상을 정의합니다.
// greet.js
export function renderGreeting(root, name) {
root.innerHTML = `<p data-testid="greeting">${name}님 안녕하세요</p>`;
}
jsdom으로 DOM을 흉내 내고 함수를 검증합니다.
// greet.test.js
describe("renderGreeting", () => {
it("이름을 포함한 인사말을 표시한다", () => {
const dom = new JSDOM(`<!doctype html><div id="root"></div>`);
const root = dom.window.document.getElementById("root");
renderGreeting(root, "민지");
const text = root.querySelector('[data-testid="greeting"]').textContent;
expect(text).toBe("민지님 안녕하세요");
});
});
jsdom을 사용하면 Node.js 환경에서도 DOM API를 사용할 수 있습니다. 즉, “브라우저 없이도 DOM을 다룬다”는 장점이 핵심입니다.
이제 이벤트가 포함된 카운터 컴포넌트를 만들어 봅니다.
// counter.js
export function initCounter(root) {
let value = 0;
root.innerHTML = `
<div>
<output data-testid="value">0</output>
<button data-testid="inc">+</button>
</div>
`;
root.querySelector('[data-testid="inc"]').addEventListener("click", () => {
value += 1;
root.querySelector('[data-testid="value"]').textContent = String(value);
});
}
사용자 시나리오를 이벤트로 재현해 기능을 검증합니다.
// counter.test.js
describe("initCounter", () => {
it("버튼 클릭 시 값이 증가한다", () => {
const dom = new JSDOM(`<!doctype html><div id="app"></div>`);
const app = dom.window.document.getElementById("app");
initCounter(app);
const button = app.querySelector('[data-testid="inc"]');
const value = app.querySelector('[data-testid="value"]');
button.dispatchEvent(new dom.window.Event("click"));
expect(value.textContent).toBe("1");
});
});
사용자 시나리오를 이벤트로 재현해 기능을 검증합니다. 한 문장으로 요약하면 “버튼을 눌렀다고 가정하고, 값이 바뀌었는지 assert 한다”입니다.
BrowserMock처럼 가벼운 도구로도 DOM 구조를 흉내 낼 수 있습니다. BrowserMock은 “테스트 프레임워크 없이 HTML을 빠르게 그려 보는 선택 도구”로 생각하면 됩니다.
// browser-mock 예시
const { document, window } = mock("<form><input name=\"title\" /></form>");
const input = document.querySelector("input");
input.value = "회의 준비";
document.querySelector("form").dispatchEvent(new window.Event("submit"));
BrowserMock처럼 간단한 HTML 문자열로 DOM을 만들 수 있는 도구를 사용하면 테스트 세팅이 빨라집니다.
BrowserMock은 “UI 상태를 빠르게 그림으로 확인”하는 용도로 좋습니다. jsdom 테스트 코드보다 짧고, 다음 순서를 반복하면 됩니다.
- HTML 조각을 문자열로 만든다.
- 초기화 함수를 실행한다.
- 이벤트를 발생시켜 상태 변화를 재현한다.
document.body.innerHTML이나 특정 노드의 텍스트를 출력해 캡처한다.
💬 댓글
이 글에 대한 의견을 남겨주세요