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

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?

Related

Testing redux-saga takeEvery

I have the following super simple Redux-Saga that I want to test with Jest.
function* nextApi() {
yield* takeEvery(
(action) => !!(action.meta && action.meta.next),
nextApiSaga
)
}
I've looked at Redux-Sagas-Test-Plan, but that only seems to allow you to unit test functions that contain Saga Effect Creators and doesn't seem to support Saga Helpers. There is also Redux-Saga-Test but that just does a deepEqual on the yielded effect and doesn't test the arrow function.
What I want to be able to do is past the following two objects to takeEvery and see that nextApiSaga is only called in the second case.
{ type: 'foo' }
{ type: 'foo', meta: { next: 'bar' } }
I left you a comment about redux-saga-test-plan having methods for saga helpers, but you can easily test takeEvery with it. Call testSaga with your saga and then invoke the takeEvery method assertion with the pattern (note I keep a reference to your original anonymous function) and the other saga.
const helper = action => !!(action.meta && action.meta.next)
function* nextApi() {
yield* takeEvery(
helper,
nextApiSaga
)
}
testSaga(nextApi).takeEvery(helper, nextApiSaga)
Taking a different approach, I came up with this. Not sure if it's the best answer, but it seems to work. Adding here in case anyone else has the same problem and still open to better suggestions.
function getTakeEveryFunction(saga) {
return saga().next().value.TAKE.pattern
}
it('takes actions with meta.next property', () => {
const func = getTakeEveryFunction(nextApi)
expect(func({ type:'foo' })).toBe(false)
expect(func({ type:'foo', meta: { next: 'bar' } })).toBe(true)
})

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

Confused about PhpSpec stubs and mocks again

I'm building a Laravel 5 application at the moment and have gotten myself confused about how to mock things in PhpSpec.
I'm building a schedule times validator that requires the intended schedule to be checked against all current schedules and see if there's any overlap (events are not allowed to overlap).
I need to pull in the schedules in question so I can test against them. At the moment it's a very basic whereBetween query, but it's going to get a lot more complicated as there'll be recurring schedules to check against as well.
So here's my stripped down class. I really just want to test the doesNotOverlap function.
use App\Schedule;
class ScheduleTimesValidator
{
protected $schedule;
public function __construct(Schedule $schedule)
{
$this->schedule = $schedule;
}
public function doesNotOverlap($slug, $intended)
{
$schedules = $this->getSchedulesBetween($slug, $intended);
if(empty($schedules)) return true;
return false;
}
protected function getSchedulesBetween($slug, $intended)
{
// Casting to array to make testing a little easier
return $this->schedule->whereIsRecurring(false)
->ofChurch($slug)
->whereBetween('start', [$intended['start'], $intended['end']])
->get()->toArray();
}
and here's my Spec
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class ScheduleTimesValidatorSpec extends ObjectBehavior
{
protected $validIntended = [
'start' => '2015-12-01 12:00:00',
'end' => '2015-12-01 13:00:00'
];
protected $churchNonRecurringSchedules = [
['start' => '2014-11-20 13:00:00', 'end' => '2014-11-21 14:00:00'],
['start' => '2014-11-23 10:36:07', 'end' => '2014-11-23 11:36:07'],
];
function let($schedule)
{
$schedule->beADoubleOf('App\Schedule');
$this->beConstructedWith($schedule);
}
function it_is_initializable()
{
$this->shouldHaveType('App\Validation\ScheduleTimesValidator');
}
function it_should_return_true_if_it_does_not_overlap($schedule)
{
// $schedule->any()->willReturn([]);
// $schedule->whereIsRecurring()->shouldBeCalled();
// $schedule->whereIsRecurring(false)->ofChurch()->whereBetween()->get()->toArray()->willReturn([]);
// $schedule->willReturn([]);
// $this->getSchedulesBetween('slug', $this->validIntended)->willReturn([]);
$this->doesNotOverlap('slug', $this->validIntended)->shouldReturn(true);
}
// Tear Down
function letgo() {}
}
If I run it like that I get:
! it should return true if it does not overlap
method 'Double\App\Schedule\P8::whereIsRecurring()' not found.
I tried (as you can see) various commented out things to mock what $schedule will return, but that doesn't seem to work.
So I guess I want to mock the protected getSchedulesBetween method in the class, but doing things like $this->getSchedulesBetween($arg, $arg)->willReturn(blah) doesn't work.
Do I need to pull getSchedulesBetween() out of the class and move it into another class and then mock that? Or do I need to push $this->schedule->blah into the doestNotOverlap method so I can mock what $schedule will return?
I don't want to actually test the App\Schedule Laravel Model - I just want to mock what it's returning and will be hardcoding a variety of queries that will be run to get the different model results.
End of a long day here so brain a little zonked.
Update 2014-10-23
So I created a scope on my Schedule model
public function scopeSchedulesBetween($query, $slug, $intended)
{
return $query->whereIsRecurring(false)
->ofChurch($slug)
->whereBetween('start', [$intended['start'], $intended['end']]);
}
Then created a new App\Helpers\ScheduleQueryHelper which instantiated App\Schedule as a variable and added this method:
public function getSchedulesBetween($slug, $intended)
{
return $this->schedule->schedulesBetween($slug, $intended)->get()->toArray();
}
Then updated my spec to do
function let($scheduleQueryHelper)
{
$scheduleQueryHelper->beADoubleOf('App\Helpers\ScheduleQueryHelper');
$this->beConstructedWith($scheduleQueryHelper);
}
function it_should_return_true_if_it_does_not_overlap($scheduleQueryHelper)
{
$scheduleQueryHelper->getSchedulesBetween('slug', $this->validIntended)->willReturn([]);
$this->doesNotOverlap('slug', $this->validIntended)->shouldReturn(true);
}
And back in my ScheduleTimesValidator class did
public function doesNotOverlap($slug, $intended)
{
$schedules = $this->scheduleQueryHelper->getSchedulesBetween($slug, $intended);
if(empty($schedules)) {
return true;
}
return false;
}
And now PhpSpec is mocking that other class ok. However this seems like a very roundabout way to be doing things.

Moq tests using ExpectSet() with It.Is<T>() aren't behaving as... expected

I've isolated the behaviour into the following test case. I'd be grateful to anyone who can tell me how to expect/verify a property set for a List<T> property - it appears there's something going on inside It.Is<T>(predicate) that isn't making a whole lot of sense to me right now. Sample code will run as a console app from VS2008 - you'll need to add a reference to Moq 2.6 (I'm on 2.6.1014.1) - please try uncommenting the different ExpectSet statements to see what's happening...
using System;
using Moq;
using System.Collections.Generic;
namespace MoqDemo {
public interface IView {
List<string> Names { get; set; }
}
public class Controller {
private IView view;
public Controller(IView view) {
this.view = view;
}
public void PopulateView() {
List<string> names = new List<string>() { "Hugh", "Pugh", "Barney McGrew" };
view.Names = names;
}
public class MyApp {
public static void Main() {
Mock<IView> mockView = new Mock<IView>();
// This works - and the expectation is verifiable.
mockView.ExpectSet(mv => mv.Names);
// None of the following can be verified.
// mockView.ExpectSet(mv => mv.Names, It.Is<Object>(o => o != null));
// mockView.ExpectSet(mv => mv.Names, It.Is<List<string>>(names => names.Count == 3));
// mockView.ExpectSet(mv => mv.Names, It.IsAny<IList<String>>());
Controller controller = new Controller(mockView.Object);
controller.PopulateView();
try {
mockView.VerifyAll();
Console.WriteLine("Verified OK!");
} catch (MockException ex) {
Console.WriteLine("Verification failed!");
Console.WriteLine(ex.Message);
}
Console.ReadKey(false);
}
}
}
}
I'm not using the very latest version of Moq, so I don't have an overload of ExpectSet that takes two parameters, but I've had some success with this pattern:
mockView.ExpectSet(mv => mv.Names).Callback(n => Assert.That(n != null));
The Assert (from NUnit) call in the callback will throw an exception if the value assigned to .Names doesn't match the predicate. It does make it hard to trace when a test fails, though. I agree that the ability to pass an It.Is or It.IsAny as the second parameter would be handy.
The second parameter of ExpectSet() is the value you're expecting. You can't use It.Is<T> in this case as there's no overload that takes a predicate - though it would be nice ;) Here's a (simplified) excerpt from your sample, illustrating the use of a value:
var mockView = new Mock<IView>();
var list = new List<string> { "Hugh", "Pugh", "Barney McGrew" };
mockView.ExpectSet(mv => mv.Names, list);
mockView.Object.Names = list;
Hope that helps.
Edit: fixed typo.
BTW, It.Is is not supported on ExpectSet. Your code compiles just because they are regular method invocations when used as values (as opposed to expressions), whereas when used in an Expect expression they are pre-processed by Moq and given specific meaning (rather than the null/default value that all It.Is members actually return).
You could use the stub behavior on the given property (mockView.Stub(mv => mv.Names)) and later assert directly for its value after execution.
Moq doesn't provide an overload receiving It.IsAny as it's effectively the same as calling ExpectSet without passing an expected value ;)