Skip to content

Commit

Permalink
fix: archived records are hidden in entity select unless explicitly a…
Browse files Browse the repository at this point in the history
…ctivated (#2056)

closes #1983

---------

Co-authored-by: Simon <simon@aam-digital.com>
Co-authored-by: Sebastian <sebastian@aam-digital.com>
  • Loading branch information
3 people authored Feb 2, 2024
1 parent d025bb0 commit 4b434fe
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,29 @@
(optionSelected)="selectEntity($event.option.value)"
autoActiveFirstOption
>
<ng-content select="mat-option"></ng-content>
<mat-option *ngFor="let res of filteredEntities" [value]="res">
<app-display-entity
[entityToDisplay]="res"
[linkDisabled]="true"
></app-display-entity>
</mat-option>
<!-- The following mat-option is never displayed ("display: none"), but has to be there, because the mat-checkbox is only shown if there is at least one mat-option, may it also not be displayed. -->
<mat-option
*ngIf="
filteredEntities.length < 1 &&
!includeInactive &&
inactiveFilteredEntities.length > 0
"
style="display: none"
></mat-option>
<mat-checkbox
*ngIf="inactiveFilteredEntities.length > 0"
labelPosition="after"
(change)="toggleIncludeInactive()"
[checked]="includeInactive"
i18n="Label for checkbox|e.g. include inactive children"
>
Also show {{ inactiveFilteredEntities.length }} inactive
</mat-checkbox>
</mat-autocomplete>
</mat-form-field>
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,26 @@ import { Child } from "../../../child-dev-project/children/model/child";
import { School } from "../../../child-dev-project/schools/model/school";
import { MockedTestingModule } from "../../../utils/mocked-testing.module";
import { LoginState } from "../../session/session-states/login-state.enum";
import { HarnessLoader } from "@angular/cdk/testing";
import { TestbedHarnessEnvironment } from "@angular/cdk/testing/testbed";
import { MatAutocompleteHarness } from "@angular/material/autocomplete/testing";
import { EntityMapperService } from "app/core/entity/entity-mapper/entity-mapper.service";

describe("EntitySelectComponent", () => {
let component: EntitySelectComponent<any>;
let fixture: ComponentFixture<EntitySelectComponent<any>>;

const testUsers: Entity[] = ["Abc", "Bcd", "Abd", "Aba"].map((s) => {
const user = new User();
user.name = s;
return user;
});
const testChildren: Entity[] = [new Child(), new Child()];
const otherEntities: Entity[] = [new School()];
let loader: HarnessLoader;
let testUsers: Entity[];
let testChildren: Entity[];

beforeEach(waitForAsync(() => {
testUsers = ["Abc", "Bcd", "Abd", "Aba"].map((s) => {
const user = new User();
user.name = s;
return user;
});
testChildren = [new Child(), new Child()];
const otherEntities: Entity[] = [new School()];
TestBed.configureTestingModule({
imports: [
EntitySelectComponent,
Expand All @@ -40,6 +46,7 @@ describe("EntitySelectComponent", () => {

beforeEach(() => {
fixture = TestBed.createComponent(EntitySelectComponent);
loader = TestbedHarnessEnvironment.loader(fixture);
component = fixture.componentInstance;
fixture.detectChanges();
});
Expand Down Expand Up @@ -82,6 +89,25 @@ describe("EntitySelectComponent", () => {
);
}));

it("accepts initial selection as IDs", fakeAsync(() => {
component.entityType = User.ENTITY_TYPE;

component.selection = [testUsers[1].getId(), testUsers[2].getId()];
fixture.detectChanges();
tick();
expect(component.selectedEntities).toEqual([testUsers[1], testUsers[2]]);
}));

it("discards IDs from initial selection that don't correspond to an existing entity", fakeAsync(() => {
component.entityType = User.ENTITY_TYPE;

component.selection = ["not-existing-entity", testUsers[1].getId()];
fixture.detectChanges();
tick();

expect(component.selectedEntities).toEqual([testUsers[1]]);
}));

it("emits whenever a new entity is selected", fakeAsync(() => {
spyOn(component.selectionChange, "emit");
component.entityType = User.ENTITY_TYPE;
Expand Down Expand Up @@ -115,7 +141,10 @@ describe("EntitySelectComponent", () => {
});

it("adds a new entity if it matches a known entity", fakeAsync(() => {
component.entityType = User.ENTITY_TYPE;
component.allEntities = testUsers;
tick();

component.select({ value: testUsers[0]["name"] });
expect(component.selectedEntities).toEqual([testUsers[0]]);
tick();
Expand All @@ -129,36 +158,129 @@ describe("EntitySelectComponent", () => {
}));

it("autocompletes with the default accessor", fakeAsync(() => {
component.entityType = User.ENTITY_TYPE;
tick();
component.allEntities = testUsers;
component.loading.next(false);

component.formControl.setValue(null);
tick();
expect(component.filteredEntities.length).toEqual(4);

component.formControl.setValue("A");
tick();
expect(component.filteredEntities.length).toEqual(3);

component.formControl.setValue("c");
tick();
expect(component.filteredEntities.length).toEqual(2);

component.formControl.setValue("Abc");
tick();
expect(component.filteredEntities.length).toEqual(1);

component.formControl.setValue("z");
tick();
expect(component.filteredEntities.length).toEqual(0);
tick();
}));

it("shows inactive entites according to the includeInactive state", fakeAsync(() => {
testUsers[0].isActive = false;
testUsers[2].isActive = false;
component.entityType = User.ENTITY_TYPE;
tick();
component.allEntities = testUsers;
component.loading.next(false);

component.formControl.setValue(null);
expect(component.filteredEntities.length).toEqual(2);

component.toggleIncludeInactive();
expect(component.filteredEntities.length).toEqual(4);

testUsers[2].isActive = true;
component.toggleIncludeInactive();
expect(component.filteredEntities.length).toEqual(3);
}));

it("shows the autocomplete options and eventually the hidden autocomplete option in case of corresponding inactive entities appropriately", fakeAsync(async () => {
const testEntities = [
"Aaa",
"Aab",
"Aac",
"Baa",
"Bab",
"Bac",
"Caa",
"Cab",
].map((s) => {
const user = new User();
user.name = s;
return user;
});
testEntities[6].isActive = false;
testEntities[7].isActive = false;

const mockEntityMapper = TestBed.inject(EntityMapperService);
spyOn(mockEntityMapper, "loadType").and.resolveTo(testEntities);
component.entityType = User.ENTITY_TYPE;
tick();
component.allEntities = testEntities;

component.loading.next(false);
const autocomplete = await loader.getHarness(MatAutocompleteHarness);
let options;

autocomplete.enterText("X");
options = await autocomplete.getOptions();
expect(options.length).toEqual(0);

autocomplete.clear();
autocomplete.enterText("Ba");
options = await autocomplete.getOptions();
expect(options.length).toEqual(3);

autocomplete.clear();
autocomplete.enterText("Ca");
options = await autocomplete.getOptions();
expect(options.length).toEqual(1); // dummy element, because some inactive hidden options are available
expect(component.inactiveFilteredEntities.length).toEqual(2);

tick();
}));

it("shows also include inactive options upon toggling 'include inactive'", fakeAsync(async () => {
const active = Child.create("active child");
const inactive = Child.create("inactive child");
inactive.inactive = true;

spyOn(TestBed.inject(EntityMapperService), "loadType").and.resolveTo([
active,
inactive,
]);
component.entityType = Child.ENTITY_TYPE;
tick();

expect(component.filteredEntities).toEqual([active]);

component.toggleIncludeInactive();
expect(component.filteredEntities).toEqual([active, inactive]);
}));

it("should use the configurable toStringAttributes for comparing values", fakeAsync(() => {
class Person extends Entity {
static toStringAttributes = ["firstname", "lastname"];

firstname: string;
lastname: string;
}

const p1 = Object.assign(new Person(), { firstname: "Aa", lastname: "bb" });
const p2 = Object.assign(new Person(), { firstname: "Aa", lastname: "cc" });
const mockEntityMapper = TestBed.inject(EntityMapperService);
spyOn(mockEntityMapper, "loadType").and.resolveTo([p1, p2]);
component.entityType = Person.ENTITY_TYPE;
tick();
component.allEntities = [p1, p2];
component.loading.next(false);

Expand All @@ -172,9 +294,11 @@ describe("EntitySelectComponent", () => {
}));

it("should add an unselected entity to the filtered entities array", fakeAsync(() => {
component.entityType = User.ENTITY_TYPE;
component.allEntities = testUsers;
const selectedUser = testUsers[1];
tick();

const selectedUser = testUsers[1];
component.selectEntity(selectedUser);
expect(component.filteredEntities).not.toContain(selectedUser);

Expand All @@ -187,8 +311,17 @@ describe("EntitySelectComponent", () => {
component.entityType = [User.ENTITY_TYPE, Child.ENTITY_TYPE];
tick();
fixture.detectChanges();
expect(component.allEntities).toEqual([...testUsers, ...testChildren]);
expect(component.filteredEntities).toEqual([...testUsers, ...testChildren]);

expect(component.allEntities).toEqual(
[...testUsers, ...testChildren].sort((a, b) =>
a.toString().localeCompare(b.toString()),
),
);
expect(component.filteredEntities).toEqual(
[...testUsers, ...testChildren].sort((a, b) =>
a.toString().localeCompare(b.toString()),
),
);
}));

it("should be able to select entities from different types", fakeAsync(() => {
Expand Down
Loading

0 comments on commit 4b434fe

Please sign in to comment.