1

I've got an Angular test suite which uses a MockActivatedRoute class I created. All of the values are null except when I need to set them for a given test. In general it works great, but now I'm in a situation where I need two different values for the route.snapshot.data.session.permissions array: one test where the array can be empty and one where it needs a specific value.

I've tried:

  • spying on the permissions array and using Jest's returnValue method;
  • jest.replaceProperty(route.snapshot.data.session, 'permissions, [Permissions.VIEW_REQUEST_SUMMARY_PERMISSION]);, including calling fixture.detectChanges();; and
  • creating an ActivatedRoute definition inline, and using Testbed.inject within the individual test;

but for some reason the permissions array never changes from what is set at the beginning of the test suite. Can someone help me figure out how to change this value?

  • Angular: 18.2.13
  • Jest: 29.7.0

The code being tested:

ngOnInit() {
  const userSession = this.activatedRoute.snapshot.data.session;
  if (userSession.permissions.includes(Permissions.VIEW_REQUEST_SUMMARY_PERMISSION)) {
    this.getRequestSummary();
  }
}

The test suite:

import { MockActivatedRoute } from 'src/app/mocks/mock.activated-route';

describe('SidebarComponent', () => {
  let component: SidebarComponent;
  let fixture: ComponentFixture<SidebarComponent>;
  let route = new MockActivatedRoute();
  route.snapshot = { data: { session: { permissions: []},},};

  beforeEach(async () => {
    TestBed.configureTestingModule({
      imports: [],
      providers:[
        provideHttpClient(),
        provideHttpClientTesting(),
        { provide: ActivatedRoute, useValue: route},
      ],
      declarations: [ SidebarComponent ],
      schemas: [NO_ERRORS_SCHEMA],
    })
    .compileComponents();

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

  // the following test passes
  // I left out the definition of mockAccountsService in this example for brevity
  it('should not call getRequestSummary when Permissions.VIEW_REQUEST_SUMMARY_PERMISSION does not exist', () => {
    const spy = jest.spyOn(mockAccountsService, 'getRequests');
    expect(spy).not.toHaveBeenCalled();
  });

  it('should call getRequestSummary when Permissions.VIEW_REQUEST_SUMMARY_PERMISSION does exist', () => {
    // these are my attempts
    const spyRoute = jest.spyOn(route.snapshot.data.session, 'permissions');
    spyRoute.mockReturnValue([Permissions.VIEW_REQUEST_SUMMARY_PERMISSION]);

    jest.replaceProperty(route.snapshot.data.session, 'permissions', [Permissions.VIEW_REQUEST_SUMMARY_PERMISSION]);

    const spy = jest.spyOn(mockAccountsService, 'getRequests');
    fixture.detectChanges();
    expect(spy).toHaveBeenCalled();
  });
});
1
  • Can you providoe MockActivatedRoute implementation code ? Commented Jul 30 at 9:24

2 Answers 2

1
+200

The permission array is not changing because you are calling fixture.detectChanges() in beforeEach, so ngOnInit() runs there itself and reads activatedRoute.snapshot.data.session.permissions once. Everything(spying/array replacement) that is tried happens after ngOnInit() already ran which results in no effect. And the route instance is also created outside beforeEach, so it is shared across the tests unless we reassign it.

We can fix this issue by creating a fresh MockActivatedRoute per test, set the snapshot before the first detectChanges and not calling the detectChanges() method in beforeEach.

// top-level
let route: MockActivatedRoute; // was: let route = new MockActivatedRoute();

// beforeEach
route = new MockActivatedRoute();
route.snapshot = { data: { session: { permissions: [] } } };
// removed: fixture.detectChanges();

// test: without permission
route.snapshot.data.session.permissions = [];
fixture.detectChanges();

// test: with permission
route.snapshot.data.session.permissions = [Permissions.VIEW_REQUEST_SUMMARY_PERMISSION];
fixture.detectChanges();

Sign up to request clarification or add additional context in comments.

Comments

1

According to TestBed's Documentation:

Call configureTestingModule to refine the testing module configuration for a particular set of tests by adding and removing imports, declarations (of components, directives, and pipes), and providers.

That means that the Provider you specified(MockActivatedRoute) is reused for every test, and not updated with your spies.

You should remove the .compileComponents() call from TestBed.configureTestingModule({, and in each test do

const newRoute = { snapshot: { data: { session: { permissions: [Permissions.VIEW_REQUEST_SUMMARY_PERMISSION]},},},};
TestBed.overrideProvider(ActivatedRoute, {useValue: newRoute});
TestBed.compileComponents();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.