Spectator Angular testing - pass input before ngOnInit
Asked Answered
F

2

6

I am using Spectator to write my Angular 8 tests and Jest to run them. According to the README I can use setInput() to assign my value to the name of the field, which works. The problem is that The input is being validated AFTER the component is created, but I need it before that because I use it for initialization in my ngOnInit method:

// item.component.ts

@Input() items: Items[] = [];

ngOnInit(): void {
    // do something with this.items
    // read query param 'page' and use it for something
}

with

// item.component.spec.ts

let spectator: SpectatorRouting<ItemComponent>;
const createComponent = createRoutingFactory({
    component: ItemComponent,
    queryParams: {page: 1}
});

beforeEach(() => spectator = createComponent());

it('test items', () => {
    spectator.setRouteQueryParam('page', '2');
    spectator.setInput("items", myItemsList); 
});

The spectator will set the queryParam page and Input items correctly, but only after the component is already created. During the component creation ngOnInit will initialize with page == 1 and items == [].

I could create the spectator component within each method and pass the queryParams separately, but I can't find a way to pass the input in the createRoutingFactory arguments.

Alternatively I could use a host component factory to pass my input parameters, but then I lose the ability to pass query params I believe.

Fictive answered 7/12, 2019 at 17:33 Comment(0)
T
17

You can set detectChanges=false in the createRoutingFactory options. This will make createComponent() not calling onInit() automatically, and in your tests you should call spectator.detectChanges() after setting the inputs (or stubing/mocking services spys):

// item.component.spec.ts

let spectator: SpectatorRouting<ItemComponent>;
const createComponent = createRoutingFactory({
    component: ItemComponent,
    queryParams: {page: 1},
    detectChanges: false // set this to avoid calling onInit() automatically
});

beforeEach(() => spectator = createComponent());

it('test items', () => {
    spectator.setRouteQueryParam('page', '2');
    // spectator.inject(AnyService).doSomething.andReturn()... // stub services if needed
    spectator.setInput("items", myItemsList); 
    spectator.detectChanges(); // Now onInit() will be called
});
Town answered 5/11, 2020 at 17:30 Comment(1)
Yeah, I learned this later on too. I forgot about this question, otherwise I would have updated it. I'll mark your solution as the answer since it's cleaner than calling ngOnInit again. Cheers.Fictive
F
-1

I found the answer to this question. It turned out to be quite simple, ngOnInit can be called again to reinitialize the component after setting up the mocks and other parameters. So my test method becomes:

// item.component.spec.ts

let spectator: SpectatorRouting<ItemComponent>;
const createComponent = createRoutingFactory({
    component: ItemComponent,
    queryParams: {page: 1}
});

beforeEach(() => spectator = createComponent());

it('test items', () => {
    spectator.setRouteQueryParam('page', '2');
    spectator.setInput("items", myItemsList); 
    spectator.component.ngOnInit(); // Now the component is reinitialized and the input will contain myItemsList
});
Fictive answered 14/12, 2019 at 9:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.