auto-spies
auto-spies copied to clipboard
accessorSpies in jest-auto-spies + nx workspace not mocking return value
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:
- npx create-nx-workspace
- cd to your project
- nx g s --name=one --project=app --skipTests
- then check the changes in this commit
- 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):
- OS: Mac OSX
- Browser chrome
- Version 88.0.4324.146
You can also clone this repo where the issue occurs https://github.com/GuilleEneas/jest-auto-spies-issue
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.
Thanks @GuilleEneas !
Sometimes Jest has weird issues with it's caching, did you try cleaning it's cache and run it again?
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
.
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 😀
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...
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?
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
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 🤓
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
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)
Wow... good job finding it!
I'll take a look at it next week and report back
Thanks!
I've also faced with this issue, but in a non-nx project, so I think this issue is not related to nx.
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
}
);
});
});
});
});
@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!
@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?
@GuilleEneas yep
Btw with a brand new nx I couldn't reproduce
@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(...)
:(