본문 바로가기
source-code/software

[jest] jest dom을 통한 DOM 객체 동작 테스트 하기

by mattew4483 2024. 4. 10.
728x90
반응형

Backgrounds

현재 개발 중인 서비스에서는

사용자가 생성한 데이터를 통해 웹 페이지에서 특정 요소(HTMLElement)를 조회하는 기능을 제공하고 있습니다.

 

이때 해당 요소를 찾는 알고리즘이 제법 복잡하고 예외 케이스가 많이 발생해,

코드를 수정할 때마다 고객사 페이지에 직접 접속해 정상 동작 여부를 확인하는 불편함이 존재했습니다.

 

그리고 이로 인해

1) 개발 소요 시간 증대

2) 적극적인 리팩토링 어려움 (수정이 발생하면, 기존 잘 되던 케이스가 안될 것이라는 두려움) 과 같은 문제들이 발생했습니다.

 

Solutions

최선의 방안은 모든 고객사 페이지를 자동으로 크롤링하면서, 로직이 정상 동작하는지 확인하는 것이겠으나...

하루아침에 이 정도의 자동화 테스트를 도입하기엔 현실적인 무리가 있었습니다.

 

따라서 우선적으로

1) 테스트 하고자 하는 사용자 페이지 html을 다운로드하여

2) 해당 html에서 알고리즘을 통해 입력 데이터로 요소를 정상적으로 조회할 수 있는지 테스트하고자 했습니다.

 

1. 필요 라이브러리 설치

1) fs

파일 시스템 모듈을 이용해 다운 받은 html 파일을 읽어옵니다.

 

2) jest, @testing-library/jest-dom

jest를 통해 테스트를 수행하며

@testing-library/jest-dom의 유틸리티 함수들을 통해 DOM 요소에 대한 테스트를 쉽게 작성할 수 있습니다.

 

3) jsdom

jsdom은 브라우저에서 실행되는 Javascript 코드와 유사한 환경을 제공하며,

이를 통해 Node 환경에서도 DOM 조작, 이벤트 처리, CSS 선택자 등을 사용할 수 있습니다.

 

2. 기본 테스트 코드 작성

const { JSDOM } = require("jsdom");

DOM 객체를 생성하기 위해 JSDDOM을 import 하면 

ReferenceError: TextEncoder is not defined

라는 에러가 발생합니다.

 

https://github.com/inrupt/solid-client-authn-js/issues/1676

 

jest jsdom: ReferenceError: TextEncoder is not defined · Issue #1676 · inrupt/solid-client-authn-js

Search terms you've used jsdom, TextEncoder Impacted package Which packages do you think might be impacted by the bug ? solid-client-authn-browser solid-client-authn-node solid-client-authn-core oi...

github.com

테스트가 실행되기 전 setup으로, TextEncoder와 TextDecoder를 mocking하면 정상적으로 동작합니다.

 

테스트하고자 하는 웹 사이트의 html을 다운 받은 후

 

const path = require("path");
const fs = require("fs");

// jsdom TextEncoder/TextDecoder mocking
const { TextEncoder } = require("util");
const { TextDecoder } = require("util");
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;
const { JSDOM } = require("jsdom");

// @testing-library/jest-dom에서 `toBeInTheDocument` 함수를 가져옵니다.
const { toBeInTheDocument } = require("@testing-library/jest-dom/matchers");
// Jest의 Matchers에 `toBeInTheDocument` 함수를 추가합니다.
expect.extend({ toBeInTheDocument });

it("target-id라는 id값을 가진 요소가 DOM에 존재한다", () => {
  const htmlPath = path.resolve(__dirname, "./test.html");
  const html = fs.readFileSync(htmlPath, "utf-8");
  // JSDOM을 사용하여 DOM 객체 생성
  const dom = new JSDOM(html);
  const document = dom.window.document;

  // 특정 요소 존재 여부 테스트
  const targetElement = document.querySelector("#target-id");
  expect(targetElement).toBeInTheDocument();
});

fs로 읽어온 html 파일을 통해 DOM 객체를 생성한 뒤, 

해당 DOM의 document API를 사용해 특정 요소를 조회할 수 있습니다!

(실제 알고리즘에서는 xPath 문법을 사용합니다)

 

마지막으로 @testing-library를 통해 해당 요소가 문서상에 존재하는지 테스트할 수 있게 됩니다.

정상적으로 테스트가 실행되는 모습!

728x90
반응형