Ionic2: platform.is() response is undefined - ionic2

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.

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?

TypeScript Generic Collection: List

I am trying to learn TypeScript, and need some advice on implementing generic collection types. I put the dictionary and HashSet in another question, here I'd like any advice on my list type.
Especially the ForEach-Operation looks a bit strange. I think I found it in another question here, and "improved" by returning true or false to give feedback if the iteration was stopped early or completed.
import { IForEachFunction } from "./IForEachFunction"
export class List<T> {
private _items: Array<T>;
public constructor() {
this._items = [];
}
public get Count(): number {
return this._items.length;
}
public Item(index: number): T {
return this._items[index];
}
public Add(value: T): void {
this._items.push(value);
}
public RemoveAt(index: number): void {
this._items.splice(index, 1);
}
public Remove(value: T): void {
let index = this._items.indexOf(value);
this.RemoveAt(index);
}
public ForEach(callback: IForEachFunction<T>): boolean {
for (const element of this._items) {
if (callback(element) === false) {
return false;
}
}
return true;
}
}
The ForEach-Iteration relies on an interface from another file:
export interface IForEachFunction<T> {
(callback: T): boolean | void;
}
You would use my list and the ForEach-Method like this:
let myList: List<a_type> = new List<a_type>();
let completed: boolean = myList.ForEach(xyz => {
// do something with xyz
return false; // aborts the iteration
return true; // continues with the next element
});
if (completed) // we can see what happened "during" the iteration
I think this is not bad, but I'd appreciate any input. I am not sure if I use the === correctly.
Another question which I really like to know: How could I define a function with the interface IForEachFunction? I do not really "re-use" that interface visibly, I always declare an anonymous method as shown above. If I wanted to call a method having the interface definition, is that possible?
Thanks!
Ralf
One problem I see is that you have an interface instance:
callback: IForEachFunction<T>
This contains a method called
callback()
But you only call callback once. You would have call callback() method inside your interface:
callback.callback()
Also your code looks like it is inspired by C# or Java. In TypeScript you would often just use an array. This simplifies certain code constructs.

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.

Laravel testing - Problems with created routes

I have a question about routing while testing packages. The function setRoutes creates new routes in the test file as follows:
class PackageTests extends \Orchestra\Testbench\TestCase {
protected function setRoutes()
{
Route::group([
'prefix' => Package::functionToCall1(),
'before' => 'filter'
], function() {
Route::get('/', function () {
return "hello";
});
});
Route::enableFilters();
}
protected function getEnvironmentSetUp($app)
{
$this->app = $app;
$this->setRoutes();
Config::set('app.url', "http://localhost/" );
}
public function testFunction1()
{
$crawler = $this->call(
'GET',
'http://localhost/'
);
// doing this call, the function on the prefix is called
$this->assertResponseOk();
}
}
Inside the function called in the prefix, functionToCall1() urls are not taken successfully. A call to URL::current() returns "/" and a call to Request::fullUrl() returns "http://:" when phpunit is executed but they returns the full url when used executing a url in the browser. This is the code of the package:
class Package
{
function functionToCall1()
{
var_dump(URL::current() ); // returns "/"
var_dump(Request::fullUrl()); // returns "http://:"
// I want them to return 'http://localhost'
}
}
I tried setting up the url Config::set('app.url', "http://localhost/" ); but it was useless.
To sum up, is there a way to call a function in the prefix and get the testing url?
Thanks, I would really appreciate your answers :)
I have had to deal with a similar issue. My solution was found here:
Mocking Laravel's Request::segment method
Apparently there is an order of operations issue with testing a Request facade.
I was trying to use Request::segments() before the request was being built, so there were never any segments to return.
I imagine it's the same problem with Request::fullUrl().
Here is my solution:
class MyTestClass extends TestCase
{
public function setUp()
{
// No call to parent::setUp()
$this->app = $this->createApplication();
$this->app->request->server->set('REQUEST_URI', '/some/uri');
$this->client = $this->createClient();
$this->app->boot();
}
public function testWhatever()
{
$this->call('GET', '/some/uri');
}
}
This allows me to get the request data properly, even though it looks pretty bad.

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 ;)