Testing manipulation of service values within Angular component

I have encountered an issue while trying to manipulate the service return value in my test and assign that value to a component's field.

During the test, I mock the myService within the Test1 and set its return value to true so that it always returns true. After calling fixture.detectChanges();, I trigger

this.myService.getProperty('param');
within the PageComponent expecting it to return true and update the value of myField to true as well. However, this does not happen as expected; the field value remains false, causing Test1 to fail.

I am confused about why setting the return value to true in the test is not reflecting in the component's value. Can someone help me understand what might be going wrong?

Test

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { anything, instance, mock, reset, verify, when } from 'ts-mockito';
import { MyService } from '../services/myservice.service';

describe('Test', () => {
    let component: PageComponent;
    let fixture: ComponentFixture<PageComponent>;
    let myServiceMock: myService = mock(MyService);

    describe('PageComponent', () => {
        beforeEach(() => {
            TestBed.configureTestingModule({
                imports: [],
                declarations: [PageComponent],
                schemas: [NO_ERRORS_SCHEMA],
                providers: [
                    { provide: myService, useValue: instance(myServiceMock) },
                ]
            }).compileComponents();

            fixture = TestBed.createComponent(PageComponent);
            component = fixture.componentInstance;
            fixture.detectChanges();
        });

        afterEach(() => {
            reset(myServiceMock);
        });

        it('Test1 - property should be true', () => {
            when(myServiceMock.getProperty(anything())).thenReturn(true);
            fixture.detectChanges();
            verify(myServiceMock.getProperty(anything())).once();
            expect(component.isCountryInfoVisible).toBeTrue();
            // Test Failed
            // Expected value to be true:
            //  true
            // Received:
            //  false
        });
    });
});

PageComponent

export class PageComponent implements OnInit {
    myField: boolean;

    constructor(private myService: MyService) {}

    ngOnInit(): void {
        this.myField = this.myService.getProperty('param');
    }
}

MyService

@Injectable()
export class MyService {

    private properties: Map<string, string> = new Map<string, string>();

    constructor() { }

    public getProperty(key: string): string {
        return this.properties.get(key);
    }

    ....
}

Answer №1

Special thanks to @EstusFlask for helping me understand the situation;

I realized that my service call was placed inside the ngOnInit function, which is already triggered by the first fixture.detectChanges();. As a result, the second fixture.detectChanges(); does not have any impact because it is not called again.

Solution: I need to move the

when(myServiceMock.getProperty(anything())).thenReturn(true);
just before the first fixture.detectChanges();, like this:

fixture = TestBed.createComponent(PageComponent);
component = fixture.componentInstance;

when(myServiceMock.getProperty(anything())).thenReturn(true);

fixture.detectChanges();

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieving JSON data in Angular 5 returns a 400 bad request error

Having trouble calling the REST API of Amazon S3 from Angular 5. Keep getting a 400 bad request error. This problem has been persisting for a while now and I really need to find a solution or at least get some suggestions on where the issue might be. Her ...

How to access specific properties of an object within the subscribe function in Angular

I've successfully implemented an API that returns an array of table entity objects when queried. Here is the corresponding TableEntity interface in my Angular application: export interface TableEntity { partitionKey: string; rowKey: string; ...

Preventing Bootstrap modal from closing when clicking outside of the modal in Angular 4

I'm working with Angular 4 and trying to prevent the model from closing when I click outside of it. Below is the code snippet I am using: <div id="confirmTaskDelete" class="modal fade" [config]=" {backdrop: 'static', keyboard: false}" ro ...

When the back button is pressed on android, the navbar does not immediately refresh the active class

When using a webapp on Chrome for Android, pressing the back button results in double active items in the navbar. Clicking outside of the navbar removes the old active item. I attempted to resolve the issue by adding [routerLinkActiveOptions]="{ exact: tr ...

Ways to retrieve a particular element within an array

I am looking to access each individual element of the "to" value within the children property of my array. const items = [{ name: 'Administrator', children: [ { name: 'Catalog', to: 'catalog' }, and he ...

The information is being properly displayed in the console, but when attempting to show it on the webpage, an ERROR occurs with the message: "Error trying to differentiate '[object Object]'"

The data is successfully displayed in the console. However, when trying to display it on the page, an error occurs: ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed services getdetails(id:number) : ...

JavaScript Array Split Operation

I am facing a challenge with an array that contains multiple elements. A user has the ability to raise an HTML flag, which should result in the array being split at that specific point. It is important to note that the user can raise the flag multiple time ...

The closest function cannot be found for _e$relatedTarget, resulting in a TypeError

I have a customized input field where, upon losing focus, I am successfully utilizing the next focused element using event.relatedTarget e.target.closest(".input-container") !== e.relatedTarget?.closest(".input-container") Now, for tes ...

Managing Tenant Subdomains in Angular 2 with Router 3

Looking to set up tenant.app.com in Angular 2 (RC6, Router 3.0) Is there any specific documentation available for this requirement? Most resources I have come across assume a base url = / and then extract the url from there. I am aiming for a www version ...

The function `getMovie` is not a valid function in the `dataService` causing a

When attempting to utilize a service for retrieving a JSON object, I encountered an error while using the service method: ERROR TypeError: this.dataService.getMovie is not a function Here is my code snippet: DataService: @Injectable({ providedIn: &ap ...

FFmpeg failed to load due to an error: ReferenceError - SharedArrayBuffer is undefined in Angular version 18.2.3

Inquiry: Currently, I am engaged in an Angular endeavor (version 18.2.3) where the implementation of ffmpeg.wasm is crucial for video trimming and frame extraction. Nevertheless, a predicament arises as I strive to load FFmpeg; an error message surfaces w ...

Using TypeScript along with Nuxt.js and Vuex to access methods from an imported class

Currently, I am in the process of developing a nuxt.js application with typescript and my goal is to segregate the API Calls from the vuex store. However, I've encountered an issue where it seems like I cannot utilize the methods when importing the cl ...

Tips on applying a class to a host element using @hostbinding in Angular 2

I've been wanting to assign a class to the host element of my component, and initially I used the host property in this manner: @Component({ selector: 'left-bar', host: { 'class': 'left-bar' }, templateUrl: 'a ...

Leveraging TweenMax within an Angular2 development venture

What is the best way to integrate TweenMax into my Angular2 project? I would like to avoid adding the script directly in my HTML and instead import TweenMax using the following syntax: import { TweenMax } from 'gsap'; Please keep in mind that I ...

Increment counter when a key is pressed in Angular 4 and decrement when the backspace key is pressed

As a beginner in Angular, my goal is to create a feature where: The character count in a label increases as text is entered into a textarea. When the backspace key is pressed, the counter should decrease. If the user attempts to enter more characters tha ...

When conditional types are used to pass unions through generics, the assigned value defaults to 'any' instead of

In search of a universal type to implement in my actions. Actions can vary from simple functions to functions that return another function, demonstrated below: () => void () => (input: I) => void An Action type with a conditional generic Input h ...

Issue encountered with express-jwt and express-graphql: TypeScript error TS2339 - The 'user' property is not found on the 'Request' type

Implementing express-jwt and graphql together in typescript has been a challenge for me. import * as express from 'express' import * as expressGraphql from 'express-graphql' import * as expressJwt from 'express-jwt' import s ...

The text inside the Mapbox GL popup cannot be highlighted or copied

I'm encountering an issue where the text in my popups is unselectable. Even though I can close the popups through various methods, such as clicking on them, the pointer remains as a hand icon when hovering over the text and doesn't change to the ...

What is the best way to bring in an array from a local file for utilization in a Vue 3 TypeScript project?

Encountering a TS7016 error 'Could not find a declaration file for module '../composables/httpResponses'. '/Users/username/project/src/composables/httpResponses.js' implicitly has an 'any' type.' while attempting to ...

Is it achievable to display keys from an interface using Typescript in node.js?

Using node.js with typescript, I have a query. I defined a type from interfaces key, and I'm wondering if it's feasible to display the key list? interface IFooReal { prop1: string; prop2: number; } type KnownKeys<T> = { [K in ...