stabilise unit tests (#1878)

* cleanup async usage

* cleanup async usage

* fix library favorite tests and code
This commit is contained in:
Denys Vuika 2020-12-11 13:01:31 +00:00 committed by GitHub
parent 72cc4f705f
commit b71e1530d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 153 additions and 183 deletions

View File

@ -22,9 +22,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { ContentActionRef } from '@alfresco/adf-extensions';
import { ContentActionRef, SidebarTabRef } from '@alfresco/adf-extensions';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Store } from '@ngrx/store';
import { SetInfoDrawerStateAction, ToggleInfoDrawerAction } from '@alfresco/aca-shared/store';
import { of, Subject } from 'rxjs';
@ -38,7 +38,7 @@ describe('InfoDrawerComponent', () => {
let fixture: ComponentFixture<InfoDrawerComponent>;
let component: InfoDrawerComponent;
let contentApiService: ContentApiService;
let tab;
let tab: SidebarTabRef;
let appExtensionService: AppExtensionService;
const mockStream = new Subject();
const storeMock = {
@ -61,7 +61,10 @@ describe('InfoDrawerComponent', () => {
TestBed.configureTestingModule({
imports: [LibTestingModule, SharedToolbarModule],
declarations: [InfoDrawerComponent],
providers: [ContentApiService, { provide: AppExtensionService, useValue: extensionServiceMock }, { provide: Store, useValue: storeMock }],
providers: [
{ provide: AppExtensionService, useValue: extensionServiceMock },
{ provide: Store, useValue: storeMock }
],
schemas: [NO_ERRORS_SCHEMA]
});
@ -70,7 +73,7 @@ describe('InfoDrawerComponent', () => {
appExtensionService = TestBed.inject(AppExtensionService);
contentApiService = TestBed.inject(ContentApiService);
tab = { title: 'tab1' };
tab = { title: 'tab1', id: 'tab1', component: '' };
spyOn(appExtensionService, 'getSidebarTabs').and.returnValue([tab]);
});
@ -91,7 +94,7 @@ describe('InfoDrawerComponent', () => {
expect(storeMock.dispatch).toHaveBeenCalledWith(new SetInfoDrawerStateAction(false));
});
it('should set displayNode when node is library', async(() => {
it('should set displayNode when node is library', () => {
spyOn(contentApiService, 'getNodeInfo');
const nodeMock: any = {
entry: { id: 'nodeId' },
@ -104,9 +107,9 @@ describe('InfoDrawerComponent', () => {
expect(component.displayNode).toBe(nodeMock);
expect(contentApiService.getNodeInfo).not.toHaveBeenCalled();
}));
});
it('should call getNodeInfo() when node is a shared file', async(() => {
it('should call getNodeInfo() when node is a shared file', () => {
const response: any = { entry: { id: 'nodeId' } };
spyOn(contentApiService, 'getNodeInfo').and.returnValue(of(response));
const nodeMock: any = { entry: { nodeId: 'nodeId' }, isLibrary: false };
@ -117,9 +120,9 @@ describe('InfoDrawerComponent', () => {
expect(component.displayNode).toBe(response);
expect(contentApiService.getNodeInfo).toHaveBeenCalled();
}));
});
it('should call getNodeInfo() when node is a favorite file', async(() => {
it('should call getNodeInfo() when node is a favorite file', () => {
const response: any = { entry: { id: 'nodeId' } };
spyOn(contentApiService, 'getNodeInfo').and.returnValue(of(response));
const nodeMock: any = {
@ -133,9 +136,9 @@ describe('InfoDrawerComponent', () => {
expect(component.displayNode).toBe(response);
expect(contentApiService.getNodeInfo).toHaveBeenCalled();
}));
});
it('should call getNodeInfo() when node is a recent file', async(() => {
it('should call getNodeInfo() when node is a recent file', () => {
const response: any = { entry: { id: 'nodeId' } };
spyOn(contentApiService, 'getNodeInfo').and.returnValue(of(response));
const nodeMock: any = {
@ -152,7 +155,7 @@ describe('InfoDrawerComponent', () => {
expect(component.displayNode).toBe(response);
expect(contentApiService.getNodeInfo).toHaveBeenCalled();
}));
});
it('should dispatch close panel on Esc keyboard event', () => {
const event = new KeyboardEvent('keydown', {

View File

@ -38,13 +38,13 @@ describe('ContextActionsDirective', () => {
directive = new ContextActionsDirective(storeMock);
});
it('should not render context menu when `enabled` property is false', fakeAsync(() => {
it('should not render context menu when `enabled` property is false', () => {
spyOn(directive, 'execute').and.stub();
directive.enabled = false;
directive.onContextMenuEvent(new MouseEvent('contextmenu'));
expect(directive.execute).not.toHaveBeenCalled();
}));
});
it('should call service to render context menu', fakeAsync(() => {
const el = document.createElement('div');

View File

@ -28,7 +28,6 @@ import { AppTestingModule } from '../../testing/app-testing.module';
import { ContextMenuComponent } from './context-menu.component';
import { ContextMenuModule } from './context-menu.module';
import { ContextMenuOverlayRef } from './context-menu-overlay';
import { TranslateModule, TranslateLoader, TranslateFakeLoader } from '@ngx-translate/core';
import { ContentActionType } from '@alfresco/adf-extensions';
import { of } from 'rxjs';
@ -52,15 +51,8 @@ describe('ContextMenuComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
AppTestingModule,
ContextMenuModule,
TranslateModule.forRoot({
loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }
})
],
imports: [ContextMenuModule, AppTestingModule],
providers: [
AppExtensionService,
{
provide: ContextMenuOverlayRef,
useValue: {
@ -103,11 +95,11 @@ describe('ContextMenuComponent', () => {
expect(contextMenuElements[0].querySelector('span').innerText).toBe(contextItem.title);
}));
it('should run action with provided action id', fakeAsync(() => {
it('should run action with provided action id', () => {
spyOn(extensionsService, 'runActionById');
component.runAction(contextItem.actions.click);
expect(extensionsService.runActionById).toHaveBeenCalledWith(contextItem.actions.click);
}));
});
});

View File

@ -24,7 +24,7 @@
*/
import { Router, ActivatedRoute } from '@angular/router';
import { TestBed, ComponentFixture, async, fakeAsync, tick } from '@angular/core/testing';
import { TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testing';
import { UserPreferencesService, UploadService, AlfrescoApiService } from '@alfresco/adf-core';
import { ClosePreviewAction } from '@alfresco/aca-shared/store';
import { PreviewComponent } from './preview.component';
@ -615,21 +615,23 @@ describe('PreviewComponent', () => {
expect(ids).toEqual(['node2', 'node1']);
});
it('should return to parent folder on nodesDeleted event', async(() => {
it('should return to parent folder on nodesDeleted event', async () => {
spyOn(component, 'navigateToFileLocation');
fixture.detectChanges();
await fixture.whenStable();
contentManagementService.nodesDeleted.next();
expect(component.navigateToFileLocation).toHaveBeenCalled();
}));
});
it('should return to parent folder on fileUploadDeleted event', async(() => {
it('should return to parent folder on fileUploadDeleted event', async () => {
spyOn(component, 'navigateToFileLocation');
fixture.detectChanges();
await fixture.whenStable();
uploadService.fileUploadDeleted.next();
expect(component.navigateToFileLocation).toHaveBeenCalled();
}));
});
it('should emit nodeUpdated event on fileUploadComplete event', fakeAsync(() => {
spyOn(alfrescoApiService.nodeUpdated, 'next');
@ -640,12 +642,13 @@ describe('PreviewComponent', () => {
expect(alfrescoApiService.nodeUpdated.next).toHaveBeenCalled();
}));
it('should return to parent folder when event emitted from extension', async(() => {
it('should return to parent folder when event emitted from extension', async () => {
spyOn(component, 'navigateToFileLocation');
fixture.detectChanges();
await fixture.whenStable();
store.dispatch(new ClosePreviewAction());
expect(component.navigateToFileLocation).toHaveBeenCalled();
}));
});
describe('Keyboard navigation', () => {
beforeEach(() => {

View File

@ -24,7 +24,7 @@
*/
import { SearchInputControlComponent } from './search-input-control.component';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AppTestingModule } from '../../../testing/app-testing.module';
import { NO_ERRORS_SCHEMA } from '@angular/core';
@ -32,19 +32,17 @@ describe('SearchInputControlComponent', () => {
let fixture: ComponentFixture<SearchInputControlComponent>;
let component: SearchInputControlComponent;
beforeEach(async(() => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [AppTestingModule],
declarations: [SearchInputControlComponent],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents()
.then(() => {
});
fixture = TestBed.createComponent(SearchInputControlComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
}));
it('should emit submit event on searchSubmit', async () => {
const keyboardEvent = { target: { value: 'a' } };

View File

@ -24,15 +24,14 @@
*/
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { TestBed, async, ComponentFixture, fakeAsync, tick } from '@angular/core/testing';
import { TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testing';
import { SearchInputComponent } from './search-input.component';
import { AppTestingModule } from '../../../testing/app-testing.module';
import { Actions, ofType } from '@ngrx/effects';
import { SearchByTermAction, SearchActionTypes } from '@alfresco/aca-shared/store';
import { map } from 'rxjs/operators';
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
import { SearchLibrariesQueryBuilderService } from '../search-libraries-results/search-libraries-query-builder.service';
import { ContentManagementService } from '../../../services/content-management.service';
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
describe('SearchInputComponent', () => {
let fixture: ComponentFixture<SearchInputComponent>;
@ -40,22 +39,20 @@ describe('SearchInputComponent', () => {
let actions$: Actions;
let content: ContentManagementService;
beforeEach(async(() => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [AppTestingModule],
declarations: [SearchInputComponent],
schemas: [NO_ERRORS_SCHEMA],
providers: [SearchQueryBuilderService, SearchLibrariesQueryBuilderService]
})
.compileComponents()
.then(() => {
providers: [SearchQueryBuilderService],
schemas: [NO_ERRORS_SCHEMA]
});
actions$ = TestBed.inject(Actions);
fixture = TestBed.createComponent(SearchInputComponent);
content = TestBed.inject(ContentManagementService);
component = fixture.componentInstance;
fixture.detectChanges();
});
}));
it('should change flag on library400Error event', () => {
expect(component.has400LibraryError).toBe(false);

View File

@ -24,7 +24,7 @@
*/
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { SidenavComponent } from './sidenav.component';
import { AppTestingModule } from '../../testing/app-testing.module';
import { AppExtensionService } from '@alfresco/aca-shared';
@ -33,46 +33,44 @@ describe('SidenavComponent', () => {
let fixture: ComponentFixture<SidenavComponent>;
let component: SidenavComponent;
let extensionService: AppExtensionService;
const navbarMock: any = [
beforeEach(() => {
TestBed.configureTestingModule({
imports: [AppTestingModule],
declarations: [SidenavComponent],
schemas: [NO_ERRORS_SCHEMA]
});
fixture = TestBed.createComponent(SidenavComponent);
component = fixture.componentInstance;
extensionService = TestBed.inject(AppExtensionService);
extensionService.navbar = [
{
id: 'route',
items: [
{
route: 'route'
id: 'item-1',
icon: 'item',
route: 'route',
title: 'item-1'
}
]
}
];
});
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [AppTestingModule],
providers: [AppExtensionService],
declarations: [SidenavComponent],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(SidenavComponent);
component = fixture.componentInstance;
extensionService = TestBed.inject(AppExtensionService);
extensionService.navbar = navbarMock;
it('should set the sidenav data', async () => {
fixture.detectChanges();
});
}));
await fixture.whenStable();
// TODO: fix with ADF 4.1
it('should set the sidenav data', async(() => {
expect(component.groups).toEqual([
{
items: [
{
expect(component.groups.length).toBe(1);
expect(component.groups[0].items.length).toBe(1);
expect(component.groups[0].items[0]).toEqual({
id: 'item-1',
icon: 'item',
url: '/route',
route: 'route',
url: '/route'
}
]
} as any
]);
}));
title: 'item-1'
});
});
});

View File

@ -24,9 +24,9 @@
*/
import { Component, ViewChild } from '@angular/core';
import { LibraryFavoriteDirective } from './library-favorite.directive';
import { LibraryEntity, LibraryFavoriteDirective } from './library-favorite.directive';
import { AlfrescoApiService, CoreModule } from '@alfresco/adf-core';
import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { AppTestingModule } from '../testing/app-testing.module';
@ -35,17 +35,17 @@ import { AppTestingModule } from '../testing/app-testing.module';
template: ` <button #favoriteLibrary="favoriteLibrary" [acaFavoriteLibrary]="selection">Favorite</button> `
})
class TestComponent {
@ViewChild('favoriteLibrary')
@ViewChild('favoriteLibrary', { static: true })
directive: LibraryFavoriteDirective;
selection = null;
selection: LibraryEntity = null;
}
describe('LibraryFavoriteDirective', () => {
let fixture: ComponentFixture<TestComponent>;
let api: AlfrescoApiService;
let component: TestComponent;
let selection: { entry: { guid: string; id: string } };
let selection: LibraryEntity;
beforeEach(() => {
TestBed.configureTestingModule({
@ -55,7 +55,8 @@ describe('LibraryFavoriteDirective', () => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
api = TestBed.inject(AlfrescoApiService);
selection = { entry: { guid: 'guid', id: 'id' } };
selection = { entry: { guid: 'guid', id: 'id', title: 'Site', visibility: 'PUBLIC' }, isLibrary: true, isFavorite: false };
component.selection = selection;
});
it('should not check for favorite if no selection exists', () => {
@ -65,59 +66,60 @@ describe('LibraryFavoriteDirective', () => {
expect(api.peopleApi.getFavoriteSite).not.toHaveBeenCalled();
});
it('should mark selection as favorite when getFavoriteSite returns successfully', async(() => {
it('should mark selection as favorite', async () => {
spyOn(api.peopleApi, 'getFavoriteSite').and.returnValue(Promise.resolve(null));
component.selection = selection;
fixture.detectChanges();
fixture.whenStable().then(() => {
delete selection.isFavorite;
fixture.detectChanges();
await fixture.whenStable();
expect(api.peopleApi.getFavoriteSite).toHaveBeenCalled();
expect(component.directive.isFavorite()).toBe(true);
});
}));
it('should mark selection not favorite when getFavoriteSite errors', async(() => {
it('should mark selection not favorite', async () => {
spyOn(api.peopleApi, 'getFavoriteSite').and.returnValue(Promise.reject());
component.selection = selection;
fixture.detectChanges();
fixture.whenStable().then(() => {
delete selection.isFavorite;
fixture.detectChanges();
await fixture.whenStable();
expect(api.peopleApi.getFavoriteSite).toHaveBeenCalled();
expect(component.directive.isFavorite()).toBe(false);
});
}));
it('should call addFavorite() on click event when selection is not a favorite', async(() => {
it('should call addFavorite() on click event when selection is not a favorite', async () => {
spyOn(api.peopleApi, 'getFavoriteSite').and.returnValue(Promise.reject());
spyOn(api.peopleApi, 'addFavorite').and.returnValue(Promise.resolve(null));
component.selection = selection;
fixture.detectChanges();
await fixture.whenStable();
expect(component.directive.isFavorite()).toBeFalsy();
fixture.whenStable().then(() => {
fixture.nativeElement.querySelector('button').dispatchEvent(new MouseEvent('click'));
fixture.detectChanges();
expect(api.peopleApi.addFavorite).toHaveBeenCalled();
});
}));
it('should call removeFavoriteSite() on click event when selection is not a favorite', async(() => {
it('should call removeFavoriteSite() on click event when selection is favorite', async () => {
spyOn(api.peopleApi, 'getFavoriteSite').and.returnValue(Promise.resolve(null));
spyOn(api.favoritesApi, 'removeFavoriteSite').and.returnValue(Promise.resolve());
component.selection = selection;
selection.isFavorite = true;
fixture.detectChanges();
await fixture.whenStable();
expect(component.directive.isFavorite()).toBeFalsy();
expect(component.directive.isFavorite()).toBeTruthy();
fixture.whenStable().then(() => {
fixture.nativeElement.querySelector('button').dispatchEvent(new MouseEvent('click'));
fixture.detectChanges();
await fixture.whenStable();
expect(api.favoritesApi.removeFavoriteSite).toHaveBeenCalled();
});
}));
});

View File

@ -39,7 +39,7 @@ export interface LibraryEntity {
})
export class LibraryFavoriteDirective implements OnChanges {
@Input('acaFavoriteLibrary')
library: any = null;
library: LibraryEntity = null;
@Output() toggle = new EventEmitter<any>();
// tslint:disable-next-line: no-output-native
@ -49,7 +49,19 @@ export class LibraryFavoriteDirective implements OnChanges {
@HostListener('click')
onClick() {
this.toggleFavorite();
const guid = this.targetLibrary.entry.guid;
if (this.targetLibrary.isFavorite) {
this.removeFavorite(guid);
} else {
this.addFavorite({
target: {
site: {
guid
}
}
});
}
}
constructor(private alfrescoApiService: AlfrescoApiService) {}
@ -64,44 +76,23 @@ export class LibraryFavoriteDirective implements OnChanges {
this.markFavoriteLibrary(changes.library.currentValue);
}
isFavorite() {
isFavorite(): boolean {
return this.targetLibrary && this.targetLibrary.isFavorite;
}
toggleFavorite() {
if (this.targetLibrary.isFavorite) {
this.removeFavorite(this.targetLibrary.entry.guid);
} else {
const favoriteBody = this.createFavoriteBody(this.targetLibrary);
this.addFavorite(favoriteBody);
}
}
private async markFavoriteLibrary(library: LibraryEntity) {
if (this.targetLibrary.isFavorite === undefined) {
await this.getFavoriteSite(library);
try {
await this.alfrescoApiService.peopleApi.getFavoriteSite('-me-', library.entry.id);
this.targetLibrary.isFavorite = true;
} catch {
this.targetLibrary.isFavorite = false;
}
} else {
this.targetLibrary = library;
}
}
private getFavoriteSite(library: LibraryEntity) {
this.alfrescoApiService.peopleApi
.getFavoriteSite('-me-', library.entry.id)
.then(() => (this.targetLibrary.isFavorite = true))
.catch(() => (this.targetLibrary.isFavorite = false));
}
private createFavoriteBody(library: LibraryEntity): FavoriteBody {
return {
target: {
site: {
guid: library.entry.guid
}
}
};
}
private addFavorite(favoriteBody: FavoriteBody) {
this.alfrescoApiService.peopleApi
.addFavorite('-me-', favoriteBody)

View File

@ -116,13 +116,10 @@ describe('NodeActionsService', () => {
});
describe('ContentNodeSelector configuration', () => {
it('should validate selection when allowableOperation has `create`', async(() => {
it('should validate selection when allowableOperation has `create`', () => {
spyOn(dialog, 'open');
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
const subject = new Subject<MinimalNodeEntryEntity[]>();
service.getContentNodeSelection('', contentEntities as NodeEntry[]);
subject.next([new TestNode().entry]);
const isSelectionValid = dialog.open['calls'].argsFor(0)[1].data.isSelectionValid({
name: 'some-folder-template',
@ -133,15 +130,12 @@ describe('NodeActionsService', () => {
});
expect(isSelectionValid).toBe(true);
}));
});
it('should invalidate selection when allowableOperation does not have `create`', async(() => {
it('should invalidate selection when allowableOperation does not have `create`', () => {
spyOn(dialog, 'open');
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
const subject = new Subject<MinimalNodeEntryEntity[]>();
service.getContentNodeSelection('', contentEntities as NodeEntry[]);
subject.next([new TestNode().entry]);
const isSelectionValid = dialog.open['calls'].argsFor(0)[1].data.isSelectionValid({
name: 'some-folder-template',
@ -152,15 +146,12 @@ describe('NodeActionsService', () => {
});
expect(isSelectionValid).toBe(false);
}));
});
it('should invalidate selection if isSite', async(() => {
it('should invalidate selection if isSite', () => {
spyOn(dialog, 'open');
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
const subject = new Subject<MinimalNodeEntryEntity[]>();
service.getContentNodeSelection('', contentEntities as NodeEntry[]);
subject.next([new TestNode().entry]);
const isSelectionValid = dialog.open['calls'].argsFor(0)[1].data.isSelectionValid({
name: 'some-folder-template',
@ -172,15 +163,12 @@ describe('NodeActionsService', () => {
});
expect(isSelectionValid).toBe(false);
}));
});
it('should validate selection if not a Site', async(() => {
it('should validate selection if not a Site', () => {
spyOn(dialog, 'open');
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
const subject = new Subject<MinimalNodeEntryEntity[]>();
service.getContentNodeSelection('', contentEntities as NodeEntry[]);
subject.next([new TestNode().entry]);
const isSelectionValid = dialog.open['calls'].argsFor(0)[1].data.isSelectionValid({
name: 'some-folder-template',
@ -192,7 +180,7 @@ describe('NodeActionsService', () => {
});
expect(isSelectionValid).toBe(true);
}));
});
});
describe('doBatchOperation', () => {
@ -244,7 +232,7 @@ describe('NodeActionsService', () => {
});
}));
it("should not throw error if entry in 'contentEntities' does not have id, but has nodeId property", async(() => {
it("should not throw error if entry in 'contentEntities' does not have id, but has nodeId property", () => {
const contentEntities = [new TestNode(), { entry: { nodeId: '1234' } }];
const subject = new Subject<MinimalNodeEntryEntity[]>();
@ -256,7 +244,7 @@ describe('NodeActionsService', () => {
expect(spyOnSuccess).toHaveBeenCalled();
expect(spyOnError).not.toHaveBeenCalledWith(badRequestError);
}));
});
});
describe('getEntryParentId', () => {
@ -580,8 +568,6 @@ describe('NodeActionsService', () => {
copyObservable = service.copyNodeAction(folderToCopy.entry, folderParentAndDestination.entry.id);
});
afterEach(() => subject.complete());
it('when folder to copy has a file as content', async(() => {
const testFamilyNodes = [
{