I have to read a NFC tag with ionic 2, the problem is the first attempt doesn't read then if I read again is working fine. I initialize nfc listener in platform.ready() I think that this should be enough...
This is my code:
#IonicPage()
#Component({
selector: 'page-dispositivo',
templateUrl: 'dispositivo.html',
providers: [NFC, Ndef, Diagnostic, Vibration]
})
export class DispositivoPage {
subscriptions: Array<Subscription> = new Array<Subscription>();
constructor(
public navCtrl: NavController,
public navParams: NavParams,
private auth: AuthService,
public loading: LoadingController,
public alertCtrl: AlertController,
public toastCtrl: ToastController,
private nfc: NFC,
private ndef: Ndef,
public diagnostic: Diagnostic,
public platform: Platform,
public vibration: Vibration
) {
platform.ready().then(() => {
this.initNFC();
});
}
initNFC() {
this.nfc.enabled()
.then(() => {
this.addListenNFC();
}).catch(err => {
let alert = this.alertCtrl.create({
subTitle: 'Active la conexión NFC para para leer artículos',
buttons: [
{
text: 'Activar más tarde',
handler: () => {
this.goToHome();
}
},
{
text: 'Ir a Ajustes para activar',
handler: () => {
this.nfc.showSettings().then(rs => {
this.goToHome();
});
}
}]
});
alert.present();
});
}
addListenNFC() {
this.subscriptions.push(this.nfc.addTagDiscoveredListener().subscribe(nfcData => {
this.processResponse(nfcData);
}));
}
I don't know what is happening, somebody can help me?
Related
I have a simple custom control as below. Everything is working but the unit test is failing. How can I unit test this custom control? How can I pass a valid NgControl directive?
I have tried using providers:
[
{
provide: NgControl,
useValue: new FormGroup()
}
]
but I still get the same error.
core-edi.component.ts
import { Component, OnInit, Input, ViewChild, ElementRef, Self, Optional, forwardRef } from '#angular/core';
import {
ControlValueAccessor, NG_VALUE_ACCESSOR, Validator, AbstractControl,
ValidatorFn, Validators, NG_VALIDATORS, NgControl, NgForm
} from '#angular/forms';
import { Placeholder } from '#angular/compiler/src/i18n/i18n_ast';
#Component({
selector: 'app-core-edi',
templateUrl: './core-edi.component.html',
styleUrls: ['./core-edi.component.css'],
})
export class CoreEdiComponent implements ControlValueAccessor, Validator, OnInit {
#ViewChild('input') input: ElementRef;
disabled;
#Input() type = 'text';
#Input() isRequired: boolean = false;
#Input() pattern: string = null;
#Input() label: string = null;
#Input() placeholder: string;
#Input() errorMsg: string;
#Input() min: number;
#Input() minLength: number;
myhint: string = '10 digit number';
constructor(#Self() public controlDir: NgControl) {
this.controlDir.valueAccessor = this;
}
ngOnInit() {
const control = this.controlDir.control;
const validators: ValidatorFn[] = control.validator ? [control.validator] : [];
if (this.isRequired) {
validators.push(Validators.required);
}
if (this.pattern) {
validators.push(Validators.pattern(this.pattern));
}
if (this.min) {
validators.push(Validators.min(this.min));
}
control.setValidators(validators);
control.updateValueAndValidity();
this.placeholder = this.placeholder + (this.isRequired ? '*' : '');
}
onChange(event) {
}
onTouched() {
}
writeValue(obj: any): void {
this.input.nativeElement.value = obj;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.disabled = isDisabled;
}
validate(c: AbstractControl): { [key: string]: any; } {
const validators: ValidatorFn[] = [];
if (this.isRequired) {
validators.push(Validators.required);
}
if (this.pattern) {
validators.push(Validators.pattern(this.pattern));
}
if (this.min) {
validators.push(Validators.min(this.min));
}
return validators;
}
core-edi.component.html
<div class="form-label-group" fxLayout="column" fxLayoutGap="5px">
<mat-form-field class="edi-field-width">
<input matInput class="form-control"
[type]="type" #input
(input)="onChange($event.target.value)"
(blur)="onTouched()"
[disabled]="disabled"
[placeholder]="placeholder"
[min]="1111111111"
[minLength] = 10
(keyup)="mykeyup()">
<mat-hint>Hint: {{ myhint }}</mat-hint>
</mat-form-field>
<span class="error"
*ngIf="controlDir && !controlDir.control.valid
&& controlDir.control.touched">{{errorMsg}}</span>
</div>
core-edi.component.spec.ts
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { CoreEdiComponent } from './core-edi.component';
import { FormsModule, ReactiveFormsModule, FormControl, NgControl, FormControlDirective } from '#angular/forms';
import { MaterialModule } from 'src/app/material/material.module';
fdescribe('CoreEdiComponent', () => {
let component: CoreEdiComponent;
let fixture: ComponentFixture<CoreEdiComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CoreEdiComponent ],
imports: [
FormsModule,
ReactiveFormsModule,
MaterialModule
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CoreEdiComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
No provider for NgControl ("[ERROR ->]<app-core-edi></app-core-edi>"): #0:0
at syntaxError (./node_modules/#angular/compiler/fesm5/compiler.js?:1275:17)
at TemplateParser.parse (./node_modules/#angular/compiler/fesm5/compiler.js?:15084:19)
at JitCompiler._parseTemplate (./node_modules/#angular/compiler/fesm5/compiler.js?:24272:37)
at JitCompiler._compileTemplate (./node_modules/#angular/compiler/fesm5/compiler.js?:24259:23)
at eval (./node_modules/#angular/compiler/fesm5/compiler.js?:24202:62)
at Set.forEach (<anonymous>)
at JitCompiler._compileComponents (./node_modules/#angular/compiler/fesm5/compiler.js?:24202:19)
at eval (./node_modules/#angular/compiler/fesm5/compiler.js?:24120:19)
at Object.then (./node_modules/#angular/compiler/fesm5/compiler.js?:1266:77)
at JitCompiler._compileModuleAndAllComponents (./node_modules/#angular/compiler/fesm5/compiler.js?:24118:26)
Expected undefined to be truthy.
at UserContext.eval (./src/app/core/core-edi/core-edi.component.spec.ts?:30:27)
at ZoneDelegate.invoke (./node_modules/zone.js/dist/zone.js?:390:26)
at ProxyZoneSpec.onInvoke (./node_modules/zone.js/dist/zone-testing.js?:288:39)
I have not been through understanding how to unit test in angular yet, but maybe its in the app.module that you need to add like the ReactiveFormsModule
The answer to this helped me out
Why do I get this Template parse errors in Angular
Just my 2cents
So, I'm getting the error TypeError: Cannot read property 'subscribe' of undefined for all the test cases in my module. In my component I'm injecting "ActivatedRoute" and "Router" and in my ngOnInit(), I'm getting some data that I'm passing within the routing-module.
These are the files I have:
custom-routing.module.ts
const casesRoutes: Routes = [
{
path: '',
component: MainComponent,
children: [
{
path: '',
component: CustomComponent,
resolve: {
someData: CustomResolver
},
children: [
{
path: 'child',
component: ChildComponent
}
]
},
{
path: ':id/edit',
component: CaseEditComponent,
resolve: {
theCase: CaseDetailResolver
}
}
]
}
];
#NgModule({
imports: [
RouterModule.forChild(casesRoutes)
],
exports: [
RouterModule
],
providers: [
CustomResolver
]
})
export class CustomRoutingModule { }
custom.component.ts
#Component({
selector: 'my-custom',
styleUrls: ['./custom.component.css'],
templateUrl: './custom.component.html',
})
export class CustomComponent implements OnInit {
public someData: TheData;
constructor(private route: ActivatedRoute, private router: Router) { }
public ngOnInit(): void {
this.route.data.subscribe((data) => {
this.someData = data.someData;
});
}
public navigateTo(): void {
this.router.navigate(['child'], { relativeTo: this.route });
}
}
custom.component.spec.ts
describe('CustomComponent', () => {
let comp: CustomComponent;
let fixture: ComponentFixture<CustomComponent>;
let router = {
navigate: jasmine.createSpy('navigate')
}
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
CustomComponent
],
providers: [
{
provide: ActivatedRoute,
useValue: {
data: Observable.of({
someData: { id: 1, lastName: 'Last', firstName: 'First' }
})
}
},
{
provide: Router,
useValue: router
}
]
}).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(CustomComponent);
comp = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create component', () => {
expect(comp).toBeDefined();
});
it('should initialize the component correctly and expect some data returned from ActivatedRoute', () => {
comp.ngOnInit();
expect(comp.someData).toBeDefined();
});
it('should verify the navigate method from router is called', () => {
comp.navigateTo();
expect(router.navigate).toHaveBeenCalled();
});
});
At first I thought it could be breaking because of the statement in ngOnInit() since it's the only case I'm using the subscribe method but even the first test where I check the component is defined, is failing. I even added some console.info() calls to review that this.route.data in the component has some data and it actually has so I have no idea what could be causing it.
I have a page which is listening to beacon events. I want to show a popup when the beacon is detected. I have the following code:
home.ts
export class HomePage {
beacon_found: boolean;
constructor(public navCtrl: NavController, public events: Events, public ibeacon: IBeacon) {
this.ibeacon.requestAlwaysAuthorization();
let delegate = this.ibeacon.Delegate();
let region = this.ibeacon.BeaconRegion('ibirapuera','B9407F30-F5F8-466E-AFF9-25556B57FE6D');
this.ibeacon.startMonitoringForRegion(region)
.then(
() => console.log('Native layer recieved the request to monitoring'),
error => console.error('Native layer failed to begin monitoring: ', error)
)
delegate.didStartMonitoringForRegion()
.subscribe(
(data) => console.log("Started monitoring beacons", data)
)
delegate.didEnterRegion()
.subscribe(
(data) => {
this.beacon_found = true;
}
)
delegate.didExitRegion()
.subscribe(
(data) => {
console.log("Exit Region");
}
)
}
}
home.html
<div class="card-beacon" *ngIf="beacon_found">
</div>
The problem is that when I detect the beacon, the div is not being displayed. I read something about async databiding, but I have no idea how to do it.
Does anybody know how to solve it, please?
Thanks in advance.
I got it working using ChangeDetectorRef
import { Component, Input, ChangeDetectorRef } from '#angular/core';
export class HomePage {
beacon_found: boolean;
constructor(public navCtrl: NavController, public events: Events, public cdr: ChangeDetectorRef) {
events.subscribe('beacon:detected',(data) => {
this.beacon_found = true;
cdr.detectChanges();
})
events.subscribe('beacon:undetected',(data) => {
this.beacon_found = false;
cdr.detectChanges();
})
}
}
This is where you should use an rxjs BehaviorSubject:
beaconFoundSubject : BehaviorSubject<boolean> = new BehaviorSubject(false);
In your constructor (where NgZone may need to be injected and used to notify beaconFoundSubject):
constructor(private ngzone: NgZone) {
....
delegate.didEnterRegion()
.subscribe(
(data) => {
this.ngzone.run(() => this.beaconFoundSubject.next(true));
}
)
And then in your template:
<div class="card-beacon" *ngIf="beaconFoundSubject | async">
</div>
I'm new with Ionic2 and I was following this tutorial and a simple test like
describe('Dummy test', () => {
it('should do nothing', () => {
expect(true).toBeTruthy();
expect(1 + 1).toBe(2);
});
});
works fine, but for some reason I keep getting this error when I try to follow the rest of the tutorial.
Component: Root Component
✖ initialises with a root page of LoginPage
Firefox 45.0.0 (Linux 0.0.0)
TypeError: win is undefined in src/test.ts (line 937)
My src/test.ts is the same as the tutorial and it doesn't have any win in it. My app.spec.ts is this
import { TestBed, ComponentFixture, async } from '#angular/core/testing';
import { IonicModule } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { UserData } from '../providers/user-data';
import { LoginPage } from '../pages/login/login';
import { Platform } from 'ionic-angular';
import { MyApp } from './app.component';
import { LoginPage } from '../pages/login/login';
let comp: MyApp;
let fixture: ComponentFixture<MyApp>;
describe('Component: Root Component', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MyApp],
providers: [
StatusBar,
SplashScreen,
UserData,
Platform
],
imports: [
IonicModule.forRoot(MyApp)
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyApp);
comp = fixture.componentInstance;
});
afterEach(() => {
fixture.destroy();
comp = null;
});
it('initialises with a root page of LoginPage', () => {
expect(comp['rootPage']).toBe(LoginPage);
});
});
And my app.component.ts is this
import { Component } from '#angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { MenuSidePage } from '../pages/menu-side/menu-side';
import { LoginPage } from '../pages/login/login';
import { UserData } from '../providers/user-data';
#Component({
template: `<ion-nav #nav [root]="rootPage"></ion-nav>`
})
export class MyApp {
rootPage: any;
constructor(
public platform: Platform,
public statusBar: StatusBar,
public splashScreen: SplashScreen,
private userData: UserData,
) {
platform
.ready()
.then(() => {
//First - check if user is logged
if(this.userData.currentUser) {
this.rootPage = MenuSidePage;
} else {
this.rootPage = LoginPage;
}
statusBar.styleDefault();
splashScreen.hide();
});
}
}
I don't have yet the solution, but you shouldn't use compileComponents() 'cause you are using a template and not a templateUrl like said in this tutorial :
"We need to use compileComponents when we need to asynchronously compile a component, such as one that has an external template (one that is loaded through templateUrl and isn’t inlined with template). This is why the beforeEach block that this code runs in uses an async parameter – it sets up an asynchronous test zone for the compileComponents to run inside."
Hope it's a kind of helping :)
The win() function come from the Plaftorm, you have to mock it as follow :
export class PlatformMock {
public ready(): Promise<string> {
return new Promise((resolve) => {
resolve('READY');
});
}
public getQueryParam() {
return true;
}
public registerBackButtonAction(fn: Function, priority?: number): Function {
return (() => true);
}
public hasFocus(ele: HTMLElement): boolean {
return true;
}
public doc(): HTMLDocument {
return document;
}
public is(): boolean {
return true;
}
public getElementComputedStyle(container: any): any {
return {
paddingLeft: '10',
paddingTop: '10',
paddingRight: '10',
paddingBottom: '10',
};
}
public onResize(callback: any) {
return callback;
}
public registerListener(ele: any, eventName: string, callback: any): Function {
return (() => true);
}
public win(): Window {
return window;
}
public raf(callback: any): number {
return 1;
}
public timeout(callback: any, timer: number): any {
return setTimeout(callback, timer);
}
public cancelTimeout(id: any) {
// do nothing
}
public getActiveElement(): any {
return document['activeElement'];
}
}
Here is the link to see a project for real integration of this mock class.
Hope it helps :)
I have written a test for my component and it is failing with
Error: Cannot resolve all parameters for 'Router'(?, ?, ?, ?, ?, ?,
?). Make sure that all the parameters are decorated with Inject or
have valid type annotations and that 'Router' is decorated with
Injectable.
import { Component, OnInit } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { Supplier } from './supplier';
import { SupplierService } from './supplier.service';
import { AppService } from '../shared/app.service';
#Component({
moduleId: module.id,
selector: 'supplier-form',
templateUrl: './supplier-form.component.html',
styleUrls: ['./supplier-form.component.css']
})
export class SupplierFormComponent implements OnInit {
private countries: any;
private model: Supplier;
private errorMessage: string;
private submitted: boolean = false;
private active: boolean = true;
constructor(private appService: AppService, private supplierService: SupplierService, private router: Router, private route: ActivatedRoute) {
this.model = new Supplier();
this.route.params.subscribe(params => {
let id = +params['id']; // (+) converts string 'id' to a number
if (!isNaN(id))
this.supplierService.getSupplierById(id)
.subscribe(supplier => this.model = supplier, error => this.errorMessage = error);
});
}
ngOnInit() {
this.getCountries();
}
private getCountries() {
this.appService.getCountry()
.subscribe(countries => this.countries = countries.items,
error => this.errorMessage = error);
}
private navigateToHomePage(supplier) {
if (supplier) {
let link = [''];
this.router.navigate(link);
}
}
private onSubmit(): void {
this.submitted = true;
this.supplierService.saveSupplier(this.model).subscribe(
supplier => this.navigateToHomePage(supplier),
error => this.errorMessage = error);
}
}
very simple component all its doing is getting countries from a service which is using Http call and calling save method on another service which is also http call. I am mocking those services with my Mock classes. below is my test code.
import { By } from '#angular/platform-browser';
import { DebugElement, provide } from '#angular/core';
import { disableDeprecatedForms, provideForms } from '#angular/forms';
import { Router, ActivatedRoute } from '#angular/router';
import * as Rx from 'rxjs/Rx';
import {
beforeEach, beforeEachProviders,
describe, xdescribe,
expect, it, xit,
async, inject, addProviders,
TestComponentBuilder, ComponentFixture
} from '#angular/core/testing';
import { SupplierFormComponent } from './supplier-form.component';
import { SupplierService } from './supplier.service';
import { AppService } from '../shared/app.service';
describe('Component: Supplier', () => {
var builder;
beforeEachProviders(() => {
return [
disableDeprecatedForms(),
provideForms(),
Router, ActivatedRoute,
provide(AppService, { useClass: MockAppService }),
provide(SupplierService, { useClass: MockSupplierService })
];
});
beforeEach(inject([TestComponentBuilder], (tcb) => {
builder = tcb;
}));
it('should create Supplier Component', async(() => {
/*.overrideProviders(
SupplierFormComponent,
[{ provide: AppService, useClass: MockAppService }]
)*/
builder.createAsync(SupplierFormComponent)
.then((fixture: ComponentFixture<SupplierFormComponent>) => {
fixture.detectChanges
var compiled = fixture.debugElement.nativeElement;
console.log(compiled);
})
.catch((error) => {
console.log("error occured: " + error);
});
}));
});
class MockAppService {
public name = "Injected App Service";
public fakeResponse: any = [{ "id": 1, "name": "uk" }];
public getCountry() {
return this.fakeResponse;
}
}
class MockSupplierService {
public name = "Injected Supplier Service";
saveSupplier(supplier: any): boolean {
return true;
}
}
any idea how can i mock router properly with RC.4.