hirezio / auto-spies

Create automatic spies from classes
MIT License
179 stars 30 forks source link

accessorSpies in jest-auto-spies + nx workspace not mocking return value #42

Open GuilleEneas opened 3 years ago

GuilleEneas commented 3 years ago

Describe the bug When creating a service with a getter and trying to mock it in a test the returned value is undefined.

To Reproduce Steps to reproduce the behavior:

  1. npx create-nx-workspace
  2. cd to your project
  3. nx g s --name=one --project=app --skipTests
  4. then check the changes in this commit
  5. ng test --watch

and boom

 FAIL  apps/app/src/app/app.component.spec.ts
  ● AppComponent › whatever

    expect(received).toStrictEqual(expected) // deep equality

    Expected: {"fake": "value"}
    Received: undefined

      32 |     const value = componentUnderTest.getGetter();
      33 |
    > 34 |     expect(value).toStrictEqual({
         |                   ^
      35 |       fake: 'value'
      36 |     });
      37 |   });

      at src/app/app.component.spec.ts:34:19
      at ZoneDelegate.Object.<anonymous>.ZoneDelegate.invoke (../../node_modules/zone.js/dist/zone.js:386:30)
      at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (../../node_modules/zone.js/dist/proxy.js:117:43)
      at ZoneDelegate.Object.<anonymous>.ZoneDelegate.invoke (../../node_modules/zone.js/dist/zone.js:385:36)
      at Zone.Object.<anonymous>.Zone.run (../../node_modules/zone.js/dist/zone.js:143:47)

Test Suites: 1 failed, 1 passed, 2 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        3.522s

Expected behavior the test should pass

Desktop (please complete the following information):

You can also clone this repo where the issue occurs https://github.com/GuilleEneas/jest-auto-spies-issue

GuilleEneas commented 3 years ago

I checked a bit and the returned object from provideAutoSpy method contains the getter, while after calling TestBed.inject the returned object has the getters striped out.

shairez commented 3 years ago

Thanks @GuilleEneas !

Sometimes Jest has weird issues with it's caching, did you try cleaning it's cache and run it again?

GuilleEneas commented 3 years ago

Hi @shairez !

Yes, I did. As I mention before, the method provideAutoSpy seems to work as expected, is the interaction with the test bed injector the one that seems to remove the getters and setters, but keeps the accessorSpies.

shairez commented 3 years ago

Really weird issue, without debugging I was able to simulate the issue

But when debugging it step by step... I was able to pass the test and see the getters on OneService

WTF 😀

image

shairez commented 3 years ago

It might have something to do with the fact that I made a small change to AppComponent (added a method and then removed it).

So I suspect it's an issue with the nx cache or something alike...

GuilleEneas commented 3 years ago

this is weird, as when I was debugging step by step the injector returned an object without getters. do you suggest it is a nx bug instead?

shairez commented 3 years ago

Yeah, the first time I debugged it I saw the issue... but then I changed the file a bit... reverted it (but because it was "changed" the timestamp was different I guess) and then I couldn't reproduce anymore.

Try that and let me know if that's the case for you as well

if so, it might be the nx cache

GuilleEneas commented 3 years ago

I can't make the test pass, even following your steps. I'll try to create this issue with the nx workspace alone to see if this can be an nx issue... do you know if they fix this issues when people submit them. I'll keep you posted 🤓

shairez commented 3 years ago

Hmm... this is a tricky one.. I guess you'll need to simulate the caching issue in a reproducible way in order for them to fix it

GuilleEneas commented 3 years ago

I made some more research, the problem is the Object.defineProperty method, somehow that property got stripped out after being inserted and retrieved from the testbed. I created this repos which reproduces the error https://github.com/GuilleEneas/nx-angular-testing-issue . Could you check it (when having time)?... and please let me know if you think is worth reporting (and if they would be interested in fixing it, in your opinion, ofc)

shairez commented 3 years ago

Wow... good job finding it!

I'll take a look at it next week and report back

Thanks!

peterreisz commented 3 years ago

I've also faced with this issue, but in a non-nx project, so I think this issue is not related to nx.

mtpultz commented 2 years ago

I having this issue in an Nx project. I've tried nx test --clearCache in case that helps, but when I spy on a simple service like:

@Injectable({
  providedIn: 'root',
})
export class PartyService {
  private _partyId!: number;

  public set partyId(partyId: number) {
      this._partyId = partyId;
  }

  public get partyId(): number {
    return this._partyId;
  }
}

The value is always undefined:

describe('CollegeLicenceInformationPage', () => {
  let component: CollegeLicenceInformationPage;
  let partyServiceSpy: Spy<PartyService>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule,
        ReactiveFormsModule,
        RouterTestingModule,
      ],
      providers: [
        CollegeLicenceInformationPage,
        {
          provide: PartyService,
          useValue: createSpyFromClass(PartyService, {
            gettersToSpyOn: ['partyId'],
            settersToSpyOn: ['partyId'],
          }),
        },
      ],
    });

    component = TestBed.inject(CollegeLicenceInformationPage);
    partyServiceSpy = TestBed.inject<any>(PartyService);
  });

  describe('INIT', () => {
    given('partyId exists', () => {
      const partyId = randNumber({ min: 1 });
      partyServiceSpy.accessorSpies.setters.partyId.mockReturnValue(partyId);

      when('initializing the page', () => {
        component.ngOnInit();

        then(
          'resource should get the college licence information of the party',
          () => {
            expect(partyServiceSpy.partyId).toBe(partyId); // <--- Always undefined
          }
        );
      });
    });
  });
});
shairez commented 2 years ago

@GuilleEneas I cannot reproduce the problem from the second run of the tests (only on the first one it fails) Tried to clear both jest and nx cache but no luck

@peterreisz did it continue to happen?

@mtpultz can you reproduce it consistently and can upload a mini-repo that can show that?

Thanks!

GuilleEneas commented 2 years ago

@shairez I need to check, this was long ago, I might remember that this wasn't happening when updating nx. I'll check in the following days. just to be clear did you check this repo https://github.com/GuilleEneas/nx-angular-testing-issue?

shairez commented 2 years ago

@GuilleEneas yep

Btw with a brand new nx I couldn't reproduce

mtpultz commented 2 years ago

@shairez I created a new install of Nx, and was able to quickly reproduce it using a barebones Angular application- https://github.com/mtpultz/jest-auto-spies-error. When you run nx test you see a similar error to the one posted above.

UPDATE: Sorry @shairez looks like I had a typo and was using setters in my statement bonnieServiceSpy.accessorSpies.setters.bonnieId.mockReturnValue(bonnieId); instead of getters bonnieServiceSpy.accessorSpies.getters.bonnieId.mockReturnValue(bonnieId); when using mockReturnValue(...) :(