Spelunking in node_modules 👷

지난 주에 한 달 넘게 자리를 비운 후 다시 일을 시작했습니다. 그렇게 오랫동안 자리를 비웠다가 돌아오면 가장 먼저 하는 일은 무엇인가요? 당연히 종속성을 업그레이드하는 것이죠! 특히 kcd-scripts와 paypal-scripts 프로젝트에 집중했습니다. 특히 rollup, jest, lint-staged에 각각 몇 가지 멋진 기능이 추가되었기 때문에 기대가 컸습니다.

대부분 순조롭게 진행되었습니다. rollup과 관련하여 몇 가지 사용 중단 경고가 있었지만 충분히 간단했습니다. Jest에서 변경해야 할 간단한 변경사항이 하나 있었는데, (이 변경 사항이 출시되면 되돌릴 수 있을 것 같습니다.)

하지만 여러 프로젝트에서 kcd-scripts를 업데이트하기 시작했습니다. downshift를 업데이트하기 전 까지는 모든 것이 잘 진행되고 있었습니다. downshift 에는 오류 사례(예를 들어 prop getter와 상호 작용하는 방식을 검증할 때 발생하는 오류)에 대한 여러 테스트가 있습니다. downshift 를 마운트 하려고 할 때 뭔가 잘못하면 에러가 발생한다는 몇 가지 주장이 있습니다. 특히, 이 테스트에서 다음과 같은 결과가 나왔습니다.

Error: Uncaught [Error: downshift: You provided the id of "foo" for your input, but the htmlFor of your label is "bar". You must either remove the id from your input or set the htmlFor of the label equal to the input id.]
    at reportException (/Users/kdodds/Developer/downshift/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
    at invokeEventListeners (/Users/kdodds/Developer/downshift/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:209:9)
    at HTMLUnknownElementImpl._dispatch (/Users/kdodds/Developer/downshift/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
    at HTMLUnknownElementImpl.dispatchEvent (/Users/kdodds/Developer/downshift/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
    at HTMLUnknownElementImpl.dispatchEvent (/Users/kdodds/Developer/downshift/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
    at HTMLUnknownElement.dispatchEvent (/Users/kdodds/Developer/downshift/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:143:21)
    at Object.invokeGuardedCallbackDev (/Users/kdodds/Developer/downshift/node_modules/react-dom/cjs/react-dom.development.js:581:16)
    at invokeGuardedCallback (/Users/kdodds/Developer/downshift/node_modules/react-dom/cjs/react-dom.development.js:438:27)
    at renderRoot (/Users/kdodds/Developer/downshift/node_modules/react-dom/cjs/react-dom.development.js:10366:7)

...

하지만 재미있는 점은 테스트가 모두 통과되었다는 것입니다! 게다가 이 로그는 console.error 호출에서 발생하고 있으며, 해당 파일의 맨 위에는 아무것도 로깅하지 않도록 console.error를 모킹하고 있습니다!

beforeEach(() => {
  jest.spyOn(console, 'error')
  console.error.mockImplementation(() => {})
})

afterEach(() => {
  console.error.mockRestore()
})

<aside> 💡 console.error를 보지 않기 위해 mocking하는 경우가 있구나!

</aside>

이렇게 해서 애초에 예상했던 React가 오류를 로깅하는 노이즈를 피할 수 있었습니다! 아, 그리고 오류는 React에서 발생한 것이 아닙니다… 직접적으로는 아니죠… 실제로는 JSDOM에서 발생합니다! 스택 트레이스를 기억하시나요? 상단에 이렇게 적혀있습니다.

at reportException (/Users/kdodds/Developer/downshift/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)

stack trace를 마주하면 어떻게 해야 할까요?

이와 같은 stack trace가 표시되면 먼저 자신의 코드에서 어디가 잘못되었는지 확인할 수 있습니다. 이렇게 하면 코드에서 문제를 일으키는 원인을 파악하고 문제를 해결할 수 있습니다. 여기서도 문제를 파악할 수 없다면 stack trace를 최대한 따라가는 것이 정말 도움이 될 수 있습니다. 디버거(예: 브라우저 개발자 도구)를 사용하는 것은 이를 위한 훌륭한 방법입니다.

그래서 여기서부터 탐험을 시작합니다. 종속성을 업그레이드하기 전에는 코드가 제대로 작동했기 때문에 괜찮다는 것을 알고 있었습니다. 그래서 종속성에서 뭔가 변경된 것이 틀림없다고 생각했습니다. 그래서 어떻게 해야 할까요? 우선 이전 node_modules 디렉토리를 열고 무슨 일이 있었는지 확인해 보세요!