Ionic Refresher doesn't work correctly - ionic2

Iam try to make a ionic 3 demo and i have
<ion-refresher (ion-Refresh)="doRefresh($event)" >
<ion-refresher-content></ion-refresher-content>
and it's function looks like
doRefresh(e){
this.service.getTask()
.subscribe(
data => console.log(data),
err => console.log(err)
, () => e.complete()
);
}
but it doesn't enter doRefresh function.

I think the you need to remove the -
<ion-refresher (ion-Refresh)="doRefresh($event)" >
should be
<ion-refresher (ionRefresh)="doRefresh($event)" >
Ion Refresher

Related

Test Jest and NestJs

I have a service (in Nestjs) and I want test the function exception whit Jest.
My service:
class MyService{
public throwError(ms: string) {
throw new UnprocessableEntityException(ms);
}
}
And I want test it, but I don't know how to do it.
I feel like jest's docs point this out pretty well, but as a quick example, for the above code you'd just need something simple like
describe('MyuService', () => {
describe('throwError', () => {
it('should throw an UnprocessableEntityException', () => {
const myService = new MyService();
expect(
() => myService.throwError('some string')
).toThrow(new UnprocessableEntityException('some string'));
})
})
})
For even more examples, there's a git repo here with a lot of different samples from rxjs to typeorm to graphql, sync and async

How to handle login errors with Ionic custom auth?

I'm trying to implement a user login with Ionic Cloud's Auth Service, and would prefer to no show the Cordova inAppBrowser. In case of an authentication error (e.g. wrong password), I would expect the error handler to fire, but for some reason this never seems to be the case.
The method in my login component contains this:
let loginData = {
email: this.email,
password: this.password
};
let loginOptions: AuthLoginOptions = {
inAppBrowserOptions: {
hidden: true
}
};
this.auth.login('custom', loginData, loginOptions).then(() => {
console.log('login success');
}, (err) => {
console.log('login error', err); // <-- this never gets executed.
});
I made sure that my authentication server responds with an HTTP status of 401 and a JSON body that contains an error property. This is the code (PHP, Laravel 3):
public function get_login()
{
try {
$redirect_uri = CustomAuthentication::process(
$_GET['token'],
$_GET['state'],
$_GET['redirect_uri']
);
return Redirect::to($redirect_uri);
} catch (\Exception $e) {
return Response::json(array(
'ok' => false,
'error' => $e->getMessage(),
'code' => $e->getCode()
), 401);
}
}
I found two issues on github that seem relevant:
https://github.com/driftyco/ionic-cloud/issues/53
https://github.com/driftyco/ionic-cloud-angular/issues/22
Apparently there is no way to get this to work at the moment, when the inAppBrowser is hidden. Or is there another option?
In case there's no way to achieve this for now, what would be an alternative, in order to provide the users with a nice login flow, that shoes them a meaningful error message for unsuccessful login attempts?
Should I try to implement this with a visible inAppBrowser? If so, where can I find docs or an example?
Unfortunately the official docs don't tell much (http://docs.ionic.io/services/auth/custom-auth.html#login) and the tutorials I found are outdated.
I had the same issue!!
In your server, you have to redirect when there is an authentication error instead of rendering a JSON.
Something like this:
public function get_login()
{
try {
$redirect_uri = CustomAuthentication::process(
$_GET['token'],
$_GET['state'],
$_GET['redirect_uri']
);
return Redirect::to($redirect_uri);
} catch (\Exception $e) {
$redirect_uri = $_GET['redirect_uri'] . '&' . http_build_query([
'error' => $e->getMessage(),
'state' => 401,
'code' => $e->getCode(),
]);
return Redirect::to($redirect_uri);
}
}
(Sorry if there is an error in the code, I don't know Lavarel ;))
This code is based on https://github.com/ionic-team/ionic-cloud/issues/53#issuecomment-296369084
In the Ruby on Rails world:
error_params = { error: error, state: 401 }
url = "#{params[:redirect_uri]}&#{error_params.to_query}"
redirect_to url
Immediately after I made this change on my server, the ionic application started to work.
anyErrors : any;
in the controller.ts file
this.auth.login('basic', details).then(() => {
this.isUserLoggedIn = true; // <------ Debug here (1)
this.currentUserData = this.user;
console.log(this.currentUserData);
return this.currentUserData;
}, (err: IDetailedError) => {
this.anyErrors= err; // map the error here
});
in the html file
<div >
<ion-row >
<ion-item >
<ion-label text-wrap color=red color="primary" >
{{anyErrors}}
</ion-label>
</ion-item>
</ion-row>
</div>
So any error in ionic .ts will flow the the html page I use this for the login page. i.e below the login submit button, i have the above div code. if there is no error the msg will not display, if there is an error msg it will display.

ember liquid-teather transitions.js

I am using ember liquid-teather - http://pzuraq.github.io/liquid-tether/#/examples?a=animation-with-context
The code I have used is from the example under 'Animation With Context'.
The modal works, but there is no nice transitions as am getting an error in the console re the transitions.js file.
See my transitions code below:
export default function(){
this.transition(
target('modal-dialog'),
this.toValue(({ index: newIndex }, { index: oldIndex }) => newIndex > oldIndex),
this.use('tether', ['to-left', options]),
this.reverse('tether', ['to-right', options])
);
this.transition(
target('modal-dialog'),
this.toValue(({ index }) => index === 1),
this.use('tether', 'fade', 'fade')
);
this.transition(
target('modal-dialog'),
this.toValue(({ index }) => !index),
this.use('tether', 'fade', 'fade')
);
}
The error is: target not defined.
How do I define target?
Thank you in advance! :-)
You can check here what values are allowed for options.
http://tether.io/
Search under options :).
scratch that! I have solved my own question. I just needed to declare this at the top of the transitions.js file.
import { target } from 'liquid-tether';
But now the issue I am getting is 'options not define'. ...Any ideas anyone?
options not defined refers to the options you are passing to your animation. It is not very clear from the docs but it is expecting an options hash here. For example:
this.use('tether', ['to-left', {duration: 500}]),
Check the liquid fire site for all the options available for animations

Angular2 Component: Testing form input value change

I have a text input and i'm listening for the changes.
mycomponent.ts
ngOnInit() {
this.searchInput = new Control();
this.searchInput.valueChanges
.distinctUntilChanged()
.subscribe(newValue => this.search(newValue))
}
search(query) {
// do something to search
}
mycomponent.html
<search-box>
<input type="text" [ngFormControl]="searchInput" >
</search-box>
Running the application everything works fine, but i want to unit-test it.
So here's what i tried
mycomponent.spec.ts
beforeEach(done => {
createComponent().then(fix => {
cmpFixture = fix
mockResponse()
instance = cmpFixture.componentInstance
cmpFixture.detectChanges();
done();
})
})
describe('on searching on the list', () => {
let compiled, input
beforeEach(() => {
cmpFixture.detectChanges();
compiled = cmpFixture.debugElement.nativeElement;
spyOn(instance, 'search').and.callThrough()
input = compiled.querySelector('search-box > input')
input.value = 'fake-search-query'
cmpFixture.detectChanges();
})
it('should call the .search() method', () => {
expect(instance.search).toHaveBeenCalled()
})
})
Test fails as the .search() method is not called.
I guess i have to set the value in another way to have the test realize of the change but i really don't know how.
Anyone has ideas?
It might be a little bit late, but it seems that your code is not dispatching input event after setting input element value:
// ...
input.value = 'fake-search-query';
input.dispatchEvent(new Event('input'));
cmpFixture.detectChanges();
// ...
Updating input html field from within an Angular 2 test
Triggering the value change of FormControl is as simple as:
cmpFixture.debugElement.componentInstance.searchInput.setValue(newValue);
Custom component with #input, subscriptions, two way data binding
If you got a custom component you would need further changes in your application to be able to successfully unit test your application
have a look at the gist here this will give you some idea
https://gist.github.com/AikoPath/050ad0ffb91d628d4b10ef81736af386/raw/846c7bcfc54be8cce78eba8d12015bf749b91eee/#ViewChild(ComponentUnderTestComponent).js
More over complete reading over here carefully otherwise you can easily get confused again -
https://betterprogramming.pub/testing-angular-components-with-input-3bd6c07cfaf6

Angular2 - testing component with two "it" creates 'selector "#root0" did not match any elements error'

I am trying to create a simple component test, when I createAsync an element twice I get The selector "#root0" did not match any elements error. I assume it creates it the second time with #root1 but looks for #root0
it('should render',
inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
tcb.createAsync(TestComponent)
.then((componentFixture) => {
componentFixture.detectChanges();
expect(true).toBeTruthy();
componentFixture.destroy();
}).catch((e) =>{
console.log(e);
});
})
);
it('should render',
inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
tcb.createAsync(TestComponent)
.then((componentFixture) => {
componentFixture.detectChanges();
expect(true).toBeTruthy();
componentFixture.destroy();
}).catch((e) =>{
console.log(e);
});
})
);
If I run just one "it" test it works fine. the second one fails... I tried it with and without the componentFixture.destroy(); but no success...
To be clear - the tests passes, but the error shows up in the console.
Here is the complete error log:
LOG: BaseException{message: 'The selector "#root0" did not match any elements', stack: 'Error: The selector "#root0" did not match any elements
at new BaseException (http://localhost:9876/base/node_modules/angular2/bundles/angular2.dev.js?914563a3aa3b4999ed51fe88c1b6233d2f09e880:7070:21)
at DomRenderer.selectRootElement (http://localhost:9876/base/node_modules/angular2/bundles/angular2.dev.js?914563a3aa3b4999ed51fe88c1b6233d2f09e880:13643:15)
at HostViewFactory.viewFactory_HostTestComponent0 [as viewFactory] (viewFactory_HostTestComponent:72:18)
at AppViewManager_.createRootHostView (http://localhost:9876/base/node_modules/angular2/bundles/angular2.dev.js?914563a3aa3b4999ed51fe88c1b6233d2f09e880:9172:34)
at http://localhost:9876/base/node_modules/angular2/bundles/angular2.dev.js?914563a3aa3b4999ed51fe88c1b6233d2f09e880:12189:46
at M (http://localhost:9876/base/node_modules/systemjs/dist/system-polyfills.js?064ab212cfd9e125474ae3bbb600c366b31e79cb:4:8769)
at H (http://localhost:9876/base/node_modules/systemjs/dist/system-polyfills.js?064ab212cfd9e125474ae3bbb600c366b31e79cb:4:8401)
at R.when (http://localhost:9876/base/node_modules/systemjs/dist/system-polyfills.js?064ab212cfd9e125474ae3bbb600c366b31e79cb:4:12075)
at b.run (http://localhost:9876/base/node_modules/systemjs/dist/system-polyfills.js?064ab212cfd9e125474ae3bbb600c366b31e79cb:4:11111)
at t._drain (http://localhost:9876/base/node_modules/systemjs/dist/system-polyfills.js?064ab212cfd9e125474ae3bbb600c366b31e79cb:4:3029)
at drain (http://localhost:9876/base/node_modules/systemjs/dist/system-polyfills.js?064ab212cfd9e125474ae3bbb600c366b31e79cb:4:2683)
at MutationObserver.e (http://localhost:9876/base/node_modules/systemjs/dist/system-polyfills.js?064ab212cfd9e125474ae3bbb600c366b31e79cb:4:4604)
at Zone.run (http://localhost:9876/base/node_modules/angular2/bundles/angular2-polyfills.js?2a193e6e9bdd25760b711f1ce03caeac530e48c1:138:17)
at MutationObserver.zoneBoundFn (http://localhost:9876/base/node_modules/angular2/bundles/angular2-polyfills.js?2a1
This is a known issue https://github.com/angular/angular/issues/6483 (dup of https://github.com/angular/angular/issues/5662) when templateUrl is used in components.
Update
This is fixed in Angular 2.0.0-beta.3
See https://github.com/angular/angular/issues/6483#issuecomment-179557485 for more details
Basically, what I had to do:
Manually add typings for jasmine with tsd install jasmine -so and add ///<reference... in the test files;
Add this in my imports:
import {setBaseTestProviders} from 'angular2/testing';
import {
TEST_BROWSER_PLATFORM_PROVIDERS,
TEST_BROWSER_APPLICATION_PROVIDERS
} from 'angular2/platform/testing/browser';
Add this before my Component tests:
setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS);
An update to the update:
Beta.3 did fix the problem as Günter Zöchbauer mentioned, we can now use injectAsync that didn't work before.
Also I suggest to use this:
import {setBaseTestProviders} from 'angular2/testing';
import {getTestInjector} from 'angular2/testing';
import {TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS
} from 'angular2/platform/testing/browser';
if (getTestInjector().platformProviders.length === 0 || getTestInjector().applicationProviders.length === 0) {
setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS);
}
otherwise you will get an error when loading your BaseTestProviders the second time.