Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use show requests for hasMany associations #2173

Merged
merged 17 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions src/app/components/admin/orphan/details/details.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,23 @@ import { SharedModule } from "@shared/shared.module";
import { generateBawApiError } from "@test/fakes/BawApiError";
import { generateSite } from "@test/fakes/Site";
import { assertDetail, Detail } from "@test/helpers/detail-view";
import { nStepObservable } from "@test/helpers/general";
import { interceptMappedApiRequests, nStepObservable } from "@test/helpers/general";
import { assertPageInfo } from "@test/helpers/pageRoute";
import { mockActivatedRoute } from "@test/helpers/testbed";
import { Subject } from "rxjs";
import { of, Subject } from "rxjs";
import { appLibraryImports } from "src/app/app.module";
import { AssociationInjector } from "@models/ImplementsInjector";
import { ASSOCIATION_INJECTOR } from "@services/association-injector/association-injector.tokens";
import { Id } from "@interfaces/apiInterfaces";
import { AdminOrphanComponent } from "./details.component";

describe("AdminOrphanComponent", () => {
let component: AdminOrphanComponent;
let fixture: ComponentFixture<AdminOrphanComponent>;
let injector: AssociationInjector;
const siteProjectIds = [1, 2, 3];

function configureTestingModule(model: Site, error?: BawApiError) {
function setup(model: Site, error?: BawApiError) {
TestBed.configureTestingModule({
imports: [
...appLibraryImports,
Expand All @@ -50,31 +52,36 @@ describe("AdminOrphanComponent", () => {

fixture = TestBed.createComponent(AdminOrphanComponent);
injector = TestBed.inject(ASSOCIATION_INJECTOR);

const accountsApi = TestBed.inject(
ACCOUNT.token
) as SpyObject<AccountsService>;
const projectsApi = TestBed.inject(
PROJECT.token
) as SpyObject<ProjectsService>;

component = fixture.componentInstance;

const mockProjectApiResponses = new Map<any, Project>([
[1, new Project({ id: 1, siteIds: [1], name: "custom project" })],
[2, new Project({ id: 2, siteIds: [1], name: "custom project" })],
[3, new Project({ id: 3, siteIds: [1], name: "custom project" })],
]);
projectsApi.show.and.callFake((id: Id) =>
of(mockProjectApiResponses.get(id))
);

const accountsSubject = new Subject<User>();
const projectsSubject = new Subject<Project[]>();
const promise = Promise.all([
nStepObservable(
accountsSubject,
() => new User({ id: 1, userName: "custom username" })
),
nStepObservable(projectsSubject, () =>
[1, 2, 3].map(
(id) => new Project({ id, siteIds: [1], name: "custom project" })
)
),
...interceptMappedApiRequests(projectsApi.show, mockProjectApiResponses),
]);

// Catch associated models
accountsApi.show.and.callFake(() => accountsSubject);
projectsApi.filter.and.callFake(() => projectsSubject);

// Update model to contain injector
if (model) {
Expand All @@ -87,28 +94,28 @@ describe("AdminOrphanComponent", () => {
assertPageInfo<Site>(AdminOrphanComponent, "Test Orphaned Site", {
site: {
model: new Site(generateSite({ name: "Test Orphaned Site" })),
}
},
});

it("should create", () => {
configureTestingModule(new Site(generateSite()));
setup(new Site(generateSite()));
fixture.detectChanges();
expect(component).toBeTruthy();
});

it("should handle error", () => {
configureTestingModule(undefined, generateBawApiError());
setup(undefined, generateBawApiError());
fixture.detectChanges();
expect(component).toBeTruthy();
});

describe("details", () => {
const model = new Site(
generateSite({ locationObfuscated: true, projectIds: [1, 2, 3] })
generateSite({ locationObfuscated: true, projectIds: siteProjectIds })
);

beforeEach(async function () {
const promise = configureTestingModule(model);
const promise = setup(model);
fixture.detectChanges();
await promise;
fixture.detectChanges();
Expand Down Expand Up @@ -150,7 +157,7 @@ describe("AdminOrphanComponent", () => {
{
label: "Projects",
key: "projects",
children: [1, 2, 3].map((id) => ({
children: siteProjectIds.map((id) => ({
model: `Project: custom project (${id})`,
})),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { AudioRecording } from "@models/AudioRecording";
import { generateAudioRecording } from "@test/fakes/AudioRecording";
import { AssociationInjector } from "@models/ImplementsInjector";
import { ASSOCIATION_INJECTOR } from "@services/association-injector/association-injector.tokens";
import { Id } from "@interfaces/apiInterfaces";
import { AnnotationSearchFormComponent } from "./annotation-search-form.component";

describe("AnnotationSearchFormComponent", () => {
Expand Down Expand Up @@ -61,22 +62,30 @@ describe("AnnotationSearchFormComponent", () => {
sitesApiSpy = spectator.inject(SHALLOW_SITE.token);
recordingsApiSpy = spectator.inject(AUDIO_RECORDING.token);

mockTagsResponse = Array.from(
{ length: 10 },
() => new Tag(generateTag(), injector)
);
mockSitesResponse = Array.from(
{ length: 10 },
() => new Site(generateSite(), injector)
);
mockProject = new Project(generateProject(), injector);
mockRecording = new AudioRecording(generateAudioRecording(), injector);
// so that the models can use their associations, we need to provide the
// association injector to the mock models
mockTagsResponse.forEach((tag) => (tag["injector"] = injector));
mockSitesResponse.forEach((site) => (site["injector"] = injector));
mockProject["injector"] = injector;
mockRecording["injector"] = injector

modelChangeSpy = spyOn(spectator.component.searchParametersChange, "emit");

// we mock both filter and show requests because we need to have consistent
// mock data for the typeahead queries that use filter requests, and the
// has-many associations that use show requests
tagsApiSpy.filter.andCallFake(() => of(mockTagsResponse));
tagsApiSpy.show.andCallFake((id: Id) =>
of(mockTagsResponse.find((tag) => tag.id === id))
);

sitesApiSpy.filter.andCallFake(() => of(mockSitesResponse));
sitesApiSpy.show.andCallFake((id: Id) =>
of(mockSitesResponse.find((site) => site.id === id))
);

recordingsApiSpy.filter.andCallFake(() => of([mockRecording]));
recordingsApiSpy.show.andCallFake(() => of(mockRecording));

const searchParameters = new AnnotationSearchParameters(params, injector);
searchParameters.routeProjectModel = mockProject;
Expand Down Expand Up @@ -104,6 +113,19 @@ describe("AnnotationSearchFormComponent", () => {
spectator.query(".advanced-filters>[ng-reflect-collapsed]");
const recordingsTypeahead = () => spectator.query("#recordings-input");

beforeEach(() => {
mockTagsResponse = Array.from(
{ length: 10 },
() => new Tag(generateTag())
);
mockSitesResponse = Array.from(
{ length: 10 },
() => new Site(generateSite())
);
mockProject = new Project(generateProject());
mockRecording = new AudioRecording(generateAudioRecording());
});

it("should create", () => {
setup();
expect(spectator.component).toBeInstanceOf(AnnotationSearchFormComponent);
Expand All @@ -125,9 +147,11 @@ describe("AnnotationSearchFormComponent", () => {

// check the population of a typeahead input that does not use a property backing
it("should pre-populate the tags typeahead input if provided in the search parameters model", () => {
setup({ tags: "0" });
const testedTag = mockTagsResponse[0];

setup({ tags: testedTag.id.toString() });
const realizedTagPills = tagPills();
expect(realizedTagPills[0].innerText).toEqual(`${mockTagsResponse[0]}`);
expect(realizedTagPills[0].innerText).toEqual(`${testedTag.text}`);
});

// check the population of an external component that is not a typeahead input
Expand Down
Loading
Loading