question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`mock<X>Once` methods seem to be first-in first-out (unlike `mock<X>` methods)

See original GitHub issue

🐛 Bug Report

This could be a result of me misusing mocks in a manner that shouldn’t be done, but basically the order that mock<X>Once calls resolve in seems to be first-in, first-out.

This to me doesn’t make sense, as I’d expect them to to be first-in, last-out, as that would match the order that they’re registered in code, so that “deeper” mock implementations would override “shallower” ones (which is the behaviour of the mock<X> methods).

This is particularly nasty as it means if you have a test that fails before a mock<X>Once call would happen, it can cause a cascade of test failures, due to off-by-1 error.

To Reproduce

Steps to reproduce the behavior:

describe('mockOnce', () => {
  const mockFn = jest.fn();

  beforeEach(() => jest.clearAllMocks());

  describe('strings', () => {
    beforeEach(() => {
      console.log('strings > beforeEach');
      mockFn.mockReturnValueOnce('a');
    });

    it('is a function', () => {
      console.log('strings > it > is a function');
      expect(typeof mockFn).toBe('function');
    });
    it('returns a string', () => {
      console.log('strings > it > returns a string');
      expect(typeof mockFn()).toBe('string');
    });
  });
  describe('numbers', () => {
    beforeEach(() => {
      console.log('numbers > beforeEach');
      mockFn.mockReturnValueOnce(1);
    });

    it('is a function', () => {
      console.log('numbers > it > is a function');
      expect(typeof mockFn).toBe('function');
    });
    it('returns a number', () => {
      console.log('numbers > it > returns a number');
      expect(typeof mockFn()).toBe('number');
    });
  });
});

Outputs:

 FAIL  ./add-test.js
  mockOnce
    strings
      ✓ is a function (11ms)
      ✓ returns a string (2ms)
    numbers
      ✓ is a function (1ms)
      ✕ returns a number (60ms)

  ● mockOnce › numbers › returns a number

    expect(received).toBe(expected) // Object.is equality

    Expected value to be:
      "number"
    Received:
      "string"

      31 |     it('returns a number', () => {
      32 |       console.log('numbers > it > returns a number');
    > 33 |       expect(typeof mockFn()).toBe('number');
      34 |     });
      35 |   });
      36 | });

      at Object.it (add-test.js:33:31)

  console.log add-test.js:8
    strings > beforeEach

  console.log add-test.js:13
    strings > it > is a function

  console.log add-test.js:8
    strings > beforeEach

  console.log add-test.js:17
    strings > it > returns a string

  console.log add-test.js:23
    numbers > beforeEach

  console.log add-test.js:28
    numbers > it > is a function

  console.log add-test.js:23
    numbers > beforeEach

  console.log add-test.js:32
    numbers > it > returns a number

Test Suites: 1 failed, 1 total
Tests:       1 failed, 3 passed, 4 total
Snapshots:   0 total
Time:        1.119s
Ran all test suites.

Expected behavior

All the tests pass, as they would if you use mockReturn instead of mockReturnOnce.

Link to repl or repo (highly encouraged)

repl.

Run npx envinfo --preset jest

Paste the results here:

  System:
    OS: Windows 10
    CPU: (8) x64 Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
  Binaries:
    Node: 10.15.3 - C:\nodejs\node.EXE
    Yarn: 1.13.0 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 6.9.0 - ~\AppData\Roaming\npm\npm.CMD

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
G-Rathcommented, Apr 22, 2019

If another Once call discards the last Once call, you can’t do

But I’m not saying they should be discarded 😕

I just tested your code, and that works (of course) - I swear in the past I was having the opposite behaviour, which lead me to initially conclude that your code would have the opposite result: since mockReturnValue was called last, it’d be called first.

Now that I think about it, what I encountered when I first started using jest must has been that mockReturnValue has a higher precedence than mockImplementation.

~> All Once mocks and also all non-Once mocks~

~I’m guessing jest doesn’t want to expand their api to support this as a feature? (i.e clearAllMockOnces)~

~Ideally I’m trying to save having to call mockImplementation in a top-level beforeEach, and then have to keep in mind whenever I call a~

The whole thing would just be too big of a breaking change for jest. I’ll just have to adjust my thinking and be extra careful with my mocks.

Thanks for taking the time to clarify this all for me 😄

0reactions
jeysalcommented, Apr 21, 2019

Could you explain that one further for me?

If another Once call discards the last Once call, you can’t do

fn.mockReturnValueOnce(1).mockReturnValueOnce(2).mockReturnValue(3)

anymore (except by implementing it yourself in user code).

Does resetAllMocks remove all Once mocks? I was under the impression it didn’t?

All Once mocks and also all non-Once mocks

Read more comments on GitHub >

github_iconTop Results From Across the Web

Can I mock another method in then statement of first method?
wasNull to return once false in first case and true in another one. Here is how I run scenario val rs: WrappedResultSet =...
Read more >
Stubbing and Mocking with Mockito and JUnit - Semaphore CI
Learn how to create true unit tests by mocking all external dependencies in your JUnit classes with the help of Mockito.
Read more >
unittest.mock — mock object library — Python 3.11.1 ...
After performing an action, you can make assertions about which methods / attributes were used and arguments they were called with. You can...
Read more >
Mocking different values for the same module using Jest
Learn how to use Jest mocking utilities to setup tests with different mock ... function return "GL" in the first invocation, and "EN"...
Read more >
Creating Mock Classes
Note that the mock class doesn't define AppendPacket() , unlike the real class. ... When a mock method is called, the last matching...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found