src/app/core/entity-details/related-entities-with-summary/related-entities-with-summary.component.spec.ts
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
waitForAsync,
} from "@angular/core/testing";
import { RelatedEntitiesWithSummaryComponent } from "./related-entities-with-summary.component";
import { Child } from "../../../child-dev-project/children/model/child";
import { MockedTestingModule } from "../../../utils/mocked-testing.module";
import { EducationalMaterial } from "../../../child-dev-project/children/educational-material/model/educational-material";
import { ConfigurableEnumValue } from "../../basic-datatypes/configurable-enum/configurable-enum.interface";
import { EntityMapperService } from "../../entity/entity-mapper/entity-mapper.service";
import { Subject } from "rxjs";
import { UpdatedEntity } from "../../entity/model/entity-update";
describe("RelatedEntitiesWithSummaryComponent", () => {
let component: RelatedEntitiesWithSummaryComponent;
let fixture: ComponentFixture<RelatedEntitiesWithSummaryComponent>;
const updates = new Subject<UpdatedEntity<EducationalMaterial>>();
const child = new Child("22");
const PENCIL: ConfigurableEnumValue = {
id: "pencil",
label: "Pencil",
};
const RULER: ConfigurableEnumValue = {
id: "ruler",
label: "Ruler",
};
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
RelatedEntitiesWithSummaryComponent,
MockedTestingModule.withState(),
],
}).compileComponents();
const entityMapper = TestBed.inject(EntityMapperService);
spyOn(entityMapper, "receiveUpdates").and.returnValue(updates);
}));
beforeEach(() => {
fixture = TestBed.createComponent(RelatedEntitiesWithSummaryComponent);
component = fixture.componentInstance;
component.entity = child;
component.entityType = EducationalMaterial.ENTITY_TYPE;
component.summaries = {
countProperty: "materialAmount",
groupBy: "materialType",
total: true,
average: true,
};
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
it("produces an empty summary when there are no records", () => {
component.data = [];
component.updateSummary(component.data);
expect(component.summarySum).toHaveSize(0);
expect(component.summaryAvg).toHaveSize(0);
});
function setRecordsAndGenerateSummary(
...records: Partial<EducationalMaterial>[]
) {
component.data = records.map(EducationalMaterial.create);
component.updateSummary(component.data);
}
it("produces a singleton summary when there is a single record", () => {
setRecordsAndGenerateSummary({ materialType: PENCIL, materialAmount: 1 });
expect(component.summarySum).toEqual(`${PENCIL.label}: 1`);
expect(component.summaryAvg).toEqual(`${PENCIL.label}: 1`);
});
it("produces a summary of all records when they are all different", () => {
setRecordsAndGenerateSummary(
{ materialType: PENCIL, materialAmount: 2 },
{ materialType: RULER, materialAmount: 1 },
{ materialAmount: 1 },
);
expect(component.summarySum).toEqual(
`${PENCIL.label}: 2, ${RULER.label}: 1, undefined: 1`,
);
expect(component.summaryAvg).toEqual(
`${PENCIL.label}: 2, ${RULER.label}: 1, undefined: 1`,
);
});
it("produces a singly summary without grouping, if `groupBy` is not given (or the group value undefined)", () => {
component.data = [{ amount: 1 }, { amount: 5 }] as any[];
delete component.summaries.groupBy;
component.summaries.countProperty = "amount";
component.updateSummary(component.data);
expect(component.summarySum).toEqual(`6`);
expect(component.summaryAvg).toEqual(`3`);
});
it("produces a summary of all records when there are duplicates", () => {
setRecordsAndGenerateSummary(
{ materialType: PENCIL, materialAmount: 1 },
{ materialType: RULER, materialAmount: 1 },
{ materialType: PENCIL, materialAmount: 3 },
);
expect(component.summarySum).toEqual(
`${PENCIL.label}: 4, ${RULER.label}: 1`,
);
expect(component.summaryAvg).toEqual(
`${PENCIL.label}: 2, ${RULER.label}: 1`,
);
});
it("produces summary of all records when average is false and total is true", () => {
component.summaries.total = true;
component.summaries.average = false;
setRecordsAndGenerateSummary(
{ materialType: PENCIL, materialAmount: 1 },
{ materialType: RULER, materialAmount: 1 },
{ materialType: PENCIL, materialAmount: 3 },
);
expect(component.summarySum).toEqual(
`${PENCIL.label}: 4, ${RULER.label}: 1`,
);
expect(component.summaryAvg).toEqual(``);
});
it("produces summary of all records when average is true and total is false", () => {
component.summaries.total = false;
component.summaries.average = true;
setRecordsAndGenerateSummary(
{ materialType: PENCIL, materialAmount: 1 },
{ materialType: RULER, materialAmount: 1 },
{ materialType: PENCIL, materialAmount: 3 },
);
expect(component.summarySum).toEqual(``);
expect(component.summaryAvg).toEqual(
`${PENCIL.label}: 2, ${RULER.label}: 1`,
);
});
it("does not produces summary of all records when both average and total are false", () => {
component.summaries.total = false;
component.summaries.average = false;
setRecordsAndGenerateSummary(
{ materialType: PENCIL, materialAmount: 1 },
{ materialType: RULER, materialAmount: 1 },
{ materialType: PENCIL, materialAmount: 3 },
);
expect(component.summarySum).toEqual(``);
expect(component.summaryAvg).toEqual(``);
});
it("produces summary of all records when both average and total are true", () => {
setRecordsAndGenerateSummary(
{ materialType: PENCIL, materialAmount: 1 },
{ materialType: RULER, materialAmount: 1 },
{ materialType: PENCIL, materialAmount: 3 },
);
expect(component.summarySum).toEqual(
`${PENCIL.label}: 4, ${RULER.label}: 1`,
);
expect(component.summaryAvg).toEqual(
`${PENCIL.label}: 2, ${RULER.label}: 1`,
);
});
it("loads all education data associated with a child and updates the summary", fakeAsync(() => {
const educationalData = [
{ materialType: PENCIL, materialAmount: 1, child: child.getId() },
{ materialType: RULER, materialAmount: 2, child: child.getId() },
].map(EducationalMaterial.create);
spyOn(TestBed.inject(EntityMapperService), "loadType").and.resolveTo(
educationalData,
);
component.entity = new Child("22");
component.ngOnInit();
tick();
fixture.detectChanges();
tick();
expect(component.summarySum).toEqual(
`${PENCIL.label}: 1, ${RULER.label}: 2`,
);
expect(component.data).toEqual(educationalData);
}));
it("should update the summary when entity updates are received", fakeAsync(() => {
component.ngOnInit();
fixture.detectChanges();
tick();
const update1 = EducationalMaterial.create({
child: child.getId(),
materialType: PENCIL,
materialAmount: 1,
});
updates.next({ entity: update1, type: "new" });
fixture.detectChanges();
tick();
expect(component.data).toEqual([update1]);
expect(component.summarySum).toBe(`${PENCIL.label}: 1`);
const update2 = update1.copy() as EducationalMaterial;
update2.materialAmount = 2;
updates.next({ entity: update2, type: "update" });
fixture.detectChanges();
tick();
expect(component.data).toEqual([update2]);
expect(component.summarySum).toBe(`${PENCIL.label}: 2`);
const unrelatedUpdate = update1.copy() as EducationalMaterial;
unrelatedUpdate.child = "differentChild";
updates.next({ entity: unrelatedUpdate, type: "new" });
fixture.detectChanges();
tick();
// No change
expect(component.data).toEqual([update2]);
expect(component.summarySum).toBe(`${PENCIL.label}: 2`);
}));
});