Skip to content

Disable @typescript-eslint/unbound-method rule in Jest tests#391

Merged
Mrtenz merged 5 commits intomainfrom
mrtenz/disable-@typescript-eslint/unbound-method-in-tests
Aug 7, 2025
Merged

Disable @typescript-eslint/unbound-method rule in Jest tests#391
Mrtenz merged 5 commits intomainfrom
mrtenz/disable-@typescript-eslint/unbound-method-in-tests

Conversation

@Mrtenz
Copy link
Copy Markdown
Member

@Mrtenz Mrtenz commented Feb 19, 2025

This disables the @typescript-eslint/unbound-method rule in tests, which is too strict in cases, for example when asserting that a function has been called:

const someObject = {
  foo: function() {
    // ...
  }
};

// Assuming this is mocked somewhere.
expect(someObject.foo).toHaveBeenCalled();

@Mrtenz Mrtenz marked this pull request as ready for review February 19, 2025 13:12
@Mrtenz Mrtenz requested review from a team as code owners February 19, 2025 13:12
@Gudahtt
Copy link
Copy Markdown
Member

Gudahtt commented Feb 19, 2025

Hmm. A lot of JavaScript developers don't have a great understanding of binding. This rule prevents a common footgun.

The case you mentioned is indeed inconvenient to deal with, but I have discovered that there is a separate rule just for this case: https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/unbound-method.md

We could consider using that instead for tests, so that the scenario you described here isn't flagged as a problem.

@Mrtenz
Copy link
Copy Markdown
Member Author

Mrtenz commented Feb 19, 2025

Hmm. A lot of JavaScript developers don't have a great understanding of binding. This rule prevents a common footgun.

The case you mentioned is indeed inconvenient to deal with, but I have discovered that there is a separate rule just for this case: https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/unbound-method.md

We could consider using that instead for tests, so that the scenario you described here isn't flagged as a problem.

I wasn't aware of this rule. Makes sense to use this instead!

@Mrtenz Mrtenz force-pushed the mrtenz/disable-@typescript-eslint/unbound-method-in-tests branch from 925fa87 to ac81874 Compare March 2, 2025 13:52
languageOptions: {
globals: {
...globals.jest,
languageOptions: {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes are just indentation, I haven't changed any actual rules here. The only real changes in this file are on the bottom.


rules: {
'@typescript-eslint/unbound-method': 'off',
'jest/unbound-method': 'error',
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rule requires type information, so we can't enable it in the general config, which may be used for JavaScript files.

extends: [vitest.configs.recommended],

rules: {
'@typescript-eslint/unbound-method': 'off',
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vitest doesn't have an equivalent rule, so I think we can just disable the rule here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. If we're moving everything to Vitest then doesn't it seem like we would still be ignoring a possible footgun?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently a solution is in the works: vitest-dev/eslint-plugin-vitest#591

Not ideal, but, I'm OK with disabling this in the interim personally.

@mcmire
Copy link
Copy Markdown
Contributor

mcmire commented Mar 21, 2025

@Mrtenz In the example you posted in the PR description:

const someObject = {
  foo: function() {
    // ...
  }
};

// Assuming this is mocked somewhere.
expect(someObject.foo).toHaveBeenCalled();

could the lint violation be avoided by using the following?

const someObject = {
  foo: function() {
    // ...
  }
};

const fooSpy = jest.spyOn(someObject, 'foo');
// or: const fooSpy = vi.spyOn(someObject, 'foo');

expect(fooSpy).toHaveBeenCalled();

If so, are there are other examples where this lint rule would be inconvenient?

Copy link
Copy Markdown
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good! Seeing some test errors though

@Gudahtt
Copy link
Copy Markdown
Member

Gudahtt commented Apr 17, 2025

@mcmire I think you're right, that pattern would avoid this lint violation.

We could document that workaround instead 🤔. But I don't know, it still seems better to allow referencing a function unbound for assertions, as it's a bit shorter and maybe easier to read. The risks of passing an unbound method don't apply in that case anyway.

Thoughts on this workaround v.s. disabling the rule in the case of vitest, where we don't have a more specific rule for this yet?

console.log('Hello, world!');
import { describe, expect, it } from 'vitest';

describe('dummy test file', () => {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not actually run, but needed because otherwise ESLint will fail because there's no tests.

@Mrtenz
Copy link
Copy Markdown
Member Author

Mrtenz commented Apr 17, 2025

Thoughts on this workaround v.s. disabling the rule in the case of vitest, where we don't have a more specific rule for this yet?

@Gudahtt Thinking about it, maybe it's better we don't disable it for the Vitest config, since enabling the Vitest-specific rule in the future would be a breaking change, whereas just replacing the TypeScript with the Vitest rule when it's available would not (I think)?

@Gudahtt
Copy link
Copy Markdown
Member

Gudahtt commented Apr 17, 2025

Yes I think you're right, it would be a breaking change if we disabled it now and enabled the vitest rule later.

But replacing the base rule with the Jest rule just loosens the check, so it's non-breaking.

@Mrtenz Mrtenz changed the title Disable @typescript-eslint/unbound-method rule in tests Disable @typescript-eslint/unbound-method rule in Jest tests Aug 7, 2025
@Mrtenz Mrtenz requested a review from Gudahtt August 7, 2025 12:36
cursor[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@Gudahtt Gudahtt force-pushed the mrtenz/disable-@typescript-eslint/unbound-method-in-tests branch from f36f1f6 to 0209632 Compare August 7, 2025 13:02
@Mrtenz Mrtenz merged commit c832feb into main Aug 7, 2025
26 checks passed
@Mrtenz Mrtenz deleted the mrtenz/disable-@typescript-eslint/unbound-method-in-tests branch August 7, 2025 13:12
@Gudahtt Gudahtt mentioned this pull request Nov 7, 2025
Gudahtt added a commit that referenced this pull request Nov 10, 2025
Gudahtt added a commit that referenced this pull request Nov 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants