18

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(p => {
      if (p) {
        this.useCase = p.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 know we can set ActivatedRoute to an object that will be used through out this testing, as such:

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

But this will set the values for all the test cases. Is there a way to dynamically change the ActivatedRoute in each different test case?

Freestyle09
  • 4,894
  • 8
  • 52
  • 83
stack247
  • 5,579
  • 4
  • 41
  • 64

4 Answers4

30

You can get it with TestBed.get(ActivatedRoute) in your it functions if you want to stock it in a variable. You can update value also.

From Karma v9.0.0 at the angular's newest versions the TestBed.get method is deprecated

adrisons
  • 3,443
  • 3
  • 32
  • 48
Suresh Kumar Ariya
  • 9,516
  • 1
  • 18
  • 27
2

Credit to Suresh for the correct answer, and to update it slightly as of Angular 9 TestBed.get is deprecated. The recommended approach is now

let activatedRoute: ActivatedRoute;
...
activatedRoute = TestBed.inject(ActivatedRoute);
activatedRoute.snapshot.params = { foo: 'bar' };
Phil Mayfield
  • 203
  • 1
  • 2
  • 8
1

if you are not using testBed then use this line of code:

in the beforeEach method, the activatedRoute mock should be defined as follows:

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

then in your it method, update the activatedRoute to:

activatedRoute.queryParams = of({id: 2})};
IAfanasov
  • 4,775
  • 3
  • 27
  • 42
Ashia Nagi
  • 11
  • 1
0

There is an alternative with a stub class. Follow bellow the approach.

Declare 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 declare an alias for the activated route provider

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

And you can use it anywhere you desire. Bellow example in "it" test.

it('should show example, how to set parameters', () => {
        let spy = spyOn(router, 'navigate');
        
        // here we pass the 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 like you desire.
        route.push({id: 0})

        expect(spy).toHaveBeenCalledWith(['not-found'])
    });
Vitor Kevin
  • 785
  • 7
  • 16