0

I have an Angular service that calls an api backend and returns a list of employees, in a project. I'm writing a unit test for the component that calls the service method, and mocking the service, but the mocked responses are not being assigned in the component, so the unit test is failing every time

./employee.ts

export interface Employee {
  id: string;
  name: string;
  dateOfBirth: string;
  dateJoined: string;
}

./employee.service.ts

@Injectable({
  providedIn: 'root',
})
export class EmployeeService {
  constructor(private http: HttpClient) { }

  getEmployees(countryId: string, branchId: string): Observable<Employee[]> {
    return this.http.get<Employee[]>(`api/employees/${countryId}/${branchId}`);
  }
}

./app.component.ts

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  providers: [ EmployeeService ],
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {
  employees$!: Observable<Employee[]>;
  countryId: string = '';
  branchId: string = '';

  constructor(private employeeService: EmployeeService) {}

  search(): void {
    this.employees$ = this.employeeService.getEmployees(this.countryId, this.branchId);
  }
}

./app.component.spec.js

describe('Unit tests for AppComponent', () => {
  const mockEmployee = {
    id: "1234",
    name: "Mock Employee Name",
    dateOfBirth: "2000-01-01",
    dateJoined: "2020-01-01"
  };

  const mockEmployees = [mockEmployee];

  let fixture: ComponentFixture<AppComponent>;
  let app: AppComponent;
  let mockEmployeeService: jasmine.SpyObj<EmployeeService>;

  beforeEach(async () => {
    mockEmployeeService = jasmine.createSpyObj('EmployeeService', ['getEmployees']);
    await TestBed.configureTestingModule({
      declarations: [ AppComponent ],
      imports: [ HttpClientTestingModule, FormsModule ],
      providers: [ {provide: EmployeeService, useValue: mockEmployeeService} ]
    }).compileComponents();
    fixture = TestBed.createComponent(AppComponent);
    app = fixture.componentInstance;
  });

  it('should test the employees are returned correctly from the service', fakeAsync() => {
    const getEmployeesSpy = mockEmployeeService.getEmployees.and.returnValue(of(mockEmployees));

    // Search for all employees in region 1234 with no trade reference set
    app.countryId = "1234";
    app.branchId = "4321";
    app.search();
    fixture.detectChanges();

    expect(getEmployeesSpy.calls.any()).toBe(true);
    expect(app.employees$).toEqual(mockEmployees);
  });
});

What am I missing?

Joseph McCarthy
  • 897
  • 2
  • 19
  • 41
  • I'm curious how do you compare Observable and object `expect(app.employees$).toEqual(mockEmployees);` – yurzui Feb 10 '22 at 18:14
  • Have you tried smth like `app.employees$.subscribe((res) => { expect(res).toEqual(mockEmployees); });`? – yurzui Feb 10 '22 at 18:17

1 Answers1

1
  • use waitForAsync instead of fakeAsync
  • replace your expects with:
expect(getEmployeesSpy).toHaveBeenCalled();
expect(app.employees$).toBeObservable(mockEmployees);

wlf
  • 3,086
  • 1
  • 19
  • 29