Skip to content

Commit

Permalink
fix: Association decorators should not raise errors
Browse files Browse the repository at this point in the history
This pull request creates a new association injector that can be used to inject options into the baw-api.service.ts
 
- Add injectable BawApiOptions object to the baw-api.service
- Add missing PageInfo tests to annotation search page
- Fix a bug where the associations would throw errors (e.g. the audio recording list page if not logged in)
- Fix TypeScript typing for ServiceToken.kind
 
Fixes: #1967
  • Loading branch information
hudson-newey authored Nov 11, 2024
1 parent acac43f commit 8909001
Show file tree
Hide file tree
Showing 93 changed files with 767 additions and 381 deletions.
7 changes: 7 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#! this file should only be used as a last resort to exclude files from pettier
# you should always prefer to use // prettier-ignore to exluce individual lines

# we ignore the service token file from pettier so that we can one-line all of
# the service tokens
# this makes it much more readable as each service token has its ownn line
src/app/services/baw-api/ServiceTokens.ts
3 changes: 2 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
ApplicationRef,
CUSTOM_ELEMENTS_SCHEMA,
DoBootstrap,
NgModule,
Expand Down Expand Up @@ -114,7 +115,7 @@ export const appImports = [
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule implements DoBootstrap {
public ngDoBootstrap(app: any): void {
public ngDoBootstrap(app: ApplicationRef): void {
app.bootstrap(AppComponent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { ToastrService } from "ngx-toastr";
import { ConfirmationComponent } from "@components/harvest/components/modal/confirmation.component";
import { LoadingComponent } from "@shared/loading/loading.component";
import { UserLinkComponent } from "@shared/user-link/user-link/user-link.component";
import { Injector } from "@angular/core";
import { SHALLOW_HARVEST } from "@baw-api/ServiceTokens";
import { Harvest } from "@models/Harvest";
import { Project } from "@models/Project";
Expand All @@ -16,6 +15,7 @@ import { User } from "@models/User";
import { generateUser } from "@test/fakes/User";
import { ShallowHarvestsService } from "@baw-api/harvest/harvest.service";
import { generateHarvest } from "@test/fakes/Harvest";
import { ASSOCIATION_INJECTOR } from "@services/association-injector/association-injector.tokens";
import { AllUploadsComponent } from "./all-uploads.component";

// the functionality that the project names are shown in the harvest list
Expand All @@ -38,7 +38,7 @@ describe("AllUploadsComponent", () => {

spectator = createComponent({ detectChanges: false });

const injector = spectator.inject(Injector);
const injector = spectator.inject(ASSOCIATION_INJECTOR);
fakeHarvest["injector"] = injector;

fakeHarvestApi = spectator.inject(SHALLOW_HARVEST.token);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Injector } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { RouterTestingModule } from "@angular/router/testing";
import { MockBawApiModule } from "@baw-api/baw-apiMock.module";
Expand All @@ -21,10 +20,12 @@ import { assertPageInfo } from "@test/helpers/pageRoute";
import { mockActivatedRoute } from "@test/helpers/testbed";
import { Subject } from "rxjs";
import { PageTitleStrategy } from "src/app/app.component";
import { ASSOCIATION_INJECTOR } from "@services/association-injector/association-injector.tokens";
import { AssociationInjector } from "@models/ImplementsInjector";
import { AdminAnalysisJobComponent } from "./details.component";

describe("AdminAnalysisJobComponent", () => {
let injector: Injector;
let injector: AssociationInjector;
let spec: Spectator<AdminAnalysisJobComponent>;
const createComponent = createComponentFactory({
component: AdminAnalysisJobComponent,
Expand Down Expand Up @@ -54,7 +55,7 @@ describe("AdminAnalysisJobComponent", () => {
],
});

injector = spec.inject(Injector);
injector = spec.inject(ASSOCIATION_INJECTOR);
const accountsApi = spec.inject(ACCOUNT.token);
const scriptsApi = spec.inject(SCRIPT.token);
const savedSearchesApi = spec.inject(SAVED_SEARCH.token);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Injector } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ActivatedRoute } from "@angular/router";
import { RouterTestingModule } from "@angular/router/testing";
Expand All @@ -21,12 +20,14 @@ import { assertPageInfo } from "@test/helpers/pageRoute";
import { mockActivatedRoute } from "@test/helpers/testbed";
import { 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 { AdminOrphanComponent } from "./details.component";

describe("AdminOrphanComponent", () => {
let component: AdminOrphanComponent;
let fixture: ComponentFixture<AdminOrphanComponent>;
let injector: Injector;
let injector: AssociationInjector;

function configureTestingModule(model: Site, error?: BawApiError) {
TestBed.configureTestingModule({
Expand All @@ -48,7 +49,7 @@ describe("AdminOrphanComponent", () => {
}).compileComponents();

fixture = TestBed.createComponent(AdminOrphanComponent);
injector = TestBed.inject(Injector);
injector = TestBed.inject(ASSOCIATION_INJECTOR);
const accountsApi = TestBed.inject(
ACCOUNT.token
) as SpyObject<AccountsService>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Injector } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ActivatedRoute } from "@angular/router";
import { RouterTestingModule } from "@angular/router/testing";
Expand All @@ -22,12 +21,14 @@ import { assertPageInfo } from "@test/helpers/pageRoute";
import { mockActivatedRoute } from "@test/helpers/testbed";
import { Subject } from "rxjs";
import { appLibraryImports } from "src/app/app.module";
import { ASSOCIATION_INJECTOR } from "@services/association-injector/association-injector.tokens";
import { AssociationInjector } from "@models/ImplementsInjector";
import { AdminScriptComponent } from "./details.component";

describe("ScriptComponent", () => {
let component: AdminScriptComponent;
let fixture: ComponentFixture<AdminScriptComponent>;
let injector: Injector;
let injector: AssociationInjector;

function configureTestingModule(model: Script, error?: BawApiError) {
TestBed.configureTestingModule({
Expand All @@ -50,7 +51,7 @@ describe("ScriptComponent", () => {
}).compileComponents();

fixture = TestBed.createComponent(AdminScriptComponent);
injector = TestBed.inject(Injector);
injector = TestBed.inject(ASSOCIATION_INJECTOR);
const accountsApi = TestBed.inject(
ACCOUNT.token
) as SpyObject<AccountsService>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
import { SharedModule } from "@shared/shared.module";
import { MockBawApiModule } from "@baw-api/baw-apiMock.module";
import { AnnotationSearchParameters } from "@components/annotations/pages/annotationSearchParameters";
import { Injector, INJECTOR } from "@angular/core";
import { Project } from "@models/Project";
import { generateProject } from "@test/fakes/Project";
import { TagsService } from "@baw-api/tag/tags.service";
Expand All @@ -30,11 +29,13 @@ import { Params } from "@angular/router";
import { AudioRecordingsService } from "@baw-api/audio-recording/audio-recordings.service";
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 { AnnotationSearchFormComponent } from "./annotation-search-form.component";

describe("AnnotationSearchFormComponent", () => {
let spectator: Spectator<AnnotationSearchFormComponent>;
let injector: SpyObject<Injector>;
let injector: SpyObject<AssociationInjector>;

let tagsApiSpy: SpyObject<TagsService>;
let sitesApiSpy: SpyObject<ShallowSitesService>;
Expand All @@ -55,7 +56,7 @@ describe("AnnotationSearchFormComponent", () => {
function setup(params: Params = {}): void {
spectator = createComponent({ detectChanges: false });

injector = spectator.inject(INJECTOR);
injector = spectator.inject(ASSOCIATION_INJECTOR);
tagsApiSpy = spectator.inject(TAG.token);
sitesApiSpy = spectator.inject(SHALLOW_SITE.token);
recordingsApiSpy = spectator.inject(AUDIO_RECORDING.token);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Injector } from "@angular/core";
import { Params } from "@angular/router";
import { Filters, InnerFilter } from "@baw-api/baw-api.service";
import {
Expand Down Expand Up @@ -27,7 +26,7 @@ import { hasMany } from "@models/AssociationDecorators";
import { AudioEvent } from "@models/AudioEvent";
import { AudioRecording } from "@models/AudioRecording";
import { IParameterModel } from "@models/data/parametersModel";
import { ImplementsInjector } from "@models/ImplementsInjector";
import { AssociationInjector, HasAssociationInjector } from "@models/ImplementsInjector";
import { Project } from "@models/Project";
import { Region } from "@models/Region";
import { Site } from "@models/Site";
Expand Down Expand Up @@ -99,12 +98,12 @@ export class AnnotationSearchParameters
extends AbstractData
implements
IAnnotationSearchParameters,
ImplementsInjector,
HasAssociationInjector,
IParameterModel<AudioEvent>
{
public constructor(
protected queryStringParameters: Params = {},
public injector?: Injector
public injector?: AssociationInjector
) {
const deserializedObject: IAnnotationSearchParameters =
deserializeParamsToObject<IAnnotationSearchParameters>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createRoutingFactory, Spectator, SpyObject } from "@ngneat/spectator";
import { Params } from "@angular/router";
import { of } from "rxjs";
import { CUSTOM_ELEMENTS_SCHEMA, INJECTOR, Injector } from "@angular/core";
import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import { modelData } from "@test/helpers/faker";
import {
MEDIA,
Expand Down Expand Up @@ -34,14 +34,17 @@ import { generateAudioRecording } from "@test/fakes/AudioRecording";
import { ShallowSitesService } from "@baw-api/site/sites.service";
import { patchSharedArrayBuffer } from "src/patches/tests/testPatches";
import { testAsset } from "@test/helpers/karma";
import { assertPageInfo } from "@test/helpers/pageRoute";
import { AssociationInjector } from "@models/ImplementsInjector";
import { ASSOCIATION_INJECTOR } from "@services/association-injector/association-injector.tokens";
import { AnnotationSearchParameters } from "../annotationSearchParameters";
import { AnnotationSearchComponent } from "./search.component";

describe("AnnotationSearchComponent", () => {
const responsePageSize = 24;

let spectator: Spectator<AnnotationSearchComponent>;
let injector: Injector;
let injector: AssociationInjector;

let audioEventsApiSpy: SpyObject<ShallowAudioEventsService>;
let mediaServiceSpy: SpyObject<MediaService>;
Expand All @@ -59,6 +62,12 @@ describe("AnnotationSearchComponent", () => {
const createComponent = createRoutingFactory({
component: AnnotationSearchComponent,
imports: [MockBawApiModule, SharedModule, RouterTestingModule],
providers: [
{
provide: AnnotationService,
useValue: { show: () => mockAnnotationResponse },
},
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
});

Expand All @@ -70,16 +79,10 @@ describe("AnnotationSearchComponent", () => {
regionId: routeRegion.id,
siteId: routeSite.id,
},
providers: [
{
provide: AnnotationService,
useValue: { show: () => mockAnnotationResponse },
},
],
queryParams: queryParameters,
});

injector = spectator.inject(INJECTOR);
injector = spectator.inject(ASSOCIATION_INJECTOR);
mediaServiceSpy = spectator.inject(MEDIA.token);
mediaServiceSpy.createMediaUrl = jasmine.createSpy("createMediaUrl") as any;
mediaServiceSpy.createMediaUrl.and.returnValue(testAsset("example.flac"));
Expand Down Expand Up @@ -149,6 +152,8 @@ describe("AnnotationSearchComponent", () => {
setup();
}));

assertPageInfo(AnnotationSearchComponent, "Search Annotations");

it("should create", () => {
expect(spectator.component).toBeInstanceOf(AnnotationSearchComponent);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
Component,
ElementRef,
Injector,
Inject,
OnInit,
ViewChild,
} from "@angular/core";
Expand All @@ -28,6 +28,8 @@ import { firstValueFrom } from "rxjs";
import { Region } from "@models/Region";
import { Project } from "@models/Project";
import { Site } from "@models/Site";
import { ASSOCIATION_INJECTOR } from "@services/association-injector/association-injector.tokens";
import { AssociationInjector } from "@models/ImplementsInjector";
import { AnnotationSearchParameters } from "../annotationSearchParameters";

const projectKey = "project";
Expand All @@ -51,7 +53,7 @@ class AnnotationSearchComponent
protected config: NgbPaginationConfig,
protected modals: NgbModal,
protected annotationService: AnnotationService,
private injector: Injector
@Inject(ASSOCIATION_INJECTOR) private injector: AssociationInjector
) {
super(
router,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
SHALLOW_SITE,
TAG,
} from "@baw-api/ServiceTokens";
import { CUSTOM_ELEMENTS_SCHEMA, INJECTOR, Injector } from "@angular/core";
import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import { TagsService } from "@baw-api/tag/tags.service";
import { VerificationGridComponent } from "@ecoacoustics/web-components/@types/components/verification-grid/verification-grid";
import { VerificationHelpDialogComponent } from "@ecoacoustics/web-components/@types/components/verification-grid/help-dialog";
Expand Down Expand Up @@ -57,12 +57,14 @@ import { detectChanges } from "@test/helpers/changes";
import { nodeModule, testAsset } from "@test/helpers/karma";
import { patchSharedArrayBuffer } from "src/patches/tests/testPatches";
import { ProgressWarningComponent } from "@components/annotations/components/modals/progress-warning/progress-warning.component";
import { AssociationInjector } from "@models/ImplementsInjector";
import { ASSOCIATION_INJECTOR } from "@services/association-injector/association-injector.tokens";
import { AnnotationSearchParameters } from "../annotationSearchParameters";
import { VerificationComponent } from "./verification.component";

describe("VerificationComponent", () => {
let spectator: SpectatorRouting<VerificationComponent>;
let injector: SpyObject<Injector>;
let injector: SpyObject<AssociationInjector>;

let mockAudioEventsApi: SpyObject<ShallowAudioEventsService>;
let mediaServiceSpy: SpyObject<MediaService>;
Expand Down Expand Up @@ -115,7 +117,7 @@ describe("VerificationComponent", () => {
queryParams: queryParameters,
});

injector = spectator.inject(INJECTOR);
injector = spectator.inject(ASSOCIATION_INJECTOR);

mediaServiceSpy = spectator.inject(MEDIA.token);
mediaServiceSpy.createMediaUrl = jasmine.createSpy("createMediaUrl") as any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
AfterViewInit,
Component,
ElementRef,
Injector,
Inject,
OnInit,
ViewChild,
} from "@angular/core";
Expand Down Expand Up @@ -40,6 +40,8 @@ import { ShallowAudioEventsService } from "@baw-api/audio-event/audio-events.ser
import { AudioEvent } from "@models/AudioEvent";
import { PageFetcherContext } from "@ecoacoustics/web-components/@types/services/gridPageFetcher";
import { annotationResolvers, AnnotationService } from "@services/models/annotation.service";
import { AssociationInjector } from "@models/ImplementsInjector";
import { ASSOCIATION_INJECTOR } from "@services/association-injector/association-injector.tokens";
import { AnnotationSearchParameters } from "../annotationSearchParameters";

// TODO: using extends here makes the interface loosely typed
Expand Down Expand Up @@ -75,7 +77,7 @@ class VerificationComponent
private route: ActivatedRoute,
private router: Router,
private location: Location,
private injector: Injector
@Inject(ASSOCIATION_INJECTOR) private injector: AssociationInjector
) {
super();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Injector } from "@angular/core";
import { RouterTestingModule } from "@angular/router/testing";
import { AudioRecordingsService } from "@baw-api/audio-recording/audio-recordings.service";
import { Filters } from "@baw-api/baw-api.service";
Expand All @@ -18,12 +17,14 @@ import { generateSite } from "@test/fakes/Site";
import { nStepObservable } from "@test/helpers/general";
import { assertSpinner } from "@test/helpers/html";
import { BehaviorSubject, Subject } from "rxjs";
import { AssociationInjector } from "@models/ImplementsInjector";
import { ASSOCIATION_INJECTOR } from "@services/association-injector/association-injector.tokens";
import { DownloadTableComponent } from "./download-table.component";

describe("DownloadTableComponent", () => {
let defaultSite: Site;
let defaultRecording: AudioRecording;
let injector: Injector;
let injector: AssociationInjector;
let siteApi: SpyObject<ShallowSitesService>;
let recordingApi: SpyObject<AudioRecordingsService>;
let spec: Spectator<DownloadTableComponent>;
Expand Down Expand Up @@ -55,7 +56,9 @@ describe("DownloadTableComponent", () => {
spec = createComponent({ detectChanges: false, props: { filters$ } });
recordingApi = spec.inject(AudioRecordingsService);
siteApi = spec.inject(SHALLOW_SITE.token);
injector = spec.inject(Injector);
injector = spec.inject(ASSOCIATION_INJECTOR);
// injector = spec.inject(Injector as any);
// console.log("service", injector.get(ToastrService));
defaultRecording = new AudioRecording(generateAudioRecording(), injector);
defaultSite = new Site(generateSite(), injector);
}
Expand Down
Loading

0 comments on commit 8909001

Please sign in to comment.