return FALSE; $r = well_tag_thread__update(array('id' => $id), $update); return $r; } function well_tag_thread_find($tagid, $page, $pagesize) { $arr = well_tag_thread__find(array('tagid' => $tagid), array('id' => -1), $page, $pagesize); return $arr; } function well_tag_thread_find_by_tid($tid, $page, $pagesize) { $arr = well_tag_thread__find(array('tid' => $tid), array(), $page, $pagesize); return $arr; } ?>javascript - How would I test this promise based code with jest? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How would I test this promise based code with jest? - Stack Overflow

programmeradmin2浏览0评论

How would I test this code in jest? I'd like to make sure that the error and success of the passed promise is being called as needed. I'm sure it's something sorta simple, but it's driving me crazy. Thanks very much.

handleStatusChangeRequest (changeEntryStatus) {
  return changeEntryStatus().then(() => {
    this.handleStatusChangeSuccess()
  }).catch(err => {
    this.handleErrorDisplay(err)
  })
}

How would I test this code in jest? I'd like to make sure that the error and success of the passed promise is being called as needed. I'm sure it's something sorta simple, but it's driving me crazy. Thanks very much.

handleStatusChangeRequest (changeEntryStatus) {
  return changeEntryStatus().then(() => {
    this.handleStatusChangeSuccess()
  }).catch(err => {
    this.handleErrorDisplay(err)
  })
}
Share Improve this question edited Nov 2, 2018 at 13:19 skyboyer 23.8k7 gold badges62 silver badges71 bronze badges asked Oct 6, 2018 at 1:50 Cameron StrandbergCameron Strandberg 1342 silver badges11 bronze badges 2
  • What do you have in mind for assertions? Snapshots, mocking and verifying method calls, ...? – stealththeninja Commented Oct 6, 2018 at 2:01
  • It's just the full jest test suite . . . not bringing in mocha or anything like that. Just within the react-create-app (sp?) tool chain. – Cameron Strandberg Commented Oct 6, 2018 at 2:16
Add a ment  | 

4 Answers 4

Reset to default 2

If your code uses promises, there is a nice way to handle asynchronous tests. Just return a promise from your test, and Jest will wait for that promise to resolve.
If the promise is rejected, the test will automatically fail.

For example, let's say that changeData, instead of using a callback, returns a promise that is supposed to resolve to the string "status has been successfully modified".

Be sure to return the promise - if you omit this return statement, your test will plete before your changeData() -[async function] pletes.

Here's a convenient and easy to follow pattern

test('if the data is changed', () => {
  return changeData().then((data) => {
    expect(data).toBe('status has been successfully modified');
  });
})

Happy testing :)

This could be refactored, but for the sake of demonstration, I left the repeating bits in.

In example.spec.js, the callback, changeEntryStatus, is stubbed to return a promise. In order to check if other instance methods (this.method) were called, they are first mocked, then assertions are called on the mock after running the method being tested. Learn more in the Jest docs. (See my thoughts on mocking methods of the unit being tested at the bottom.)

Run the example on repl.it.

example.js:

class Example {
  handleStatusChangeRequest(changeEntryStatus) {
    return changeEntryStatus().then(() => {
      this.handleStatusChangeSuccess()
    }).catch(err => {
      this.handleErrorDisplay(err)
    })
  }

  handleStatusChangeSuccess() {
    console.log('stubbed handleStatusChangeSuccess')
  }

  handleErrorDisplay(error) {
    console.log('stubbed handleErrorDisplay:', error)
  }
}

module.exports = Example;

example.spec.js:

const Example = require('./entryStatus')
describe('handleStatusChangeRequest', () => {
  it('should run the changeEntryStatus callback', () => {
    const {handleStatusChangeRequest} = new Example()
    const stub = jest.fn().mockResolvedValue()

    handleStatusChangeRequest(stub)

    // must return because handleStatusChangeRequest is asynchronous
    return expect(stub).toHaveBeenCalled()
  });

  it('should call example.handleStatusChangeSuccess', async () => {
    const example = new Example()
    const stub = jest.fn().mockResolvedValue()
    example.handleStatusChangeSuccess = jest.fn()

    await example.handleStatusChangeRequest(stub)

    expect(example.handleStatusChangeSuccess).toHaveBeenCalled();
  })

  it('should call example.handleErrorDisplay', async () => {
    const example = new Example()
    const fakeError = { code: 'fake_error_code' }
    const stub = jest.fn().mockRejectedValue(fakeError)
    example.handleErrorDisplay = jest.fn()


    await example.handleStatusChangeRequest(stub)

    expect(example.handleErrorDisplay).toHaveBeenCalled()
    expect(example.handleErrorDisplay).toHaveBeenCalledWith(fakeError)
  });
});

Opinionated Disclaimer: Mocking methods of the unit under test is a smell. Consider checking for the expected effects of calling handleStatusChangeSuccess and handleErrorDisplay instead of checking to see if they were called. Then don't even expose those methods publicly unless consumers of the class need access.

Opinionated Disclaimer: Mocking methods of the unit under test is a smell. Consider checking for the expected effects of calling handleStatusChangeSuccess and handleErrorDisplay instead of checking to see if they were called. Then don't even expose those methods publicly unless consumers of the class need access.

I wholeheartedly agree with webprojohn's disclaimer. Mocks are a smell as tests should assert the behavior of the code, not its implementation. Testing the latter makes the code brittle to change.

Stepping off my soapbox... :) We're looking for a way to test an asynchronous method. I'm not sure what assertions your tests should make to verify the behavior inside handleStatusChangeSuccess() and handleErrorDisplay(err) so the example below leaves a ment where those assertions would go. The following uses Promise.resolve() and Promise.reject() to trigger the outes to test. I've used async/await, Jest has other async examples in their docs.

const Example = require('./example')

describe('handleStatusChangeRequest', () => {
  it('should resolve successfully', async () => {
    const {handleStatusChangeRequest} = new Example();
    const resolvePromise = () => Promise.resolve();

    await handleStatusChangeRequest(resolvePromise);

    // resolution assertions here
  });

  it('should resolve errors', async () => {
    const {handleStatusChangeRequest} = new Example();
    const fakeError = new Error('eep');
    const rejectPromise = () => Promise.reject(fakeError);

    // if your method doesn't throw, we can remove this try/catch
    // block and the fail() polyfill
    try {
      await example.handleStatusChangeRequest(rejectPromise);

      // if we don't throw our test shouldn't get here, so we
      // polyfill a fail() method since Jest doesn't give us one.
      // See https://github./facebook/jest/issues/2129
      expect(true).toBe(false);
    }
    catch (e) {
      // rejection assertions here
    }
  });
});

The answer I have looks so:

Success tests

const instance = el.find(EntryToolBar).instance()
const spy = jest.spyOn(instance, 'handleStatusChangeSuccess')

await instance.handleStatusChangeRequest(() => Promise.resolve('cool man'))

expect(spy).toHaveBeenCalledTimes(1)

Error tests

const instance = el.find(EntryToolBar).instance()
const spy = jest.spyOn(instance, 'handleErrorDisplay')

await instance.handleStatusChangeRequest(() => Promise.reject(Error('shit')))
expect(spy).toHaveBeenCalledTimes(1)

As I stated above, the handleStatusChangeSuccess and handleError methods are test else where with some snapshots (they just set state and render out some different jsx). I feel pretty good about this. I'm using spys/mocks, but I'm testing the implementation functions elsewhere. Sufficient?

发布评论

评论列表(0)

  1. 暂无评论