NullInjectorError: No provider for InjectionToken Window - ngxs

I have been trying to debug this issue but I have had no success. I believe it's a lack of import of a nebular service or provider but I am not sure which one or where to find it.
my search.component.spec.ts
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { HttpClientTestingModule } from '#angular/common/http/testing';
import { NgxsModule, Store } from '#ngxs/store';
import { of } from 'rxjs';
import { SearchComponent } from './search.component';
import { NbAutocompleteModule, NbInputModule, NbOverlay, NbOverlayService, NbTriggerStrategyBuilderService, NbWindowService, NB_WINDOW } from '#nebular/theme';
import { InjectionToken } from '#angular/core';
describe('SearchComponent', () => {
let component: SearchComponent;
let fixture: ComponentFixture<SearchComponent>;
let store: Store;
let windowMock: NbWindowService = { } as any;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SearchComponent ],
imports: [NgxsModule.forRoot([]), HttpClientTestingModule, NbAutocompleteModule, NbInputModule ],
providers: [ NbWindowService, NbTriggerStrategyBuilderService,
{provide: NB_WINDOW, useClass: InjectionToken }
,
{ provide: NbOverlayService, useClass: NbOverlay }]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SearchComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
const store:Store = TestBed.inject(Store);
spyOn(store, 'select').and.returnValue(of(null));
spyOn(store, 'selectSnapshot').and.returnValue(null);
expect(component).toBeTruthy();
});
});
my search.component.html
<input #autoInput
nbInput
type="text"
(input)="onChange()"
placeholder="Search for companies"
[nbAutocomplete]="auto"
class= "search__input" />
<nb-autocomplete #auto (selectedChange)="onSelectionChange($event)">
<nb-option *ngFor="let option of filteredOptions$ | async" [value]="option">
{{ option }}
</nb-option>
</nb-autocomplete>
It's the bog-standard search component provided by nebular https://akveo.github.io/nebular/docs/components/autocomplete/overview#nbautocompletedirective
SearchComponent > should create
NullInjectorError: R3InjectorError(DynamicTestModule)[InjectionToken Window -> InjectionToken Window]:
NullInjectorError: No provider for InjectionToken Window!
error properties: Object({ ngTempTokenPath: null, ngTokenPath: [ 'InjectionToken Window', 'InjectionToken Window' ] })
at <Jasmine>
at NullInjector.get (http://localhost:63217/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:915:1)
at R3Injector.get (http://localhost:63217/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:11081:1)
at R3Injector.get (http://localhost:63217/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:11081:1)
at NgModuleRef$1.get (http://localhost:63217/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:24198:1)
at Object.get (http://localhost:63217/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:22101:1)
at getOrCreateInjectable (http://localhost:63217/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:3921:1)
at Module.ɵɵdirectiveInject (http://localhost:63217/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:13752:1)
at NodeInjectorFactory.NbMenuComponent_Factory [as factory] (http://localhost:63217/_karma_webpack_/node_modules/#nebular/theme/__ivy_ngcc__/fesm2015/index.js:9693:120)
at getNodeInjectable (http://localhost:63217/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:4029:1)
at instantiateRootComponent (http://localhost:63217/_karma_webpack_/node_modules/#angular/core/__ivy_ngcc__/fesm2015/core.js:7825:1)

Related

Nativescript + angular : blank page on tab view after upgrading to 8.2.0 without any error

Environment
CLI: 6.0.3
Cross-platform modules:6.0.0
Android Runtime:6.0.2
iOS Runtime:6.0.2
Plugin(s):
NativeScript-Angular:8.2.0
Angular:8.2.0
After upgrading to the latest cli and nativescript-angular I get a blank white screen when I start the app which opens the page tab based, but when I try to output something using the component ts file I can get it on the console. The problem is only at the template level (I get a blank page).
this is my app.modules.ts file:
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { CoreModule } from "./core/core.module";
import { SharedModule } from "./shared/shared.module";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { NativeScriptCommonModule } from "nativescript-angular/common";
import { TNSImageModule } from 'nativescript-image/angular';
import * as applicationModule from "tns-core-modules/application";
import * as imageModule from "nativescript-image";
declare var GMSServices: any;
if (applicationModule.android) {
applicationModule.on(applicationModule.launchEvent, () => {
console.log('initialize pipeline');
imageModule.initialize();
});
} else {
GMSServices.provideAPIKey("*********");
}
// Uncomment and add to NgModule imports if you need to use two-way binding
// import { NativeScriptFormsModule } from "nativescript-angular/forms";
// Uncomment and add to NgModule imports if you need to use the HttpClient wrapper
// import { NativeScriptHttpClientModule } from "nativescript-angular/http-client";
#NgModule({
bootstrap: [AppComponent],
imports: [NativeScriptCommonModule, CoreModule, SharedModule, TNSImageModule, AppRoutingModule],
declarations: [AppComponent],
providers: [],
schemas: [NO_ERRORS_SCHEMA]
})
/*
Pass your application module to the bootstrapModule function located in main.ts to start your app
*/
export class AppModule {}
this is the app-routing.modules.ts
import { NgModule } from "#angular/core";
import { NativeScriptRouterModule } from "nativescript-angular/router";
//import { hasKey } from "tns-core-modules/application-settings";
import { Routes } from "#angular/router";
//const homePath = (hasKey('skipLoginScreen') ? 'home/tabs':'auth/login');
const routes: Routes = [
{
path: "",
redirectTo: "home",
pathMatch: "full"
},
{
path: "home",
loadChildren: "~/app/home/home.module#HomeModule"
},
{
path: "products",
loadChildren: "~/app/products/products.module#ProductsModule"
},
{
path: "auth",
loadChildren: "~/app/auth/auth.module#AuthModule"
},
{
path: "account",
loadChildren: "~/app/account/account.module#AccountModule"
},
{
path: "cart",
loadChildren: "~/app/cart/cart.module#CartModule"
}
];
#NgModule({
imports: [NativeScriptRouterModule.forRoot(routes, { enableTracing: true } )],
exports: [NativeScriptRouterModule]
})
export class AppRoutingModule {}
this is my home-routing.module.ts:
import { NgModule } from "#angular/core";
import { Routes } from "#angular/router";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { TabsComponent } from "./tabs.component";
import { HomeComponent } from "./home-tab/home.component";
import { CategoriesComponent } from "./categories-tab/categories.component";
import { InfoComponent } from "./info-tab/info.component";
import { LocationsComponent } from "./locations-tab/locations.component";
import { AccountComponent } from "./account-tab/account.component";
export const COMPONENTS = [TabsComponent, HomeComponent, CategoriesComponent, InfoComponent, LocationsComponent, AccountComponent];
const routes: Routes = [
{
path: "",
redirectTo: "tabs",
pathMatch: "full"
},
{
path: "tabs",
component: TabsComponent,
children: [{ path: "home", component: HomeComponent, outlet: "homeTab" }, { path: "categories", component: CategoriesComponent, outlet: "categoriesTab" }, { path: "info", component: InfoComponent, outlet: "infoTab" }, { path: "locations", component: LocationsComponent, outlet: "locationsTab" }, { path: "account", component: AccountComponent, outlet: "accountTab" }]
}
];
#NgModule({
imports: [NativeScriptRouterModule.forChild(routes)],
exports: [NativeScriptRouterModule]
})
export class HomeRoutingModule {}
this is my home.module.ts:
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { HomeRoutingModule, COMPONENTS } from "./home-routing.module";
import { SharedModule } from "../shared/shared.module";
import { PushNotificationsService } from './../core/services/push-notifications.service';
// Uncomment and add to NgModule imports if you need to use two-way binding
// import { NativeScriptFormsModule } from "nativescript-angular/forms";
// Uncomment and add to NgModule imports if you need to use the HttpClient wrapper
// import { NativeScriptHttpClientModule } from "nativescript-angular/http-client";
#NgModule({
imports: [SharedModule, HomeRoutingModule],
providers: [PushNotificationsService],
declarations: [...COMPONENTS],
schemas: [NO_ERRORS_SCHEMA]
})
/*
Pass your application module to the bootstrapModule function located in main.ts to start your app
*/
export class HomeModule {}
this is my tabs.component.ts:
import { Component, OnInit } from "#angular/core";
import { Page } from "tns-core-modules/ui/page";
import { RouterExtensions } from "nativescript-angular/router";
import { DataService } from "../core/services/data.service";
import { ActivatedRoute } from "#angular/router";
#Component({
selector: "tabs",
moduleId: module.id,
templateUrl: "./tabs.component.html"
})
export class TabsComponent implements OnInit {
selectedIndex: number = 4;
constructor(private page: Page, private activeRoute: ActivatedRoute, private dataService: DataService, private routerExt: RouterExtensions) {}
ngOnInit(): void {
this.page.actionBarHidden = true;
this.routerExt.navigate([{ outlets: { homeTab: ["home"], infoTab: ["info"], categoriesTab: ["categories"], accountTab: ["account"], locationsTab: ["locations"] } }], { relativeTo: this.activeRoute });
this.dataService.getActivatedTab().subscribe(index => {
this.selectedIndex = index;
});
}
onTabChanged(args) {
setTimeout(() => {
this.dataService.setActivatedTab(args.newIndex);
}, 30);
}
}

Jasmine testcase for angular2 router.navigate()

I am having a app.component.html file with button to navigate to another component called HomeComponent
<button (click)="nav()" id="nav">Navigate</button>
<router-outlet></router-outlet>
My app.component.ts file
import { Component } from '#angular/core';
import { RouterModule,Router, Routes } from '#angular/router';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
constructor(private router: Router){
}
nav(){
this.router.navigate(['/home']);
}
}
and my app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { RouterModule, Routes,Router } from '#angular/router';
#NgModule({
declarations: [
AppComponent,
HomeComponent
],
imports: [
BrowserModule,
RouterModule.forRoot([{ path: "", component: AppComponent}]),
RouterModule.forChild([{ path: "home", component: HomeComponent}])
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Here is my spec file app.component.spec.ts
import { TestBed, async, ComponentFixture, fakeAsync, tick,inject } from '#angular/core/testing';
import { By, BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { DebugElement } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { Router, RouterOutlet } from "#angular/router";
import { FormsModule } from "#angular/forms";
import { RouterTestingModule } from '#angular/router/testing';
import * as br from '#angular/platform-browser';
describe('Component:AppComponent', () => {
let location, router;
let mockRouter
beforeEach(() => {
mockRouter = {
navigate: jasmine.createSpy('navigate')
};
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([
{ path: 'home', component: HomeComponent }
])],
declarations: [AppComponent, HomeComponent]
});
});
it('should go home', async(() => {
let fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
console.log(mockRouter.navigate);
let component = TestBed.createComponent(AppComponent).componentInstance;
component.nav();
spyOn(component, 'nav');
fixture.detectChanges();
expect(mockRouter.navigate).toHaveBeenCalledWith(['/home']);
}));
});
I am getting the result as
In order to create unit test case for router.navigate you can do something like this:
import { TestBed, async, ComponentFixture, fakeAsync, tick,inject } from '#angular/core/testing';
import { By, BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { DebugElement } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { Router, RouterOutlet } from "#angular/router";
import { FormsModule } from "#angular/forms";
import { RouterTestingModule } from '#angular/router/testing';
import * as br from '#angular/platform-browser';
describe('Component:AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [AppComponent, HomeComponent]
});
});
it('should go home', async(inject([Router], (router) => {
spyOn(router, 'navigate'); //added a spy on router
let fixture = TestBed.createComponent(AppComponent);
let component = TestBed.createComponent(AppComponent).componentInstance;
component.nav();
expect(router.navigate).toHaveBeenCalled();
expect(router.navigate).toHaveBeenCalledWith(['/home']);
}));
});
You have spied on router but you haven't provided it to the testBed environment. Try adding
providers: [
{ provide: Router, useValue: mockRouter},
],
after declarations.
Also you need not include RouterTestingModule since you are not clicking any links.
References:
https://stackoverflow.com/a/46342813/8558515
Angular 2 Unit Testing - Cannot read property 'root' of undefined

NgxLocalStorage Doesn't Retrieve Value

I'm learning how to use the Visual Studio 2017 SPA Template for Angular 2.
For this exercise I would just like my HomeComponent to display the name of the logged on user stored in local storage (NgxLocalStorage) after logging in on my AppLoginComponent. https://www.npmjs.com/package/ngx-localstorage
I've researched this issue and I believe I'm going down the right track but for some reason my HomeComponent doesn't see the key/value pair in localStorage. However, I can see it in Chrome's Developer Tools after I set it in login().
NgxLocalStorage has a method called get, not getItem but it appears to work the same way as getItem. Unfortunately it's not retrieving my value.
I'm pretty new to Angular 2, I'm sure I'm just missing something somewhere, please help.
I have imported NgxLocalStorageModule into NgModule in app.module.shared:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { RouterModule } from '#angular/router';
import { NgxLocalStorageModule } from 'ngx-localstorage';
import { AppComponent } from './components/app/app.component';
import { NavMenuComponent } from './components/navmenu/navmenu.component';
import { HomeComponent } from './components/home/home.component';
import { AppLoginComponent } from './components/applogin/applogin.component';
import { FacebookService, FacebookModule } from 'ngx-facebook/dist/esm/index';
#NgModule({
declarations: [
AppComponent,
NavMenuComponent,
HomeComponent,
AppLoginComponent
],
imports: [
CommonModule,
HttpModule,
FormsModule,
RouterModule.forRoot([
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'applogin', component: AppLoginComponent },
{ path: '**', redirectTo: 'home' }
]),
FacebookModule.forRoot(),
NgxLocalStorageModule.forRoot()
],
providers: [FacebookService, NgxLocalStorageModule]
})
export class AppModuleShared {
}
In my HomeComponent I have:
import { Component } from '#angular/core';
import { LocalStorageService } from 'ngx-localstorage';
#Component({
selector: 'home',
templateUrl: './home.component.html'
})
export class HomeComponent {
currentUser: string;
constructor(private localStorage: LocalStorageService) {
this.currentUser = JSON.parse(localStorage.get('currentUser') || '');
}
}
In AppLoginComponent I have:
import { Component, NgZone } from '#angular/core';
import { FacebookService, InitParams, LoginResponse } from 'ngx-facebook/dist/esm/index';
import { LocalStorageService } from 'ngx-localstorage';
#Component({
selector: 'applogin',
templateUrl: './applogin.component.html'
})
export class AppLoginComponent {
public loggedIn = false;
name = "";
constructor(private _ngZone: NgZone, private fb: FacebookService, localStorage: LocalStorageService) {
let initParams: InitParams = {
appId: '123456789',
xfbml: true,
version: 'v2.8'
};
fb.init(initParams);
}
login() {
var self = this;
this.fb.login()
.then((res: LoginResponse) => {
if (res.authResponse) {
this.fb.api('/me')
.then((res: any) => {
self._ngZone.run(() => {
self.name = res.name;
self.loggedIn = true;
localStorage.setItem('currentUser', res.name);
});
});
} else {
alert('Not authorized.');
}
})
.catch();
}
I have created plunker where everything works. You press login button it will navigate to different component and show user in console the only difference from your code i used
this.localStorage.set('item', item);
and this.localStorage.get('item');
also in your code
this.fb.api('/me')
.then((res: any) => {
self._ngZone.run(() => {
self.name = res.name;
self.loggedIn = true;
localStorage.setItem('currentUser', res.name);
});
});
you can't use like this services outside constructor and don't use self you need to add 'this'. and in you constructor prefix localStorage with private
and do initialization better in OnInit hook.
import { Component, NgZone, OnInit } from '#angular/core';
import { FacebookService, InitParams, LoginResponse } from 'ngx-facebook/dist/esm/index';
import { LocalStorageService } from 'ngx-localstorage';
#Component({
selector: 'applogin',
templateUrl: './applogin.component.html'
})
export class AppLoginComponent implements OnInit {
public loggedIn = false;
name = "";
constructor(private _ngZone: NgZone, private fb: FacebookService, private localStorage: LocalStorageService) {
}
ngOnInit() {
let initParams: InitParams = {
appId: '123456789',
xfbml: true,
version: 'v2.8'
};
fb.init(initParams);
}
login() {
this.fb.login()
.then((res: LoginResponse) => {
if (res.authResponse) {
this.fb.api('/me')
.then((res: any) => {
this._ngZone.run(() => {
this.name = res.name;
this.loggedIn = true;
this.localStorage.set('currentUser', res.name);
});
});
} else {
alert('Not authorized.');
}
})
.catch();
}
and in app.module.shared.ts remove this line
providers: [FacebookService, NgxLocalStorageModule]
cause forRoot is importing them already. should be like this
#NgModule({
declarations: [
AppComponent,
NavMenuComponent,
HomeComponent,
AppLoginComponent
],
imports: [
CommonModule,
HttpModule,
FormsModule,
RouterModule.forRoot([
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'applogin', component: AppLoginComponent },
{ path: '**', redirectTo: 'home' }
]),
FacebookModule.forRoot(),
NgxLocalStorageModule.forRoot()
]
})
export class AppModuleShared {
}
and the last
import { FacebookService, FacebookModule } from 'ngx-facebook/dist/esm/index';
try to use import without dist
import { FacebookModule } from 'ngx-facebook';
The input has to be a string. You can put in some mock data like
localStorage.setItem('currentUser', 'TrevorBrooks');
and retrieve it via get to be sure there is a item saved. And check what data type you are sending. Is it a user object or is it just the name?
Greetings
You should use NgOnInit, is the best approach for your problem than using the constructor since the constructor is for initialization, dependency injection among others.. so, what could be happening is that the data is not yet available by the time you request it. Besides in the npmjs.com page they clearly add an example using ngOnInit so i guess they saw this issue coming.
In your components, do import { .., OnInit, .. } from '#angular/core';
`
so you'd have something like:
import { Component, NgZone, OnInit } from '#angular/core';
and in your component export class:
export class AppLoginComponent implements OnInit{
ngOnInit() {
//write your code here
}
1.Make sure you have been installed the local storage module from npm
npm install --save angular2-localstorage
2.Import the WebStorageModule in your app module:
import {Component} from "angular2/core";
import {WebStorageModule, LocalStorageService} from "angular2-localstorage";
#NgModule({
import: [WebStorageModule]
#Component({
providers: [LocalStorageService]
})
export class AppModule {}
2.Use the LocalStorage decorator
import {LocalStorage, SessionStorage} from "angular2-localstorage/WebStorage";
class MySuperComponent {
#LocalStorage() public lastSearchQuery:Object = {};
#LocalStorage('differentLocalStorageKey') public lastSearchQuery:Object = {};
}
Example
#Component({
selector: 'app-login',
template: `
<form>
<div>
<input type="text" [(ngModel)]="username" placeholder="Username" />
<input type="password" [(ngModel)]="password" placeholder="Password" />
</div>
<input type="checkbox" [(ngModel)]="rememberMe" /> Keep me logged in
<button type="submit">Login</button>
</form>
`
})
class AppLoginComponent {
//here happens the magic. `username` is always restored from the localstorage when you reload the site
#LocalStorage() public username:string = '';
public password:string;
//here happens the magic. `rememberMe` is always restored from the localstorage when you reload the site
#LocalStorage() public rememberMe:boolean = false;
}
View
#Component({
selector: 'admin-menu',
template: `
<div *ngFor="#menuItem of menuItems() | mapToIterable; #i = index">
<h2 (click)="hiddenMenuItems[i] = !!!hiddenMenuItems[i]">
{{i}}: {{category.label}}
</h2>
<div style="padding-left: 15px;" [hidden]="hiddenMenuItems[i]">
<a href>Some sub menu item 1</a>
<a href>Some sub menu item 2</a>
<a href>Some sub menu item 3</a>
</div>
</div>
`
})
class AdminMenuComponent {
public menuItems = [{title: 'Menu1'}, {title: 'Menu2'}, {title: 'Menu3'}];
//here happens the magic. `hiddenMenuItems` is always restored from the localstorage when you reload the site
#LocalStorage() public hiddenMenuItems:Array<boolean> = [];
//here happens the magic. `profile` is always restored from the sessionStorage when you reload the site from the current tab/browser. This is perfect for more sensitive information that shouldn't stay once the user closes the browser.
#SessionStorage() public profile:any = {};
}
For more Clarification refer this link link

No provider for Store! Error at injectionError

app.component.html
<page-router-outlet></page-router-outlet>
app.component.ts
import 'rxjs/add/operator/let';
import { Component, ViewEncapsulation } from '#angular/core';
import { EchoesState, getSidebarCollapsed$ } from './core/store';
import { Store } from '#ngrx/store';
#Component({
selector: "ns-app",
templateUrl: "app.component.html",
})
export class AppComponent {
constructor(private store: Store<EchoesState>){}
}
app.module.ts
import 'nativescript-localstorage';
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { NativeScriptFormsModule } from "nativescript-angular/forms";
import { AppRoutingModule } from "./app.routing";
import { AppComponent } from "./app.component";
import { ItemService } from "./item/item.service";
import { ItemsComponent } from "./item/items.component";
import { ItemDetailComponent } from "./item/item-detail.component";
#NgModule({
bootstrap: [
AppComponent
],
imports: [
NativeScriptModule,
AppRoutingModule
],
declarations: [
AppComponent,
ItemsComponent,
ItemDetailComponent
],
providers: [
ItemService
],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class AppModule { }
app.routing.ts
import { NgModule } from "#angular/core";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { Routes } from "#angular/router";
import { ItemsComponent } from "./item/items.component";
import { ItemDetailComponent } from "./item/item-detail.component";
const routes: Routes = [
{ path: "", redirectTo: "/items", pathMatch: "full" },
{ path: "items", component: ItemsComponent },
{ path: "item/:id", component: ItemDetailComponent },
];
#NgModule({
imports: [NativeScriptRouterModule.forRoot(routes)],
exports: [NativeScriptRouterModule]
})
export class AppRoutingModule { }
main.aot.ts
import { platformNativeScript } from "nativescript-angular/platform-static";
import { AppModuleNgFactory } from "./app.module.ngfactory";
platformNativeScript().bootstrapModuleFactory(AppModuleNgFactory);
main.ts
import { platformNativeScriptDynamic } from "nativescript-angular/platform";
import { AppModule } from "./app.module";
platformNativeScriptDynamic().bootstrapModule(AppModule);
package.json
{
"android": {
"v8Flags": "--expose_gc"
},
"main": "main.js",
"name": "tns-template-hello-world-ng",
"version": "3.0.0"
}
store/index.js:
import { Observable } from 'rxjs/Observable';
import { NgModule } from '#angular/core';
import { StoreModule, combineReducers } from '#ngrx/store';
import { compose } from '#ngrx/core/compose';
import { StoreDevtoolsModule } from '#ngrx/store-devtools';
import { localStorageSync } from 'ngrx-store-localstorage';
import 'rxjs/add/operator/let';
import { environment } from '../../environments/environment';
import { getSidebarExpanded } from './app-layout';
import { getAppReducersRegistry, EchoesState, EchoesReducers, EchoesActions } from './reducers';
export { EchoesState } from './reducers';
const actions = EchoesActions; // storeAssets.actions;
const reducers = EchoesReducers; // storeAssets.reducers;
const composeStore = reducers;
const optionalImports = [];
const productionReducer = compose(localStorageSync(Object.keys(reducers), true), combineReducers)(reducers);
export function appReducer(state: any, action: any) {
return productionReducer(state, action);
}
if (!environment.production) { optionalImports.push(StoreDevtoolsModule.instrumentOnlyWithExtension());
}
#NgModule({
imports: [
StoreModule.provideStore(appReducer),
...optionalImports
],
declarations: [],
exports: [],
providers: [ ...actions ]
})
export class CoreStoreModule {
constructor() {
console.log('CoreStoreModule initiated:', reducers);
}
};
function getAppLayoutState(state$: Observable<EchoesState>) {
return state$.select(state => state.appLayout);
}
export function getSidebarCollapsed$(state$: Observable<EchoesState>) {
return state$.select((state) => state.appLayout.sidebarExpanded);
}
store/reducers.ts
import { AppLayout, AppLayoutActions, appLayout, appLayoutRegister } from './app-layout';
import { NowChannellistActions, NowChannellistInterface, nowChannellist, nowChannellistRegister } from './now-channellist';
import { NowPlaylistActions, NowPlaylistInterface, nowPlaylist, nowPlaylistRegister } from './now-playlist';
// reducers
import { PlayerActions, YoutubePlayerState, player, playerRegister } from './youtube-player';
import { UploadsList, VideosListActions, search, searchRegister } from './uploads-list';
import { UserProfileActions, UserProfileData, user, userRegister } from './user-profile';
import { Observable } from 'rxjs/Observable';
export interface EchoesState {
player: YoutubePlayerState;
nowPlaylist: NowPlaylistInterface;
nowChannellist: NowChannellistInterface;
user: UserProfileData;
search: UploadsList;
appLayout: AppLayout;
};
export let EchoesReducers = {
player,
nowPlaylist,
nowChannellist,
user,
search,
appLayout,
};
export let EchoesActions = [
PlayerActions,
NowPlaylistActions,
NowChannellistActions,
UserProfileActions,
VideosListActions,
AppLayoutActions
];
export function getAppReducersRegistry() {
return [
playerRegister,
nowPlaylistRegister,
nowChannellistRegister,
userRegister,
searchRegister,
appLayoutRegister
];
};
export function getPlayer$ (state$: Observable<EchoesState>): Observable<YoutubePlayerState> {
return state$.select(state => state.player);
};
export function getPlayerSearch$ (state$: Observable<EchoesState>): Observable<UploadsList> {
return state$.select(state => state.search);
};
export function getPlayerSearchResults$ (state$: Observable<EchoesState>): Observable<any[]> {
return state$.select(state => state.search.results);
};
export function getAppLayout$ ($state: Observable<EchoesState>): Observable<AppLayout> {
return $state.select(state => state.appLayout);
};
export function getNowPlaylist$ ($state: Observable<EchoesState>): Observable<NowPlaylistInterface> {
return $state.select(state => state.nowPlaylist);
};
export function getNowChannellist$ ($state: Observable<EchoesState>): Observable<NowChannellistInterface> {
return $state.select(state => state.nowChannellist);
};
The error I am getting is:
No provider for Store!
Error
at injectionError (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:1238:86)
[angular]
at noProviderError (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:1276:12)
[angular]
at ReflectiveInjector_._throwOrNull (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:2777:19)
[angular]
at ReflectiveInjector_._getByKeyDefault (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:2816:25)
[angular]
at ReflectiveInjector_._getByKey (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:2748:25)
[angular]
at ReflectiveInjector_.get (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:2617:21)
[angular]
at AppModuleInjector.NgModuleInjector.get (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:3585:52)
[angular]
at resolveDep (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:11046:45)
[angular]
at createClass (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:10899:35)
[angular]
at createDirectiveInstance (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:10730:37)
[angular]
at createViewNodes (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:12093:49)
[angular]
at createRootView (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:11998:5)
[angular]
at callWithDebugContext (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:13213:42)
[angular]
at Object.debugCreateRootView [as createRootView] (file:///data/data/org.nativescript.MyApptarchec/files/app/tns_modules/#angular/core/bundles/core.umd.js:12673:12)
[angular]
I know this question seems dead, but for info, the provideStore function doesn't exist anymore, you should do
StoreModule.forRoot(/*your reducers here*/)
You need to add the provider to the NgModule, i.e module.ts under providers,
providers: [
Store
]
You should import Store in your main module (app.module.ts):
imports: [
StoreModule.provideStore({ /* your reducers here... */ }),
...

Angular 2 unit test for component

I am using ng2 with webpack 2.
I cant figure out how to test component functions
Here is my component
import { Component, OnInit } from '#angular/core';
import { GlobalDataService } from '../global.service';
import { Router } from '#angular/router';
#Component({
selector: 'login',
templateUrl: './login.component.html'
})
export class LoginComponent {
constructor(private gd: GlobalDataService, private router: Router) { }
login(): void {
this.gd.shareObj['role'] = 'admin';
this.router.navigateByUrl('/login');
}
}
I would like to test login() function and see, if this.gd.shareObj['role'] = 'admin'; is truly set as admin.
What could .spec.ts file look like?
I would do it as follows:
class RouterStub {
navigateByUrl(url: String) { return url; }
}
class GlobalDataServiceStub {
shareObj: any = {};
}
describe('LoginComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [LoginComponent],
providers: [
{ provide: GlobalDataService, useClass: GlobalDataServiceStub },
{ provide: Router, useClass: RouterStub }
]
});
fixture = TestBed.createComponent(LoginComponent);
comp = fixture.componentInstance;
});
it('should set role to admin',
inject([GlobalDataService], (gd: GlobalDataService) => {
comp.login();
expect(gd.shareObj['role']).toBe('admin');
})
);
});
Plunker Example

Resources