Jest: `jest.mock()`์˜ ๋ชจ๋“ˆ ํŒฉํ† ๋ฆฌ๋Š” ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2017๋…„ 01์›” 11์ผ  ยท  33์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: facebook/jest

RN์—์„œ Picker ๋ฅผ ์กฐ๋กฑํ•˜๊ธฐ ์œ„ํ•ด #1960์˜ ์Šค๋‹ˆํŽซ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

import React, {Component} from 'react';

jest.mock(`Picker`, () => {
 // ...etc
});

Jest 17์—์„œ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๊ณ  Jest 18์—์„œ ๋‹ค์Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

/Users/simonsmith/Sites/new-look/newlookapp/test/unit/setup.js: babel-plugin-jest-hoist: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
    Invalid variable access: React
    Whitelisted objects: Array, ArrayBuffer, ..... etc

๋‚˜๋Š” React 15.4.2์™€ RN 0.40์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

babel-jest@test ๋ฅผ ์‹œ๋„ํ–ˆ๋Š”๋ฐ ์˜ˆ์ƒ๋Œ€๋กœ ์‹คํ–‰๋˜์ง€๋งŒ ๋ชจ๋“  ์Šค๋ƒ…์ƒท์ด ์‹คํŒจํ•˜๊ณ  ์ด๊ฒƒ๊ณผ ๊ด€๋ จ์ด ์—†๋Š” ๋” ๋งŽ์€ ์†Œํ’ˆ์ด ํ†ต๊ณผํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด๋‚˜ babel-jest ์˜ ๋‹ค์Œ ๋ฆด๋ฆฌ์Šค๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๊นŒ?

๊ฐ์‚ฌ ํ•ด์š” :)

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

$#$ jest.mock jest.doMock ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  33 ๋Œ“๊ธ€

๋‹น์‹ ์€ ์ด๊ฒƒ์„ ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:

jest.mock(`Picker`, () => {
  const React = require('react');
});

์ด๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ ์ˆ˜์ •ํ•œ ๋ฒ„๊ทธ์˜€์Šต๋‹ˆ๋‹ค. ๋ชจ์˜์—์„œ๋Š” ๋กœ์ปฌ์—์„œ๋งŒ ์š”๊ตฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์™ธ๋ถ€ ๋ณ€์ˆ˜์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด์œ ๋ฅผ ์„ค๋ช…ํ•˜๋ ค๋ฉด: jest.resetModules() ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ˜„์žฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๋ชจ๋“ˆ์„ ์žฌ์„ค์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ require๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๊ฐ ๋ชจ๋“ˆ์˜ ์ƒˆ ๋ฒ„์ „์„ ์–ป๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์—์„œ React๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ž ์žฌ์ ์œผ๋กœ ๋‘ ๊ฐœ์˜ React ์‚ฌ๋ณธ์„ ๊ฐ–๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์•„ํ•˜, ๊ทธ๊ฑด ๋‚ด๊ฐ€ ํ™•์‹ ํ•  ์ˆ˜ ์—†๋Š” ๋ถ€๋ถ„์ด์—ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”!

์ด ์šฉ๋„๋Š” ๊ดœ์ฐฎ๊ณ  ํƒˆ์ถœ์šฉ ํ•ด์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. mockFoo ๋ณ€์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๋Ÿฌ ๋ชจ์˜๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ :

jest.mock('./OfferList', () => 'OfferList');
jest.mock('./OfferHeader', () => 'OfferHeader');
jest.mock('./OfferHiredModal', () => 'OfferHiredModal');

๋ชจ๋“  ๋‹จ์ผ ๋ชจ์˜์— const React = require('React'); ๋ฅผ ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

๋„ค.

jest.mock(`Picker`, () => {
  const React = require('React');
});

๋ˆ„๊ตฐ๊ฐ€ ์ด๊ฒƒ์„ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ๊ณ  ๋กœ์ปฌ์ด ์•„๋‹Œ CI(circle/gitlab)์—์„œ ์‹คํŒจํ•˜๋Š” ๊ฒƒ์„ ๋ณด๋Š” ๊ฒฝ์šฐ React ๊ฐ€ ์†Œ๋ฌธ์ž react ์ธ์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

jest.mock(`Picker`, () => {
  const React = require('react');
});

@cpojer __dirname ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€๋ฐ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š”๋ฐ ์–ด๋–ป๊ฒŒ ์–ป์„ ์ˆ˜ ์žˆ๋‚˜์š”?
/Users/xx/project ์™€ ๊ฐ™์€ ํ™˜๊ฒฝ ๊ด€๋ จ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@cpojer ๋‚˜๋Š” ๋‹น์‹ ์˜ ์„ค๋ช…์„ ์ •๋ง๋กœ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์—์„œ React๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ž ์žฌ์ ์œผ๋กœ ๋‘ ๊ฐœ์˜ React ์‚ฌ๋ณธ์„ ๊ฐ–๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋กœ์ปฌ์—์„œ React๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋กœ์ปฌ React ์‚ฌ๋ณธ๋„ ๋‘ ๊ฐœ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋งž์ฃ ?

๋‘˜ ์‚ฌ์ด์— jest.resetModules() ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ํ˜ธ์ถœ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ๋ฒ”์œ„ ์•ˆ์— ๋„ฃ์„ ์ˆ˜ ์—†๋Š” ES6 ๋ชจ๋“ˆ์—์„œ ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์ž‘๋™์‹œํ‚ค๋‚˜์š”?

์˜ˆ๋ฅผ ๋“ค์–ด https://github.com/airbnb/babel-plugin-dynamic-import-node ์™€ ํ•จ๊ป˜ import ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@SimenB ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค... ์˜ˆ๋ฅผ ๋“ค์–ด์ฃผ์‹ค ์ˆ˜ ์žˆ๋‚˜์š”? ๋™์  ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์ง€์›ํ•˜๋Š” TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€๋งŒ ๋ชจ์˜ ๊ตฌํ˜„์ด ๋น„๋™๊ธฐํ™”๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Jest๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ๊ณ„์†ํ•˜๊ธฐ ์ „์— ๋ชจ์˜๊ฐ€ ํ•ด๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์•ฝ์†๋งŒ ๊ธฐ๋‹ค๋ฆฌ์„ธ์š”.

let myDep;

beforeEach(async () => {
  jest.resetModules();

  myDep = await import('./some-modules.js');
})

typescript๋กœ ์–ด๋–ป๊ฒŒ ๋ณด์ด๋Š”์ง€ ๋ชจ๋ฅด์ง€๋งŒ ๋„ˆ๋ฌด ๋‹ค๋ฅด์ง€ ์•Š์•„์•ผํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ ๋‚ด์—์„œ ES6 ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ์กฐ๋กฑํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

/**
 * @jest-environment jsdom
 */

import SagaTester from "redux-saga-tester";
import supportRequests from "sagas/support_requests";
import reducers from "reducers";

import { fetched } from "actions/support_requests";

describe("success", () => {
  it("sends the message via connection", async () => {
    const sagaTester = new SagaTester({
      reducers: reducers,
      initialState: {
        router: { location: { pathname: "/support_requests" } },
        supportRequests: null,
        authenticated: true,
        currentUser: { isSupportAgent: true },
      },
    });
    jest.mock("sagas/oauth", () => {
      return {
        ...require.requireActual("sagas/oauth"),
        callFetch: function* () {
          return { ok: true, json: () => Promise.resolve({ support_requests: [], meta: { pagination: {} } }) };
        },
      };
    });
    sagaTester.start(supportRequests);
    await sagaTester.waitFor(fetched);
  });
});

ํ™•์‚ฐ ์—ฐ์‚ฐ์ž(...) ๋ฐ ์ƒ์„ฑ๊ธฐ ํ•จ์ˆ˜๋Š” ๋ฐ”๋ฒจ์— ์˜ํ•ด _extends ๋ฐ regeneratorRuntime ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์œผ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

babel-plugin-jest-hoist: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
    Invalid variable access: _extends
    Whitelisted objects: Array, ArrayBuffer, Boolean, DataView, Date, Error, EvalError, Float32Array, Float64Array, Function, Generator, GeneratorFunction, Infinity, Int16Array, Int32Array, Int8Array, InternalError, Intl, JSON, Map, Math, NaN, Number, Object, Promise, Proxy, RangeError, ReferenceError, Reflect, RegExp, Set, String, Symbol, SyntaxError, TypeError, URIError, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray, WeakMap, WeakSet, arguments, expect, jest, require, undefined, console, DTRACE_NET_SERVER_CONNECTION, DTRACE_NET_STREAM_END, DTRACE_HTTP_SERVER_REQUEST, DTRACE_HTTP_SERVER_RESPONSE, DTRACE_HTTP_CLIENT_REQUEST, DTRACE_HTTP_CLIENT_RESPONSE, global, process, Buffer, clearImmediate, clearInterval, clearTimeout, setImmediate, setInterval, setTimeout.
    Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` are permitted.

์ด์ „์— ๋ฌธ์ œ๋ฅผ ๊ฒฝํ—˜ํ•œ ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ์ตœ์‹  ๋†๋‹ด์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Invalid variable access: _asyncToGenerator

babel-plugin-transform-regenerator๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ " jest.mock() ์˜ ๋ชจ๋“ˆ ํŒฉํ† ๋ฆฌ"๊ฐ€ "๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ด ํ—ˆ์šฉ๋˜์ง€ ์•Š์Œ"์— ๋Œ€ํ•ด ๋ถˆํ‰ํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

// ํŽธ์ง‘ํ•˜๋‹ค:
์ „์ฒด ํ…Œ์ŠคํŠธ๋Š”

it('should request data via API', async () => {
    const store = mockStore({ fields: initialState });
    jest.resetModules();
    jest.mock('services/api-client', () => ({
        getFieldsByFarm: async () => {
            return [{ field: {} }];
        },
    }));
    const Actions = require('./actions');
    const expected = [
        { type: 'FIELDS/REQUEST' },
        { type: 'FIELDS/RECEIVE', payload: { items: [{ field: {} }], didInvalidate: false },},
    ];
    await store.dispatch(Actions.getFieldsByFarm());
    const dispatchedActions = store.getActions();
    expect(dispatchedActions[0]).toEqual(expected[0]);
    expect(dispatchedActions[1].payload).toEqual(expect.objectContaining(expected[1].payload));
});

๋น„๋™๊ธฐ IIFE์—์„œ ํ…Œ์ŠคํŠธ์˜ ์ผ๋ถ€๋ฅผ ๋ž˜ํ•‘ํ•˜๊ณ  ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ์•ž์˜ async ๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด jest๊ฐ€ ์˜ค๋ฅ˜๋ฅผ throwํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 it('should request data via API', (done) => {
    const store = mockStore({ fields: initialState });
    jest.resetModules();
    jest.mock('services/api-clients/nana', () => ({
        getFieldsByFarm: async () => {
            return [{ field: {} }];
        },
    }));
    const Actions = require('./actions');
    (async () => {
        const expected = [
            { type: 'FIELDS/REQUEST' },
            {
                type: 'FIELDS/RECEIVE',
                payload: { items: [{ field: {} }], didInvalidate: false },
            },
        ];
        await store.dispatch(Actions.getFieldsByFarm());
        const dispatchedActions = store.getActions();
        expect(dispatchedActions[0]).toEqual(expected[0]);
        expect(dispatchedActions[1].payload).toEqual(expect.objectContaining(expected[1].payload));
        done();
    })();
});

$#$ jest.mock jest.doMock ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ์€ ๋‹ค๋ฅธ ๊ฒƒ๋“ค์ด ์‹คํŒจํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์•„์ง ์™„์ „ํžˆ ํ™•์‹ ํ•  ์ˆ˜ ์—†์ง€๋งŒ( ๐Ÿ˜„ ) ์ •๋ง ๋„์›€์ด ๋˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”! ๐Ÿ™‚

doMock ๋Š” ์ž‘๋™ํ•˜๊ณ  mock ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์•Œ๊ณ  ๊ณ„์‹ญ๋‹ˆ๊นŒ? ๋‚˜์—๊ฒŒ ์ด์ƒํ•œ ์ ์€ "MockedComponent"๋ผ๋Š” ์ด๋ฆ„์˜ ๋ณ€์ˆ˜๋ฅผ ๋„ฃ์œผ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์ง€๋งŒ "mockedComponent"๋ฅผ ๋„ฃ์„ ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ์—†์—ˆ์ง€๋งŒ ์ฐธ์กฐ๋Š” "์ •์˜๋˜์ง€ ์•Š์Œ"์ด์—ˆ์Šต๋‹ˆ๋‹ค.

'jest.mock' ํ˜ธ์ถœ์€ 'it' ํ˜ธ์ถœ์—์„œ ์ „์ฒ˜๋ฆฌ๊ธฐ์— ์˜ํ•ด ์™ธ๋ถ€ ํด๋กœ์ €๋กœ ์ด๋™๋˜๋ฉฐ ์ž˜ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. 'jest.doMock' ํ˜ธ์ถœ์€ ์ „์ฒ˜๋ฆฌ๊ธฐ์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

nodejs 10.0.0 ๋กœ jest๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œ๋œ ๋…ธ๋“œ ๋ฒ„์ „ ์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

@Soontao ์žฌ์ƒ์ด ์•ˆ๋˜๋Š”๋ฐ ์ž‘์€ ์žฌ์ƒ์‚ฐ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‚˜์š”?

@์‹œ๋ฉ˜๋น„
๋น ๋ฅธ ๋‹ต๋ณ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ node v10 ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ์žฌํ˜„ํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๋ชจ๋“  ํ…Œ์ŠคํŠธ๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๊ฐ€ ๋‹ค๋ฅธ ์ด์œ ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•œ ๊ฒƒ์œผ๋กœ ์ƒ๊ฐํ•˜๊ณ  nodejs๋ฅผ ๋‹ค์‹œ ์„ค์น˜ํ•  ๋•Œ ์†์‹ค๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

nodejs 10.0.0์œผ๋กœ ์‹คํ–‰ํ•  ๋•Œ ๋™์ผํ•œ ๋ฌธ์ œ

 /xxx/node_modules/react-native/jest/setup.js: babel-plugin-jest-hoist: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
    Invalid variable access: console
    Whitelisted objects: Array, ArrayBuffer, Boolean, DataView, Date, Error, EvalError, Float32Array, Float64Array, Function, Generator, GeneratorFunction, Infinity, Int16Array, Int32Array, Int8Array, InternalError, Intl, JSON, Map, Math, NaN, Number, Object, Promise, Proxy, RangeError, ReferenceError, Reflect, RegExp, Set, String, Symbol, SyntaxError, TypeError, URIError, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray, WeakMap, WeakSet, arguments, expect, jest, require, undefined, DTRACE_NET_SERVER_CONNECTION, DTRACE_NET_STREAM_END, DTRACE_HTTP_SERVER_REQUEST, DTRACE_HTTP_SERVER_RESPONSE, DTRACE_HTTP_CLIENT_REQUEST, DTRACE_HTTP_CLIENT_RESPONSE, global, process, Buffer, clearImmediate, clearInterval, clearTimeout, setImmediate, setInterval, setTimeout.
    Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` are permitted.

      at invariant (node_modules/babel-plugin-jest-hoist/build/index.js:14:11)
      at newFn (node_modules/babel-traverse/lib/visitors.js:276:21)
      at NodePath._call (node_modules/babel-traverse/lib/path/context.js:76:18)
      at NodePath.call (node_modules/babel-traverse/lib/path/context.js:48:17)
      at NodePath.visit (node_modules/babel-traverse/lib/path/context.js:105:12)
      at TraversalContext.visitQueue (node_modules/babel-traverse/lib/context.js:150:16)

๊ทธ๊ฒƒ์€ ๋…ธ๋“œ 10๊ณผ ์•„๋ฌด ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์— console ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค. ํ™๋ณด ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค! ์ˆ˜๋™ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๋Œ€์‹  globals ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค...

์—ฌ๊ธฐ์— ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋œ ๊ฒƒ: #6075

yarn add --dev babel-jest babel-core regenerator-runtime ๋กœ babel-jest๋ฅผ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๋ฉด ์ด ์˜ค๋ฅ˜๊ฐ€ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ธํ„ฐ๋„ท ๊ฒ€์ƒ‰์„ ํ•˜๋Š” ๋™์•ˆ ์ด๊ฒƒ์„ ์šฐ์—ฐํžˆ ๋ฐœ๊ฒฌํ–ˆ๊ณ  ๋‹ค๋ฅธ ๋ชจ๋“  ์‚ฌ๋žŒ๋“ค๊ณผ ํ•จ๊ป˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์—์„œ ์ด ์ค‘์š”ํ•œ ์ค„์„ ๋†“์นœ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

_mock์ด ๋Š๋ฆฌ๊ฒŒ ์š”๊ตฌ๋˜๋Š” ๊ฒƒ์ด ํ™•์ธ๋˜๋ฉด mock ์ ‘๋‘์‚ฌ๊ฐ€ ๋ถ™์€ ๋ณ€์ˆ˜ ์ด๋ฆ„์ด ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค._

์กฐ๋กฑํ•˜๋ ค๋Š” ํ•ญ๋ชฉ์˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜์—ฌ YourComponentName์„ ์กฐ๋กฑ ํ•˜์‹ญ์‹œ์˜ค.

ํ…Œ์ŠคํŠธ์—์„œ tsx ์ง€์›์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ๋‚ด jest.conf์— ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ ํ›„ ์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค(ํ•ด๋‹น ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉด ๋‚ด spec.tsx ํŒŒ์ผ์— tsx๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  globals: {
    jasmine: true,
+   'ts-jest': {
+     babelConfig: true
+   }
  }
module.exports = {
  // eslint-disable-next-line no-undef
  rootDir: path.resolve(__dirname, '../'),
  roots: ['<rootDir>/src'],
  verbose: false,
  moduleFileExtensions: ['ts', 'tsx', 'vue', 'js', 'jsx', 'json'],
  testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(ts|js)x?$',
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  },
  transform: {
    '^.+\\.vue$': 'vue-jest',
    '^.+\\.(js|jsx)?$': 'babel-jest',
    '^.+\\.tsx?$': 'ts-jest'
  },
  transformIgnorePatterns: ['<rootDir>/node_modules/(?!lodash-es)'],
  snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
  setupFilesAfterEnv: ['<rootDir>/test/jest.init.ts'],

  // run tests with --coverage to see coverage
  coverageDirectory: '<rootDir>/test/coverage',
  coverageReporters: ['html', 'text-summary'],
  collectCoverageFrom: ['src/**/*.{ts,tsx,js,jsx,vue}', '!**/node_modules/**'],

  globals: {
    jasmine: true,
    'ts-jest': {
      babelConfig: true
    }
  }
}

๋‚ด๊ฐ€ ์–ป์€ ์˜ค๋ฅ˜:

   babel-plugin-jest-hoist: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
    Invalid variable access: _debounce
    Whitelisted objects: Array, ArrayBuffer, Boolean, DataView, Date, Error, EvalError, Float32Array, Float64Array, Function, Generator, GeneratorFunction, Infinity, Int16Arra
y, Int32Array, Int8Array, InternalError, Intl, JSON, Map, Math, NaN, Number, Object, Promise, Proxy, RangeError, ReferenceError, Reflect, RegExp, Set, String, Symbol, SyntaxEr
ror, TypeError, URIError, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray, WeakMap, WeakSet, arguments, console, expect, isNaN, jest, parseFloat, parseInt, require, un
defined, DTRACE_NET_SERVER_CONNECTION, DTRACE_NET_STREAM_END, DTRACE_HTTP_SERVER_REQUEST, DTRACE_HTTP_SERVER_RESPONSE, DTRACE_HTTP_CLIENT_REQUEST, DTRACE_HTTP_CLIENT_RESPONSE,
 COUNTER_NET_SERVER_CONNECTION, COUNTER_NET_SERVER_CONNECTION_CLOSE, COUNTER_HTTP_SERVER_REQUEST, COUNTER_HTTP_SERVER_RESPONSE, COUNTER_HTTP_CLIENT_REQUEST, COUNTER_HTTP_CLIEN
T_RESPONSE, global, process, Buffer, clearImmediate, clearInterval, clearTimeout, setImmediate, setInterval, setTimeout.
    Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` (case inse
nsitive) are permitted.

์ฝ”๋“œ ์ž์ฒด:

const DEBOUNCE_DELAY = 10
const _debounce = jest.requireActual('lodash-es/debounce').default
jest.mock('lodash-es/debounce', () =>
  jest.fn((fn) => _debounce(fn, DEBOUNCE_DELAY))
)

๋งค์ง ๋„˜๋ฒ„์™€ ์ธ๋ผ์ธ ์ž„ํฌํŠธ๋กœ ๋‹ค์‹œ ์ž‘์„ฑํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

jest.mock('lodash-es/debounce', () =>
  jest.fn((fn) => jest.requireActual('lodash-es/debounce').default(fn, 10))
)

์ „์—ญ( 'ts-jest': { babelConfig: true } ) ์ฝ”๋“œ์—์„œ ํ•ด๋‹น ๊ตฌ์„ฑ ์—†์ด๋Š” ์ž˜ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ตฌ์„ฑ์— ํ•ด๋‹น ์ค„์ด ์—†์œผ๋ฉด tsx๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์—ˆ๊ณ  ํ•ด๋‹น ์˜ค๋ฅ˜์— ์ง๋ฉดํ–ˆ์Šต๋‹ˆ๋‹ค.

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     โ€ข To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     โ€ข If you need a custom transformation specify a "transform" option in your config.
     โ€ข If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    C:\Users\Alend\vue-project\src\my-component\MyComponent.spec.tsx:20
                            render: function () { return <div id="foo">Foo</div>; }
                                                         ^

package.json์˜ ์ผ๋ถ€ ๋ฒ„์ „:

"@babel/core": "^7.4.5",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "24.8.0",
"jest": "24.8.0",
"ts-jest": "24.0.2",

babel ๊ตฌ์„ฑ ์ž์ฒด:

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        modules: 'commonjs',
        targets: {
          browsers: ['> 1%', 'last 2 versions', 'not ie <= 11']
        }
      }
    ],
    '@vue/babel-preset-jsx'
  ],
  plugins: [
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-proposal-export-namespace-from',
    '@babel/plugin-proposal-function-sent',
    '@babel/plugin-proposal-json-strings',
    '@babel/plugin-proposal-numeric-separator',
    '@babel/plugin-proposal-throw-expressions',
    '@babel/plugin-syntax-dynamic-import',

    ['@babel/plugin-transform-runtime', { corejs: 2 }],
    ['@babel/plugin-proposal-decorators', { legacy: true }]
  ]
}

๊ทธ๋Ÿฌํ•œ ๋ฌธ์ œ๊ฐ€ ์—ฌ์ „ํžˆ ์กด์žฌํ•˜๋Š” ๊ฒƒ ๊ฐ™์œผ๋ฉฐ ์ด์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•๋„ ๋ฐ˜์‘ ์•ฑ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“œ๋Š” ๋ฐ ๋„์›€์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

`
ReferenceError: mockComponent๊ฐ€ ์ •์˜๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

  17 | const mockComponent = () => <div>Mock</div>;
  18 | 
> 19 | jest.mock('./components/Component', () => ({ Component: mockComponent }));

`

@khrysyn
Jest๋Š” jest.mock ํ˜ธ์ถœ์„ ๋ชจ๋“ˆ์˜ ๋งจ ์œ„๋กœ ์ž๋™์œผ๋กœ ํ˜ธ์ด์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์ด jest.mock์ด ์‹คํ–‰๋  ๋•Œ mockComponent const๊ฐ€ ์•„์ง ์ •์˜๋˜์ง€ ์•Š์€ ์ด์œ ์ž…๋‹ˆ๋‹ค.

์ด "๋ฌธ์ œ/๊ธฐ๋Šฅ"์„ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด 2๋‹จ๊ณ„๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

jest.mock('./components/Component', () => ({ Component: jest.fn() }));
import { Component } from "./components/Component";

Component.mockImplementation(() => <div>Mock</div>);

@khrysyn
Jest๋Š” jest.mock ํ˜ธ์ถœ์„ ๋ชจ๋“ˆ์˜ ๋งจ ์œ„๋กœ ์ž๋™์œผ๋กœ ํ˜ธ์ด์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์ด jest.mock์ด ์‹คํ–‰๋  ๋•Œ mockComponent const๊ฐ€ ์•„์ง ์ •์˜๋˜์ง€ ์•Š์€ ์ด์œ ์ž…๋‹ˆ๋‹ค.

์ด "๋ฌธ์ œ/๊ธฐ๋Šฅ"์„ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด 2๋‹จ๊ณ„๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

jest.mock('./components/Component', () => ({ Component: jest.fn() }));
import { Component } from "./components/Component";

Component.mockImplementation(() => <div>Mock</div>);

์ด๊ฒŒ ์ •๋ง ๋งž๋‚˜์š”? @nckblu๋Š” ์ด๋ฏธ ์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด 'mock'์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ณ€์ˆ˜๋Š” ์˜ˆ์™ธ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  'mockComponent'๋Š” ๊ทธ ์˜ˆ์™ธ์— ์†ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋งž์ฃ ?

๊ทธ ๋™์•ˆ, ๋””๋ฒ„๊ทธ ๋ฌธ(์˜ˆ: console.log('Checking...'))์„ ์ถ”๊ฐ€ํ•˜๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์›ํ•˜๋ฉด console.log ์•ž์— global์„ ๋ถ™์—ฌ์„œ ์ž‘๋™ํ•˜๋„๋ก ํ•˜์‹ญ์‹œ์˜ค.

global.console.log('global console working')

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰