oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
73.45k stars 2.71k forks source link

Bun mocks to be scoped to test file #12823

Open cybercoder-naj opened 2 months ago

cybercoder-naj commented 2 months ago

What version of Bun is running?

1.1.18+5a0b93523

What platform is your computer?

Linux 6.6.32-1-lts x86_64 unknown

What steps can reproduce the bug?

  1. Create two test files.
  2. In one of the files, mock a module.
  3. Do not mock this module in the second test file.
  4. Run the tests on both files individually by test pattern filtering.
  5. Run all the tests together.

For example:

// group1.test.ts
import { expect, test, mock } from 'bun:test';
import app from 'server';

mock.module("./myModule", () => {
  importantFn() {
    return "Hello"
  }
});

test('something', () => {
  const res = await app.request("...");
  expect(res.status).toBe(200);
})

// group2.test.ts
import { expect, test } from 'bun:test';
import app from 'server';

test('another route', () => {
  const res = await app.request("...");
  expect(res.status).toBe(404);
})

What is the expected behavior?

I expect that the mocked modules should be scoped to the file it is in and not spill over to other files. If group1.test.ts has a mock.module in that file, it should only mock the module for those tests in that file only.

What do you see instead?

mock.module also mocks the functions in other test files where I don't want them to be mocked.

Additional information

I just checked my code again... This is the case even when the function is defined inside the test block. For Example:

// group1.test.ts
import { expect, test, mock } from 'bun:test';
import app from 'server';

test('something', () => {

  mock.module("./myModule", () => {
    importantFn() {
      return "Hello"
    }
  });

  const res = await app.request("...");
  expect(res.status).toBe(200);
})

In the above case as well, the mocked module affects other test cases. This violates unit testing in isolation.

aryzing commented 3 weeks ago

Just bumped into this as well. Bun's test runner is so much better than anything else out there, but the current module mocking behavior is hard to work with. Even "mid-test" module mocks affect the module in other tests/test files.

// file1.test.ts ------------------
import { test, expect, mock } from "bun:test";
import { foo } from "./my-module";

test("Test (2)", () => {
  expect(foo()).toBe("foo"); // OK

  mock.module("./my-module", () => ({
    foo: mock(() => "bar"),
  }));

  expect(foo()).toBe("bar"); // OK
});

test("Test (3)", () => {
  expect(foo()).toBe("foo"); // FAILS - mock carried from above test
});

// file2.test.ts -----------------------
import { test, expect } from "bun:test";
import { foo } from "./my-module";

test("Test (1)", () => {
  expect(foo()).toBe("foo"); // FAILS - the mock from the other file is carried over into this file too
});

For organizational purposes, if the behavior is changed, any ideas on when that would be? @Jarred-Sumner