how to get the property of behaivourSubject type property of a service ?, angular testing - jasmine

I have a service like
export class TestService {
public props: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
props$ = this.props.asObservable();
test(){
}
}
and this is my .spect file of my component
let component: MainComponent;
let fixture: ComponentFixture<MainComponent>;
let testServiceSpy: jasmine.SpyObj<TestService>;
beforeEach(async(() => {
testServiceSpy = jasmine.createSpyObj<TestService>("TestService", [
"test",
],);
TestBed.configureTestingModule({
declarations: [ MainComponent ],
schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA],
imports:[HttpClientTestingModule],
providers:[
{
provide:TestService,
useValue:technicalFacilitiesServiceSpy,
},
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MainComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
and when I try to test in my .spect file like
testServiceSpy.props
I see undefined,
how could I get the default value? false in this case

You have to use the 3rd argument of createSpyObj to mock the public instance variable.
Try doing the following:
testServiceSpy = jasmine.createSpyObj<TestService>("TestService", [
"test",
], { props$: of(false) });
....
{
provide: TestService,
useValue: testServiceSpy
}
Check out this link on how to change the instance variable: https://stackoverflow.com/a/43793575/7365461

Related

angular unit test, method has already been spied upon issue after updating into angular9

I just updated my angular app into version 9. Everything works fine excluding the unit tests. After updating, the unit tests not working.
Below is my sample test suite
describe("test Component", () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
],
providers: [
{ provide: InitService, useValue: mockInit },
{ provide: ControlsService, useValue: genericMock },
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
}));
it('should initialize slides', () => {
const fixture = TestBed.createComponent(AppComponent);
const slides = TestBed.inject(SlideChangeService);
const controls = TestBed.inject(ControlsService);
spyOn(slides, 'initialize');
spyOn(controls, 'initialize');
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(slides.initialize).toHaveBeenCalled();
expect(controls.initialize).toHaveBeenCalled();
});
});
});
it works fine before the angular updation, but now it shows below error!!!
Error: <spyOn> : initialize has already been spied upon
so, how we can spy on two different services that using same method name in angular9 unit tests?

How do I set a new State to test an observable?

I have tried all the day to make a simple test in jasmine, but i think i am doing something wrong. I have a piece of code that i wish to test, but i can't go inside. I was trying to follow nrgx 7 documentation, but i failed.
The unit test below should test my enderecoFeatureSubscription. The store.setState({ cep: null, endereco: RES }) is doing nothing with the store, so my subscription doens't do anything
let component: FormComponent;
let fixture: ComponentFixture<FormComponent>;
let store: MockStore<ICepState>
const initialState = {
cep: null, endereco: null
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [FormComponent],
imports: [StoreModule.forRoot({}),],
providers: [
provideMockStore({ initialState: CEPSTATE })
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
store = TestBed.get(Store);
});
it('should test enderecoFeatureSubscription ', () => {
store.setState({ cep: null, endereco: RES })
expect(component.endereco).toEqual(RES)
});
Component
private enderecoFeatureSubscription = this.store.pipe(select(enderecoFeatureSelector)).subscribe((endereco: IEndereco | any) => {
if (!endereco) {
return;
}
this.endereco = endereco
})
If you can help i thank you, because i hav wasted a lot of time with it.
In ngrx ver. > 8.0.0, there is a method store.refreshState refreshes the state if you use store.setState on respective overridden selectors. Unfortunately, refreshState method does not exist in ngrx 7. There is an alternative to that - you should override the desired selector using store.overrideSelector like this -
it('should test enderecoFeatureSubscription ', () => {
store.overrideSelector(enderecoFeatureSelector, <put you mocked value>
fixture.detectChanges(); //MAKE sure to remove fixture.detectChanges() from beforeEach
expect(component.endereco).toEqual(RES)
});
i did some changes to my test work fine.
1 - Removed 'const initialState' and imported from my app state file.
2 - The type of MockStore, i changed to my app state type
3 - In the test, i set a new value to 'cepState.endereco' and call setState with initialState
4 - I changed 'store' for 'mockStore', but it doesn't make diference
5 - finally, i brought the right import
Look the code bellow:
describe('FormComponent', () => {
let component: FormComponent;
let fixture: ComponentFixture<FormComponent>;
let mockStore: MockStore<AppState>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [FormComponent],
imports: [
StoreModule.forRoot({ 'cepState': CepReducer })
],
providers: [provideMockStore({ initialState })]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
mockStore = TestBed.get(Store);
});
it('should test new endereco state', () => {
initialState.cepState.endereco = RES
mockStore.setState(initialState)
expect(component.endereco).toEqual(RES)
});
});

Can I access request headers in my graphql query, in nestjs?

I am trying to access the ip-address of the user in the query of graphql. But I cannot reach any header information. How can I access the context I am creating in my factory, inside of my graphql requests?
// app.module.ts
...
#Module({
imports: [
ConfigModule,
GraphQLModule.forRootAsync({
imports: [
LanguageModule,
SearchModule],
inject: [ConfigService],
useFactory: () => ({
autoSchemaFile: 'schema.gql',
debug: true,
fieldResolverEnhancers: ['guards'],
formatError: (error: GraphQLError): GraphQLFormattedError => {
return error.originalError instanceof BaseException
? error.originalError.serialize()
: error;
},
context: ({ req }): object => {
console.log("req.ip: ", req.ip); // Here I have the ip
return { req };
},
}),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
// search.resolver.ts
...
#Resolver(() => Search)
export class SearchResolver {
constructor(private readonly service: service) {}
#Query(() => Search)
async search(#Args() args: SearchArgs): Promise<Search> {
// I want the ip here, I want to send it as an argument into the query function below
const response = await this.service.query(args.query, {
language: args.language,
});
return response;
}
}
According to this thread resolver context parameter should contain req but it depends [on configuration].
Resolvers typically takes (parent, args, context, info) arguments - check if context is defined in yours.

Testing ngrx Effects with Jasmine spy

I am writing an ngrx effect and trying to test it. However, the effect calls a service that calls an API that will require authentication. As a result, I am trying to create a spy in Jasmine to handle returning the data. This is my first time using ngrx effects, so I am really unsure where to put different parts of the code. Nothing I have done is allowing this test to run correctly.
The effect is a very simple one as follows:
#Effect() itemSelected: Observable<Action> = this.d.pessimisticUpdate('ITEM_SELECTED', {
run: (action: ItemSelected) => {
return this.myService.getItemById(action.payload).map((res) => ({
type: 'ITEM_INFO_RETURNED',
payload: res
}));
},
onError: (a: ItemSelected, error) => {
console.error('Error', error);
}
});
constructor(private d: DataPersistence<ItemState>, private myService: MyService) {
// add auth headers here
}
My test is currently written as follows:
describe('ItemEffects', () => {
let actions: Observable<any>;
let effects: ItemEffects;
let myService = jasmine.createSpyObj('MyService', ['getItemById']);
let item1: Item = {id: 1, name: 'Item 1'};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({}),
],
providers: [
ItemEffects,
DataPersistence,
provideMockActions(() => actions),
{
provide: MyService,
useValue: myService
}
],
});
effects = TestBed.get(ItemEffects);
});
describe('someEffect', () => {
it('should work', async () => {
myService.getItemById.and.callFake(function (id) {
return items.find((r) => r.id === id);
});
actions = hot('-a-|', { a:{ type:'ITEM_INFO_RETURNED', payload:1}});
expect(effects.itemSelected).toEqual(
{ type: 'ITEM_INFO_RETURNED', payload: { item1 } }
);
});
});
});
This is still attempting to use the production MyService (requiring authentication). If I move the myService override out of the provider and into the actual test,
TestBed.overrideProvider(MyService, { useValue: myService });
I get an error that it cannot read the property "itemSelected" of undefined, which would be when I am calling the effects at the very end of the test.
I am really new to ngrx, as well as to TestBed. Is there somewhere else I should be defining this Jasmine spy? Should I be using something other than createSpyOn for this?
Thanks in advance!

"No provider for MdDialogRef!"

Suppose I have this component:
#Component({
selector: 'pizza-dialog',
template: `
<h1 md-dialog-title>Would you like to order pizza?</h1>
<md-dialog-actions>
<button (click)="dialogRef.close('yes')">Yes</button>
<button md-dialog-close>No</button>
</md-dialog-actions>
`
})
export class PizzaDialog {
constructor(public dialogRef: MdDialogRef<PizzaDialog>) { }
}
I've already imported MdDialog into my app module:
#NgModule({
imports: [
BrowserModule,
MaterialModule.forRoot(),
MdDialogModule.forRoot(),
],
...
})
Why would I get this error?
No provider for MdDialogRef!
You may have tried to use your dialog component in a template like this:
<pizza-dialog ...></pizza-dialog>
Delete that from your template and open the dialog using MdDialog.open() as is done here:
#Component({
selector: 'pizza-component',
template: `
<button type="button" (click)="openDialog()">Open dialog</button>
`
})
export class PizzaComponent {
dialogRef: MdDialogRef<PizzaDialog>;
constructor(public dialog: MdDialog) { }
openDialog() {
this.dialogRef = this.dialog.open(PizzaDialog, {
disableClose: false
});
this.dialogRef.afterClosed().subscribe(result => {
console.log('result: ' + result);
this.dialogRef = null;
});
}
}
This code was copied from:
https://github.com/angular/material2/blob/master/src/lib/dialog/README.md
You must not change your implementation.
You can provide a Mock for the MdDialogRef.
In the following example I fake the MdDialogRef with the MdDialogRefMock class and register it in the providers section:
import { async, ComponentFixture, TestBed } from "#angular/core/testing";
import { CUSTOM_ELEMENTS_SCHEMA } from "#angular/core";
import { MessageBoxYesNoComponent } from "./message-box-yes-no.component";
import { MdDialogRef } from "#angular/material";
class MdDialogRefMock {
}
describe("MessageBoxYesNoComponent", () => {
let component: MessageBoxYesNoComponent;
let fixture: ComponentFixture<MessageBoxYesNoComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MessageBoxYesNoComponent ],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [
],
providers: [
{ provide: MdDialogRef, useClass: MdDialogRefMock }
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MessageBoxYesNoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
});
If you are using Jasmine, you can also create a Spy instead of creating the Fake-Class:
let mdDialogSpy = jasmine.createSpy('MdDialogRef');
Remove <pizza-dialog ...></pizza-dialog> from the template, it only require the button that open the Dialong because in the code you set the relation with the dialog.
Add MdDialogRef to providers of your module

Resources