Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.1.0 breaks instanceOf tests #32

Closed
Jason3S opened this issue Feb 7, 2023 · 8 comments · Fixed by #33
Closed

1.1.0 breaks instanceOf tests #32

Jason3S opened this issue Feb 7, 2023 · 8 comments · Fixed by #33

Comments

@Jason3S
Copy link

Jason3S commented Feb 7, 2023

I'm not sure if this was intended, but #31, breaks instanceof class.

import { afterEach, describe, expect, test, vi } from 'vitest';

import { MyClass } from './MyClass';

vi.mock('./MyClass');

const mockedMyClass = vi.mocked(MyClass);

describe('MyClass', () => {
    afterEach(() => {
        mockedMyClass.mockClear();
    });

    test.each`
        name          | expected
        ${'Atlantic'} | ${'Atlantic'}
        ${'Pacific'}  | ${'Pacific'}
    `('new MyClass $name', ({ name, expected }) => {
        const instance = new MyClass(name);
        expect(instance).toBeInstanceOf(MyClass);  // Was working in 1.0.2
        expect(mockedMyClass).toHaveBeenCalledTimes(1);
        expect(mockedMyClass).toHaveBeenCalledWith(expected);
    });
});

It is a bit of a contrived example. But I'm not sure how to preserve the inheritance chain.

Repo: https://github.com/Jason3S/tinyspy-issue-32
StackBlitz: https://stackblitz.com/edit/vitest-dev-vitest-dhhorq?file=README.md

@sheremet-va
Copy link
Member

Doesn't seem to be intentional, @trivikr what do you think?

@trivikr
Copy link

trivikr commented Feb 7, 2023

The error in this case was:

AssertionError: expected <Anonymous Class>{} to be an instance of MyClass

I played around with Function.prototype.bind, but the error persists
https://stackoverflow.com/a/8843181

@trivikr
Copy link

trivikr commented Feb 7, 2023

The following solution fixes instance of checks:

        result = new.target
          ? new (fn.impl as any)(...args)
          : fn.impl.apply(this, args)
        if (new.target) Object.setPrototypeOf(r, this);

@sheremet-va Would you like to attempt trying it out?

@sheremet-va
Copy link
Member

Would you like to attempt trying it out?

What are the performance implications of this?

@trivikr
Copy link

trivikr commented Feb 7, 2023

What are the performance implications of this?

I think we should follow Make it work, Make it right, Make it fast.

In this case, the Make it work/right is not true as per #29

@sheremet-va
Copy link
Member

In this case, the Make it work/right is not true as per #29

Only if it is really a bug. These revelations are leading me to believe that this is intended behavior. It is consistent with sinon and jest behaviors at least:

import { stub } from "sinon";
import { ModuleMocker } from "jest-mock";

const obj = {
  className: class Foo {},
};

stub(obj, "className").callsFake(function () {
  console.log(new.target);
});

obj.className(); // undefined
new obj.className(); // undefined

const mocker = new ModuleMocker(global);

mocker.spyOn(obj, "className").mockImplementation(function () {
  console.log(new.target);
});

obj.className(); // undefined
new obj.className(); // undefined

@Jason3S
Copy link
Author

Jason3S commented Feb 7, 2023

@sheremet-va and @trivikr,

Thank you for the quick response and turn around.

@trivikr
Copy link

trivikr commented Feb 7, 2023

Added a summary in #29 (comment) for future discussion about new.target

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 a pull request may close this issue.

3 participants