Merge branch 'DURACOM-191' into DURACOM-234

This commit is contained in:
Giuseppe Digilio
2024-03-17 17:35:40 +01:00
22 changed files with 250 additions and 138 deletions

View File

@@ -1,35 +1,40 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { import {
async,
ComponentFixture, ComponentFixture,
TestBed, TestBed,
waitForAsync,
} from '@angular/core/testing'; } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { NotificationsSuggestionTargetsPageComponent } from '../../../quality-assurance-notifications-pages/notifications-suggestion-targets-page/notifications-suggestion-targets-page.component'; import { PublicationClaimComponent } from '../../../notifications/suggestion-targets/publication-claim/publication-claim.component';
import { AdminNotificationsPublicationClaimPageComponent } from './admin-notifications-publication-claim-page.component';
describe('NotificationsSuggestionTargetsPageComponent', () => { describe('AdminNotificationsPublicationClaimPageComponent', () => {
let component: NotificationsSuggestionTargetsPageComponent; let component: AdminNotificationsPublicationClaimPageComponent;
let fixture: ComponentFixture<NotificationsSuggestionTargetsPageComponent>; let fixture: ComponentFixture<AdminNotificationsPublicationClaimPageComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
CommonModule, CommonModule,
TranslateModule.forRoot(), TranslateModule.forRoot(),
NotificationsSuggestionTargetsPageComponent, AdminNotificationsPublicationClaimPageComponent,
], ],
providers: [ providers: [
NotificationsSuggestionTargetsPageComponent, AdminNotificationsPublicationClaimPageComponent,
], ],
schemas: [NO_ERRORS_SCHEMA], schemas: [NO_ERRORS_SCHEMA],
}).overrideComponent(AdminNotificationsPublicationClaimPageComponent, {
remove: {
imports: [PublicationClaimComponent],
},
}) })
.compileComponents(); .compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(NotificationsSuggestionTargetsPageComponent); fixture = TestBed.createComponent(AdminNotificationsPublicationClaimPageComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@@ -1,3 +1,4 @@
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { import {
ComponentFixture, ComponentFixture,
TestBed, TestBed,
@@ -11,6 +12,7 @@ import { SearchService } from '../../core/shared/search/search.service';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { ActivatedRouteStub } from '../../shared/testing/active-router.stub'; import { ActivatedRouteStub } from '../../shared/testing/active-router.stub';
import { AdminNotifyDashboardComponent } from './admin-notify-dashboard.component'; import { AdminNotifyDashboardComponent } from './admin-notify-dashboard.component';
import { AdminNotifyMetricsComponent } from './admin-notify-metrics/admin-notify-metrics.component';
import { AdminNotifyMessage } from './models/admin-notify-message.model'; import { AdminNotifyMessage } from './models/admin-notify-message.model';
import { AdminNotifySearchResult } from './models/admin-notify-message-search-result.model'; import { AdminNotifySearchResult } from './models/admin-notify-message-search-result.model';
@@ -46,6 +48,11 @@ describe('AdminNotifyDashboardComponent', () => {
{ provide: SearchService, useValue: { search: () => createSuccessfulRemoteDataObject$(results) } }, { provide: SearchService, useValue: { search: () => createSuccessfulRemoteDataObject$(results) } },
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() }, { provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
], ],
schemas: [NO_ERRORS_SCHEMA],
}).overrideComponent(AdminNotifyDashboardComponent, {
remove: {
imports: [AdminNotifyMetricsComponent],
},
}) })
.compileComponents(); .compileComponents();

View File

@@ -3,7 +3,7 @@
[linkType]="linkType" [linkType]="linkType"
[listID]="listID"></ds-collection-search-result-list-element> [listID]="listID"></ds-collection-search-result-list-element>
<div> <div>
<a class="btn btn-light mt-1" [routerLink]="[editPath]"> <a class="btn btn-light mt-1" data-test="coll-link" [routerLink]="[editPath]">
<i class="fa fa-edit"></i> {{"admin.search.collection.edit" | translate}} <i class="fa fa-edit"></i> {{"admin.search.collection.edit" | translate}}
</a> </a>
</div> </div>

View File

@@ -19,6 +19,7 @@ import { mockTruncatableService } from '../../../../../shared/mocks/mock-trucata
import { getMockThemeService } from '../../../../../shared/mocks/theme-service.mock'; import { getMockThemeService } from '../../../../../shared/mocks/theme-service.mock';
import { CollectionElementLinkType } from '../../../../../shared/object-collection/collection-element-link.type'; import { CollectionElementLinkType } from '../../../../../shared/object-collection/collection-element-link.type';
import { CollectionSearchResult } from '../../../../../shared/object-collection/shared/collection-search-result.model'; import { CollectionSearchResult } from '../../../../../shared/object-collection/shared/collection-search-result.model';
import { CollectionSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component';
import { ThemeService } from '../../../../../shared/theme-support/theme.service'; import { ThemeService } from '../../../../../shared/theme-support/theme.service';
import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service';
import { CollectionAdminSearchResultListElementComponent } from './collection-admin-search-result-list-element.component'; import { CollectionAdminSearchResultListElementComponent } from './collection-admin-search-result-list-element.component';
@@ -51,8 +52,13 @@ describe('CollectionAdminSearchResultListElementComponent', () => {
{ provide: ThemeService, useValue: getMockThemeService() }, { provide: ThemeService, useValue: getMockThemeService() },
], ],
schemas: [NO_ERRORS_SCHEMA], schemas: [NO_ERRORS_SCHEMA],
}) }).overrideComponent(CollectionAdminSearchResultListElementComponent, {
.compileComponents(); remove: {
imports: [
CollectionSearchResultListElementComponent,
],
},
}).compileComponents();
})); }));
beforeEach(() => { beforeEach(() => {
@@ -62,7 +68,7 @@ describe('CollectionAdminSearchResultListElementComponent', () => {
component.linkTypes = CollectionElementLinkType; component.linkTypes = CollectionElementLinkType;
component.index = 0; component.index = 0;
component.viewModes = ViewMode; component.viewModes = ViewMode;
fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
@@ -70,10 +76,7 @@ describe('CollectionAdminSearchResultListElementComponent', () => {
}); });
it('should render an edit button with the correct link', () => { it('should render an edit button with the correct link', () => {
component.ngOnInit(); const a = fixture.debugElement.query(By.css('a[data-test="coll-link"]'));
fixture.detectChanges();
const a = fixture.debugElement.query(By.css('a'));
const link = a.nativeElement.href; const link = a.nativeElement.href;
expect(link).toContain(getCollectionEditRoute(id)); expect(link).toContain(getCollectionEditRoute(id));
}); });

View File

@@ -157,13 +157,6 @@ export const APP_ROUTES: Route[] = [
.then((m) => m.ROUTES), .then((m) => m.ROUTES),
canActivate: [EndUserAgreementCurrentUserGuard], canActivate: [EndUserAgreementCurrentUserGuard],
}, },
{
path: NOTIFICATIONS_MODULE_PATH,
loadChildren: () => import('./admin/admin-notifications/admin-notifications-routes')
.then((m) => m.ROUTES),
providers: [provideSuggestionNotificationsState()],
canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard],
},
{ {
path: NOTIFICATIONS_MODULE_PATH, path: NOTIFICATIONS_MODULE_PATH,
loadChildren: () => import('./quality-assurance-notifications-pages/notifications-pages-routes') loadChildren: () => import('./quality-assurance-notifications-pages/notifications-pages-routes')

View File

@@ -8,6 +8,7 @@ import { By } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { BrowseDefinition } from '../../core/shared/browse-definition.model'; import { BrowseDefinition } from '../../core/shared/browse-definition.model';
import { GenericConstructor } from '../../core/shared/generic-constructor';
import { DynamicComponentLoaderDirective } from '../../shared/abstract-component-loader/dynamic-component-loader.directive'; import { DynamicComponentLoaderDirective } from '../../shared/abstract-component-loader/dynamic-component-loader.directive';
import { getMockThemeService } from '../../shared/mocks/theme-service.mock'; import { getMockThemeService } from '../../shared/mocks/theme-service.mock';
import { ActivatedRouteStub } from '../../shared/testing/active-router.stub'; import { ActivatedRouteStub } from '../../shared/testing/active-router.stub';
@@ -24,6 +25,19 @@ import { BrowseByPageComponent } from './browse-by-page.component';
class BrowseByTestComponent { class BrowseByTestComponent {
} }
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'ds-browse-by-switcher',
template: `<ng-template #DynamicComponentLoader dsDynamicComponentLoader></ng-template>`,
standalone: true,
imports: [DynamicComponentLoaderDirective],
})
class TestBrowseBySwitcherComponent extends BrowseBySwitcherComponent {
getComponent(): GenericConstructor<Component> {
return BrowseByTestComponent;
}
}
class TestBrowseByPageBrowseDefinition extends BrowseDefinition { class TestBrowseByPageBrowseDefinition extends BrowseDefinition {
getRenderType(): BrowseByDataType { getRenderType(): BrowseByDataType {
return 'BrowseByPageComponent' as BrowseByDataType; return 'BrowseByPageComponent' as BrowseByDataType;
@@ -42,7 +56,7 @@ describe('BrowseByPageComponent', () => {
themeService = getMockThemeService(); themeService = getMockThemeService();
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [BrowseBySwitcherComponent, BrowseByPageComponent, DynamicComponentLoaderDirective], imports: [TestBrowseBySwitcherComponent, BrowseByPageComponent, DynamicComponentLoaderDirective],
providers: [ providers: [
BrowseByTestComponent, BrowseByTestComponent,
{ provide: ActivatedRoute, useValue: activatedRoute }, { provide: ActivatedRoute, useValue: activatedRoute },
@@ -53,6 +67,9 @@ describe('BrowseByPageComponent', () => {
remove: { remove: {
imports: [BrowseBySwitcherComponent], imports: [BrowseBySwitcherComponent],
}, },
add: {
imports: [TestBrowseBySwitcherComponent],
},
}) })
.compileComponents(); .compileComponents();

View File

@@ -1,15 +1,13 @@
/* eslint-disable max-classes-per-file */ /* eslint-disable max-classes-per-file */
import { Injectable } from '@angular/core';
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { isEmpty } from 'rxjs/operators'; import {
isEmpty,
take,
} from 'rxjs/operators';
import { APP_DATA_SERVICES_MAP } from '../../../../config/app-config.interface'; import { APP_DATA_SERVICES_MAP } from '../../../../config/app-config.interface';
import { import { TestDataService } from '../../../shared/testing/test-data-service.mock';
followLink, import { followLink } from '../../../shared/utils/follow-link-config.model';
FollowLinkConfig,
} from '../../../shared/utils/follow-link-config.model';
import { DATA_SERVICE_FACTORY } from '../../data/base/data-service.decorator';
import { FindListOptions } from '../../data/find-list-options.model';
import { HALLink } from '../../shared/hal-link.model'; import { HALLink } from '../../shared/hal-link.model';
import { HALResource } from '../../shared/hal-resource.model'; import { HALResource } from '../../shared/hal-resource.model';
import { ResourceType } from '../../shared/resource-type'; import { ResourceType } from '../../shared/resource-type';
@@ -39,16 +37,9 @@ class TestModel implements HALResource {
successor?: TestModel; successor?: TestModel;
} }
@Injectable() const mockDataServiceMap: any = {
class TestDataService { [TEST_MODEL.value]: () => import('../../../shared/testing/test-data-service.mock').then(m => m.TestDataService),
findListByHref(href: string, findListOptions: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<any>[]) { };
return 'findListByHref';
}
findByHref(href: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<any>[]) {
return 'findByHref';
}
}
let testDataService: TestDataService; let testDataService: TestDataService;
@@ -76,35 +67,39 @@ describe('LinkService', () => {
spyOn(testDataService, 'findListByHref').and.callThrough(); spyOn(testDataService, 'findListByHref').and.callThrough();
spyOn(testDataService, 'findByHref').and.callThrough(); spyOn(testDataService, 'findByHref').and.callThrough();
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [LinkService, { providers: [
provide: TestDataService, LinkService,
useValue: testDataService, {
}, { provide: TestDataService,
provide: DATA_SERVICE_FACTORY, useValue: testDataService,
useValue: jasmine.createSpy('getDataServiceFor').and.returnValue(TestDataService), },
}, { {
provide: LINK_DEFINITION_FACTORY, provide: APP_DATA_SERVICES_MAP,
useValue: jasmine.createSpy('getLinkDefinition').and.returnValue({ useValue: mockDataServiceMap,
resourceType: TEST_MODEL, },
linkName: 'predecessor', {
propertyName: 'predecessor', provide: LINK_DEFINITION_FACTORY,
}), useValue: jasmine.createSpy('getLinkDefinition').and.returnValue({
}, {
provide: LINK_DEFINITION_MAP_FACTORY,
useValue: jasmine.createSpy('getLinkDefinitions').and.returnValue([
{
resourceType: TEST_MODEL, resourceType: TEST_MODEL,
linkName: 'predecessor', linkName: 'predecessor',
propertyName: 'predecessor', propertyName: 'predecessor',
}, }),
{ },
resourceType: TEST_MODEL, {
linkName: 'successor', provide: LINK_DEFINITION_MAP_FACTORY,
propertyName: 'successor', useValue: jasmine.createSpy('getLinkDefinitions').and.returnValue([
}, {
]), resourceType: TEST_MODEL,
}, linkName: 'predecessor',
{ provide: APP_DATA_SERVICES_MAP, useValue: {} }, propertyName: 'predecessor',
},
{
resourceType: TEST_MODEL,
linkName: 'successor',
propertyName: 'successor',
},
]),
},
], ],
}); });
service = TestBed.inject(LinkService); service = TestBed.inject(LinkService);
@@ -113,10 +108,13 @@ describe('LinkService', () => {
describe('resolveLink', () => { describe('resolveLink', () => {
describe(`when the linkdefinition concerns a single object`, () => { describe(`when the linkdefinition concerns a single object`, () => {
beforeEach(() => { beforeEach(() => {
service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor'))); result = service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor')));
}); });
it('should call dataservice.findByHref with the correct href and nested links', () => { it('should call dataservice.findByHref with the correct href and nested links', (done) => {
expect(testDataService.findByHref).toHaveBeenCalledWith(testModel._links.predecessor.href, true, true, followLink('successor')); result.predecessor.pipe(take(1)).subscribe(() => {
expect(testDataService.findByHref).toHaveBeenCalledWith(testModel._links.predecessor.href, true, true, followLink('successor'));
done();
});
}); });
}); });
describe(`when the linkdefinition concerns a list`, () => { describe(`when the linkdefinition concerns a list`, () => {
@@ -127,10 +125,13 @@ describe('LinkService', () => {
propertyName: 'predecessor', propertyName: 'predecessor',
isList: true, isList: true,
}); });
service.resolveLink(testModel, followLink('predecessor', { findListOptions: { some: 'options ' } as any }, followLink('successor'))); result = service.resolveLink(testModel, followLink('predecessor', { findListOptions: { some: 'options ' } as any }, followLink('successor')));
}); });
it('should call dataservice.findListByHref with the correct href, findListOptions, and nested links', () => { it('should call dataservice.findListByHref with the correct href, findListOptions, and nested links', (done) => {
expect(testDataService.findListByHref).toHaveBeenCalledWith(testModel._links.predecessor.href, { some: 'options ' } as any, true, true, followLink('successor')); result.predecessor.pipe(take(1)).subscribe((res) => {
expect(testDataService.findListByHref).toHaveBeenCalledWith(testModel._links.predecessor.href, { some: 'options ' } as any, true, true, followLink('successor'));
done();
});
}); });
}); });
describe('either way', () => { describe('either way', () => {
@@ -142,15 +143,14 @@ describe('LinkService', () => {
expect((service as any).getLinkDefinition).toHaveBeenCalledWith(testModel.constructor as any, 'predecessor'); expect((service as any).getLinkDefinition).toHaveBeenCalledWith(testModel.constructor as any, 'predecessor');
}); });
it('should call getDataServiceFor with the correct resource type', () => { it('should return the model with the resolved link', (done) => {
expect((service as any).getDataServiceFor).toHaveBeenCalledWith(TEST_MODEL);
});
it('should return the model with the resolved link', () => {
expect(result.type).toBe(TEST_MODEL); expect(result.type).toBe(TEST_MODEL);
expect(result.value).toBe('a test value'); expect(result.value).toBe('a test value');
expect(result._links.self.href).toBe('http://self.link'); expect(result._links.self.href).toBe('http://self.link');
expect(result.predecessor).toBe('findByHref'); result.predecessor.subscribe((res) => {
expect(res).toBe('findByHref');
done();
});
}); });
}); });
@@ -167,12 +167,16 @@ describe('LinkService', () => {
describe(`when there is no dataservice for the resourcetype in the link`, () => { describe(`when there is no dataservice for the resourcetype in the link`, () => {
beforeEach(() => { beforeEach(() => {
((service as any).getDataServiceFor as jasmine.Spy).and.returnValue(undefined); (service as any).map = {};
}); });
it('should throw an error', () => { it('should throw an error', (done) => {
expect(() => { result = service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor')));
service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor'))); result.predecessor.subscribe({
}).toThrow(); error: (error: unknown) => {
expect(error).toBeDefined();
done();
},
});
}); });
}); });
}); });
@@ -237,8 +241,11 @@ describe('LinkService', () => {
result = service.resolveLinks(testModel, followLink('predecessor')); result = service.resolveLinks(testModel, followLink('predecessor'));
}); });
it('should return the model with the resolved link', () => { it('should return the model with the resolved link', (done) => {
expect(result.predecessor).toBe('findByHref'); result.predecessor.subscribe((res) => {
expect(res).toBe('findByHref');
done();
});
}); });
}); });

View File

@@ -7,7 +7,6 @@ import {
import { import {
EMPTY, EMPTY,
Observable, Observable,
of,
} from 'rxjs'; } from 'rxjs';
import { import {
catchError, catchError,
@@ -93,7 +92,7 @@ export class LinkService {
} }
} }
return of(null); return EMPTY;
}), }),
catchError((err: unknown) => { catchError((err: unknown) => {
throw new Error(`The @link() for ${String(linkToFollow.name)} on ${model.constructor.name} models uses the resource type ${matchingLinkDef.resourceType.value.toUpperCase()}, but there is no service with an @dataService(${matchingLinkDef.resourceType.value.toUpperCase()}) annotation in order to retrieve it`); throw new Error(`The @link() for ${String(linkToFollow.name)} on ${model.constructor.name} models uses the resource type ${matchingLinkDef.resourceType.value.toUpperCase()}, but there is no service with an @dataService(${matchingLinkDef.resourceType.value.toUpperCase()}) annotation in order to retrieve it`);

View File

@@ -36,7 +36,7 @@
[authorityValue]="mdValue.newValue.confidence" [authorityValue]="mdValue.newValue.confidence"
[iconMode]="true" [iconMode]="true"
></i> ></i>
<input class="form-control form-outline" [(ngModel)]="mdValue.newValue.authority" [disabled]="!editingAuthority" <input class="form-control form-outline" data-test="authority-input" [(ngModel)]="mdValue.newValue.authority" [disabled]="!editingAuthority"
[attr.aria-label]="(dsoType + '.edit.metadata.edit.authority.key') | translate" [attr.aria-label]="(dsoType + '.edit.metadata.edit.authority.key') | translate"
(change)="onChangeAuthorityKey()" /> (change)="onChangeAuthorityKey()" />
<button class="btn btn-outline-secondary btn-sm ng-star-inserted" id="metadata-confirm-btn" *ngIf="!editingAuthority" <button class="btn btn-outline-secondary btn-sm ng-star-inserted" id="metadata-confirm-btn" *ngIf="!editingAuthority"

View File

@@ -37,6 +37,8 @@ import {
VIRTUAL_METADATA_PREFIX, VIRTUAL_METADATA_PREFIX,
} from '../../../core/shared/metadata.models'; } from '../../../core/shared/metadata.models';
import { ItemMetadataRepresentation } from '../../../core/shared/metadata-representation/item/item-metadata-representation.model'; import { ItemMetadataRepresentation } from '../../../core/shared/metadata-representation/item/item-metadata-representation.model';
import { DsDynamicOneboxComponent } from '../../../shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component';
import { DsDynamicScrollableDropdownComponent } from '../../../shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component';
import { ThemedTypeBadgeComponent } from '../../../shared/object-collection/shared/badges/type-badge/themed-type-badge.component'; import { ThemedTypeBadgeComponent } from '../../../shared/object-collection/shared/badges/type-badge/themed-type-badge.component';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { VarDirective } from '../../../shared/utils/var.directive'; import { VarDirective } from '../../../shared/utils/var.directive';
@@ -202,7 +204,7 @@ describe('DsoEditMetadataValueComponent', () => {
}) })
.overrideComponent(DsoEditMetadataValueComponent, { .overrideComponent(DsoEditMetadataValueComponent, {
remove: { remove: {
imports: [ThemedTypeBadgeComponent], imports: [DsDynamicOneboxComponent, DsDynamicScrollableDropdownComponent, ThemedTypeBadgeComponent],
}, },
}) })
.compileComponents(); .compileComponents();
@@ -464,22 +466,30 @@ describe('DsoEditMetadataValueComponent', () => {
expect(component.onChangeEditingAuthorityStatus).toHaveBeenCalledWith(true); expect(component.onChangeEditingAuthorityStatus).toHaveBeenCalledWith(true);
}); });
it('should disable the input when editingAuthority is false', () => { it('should disable the input when editingAuthority is false', (done) => {
component.editingAuthority = false; component.editingAuthority = false;
fixture.detectChanges(); fixture.detectChanges();
const inputElement = fixture.nativeElement.querySelector('input'); fixture.detectChanges();
expect(inputElement.disabled).toBe(true); fixture.whenStable().then(() => {
const inputElement = fixture.nativeElement.querySelector('input[data-test="authority-input"]');
expect(inputElement.disabled).toBeTruthy();
done();
});
}); });
it('should enable the input when editingAuthority is true', () => { it('should enable the input when editingAuthority is true', (done) => {
component.editingAuthority = true; component.editingAuthority = true;
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => {
const inputElement = fixture.nativeElement.querySelector('input[data-test="authority-input"]');
expect(inputElement.disabled).toBeFalsy();
done();
});
const inputElement = fixture.nativeElement.querySelector('input');
expect(inputElement.disabled).toBe(false);
}); });
it('should update mdValue.newValue properties when authority is present', () => { it('should update mdValue.newValue properties when authority is present', () => {

View File

@@ -18,7 +18,10 @@ import {
} from '@ngx-translate/core'; } from '@ngx-translate/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { APP_CONFIG } from '../../../../../config/app-config.interface'; import {
APP_CONFIG,
APP_DATA_SERVICES_MAP,
} from '../../../../../config/app-config.interface';
import { BrowseDefinitionDataService } from '../../../../core/browse/browse-definition-data.service'; import { BrowseDefinitionDataService } from '../../../../core/browse/browse-definition-data.service';
import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service'; import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../../../../core/cache/object-cache.service'; import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
@@ -42,15 +45,23 @@ import { UUIDService } from '../../../../core/shared/uuid.service';
import { WorkspaceitemDataService } from '../../../../core/submission/workspaceitem-data.service'; import { WorkspaceitemDataService } from '../../../../core/submission/workspaceitem-data.service';
import { MetadataValuesComponent } from '../../../../item-page/field-components/metadata-values/metadata-values.component'; import { MetadataValuesComponent } from '../../../../item-page/field-components/metadata-values/metadata-values.component';
import { GenericItemPageFieldComponent } from '../../../../item-page/simple/field-components/specific-field/generic/generic-item-page-field.component'; import { GenericItemPageFieldComponent } from '../../../../item-page/simple/field-components/specific-field/generic/generic-item-page-field.component';
import { ThemedItemPageTitleFieldComponent } from '../../../../item-page/simple/field-components/specific-field/title/themed-item-page-field.component';
import { mockRouteService } from '../../../../item-page/simple/item-types/shared/item.component.spec'; import { mockRouteService } from '../../../../item-page/simple/item-types/shared/item.component.spec';
import { ThemedMetadataRepresentationListComponent } from '../../../../item-page/simple/metadata-representation-list/themed-metadata-representation-list.component';
import { TabbedRelatedEntitiesSearchComponent } from '../../../../item-page/simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component';
import { RelatedItemsComponent } from '../../../../item-page/simple/related-items/related-items-component';
import { DsoEditMenuComponent } from '../../../../shared/dso-page/dso-edit-menu/dso-edit-menu.component';
import { isNotEmpty } from '../../../../shared/empty.util'; import { isNotEmpty } from '../../../../shared/empty.util';
import { MetadataFieldWrapperComponent } from '../../../../shared/metadata-field-wrapper/metadata-field-wrapper.component';
import { mockTruncatableService } from '../../../../shared/mocks/mock-trucatable.service'; import { mockTruncatableService } from '../../../../shared/mocks/mock-trucatable.service';
import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock'; import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock';
import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
import { ThemedResultsBackButtonComponent } from '../../../../shared/results-back-button/themed-results-back-button.component';
import { BrowseDefinitionDataServiceStub } from '../../../../shared/testing/browse-definition-data-service.stub'; import { BrowseDefinitionDataServiceStub } from '../../../../shared/testing/browse-definition-data-service.stub';
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { ThemedThumbnailComponent } from '../../../../thumbnail/themed-thumbnail.component';
import { JournalComponent } from './journal.component'; import { JournalComponent } from './journal.component';
let comp: JournalComponent; let comp: JournalComponent;
@@ -121,9 +132,22 @@ describe('JournalComponent', () => {
{ provide: RouteService, useValue: mockRouteService }, { provide: RouteService, useValue: mockRouteService },
{ provide: BrowseDefinitionDataService, useValue: BrowseDefinitionDataServiceStub }, { provide: BrowseDefinitionDataService, useValue: BrowseDefinitionDataServiceStub },
{ provide: APP_CONFIG, useValue: {} }, { provide: APP_CONFIG, useValue: {} },
{ provide: APP_DATA_SERVICES_MAP, useValue: {} },
], ],
schemas: [NO_ERRORS_SCHEMA], schemas: [NO_ERRORS_SCHEMA],
}).overrideComponent(JournalComponent, { }).overrideComponent(JournalComponent, {
remove: {
imports: [
ThemedResultsBackButtonComponent,
ThemedItemPageTitleFieldComponent,
DsoEditMenuComponent,
MetadataFieldWrapperComponent,
ThemedThumbnailComponent,
RelatedItemsComponent,
TabbedRelatedEntitiesSearchComponent,
ThemedMetadataRepresentationListComponent,
],
},
add: { changeDetection: ChangeDetectionStrategy.Default }, add: { changeDetection: ChangeDetectionStrategy.Default },
}) })
.overrideComponent(GenericItemPageFieldComponent, { .overrideComponent(GenericItemPageFieldComponent, {

View File

@@ -3,6 +3,7 @@ import {
fakeAsync, fakeAsync,
TestBed, TestBed,
tick, tick,
waitForAsync,
} from '@angular/core/testing'; } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { NotifyRequestsStatusDataService } from 'src/app/core/data/notify-services-status-data.service'; import { NotifyRequestsStatusDataService } from 'src/app/core/data/notify-services-status-data.service';
@@ -10,6 +11,7 @@ import { NotifyRequestsStatusDataService } from 'src/app/core/data/notify-servic
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
import { NotifyRequestsStatus } from '../notify-requests-status.model'; import { NotifyRequestsStatus } from '../notify-requests-status.model';
import { RequestStatusEnum } from '../notify-status.enum'; import { RequestStatusEnum } from '../notify-status.enum';
import { RequestStatusAlertBoxComponent } from '../request-status-alert-box/request-status-alert-box.component';
import { NotifyRequestsStatusComponent } from './notify-requests-status.component'; import { NotifyRequestsStatusComponent } from './notify-requests-status.component';
describe('NotifyRequestsStatusComponent', () => { describe('NotifyRequestsStatusComponent', () => {
@@ -22,7 +24,7 @@ describe('NotifyRequestsStatusComponent', () => {
itemuuid: 'testUuid', itemuuid: 'testUuid',
}); });
beforeEach(() => { beforeEach(waitForAsync(() => {
notifyInfoServiceSpy = { notifyInfoServiceSpy = {
getNotifyRequestsStatus:() => createSuccessfulRemoteDataObject$(mock), getNotifyRequestsStatus:() => createSuccessfulRemoteDataObject$(mock),
}; };
@@ -31,8 +33,12 @@ describe('NotifyRequestsStatusComponent', () => {
providers: [ providers: [
{ provide: NotifyRequestsStatusDataService, useValue: notifyInfoServiceSpy }, { provide: NotifyRequestsStatusDataService, useValue: notifyInfoServiceSpy },
], ],
}).overrideComponent(NotifyRequestsStatusComponent, {
remove: {
imports: [RequestStatusAlertBoxComponent],
},
}); });
}); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(NotifyRequestsStatusComponent); fixture = TestBed.createComponent(NotifyRequestsStatusComponent);

View File

@@ -1,10 +1,6 @@
<ng-container *ngIf="data?.length > 0 && displayOptions"> <ng-container *ngIf="data?.length > 0 && displayOptions">
<div <div [ngClass]="{'align-items-center': data.length === 1}"
[ngClass]="{'align-items-center': data.length === 1}" class="alert d-flex flex-row sections-gap {{displayOptions.alertType}}">
class="alert d-flex flex-row sections-gap {{
displayOptions.alertType
}}"
>
<img <img
class="source-logo" class="source-logo"
src="assets/images/qa-coar-notify-logo.png" src="assets/images/qa-coar-notify-logo.png"
@@ -14,17 +10,11 @@
<ds-truncatable-part [id]="status" [minLines]="1"> <ds-truncatable-part [id]="status" [minLines]="1">
<div class="w-100 d-flex flex-column"> <div class="w-100 d-flex flex-column">
<ng-container *ngFor="let request of data"> <ng-container *ngFor="let request of data">
<div <div [innerHTML]="displayOptions.text | translate: {
[innerHTML]=" serviceName: request.serviceName,
displayOptions.text serviceUrl: request.serviceUrl,
| translate offerType: request.offerType
: { }"></div>
serviceName: request.serviceName,
serviceUrl: request.serviceUrl,
offerType: request.offerType
}
"
></div>
</ng-container> </ng-container>
</div> </div>
</ds-truncatable-part> </ds-truncatable-part>

View File

@@ -2,9 +2,12 @@ import {
ComponentFixture, ComponentFixture,
fakeAsync, fakeAsync,
TestBed, TestBed,
waitForAsync,
} from '@angular/core/testing'; } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { TruncatableComponent } from '../../../../shared/truncatable/truncatable.component';
import { TruncatablePartComponent } from '../../../../shared/truncatable/truncatable-part/truncatable-part.component';
import { RequestStatusEnum } from '../notify-status.enum'; import { RequestStatusEnum } from '../notify-status.enum';
import { RequestStatusAlertBoxComponent } from './request-status-alert-box.component'; import { RequestStatusAlertBoxComponent } from './request-status-alert-box.component';
@@ -28,11 +31,15 @@ describe('RequestStatusAlertBoxComponent', () => {
}, },
]; ];
beforeEach(async () => { beforeEach(waitForAsync(() => {
await TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), RequestStatusAlertBoxComponent], imports: [TranslateModule.forRoot(), RequestStatusAlertBoxComponent],
}).overrideComponent(RequestStatusAlertBoxComponent, {
remove: {
imports: [TruncatablePartComponent, TruncatableComponent],
},
}).compileComponents(); }).compileComponents();
}); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(RequestStatusAlertBoxComponent); fixture = TestBed.createComponent(RequestStatusAlertBoxComponent);

View File

@@ -1,6 +1,7 @@
import { import {
NgClass, NgClass,
NgForOf, NgForOf,
NgIf,
} from '@angular/common'; } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
@@ -22,6 +23,7 @@ import { RequestStatusEnum } from '../notify-status.enum';
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true, standalone: true,
imports: [ imports: [
NgIf,
TruncatablePartComponent, TruncatablePartComponent,
TruncatableComponent, TruncatableComponent,
NgForOf, NgForOf,

View File

@@ -1,3 +1,4 @@
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { import {
ComponentFixture, ComponentFixture,
TestBed, TestBed,
@@ -19,7 +20,9 @@ import { EPersonDataService } from '../../../core/eperson/eperson-data.service';
import { EPerson } from '../../../core/eperson/models/eperson.model'; import { EPerson } from '../../../core/eperson/models/eperson.model';
import { PaginationService } from '../../../core/pagination/pagination.service'; import { PaginationService } from '../../../core/pagination/pagination.service';
import { RouteService } from '../../../core/services/route.service'; import { RouteService } from '../../../core/services/route.service';
import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component';
import { AuthServiceMock } from '../../../shared/mocks/auth.service.mock'; import { AuthServiceMock } from '../../../shared/mocks/auth.service.mock';
import { PaginationComponent } from '../../../shared/pagination/pagination.component';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
import { routeServiceStub } from '../../../shared/testing/route-service.stub'; import { routeServiceStub } from '../../../shared/testing/route-service.stub';
@@ -143,6 +146,11 @@ describe('ProcessOverviewTableComponent', () => {
{ provide: AuthService, useValue: authService }, { provide: AuthService, useValue: authService },
{ provide: RouteService, useValue: routeService }, { provide: RouteService, useValue: routeService },
], ],
schemas: [NO_ERRORS_SCHEMA],
}).overrideComponent(ProcessOverviewTableComponent, {
remove: {
imports: [ PaginationComponent, ThemedLoadingComponent ],
},
}).compileComponents(); }).compileComponents();
})); }));

View File

@@ -1,9 +1,9 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { import {
async,
ComponentFixture, ComponentFixture,
TestBed, TestBed,
waitForAsync,
} from '@angular/core/testing'; } from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -17,7 +17,7 @@ describe('NotificationsSuggestionTargetsPageComponent', () => {
let component: NotificationsSuggestionTargetsPageComponent; let component: NotificationsSuggestionTargetsPageComponent;
let fixture: ComponentFixture<NotificationsSuggestionTargetsPageComponent>; let fixture: ComponentFixture<NotificationsSuggestionTargetsPageComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
CommonModule, CommonModule,
@@ -32,7 +32,7 @@ describe('NotificationsSuggestionTargetsPageComponent', () => {
}) })
.overrideComponent(NotificationsSuggestionTargetsPageComponent, { .overrideComponent(NotificationsSuggestionTargetsPageComponent, {
remove: { remove: {
providers: [PublicationClaimComponent], imports: [PublicationClaimComponent],
}, },
}) })
.compileComponents(); .compileComponents();

View File

@@ -14,6 +14,7 @@ import { SearchConfigurationService } from '../core/shared/search/search-configu
import { configureSearchComponentTestingModule } from '../shared/search/search.component.spec'; import { configureSearchComponentTestingModule } from '../shared/search/search.component.spec';
import { ConfigurationSearchPageComponent } from './configuration-search-page.component'; import { ConfigurationSearchPageComponent } from './configuration-search-page.component';
import createSpy = jasmine.createSpy; import createSpy = jasmine.createSpy;
import { of } from 'rxjs';
const CONFIGURATION = 'test-configuration'; const CONFIGURATION = 'test-configuration';
const QUERY = 'test query'; const QUERY = 'test query';
@@ -52,6 +53,7 @@ describe('ConfigurationSearchPageComponent', () => {
routeService = TestBed.inject(RouteService); routeService = TestBed.inject(RouteService);
routeService.setParameter = createSpy('setParameter'); routeService.setParameter = createSpy('setParameter');
routeService.getRouteParameterValue = createSpy('getRouteParameterValue').and.returnValue(of(CONFIGURATION));
fixture.detectChanges(); fixture.detectChanges();

View File

@@ -1,5 +1,8 @@
// eslint-disable-next-line max-classes-per-file // eslint-disable-next-line max-classes-per-file
import { Component } from '@angular/core'; import {
Component,
NO_ERRORS_SCHEMA,
} from '@angular/core';
import { import {
ComponentFixture, ComponentFixture,
TestBed, TestBed,
@@ -10,6 +13,7 @@ import { ActivatedRoute } from '@angular/router';
import { BrowseByDataType } from '../../../../browse-by/browse-by-switcher/browse-by-data-type'; import { BrowseByDataType } from '../../../../browse-by/browse-by-switcher/browse-by-data-type';
import { BrowseBySwitcherComponent } from '../../../../browse-by/browse-by-switcher/browse-by-switcher.component'; import { BrowseBySwitcherComponent } from '../../../../browse-by/browse-by-switcher/browse-by-switcher.component';
import { BrowseDefinition } from '../../../../core/shared/browse-definition.model'; import { BrowseDefinition } from '../../../../core/shared/browse-definition.model';
import { GenericConstructor } from '../../../../core/shared/generic-constructor';
import { DynamicComponentLoaderDirective } from '../../../abstract-component-loader/dynamic-component-loader.directive'; import { DynamicComponentLoaderDirective } from '../../../abstract-component-loader/dynamic-component-loader.directive';
import { getMockThemeService } from '../../../mocks/theme-service.mock'; import { getMockThemeService } from '../../../mocks/theme-service.mock';
import { ActivatedRouteStub } from '../../../testing/active-router.stub'; import { ActivatedRouteStub } from '../../../testing/active-router.stub';
@@ -24,6 +28,18 @@ import { ComcolBrowseByComponent } from './comcol-browse-by.component';
class BrowseByTestComponent { class BrowseByTestComponent {
} }
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'ds-browse-by-switcher',
template: `<ng-template #DynamicComponentLoader dsDynamicComponentLoader></ng-template>`,
standalone: true,
imports: [DynamicComponentLoaderDirective],
})
class TestBrowseBySwitcherComponent extends BrowseBySwitcherComponent {
getComponent(): GenericConstructor<Component> {
return BrowseByTestComponent;
}
}
class TestBrowseByPageBrowseDefinition extends BrowseDefinition { class TestBrowseByPageBrowseDefinition extends BrowseDefinition {
getRenderType(): BrowseByDataType { getRenderType(): BrowseByDataType {
return 'ComcolBrowseByComponent' as BrowseByDataType; return 'ComcolBrowseByComponent' as BrowseByDataType;
@@ -42,17 +58,21 @@ describe('ComcolBrowseByComponent', () => {
themeService = getMockThemeService(); themeService = getMockThemeService();
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [BrowseBySwitcherComponent, ComcolBrowseByComponent, DynamicComponentLoaderDirective], imports: [TestBrowseBySwitcherComponent, ComcolBrowseByComponent, DynamicComponentLoaderDirective],
providers: [ providers: [
BrowseByTestComponent, BrowseByTestComponent,
{ provide: ActivatedRoute, useValue: activatedRoute }, { provide: ActivatedRoute, useValue: activatedRoute },
{ provide: ThemeService, useValue: themeService }, { provide: ThemeService, useValue: themeService },
], ],
schemas: [NO_ERRORS_SCHEMA],
}) })
.overrideComponent(ComcolBrowseByComponent, { .overrideComponent(ComcolBrowseByComponent, {
remove: { remove: {
imports: [BrowseBySwitcherComponent], imports: [BrowseBySwitcherComponent],
}, },
add: {
imports: [TestBrowseBySwitcherComponent],
},
}) })
.compileComponents(); .compileComponents();

View File

@@ -1,21 +1,13 @@
import { AdminNotifySearchResultComponent } from '../../../../admin/admin-notify-dashboard/admin-notify-search-result/admin-notify-search-result.component';
import { AdminNotifySearchResult } from '../../../../admin/admin-notify-dashboard/models/admin-notify-message-search-result.model';
import { Context } from '../../../../core/shared/context.model'; import { Context } from '../../../../core/shared/context.model';
import { ViewMode } from '../../../../core/shared/view-mode.model'; import { ViewMode } from '../../../../core/shared/view-mode.model';
import { getTabulatableObjectsComponent } from './tabulatable-objects.decorator'; import { getTabulatableObjectsComponent } from './tabulatable-objects.decorator';
const type = 'TestType';
class TestTable {
}
describe('TabulatableObject decorator function', () => { describe('TabulatableObject decorator function', () => {
it('should have a decorator for table', () => {
const tableDecorator = getTabulatableObjectsComponent(['Item'], ViewMode.Table);
expect(tableDecorator.length).not.toBeNull();
});
it('should return the matching class', () => { it('should return the matching class', () => {
const component = getTabulatableObjectsComponent([type], ViewMode.Table, Context.Search); const component = getTabulatableObjectsComponent([AdminNotifySearchResult], ViewMode.Table, Context.CoarNotify);
expect(component).toEqual(TestTable); expect(component).toEqual(AdminNotifySearchResultComponent);
}); });
}); });

View File

@@ -18,6 +18,7 @@ import { DSONameServiceMock } from '../../../../mocks/dso-name.service.mock';
import { createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils'; import { createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils';
import { TruncatableService } from '../../../../truncatable/truncatable.service'; import { TruncatableService } from '../../../../truncatable/truncatable.service';
import { TruncatePipe } from '../../../../utils/truncate.pipe'; import { TruncatePipe } from '../../../../utils/truncate.pipe';
import { ItemSearchResultGridElementComponent } from '../../../search-result-grid-element/item-search-result/item/item-search-result-grid-element.component';
import { ItemGridElementComponent } from './item-grid-element.component'; import { ItemGridElementComponent } from './item-grid-element.component';
@@ -69,6 +70,9 @@ describe('ItemGridElementComponent', () => {
], ],
schemas: [NO_ERRORS_SCHEMA], schemas: [NO_ERRORS_SCHEMA],
}).overrideComponent(ItemGridElementComponent, { }).overrideComponent(ItemGridElementComponent, {
remove: {
imports: [ItemSearchResultGridElementComponent],
},
add: { changeDetection: ChangeDetectionStrategy.Default }, add: { changeDetection: ChangeDetectionStrategy.Default },
}).compileComponents(); }).compileComponents();
})); }));

View File

@@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { FindListOptions } from '../../core/data/find-list-options.model';
import { FollowLinkConfig } from '../utils/follow-link-config.model';
@Injectable()
export class TestDataService {
findListByHref(href: string, findListOptions: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<any>[]) {
return of('findListByHref');
}
findByHref(href: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<any>[]) {
return of('findByHref');
}
}