import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpResponse } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { FormBuilder } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { of, Subject, from } from 'rxjs';

import { IUnit } from 'app/entities/unit/unit.model';
import { UnitService } from 'app/entities/unit/service/unit.service';
import { IVariableScope } from 'app/entities/variable-scope/variable-scope.model';
import { VariableScopeService } from 'app/entities/variable-scope/service/variable-scope.service';
import { IVariableCategory } from 'app/entities/variable-category/variable-category.model';
import { VariableCategoryService } from 'app/entities/variable-category/service/variable-category.service';
import { IVariable } from '../variable.model';
import { VariableService } from '../service/variable.service';
import { VariableFormService } from './variable-form.service';

import { VariableUpdateComponent } from './variable-update.component';

describe('Variable Management Update Component', () => {
  let comp: VariableUpdateComponent;
  let fixture: ComponentFixture<VariableUpdateComponent>;
  let activatedRoute: ActivatedRoute;
  let variableFormService: VariableFormService;
  let variableService: VariableService;
  let unitService: UnitService;
  let variableScopeService: VariableScopeService;
  let variableCategoryService: VariableCategoryService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule, VariableUpdateComponent],
      providers: [
        FormBuilder,
        {
          provide: ActivatedRoute,
          useValue: {
            params: from([{}]),
          },
        },
      ],
    })
      .overrideTemplate(VariableUpdateComponent, '')
      .compileComponents();

    fixture = TestBed.createComponent(VariableUpdateComponent);
    activatedRoute = TestBed.inject(ActivatedRoute);
    variableFormService = TestBed.inject(VariableFormService);
    variableService = TestBed.inject(VariableService);
    unitService = TestBed.inject(UnitService);
    variableScopeService = TestBed.inject(VariableScopeService);
    variableCategoryService = TestBed.inject(VariableCategoryService);

    comp = fixture.componentInstance;
  });

  describe('ngOnInit', () => {
    it('Should call Unit query and add missing value', () => {
      const variable: IVariable = { id: 456 };
      const baseUnit: IUnit = { id: 10597 };
      variable.baseUnit = baseUnit;

      const unitCollection: IUnit[] = [{ id: 3695 }];
      jest.spyOn(unitService, 'query').mockReturnValue(of(new HttpResponse({ body: unitCollection })));
      const additionalUnits = [baseUnit];
      const expectedCollection: IUnit[] = [...additionalUnits, ...unitCollection];
      jest.spyOn(unitService, 'addUnitToCollectionIfMissing').mockReturnValue(expectedCollection);

      activatedRoute.data = of({ variable });
      comp.ngOnInit();

      expect(unitService.query).toHaveBeenCalled();
      expect(unitService.addUnitToCollectionIfMissing).toHaveBeenCalledWith(
        unitCollection,
        ...additionalUnits.map(expect.objectContaining),
      );
      expect(comp.unitsSharedCollection).toEqual(expectedCollection);
    });

    it('Should call VariableScope query and add missing value', () => {
      const variable: IVariable = { id: 456 };
      const variableScope: IVariableScope = { id: 20996 };
      variable.variableScope = variableScope;

      const variableScopeCollection: IVariableScope[] = [{ id: 8247 }];
      jest.spyOn(variableScopeService, 'query').mockReturnValue(of(new HttpResponse({ body: variableScopeCollection })));
      const additionalVariableScopes = [variableScope];
      const expectedCollection: IVariableScope[] = [...additionalVariableScopes, ...variableScopeCollection];
      jest.spyOn(variableScopeService, 'addVariableScopeToCollectionIfMissing').mockReturnValue(expectedCollection);

      activatedRoute.data = of({ variable });
      comp.ngOnInit();

      expect(variableScopeService.query).toHaveBeenCalled();
      expect(variableScopeService.addVariableScopeToCollectionIfMissing).toHaveBeenCalledWith(
        variableScopeCollection,
        ...additionalVariableScopes.map(expect.objectContaining),
      );
      expect(comp.variableScopesSharedCollection).toEqual(expectedCollection);
    });

    it('Should call VariableCategory query and add missing value', () => {
      const variable: IVariable = { id: 456 };
      const variableCategory: IVariableCategory = { id: 29225 };
      variable.variableCategory = variableCategory;

      const variableCategoryCollection: IVariableCategory[] = [{ id: 8235 }];
      jest.spyOn(variableCategoryService, 'query').mockReturnValue(of(new HttpResponse({ body: variableCategoryCollection })));
      const additionalVariableCategories = [variableCategory];
      const expectedCollection: IVariableCategory[] = [...additionalVariableCategories, ...variableCategoryCollection];
      jest.spyOn(variableCategoryService, 'addVariableCategoryToCollectionIfMissing').mockReturnValue(expectedCollection);

      activatedRoute.data = of({ variable });
      comp.ngOnInit();

      expect(variableCategoryService.query).toHaveBeenCalled();
      expect(variableCategoryService.addVariableCategoryToCollectionIfMissing).toHaveBeenCalledWith(
        variableCategoryCollection,
        ...additionalVariableCategories.map(expect.objectContaining),
      );
      expect(comp.variableCategoriesSharedCollection).toEqual(expectedCollection);
    });

    it('Should update editForm', () => {
      const variable: IVariable = { id: 456 };
      const baseUnit: IUnit = { id: 13102 };
      variable.baseUnit = baseUnit;
      const variableScope: IVariableScope = { id: 31149 };
      variable.variableScope = variableScope;
      const variableCategory: IVariableCategory = { id: 26584 };
      variable.variableCategory = variableCategory;

      activatedRoute.data = of({ variable });
      comp.ngOnInit();

      expect(comp.unitsSharedCollection).toContain(baseUnit);
      expect(comp.variableScopesSharedCollection).toContain(variableScope);
      expect(comp.variableCategoriesSharedCollection).toContain(variableCategory);
      expect(comp.variable).toEqual(variable);
    });
  });

  describe('save', () => {
    it('Should call update service on save for existing entity', () => {
      // GIVEN
      const saveSubject = new Subject<HttpResponse<IVariable>>();
      const variable = { id: 123 };
      jest.spyOn(variableFormService, 'getVariable').mockReturnValue(variable);
      jest.spyOn(variableService, 'update').mockReturnValue(saveSubject);
      jest.spyOn(comp, 'previousState');
      activatedRoute.data = of({ variable });
      comp.ngOnInit();

      // WHEN
      comp.save();
      expect(comp.isSaving).toEqual(true);
      saveSubject.next(new HttpResponse({ body: variable }));
      saveSubject.complete();

      // THEN
      expect(variableFormService.getVariable).toHaveBeenCalled();
      expect(comp.previousState).toHaveBeenCalled();
      expect(variableService.update).toHaveBeenCalledWith(expect.objectContaining(variable));
      expect(comp.isSaving).toEqual(false);
    });

    it('Should call create service on save for new entity', () => {
      // GIVEN
      const saveSubject = new Subject<HttpResponse<IVariable>>();
      const variable = { id: 123 };
      jest.spyOn(variableFormService, 'getVariable').mockReturnValue({ id: null });
      jest.spyOn(variableService, 'create').mockReturnValue(saveSubject);
      jest.spyOn(comp, 'previousState');
      activatedRoute.data = of({ variable: null });
      comp.ngOnInit();

      // WHEN
      comp.save();
      expect(comp.isSaving).toEqual(true);
      saveSubject.next(new HttpResponse({ body: variable }));
      saveSubject.complete();

      // THEN
      expect(variableFormService.getVariable).toHaveBeenCalled();
      expect(variableService.create).toHaveBeenCalled();
      expect(comp.isSaving).toEqual(false);
      expect(comp.previousState).toHaveBeenCalled();
    });

    it('Should set isSaving to false on error', () => {
      // GIVEN
      const saveSubject = new Subject<HttpResponse<IVariable>>();
      const variable = { id: 123 };
      jest.spyOn(variableService, 'update').mockReturnValue(saveSubject);
      jest.spyOn(comp, 'previousState');
      activatedRoute.data = of({ variable });
      comp.ngOnInit();

      // WHEN
      comp.save();
      expect(comp.isSaving).toEqual(true);
      saveSubject.error('This is an error!');

      // THEN
      expect(variableService.update).toHaveBeenCalled();
      expect(comp.isSaving).toEqual(false);
      expect(comp.previousState).not.toHaveBeenCalled();
    });
  });

  describe('Compare relationships', () => {
    describe('compareUnit', () => {
      it('Should forward to unitService', () => {
        const entity = { id: 123 };
        const entity2 = { id: 456 };
        jest.spyOn(unitService, 'compareUnit');
        comp.compareUnit(entity, entity2);
        expect(unitService.compareUnit).toHaveBeenCalledWith(entity, entity2);
      });
    });

    describe('compareVariableScope', () => {
      it('Should forward to variableScopeService', () => {
        const entity = { id: 123 };
        const entity2 = { id: 456 };
        jest.spyOn(variableScopeService, 'compareVariableScope');
        comp.compareVariableScope(entity, entity2);
        expect(variableScopeService.compareVariableScope).toHaveBeenCalledWith(entity, entity2);
      });
    });

    describe('compareVariableCategory', () => {
      it('Should forward to variableCategoryService', () => {
        const entity = { id: 123 };
        const entity2 = { id: 456 };
        jest.spyOn(variableCategoryService, 'compareVariableCategory');
        comp.compareVariableCategory(entity, entity2);
        expect(variableCategoryService.compareVariableCategory).toHaveBeenCalledWith(entity, entity2);
      });
    });
  });
});
