I have to test a function that uses the fromEvent observable function. Before the upgrade to 'lettable' operators, I was just doing this:
spyOn(Observable, 'fromEvent').and.callFake(mockFromEventFunction)
But now, Rxjs have changed, and Observable.fromEvent is just a function named fromEvent, that is imported like this: (and used the same way)
import { fromEvent } from 'rxjs/observable/fromEvent';
My question is, how I can mock that function with Jasmine spy utilities without knowing it's parent context?
I advise that this doesn't work:
import * as FromEventContext from 'rxjs/observable/fromEvent';
...
spyOn(FromEventContext , 'fromEvent').and.callFake(mockFromEventFunction)
Now I have a workaround wrapping that fromEvent in one Object which I know the context. But I am wondering how I can solve this cleanly.
Thanks in advance.
After some investigation I discovered that the fact that we can or cannot mock this single exported functions is directly dependen in how our bundler resolves the modules when testing.
So for example, you may stumble to this error or similarly:
Error: : myFunctionName is not declared writable or has no setter
Caused because the bundler just wrapped those lonely exported functions into a getter property, making them impossible to mock.
The solution that I ended using is compile modules in 'commonjs'
when testing.
For example, if you are working with typescript, you would need to change change your tsconfig.spec.ts
to use commonjs module:
"compilerOptions": {
....
// force commonjs module output, since it let mock exported members on modules to anywhere in the application (even in the same file)
"module": "commonjs",
},
The resultant output of any exported member of a module in commonjs would be like: exports.myFunc = function() {}
. This led use spyOn without worries since it is wrapped on the 'exports' object. One great use case of that, is that it would be mocked anywhere, including the usages in its own file!
Example:
// some-module.js
export function functionToMock() {
return 'myFuncToMock';
}
export function functionToTest() {
return functionToMock();
}
// testing-module.spec.js
import * as SomeModule from ./some-module
spyOn(SomeModule, 'functionToMock').and.returnValue('mockedCorrectly');
SomeModule.functionToTest().toBe('mockedCorrectly')