Testing Angular components, modifying ActivatedRoute parameters dynamically to cover various test scenarios

Component:

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html'
})
export class TestComponent implements OnInit {
  useCase: string;

  constructor(
    private route: ActivatedRoute,
  ) {}

  ngOnInit() {
    this.route.queryParams.subscribe(param => {
      if (param) {
        this.useCase = param.u;
      }
    });
  }
}

Test Spec

describe('TestComponent', () => {
  let component: TestComponent;
  let fixture: ComponentFixture<TestComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        AppModule
      ],
      providers: [
        { provide: ActivatedRoute, useValue: ??? }
      ]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
  });

  it('should create', () => {
    expect(component).toBeTruthy();
    expect(component.useCase).toBeFalsy();
  });

  it('should set useCase variable with query string value', () => {
    fixture.detectChanges();
    // Set different route.queryParams here...
    expect(component.useCase).toBe('success');
  });
});

Using Angular 6, Karma and Jasmine for unit testing.

I am aware that we can set ActivatedRoute to an object that will be used throughout the testing process by using:

providers: [
  { provide: ActivatedRoute, useValue: {
    queryParams: Observable.of({id: 123})
  } }
]

However, this approach sets the values for all test cases. Is there a way to dynamically change the ActivatedRoute in each different test case?

Answer №1

If you're looking to store it in a variable, try using TestBed.get(ActivatedRoute) within your it functions. You can also update the value as needed.

As of Karma v9.0.0 and newer versions of Angular, the TestBed.get method has been marked as deprecated.

Answer №2

Kudos to Suresh for providing the accurate solution, and just a heads up that as of Angular 9 TestBed.get is no longer in use. The new recommended method is:

let activatedRoute: ActivatedRoute;
...
activatedRoute = TestBed.inject(ActivatedRoute);
activatedRoute.snapshot.params = { foo: 'bar' };

Answer №3

When you're not utilizing testBed, add this line of code:

Within the beforeEach function, make sure to define the activatedRoute mock like so:

activatedRoute = {queryParams: of({id: 1})};

Next, in your it method, remember to update the activatedRoute with:

activatedRoute.queryParams = of({id: 2})};

Answer №4

If you're looking for an alternative using a stub class, check out the method below.

Create a stub class

class ActivatedRouteStub {
    private _params = new Subject<any>();

    get params() {
        return this._params.asObservable();
    }

    public push(value) {
        this._params.next(value);
    }
}

In your beforeEach function, define an alias for the activated route provider

beforeEach(waitForAsync(() => {
        TestBed.configureTestingModule({
            imports: [
                RouterTestingModule
            ],
            declarations: [YourComponentComponent],
            providers: [
                {
                    provide: ActivatedRoute,
                    useClass: ActivatedRouteStub
                }
            ]
        })
            .compileComponents();
    }));

You can now use it wherever you need to. Below is an example within an "it" test.

it('should demonstrate how to set parameters', () => {
        let spy = spyOn(router, 'navigate');
        
        // here we provide any parameter for return and type the route variable with the stub class
        let route: ActivatedRouteStub = TestBed.inject<any>(ActivatedRoute);
        // you can push the parameters as needed.
        route.push({id: 0})

        expect(spy).toHaveBeenCalledWith(['not-found'])
    });

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

redux-toolkit extraReducers not triggering

I've been experimenting with createAsyncThunk, but I'm having trouble getting the extraReducers to trigger. This is what my current setup looks like: export const getAllAgents = createAsyncThunk( "getAllAgents", async (token: string ...

How can I redirect a page using an axios interceptor in Next.js?

Is there a way to redirect the page in an axios interceptor when dealing with server-side rendering limitations? Unfortunately, I am unable to access the server side context in the axios interceptor. I have tried using next/router but it only works on the ...

Using NextJS's API routes to implement Spotify's authorization flow results in a CORS error

I am currently in the process of setting up the login flow within NextJS by referring to the guidelines provided in the Spotify SDK API Tutorial. This involves utilizing NextJS's api routes. To handle this, I've created two handlers: api/login.t ...

Executing an AngularJS function using regular JavaScript code

I am currently working with AngularJS and Typescript. I have integrated an external library into my project and now I need to call an AngularJS method from that library, which is written in vanilla JavaScript. I tried following this example, but unfortunat ...

A guide on tallying up the occurrences of a boolean value within a map

The Angular 8 framework is being utilized. Within an array named teams, the length can be accessed using teams.length. Each entry in the teams array contains a nested map called teamInfo. Within this map, there is a boolean value isClosed that can ...

Troubleshooting font color issues with PrimeNG charts in Angular

I have a chart and I am looking to modify the color of the labels https://i.sstatic.net/vsw6x.png The gray labels on the chart need to be changed to white for better readability Here is my code snippet: HTML5: <div class="box-result"> ...

Encountering a Node-gyp rebuild issue while integrating NGRX into an Angular application on Mac OS

I am currently working on integrating ngrx/store into my Angular application. Johns-MBP:Frontend johnbell$ npm install @ngrx/store <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aac9cbc4dccbd9ea9b849c849b99">[email pr ...

Should ts-node be avoided in a production environment due to potential risks?

My current setup involves using ts-node with express in production and so far, it's been functioning smoothly. Am I missing out on any benefits by not compiling and running .js files instead? ...

Utilizing the protractor tool to navigate through menu options and access submenus efficiently

I am new to using Protractor and I'm struggling to write code that can select the menu, submenus, and click them within the div with id="navbar". Can someone please assist me with this issue? Unfortunately, I am facing difficulties posting the HTML co ...

What causes this Selenium test to always fail unless I manually add a pdb breakpoint?

Currently, I am working on a Selenium LiveServerTestCase within a Django project that is responsible for testing an AJAX-powered page. The main issue I am facing is the delay in loading another item after the initial page loads. In order to test for this s ...

Enhancing external access

I am currently working on enhancing the types of convict. The current definitions export convict using the following: namespace convict { ... } interface convict { ... } declare var convict: convict; export = convict; To augment the interface, I have mad ...

The identifier "id" is not a valid index for this type

The code snippet below demonstrates the similarities and differences between the functions addThingExample2 and addThing. While addThingExample2 directly uses the union type Things, addThing utilizes a generic parameter THING extends Thing. The expression ...

Angular2: Validating routes with integer parameters

Take this router as an example: { path: '/client', component: ClientRootComponent, children: [ {path: '', component: ClientListComponent}, {path: ':clientId', component: ClientOpenComponent, resolv ...

How to access individual reactive form instances within an ngFor loop in Angular

I've been grappling with this issue for a few hours now, trying to find a solution that doesn't involve adding fields dynamically. All I need is the ability to access the properties of each form instance, but currently, it only displays one insta ...

What is the best way to dynamically add data to a JSON file?

image of JSON file Just a heads up: I'm looking to add data directly without the need to write it to a .json file, perhaps by using Angularfire2 database. user = { name: 'Arthur', age: 21 }; const options = {Headers, responseType: &apo ...

Tips for refreshing the 'state' of an Angular Router component

I'm facing an issue with passing data between pages using Angular routing. Everything works as expected when navigating to the "next" page for the first time. However, upon returning to the home page and selecting a different item, the Router's s ...

Extending a Svelte component with a P5JS class: A step-by-step guide

As a newcomer to SO, I haven't asked many questions before, so please bear with me if I don't entirely follow the guidelines. I'll do my best to explain the issue at hand. In my project, I am utilizing Sveltekit (create-svelte) and P5JS (p5 ...

What is the most efficient way to execute useEffect when only one specific dependency changes among multiple dependencies?

My main objective is to update a state array only when a specific state (loadingStatus) undergoes a change. Yet, if I include solely loadingStatus as a dependency, React throws an error requesting all dependencies [loadingStatus, message, messageArray, set ...

Tips on expanding an interface of a subclass

Using the latest versions of TypeScript and ReactJS together has presented a challenge when it comes to extending classes and their interfaces. To address this issue for several form elements that share common validation methods, I have created a BaseComp ...

When running all test cases simultaneously, the Mocha tests encounter an error indicating that the loaded module is not functioning properly

While using mocha to run unit test cases for my nodejs code, I encountered a surprising issue. One of the modules did not load its dependent module when running all test cases together, but worked perfectly fine when run separately. I went through each fil ...