Changing component variable in Angular test affects other tests

9.5k views Asked by At

In my test I'm importing a JSON file to set a mock value (which would usually be passed in to my component as an @Input()).

It was my impression that Angular tests would reset component variables before each test runs if beforeEach is used; therefore, changing the value of a component variable inside one test shouldn't affect other tests in the same testbed.

However, I'm finding that when a variable value is changed in a test it isn't being reset by the beforeEach before the next test runs.

mock_board.json

{
   "board": {
     "type": "Archived"
   }  
}

component.spec.ts

import * as MockBoard from '../mock_board.json';
...

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        ...
      ],
      declarations: [
        MyComponent
      ],
      providers: [
       ...
      ],
      schemas: [ NO_ERRORS_SCHEMA ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    component.board = MockBoard['board'];
    fixture.detectChanges();
  });

  it('should display title if board type is `Progress`', () => {
    component.board.type = 'Progress';

    ... // expectation here
  });

  it('should change the UI if board data changes', () => {
    console.log(component.board.type); // expected 'Archived' but returns 'Progress'
  });

  ...

How can I ensure that component variables are always reset back to the original before each test runs?


EDIT

I managed to replicate the bug in StackBlitz here.

In the second test, setting the value in this way:

component.board.type = 'Progress';

causes the next test to fail, whereas rewriting the whole object like this:

component.board = { id: 1, type: 'Progress' };

causes the next test to pass.

Any ideas?!

1

There are 1 answers

1
Tiz On BEST ANSWER

From your StackBlitz (and many log statements!) it appears that when you change the value in component.board it was also changing the value in data. This makes sense as the assignment in the beforeEach method (component.board = data;) would just be assigning component.board the same pointer as data. Then changing one would change the other.

To get past this you should, as some of the comments mention, clone the data object rather than directly assigning it. You can do this using JSON.parse(JSON.stringify(MockBoard['board'])) as Jelle mentioned or use something like Lodash's clone method (cloneDeep for more complex objects).

Here is an updated StackBlitz that you can use to compare to your original code.