开玩笑:如何重设手动模拟

时间:2019-01-07 07:19:55

标签: javascript unit-testing ecmascript-6 jestjs

我正在尝试在测试中检查console.log输出...

第一次测试没问题,但第二次却没有...我想这应该是模拟功能的问题..应该重置吗? 我尝试使用

jest.resetAllMocks()

但是会引发错误。

这是我的测试代码:

import Blog from '../../src/client/js/blog.js';
import mockAxios from "axios";

jest.mock('axios');

describe('client/blog', () => {

  beforeEach(() => {
    console.log = jest.fn();
  });

  afterEach(() => {
    mockAxios.delete.mockClear();
    console.log.mockClear();
  });

  it('set the DeletePostHandler', async function () {
    // WHEN
     ...
    jest.spyOn(window.location, 'assign').mockImplementation(url => console.log('resolved'))
    // WHEN
    await document.querySelector('#link_1').click();
    // THEN
    expect(mockAxios.delete).toHaveBeenCalledTimes(1);
    expect(console.log.mock.calls[0][0]).toBe('resolved')
  });


  it('does not set the DeletePostHandler', async function () {
    // WHEN
    ...
    jest.spyOn(window.location, 'assign').mockImplementation(url => console.log('rejected'))
    // WHEN
    await document.querySelector('#link_1').click();
    // THEN
    expect(mockAxios.delete).toHaveBeenCalledTimes(1);
    expect(console.log.mock.calls[0][0]).toBe('rejected')
  });

});

感谢您的反馈

更新1

当我不模拟控制台时,我可以检查正确的输出:

 PASS  tests/client/blog.spec.js
  client/blog
    ✓ set the DeletePostHandler (28ms)
    ✓ does not set the DeletePostHandler (4ms)

  console.log tests/client/blog.spec.js:26
    resolved

  console.log tests/client/blog.spec.js:43
    rejected

 PASS  tests/client/comment.spec.js
  client/comment
    ✓ test setup OK (2ms)

Test Suites: 2 passed, 2 total

更新2

按照@Yuri的评论中的建议,我放弃了console.log检查,然后我整理了规格并添加了一些console.log来检查输出,我仍然无法正确测试第二个测试...作为window.location .assign模拟无法在第二次测试中正确重置。...

/tests/client/blog.spec.js

import Blog from '../../src/client/js/blog.js';
import mockAxios from "axios";

jest.mock('axios');

describe('client/blog', () => {

  beforeAll(() => {
    jest.spyOn(window.location, 'assign').mockImplementation(() => {});
  });

  afterEach(() => {
    mockAxios.delete.mockClear();
  });

  afterAll(() => {
    // clean up after all tests
    window.location.assign.mockRestore()
  });

  it('set the DeletePostHandler', async function () {
    // WHEN
    const post = '<div class="posts"><div class="post">' +
      '<p>Today should be a great day to be alive!</p>' +
      '<div class="is-hidden">' +
      '<a id="link_1" class="delete-post" href="/admin/edit-post/1" data-post-id="1">delete<i class="is-hidden"></i></a>' +
      '</div></div>';
    document.body.innerHTML = post;
    Blog.pageReady('admin-index');
    // WHEN
    await document.querySelector('#link_1').click();
    // THEN
    expect(mockAxios.delete).toHaveBeenCalledTimes(1);
    expect(window.location.assign).toBeCalledWith('/admin?cache=false');
  });

  it('does not set the DeletePostHandler', async function () {
    // WHEN
    const post = '<div class="posts"><div class="post">' +
      '<p>Today should be a great day to be alive!</p>' +
      '<div class="is-hidden">' +
      '<a id="link_1" class="delete-post" href="/admin/edit-post/" data-post-id="">delete<i class="is-hidden"></i></a>' +
      '</div></div>';
    document.body.innerHTML = post;
    Blog.pageReady('admin-index');
    // WHEN
    await document.querySelector('#link_1').click();
    // THEN
    expect(mockAxios.delete).toHaveBeenCalledTimes(1);
    expect(window.location.assign).toBeCalledWith('/admin?cache=true');
  });

模仿 /axios.j s

export default {
  delete: jest.fn((url) => {
    if (url === '/api/v1/blog/1') {
        return Promise.resolve({
          data: {},
          status: 200,
          statusText: 'OK',
          headers: {}
        });
    } else {
      return Promise.reject({
        data: {},
        status: 400,
        statusText: 'Error',
        headers: {}
      });
    }
  })
};

/client/blog.js

  const deletePost = id => {
    axios.delete(`${API_BASE}/blog/${id}`, {
        headers: { 'Content-type': 'application/json' },
        data: null, // data null is necessary to pass the headers
      })
      .then((result) => {
        console.log('AXIOS RESOLVED: ', result);
        console.log('GOING TO CALL window.location.assign with /admin?cache=false');
        window.location.assign('/admin?cache=false');
      })
      .catch((e) => {
        console.log('AXIOS REJECTED: ', e);
        console.log('GOING TO CALL window.location.assign with /admin?cache=true');
        window.location.assign('/admin?cache=true');
      });
    };

控制台

console.log src/client/js/blog.js:12
    AXIOS RESOLVED:  { data: {}, status: 200, statusText: 'OK', headers: {} }

  console.log src/client/js/blog.js:13
    GOING TO CALL window.location.assign with /admin?cache=false

  console.log src/client/js/blog.js:17
    AXIOS REJECTED:  { data: {}, status: 400, statusText: 'Error', headers: {} }

  console.log src/client/js/blog.js:18
    GOING TO CALL window.location.assign with /admin?cache=true

 PASS  tests/client/comment.spec.js



● client/blog › does not set the DeletePostHandler

    expect(jest.fn()).toBeCalledWith(expected)

    Expected mock function to have been called with:
      "/admin?cache=true"
    as argument 1, but it was called with
      "/admin?cache=false".

      50 |     // THEN
      51 |     expect(mockAxios.delete).toHaveBeenCalledTimes(1);
    > 52 |     expect(window.location.assign).toBeCalledWith('/admin?cache=true');
         |                                    ^
      53 |   });
      54 |
      55 | });

      at Object.toBeCalledWith (tests/client/blog.spec.js:52:36)
      at tryCatch (node_modules/regenerator-runtime/runtime.js:62:40)
      at Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:296:22)
      at Generator.prototype.(anonymous function) [as next] (node_modules/regenerator-runtime/runtime.js:114:21)
      at step (tests/client/blog.spec.js:22:191)
      at tests/client/blog.spec.js:22:361

1 个答案:

答案 0 :(得分:0)

您最好检查要调用的模拟程序,而不是检查伪造的window.location.assign实现。

  beforeAll(() => {
    jest.spyOn(window.location, 'assign').mockImplementation(() => {}) // noop
  })

  afterAll(() => {
    // clean up after all tests
    window.location.assign.mockRestore()
  })

  it('set the DeletePostHandler', async function () {
    // WHEN
    await document.querySelector('#link_1').click();
    // THEN
    expect(mockAxios.delete).toHaveBeenCalledTimes(1);
    expect(window.location.assign).toBeCalled()
    // or better
    expect(window.location.assign).toBeCalledWith(expectedURL) 
  });