How do I marble-test an observable of void values? - unit-testing

Using RXJS's TestScheduler, is there a nice way to marble-test an event-like observable that emits undefined values?
I am using TypeScript, so type circumvention / monkey-patching is not desirable.
testScheduler.schedule(() => valueEmittingWork(), 20);
testScheduler.schedule(() => valueEmittingWork(), 40);
testScheduler.run(rx => {
rx.expectObservable(myObservable).toBe(`20ms ??? 19ms ???`);
// Above uses the new time progression syntax. What do I put instead of ???
});

As a workaround, I piped the source observable with .mapTo('a') and then was able to write:
testScheduler.run(rx => {
rx.expectObservable(myObservable.pipe(mapTo('a'))).toBe(`20ms a 19ms a`);
});

Related

Custom Validators - When to use Promise.reject() vs throw new Error()?

In the Custom Validators/Sanitizers documentation, it offers 2 methods to return an error along with a message.
body('email').custom(value => {
return User.findUserByEmail(value).then(user => {
if (user) {
return Promise.reject('E-mail already in use');
}
});
The following code also works:
body('email').custom(value => {
return User.findUserByEmail(value).then(user => {
if (user) {
throw new Error('E-mail already in use');
}
});
I understand the Promise.reject() method is asynchronous, however it doesn't seem to make a difference in the actual code.
Is there a particular situation you would want to use Promise.reject() vs throw new Error()? Or are they just the same thing but different semantics? And which method should be prioritized in situations where both methods work?

Ionic2: platform.is() response is undefined

I'm using the native Bluetooth serial library and trying to mock data for testing in the browser. By experimentation (and a little reading) it seems that the way to do this is to check for the 'cordova' platform:
export class BluetoothServiceWrapper implements OnDestroy, OnChanges {
...
private isEmulated:boolean = true;
...
constructor(platform:Platform) {
platform.ready().then(() => {
this.isEmulated = !platform.is('cordova');
});
}
The strange thing is that this works in some parts:
connect(device:BluetoothDevice) {
return Observable.create(observer => {
...
if (!this.isEmulated) {
...
}else{
... // this is executed in the browser
}
}
}
But in other parts the this.isEmulated is undefined:
write(data:any):Promise<any> {
if (!this.isEmulated) {
return BluetoothSerial.write(data);
} else {
.... // this never gets executed
}
}
Am I overcomplicating this and there is an easier way to check if we are using browser/emulation? Or is there some error in the way the context is being passed over?
I should mention that both methods get the same members when accessing 'this' i.e. the BluetoothServiceWrapper members. In the case of the 'write' function though the isEmulated variable is hidden/undefined.
Ok, this was a bit of a trap. The important piece of information that was missing from the original post was that I had another component/service perform the following:
if (!this.isConnected && (!this.isConnecting)) {
this.bluetoothServiceWrapper.connect(device).subscribe(data => this.tuningModuleService.onData(data), console.error);
this.tuningModuleService.setOutputFunction(this.bluetoothServiceWrapper.write);
}
Inside the service above I would be calling this.write('somedata'), using the function above given as reference.
The service:
outputToSerialFn: any;
constructor(applicationRef: ApplicationRef, platform: Platform) {
...
// default (mock) output function
this.outputToSerialFn = function (data) {
return new Promise((resolve, reject) => {
console.log('Mock BT OUT', data);
})
};
}
setOutputFunction(outputToSerialFn: any) {
this.outputToSerialFn = outputToSerialFn;
}
The problem is that during calls the write function would get the scope of the Service using it instead of the BluetoothWrapper service.
One solution is to replace the call above with:
this.tuningModuleService.setOutputFunction(this.bluetoothServiceWrapper.write.bind(this.bluetoothServiceWrapper));
The key word is bind.
This is probably not the best pattern but might help someone who is also struggling with this. The lesson here is that passing functions as parameters overrides the original function scope.

spyOn method in constructor with jasmine

I want to spyOn a promise and fake that promise in my unit test but the problem is that if I run first the contructor that the problem that he first run the promise and then run the Spyon.
But when i first run the spyOn and then the constructor it gives a error that storage is undefined.
Does someone know how to fix this?
Spec file:
describe('Settings Service', () => {
beforeEach(() => {
settingsService = new SettingsService(); // This gives a error beceause it runs the promise
spyOn(settingsService.storage, 'get').and.callFake((key: String): Promise<string> => {
return new Promise((resolve, reject) => { resolve('url'); });
});
});
constructor:
constructor() {
this.storage = new Storage(LocalStorage);
this.storage.get('url').then(data => {
this.setLink(data);
});
}
UPDATE:
I tried also this:
let injector: any = ReflectiveInjector.resolveAndCreate([SettingsService]);
settingsService = injector.get(SettingsService);
spyOn(settingsService.storage, 'get').and.callFake((key: String): Promise<string> => {
return new Promise((resolve, reject) => { resolve('https://secure.info/pascal'); });
});
The problem you have is that you are instantiating Storage within the constructor, so you have no access to it from the outside. That means that you cannot mock it.
Setting spyOn before calling settingsService = new SettingsService(); doesn't work either because the field storage has not been created yet.
You have two ways to solve this:
Mocking the service $httpBackend using the following code. Take a look at this post as an example
beforeEach(inject(function($injector) {
service = $injector.get('carService');
$httpBackend = $injector.get('$httpBackend');
$httpBackend.when('GET', "/api/cars/types").respond(["Toyota", "Honda", "Tesla"]);
}));
This way you can mock the promise you get when calling this.storage.get('url') and test the behaviour.
Making Storage a service and injecting it mocked: If you use this approach you could moke Storage and therefore mock the behaviour of this.storage.get('url'). The code of your class `` would look like this
static $inject = ['Storage'];
constructor(storage: Storage) {
this.storage = storage;
this.storage.get('url').then(data => {
this.setLink(data);
});
}
But this way depends on how do you define and use Storage so generally the first way will be better

How can I test if a function is returning a promise in Ember?

In Ember, I sometimes run into the situation where I need to check if a function is returning a promise. For example, if I have a route that is derived:
MyRoute = ParentRoute.extend({
beforeModel: function() {
this._super().then(function() {
// do something...
});
}
});
But although beforeModel can return a promise, it might not. In particular, if it's the default Ember.K implementation, then it doesn't. I'd rather not always be doing:
var res = this._super();
if (typeof res.then === "function") {
res.then(function() {
// do X
});
} else {
// do X
}
I assume there's a way to wrap something that one doesn't know if it's a thenable, and then chain regardless. But I couldn't find it in the documentation.
The above is undesirable because it's verbose, and requires having the code for X twice.
Thoughts?
Update:
I was able to confirm #torazaburo's response with the following coffeescript test:
`import { test, module } from 'ember-qunit'`
module "testing promise behavior"
test "can cast to promise", ->
expect 3
order = []
returnsPromise = ->
new Ember.RSVP.Promise (resolve) ->
order.push 'a'
resolve('response 1')
returnsValue = ->
order.push 'b'
'response 2'
Ember.run ->
Ember.RSVP.resolve(returnsPromise()).then (response) ->
order.push 'c'
equal response, 'response 1'
Ember.RSVP.resolve(returnsValue()).then (response) ->
order.push 'd'
equal response, 'response 2'
equal order.join(' '), 'a b c d'
Thanks for the solution! It seems RSVP's implementation of Promises also has a built in resolve method that does what you suggest, and it turns out to be the same as cast, as you suggest, althought that is now deprecated.
There may be other better ways to do this, but you could do:
function ensurePromise(x) {
return new Ember.RSVP.Promise(function(resolve) {
resolve(x);
});
}
If x is not a promise, then this returns a promise which is already fulfilled with that value, which you can then hang then's off of. If x is a promise, then it returns a promise which assumes its status (including resolved/rejected status and value/reason).
This is equivalent in native Promises to
Promise.resolve(x)
So in your case,
MyRoute = ParentRoute.extend({
beforeModel: function() {
ensurePromise(this._super()).then(function() {
// do something...
});
}
});
Note, however, that this will potentially turn a synchronous value into an asynchronous value (a promise). However, it is generally considered bad practice to have functions that behave synchronously in some cases and asynchronously in others. So it seems OK, in the case we have a value which is potentially either synchronous or asynchronous, to coerce it into something which is always asynchronous.
I believe in some past version there used to be something called RSVP.Promise.cast, which I seem to recall did roughly the same thing, but I can't track it down now.

Verification of a function call on a mock object not matched when a params array is used

I have the following test:
[Test]
public void VerifyThat_WhenInitializingTheLoggingInterceptionFacility_TheLoggingInterceptorIsAdded()
{
var kernel = new Mock<IKernel>(MockBehavior.Loose)
{
DefaultValue = DefaultValue.Mock
};
kernel.Setup(k => k.AddFacility<LoggingInterceptionFacility>())
.Returns(kernel.Object)
.Callback(() => ((IFacility)new LoggingInterceptionFacility()).Init(kernel.Object, Mock.Of<IConfiguration>()));
kernel.Setup(k => k.Register(It.IsAny<IRegistration[]>()))
.Returns(kernel.Object)
.Verifiable();
kernel.Object.AddFacility<LoggingInterceptionFacility>();
kernel.Verify(k => k.Register(It.Is<IRegistration[]>(r => r.Contains(Component.For<LoggingInterceptor>()))));
}
As you can see I am mocking the real behavior of the kernel by calling the facilitiy's Init(IKernel, IConfiguration) method which in turns calls the protected Init() method.
Here's how the protected Init() looks like:
protected override void Init()
{
Kernel.ProxyFactory.AddInterceptorSelector(new LoggingModelInterceptorsSelector());
Kernel.Register(Component.For<LoggingInterceptor>());
}
I expected that the verification would pass but it does not. If I verify that the Kernel.Register was called at all with It.IsAny<LoggingInterceptor>() the test passes.
What am I not matching right here? Is there a way to make this test pass?
It seems like you are testing way too much here. You are effectively reimplmenting a lot of Windsor's internals by piping calls from AddFacility to LoggingInterceptionFacility.Init.
All you really need to test is the fact that your facility calls Register on the kernel and assume that Windsor does the right thing. After all, it has unit tests of its own ;)
After doing that, the test becomes much more readable, which I consider the most important aspect.
[Test]
public void VerifyThat_WhenInitializingTheLoggingInterceptionFacility_TheLoggingInterceptorIsAdded()
{
var kernel = new Mock<IKernel>();
kernel.Setup(k => k.Register(It.IsAny<IRegistration[]>()))
.Returns(kernel.Object)
.Verifiable();
//Explicit interface implementation requires casting to the interface
((IFacility)new LoggingInterceptionFacility()).Init(kernel.Object, Mock.Of<IConfiguration>().Object);
//verify the type of registration here
kernel.Verify(k => k.Register(It.Is<IRegistration[]>(r => r[0] is ComponentRegistration<LoggingInterceptor>);
}
EDIT Calls to Component.For return different instances between setup and execution. I updated the code to reflect that and have the verification check the type of the component.