Angular Jasmine Karma Background Image Component Test - angularjs

I am new to Angular JS and I would like to test if the background image that I have on my header component is loaded correctly. However, on the console log, it says that the image file is not found.
Here's the whole code for your reference:
HTML:
**<div class="flex-container" [ngStyle]="{'background-image' : 'url('+ bgImage +')'}">**
<div class="text-container">
<h1>{{ title }}</h1>
<p>{{ description }}</p>
<a [href]="buttonLink" target="_blank"><button>{{ buttonText }}</button></a>
</div>
</div>
Component.ts:
import { Component, Input, OnInit } from '#angular/core';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
#Input() title: string;
#Input() description: string;
#Input() buttonText: string;
#Input() buttonLink: string;
**#Input() bgImage: string;**
constructor() { }
ngOnInit(): void {
}
}
Component.spec.ts:
import { ComponentFixture, TestBed } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { HeaderComponent } from './header.component';
describe('HeaderComponent', () => {
let component: HeaderComponent;
let fixture: ComponentFixture<HeaderComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ HeaderComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(HeaderComponent);
component = fixture.componentInstance;
});
it('should create', () => {
fixture.detectChanges();
expect(component).toBeTruthy();
});
it('should render all inputs', () => {
component.title = 'test'
component.description = 'test-description'
**component.bgImage = 'bgImageIllustrations.jpg'**
fixture.detectChanges();
const title = fixture.debugElement.query(By.css('h1')).nativeElement as HTMLElement
const description = fixture.debugElement.query(By.css('p')).nativeElement as HTMLElement
**const bgImage = fixture.debugElement.query(By.css('.flex-container')).nativeElement as HTMLElement;**
expect(title.textContent).toBe('test');
expect(description.textContent).toBe('test-description');
**console.log(getComputedStyle(bgImage).backgroundImage);**
});
});
Hope you can help me to fix this issue. Thanks!
I would like to see if I am loading the right background image

Related

React, How to use a menu in a seperate file to call an api and return data to a different section of the main file

I have a react app with a large menu, and as such am trying to move it to a seperate file from the main app.js
at the mement when you click on a link in the menu it call a node api and which returns some data, however when I try to seperate I can not get it to populate the results section which is still in the main script
Working version app.js
import React,{ useState } from 'react';
import './App.css';
import axios from 'axios';
import { Navigation } from "react-minimal-side-navigation";
import "react-minimal-side-navigation/lib/ReactMinimalSideNavigation.css";
export default class MyList extends React.Component {
constructor(props) {
super(props);
this.state = {
result: [],
};
this.callmyapi = this.callmyapi.bind(this);
}
render() {
return (
<div>
<div class="menu">
<Navigation
onSelect={({itemId}) => {
axios.get(`/api/menu/`, {
params: {
Menu: itemId,
}
})
.then(res => {
const results = res.data;
this.setState({ results });
})
.catch((err) => {
console.log(err);
})
}}
items={[
{
title: 'Pizza',
itemId: '/menu/Pizza/',
},
{
title: 'Cheese',
itemId: '/menu/cheese',
}
]}
/>
</div>
<div class="body">
this.state.results && this.state.results.map(results => <li>* {results.Name}</li>);
</div>
</div>
);
}
}
New app.js
import React,{ useState } from 'react';
import './App.css';
//import axios from 'axios';
//import { Navigation } from "react-minimal-side-navigation";
//import "react-minimal-side-navigation/lib/ReactMinimalSideNavigation.css";
import MyMenu from './mymenu';
export default class MyList extends React.Component {
constructor(props) {
super(props);
this.state = {
result: [],
};
this.callmyapi = this.callmyapi.bind(this);
}
render() {
return (
<div>
<div class="menu">
<MyMenu />
</div>
<div class="body">
this.state.results && this.state.results.map(results => <li>* {results.Name}</li>);
</div>
</div>
);
}
}
New menu file
mymenu.js
import React, { Component } from 'react';
import axios from 'axios';
import './App.css';
//import MyList from './App.js';
//import { ProSidebar, Menu, MenuItem, SubMenu } from 'react-pro-sidebar';
//import 'react-pro-sidebar/dist/css/styles.css';
import { Navigation } from "react-minimal-side-navigation";
//import Icon from "awesome-react-icons";
import "react-minimal-side-navigation/lib/ReactMinimalSideNavigation.css";
//export default async function MyMenu(){
export default class MyMenu extends React.Component {
constructor(props) {
super(props);
};
render() {
return (
<div>
<Navigation
// you can use your own router's api to get pathname
activeItemId="/management/members"
onSelect={({itemId}) => {
// return axios
axios.get(`/api/menu/`, {
params: {
// Menu: itemId,
Menu: "meat",
SubMenu : "burgers"
}
})
.then(res => {
const results = res.data;
this.setState({ results });
})
.catch((err) => {
console.log(err);
})
}}
items={[
{
title: 'Pizza',
itemId: '/menu/Pizza/',
},
{
title: 'Cheese',
itemId: '/menu/cheese',
}
]}
/>
</div>
);
}
}
Any help would be greatly appreciated
That one is quite easy once you understand state. State is component specific it that case. this.state refers to you App-Component and your Menu-Component individually. So in order for them to share one state you have to pass it down the component tree like this.
export default class MyList extends React.Component {
constructor(props) {
super(props);
this.state = {
result: [],
};
}
render() {
return (
<div>
<div class="menu">
<MyMenu handleStateChange={(results: any[]) => this.setState(results)} />
</div>
<div class="body">
this.state.results && this.state.results.map(results => <li>* {results.Name}</li>);
</div>
</div>
);
}
}
See this line: <MyMenu handleStateChange={(results: any[]) => this.setState(results)} />
There you pass a function to mutate the state of App-Component down to a the child
There you can call:
onSelect={({itemId}) => {
// return axios
axios.get(`/api/menu/`, {
params: {
// Menu: itemId,
Menu: "meat",
SubMenu : "burgers"
}
})
.then(res => {
const results = res.data;
this.props.handleStateChange(results)
})
.catch((err) => {
console.log(err);
})
You mutate the parent state and the correct data is being rendered. Make sure to practice state and how it works and how usefull patterns look like to share state between components.
Thanks - I Have found solution (also deleted link question)
above render added function
handleCallback = (results) =>{
this.setState({data: results})
}
then where I display the menu
<MyMenu parentCallback = {this.handleCallback}/>
where i display the results
{this.state.results && this.state.results.map(results => <li>{results.Name}</li>}
No aditional changes to the menu scripts

Testing MobX Component

I am facing an issue of how to test a component in Mobx that we are passing props to.
I am using Jest and I just want to make a simple snapshot test.
Next to default export I am also using named export of just the component so #inject and #observer don't influence it. I should just pass my own 'expenses' and 'filters' as a prop but it is not working.
So this is my component. I am passing RootStore as a prop to that component.
ExpenseList Component
#inject('RootStore')
#observer
export class ExpenseList extends Component {
render() {
const {expenses} = this.props.RootStore.ExpensesStore
const {filters} = this.props.RootStore.FiltersStore
const expensesFilter = selectExpense(expenses, filters)
return (
<div>
{
expenses.length === 0 ? (
<p>No expenses</p>
) : (
expensesFilter.map((expense) => {
return <ExpenseListItem key={expense.id} {...expense} />
})
)
}
</div>
)
}
}
ExpenseList.test.js
import React from 'react'
import { shallow } from 'enzyme'
import { ExpenseList } from '../../components/ExpenseList'
import expenses from '../fixtures/expenses'
test('should render ExpenseList with expenses', () => {
// const wrapper = shallow(<ExpenseList RootStore={{'ExpensesStore':{'expenses':expenses}}}/>)
const wrapper = shallow(<ExpenseList
RootStore={
{
'ExpensesStore':{
'expenses':expenses
},
'FiltersStore': {
'filters': {
text: 'e',
sortBy: 'date',
startDate: '11.2017.',
endDate: '12.2017.'
}
}
}
}
/>)
expect(wrapper).toMatchSnapshot();
})
This is my RootStore
import ExpensesStore from './ExpensesStore'
import FiltersStore from './FiltersStore'
class RootStore {
ExpensesStore = new ExpensesStore(this)
FiltersStore = new FiltersStore(this)
}
const rootStore = new RootStore()
export default rootStore
ExpensesStore
class ExpensesStore {
constructor(rootStore) {
this.rootStore = rootStore
}
#observable expenses = [];
findExpense(paramsId) {
return computed(() => {
return this.expenses.find((expense) => expense.id === paramsId)
}).get()
}
}
export default ExpensesStore
FiltersStore
class FiltersStore {
constructor(rootStore) {
this.rootStore = rootStore
}
#observable filters = {
text: '',
sortBy: 'date',
startDate: moment().startOf('month'),
endDate: moment().endOf('month')
}
}
export default FiltersStore
Ok. The problem were decorators at the top of the component.
Using shallow rendering won't provide any useful results when testing injected components; only the injector will be rendered. To test with shallow rendering, instantiate the wrappedComponent
test('should render ExpenseList with expenses', () => {
const wrapper = shallow(<ExpenseList.wrappedComponent
RootStore = {
{
ExpensesStore: {
expenses
},
FiltersStore: {
filters: {
text: 'e',
sortBy: 'date',
startDate: '',
endDate: ''
}
}
}
}
/>)
expect(wrapper).toMatchSnapshot();
})

ngOnInit method called twice

I'm a little bit new in Angular:
When I load my Angular application (Angular 4), a specific component's ngOnInit() method called even if it wasn't rendered. After I navigate my app to a route that renders this component, the ngOnInit() called again. Why is that? Is this some kind of error, or is this how it works? There is no error in the console.
(Because of this, in my component's ngOninit() a subscribe method runs twice.)
Update:
offer-info.component.ts:
import { Component, Input, OnInit, NgZone } from '#angular/core';
import { OfferService } from './offer.service';
import { Offer } from '../models';
declare var $: any;
#Component({
moduleId: module.id,
selector: 's2a-offer-info',
templateUrl: './offer-info.component.html',
})
export class OfferInfoComponent implements OnInit {
private zone: NgZone;
offer: Offer = null;
constructor(
private offerService: OfferService,
) { }
ngOnInit() {
//This is where I get two 'test' output on the console:
console.log('test');
this.zone = new NgZone({enableLongStackTrace: true});
this.offerService.getOfferForOfferInfo().subscribe((offer: Offer) => {
if (offer !== null) {
this.zone.run(() => {
this.offer = offer;
$('#s2aOfferInfoModal').modal();
});
}
});
}
}
In page-packages.component.html:
...
<!-- This tag appers only once in the whole application: -->
<s2a-offer-info></s2a-offer-info>
...
In app-routing.module.ts:
...
{ path: 'packages', component: PagePackagesComponent, canActivate: [LoggedInGuard] },
{ path: 'search', component: PageSearchComponent, canActivate: [LoggedInGuard] },
{ path: '', redirectTo: '/search', pathMatch: 'full' },
...

why subscribe function is not called in angular 2?

I am using observable in angular .Actually my issue when I click button my subscribe function not called why ?
as per documentation subscribe function will call when we call next function
https://plnkr.co/edit/83NaHoVaxiXAeUFoaEmb?p=preview
constructor() {
this.data = new Observable(observer => this.dataObserver = observer);
this.data.subscribe(value => {
console.log('+++')
console.log(value)
})
}
hndle(){
this.name.push({name:"navee"});
this.dataObserver.next(this.name);
}
here is documentation
http://reactivex.io/rxjs/manual/tutorial.html
On basis of Volodymyr Bilyachat suggestion i have modified your code. its working now plz check. Problem was in your way of using dataObserver
//our root app component
import {Component, NgModule} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
import 'rxjs/Rx';
import {Observable} from 'rxjs/Observable';
#Component({
selector: 'my-app',
template: `
<div>
<ul>
<li *ngFor ="let n of name">{{n.name}}</li>
</ul>
<button (click)="hndle()">heelo</button>
</div>
`,
})
export class App {
private data:Observable;
private dataObserver:Observer;
name:string;
name[];
constructor() {
this.dataObserver = new Observable(observer => this.dataObserver = observer);
this.dataObserver.subscribe(value => {
console.log('+++')
console.log(value)
});
}
hndle(){
this.name.push({name:"navee"});
this.dataObserver.next(this.name);
}
}
#NgModule({
imports: [ BrowserModule ],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
link https://plnkr.co/edit/PO80y2udrOhsVq4QQXc5?p=preview
I believe you are subscribing to the observable 2 times. You should be able to fix it by adding .share()
constructor() {
this.data = new Observable(observer => this.dataObserver = observer).share();
this.data.subscribe(value => {
console.log('+++')
console.log(value)
})
}
hndle(){
this.name.push({name:"navee"});
this.dataObserver.next(this.name);
}
In your case, it's better to use this solution:
constructor() {
this.data = new Subject();
this.data.subscribe(value => {
console.log('+++');
console.log(value);
});
}
hndle() { // TYPO: Probably it was meant to be handle
this.name.push({
name: 'navee'
});
this.data.next(this.name);
}
Don't forget to add:
import { Subject } from 'rxjs/Subject'
Working example:
https://plnkr.co/edit/zB8FHTVEm2QUHiEAYuQB?p=preview

How to test my RouteConfig and other decorators in an Angular 2 Component

I am trying to write unit tests for my Angular 2 component before I go any further but I have no idea how to write a test which checks whether my RouteConfig's path is set to '/documents'. I also would like to have a test which verifies that my template contains <router-outlet></router-outlet> inside.
This is my component:
import { Component } from 'angular2/core';
import { CanActivate, RouteConfig, ROUTER_DIRECTIVES } from angular2/router';
import DocumentsComponent from './documents/documents.component';
#Component({
template: `
dashboard
<router-outlet></router-outlet>
`,
directives: [
ROUTER_DIRECTIVES,
]
})
#CanActivate((next, prev) => {
// check if user has access
return true;
})
#RouteConfig([
{
path: '/documents',
name: 'Documents',
component: DocumentsComponent,
useAsDefault: true,
}
])
export default class DashboardComponent {
public name: string = 'John';
sayHello(): string {
return `Hello ${this.name}`;
}
}
And this is my test (I'm using Jasmine):
import DashboardComponent from './../app/dashboard/dashboard.component';
import {describe, it, beforeEach, expect} from 'angular2/testing';
describe('My DashboardComponent', () => {
var dashboard: DashboardComponent = null;
beforeEach(function() {
dashboard = new DashboardComponent();
});
it('should have its path set to "/documents"', function() {
// ???
});
it('should have "<router-outlet></router-outlet>" in its template', function() {
// ???
});
it('should have name property', function() {
expect(dashboard.name).toBe('John');
});
it('should say hello with name property', function() {
expect(dashboard.sayHello()).toBe('Hello John');
});
});
In case you haven't found any answers yet: https://medium.com/google-developer-experts/angular-2-unit-testing-with-jasmine-defe20421584#.13taw92p0

Resources