mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ACS-6140] migrate tests to harness (#9071)
* migrate aspect list tests to harness * [ci:force] categories management * [ci:force] fix keyboard handling * [ci:force] fix memory leak * migrate document list * migrate new version uploader dialog * migrate folder dialog * bug fixes for keyboard, remove fake unit tests * [ci:force] migrate and cleanup notification tests * migrate app details cloud * migrate app list cloud * migrate group cloud component * [ci:force] cleanup code based on reviews * [ci:force] migrate people cloud * [ci:force] migrate process list cloud * [ci:force] migrate start process cloud * [ci:force] task form cloud * [ci:force] service task list cloud * [ci:force] task list cloud * [ci:force] process attachment list and apps list * [ci:force] code review changes * [ci:force] app list bug fixes and code cleanup * [ci:force] fix incorrect/missing typings, fix tests * [ci:force] code cleanup
This commit is contained in:
@@ -39,6 +39,6 @@
|
||||
|
||||
<ng-template #loading>
|
||||
<div class="adf-aspect-list-spinner">
|
||||
<mat-spinner id="adf-aspect-spinner"></mat-spinner>
|
||||
<mat-progress-spinner mode="indeterminate" id="adf-aspect-spinner"></mat-progress-spinner>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
@@ -24,8 +24,15 @@ import { AspectListService } from './services/aspect-list.service';
|
||||
import { of } from 'rxjs';
|
||||
import { AspectEntry } from '@alfresco/js-api';
|
||||
import { delay } from 'rxjs/operators';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatExpansionPanelHarness } from '@angular/material/expansion/testing';
|
||||
import { MatTableHarness } from '@angular/material/table/testing';
|
||||
import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
|
||||
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
|
||||
|
||||
const aspectListMock: AspectEntry[] = [{
|
||||
const aspectListMock: AspectEntry[] = [
|
||||
{
|
||||
entry: {
|
||||
parentId: 'frs:aspectZero',
|
||||
id: 'frs:AspectOne',
|
||||
@@ -44,8 +51,8 @@ const aspectListMock: AspectEntry[] = [{
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
entry: {
|
||||
parentId: 'frs:AspectZer',
|
||||
id: 'frs:SecondAspect',
|
||||
@@ -64,9 +71,11 @@ const aspectListMock: AspectEntry[] = [{
|
||||
}
|
||||
]
|
||||
}
|
||||
}];
|
||||
}
|
||||
];
|
||||
|
||||
const customAspectListMock: AspectEntry[] = [{
|
||||
const customAspectListMock: AspectEntry[] = [
|
||||
{
|
||||
entry: {
|
||||
parentId: 'cst:parentAspect',
|
||||
id: 'cst:customAspect',
|
||||
@@ -85,8 +94,8 @@ const customAspectListMock: AspectEntry[] = [{
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
entry: {
|
||||
parentId: 'cst:commonaspect',
|
||||
id: 'cst:nonamedAspect',
|
||||
@@ -100,10 +109,11 @@ const customAspectListMock: AspectEntry[] = [{
|
||||
}
|
||||
]
|
||||
}
|
||||
}];
|
||||
}
|
||||
];
|
||||
|
||||
describe('AspectListComponent', () => {
|
||||
|
||||
let loader: HarnessLoader;
|
||||
let component: AspectListComponent;
|
||||
let fixture: ComponentFixture<AspectListComponent>;
|
||||
let aspectListService: AspectListService;
|
||||
@@ -111,36 +121,31 @@ describe('AspectListComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ContentTestingModule
|
||||
],
|
||||
imports: [TranslateModule.forRoot(), ContentTestingModule],
|
||||
providers: [AspectListService]
|
||||
});
|
||||
});
|
||||
|
||||
describe('Loading', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AspectListComponent);
|
||||
component = fixture.componentInstance;
|
||||
nodeService = TestBed.inject(NodesApiService);
|
||||
aspectListService = TestBed.inject(AspectListService);
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
it('should show the loading spinner when result is loading', () => {
|
||||
it('should show the loading spinner when result is loading', async () => {
|
||||
const delayResult = of(null).pipe(delay(0));
|
||||
spyOn(nodeService, 'getNode').and.returnValue(delayResult);
|
||||
spyOn(aspectListService, 'getAspects').and.returnValue(delayResult);
|
||||
fixture.detectChanges();
|
||||
const spinner = fixture.nativeElement.querySelector('#adf-aspect-spinner');
|
||||
expect(spinner).toBeDefined();
|
||||
expect(spinner).not.toBeNull();
|
||||
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('When passing a node id', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AspectListComponent);
|
||||
component = fixture.componentInstance;
|
||||
@@ -152,6 +157,7 @@ describe('AspectListComponent', () => {
|
||||
spyOn(nodeService, 'getNode').and.returnValue(of({ id: 'fake-node-id', aspectNames: ['frs:AspectOne'] } as any));
|
||||
component.nodeId = 'fake-node-id';
|
||||
fixture.detectChanges();
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -167,106 +173,80 @@ describe('AspectListComponent', () => {
|
||||
expect(component.hasEqualAspect).toBe(false);
|
||||
});
|
||||
|
||||
it('should show all the aspects', () => {
|
||||
const firstElement = fixture.nativeElement.querySelector('#aspect-list-FirstAspect');
|
||||
const secondElement = fixture.nativeElement.querySelector('#aspect-list-SecondAspect');
|
||||
|
||||
expect(firstElement).not.toBeNull();
|
||||
expect(firstElement).toBeDefined();
|
||||
expect(secondElement).not.toBeNull();
|
||||
expect(secondElement).toBeDefined();
|
||||
it('should show all the aspects', async () => {
|
||||
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-FirstAspect' }))).toBe(true);
|
||||
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-SecondAspect' }))).toBe(true);
|
||||
});
|
||||
|
||||
it('should show aspect id when name or title is not set', () => {
|
||||
const noNameAspect: HTMLElement = fixture.nativeElement.querySelector('#aspect-list-cst-nonamedAspect .adf-aspect-list-element-title');
|
||||
const noNameAspect = fixture.nativeElement.querySelector('#aspect-list-cst-nonamedAspect .adf-aspect-list-element-title');
|
||||
expect(noNameAspect).toBeDefined();
|
||||
expect(noNameAspect).not.toBeNull();
|
||||
expect(noNameAspect.innerText).toBe('cst:nonamedAspect');
|
||||
});
|
||||
|
||||
it('should show the details when a row is clicked', () => {
|
||||
const firstElement = fixture.nativeElement.querySelector('#aspect-list-FirstAspect');
|
||||
firstElement.click();
|
||||
fixture.detectChanges();
|
||||
const firstElementDesc = fixture.nativeElement.querySelector('#aspect-list-0-description');
|
||||
expect(firstElementDesc).not.toBeNull();
|
||||
expect(firstElementDesc).toBeDefined();
|
||||
it('should show the details when a row is clicked', async () => {
|
||||
const panel = await loader.getHarness(MatExpansionPanelHarness);
|
||||
await panel.expand();
|
||||
expect(await panel.getDescription()).not.toBeNull();
|
||||
|
||||
const firstElementPropertyTable = fixture.nativeElement.querySelector('#aspect-list-0-properties-table');
|
||||
expect(firstElementPropertyTable).not.toBeNull();
|
||||
expect(firstElementPropertyTable).toBeDefined();
|
||||
const nameProperties = fixture.nativeElement.querySelectorAll('#aspect-list-0-properties-table tbody .mat-column-name');
|
||||
expect(nameProperties[0]).not.toBeNull();
|
||||
expect(nameProperties[0]).toBeDefined();
|
||||
expect(nameProperties[0].innerText).toBe('channelPassword');
|
||||
expect(nameProperties[1]).not.toBeNull();
|
||||
expect(nameProperties[1]).toBeDefined();
|
||||
expect(nameProperties[1].innerText).toBe('channelUsername');
|
||||
const table = await panel.getHarness(MatTableHarness);
|
||||
const [row1, row2] = await table.getRows();
|
||||
const [r1c1, r1c2, r1c3] = await row1.getCells();
|
||||
expect(await r1c1.getText()).toBe('channelPassword');
|
||||
expect(await r1c2.getText()).toBe('The authenticated channel password');
|
||||
expect(await r1c3.getText()).toBe('d:propA');
|
||||
|
||||
const titleProperties = fixture.nativeElement.querySelectorAll('#aspect-list-0-properties-table tbody .mat-column-title');
|
||||
expect(titleProperties[0]).not.toBeNull();
|
||||
expect(titleProperties[0]).toBeDefined();
|
||||
expect(titleProperties[0].innerText).toBe('The authenticated channel password');
|
||||
expect(titleProperties[1]).not.toBeNull();
|
||||
expect(titleProperties[1]).toBeDefined();
|
||||
expect(titleProperties[1].innerText).toBe('The authenticated channel username');
|
||||
|
||||
const dataTypeProperties = fixture.nativeElement.querySelectorAll('#aspect-list-0-properties-table tbody .mat-column-dataType');
|
||||
expect(dataTypeProperties[0]).not.toBeNull();
|
||||
expect(dataTypeProperties[0]).toBeDefined();
|
||||
expect(dataTypeProperties[0].innerText).toBe('d:propA');
|
||||
expect(dataTypeProperties[1]).not.toBeNull();
|
||||
expect(dataTypeProperties[1]).toBeDefined();
|
||||
expect(dataTypeProperties[1].innerText).toBe('d:propB');
|
||||
const [r2c1, r2c2, r2c3] = await row2.getCells();
|
||||
expect(await r2c1.getText()).toBe('channelUsername');
|
||||
expect(await r2c2.getText()).toBe('The authenticated channel username');
|
||||
expect(await r2c3.getText()).toBe('d:propB');
|
||||
});
|
||||
|
||||
it('should show as checked the node properties', () => {
|
||||
const firstAspectCheckbox: HTMLInputElement = fixture.nativeElement.querySelector('#aspect-list-0-check-input');
|
||||
expect(firstAspectCheckbox).toBeDefined();
|
||||
expect(firstAspectCheckbox).not.toBeNull();
|
||||
expect(firstAspectCheckbox.checked).toBeTruthy();
|
||||
it('should show as checked the node properties', async () => {
|
||||
const panel = await loader.getHarness(MatExpansionPanelHarness);
|
||||
await panel.expand();
|
||||
|
||||
const checkbox = await panel.getHarness(MatCheckboxHarness);
|
||||
expect(await checkbox.isChecked()).toBe(true);
|
||||
});
|
||||
|
||||
it('should remove aspects unchecked', (done) => {
|
||||
const secondElement = fixture.nativeElement.querySelector('#aspect-list-1-check-input');
|
||||
expect(secondElement).toBeDefined();
|
||||
expect(secondElement).not.toBeNull();
|
||||
expect(secondElement.checked).toBeFalsy();
|
||||
secondElement.click();
|
||||
fixture.detectChanges();
|
||||
it('should remove aspects unchecked', async () => {
|
||||
const panel = await loader.getAllHarnesses(MatExpansionPanelHarness);
|
||||
await panel[1].expand();
|
||||
|
||||
const checkbox = await panel[1].getHarness(MatCheckboxHarness);
|
||||
expect(await checkbox.isChecked()).toBe(false);
|
||||
|
||||
await checkbox.toggle();
|
||||
|
||||
expect(component.nodeAspects.length).toBe(2);
|
||||
expect(component.nodeAspects[1]).toBe('frs:SecondAspect');
|
||||
component.valueChanged.subscribe((aspects) => {
|
||||
expect(aspects.length).toBe(1);
|
||||
expect(aspects[0]).toBe('frs:AspectOne');
|
||||
done();
|
||||
});
|
||||
secondElement.click();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should reset the properties on reset', (done) => {
|
||||
const secondElement = fixture.nativeElement.querySelector('#aspect-list-1-check-input');
|
||||
expect(secondElement).toBeDefined();
|
||||
expect(secondElement).not.toBeNull();
|
||||
expect(secondElement.checked).toBeFalsy();
|
||||
secondElement.click();
|
||||
fixture.detectChanges();
|
||||
expect(component.nodeAspects.length).toBe(2);
|
||||
component.valueChanged.subscribe((aspects) => {
|
||||
expect(aspects.length).toBe(1);
|
||||
done();
|
||||
});
|
||||
component.reset();
|
||||
});
|
||||
await checkbox.toggle();
|
||||
|
||||
it('should clear all the properties on clear', (done) => {
|
||||
expect(component.nodeAspects.length).toBe(1);
|
||||
component.valueChanged.subscribe((aspects) => {
|
||||
expect(aspects.length).toBe(0);
|
||||
done();
|
||||
expect(component.nodeAspects[0]).toBe('frs:AspectOne');
|
||||
});
|
||||
|
||||
it('should reset the properties on reset', async () => {
|
||||
const panel = await loader.getAllHarnesses(MatExpansionPanelHarness);
|
||||
await panel[1].expand();
|
||||
|
||||
const checkbox = await panel[1].getHarness(MatCheckboxHarness);
|
||||
expect(await checkbox.isChecked()).toBe(false);
|
||||
|
||||
await checkbox.toggle();
|
||||
|
||||
expect(component.nodeAspects.length).toBe(2);
|
||||
component.reset();
|
||||
expect(component.nodeAspects.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should clear all the properties on clear', async () => {
|
||||
expect(component.nodeAspects.length).toBe(1);
|
||||
component.clear();
|
||||
expect(component.nodeAspects.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -277,21 +257,16 @@ describe('AspectListComponent', () => {
|
||||
aspectListService = TestBed.inject(AspectListService);
|
||||
spyOn(aspectListService, 'getAspects').and.returnValue(of(aspectListMock));
|
||||
fixture.detectChanges();
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should show all the aspects', () => {
|
||||
const firstElement = fixture.nativeElement.querySelector('#aspect-list-FirstAspect');
|
||||
const secondElement = fixture.nativeElement.querySelector('#aspect-list-SecondAspect');
|
||||
|
||||
expect(firstElement).not.toBeNull();
|
||||
expect(firstElement).toBeDefined();
|
||||
expect(secondElement).not.toBeNull();
|
||||
expect(secondElement).toBeDefined();
|
||||
it('should show all the aspects', async () => {
|
||||
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-FirstAspect' }))).toBe(true);
|
||||
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-SecondAspect' }))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -71,7 +71,8 @@
|
||||
[value]="category">
|
||||
{{ category.name }}
|
||||
</mat-list-option>
|
||||
<p *ngIf="!existingCategories?.length && !existingCategoriesLoading">
|
||||
<p *ngIf="!existingCategories?.length && !existingCategoriesLoading"
|
||||
data-automation-id="no-categories-message">
|
||||
{{ 'CATEGORIES_MANAGEMENT.NO_EXISTING_CATEGORIES' | translate }}
|
||||
</p>
|
||||
</mat-selection-list>
|
||||
|
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Category, CategoryPaging, ResultNode, ResultSetPaging } from '@alfresco/js-api';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
|
||||
import { Validators } from '@angular/forms';
|
||||
import { MatError } from '@angular/material/form-field';
|
||||
@@ -28,8 +27,12 @@ import { ContentTestingModule } from '../../testing/content.testing.module';
|
||||
import { CategoriesManagementMode } from './categories-management-mode';
|
||||
import { CategoryService } from '../services/category.service';
|
||||
import { CategoriesManagementComponent } from './categories-management.component';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
|
||||
|
||||
describe('CategoriesManagementComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
let component: CategoriesManagementComponent;
|
||||
let fixture: ComponentFixture<CategoriesManagementComponent>;
|
||||
let categoryService: CategoryService;
|
||||
@@ -38,18 +41,15 @@ describe('CategoriesManagementComponent', () => {
|
||||
const category2 = new Category({ id: 'test2', name: 'testCat2' });
|
||||
const category3 = new Category({ id: 'test3', name: 'testCat3' });
|
||||
const category4 = new Category({ id: 'test4', name: 'testCat4' });
|
||||
const resultCat1 = new ResultNode({ id: 'test', name: 'testCat', path: { name: 'general/categories' }});
|
||||
const resultCat2 = new ResultNode({ id: 'test2', name: 'testCat2', path: { name: 'general/categories' }});
|
||||
const categoryPagingResponse: CategoryPaging = { list: { pagination: {}, entries: [ { entry: category1 }, { entry: category2 }]}};
|
||||
const categorySearchResponse: ResultSetPaging = { list: { pagination: {}, entries: [ { entry: resultCat1 }, { entry: resultCat2 }]}};
|
||||
const resultCat1 = new ResultNode({ id: 'test', name: 'testCat', path: { name: 'general/categories' } });
|
||||
const resultCat2 = new ResultNode({ id: 'test2', name: 'testCat2', path: { name: 'general/categories' } });
|
||||
const categoryPagingResponse: CategoryPaging = { list: { pagination: {}, entries: [{ entry: category1 }, { entry: category2 }] } };
|
||||
const categorySearchResponse: ResultSetPaging = { list: { pagination: {}, entries: [{ entry: resultCat1 }, { entry: resultCat2 }] } };
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CategoriesManagementComponent],
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ContentTestingModule
|
||||
],
|
||||
imports: [TranslateModule.forRoot(), ContentTestingModule],
|
||||
providers: [
|
||||
{
|
||||
provide: CategoryService,
|
||||
@@ -65,6 +65,7 @@ describe('CategoriesManagementComponent', () => {
|
||||
fixture = TestBed.createComponent(CategoriesManagementComponent);
|
||||
component = fixture.componentInstance;
|
||||
categoryService = TestBed.inject(CategoryService);
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -138,7 +139,9 @@ describe('CategoriesManagementComponent', () => {
|
||||
* @returns list of native elements
|
||||
*/
|
||||
function getRemoveCategoryButtons(): HTMLButtonElement[] {
|
||||
return fixture.debugElement.queryAll(By.css(`[data-automation-id="categories-remove-category-button"]`)).map((debugElem) => debugElem.nativeElement);
|
||||
return fixture.debugElement
|
||||
.queryAll(By.css(`[data-automation-id="categories-remove-category-button"]`))
|
||||
.map((debugElem) => debugElem.nativeElement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,39 +264,28 @@ describe('CategoriesManagementComponent', () => {
|
||||
});
|
||||
|
||||
describe('Spinner', () => {
|
||||
/**
|
||||
* Get the spinner element
|
||||
*
|
||||
* @returns debug element
|
||||
*/
|
||||
function getSpinner(): DebugElement {
|
||||
return fixture.debugElement.query(By.css(`.mat-progress-spinner`));
|
||||
}
|
||||
it('should not be displayed when existing categories stopped loading', async () => {
|
||||
component.categoryNameControlVisible = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
it('should be displayed with correct diameter when existing categories are loading', fakeAsync(() => {
|
||||
typeCategory('Category 1', 0);
|
||||
const categoryControlInput = getCategoryControlInput();
|
||||
categoryControlInput.value = 'Category 1';
|
||||
categoryControlInput.dispatchEvent(new InputEvent('input'));
|
||||
|
||||
const spinner = getSpinner();
|
||||
expect(spinner).toBeTruthy();
|
||||
expect(spinner.componentInstance.diameter).toBe(50);
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
discardPeriodicTasks();
|
||||
flush();
|
||||
}));
|
||||
|
||||
it('should not be displayed when existing categories stopped loading', fakeAsync(() => {
|
||||
typeCategory('Category 1');
|
||||
|
||||
const spinner = getSpinner();
|
||||
expect(spinner).toBeFalsy();
|
||||
}));
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should display correct message when there are no existing categories', fakeAsync(() => {
|
||||
spyOn(categoryService, 'getSubcategories').and.returnValue(of({list: { pagination: {}, entries: []}}));
|
||||
spyOn(categoryService, 'getSubcategories').and.returnValue(of({ list: { pagination: {}, entries: [] } }));
|
||||
typeCategory('test');
|
||||
|
||||
const noExistingCategoriesMsg = fixture.debugElement.query(By.css('mat-selection-list p'))?.nativeElement.textContent.trim();
|
||||
const noExistingCategoriesMsg = fixture.debugElement
|
||||
.query(By.css(`[data-automation-id="no-categories-message"]`))
|
||||
?.nativeElement.textContent.trim();
|
||||
expect(noExistingCategoriesMsg).toBe('CATEGORIES_MANAGEMENT.NO_EXISTING_CATEGORIES');
|
||||
}));
|
||||
});
|
||||
@@ -328,7 +320,9 @@ describe('CategoriesManagementComponent', () => {
|
||||
|
||||
it('should have correct remove category title', () => {
|
||||
const removeButtons = getRemoveCategoryButtons();
|
||||
const isTitleCorrect = removeButtons.every((removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.UNASSIGN_CATEGORY');
|
||||
const isTitleCorrect = removeButtons.every(
|
||||
(removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.UNASSIGN_CATEGORY'
|
||||
);
|
||||
expect(isTitleCorrect).toBeTrue();
|
||||
});
|
||||
|
||||
@@ -434,7 +428,9 @@ describe('CategoriesManagementComponent', () => {
|
||||
|
||||
it('should have correct remove category title', () => {
|
||||
const removeButtons = getRemoveCategoryButtons();
|
||||
const isTitleCorrect = removeButtons.every((removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.DELETE_CATEGORY');
|
||||
const isTitleCorrect = removeButtons.every(
|
||||
(removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.DELETE_CATEGORY'
|
||||
);
|
||||
expect(isTitleCorrect).toBeTrue();
|
||||
});
|
||||
|
||||
|
@@ -15,9 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, Inject, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { TranslationService, NotificationService} from '@alfresco/adf-core';
|
||||
import { TranslationService, NotificationService } from '@alfresco/adf-core';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
import { AllowableOperationsEnum } from '../common/models/allowable-operations.enum';
|
||||
import { ContentService } from '../common/services/content.service';
|
||||
@@ -26,6 +26,8 @@ import { ContentNodeSelectorComponentData } from './content-node-selector.compon
|
||||
import { NodeEntryEvent } from '../document-list/components/node.event';
|
||||
import { NodeAction } from '../document-list/models/node-action.enum';
|
||||
import { OverlayContainer } from '@angular/cdk/overlay';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-content-node-selector',
|
||||
@@ -33,7 +35,9 @@ import { OverlayContainer } from '@angular/cdk/overlay';
|
||||
styleUrls: ['./content-node-selector.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ContentNodeSelectorComponent implements OnInit {
|
||||
export class ContentNodeSelectorComponent implements OnInit, OnDestroy {
|
||||
private onDestroy$ = new Subject<void>();
|
||||
|
||||
title: string;
|
||||
action: NodeAction;
|
||||
buttonActionName: string;
|
||||
@@ -48,13 +52,15 @@ export class ContentNodeSelectorComponent implements OnInit {
|
||||
emptyFolderImageUrl: string = './assets/images/empty_doc_lib.svg';
|
||||
breadcrumbFolderNode: Node;
|
||||
|
||||
constructor(private translation: TranslationService,
|
||||
constructor(
|
||||
private translation: TranslationService,
|
||||
private contentService: ContentService,
|
||||
private notificationService: NotificationService,
|
||||
private uploadService: UploadService,
|
||||
private dialog: MatDialogRef<ContentNodeSelectorComponent>,
|
||||
private overlayContainer: OverlayContainer,
|
||||
@Inject(MAT_DIALOG_DATA) public data: ContentNodeSelectorComponentData) {
|
||||
@Inject(MAT_DIALOG_DATA) public data: ContentNodeSelectorComponentData
|
||||
) {
|
||||
this.action = data.actionName ?? NodeAction.CHOOSE;
|
||||
this.buttonActionName = `NODE_SELECTOR.${this.action}`;
|
||||
this.title = data.title;
|
||||
@@ -62,28 +68,41 @@ export class ContentNodeSelectorComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.dialog.keydownEvents().subscribe(event => {
|
||||
// Esc
|
||||
if (event.keyCode === 27) {
|
||||
this.dialog
|
||||
.keydownEvents()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((event) => {
|
||||
if (event?.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
|
||||
this.dialog.backdropClick().subscribe(() => {
|
||||
this.dialog
|
||||
.backdropClick()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(() => {
|
||||
this.close();
|
||||
});
|
||||
|
||||
this.dialog.afterOpened().subscribe(() => {
|
||||
this.dialog
|
||||
.afterOpened()
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(() => {
|
||||
this.overlayContainer.getContainerElement().setAttribute('role', 'main');
|
||||
});
|
||||
|
||||
this.uploadService.fileUploadStarting.subscribe(() => {
|
||||
this.uploadService.fileUploadStarting.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
|
||||
this.uploadStarted = true;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next();
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
close() {
|
||||
this.dialog.close();
|
||||
this.overlayContainer.getContainerElement().setAttribute('role', 'region');
|
||||
@@ -179,16 +198,17 @@ export class ContentNodeSelectorComponent implements OnInit {
|
||||
}
|
||||
|
||||
getWarningMessage(): string {
|
||||
return this.showingSearch ? 'NODE_SELECTOR.UPLOAD_BUTTON_SEARCH_WARNING_MESSAGE' :
|
||||
(this.hasNoPermissionToUpload() ? 'NODE_SELECTOR.UPLOAD_BUTTON_PERMISSION_WARNING_MESSAGE' : '');
|
||||
if (this.showingSearch) {
|
||||
return 'NODE_SELECTOR.UPLOAD_BUTTON_SEARCH_WARNING_MESSAGE';
|
||||
}
|
||||
return this.hasNoPermissionToUpload() ? 'NODE_SELECTOR.UPLOAD_BUTTON_PERMISSION_WARNING_MESSAGE' : '';
|
||||
}
|
||||
|
||||
hasNoPermissionToUpload(): boolean {
|
||||
return (!this.hasAllowableOperations && !this.showingSearch) && !this.isLoading;
|
||||
return !this.hasAllowableOperations && !this.showingSearch && !this.isLoading;
|
||||
}
|
||||
|
||||
hasUploadError(): boolean {
|
||||
return this.showingSearch || this.hasNoPermissionToUpload();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -48,6 +48,8 @@ describe('FolderDialogComponent', () => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
const getTitle = () => fixture.debugElement.query(By.css('[data-automation-id="adf-folder-dialog-title"]'));
|
||||
|
||||
describe('Edit', () => {
|
||||
beforeEach(() => {
|
||||
component.data = {
|
||||
@@ -70,8 +72,8 @@ describe('FolderDialogComponent', () => {
|
||||
});
|
||||
|
||||
it('should have the proper title', () => {
|
||||
const title = fixture.debugElement.query(By.css('[mat-dialog-title]'));
|
||||
expect(title === null).toBe(false);
|
||||
const title = getTitle();
|
||||
expect(title).not.toBeNull();
|
||||
expect(title.nativeElement.innerText.trim()).toBe('CORE.FOLDER_DIALOG.EDIT_FOLDER_TITLE');
|
||||
});
|
||||
|
||||
@@ -165,8 +167,8 @@ describe('FolderDialogComponent', () => {
|
||||
});
|
||||
|
||||
it('should have the proper title', () => {
|
||||
const title = fixture.debugElement.query(By.css(`[data-automation-id="adf-folder-dialog-title"]`));
|
||||
expect(title === null).toBe(false);
|
||||
const title = getTitle();
|
||||
expect(title).not.toBeNull();
|
||||
expect(title.nativeElement.innerText.trim()).toBe('CORE.FOLDER_DIALOG.CREATE_FOLDER_TITLE');
|
||||
});
|
||||
|
||||
|
@@ -62,12 +62,16 @@ import { domSanitizerMock } from '../../testing/dom-sanitizer-mock';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { FileAutoDownloadComponent } from './file-auto-download/file-auto-download.component';
|
||||
import { ShareDataTableAdapter } from '../data/share-datatable-adapter';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
|
||||
|
||||
const mockDialog = {
|
||||
open: jasmine.createSpy('open')
|
||||
};
|
||||
|
||||
describe('DocumentList', () => {
|
||||
let loader: HarnessLoader;
|
||||
let documentList: DocumentListComponent;
|
||||
let documentListService: DocumentListService;
|
||||
let customResourcesService: CustomResourcesService;
|
||||
@@ -116,6 +120,8 @@ describe('DocumentList', () => {
|
||||
spyFavorite = spyOn(customResourcesService.favoritesApi, 'listFavorites').and.returnValue(
|
||||
Promise.resolve(new FavoritePaging({ list: new FavoritePagingList({ entries: [] }) }))
|
||||
);
|
||||
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -1075,10 +1081,11 @@ describe('DocumentList', () => {
|
||||
expect(fixture.debugElement.query(By.css('.adf-no-permission__template'))).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should display loading template when data is loading', () => {
|
||||
it('should display loading template when data is loading', async () => {
|
||||
documentList.loading = true;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('mat-progress-spinner'))).not.toBeNull();
|
||||
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(true);
|
||||
});
|
||||
|
||||
it('should empty folder NOT show the pagination', () => {
|
||||
@@ -1406,14 +1413,16 @@ describe('DocumentList', () => {
|
||||
expect(documentList.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not show loading state if pagination is updated with merge setting as true', fakeAsync (() => {
|
||||
it('should not show loading state if pagination is updated with merge setting as true', fakeAsync(() => {
|
||||
spyFolderNode = spyOn(documentListService, 'loadFolderByNodeId').and.callFake(() =>
|
||||
of(new DocumentLoaderNode(null, {
|
||||
of(
|
||||
new DocumentLoaderNode(null, {
|
||||
list: {
|
||||
pagination: {},
|
||||
entries: mockPreselectedNodes
|
||||
}
|
||||
}))
|
||||
})
|
||||
)
|
||||
);
|
||||
fixture.detectChanges();
|
||||
const fakeDatatableRows = [
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<h1 mat-dialog-title>{{ title | translate }}</h1>
|
||||
<h1 mat-dialog-title data-automation-id="new-version-uploader-dialog-title">{{ title | translate }}</h1>
|
||||
<section mat-dialog-content *ngIf="!data.showVersionsOnly">
|
||||
<adf-version-comparison id="adf-version-comparison" [newFileVersion]="data.file" [node]="data.node"></adf-version-comparison>
|
||||
<adf-version-upload
|
||||
|
@@ -28,13 +28,13 @@ import { NewVersionUploaderDialogComponent } from './new-version-uploader.dialog
|
||||
describe('NewVersionUploaderDialog', () => {
|
||||
let component: NewVersionUploaderDialogComponent;
|
||||
let fixture: ComponentFixture<NewVersionUploaderDialogComponent>;
|
||||
let nativeElement;
|
||||
let nativeElement: HTMLElement;
|
||||
|
||||
const cssSelectors = {
|
||||
adfVersionUploadButton: '#adf-version-upload-button',
|
||||
adfVersionComparison: '#adf-version-comparison',
|
||||
adfVersionList: '.adf-version-list',
|
||||
matDialogTitle: '.mat-dialog-title'
|
||||
title: '[data-automation-id="new-version-uploader-dialog-title"]'
|
||||
};
|
||||
|
||||
const mockDialogRef = {
|
||||
@@ -45,10 +45,7 @@ describe('NewVersionUploaderDialog', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ContentTestingModule
|
||||
],
|
||||
imports: [TranslateModule.forRoot(), ContentTestingModule],
|
||||
declarations: [
|
||||
NewVersionUploaderDialogComponent,
|
||||
VersionListComponent,
|
||||
@@ -59,7 +56,8 @@ describe('NewVersionUploaderDialog', () => {
|
||||
providers: [
|
||||
{ provide: MAT_DIALOG_DATA, useValue: { node: mockNode, showVersionsOnly, file: mockFile } },
|
||||
{
|
||||
provide: MatDialogRef, useValue: mockDialogRef
|
||||
provide: MatDialogRef,
|
||||
useValue: mockDialogRef
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -72,12 +70,7 @@ describe('NewVersionUploaderDialog', () => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('Upload New Version', () => {
|
||||
|
||||
const expectedUploadNewVersionTitle = 'ADF-NEW-VERSION-UPLOADER.DIALOG_UPLOAD.TITLE';
|
||||
|
||||
it('should display adf version upload button if showVersionsOnly is passed as false from parent component', () => {
|
||||
@@ -104,7 +97,7 @@ describe('NewVersionUploaderDialog', () => {
|
||||
it('should show default title if title is not provided from parent component', () => {
|
||||
component.data.showVersionsOnly = false;
|
||||
fixture.detectChanges();
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
|
||||
expect(matDialogTitle.innerHTML).toEqual(expectedUploadNewVersionTitle);
|
||||
});
|
||||
|
||||
@@ -112,7 +105,7 @@ describe('NewVersionUploaderDialog', () => {
|
||||
component.data.showVersionsOnly = false;
|
||||
component.data.title = '';
|
||||
fixture.detectChanges();
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
|
||||
expect(matDialogTitle.innerHTML).toEqual(expectedUploadNewVersionTitle);
|
||||
});
|
||||
|
||||
@@ -120,7 +113,7 @@ describe('NewVersionUploaderDialog', () => {
|
||||
component.data.showVersionsOnly = false;
|
||||
component.data.title = 'TEST_TITLE';
|
||||
fixture.detectChanges();
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
|
||||
expect(matDialogTitle.innerHTML).toEqual('TEST_TITLE');
|
||||
});
|
||||
|
||||
@@ -150,11 +143,9 @@ describe('NewVersionUploaderDialog', () => {
|
||||
component.handleCancel();
|
||||
expect(mockDialogRef.close).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Manage Versions', () => {
|
||||
|
||||
const expectedManageVersionsTitle = 'ADF-NEW-VERSION-UPLOADER.DIALOG_LIST.TITLE';
|
||||
|
||||
it('should display adf version list if showVersionsOnly is passed as true from parent component', () => {
|
||||
@@ -182,7 +173,7 @@ describe('NewVersionUploaderDialog', () => {
|
||||
component.data.showVersionsOnly = true;
|
||||
component.data.title = undefined;
|
||||
fixture.detectChanges();
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
|
||||
expect(matDialogTitle.innerHTML).toEqual(expectedManageVersionsTitle);
|
||||
});
|
||||
|
||||
@@ -190,7 +181,7 @@ describe('NewVersionUploaderDialog', () => {
|
||||
component.data.showVersionsOnly = true;
|
||||
component.data.title = '';
|
||||
fixture.detectChanges();
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
|
||||
expect(matDialogTitle.innerHTML).toEqual(expectedManageVersionsTitle);
|
||||
});
|
||||
|
||||
@@ -198,10 +189,8 @@ describe('NewVersionUploaderDialog', () => {
|
||||
component.data.showVersionsOnly = true;
|
||||
component.data.title = 'TEST_TITLE';
|
||||
fixture.detectChanges();
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
|
||||
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
|
||||
expect(matDialogTitle.innerHTML).toEqual('TEST_TITLE');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -12,7 +12,7 @@
|
||||
(change)="$event.stopPropagation()"
|
||||
/>
|
||||
|
||||
<button mat-button
|
||||
<button
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
[attr.aria-label]="'SELECT_FILTER.BUTTON.ARIA_LABEL' | translate"
|
||||
|
@@ -19,78 +19,19 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CoreTestingModule } from '../../../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SelectFilterInputComponent } from './select-filter-input.component';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { ESCAPE } from '@angular/cdk/keycodes';
|
||||
import { MatSelect } from '@angular/material/select';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-test-filter',
|
||||
template: `
|
||||
<mat-select [(ngModel)]="field.value" [compareWith]="compare" [multiple]="multiple">
|
||||
<adf-select-filter-input *ngIf="showInputFilter" (change)="onChange($event)"></adf-select-filter-input>
|
||||
<mat-option *ngFor="let opt of options"
|
||||
[value]="opt"
|
||||
[id]="opt.id">{{opt.name}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
`
|
||||
})
|
||||
export class TestComponent {
|
||||
@ViewChild(SelectFilterInputComponent) filterInputComponent: SelectFilterInputComponent;
|
||||
field: any = { value : '' };
|
||||
showInputFilter = true;
|
||||
multiple = false;
|
||||
standardOptions = [
|
||||
{ id: '1', name: 'one' },
|
||||
{ id: '2', name: 'two' },
|
||||
{ id: '3', name: 'three' }
|
||||
];
|
||||
options = this.standardOptions;
|
||||
|
||||
compare(obj1, obj2) {
|
||||
if (!obj1 || !obj2) {
|
||||
return false;
|
||||
}
|
||||
return obj1.id === obj2.id;
|
||||
}
|
||||
|
||||
onChange(search: string) {
|
||||
if (!search) {
|
||||
this.options = this.standardOptions;
|
||||
} else {
|
||||
this.options = this.standardOptions.filter(({ name }) => name.includes(search));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe('SelectFilterInputComponent', () => {
|
||||
let testFixture: ComponentFixture<TestComponent>;
|
||||
let testComponent: TestComponent;
|
||||
let fixture: ComponentFixture<SelectFilterInputComponent>;
|
||||
let component: SelectFilterInputComponent;
|
||||
let matSelect: MatSelect;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CoreTestingModule,
|
||||
NoopAnimationsModule
|
||||
],
|
||||
declarations: [
|
||||
TestComponent
|
||||
],
|
||||
providers: [
|
||||
MatSelect
|
||||
]
|
||||
});
|
||||
imports: [TranslateModule.forRoot(), CoreTestingModule],
|
||||
providers: [MatSelect]
|
||||
});
|
||||
|
||||
describe('component', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SelectFilterInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
matSelect = TestBed.inject(MatSelect);
|
||||
@@ -137,45 +78,8 @@ describe('SelectFilterInputComponent', () => {
|
||||
component.onModelChange('some-search-term');
|
||||
expect(component.term).toBe('some-search-term');
|
||||
|
||||
component.selectFilterInput.nativeElement.dispatchEvent(new KeyboardEvent('keydown', {keyCode: ESCAPE} as any));
|
||||
component.selectFilterInput.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { code: 'Escape' } as any));
|
||||
fixture.detectChanges();
|
||||
expect(component.term).toBe('');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('testComponent', () => {
|
||||
beforeEach(() => {
|
||||
testFixture = TestBed.createComponent(TestComponent);
|
||||
testComponent = testFixture.componentInstance;
|
||||
});
|
||||
|
||||
afterEach(() => testFixture.destroy());
|
||||
|
||||
it('should preserve the values for multiple search', async () => {
|
||||
const userSelection = [{ id: '3', name: 'three' }];
|
||||
const preSelected = [
|
||||
{ id: '1', name: 'one' },
|
||||
{ id: '2', name: 'two' }
|
||||
];
|
||||
testComponent.field.value = preSelected;
|
||||
testComponent.multiple = true;
|
||||
testFixture.detectChanges();
|
||||
|
||||
const dropdown: HTMLElement = testFixture.nativeElement.querySelector('.mat-select-trigger');
|
||||
dropdown.click();
|
||||
await testFixture.whenStable();
|
||||
testFixture.detectChanges();
|
||||
|
||||
const filter = testFixture.debugElement.query(By.css('input'));
|
||||
filter.triggerEventHandler('input', { target: { value: 'three' } });
|
||||
testFixture.detectChanges();
|
||||
|
||||
const option = testFixture.debugElement.query(By.css('mat-option'));
|
||||
option.triggerEventHandler('click', null);
|
||||
testFixture.detectChanges();
|
||||
|
||||
expect(testComponent.field.value).toEqual([...preSelected, ...userSelection]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Component, ViewEncapsulation, ViewChild, ElementRef, OnDestroy, Inject, Output, EventEmitter, OnInit } from '@angular/core';
|
||||
import { ESCAPE, TAB } from '@angular/cdk/keycodes';
|
||||
import { MatSelect } from '@angular/material/select';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
@@ -43,13 +42,9 @@ export class SelectFilterInputComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.change
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((val: string) => this.term = val );
|
||||
this.change.pipe(takeUntil(this.onDestroy$)).subscribe((val: string) => (this.term = val));
|
||||
|
||||
this.matSelect.openedChange
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((isOpened: boolean) => {
|
||||
this.matSelect.openedChange.pipe(takeUntil(this.onDestroy$)).subscribe((isOpened: boolean) => {
|
||||
if (isOpened) {
|
||||
this.selectFilterInput.nativeElement.focus();
|
||||
} else {
|
||||
@@ -59,17 +54,15 @@ export class SelectFilterInputComponent implements OnInit, OnDestroy {
|
||||
|
||||
if (this.matSelect.ngControl) {
|
||||
this.previousSelected = this.matSelect.ngControl.value;
|
||||
this.matSelect.ngControl.valueChanges
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((values) => {
|
||||
this.matSelect.ngControl.valueChanges.pipe(takeUntil(this.onDestroy$)).subscribe((values) => {
|
||||
let restoreSelection = false;
|
||||
if (this.matSelect.multiple && Array.isArray(this.previousSelected)) {
|
||||
if (!Array.isArray(values)) {
|
||||
values = [];
|
||||
}
|
||||
const options = this.matSelect.options.map(option => option.value);
|
||||
const options = this.matSelect.options.map((option) => option.value);
|
||||
this.previousSelected.forEach((previous) => {
|
||||
const isSelected = [...values, ...options].some(current => this.matSelect.compareWith(current, previous));
|
||||
const isSelected = [...values, ...options].some((current) => this.matSelect.compareWith(current, previous));
|
||||
if (!isSelected) {
|
||||
values.push(previous);
|
||||
restoreSelection = true;
|
||||
@@ -97,13 +90,13 @@ export class SelectFilterInputComponent implements OnInit, OnDestroy {
|
||||
|
||||
handleKeydown($event: KeyboardEvent) {
|
||||
if (this.term) {
|
||||
if ($event.keyCode === ESCAPE) {
|
||||
event.stopPropagation();
|
||||
if ($event.code === 'Escape') {
|
||||
$event.stopPropagation();
|
||||
this.change.next('');
|
||||
}
|
||||
|
||||
if (($event.target as HTMLInputElement).tagName === 'INPUT' && $event.keyCode === TAB) {
|
||||
event.stopPropagation();
|
||||
if (($event.target as HTMLInputElement).tagName === 'INPUT' && $event.code === 'Tab') {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,25 +15,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { LiveAnnouncer } from '@angular/cdk/a11y';
|
||||
import { OverlayModule } from '@angular/cdk/overlay';
|
||||
import { Component } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MatSnackBar, MatSnackBarConfig, MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatSnackBarConfig, MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { NotificationService } from './notification.service';
|
||||
import { TranslationService } from '../../translation/translation.service';
|
||||
import { CoreTestingModule } from '../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatIconHarness } from '@angular/material/icon/testing';
|
||||
import { MatSnackBarHarness } from '@angular/material/snack-bar/testing';
|
||||
|
||||
@Component({
|
||||
template: '',
|
||||
providers: [NotificationService]
|
||||
})
|
||||
class ProvidesNotificationServiceComponent {
|
||||
|
||||
constructor(public notificationService: NotificationService) {
|
||||
|
||||
}
|
||||
constructor(public notificationService: NotificationService) {}
|
||||
|
||||
sendMessageWithoutConfig() {
|
||||
return this.notificationService.openSnackMessage('Test notification', 1000);
|
||||
@@ -44,7 +43,7 @@ class ProvidesNotificationServiceComponent {
|
||||
}
|
||||
|
||||
sendMessageWithArgs() {
|
||||
return this.notificationService.openSnackMessage('Test notification {{ arg }}', 1000, {arg: 'arg'});
|
||||
return this.notificationService.openSnackMessage('Test notification {{ arg }}', 1000, { arg: 'arg' });
|
||||
}
|
||||
|
||||
sendCustomMessage() {
|
||||
@@ -72,7 +71,7 @@ class ProvidesNotificationServiceComponent {
|
||||
sendMessageWithDecorativeIcon() {
|
||||
const notificationConfig = new MatSnackBarConfig();
|
||||
notificationConfig.duration = 1000;
|
||||
notificationConfig.data = {decorativeIcon: 'info'};
|
||||
notificationConfig.data = { decorativeIcon: 'info' };
|
||||
|
||||
return this.notificationService.openSnackMessage('with decorative icon', notificationConfig);
|
||||
}
|
||||
@@ -84,154 +83,97 @@ class ProvidesNotificationServiceComponent {
|
||||
|
||||
return this.notificationService.openSnackMessageAction('with decorative icon', 'TestWarn', notificationConfig);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
describe('NotificationService', () => {
|
||||
let loader: HarnessLoader;
|
||||
let fixture: ComponentFixture<ProvidesNotificationServiceComponent>;
|
||||
let translationService: TranslationService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CoreTestingModule,
|
||||
OverlayModule,
|
||||
MatSnackBarModule
|
||||
],
|
||||
declarations: [ProvidesNotificationServiceComponent],
|
||||
providers: [
|
||||
MatSnackBar,
|
||||
LiveAnnouncer
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), CoreTestingModule, MatSnackBarModule],
|
||||
declarations: [ProvidesNotificationServiceComponent]
|
||||
});
|
||||
translationService = TestBed.inject(TranslationService);
|
||||
fixture = TestBed.createComponent(ProvidesNotificationServiceComponent);
|
||||
fixture.detectChanges();
|
||||
loader = TestbedHarnessEnvironment.documentRootLoader(fixture);
|
||||
});
|
||||
|
||||
it('should translate messages', (done) => {
|
||||
it('should translate messages', () => {
|
||||
spyOn(translationService, 'instant').and.callThrough();
|
||||
|
||||
const promise = fixture.componentInstance.sendMessage();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
fixture.componentInstance.sendMessage();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(translationService.instant).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should translate messages with args', (done) => {
|
||||
it('should translate messages with args', () => {
|
||||
spyOn(translationService, 'instant').and.callThrough();
|
||||
|
||||
const promise = fixture.componentInstance.sendMessageWithArgs();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
expect(translationService.instant).toHaveBeenCalledWith('Test notification {{ arg }}', {arg: 'arg'});
|
||||
done();
|
||||
});
|
||||
|
||||
fixture.componentInstance.sendMessageWithArgs();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(translationService.instant).toHaveBeenCalledWith('Test notification {{ arg }}', { arg: 'arg' });
|
||||
});
|
||||
|
||||
it('should translate the action', (done) => {
|
||||
it('should translate the action', () => {
|
||||
spyOn(translationService, 'instant').and.callThrough();
|
||||
|
||||
const promise = fixture.componentInstance.sendMessageAction();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
fixture.componentInstance.sendMessageAction();
|
||||
fixture.detectChanges();
|
||||
expect(translationService.instant).toHaveBeenCalledTimes(2);
|
||||
done();
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should open a message notification bar', (done) => {
|
||||
const promise = fixture.componentInstance.sendMessage();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
it('should open a message notification bar', async () => {
|
||||
fixture.componentInstance.sendMessage();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.querySelector('snack-bar-container')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should open a message notification bar without custom configuration', (done) => {
|
||||
const promise = fixture.componentInstance.sendMessageWithoutConfig();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
done();
|
||||
expect(await loader.hasHarness(MatSnackBarHarness)).toBe(true);
|
||||
});
|
||||
|
||||
it('should open a message notification bar without custom configuration', async () => {
|
||||
fixture.componentInstance.sendMessageWithoutConfig();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.querySelector('snack-bar-container')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should open a message notification bar with custom configuration', (done) => {
|
||||
const promise = fixture.componentInstance.sendCustomMessage();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
done();
|
||||
expect(await loader.hasHarness(MatSnackBarHarness)).toBe(true);
|
||||
});
|
||||
|
||||
it('should open a message notification bar with custom configuration', async () => {
|
||||
fixture.componentInstance.sendCustomMessage();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.querySelector('snack-bar-container')).not.toBeNull();
|
||||
expect(await loader.hasHarness(MatSnackBarHarness)).toBe(true);
|
||||
});
|
||||
|
||||
it('should open a message notification bar with action', (done) => {
|
||||
const promise = fixture.componentInstance.sendMessageAction();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
done();
|
||||
it('should open a message notification bar with action', async () => {
|
||||
fixture.componentInstance.sendMessageAction();
|
||||
expect(await loader.hasHarness(MatSnackBarHarness)).toBe(true);
|
||||
});
|
||||
|
||||
it('should open a message notification bar with action and custom configuration', async () => {
|
||||
fixture.componentInstance.sendCustomMessageAction();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.querySelector('snack-bar-container')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should open a message notification bar with action and custom configuration', (done) => {
|
||||
const promise = fixture.componentInstance.sendCustomMessageAction();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
done();
|
||||
expect(await loader.hasHarness(MatSnackBarHarness)).toBe(true);
|
||||
});
|
||||
|
||||
it('should open a message notification bar with action and no custom configuration', async () => {
|
||||
fixture.componentInstance.sendMessageActionWithoutConfig();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.querySelector('snack-bar-container')).not.toBeNull();
|
||||
expect(await loader.hasHarness(MatSnackBarHarness)).toBe(true);
|
||||
});
|
||||
|
||||
it('should open a message notification bar with action and no custom configuration', (done) => {
|
||||
const promise = fixture.componentInstance.sendMessageActionWithoutConfig();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
done();
|
||||
it('should open a message notification bar with a decorative icon', async () => {
|
||||
fixture.componentInstance.sendMessageWithDecorativeIcon();
|
||||
expect(await loader.hasHarness(MatIconHarness.with({ ancestor: `[data-automation-id="adf-snackbar-message-content"]` }))).toBe(true);
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.querySelector('snack-bar-container')).not.toBeNull();
|
||||
it('should open a message notification bar with action and a decorative icon', async () => {
|
||||
fixture.componentInstance.sendMessageWithDecorativeIconAndAction();
|
||||
expect(await loader.hasHarness(MatIconHarness.with({ ancestor: `[data-automation-id="adf-snackbar-message-content"]` }))).toBe(true);
|
||||
});
|
||||
|
||||
it('should open a message notification bar with a decorative icon', (done) => {
|
||||
const promise = fixture.componentInstance.sendMessageWithDecorativeIcon();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.querySelector('[data-automation-id="adf-snackbar-message-content"] mat-icon')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should open a message notification bar with action and a decorative icon', (done) => {
|
||||
const promise = fixture.componentInstance.sendMessageWithDecorativeIconAndAction();
|
||||
promise.afterDismissed().subscribe(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.querySelector('[data-automation-id="adf-snackbar-message-content"] mat-icon')).not.toBeNull();
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -24,33 +24,32 @@ import { DEFAULT_APP_INSTANCE_THEME } from '../models/application-instance.model
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
describe('AppDetailsCloudComponent', () => {
|
||||
|
||||
let component: AppDetailsCloudComponent;
|
||||
let fixture: ComponentFixture<AppDetailsCloudComponent>;
|
||||
let host: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule,
|
||||
AppListCloudModule
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule, AppListCloudModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(AppDetailsCloudComponent);
|
||||
component = fixture.componentInstance;
|
||||
host = fixture.nativeElement as HTMLElement;
|
||||
component.applicationInstance = fakeApplicationInstance[0];
|
||||
});
|
||||
|
||||
const getAppCard = () => host.querySelector<HTMLElement>('.adf-app-listgrid-item-card');
|
||||
|
||||
it('should display application name', () => {
|
||||
fixture.detectChanges();
|
||||
const appName = fixture.nativeElement.querySelector('.adf-app-listgrid-item-card-title');
|
||||
const appName = host.querySelector<HTMLDivElement>('.adf-app-listgrid-item-card-title');
|
||||
expect(appName.innerText.trim()).toEqual(fakeApplicationInstance[0].name);
|
||||
});
|
||||
|
||||
it('should emit a click event when app selected', () => {
|
||||
spyOn(component.selectedApp, 'emit');
|
||||
fixture.detectChanges();
|
||||
const app = fixture.nativeElement.querySelector('.mat-card');
|
||||
const app = getAppCard();
|
||||
app.click();
|
||||
expect(component.selectedApp.emit).toHaveBeenCalledWith(fakeApplicationInstance[0]);
|
||||
});
|
||||
@@ -59,17 +58,17 @@ describe('AppDetailsCloudComponent', () => {
|
||||
component.applicationInstance = fakeApplicationInstance[2];
|
||||
fixture.detectChanges();
|
||||
|
||||
const theme = fixture.nativeElement.querySelector('.adf-app-listgrid-item-card').getAttribute('ng-reflect-ng-class');
|
||||
const icon = fixture.nativeElement.querySelector('.adf-app-listgrid-item-card-logo-icon');
|
||||
const card = getAppCard();
|
||||
expect(card.classList.contains(DEFAULT_APP_INSTANCE_THEME));
|
||||
|
||||
expect(theme).toEqual(DEFAULT_APP_INSTANCE_THEME);
|
||||
const icon = host.querySelector('.adf-app-listgrid-item-card-logo-icon');
|
||||
expect(icon).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render card with a non ApplicationInstanceModel input object', () => {
|
||||
component.applicationInstance = { name: 'application-new-3', createdAt: '2018-09-21T12:31:39.000Z', status: 'Pending' };
|
||||
fixture.detectChanges();
|
||||
const app = fixture.nativeElement.querySelector('.mat-card');
|
||||
const app = getAppCard();
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@@ -15,7 +15,7 @@
|
||||
<mat-list-item class="adf-app-list-item" (click)="onSelectApp(app)" (keyup.enter)="onSelectApp(app)"
|
||||
*ngFor="let app of appsList" tabindex="0" role="button" title="{{app.name}}">
|
||||
<mat-icon matListIcon>touch_app</mat-icon>
|
||||
<span matLine>{{app.name}}</span>
|
||||
<span class="adf-app-list-item-text" matLine>{{app.name}}</span>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</ng-template>
|
||||
|
@@ -27,7 +27,6 @@ import { ProcessServiceCloudTestingModule } from '../../testing/process-service-
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
describe('AppListCloudComponent', () => {
|
||||
|
||||
let component: AppListCloudComponent;
|
||||
let fixture: ComponentFixture<AppListCloudComponent>;
|
||||
let appsProcessCloudService: AppsProcessCloudService;
|
||||
@@ -52,15 +51,11 @@ describe('AppListCloudComponent', () => {
|
||||
</adf-cloud-app-list>
|
||||
`
|
||||
})
|
||||
class CustomEmptyAppListCloudTemplateComponent {
|
||||
}
|
||||
class CustomEmptyAppListCloudTemplateComponent {}
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule
|
||||
],
|
||||
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule],
|
||||
declarations: [CustomEmptyAppListCloudTemplateComponent]
|
||||
});
|
||||
fixture = TestBed.createComponent(AppListCloudComponent);
|
||||
@@ -130,7 +125,6 @@ describe('AppListCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('Grid Layout ', () => {
|
||||
|
||||
it('should display a grid by default', () => {
|
||||
fixture.detectChanges();
|
||||
expect(component.isGrid()).toBe(true);
|
||||
@@ -165,7 +159,6 @@ describe('AppListCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('List Layout ', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
component.layoutType = LAYOUT_LIST;
|
||||
});
|
||||
@@ -176,11 +169,11 @@ describe('AppListCloudComponent', () => {
|
||||
expect(component.isList()).toBe(true);
|
||||
});
|
||||
|
||||
it('should defined mat-list when layout type is LIST', () => {
|
||||
it('should display list when layout type is LIST', () => {
|
||||
fixture.detectChanges();
|
||||
const appListElement = fixture.nativeElement.querySelectorAll('mat-list');
|
||||
const appListItemElement = fixture.nativeElement.querySelectorAll('mat-list-item');
|
||||
const appName = fixture.nativeElement.querySelector('.mat-list-text');
|
||||
const appListElement = fixture.nativeElement.querySelectorAll('.adf-app-list');
|
||||
const appListItemElement = fixture.nativeElement.querySelectorAll('.adf-app-list-item');
|
||||
const appName = fixture.nativeElement.querySelector('.adf-app-list-item-text');
|
||||
expect(appListElement).toBeDefined();
|
||||
expect(appListElement).not.toBeNull();
|
||||
|
||||
@@ -200,7 +193,7 @@ describe('AppListCloudComponent', () => {
|
||||
it('should emit a click event when app selected', () => {
|
||||
spyOn(component.appClick, 'emit');
|
||||
fixture.detectChanges();
|
||||
const onAppClick = fixture.nativeElement.querySelector('.mat-card');
|
||||
const onAppClick = fixture.nativeElement.querySelector('.adf-app-listgrid-item-card');
|
||||
onAppClick.click();
|
||||
expect(component.appClick.emit).toHaveBeenCalledWith(fakeApplicationInstance[0]);
|
||||
});
|
||||
|
@@ -26,39 +26,29 @@ import { DebugElement, SimpleChange } from '@angular/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { IdentityGroupService } from '../services/identity-group.service';
|
||||
import { mockFoodGroups, mockMeatChicken, mockVegetableAubergine } from '../mock/group-cloud.mock';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatChipHarness, MatChipListHarness } from '@angular/material/chips/testing';
|
||||
import { MatIconHarness } from '@angular/material/icon/testing';
|
||||
import { MatInputHarness } from '@angular/material/input/testing';
|
||||
|
||||
describe('GroupCloudComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
let component: GroupCloudComponent;
|
||||
let fixture: ComponentFixture<GroupCloudComponent>;
|
||||
let element: HTMLElement;
|
||||
let identityGroupService: IdentityGroupService;
|
||||
let findGroupsByNameSpy: jasmine.Spy;
|
||||
|
||||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
||||
/**
|
||||
* get the native element for the selector
|
||||
*
|
||||
* @param selector selector
|
||||
* @returns native element
|
||||
*/
|
||||
function getElement<T = HTMLElement>(selector: string): T {
|
||||
return fixture.nativeElement.querySelector(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* search group by value
|
||||
*
|
||||
* @param value element input value
|
||||
*/
|
||||
async function searchGroup(value: string) {
|
||||
const input = getElement<HTMLInputElement>('input');
|
||||
input.focus();
|
||||
input.value = value;
|
||||
input.dispatchEvent(new Event('keyup'));
|
||||
input.dispatchEvent(new Event('input'));
|
||||
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
const input = await loader.getHarness(MatInputHarness);
|
||||
await input.focus();
|
||||
await input.setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,17 +57,10 @@ describe('GroupCloudComponent', () => {
|
||||
* @param value value
|
||||
*/
|
||||
async function searchGroupsAndBlur(value: string) {
|
||||
const input = getElement<HTMLInputElement>('input');
|
||||
input.focus();
|
||||
input.value = value;
|
||||
input.dispatchEvent(new Event('keyup'));
|
||||
input.dispatchEvent(new Event('input'));
|
||||
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
|
||||
input.blur();
|
||||
fixture.detectChanges();
|
||||
const input = await loader.getHarness(MatInputHarness);
|
||||
await input.focus();
|
||||
await input.setValue(value);
|
||||
await input.blur();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,18 +74,14 @@ describe('GroupCloudComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CoreTestingModule,
|
||||
ProcessServiceCloudTestingModule,
|
||||
GroupCloudModule
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), CoreTestingModule, ProcessServiceCloudTestingModule, GroupCloudModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(GroupCloudComponent);
|
||||
component = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
|
||||
identityGroupService = TestBed.inject(IdentityGroupService);
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
it('should populate placeholder when title is present', () => {
|
||||
@@ -115,7 +94,6 @@ describe('GroupCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('Search group', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
fixture.detectChanges();
|
||||
findGroupsByNameSpy = spyOn(identityGroupService, 'search').and.returnValue(of(mockFoodGroups));
|
||||
@@ -208,19 +186,19 @@ describe('GroupCloudComponent', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should not pre-select any group when preSelectGroups is empty - single mode', () => {
|
||||
it('should not pre-select any group when preSelectGroups is empty - single mode', async () => {
|
||||
component.mode = 'single';
|
||||
fixture.detectChanges();
|
||||
|
||||
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should not pre-select any group when preSelectGroups is empty - multiple mode', () => {
|
||||
it('should not pre-select any group when preSelectGroups is empty - multiple mode', async () => {
|
||||
component.mode = 'multiple';
|
||||
fixture.detectChanges();
|
||||
|
||||
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
@@ -235,10 +213,11 @@ describe('GroupCloudComponent', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should show only one mat chip with the first preSelectedGroup', () => {
|
||||
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||
it('should show only one mat chip with the first preSelectedGroup', async () => {
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toEqual(1);
|
||||
expect(chips[0].attributes['data-automation-id']).toEqual(`adf-cloud-group-chip-${mockVegetableAubergine.name}`);
|
||||
const testId = await (await chips[0].host()).getAttribute('data-automation-id');
|
||||
expect(testId).toEqual(`adf-cloud-group-chip-${mockVegetableAubergine.name}`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -252,12 +231,13 @@ describe('GroupCloudComponent', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should render all preselected groups', () => {
|
||||
it('should render all preselected groups', async () => {
|
||||
component.mode = 'multiple';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges({ preSelectGroups: change });
|
||||
fixture.detectChanges();
|
||||
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(2);
|
||||
});
|
||||
|
||||
@@ -266,42 +246,40 @@ describe('GroupCloudComponent', () => {
|
||||
const changedGroupsEmitterSpy = spyOn(component.changedGroups, 'emit');
|
||||
component.mode = 'multiple';
|
||||
|
||||
const removeIcon = fixture.debugElement.query(By.css('mat-chip mat-icon'));
|
||||
removeIcon.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
const chip = await loader.getHarness(MatChipHarness);
|
||||
const icon = await chip.getHarness(MatIconHarness);
|
||||
await (await icon.host()).click();
|
||||
|
||||
await fixture.whenStable();
|
||||
expect(removeGroupEmitterSpy).toHaveBeenCalledWith(mockVegetableAubergine);
|
||||
expect(changedGroupsEmitterSpy).toHaveBeenCalledWith([mockMeatChicken]);
|
||||
expect(component.selectedGroups.indexOf({
|
||||
expect(
|
||||
component.selectedGroups.indexOf({
|
||||
id: mockMeatChicken.id,
|
||||
name: mockMeatChicken.name
|
||||
})).toEqual(-1);
|
||||
})
|
||||
).toEqual(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multiple Mode with read-only', () => {
|
||||
|
||||
it('Should not show remove icon for pre-selected groups if readonly property set to true', async () => {
|
||||
component.mode = 'multiple';
|
||||
component.preSelectGroups = [
|
||||
{ id: mockVegetableAubergine.id, name: mockVegetableAubergine.name, readonly: true },
|
||||
mockMeatChicken
|
||||
];
|
||||
component.preSelectGroups = [{ id: mockVegetableAubergine.id, name: mockVegetableAubergine.name, readonly: true }, mockMeatChicken];
|
||||
const changes = new SimpleChange(null, [{ name: mockVegetableAubergine.name }], false);
|
||||
component.ngOnChanges({ preSelectGroups: changes });
|
||||
fixture.detectChanges();
|
||||
|
||||
await fixture.whenStable();
|
||||
|
||||
const chipList = fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip');
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(2);
|
||||
|
||||
expect(chipList.length).toBe(2);
|
||||
const removeIconAubergine = getElement(`[data-automation-id="adf-cloud-group-chip-remove-icon-${mockVegetableAubergine.name}"]`);
|
||||
const removeIconAubergine = element.querySelector(
|
||||
`[data-automation-id="adf-cloud-group-chip-remove-icon-${mockVegetableAubergine.name}"]`
|
||||
);
|
||||
expect(removeIconAubergine).toBeNull();
|
||||
const removeIconPepper = getElement(`[data-automation-id="adf-cloud-group-chip-remove-icon-${mockMeatChicken.name}"]`);
|
||||
const removeIconPepper = element.querySelector(`[data-automation-id="adf-cloud-group-chip-remove-icon-${mockMeatChicken.name}"]`);
|
||||
expect(removeIconPepper).not.toBeNull();
|
||||
|
||||
});
|
||||
|
||||
it('Should be able to remove preselected groups if readonly property set to false', async () => {
|
||||
@@ -314,28 +292,26 @@ describe('GroupCloudComponent', () => {
|
||||
const removeGroupSpy = spyOn(component.removeGroup, 'emit');
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
let chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(2);
|
||||
|
||||
const chipList = fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip');
|
||||
expect(chipList.length).toBe(2);
|
||||
|
||||
const removeIcon = getElement(`[data-automation-id="adf-cloud-group-chip-remove-icon-${mockMeatChicken.name}"]`);
|
||||
const removeIcon = element.querySelector<HTMLElement>(`[data-automation-id="adf-cloud-group-chip-remove-icon-${mockMeatChicken.name}"]`);
|
||||
removeIcon.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(removeGroupSpy).toHaveBeenCalled();
|
||||
expect(fixture.nativeElement.querySelectorAll('mat-chip-list mat-chip').length).toBe(1);
|
||||
|
||||
chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should removeDuplicatedGroups return only unique groups', () => {
|
||||
const duplicatedGroups = [ mockMeatChicken, mockMeatChicken];
|
||||
const duplicatedGroups = [mockMeatChicken, mockMeatChicken];
|
||||
expect(component.removeDuplicatedGroups(duplicatedGroups)).toEqual([mockMeatChicken]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Preselected groups and validation enabled', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(identityGroupService, 'search').and.throwError('Invalid group');
|
||||
component.validate = true;
|
||||
@@ -364,7 +340,7 @@ describe('GroupCloudComponent', () => {
|
||||
describe('Component readonly mode', () => {
|
||||
const change = new SimpleChange(null, mockFoodGroups, false);
|
||||
|
||||
it('should chip list be disabled and show one single chip - single mode', () => {
|
||||
it('should chip list be disabled and show one single chip - single mode', async () => {
|
||||
component.mode = 'single';
|
||||
component.readOnly = true;
|
||||
component.preSelectGroups = mockFoodGroups;
|
||||
@@ -372,16 +348,14 @@ describe('GroupCloudComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||
const chipList = getElement('mat-chip-list');
|
||||
|
||||
expect(chips).toBeDefined();
|
||||
expect(chipList).toBeDefined();
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(1);
|
||||
expect(chipList.attributes['ng-reflect-disabled']?.value).toEqual('true');
|
||||
|
||||
const chipList = await loader.getHarness(MatChipListHarness);
|
||||
expect(await chipList.isDisabled()).toBe(true);
|
||||
});
|
||||
|
||||
it('should chip list be disabled and show all the chips - multiple mode', () => {
|
||||
it('should chip list be disabled and show all the chips - multiple mode', async () => {
|
||||
component.mode = 'multiple';
|
||||
component.readOnly = true;
|
||||
component.preSelectGroups = mockFoodGroups;
|
||||
@@ -389,14 +363,11 @@ describe('GroupCloudComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const chips = fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||
const chipList = getElement('mat-chip-list');
|
||||
|
||||
expect(chips).toBeDefined();
|
||||
expect(chipList).toBeDefined();
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(2);
|
||||
expect(chipList.attributes['ng-reflect-disabled']?.value).toEqual('true');
|
||||
});
|
||||
});
|
||||
|
||||
const chipList = await loader.getHarness(MatChipListHarness);
|
||||
expect(await chipList.isDisabled()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -26,46 +26,29 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of } from 'rxjs';
|
||||
import { IdentityUserServiceInterface } from '../services/identity-user.service.interface';
|
||||
import { IDENTITY_USER_SERVICE_TOKEN } from '../services/identity-user-service.token';
|
||||
import {
|
||||
mockFoodUsers,
|
||||
mockKielbasaSausage,
|
||||
mockShepherdsPie,
|
||||
mockYorkshirePudding,
|
||||
mockPreselectedFoodUsers
|
||||
} from '../mock/people-cloud.mock';
|
||||
import { mockFoodUsers, mockKielbasaSausage, mockShepherdsPie, mockYorkshirePudding, mockPreselectedFoodUsers } from '../mock/people-cloud.mock';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatChipHarness, MatChipListHarness } from '@angular/material/chips/testing';
|
||||
import { MatInputHarness } from '@angular/material/input/testing';
|
||||
|
||||
describe('PeopleCloudComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
let component: PeopleCloudComponent;
|
||||
let fixture: ComponentFixture<PeopleCloudComponent>;
|
||||
let element: HTMLElement;
|
||||
let identityUserService: IdentityUserServiceInterface;
|
||||
let searchSpy: jasmine.Spy;
|
||||
|
||||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
||||
/**
|
||||
* get the native element by selector
|
||||
*
|
||||
* @param selector selector
|
||||
* @returns native element
|
||||
*/
|
||||
function getElement<T = HTMLElement>(selector: string): T {
|
||||
return fixture.nativeElement.querySelector(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search users by value
|
||||
*
|
||||
* @param value value
|
||||
*/
|
||||
async function searchUsers(value: string) {
|
||||
const input = getElement<HTMLInputElement>('input');
|
||||
input.focus();
|
||||
input.value = value;
|
||||
input.dispatchEvent(new Event('keyup'));
|
||||
input.dispatchEvent(new Event('input'));
|
||||
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
const input = await loader.getHarness(MatInputHarness);
|
||||
await input.focus();
|
||||
await input.setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,17 +57,10 @@ describe('PeopleCloudComponent', () => {
|
||||
* @param value value
|
||||
*/
|
||||
async function searchUsersAndBlur(value: string) {
|
||||
const input = getElement<HTMLInputElement>('input');
|
||||
input.focus();
|
||||
input.value = value;
|
||||
input.dispatchEvent(new Event('keyup'));
|
||||
input.dispatchEvent(new Event('input'));
|
||||
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
|
||||
input.blur();
|
||||
fixture.detectChanges();
|
||||
const input = await loader.getHarness(MatInputHarness);
|
||||
await input.focus();
|
||||
await input.setValue(value);
|
||||
await input.blur();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,15 +72,6 @@ describe('PeopleCloudComponent', () => {
|
||||
return fixture.debugElement.queryAll(By.css('[data-automation-id="adf-people-cloud-row"]'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get users chip list UI
|
||||
*
|
||||
* @returns list of debug elements
|
||||
*/
|
||||
function getUsersChipsUI(): DebugElement[] {
|
||||
return fixture.debugElement.queryAll(By.css('mat-chip'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first user from the list
|
||||
*
|
||||
@@ -116,24 +83,21 @@ describe('PeopleCloudComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CoreTestingModule,
|
||||
ProcessServiceCloudTestingModule,
|
||||
PeopleCloudModule
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), CoreTestingModule, ProcessServiceCloudTestingModule, PeopleCloudModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(PeopleCloudComponent);
|
||||
component = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
|
||||
identityUserService = TestBed.inject(IDENTITY_USER_SERVICE_TOKEN);
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
it('should populate placeholder when title is present', () => {
|
||||
component.title = 'TITLE_KEY';
|
||||
fixture.detectChanges();
|
||||
|
||||
const matLabel = getElement<HTMLInputElement>('#adf-people-cloud-title-id');
|
||||
const matLabel = element.querySelector<HTMLInputElement>('#adf-people-cloud-title-id');
|
||||
|
||||
expect(matLabel.textContent).toEqual('TITLE_KEY');
|
||||
});
|
||||
@@ -141,7 +105,7 @@ describe('PeopleCloudComponent', () => {
|
||||
it('should not populate placeholder when title is not present', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const matLabel = getElement<HTMLInputElement>('#adf-people-cloud-title-id');
|
||||
const matLabel = element.querySelector<HTMLInputElement>('#adf-people-cloud-title-id');
|
||||
|
||||
expect(matLabel.textContent).toEqual('');
|
||||
});
|
||||
@@ -196,7 +160,9 @@ describe('PeopleCloudComponent', () => {
|
||||
});
|
||||
|
||||
it('should not be able to search for a user that his email matches one of the excluded users email', async () => {
|
||||
component.excludedUsers = [{ email: mockKielbasaSausage.email, username: 'new-username', firstName: 'new-first-name', lastName: 'new-last-name' }];
|
||||
component.excludedUsers = [
|
||||
{ email: mockKielbasaSausage.email, username: 'new-username', firstName: 'new-first-name', lastName: 'new-last-name' }
|
||||
];
|
||||
fixture.detectChanges();
|
||||
|
||||
await searchUsers('first-name');
|
||||
@@ -205,7 +171,15 @@ describe('PeopleCloudComponent', () => {
|
||||
});
|
||||
|
||||
it('should not be able to search for a user that his id matches one of the excluded users id', async () => {
|
||||
component.excludedUsers = [{ id: mockKielbasaSausage.id, username: 'new-username', firstName: 'new-first-name', lastName: 'new-last-name', email: 'new-email@food.com' }];
|
||||
component.excludedUsers = [
|
||||
{
|
||||
id: mockKielbasaSausage.id,
|
||||
username: 'new-username',
|
||||
firstName: 'new-first-name',
|
||||
lastName: 'new-last-name',
|
||||
email: 'new-email@food.com'
|
||||
}
|
||||
];
|
||||
fixture.detectChanges();
|
||||
|
||||
await searchUsers('first-name');
|
||||
@@ -214,7 +188,9 @@ describe('PeopleCloudComponent', () => {
|
||||
});
|
||||
|
||||
it('should not be able to search for a user that his username matches one of the excluded users username', async () => {
|
||||
component.excludedUsers = [{ username: mockKielbasaSausage.username, firstName: 'new-first-name', lastName: 'new-last-name', email: 'new-email@food.com' }];
|
||||
component.excludedUsers = [
|
||||
{ username: mockKielbasaSausage.username, firstName: 'new-first-name', lastName: 'new-last-name', email: 'new-email@food.com' }
|
||||
];
|
||||
fixture.detectChanges();
|
||||
|
||||
await searchUsers('first-name');
|
||||
@@ -301,17 +277,20 @@ describe('PeopleCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('No preselected users', () => {
|
||||
|
||||
it('should not pre-select any user when preSelectUsers is empty - single mode', () => {
|
||||
it('should not pre-select any user when preSelectUsers is empty - single mode', async () => {
|
||||
component.mode = 'single';
|
||||
fixture.detectChanges();
|
||||
expect(getUsersChipsUI().length).toEqual(0);
|
||||
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should not pre-select any users when preSelectUsers is empty - multiple mode', () => {
|
||||
it('should not pre-select any users when preSelectUsers is empty - multiple mode', async () => {
|
||||
component.mode = 'multiple';
|
||||
fixture.detectChanges();
|
||||
expect(getUsersChipsUI().length).toEqual(0);
|
||||
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -327,14 +306,16 @@ describe('PeopleCloudComponent', () => {
|
||||
element = fixture.nativeElement;
|
||||
});
|
||||
|
||||
it('should show only one mat chip with the first preSelectedUser', () => {
|
||||
expect(getUsersChipsUI().length).toEqual(1);
|
||||
expect(getUsersChipsUI()[0].attributes['data-automation-id']).toEqual(`adf-people-cloud-chip-${mockPreselectedFoodUsers[0].username}`);
|
||||
it('should show only one mat chip with the first preSelectedUser', async () => {
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toEqual(1);
|
||||
|
||||
const testId = await (await chips[0].host()).getAttribute('data-automation-id');
|
||||
expect(testId).toEqual(`adf-people-cloud-chip-${mockPreselectedFoodUsers[0].username}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multiple Mode with Pre-selected Users', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
component.mode = 'multiple';
|
||||
});
|
||||
@@ -347,9 +328,15 @@ describe('PeopleCloudComponent', () => {
|
||||
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
expect(getUsersChipsUI().length).toEqual(2);
|
||||
expect(getUsersChipsUI()[0].attributes['data-automation-id']).toEqual(`adf-people-cloud-chip-${mockPreselectedFoodUsers[0].username}`);
|
||||
expect(getUsersChipsUI()[1].attributes['data-automation-id']).toEqual(`adf-people-cloud-chip-${mockPreselectedFoodUsers[1].username}`);
|
||||
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toEqual(2);
|
||||
|
||||
const testId1 = await (await chips[0].host()).getAttribute('data-automation-id');
|
||||
const testId2 = await (await chips[1].host()).getAttribute('data-automation-id');
|
||||
|
||||
expect(testId1).toEqual(`adf-people-cloud-chip-${mockPreselectedFoodUsers[0].username}`);
|
||||
expect(testId2).toEqual(`adf-people-cloud-chip-${mockPreselectedFoodUsers[1].username}`);
|
||||
});
|
||||
|
||||
it('Should not show remove icon for pre-selected users if readonly property set to true', async () => {
|
||||
@@ -361,12 +348,16 @@ describe('PeopleCloudComponent', () => {
|
||||
const change = new SimpleChange(null, component.preSelectUsers, false);
|
||||
component.ngOnChanges({ preSelectUsers: change });
|
||||
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const removeIcon = getElement(`[data-automation-id="adf-people-cloud-chip-remove-icon-${mockPreselectedFoodUsers[0].username}"]`);
|
||||
const removeIcon = element.querySelector(
|
||||
`[data-automation-id="adf-people-cloud-chip-remove-icon-${mockPreselectedFoodUsers[0].username}"]`
|
||||
);
|
||||
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(2);
|
||||
|
||||
expect(getUsersChipsUI().length).toBe(2);
|
||||
expect(component.preSelectUsers[0].readonly).toBeTruthy();
|
||||
expect(component.preSelectUsers[1].readonly).toBeTruthy();
|
||||
expect(removeIcon).toBeNull();
|
||||
@@ -380,27 +371,32 @@ describe('PeopleCloudComponent', () => {
|
||||
|
||||
const removeUserSpy = spyOn(component.removeUser, 'emit');
|
||||
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const removeIcon = getElement(`[data-automation-id="adf-people-cloud-chip-remove-icon-${mockPreselectedFoodUsers[0].username}"]`);
|
||||
const removeIcon = element.querySelector<HTMLElement>(
|
||||
`[data-automation-id="adf-people-cloud-chip-remove-icon-${mockPreselectedFoodUsers[0].username}"]`
|
||||
);
|
||||
|
||||
expect(getUsersChipsUI().length).toBe(2);
|
||||
expect(component.preSelectUsers[0].readonly).toBe(false, 'Removable');
|
||||
expect(component.preSelectUsers[1].readonly).toBe(false, 'Removable');
|
||||
let chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(2);
|
||||
|
||||
expect(component.preSelectUsers[0].readonly).toBe(false);
|
||||
expect(component.preSelectUsers[1].readonly).toBe(false);
|
||||
|
||||
removeIcon.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(removeUserSpy).toHaveBeenCalled();
|
||||
expect(getUsersChipsUI().length).toBe(1);
|
||||
|
||||
chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(1);
|
||||
});
|
||||
|
||||
describe('Component readonly mode', () => {
|
||||
const change = new SimpleChange(null, mockPreselectedFoodUsers, false);
|
||||
|
||||
it('should chip list be disabled and show one single chip - single mode', () => {
|
||||
it('should chip list be disabled and show one single chip - single mode', async () => {
|
||||
component.mode = 'single';
|
||||
component.readOnly = true;
|
||||
component.preSelectUsers = mockPreselectedFoodUsers;
|
||||
@@ -408,15 +404,14 @@ describe('PeopleCloudComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const chipList = getElement('mat-chip-list');
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(1);
|
||||
|
||||
expect(getUsersChipsUI()).toBeDefined();
|
||||
expect(chipList).toBeDefined();
|
||||
expect(getUsersChipsUI().length).toBe(1);
|
||||
expect(chipList.attributes['ng-reflect-disabled'].value).toEqual('true');
|
||||
const chipList = await loader.getHarness(MatChipListHarness);
|
||||
expect(await chipList.isDisabled()).toBe(true);
|
||||
});
|
||||
|
||||
it('should chip list be disabled and show mat chips for all the preselected users - multiple mode', () => {
|
||||
it('should chip list be disabled and show mat chips for all the preselected users - multiple mode', async () => {
|
||||
component.mode = 'multiple';
|
||||
component.readOnly = true;
|
||||
component.preSelectUsers = mockPreselectedFoodUsers;
|
||||
@@ -424,18 +419,16 @@ describe('PeopleCloudComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const chipList = getElement('mat-chip-list');
|
||||
const chips = await loader.getAllHarnesses(MatChipHarness);
|
||||
expect(chips.length).toBe(2);
|
||||
|
||||
expect(getUsersChipsUI()).toBeDefined();
|
||||
expect(chipList).toBeDefined();
|
||||
expect(getUsersChipsUI().length).toBe(2);
|
||||
expect(chipList.attributes['ng-reflect-disabled'].value).toEqual('true');
|
||||
const chipList = await loader.getHarness(MatChipListHarness);
|
||||
expect(await chipList.isDisabled()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Preselected users and validation enabled', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(identityUserService, 'search').and.throwError('Invalid user');
|
||||
component.validate = true;
|
||||
|
@@ -44,6 +44,9 @@ import { HttpClientModule } from '@angular/common/http';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { PreferenceCloudServiceInterface } from '@alfresco/adf-process-services-cloud';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
|
||||
|
||||
@Component({
|
||||
template: ` <adf-cloud-process-list #processListCloud>
|
||||
@@ -68,6 +71,7 @@ class CustomTaskListComponent {
|
||||
}
|
||||
|
||||
describe('ProcessListCloudComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
let component: ProcessListCloudComponent;
|
||||
let fixture: ComponentFixture<ProcessListCloudComponent>;
|
||||
let appConfig: AppConfigService;
|
||||
@@ -118,6 +122,7 @@ describe('ProcessListCloudComponent', () => {
|
||||
});
|
||||
|
||||
component.isColumnSchemaCreated$ = of(true).pipe(shareReplay(1));
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -132,41 +137,39 @@ describe('ProcessListCloudComponent', () => {
|
||||
expect(component.columns.length).toEqual(10);
|
||||
});
|
||||
|
||||
it('should display empty content when process list is empty', () => {
|
||||
it('should display empty content when process list is empty', async () => {
|
||||
const emptyList = { list: { entries: [] } };
|
||||
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(emptyList));
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(component.isLoading).toBe(true);
|
||||
let loadingContent = fixture.debugElement.query(By.css('mat-progress-spinner'));
|
||||
expect(loadingContent.nativeElement).toBeDefined();
|
||||
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(true);
|
||||
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
loadingContent = fixture.debugElement.query(By.css('mat-progress-spinner'));
|
||||
expect(loadingContent).toBeFalsy();
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent.nativeElement).toBeDefined();
|
||||
});
|
||||
|
||||
it('should load spinner and show the content', () => {
|
||||
it('should load spinner and show the content', async () => {
|
||||
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(component.isLoading).toBe(true);
|
||||
let loadingContent = fixture.debugElement.query(By.css('mat-progress-spinner'));
|
||||
expect(loadingContent.nativeElement).toBeDefined();
|
||||
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(true);
|
||||
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.isLoading).toBe(false);
|
||||
loadingContent = fixture.debugElement.query(By.css('mat-progress-spinner'));
|
||||
expect(loadingContent).toBeFalsy();
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent).toBeFalsy();
|
||||
|
@@ -21,7 +21,6 @@
|
||||
data-automation-id="adf-select-cloud-process-dropdown">
|
||||
<mat-label>{{ 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.LABEL.TYPE' | translate }}</mat-label>
|
||||
<input
|
||||
#inputAutocomplete
|
||||
matInput
|
||||
formControlName="processDefinition"
|
||||
[matAutocomplete]="auto"
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { SimpleChange, DebugElement } from '@angular/core';
|
||||
import { SimpleChange } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
||||
import { FormModel } from '@alfresco/adf-core';
|
||||
import { of, throwError } from 'rxjs';
|
||||
@@ -30,7 +30,6 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import {
|
||||
fakeProcessDefinitions,
|
||||
fakeStartForm,
|
||||
@@ -50,8 +49,13 @@ import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
|
||||
import { ESCAPE } from '@angular/cdk/keycodes';
|
||||
import { ProcessDefinitionCloud, TaskVariableCloud } from '@alfresco/adf-process-services-cloud';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatAutocompleteHarness } from '@angular/material/autocomplete/testing';
|
||||
import { MatButtonHarness } from '@angular/material/button/testing';
|
||||
|
||||
describe('StartProcessCloudComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
let component: StartProcessCloudComponent;
|
||||
let fixture: ComponentFixture<StartProcessCloudComponent>;
|
||||
let processService: StartProcessCloudService;
|
||||
@@ -64,18 +68,11 @@ describe('StartProcessCloudComponent', () => {
|
||||
const firstChange = new SimpleChange(undefined, 'myApp', true);
|
||||
|
||||
const selectOptionByName = async (name: string) => {
|
||||
const selectElement = fixture.nativeElement.querySelector('button#adf-select-process-dropdown');
|
||||
selectElement.click();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const options: any = fixture.debugElement.queryAll(By.css('.mat-autocomplete-panel .mat-option'));
|
||||
const currentOption: DebugElement = options.find(
|
||||
(option: DebugElement) => option.nativeElement.querySelector('.mat-option-text').innerHTML.trim() === name
|
||||
);
|
||||
const arrowButton = await loader.getHarness(MatButtonHarness.with({ selector: '#adf-select-process-dropdown' }));
|
||||
await arrowButton.click();
|
||||
|
||||
if (currentOption) {
|
||||
currentOption.nativeElement.click();
|
||||
}
|
||||
const panel = await loader.getHarness(MatAutocompleteHarness);
|
||||
await panel.selectOption({ text: name });
|
||||
};
|
||||
|
||||
const typeValueInto = (selector: any, value: string) => {
|
||||
@@ -112,6 +109,7 @@ describe('StartProcessCloudComponent', () => {
|
||||
spyOn(processService, 'updateProcess').and.returnValue(of());
|
||||
startProcessSpy = spyOn(processService, 'startProcess').and.returnValue(of(fakeProcessInstance));
|
||||
getStartEventFormStaticValuesMappingSpy = spyOn(processService, 'getStartEventFormStaticValuesMapping').and.returnValue(of([]));
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -372,27 +370,12 @@ describe('StartProcessCloudComponent', () => {
|
||||
});
|
||||
|
||||
it('should display the correct number of processes in the select list', async () => {
|
||||
await fixture.whenStable();
|
||||
const arrowButton = await loader.getHarness(MatButtonHarness.with({ selector: '#adf-select-process-dropdown' }));
|
||||
await arrowButton.click();
|
||||
|
||||
const arrowButton = fixture.nativeElement.querySelector('button#adf-select-process-dropdown');
|
||||
arrowButton.click();
|
||||
fixture.detectChanges();
|
||||
const processLists = fixture.debugElement.query(By.css('.mat-autocomplete-panel'));
|
||||
expect(processLists.children.length).toBe(4);
|
||||
});
|
||||
|
||||
it('should display the option def details', async () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const selectElement = fixture.nativeElement.querySelector('button#adf-select-process-dropdown');
|
||||
selectElement.click();
|
||||
fixture.detectChanges();
|
||||
const optionElement = fixture.debugElement.queryAll(By.css('.mat-autocomplete-panel .mat-option'));
|
||||
expect(selectElement).not.toBeNull();
|
||||
expect(selectElement).toBeDefined();
|
||||
expect(optionElement).not.toBeNull();
|
||||
expect(optionElement).toBeDefined();
|
||||
const panel = await loader.getHarness(MatAutocompleteHarness);
|
||||
const options = await panel.getOptions();
|
||||
expect(options.length).toBe(4);
|
||||
});
|
||||
|
||||
it('should display the key when the processDefinition name is empty or null', async () => {
|
||||
@@ -400,14 +383,12 @@ describe('StartProcessCloudComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const selectElement = fixture.nativeElement.querySelector('button#adf-select-process-dropdown');
|
||||
selectElement.click();
|
||||
fixture.detectChanges();
|
||||
const optionElement = fixture.debugElement.queryAll(By.css('.mat-autocomplete-panel .mat-option'));
|
||||
expect(selectElement).not.toBeNull();
|
||||
expect(selectElement).toBeDefined();
|
||||
expect(optionElement).not.toBeNull();
|
||||
expect(optionElement[0].nativeElement.textContent.trim()).toBe('NewProcess 1');
|
||||
const arrowButton = await loader.getHarness(MatButtonHarness.with({ selector: '#adf-select-process-dropdown' }));
|
||||
await arrowButton.click();
|
||||
|
||||
const panel = await loader.getHarness(MatAutocompleteHarness);
|
||||
const options = await panel.getOptions();
|
||||
expect(await options[0].getText()).toBe('NewProcess 1');
|
||||
});
|
||||
|
||||
it('should indicate an error to the user if process defs cannot be loaded', async () => {
|
||||
@@ -486,7 +467,7 @@ describe('StartProcessCloudComponent', () => {
|
||||
component.processDefinitionName = 'process';
|
||||
component.appName = 'myApp';
|
||||
component.ngOnChanges({});
|
||||
selectOptionByName('process');
|
||||
await selectOptionByName('process');
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
@@ -550,20 +531,6 @@ describe('StartProcessCloudComponent', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should have floating labels for process name and type', async () => {
|
||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||
component.ngOnChanges({ appName: change });
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
component.processForm.controls.processInstanceName.setValue('My sharona');
|
||||
component.processForm.controls.processDefinition.setValue('process');
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const inputLabelsNodes = document.querySelectorAll('.mat-form-field-label');
|
||||
expect(inputLabelsNodes.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should reload processes when appName input changed', async () => {
|
||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||
component.ngOnChanges({ appName: firstChange });
|
||||
@@ -837,7 +804,7 @@ describe('StartProcessCloudComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
component.processDefinitionName = 'processwithoutform1';
|
||||
selectOptionByName(fakeProcessDefinitions[0].name);
|
||||
await selectOptionByName(fakeProcessDefinitions[0].name);
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
expect(emitSpy).toHaveBeenCalledOnceWith(fakeProcessDefinitions[0]);
|
||||
|
@@ -33,6 +33,9 @@ import {
|
||||
import { TaskCloudService } from '../../services/task-cloud.service';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { IdentityUserService } from '../../../people/services/identity-user.service';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
|
||||
|
||||
const taskDetails: TaskDetailsCloudModel = {
|
||||
appName: 'simple-app',
|
||||
@@ -50,7 +53,7 @@ const taskDetails: TaskDetailsCloudModel = {
|
||||
};
|
||||
|
||||
describe('TaskFormCloudComponent', () => {
|
||||
|
||||
let loader: HarnessLoader;
|
||||
let taskCloudService: TaskCloudService;
|
||||
let identityUserService: IdentityUserService;
|
||||
|
||||
@@ -63,10 +66,7 @@ describe('TaskFormCloudComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule]
|
||||
});
|
||||
taskDetails.status = TASK_ASSIGNED_STATE;
|
||||
taskDetails.permissions = [TASK_VIEW_PERMISSION];
|
||||
@@ -82,6 +82,7 @@ describe('TaskFormCloudComponent', () => {
|
||||
fixture = TestBed.createComponent(TaskFormCloudComponent);
|
||||
debugElement = fixture.debugElement;
|
||||
component = fixture.componentInstance;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -89,7 +90,6 @@ describe('TaskFormCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('Complete button', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
component.taskId = 'task1';
|
||||
component.ngOnChanges({ appName: new SimpleChange(null, 'app1', false) });
|
||||
@@ -120,7 +120,6 @@ describe('TaskFormCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('Claim/Unclaim buttons', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(component, 'hasCandidateUsers').and.returnValue(true);
|
||||
getTaskSpy.and.returnValue(of(taskDetails));
|
||||
@@ -213,7 +212,6 @@ describe('TaskFormCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('Cancel button', () => {
|
||||
|
||||
it('should show cancel button by default', () => {
|
||||
component.appName = 'app1';
|
||||
component.taskId = 'task1';
|
||||
@@ -238,7 +236,6 @@ describe('TaskFormCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('Inputs', () => {
|
||||
|
||||
it('should not show complete/claim/unclaim buttons when readOnly=true', () => {
|
||||
component.appName = 'app1';
|
||||
component.taskId = 'task1';
|
||||
@@ -284,7 +281,6 @@ describe('TaskFormCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('Events', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
component.appName = 'app1';
|
||||
component.taskId = 'task1';
|
||||
@@ -292,7 +288,7 @@ describe('TaskFormCloudComponent', () => {
|
||||
});
|
||||
|
||||
it('should emit cancelClick when cancel button is clicked', async () => {
|
||||
spyOn(component.cancelClick,'emit').and.stub();
|
||||
spyOn(component.cancelClick, 'emit').and.stub();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
@@ -395,22 +391,18 @@ describe('TaskFormCloudComponent', () => {
|
||||
expect(reloadSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should show loading template while task data is being loaded', () => {
|
||||
it('should show loading template while task data is being loaded', async () => {
|
||||
component.loading = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
const loadingTemplate = debugElement.query(By.css('mat-progress-spinner'));
|
||||
|
||||
expect(loadingTemplate).toBeDefined();
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(true);
|
||||
});
|
||||
|
||||
it('should not show loading template while task data is not being loaded', () => {
|
||||
it('should not show loading template while task data is not being loaded', async () => {
|
||||
component.loading = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
const loadingTemplate = debugElement.query(By.css('mat-progress-spinner'));
|
||||
|
||||
expect(loadingTemplate).toBeNull();
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
});
|
||||
|
||||
it('should emit an executeOutcome event when form outcome executed', () => {
|
||||
|
@@ -27,12 +27,19 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TaskListCloudSortingModel } from '../../../models/task-list-sorting.model';
|
||||
import { shareReplay, skip } from 'rxjs/operators';
|
||||
import { ServiceTaskListCloudService } from '../services/service-task-list-cloud.service';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<adf-cloud-service-task-list #taskListCloud>
|
||||
template: ` <adf-cloud-service-task-list #taskListCloud>
|
||||
<data-columns>
|
||||
<data-column key="activityName" title="ADF_CLOUD_TASK_LIST.PROPERTIES.NAME" class="adf-full-width adf-name-column" [order]="2"></data-column>
|
||||
<data-column
|
||||
key="activityName"
|
||||
title="ADF_CLOUD_TASK_LIST.PROPERTIES.NAME"
|
||||
class="adf-full-width adf-name-column"
|
||||
[order]="2"
|
||||
></data-column>
|
||||
<data-column key="startedDate" title="ADF_CLOUD_TASK_LIST.PROPERTIES.CREATED" class="adf-hidden"></data-column>
|
||||
</data-columns>
|
||||
</adf-cloud-service-task-list>`
|
||||
@@ -50,11 +57,9 @@ class CustomTaskListComponent {
|
||||
</adf-cloud-service-task-list>
|
||||
`
|
||||
})
|
||||
class EmptyTemplateComponent {
|
||||
}
|
||||
class EmptyTemplateComponent {}
|
||||
@Component({
|
||||
template: `
|
||||
<adf-cloud-service-task-list>
|
||||
template: ` <adf-cloud-service-task-list>
|
||||
<data-columns>
|
||||
<data-column [copyContent]="true" key="id" title="ADF_CLOUD_TASK_LIST.PROPERTIES.ID"></data-column>
|
||||
<data-column key="activityName" title="ADF_CLOUD_TASK_LIST.PROPERTIES.NAME"></data-column>
|
||||
@@ -67,6 +72,7 @@ class CustomCopyContentTaskListComponent {
|
||||
}
|
||||
|
||||
describe('ServiceTaskListCloudComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
let component: ServiceTaskListCloudComponent;
|
||||
let fixture: ComponentFixture<ServiceTaskListCloudComponent>;
|
||||
let appConfig: AppConfigService;
|
||||
@@ -74,13 +80,8 @@ describe('ServiceTaskListCloudComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule
|
||||
],
|
||||
declarations: [
|
||||
EmptyTemplateComponent
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule],
|
||||
declarations: [EmptyTemplateComponent]
|
||||
});
|
||||
appConfig = TestBed.inject(AppConfigService);
|
||||
serviceTaskListCloudService = TestBed.inject(ServiceTaskListCloudService);
|
||||
@@ -108,6 +109,7 @@ describe('ServiceTaskListCloudComponent', () => {
|
||||
});
|
||||
|
||||
component.isColumnSchemaCreated$ = of(true).pipe(shareReplay(1));
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -120,19 +122,18 @@ describe('ServiceTaskListCloudComponent', () => {
|
||||
expect(component.columns.length).toEqual(3);
|
||||
});
|
||||
|
||||
it('should display empty content when process list is empty', () => {
|
||||
it('should display empty content when process list is empty', async () => {
|
||||
const emptyList = { list: { entries: [] } };
|
||||
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(emptyList));
|
||||
fixture.detectChanges();
|
||||
|
||||
const loadingContent = fixture.debugElement.query(By.css('mat-progress-spinner'));
|
||||
expect(loadingContent).toBeFalsy();
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent.nativeElement).toBeDefined();
|
||||
});
|
||||
|
||||
it('should load spinner and show the content', () => {
|
||||
it('should load spinner and show the content', async () => {
|
||||
spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
|
||||
@@ -140,8 +141,7 @@ describe('ServiceTaskListCloudComponent', () => {
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
const loadingContent = fixture.debugElement.query(By.css('mat-progress-spinner'));
|
||||
expect(loadingContent).toBeFalsy();
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent).toBeFalsy();
|
||||
@@ -235,7 +235,6 @@ describe('ServiceTaskListCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('component changes', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
component.rows = fakeServiceTask.list.entries;
|
||||
fixture.detectChanges();
|
||||
@@ -283,13 +282,15 @@ describe('ServiceTaskListCloudComponent', () => {
|
||||
|
||||
it('should reload task list when sorting on a column changes', () => {
|
||||
const getServiceTaskByRequestSpy = spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
|
||||
component.onSortingChanged(new CustomEvent('sorting-changed', {
|
||||
component.onSortingChanged(
|
||||
new CustomEvent('sorting-changed', {
|
||||
detail: {
|
||||
key: 'fakeName',
|
||||
direction: 'asc'
|
||||
},
|
||||
bubbles: true
|
||||
}));
|
||||
})
|
||||
);
|
||||
fixture.detectChanges();
|
||||
expect(component.sorting).toEqual([
|
||||
new TaskListCloudSortingModel({
|
||||
@@ -307,8 +308,7 @@ describe('ServiceTaskListCloudComponent', () => {
|
||||
|
||||
const size = component.size;
|
||||
const skipCount = component.skipCount;
|
||||
component.pagination.pipe(skip(3))
|
||||
.subscribe((updatedPagination) => {
|
||||
component.pagination.pipe(skip(3)).subscribe((updatedPagination) => {
|
||||
fixture.detectChanges();
|
||||
expect(component.size).toBe(size);
|
||||
expect(component.skipCount).toBe(skipCount);
|
||||
@@ -334,8 +334,7 @@ describe('ServiceTaskListCloudComponent', () => {
|
||||
maxItems: 250,
|
||||
skipCount: 200
|
||||
};
|
||||
component.pagination.pipe(skip(1))
|
||||
.subscribe((updatedPagination) => {
|
||||
component.pagination.pipe(skip(1)).subscribe((updatedPagination) => {
|
||||
fixture.detectChanges();
|
||||
expect(component.size).toBe(pagination.maxItems);
|
||||
expect(component.skipCount).toBe(pagination.skipCount);
|
||||
@@ -358,14 +357,8 @@ describe('ServiceTaskListCloudComponent: Injecting custom columns for task list
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule
|
||||
],
|
||||
declarations: [
|
||||
CustomTaskListComponent,
|
||||
CustomCopyContentTaskListComponent
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule],
|
||||
declarations: [CustomTaskListComponent, CustomCopyContentTaskListComponent]
|
||||
});
|
||||
|
||||
serviceTaskListCloudService = TestBed.inject(ServiceTaskListCloudService);
|
||||
@@ -396,9 +389,7 @@ describe('ServiceTaskListCloudComponent: Injecting custom columns for task list
|
||||
customCopyComponent.taskList.reload();
|
||||
copyFixture.detectChanges();
|
||||
|
||||
copyFixture.debugElement
|
||||
.query(By.css('span[title="04fdf69f-4ddd-48ab-9563-da776c9b163c"]'))
|
||||
.triggerEventHandler('mouseenter');
|
||||
copyFixture.debugElement.query(By.css('span[title="04fdf69f-4ddd-48ab-9563-da776c9b163c"]')).triggerEventHandler('mouseenter');
|
||||
|
||||
copyFixture.detectChanges();
|
||||
expect(copyFixture.debugElement.query(By.css('.adf-copy-tooltip'))).not.toBeNull();
|
||||
@@ -408,9 +399,7 @@ describe('ServiceTaskListCloudComponent: Injecting custom columns for task list
|
||||
customCopyComponent.taskList.reload();
|
||||
copyFixture.detectChanges();
|
||||
|
||||
copyFixture.debugElement
|
||||
.query(By.css('span[title="serviceTaskName"]'))
|
||||
.triggerEventHandler('mouseenter');
|
||||
copyFixture.debugElement.query(By.css('span[title="serviceTaskName"]')).triggerEventHandler('mouseenter');
|
||||
|
||||
copyFixture.detectChanges();
|
||||
expect(copyFixture.debugElement.query(By.css('.adf-copy-tooltip'))).toBeNull();
|
||||
@@ -426,10 +415,7 @@ describe('ServiceTaskListCloudComponent: Copy cell content directive from app.co
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule]
|
||||
});
|
||||
appConfig = TestBed.inject(AppConfigService);
|
||||
serviceTaskListCloudService = TestBed.inject(ServiceTaskListCloudService);
|
||||
@@ -457,7 +443,6 @@ describe('ServiceTaskListCloudComponent: Copy cell content directive from app.co
|
||||
fixture = TestBed.createComponent(ServiceTaskListCloudComponent);
|
||||
component = fixture.componentInstance;
|
||||
taskSpy = spyOn(serviceTaskListCloudService, 'getServiceTaskByRequest').and.returnValue(of(fakeServiceTask));
|
||||
|
||||
});
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
@@ -470,8 +455,7 @@ describe('ServiceTaskListCloudComponent: Copy cell content directive from app.co
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const columnWithCopyContentFlagTrue = fixture.debugElement
|
||||
.query(By.css('span[title="04fdf69f-4ddd-48ab-9563-da776c9b163c"]'));
|
||||
const columnWithCopyContentFlagTrue = fixture.debugElement.query(By.css('span[title="04fdf69f-4ddd-48ab-9563-da776c9b163c"]'));
|
||||
|
||||
columnWithCopyContentFlagTrue.triggerEventHandler('mouseenter');
|
||||
|
||||
@@ -486,8 +470,7 @@ describe('ServiceTaskListCloudComponent: Copy cell content directive from app.co
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const columnWithCopyContentFlagNotTrue = fixture.debugElement
|
||||
.query(By.css('span[title="serviceTaskName"]'));
|
||||
const columnWithCopyContentFlagNotTrue = fixture.debugElement.query(By.css('span[title="serviceTaskName"]'));
|
||||
|
||||
columnWithCopyContentFlagNotTrue.triggerEventHandler('mouseenter');
|
||||
|
||||
|
@@ -18,7 +18,8 @@
|
||||
import { Component, SimpleChange, ViewChild } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { AppConfigService,
|
||||
import {
|
||||
AppConfigService,
|
||||
DataRowEvent,
|
||||
ObjectDataRow,
|
||||
User,
|
||||
@@ -28,7 +29,8 @@ import { AppConfigService,
|
||||
AlfrescoApiServiceMock,
|
||||
AppConfigServiceMock,
|
||||
TranslationService,
|
||||
TranslationMock } from '@alfresco/adf-core';
|
||||
TranslationMock
|
||||
} from '@alfresco/adf-core';
|
||||
import { TaskListCloudService } from '../services/task-list-cloud.service';
|
||||
import { TaskListCloudComponent } from './task-list-cloud.component';
|
||||
import { fakeGlobalTasks, fakeCustomSchema, fakeGlobalTask } from '../mock/fake-task-response.mock';
|
||||
@@ -43,16 +45,29 @@ import { TaskListCloudModule } from '../task-list-cloud.module';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<adf-cloud-task-list #taskListCloud>
|
||||
template: ` <adf-cloud-task-list #taskListCloud>
|
||||
<data-columns>
|
||||
<data-column id="name" key="name" title="ADF_CLOUD_TASK_LIST.PROPERTIES.NAME" class="adf-full-width adf-name-column" [order]="3"></data-column>
|
||||
<data-column
|
||||
id="name"
|
||||
key="name"
|
||||
title="ADF_CLOUD_TASK_LIST.PROPERTIES.NAME"
|
||||
class="adf-full-width adf-name-column"
|
||||
[order]="3"
|
||||
></data-column>
|
||||
<data-column id="created" key="created" title="ADF_CLOUD_TASK_LIST.PROPERTIES.CREATED" class="adf-hidden"></data-column>
|
||||
<data-column id="startedBy" key="startedBy" title="ADF_CLOUD_TASK_LIST.PROPERTIES.CREATED" class="adf-desktop-only dw-dt-col-3 adf-ellipsis-cell">
|
||||
<data-column
|
||||
id="startedBy"
|
||||
key="startedBy"
|
||||
title="ADF_CLOUD_TASK_LIST.PROPERTIES.CREATED"
|
||||
class="adf-desktop-only dw-dt-col-3 adf-ellipsis-cell"
|
||||
>
|
||||
<ng-template let-entry="$implicit">
|
||||
<div>{{getFullName(entry.row?.obj?.startedBy)}}</div>
|
||||
<div>{{ getFullName(entry.row?.obj?.startedBy) }}</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</data-columns>
|
||||
@@ -75,11 +90,9 @@ class CustomTaskListComponent {
|
||||
</adf-cloud-task-list>
|
||||
`
|
||||
})
|
||||
class EmptyTemplateComponent {
|
||||
}
|
||||
class EmptyTemplateComponent {}
|
||||
@Component({
|
||||
template: `
|
||||
<adf-cloud-task-list>
|
||||
template: ` <adf-cloud-task-list>
|
||||
<data-columns>
|
||||
<data-column [copyContent]="true" key="id" title="ADF_CLOUD_TASK_LIST.PROPERTIES.ID"></data-column>
|
||||
<data-column key="name" title="ADF_CLOUD_TASK_LIST.PROPERTIES.NAME"></data-column>
|
||||
@@ -92,6 +105,7 @@ class CustomCopyContentTaskListComponent {
|
||||
}
|
||||
|
||||
describe('TaskListCloudComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
let component: TaskListCloudComponent;
|
||||
let fixture: ComponentFixture<TaskListCloudComponent>;
|
||||
let appConfig: AppConfigService;
|
||||
@@ -103,10 +117,7 @@ describe('TaskListCloudComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule
|
||||
],
|
||||
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule],
|
||||
providers: [
|
||||
{
|
||||
provide: TASK_LIST_CLOUD_TOKEN,
|
||||
@@ -144,6 +155,7 @@ describe('TaskListCloudComponent', () => {
|
||||
});
|
||||
|
||||
component.isColumnSchemaCreated$ = of(true).pipe(shareReplay(1));
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -162,7 +174,7 @@ describe('TaskListCloudComponent', () => {
|
||||
expect(component.columns.length).toEqual(3);
|
||||
});
|
||||
|
||||
it('should display empty content when process list is empty', () => {
|
||||
it('should display empty content when process list is empty', async () => {
|
||||
const emptyList = { list: { entries: [] } };
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(emptyList));
|
||||
fixture.detectChanges();
|
||||
@@ -171,14 +183,13 @@ describe('TaskListCloudComponent', () => {
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
const loadingContent = fixture.debugElement.query(By.css('mat-progress-spinner'));
|
||||
expect(loadingContent).toBeFalsy();
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent.nativeElement).toBeDefined();
|
||||
});
|
||||
|
||||
it('should load spinner and show the content', () => {
|
||||
it('should load spinner and show the content', async () => {
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
|
||||
|
||||
@@ -186,8 +197,7 @@ describe('TaskListCloudComponent', () => {
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
const loadingContent = fixture.debugElement.query(By.css('mat-progress-spinner'));
|
||||
expect(loadingContent).toBeFalsy();
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent).toBeFalsy();
|
||||
@@ -374,7 +384,6 @@ describe('TaskListCloudComponent', () => {
|
||||
});
|
||||
|
||||
describe('component changes', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
component.rows = fakeGlobalTasks.list.entries;
|
||||
fixture.detectChanges();
|
||||
@@ -431,13 +440,15 @@ describe('TaskListCloudComponent', () => {
|
||||
|
||||
it('should reload task list when sorting on a column changes', () => {
|
||||
const getTaskByRequestSpy = spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
component.onSortingChanged(new CustomEvent('sorting-changed', {
|
||||
component.onSortingChanged(
|
||||
new CustomEvent('sorting-changed', {
|
||||
detail: {
|
||||
key: 'fakeName',
|
||||
direction: 'asc'
|
||||
},
|
||||
bubbles: true
|
||||
}));
|
||||
})
|
||||
);
|
||||
fixture.detectChanges();
|
||||
expect(component.sorting).toEqual([
|
||||
new TaskListCloudSortingModel({
|
||||
@@ -455,8 +466,7 @@ describe('TaskListCloudComponent', () => {
|
||||
|
||||
const size = component.size;
|
||||
const skipCount = component.skipCount;
|
||||
component.pagination.pipe(skip(3))
|
||||
.subscribe((updatedPagination) => {
|
||||
component.pagination.pipe(skip(3)).subscribe((updatedPagination) => {
|
||||
fixture.detectChanges();
|
||||
expect(component.size).toBe(size);
|
||||
expect(component.skipCount).toBe(skipCount);
|
||||
@@ -482,8 +492,7 @@ describe('TaskListCloudComponent', () => {
|
||||
maxItems: 250,
|
||||
skipCount: 200
|
||||
};
|
||||
component.pagination.pipe(skip(1))
|
||||
.subscribe((updatedPagination) => {
|
||||
component.pagination.pipe(skip(1)).subscribe((updatedPagination) => {
|
||||
fixture.detectChanges();
|
||||
expect(component.size).toBe(pagination.maxItems);
|
||||
expect(component.skipCount).toBe(pagination.skipCount);
|
||||
@@ -506,14 +515,8 @@ describe('TaskListCloudComponent: Injecting custom colums for tasklist - CustomT
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule
|
||||
],
|
||||
declarations: [
|
||||
CustomTaskListComponent,
|
||||
CustomCopyContentTaskListComponent
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule],
|
||||
declarations: [CustomTaskListComponent, CustomCopyContentTaskListComponent]
|
||||
});
|
||||
taskListCloudService = TestBed.inject(TASK_LIST_CLOUD_TOKEN);
|
||||
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTasks));
|
||||
@@ -543,9 +546,7 @@ describe('TaskListCloudComponent: Injecting custom colums for tasklist - CustomT
|
||||
customCopyComponent.taskList.reload();
|
||||
copyFixture.detectChanges();
|
||||
|
||||
copyFixture.debugElement
|
||||
.query(By.css('span[title="11fe013d-c263-11e8-b75b-0a5864600540"]'))
|
||||
.triggerEventHandler('mouseenter');
|
||||
copyFixture.debugElement.query(By.css('span[title="11fe013d-c263-11e8-b75b-0a5864600540"]')).triggerEventHandler('mouseenter');
|
||||
|
||||
copyFixture.detectChanges();
|
||||
expect(copyFixture.debugElement.query(By.css('.adf-copy-tooltip'))).not.toBeNull();
|
||||
@@ -555,9 +556,7 @@ describe('TaskListCloudComponent: Injecting custom colums for tasklist - CustomT
|
||||
customCopyComponent.taskList.reload();
|
||||
copyFixture.detectChanges();
|
||||
|
||||
copyFixture.debugElement
|
||||
.query(By.css('span[title="standalone-subtask"]'))
|
||||
.triggerEventHandler('mouseenter');
|
||||
copyFixture.debugElement.query(By.css('span[title="standalone-subtask"]')).triggerEventHandler('mouseenter');
|
||||
|
||||
copyFixture.detectChanges();
|
||||
expect(copyFixture.debugElement.query(By.css('.adf-copy-tooltip'))).toBeNull();
|
||||
@@ -570,12 +569,7 @@ describe('TaskListCloudComponent: Creating an empty custom template - EmptyTempl
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientModule,
|
||||
NoopAnimationsModule,
|
||||
TranslateModule.forRoot(),
|
||||
TaskListCloudModule
|
||||
],
|
||||
imports: [HttpClientModule, NoopAnimationsModule, TranslateModule.forRoot(), TaskListCloudModule],
|
||||
providers: [
|
||||
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
|
||||
{ provide: AppConfigService, useClass: AppConfigServiceMock },
|
||||
@@ -612,10 +606,7 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule]
|
||||
});
|
||||
appConfig = TestBed.inject(AppConfigService);
|
||||
taskListCloudService = TestBed.inject(TASK_LIST_CLOUD_TOKEN);
|
||||
@@ -663,8 +654,7 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const columnWithCopyContentFlagTrue = fixture.debugElement
|
||||
.query(By.css('span[title="11fe013d-c263-11e8-b75b-0a5864600540"]'));
|
||||
const columnWithCopyContentFlagTrue = fixture.debugElement.query(By.css('span[title="11fe013d-c263-11e8-b75b-0a5864600540"]'));
|
||||
|
||||
columnWithCopyContentFlagTrue.triggerEventHandler('mouseenter');
|
||||
|
||||
@@ -679,8 +669,7 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
|
||||
component.reload();
|
||||
fixture.detectChanges();
|
||||
|
||||
const cell = fixture.debugElement
|
||||
.query(By.css('[data-automation-id="text_ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.NONE"]'));
|
||||
const cell = fixture.debugElement.query(By.css('[data-automation-id="text_ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.NONE"]'));
|
||||
expect(cell.nativeElement.textContent).toEqual('ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.NONE');
|
||||
});
|
||||
|
||||
@@ -695,15 +684,20 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
|
||||
|
||||
const emptyContent = fixture.debugElement.query(By.css('.adf-empty-content'));
|
||||
expect(emptyContent.nativeElement).toBeDefined();
|
||||
expect(component.replacePriorityValues({
|
||||
expect(
|
||||
component.replacePriorityValues(
|
||||
{
|
||||
obj: {},
|
||||
isSelected: false,
|
||||
hasValue: () => false,
|
||||
getValue: () => undefined
|
||||
}, {
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
key: 'priority'
|
||||
})).toEqual(undefined);
|
||||
}
|
||||
)
|
||||
).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('replacePriorityValues should return replaced value when rows are defined', () => {
|
||||
@@ -714,17 +708,21 @@ describe('TaskListCloudComponent: Copy cell content directive from app.config sp
|
||||
component.ngOnChanges({ appName });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.replacePriorityValues({
|
||||
expect(
|
||||
component.replacePriorityValues(
|
||||
{
|
||||
obj: {
|
||||
priority: 1
|
||||
},
|
||||
isSelected: false,
|
||||
hasValue: () => false,
|
||||
getValue: () => undefined
|
||||
}, {
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
key: 'priority'
|
||||
})).toEqual('ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.LOW');
|
||||
}
|
||||
)
|
||||
).toEqual('ADF_CLOUD_TASK_LIST.PROPERTIES.PRIORITY_VALUES.LOW');
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -35,7 +35,7 @@
|
||||
|
||||
<ng-container *ngIf="isLoading(); else empty">
|
||||
<div class="adf-app-list-spinner">
|
||||
<mat-spinner></mat-spinner>
|
||||
<mat-progress-spinner mode="indeterminate"></mat-progress-spinner>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
|
@@ -20,15 +20,17 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { AppsProcessService } from './services/apps-process.service';
|
||||
import { of, throwError } from 'rxjs';
|
||||
|
||||
import { defaultApp, deployedApps, nonDeployedApps } from '../mock/apps-list.mock';
|
||||
import { AppsListComponent, APP_LIST_LAYOUT_GRID, APP_LIST_LAYOUT_LIST } from './apps-list.component';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AppDefinitionRepresentationModel } from '../task-list';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
|
||||
|
||||
describe('AppsListComponent', () => {
|
||||
|
||||
let loader: HarnessLoader;
|
||||
let component: AppsListComponent;
|
||||
let fixture: ComponentFixture<AppsListComponent>;
|
||||
let debugElement: DebugElement;
|
||||
@@ -44,15 +46,11 @@ describe('AppsListComponent', () => {
|
||||
</adf-apps>
|
||||
`
|
||||
})
|
||||
class CustomEmptyAppListTemplateComponent {
|
||||
}
|
||||
class CustomEmptyAppListTemplateComponent {}
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessTestingModule
|
||||
],
|
||||
imports: [TranslateModule.forRoot(), ProcessTestingModule],
|
||||
declarations: [CustomEmptyAppListTemplateComponent]
|
||||
});
|
||||
fixture = TestBed.createComponent(AppsListComponent);
|
||||
@@ -61,6 +59,7 @@ describe('AppsListComponent', () => {
|
||||
|
||||
service = TestBed.inject(AppsProcessService);
|
||||
getAppsSpy = spyOn(service, 'getDeployedApplications').and.returnValue(of(deployedApps));
|
||||
loader = TestbedHarnessEnvironment.documentRootLoader(fixture);
|
||||
});
|
||||
|
||||
it('should define layoutType with the default value', () => {
|
||||
@@ -79,17 +78,16 @@ describe('AppsListComponent', () => {
|
||||
});
|
||||
|
||||
it('should show the loading spinner when the apps are loading', async () => {
|
||||
component.loading = true;
|
||||
spyOn(component, 'isLoading').and.returnValue(true);
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const loadingSpinner = fixture.nativeElement.querySelector('mat-progress-spinner');
|
||||
expect(loadingSpinner).toBeDefined();
|
||||
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(true);
|
||||
});
|
||||
|
||||
it('should show the apps filtered by defaultAppId', () => {
|
||||
component.filtersAppId = [{defaultAppId: 'fake-app-1'}];
|
||||
component.filtersAppId = [{ defaultAppId: 'fake-app-1' }];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
@@ -97,7 +95,7 @@ describe('AppsListComponent', () => {
|
||||
});
|
||||
|
||||
it('should show the apps filtered by deploymentId', () => {
|
||||
component.filtersAppId = [{deploymentId: '4'}];
|
||||
component.filtersAppId = [{ deploymentId: '4' }];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
@@ -106,7 +104,7 @@ describe('AppsListComponent', () => {
|
||||
});
|
||||
|
||||
it('should show the apps filtered by name', () => {
|
||||
component.filtersAppId = [{name: 'App5'}];
|
||||
component.filtersAppId = [{ name: 'App5' }];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
@@ -115,7 +113,7 @@ describe('AppsListComponent', () => {
|
||||
});
|
||||
|
||||
it('should show the apps filtered by id', () => {
|
||||
component.filtersAppId = [{id: 6}];
|
||||
component.filtersAppId = [{ id: 6 }];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
@@ -124,7 +122,7 @@ describe('AppsListComponent', () => {
|
||||
});
|
||||
|
||||
it('should show the apps filtered by modelId', () => {
|
||||
component.filtersAppId = [{modelId: 66}];
|
||||
component.filtersAppId = [{ modelId: 66 }];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
@@ -133,7 +131,7 @@ describe('AppsListComponent', () => {
|
||||
});
|
||||
|
||||
it('should show the apps filtered by tenantId', () => {
|
||||
component.filtersAppId = [{tenantId: 9}];
|
||||
component.filtersAppId = [{ tenantId: 9 }];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
@@ -149,7 +147,6 @@ describe('AppsListComponent', () => {
|
||||
});
|
||||
|
||||
describe('internationalization', () => {
|
||||
|
||||
it('should provide a translation for the default application name, when app name is not provided', () => {
|
||||
const appDataMock = {
|
||||
defaultAppId: 'tasks',
|
||||
@@ -173,7 +170,6 @@ describe('AppsListComponent', () => {
|
||||
});
|
||||
|
||||
describe('layout', () => {
|
||||
|
||||
it('should display a grid by default', () => {
|
||||
fixture.detectChanges();
|
||||
expect(component.isGrid()).toBe(true);
|
||||
@@ -201,7 +197,6 @@ describe('AppsListComponent', () => {
|
||||
});
|
||||
|
||||
describe('display apps', () => {
|
||||
|
||||
it('should display all deployed apps', () => {
|
||||
getAppsSpy.and.returnValue(of(deployedApps));
|
||||
fixture.detectChanges();
|
||||
@@ -222,7 +217,6 @@ describe('AppsListComponent', () => {
|
||||
});
|
||||
|
||||
describe('select apps', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
getAppsSpy.and.returnValue(of(deployedApps));
|
||||
fixture.detectChanges();
|
||||
|
@@ -22,6 +22,7 @@ import { Observable, Observer, of, Subject } from 'rxjs';
|
||||
import { AppDefinitionRepresentationModel } from '../task-list';
|
||||
import { IconModel } from './icon.model';
|
||||
import { share, takeUntil, finalize } from 'rxjs/operators';
|
||||
import { AppDefinitionRepresentation } from '@alfresco/js-api';
|
||||
|
||||
const DEFAULT_TASKS_APP: string = 'tasks';
|
||||
const DEFAULT_TASKS_APP_NAME: string = 'ADF_TASK_LIST.APPS.TASK_APP_NAME';
|
||||
@@ -39,7 +40,6 @@ export const APP_LIST_LAYOUT_GRID: string = 'GRID';
|
||||
host: { class: 'adf-apps' }
|
||||
})
|
||||
export class AppsListComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
|
||||
@ContentChild(CustomEmptyContentTemplateDirective)
|
||||
emptyCustomContent: CustomEmptyContentTemplateDirective;
|
||||
|
||||
@@ -64,19 +64,16 @@ export class AppsListComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
|
||||
apps$: Observable<AppDefinitionRepresentationModel>;
|
||||
currentApp: AppDefinitionRepresentationModel;
|
||||
appList: AppDefinitionRepresentationModel [] = [];
|
||||
appList: AppDefinitionRepresentationModel[] = [];
|
||||
loading: boolean = false;
|
||||
hasEmptyCustomContentTemplate: boolean = false;
|
||||
|
||||
private appsObserver: Observer<AppDefinitionRepresentationModel>;
|
||||
private appsObserver: Observer<AppDefinitionRepresentation>;
|
||||
private iconsMDL: IconModel;
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(
|
||||
private appsProcessService: AppsProcessService,
|
||||
private translationService: TranslationService) {
|
||||
this.apps$ = new Observable<AppDefinitionRepresentationModel>((observer) => this.appsObserver = observer)
|
||||
.pipe(share());
|
||||
constructor(private appsProcessService: AppsProcessService, private translationService: TranslationService) {
|
||||
this.apps$ = new Observable<AppDefinitionRepresentationModel>((observer) => (this.appsObserver = observer)).pipe(share());
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -84,9 +81,7 @@ export class AppsListComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
this.setDefaultLayoutType();
|
||||
}
|
||||
|
||||
this.apps$
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe((app: any) => this.appList.push(app));
|
||||
this.apps$.pipe(takeUntil(this.onDestroy$)).subscribe((app) => this.appList.push(app));
|
||||
|
||||
this.iconsMDL = new IconModel();
|
||||
this.load();
|
||||
@@ -103,14 +98,12 @@ export class AppsListComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
isDefaultApp(app: AppDefinitionRepresentationModel) {
|
||||
isDefaultApp(app: AppDefinitionRepresentation): boolean {
|
||||
return app.defaultAppId === DEFAULT_TASKS_APP;
|
||||
}
|
||||
|
||||
getAppName(app: AppDefinitionRepresentationModel) {
|
||||
return this.isDefaultApp(app)
|
||||
? this.translationService.get(DEFAULT_TASKS_APP_NAME)
|
||||
: of(app.name);
|
||||
getAppName(app: AppDefinitionRepresentationModel): Observable<string> {
|
||||
return this.isDefaultApp(app) ? this.translationService.get(DEFAULT_TASKS_APP_NAME) : of(app.name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,7 +123,7 @@ export class AppsListComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
* @returns `true` if application is selected, otherwise `false`
|
||||
*/
|
||||
isSelected(appId: number): boolean {
|
||||
return (this.currentApp !== undefined && appId === this.currentApp.id);
|
||||
return this.currentApp !== undefined && appId === this.currentApp.id;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,9 +180,9 @@ export class AppsListComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
this.loading = true;
|
||||
this.appsProcessService
|
||||
.getDeployedApplications()
|
||||
.pipe(finalize(() => this.loading = false))
|
||||
.pipe(finalize(() => (this.loading = false)))
|
||||
.subscribe(
|
||||
(res: AppDefinitionRepresentationModel[]) => {
|
||||
(res) => {
|
||||
this.filterApps(res).forEach((app) => {
|
||||
if (this.isDefaultApp(app)) {
|
||||
app.theme = DEFAULT_TASKS_APP_THEME;
|
||||
@@ -206,24 +199,28 @@ export class AppsListComponent implements OnInit, AfterContentInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
private filterApps(apps: AppDefinitionRepresentationModel []): AppDefinitionRepresentationModel[] {
|
||||
const filteredApps: AppDefinitionRepresentationModel[] = [];
|
||||
private filterApps(apps: AppDefinitionRepresentation[]): AppDefinitionRepresentation[] {
|
||||
if (this.filtersAppId) {
|
||||
apps.filter((app: AppDefinitionRepresentationModel) => {
|
||||
const filteredApps: AppDefinitionRepresentation[] = [];
|
||||
|
||||
apps.forEach((app) => {
|
||||
this.filtersAppId.forEach((filter) => {
|
||||
if (app.defaultAppId === filter.defaultAppId ||
|
||||
if (
|
||||
app.defaultAppId === filter.defaultAppId ||
|
||||
app.deploymentId === filter.deploymentId ||
|
||||
app.name === filter.name ||
|
||||
app.id === filter.id ||
|
||||
app.modelId === filter.modelId ||
|
||||
app.tenantId === filter.tenantId) {
|
||||
app.tenantId === filter.tenantId
|
||||
) {
|
||||
filteredApps.push(app);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return apps;
|
||||
}
|
||||
|
||||
return filteredApps;
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
}
|
||||
|
@@ -22,21 +22,11 @@ import { CoreModule } from '@alfresco/adf-core';
|
||||
|
||||
import { AppsListComponent } from './apps-list.component';
|
||||
import { SelectAppsDialogComponent } from './select-apps-dialog.component';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
MaterialModule,
|
||||
CoreModule
|
||||
],
|
||||
declarations: [
|
||||
AppsListComponent,
|
||||
SelectAppsDialogComponent
|
||||
],
|
||||
exports: [
|
||||
AppsListComponent,
|
||||
SelectAppsDialogComponent
|
||||
]
|
||||
imports: [CommonModule, MaterialModule, CoreModule, MatProgressSpinnerModule],
|
||||
declarations: [AppsListComponent, SelectAppsDialogComponent],
|
||||
exports: [AppsListComponent, SelectAppsDialogComponent]
|
||||
})
|
||||
export class AppsListModule {
|
||||
}
|
||||
export class AppsListModule {}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { ProcessContentService } from '../form/services/process-content.service';
|
||||
import { RelatedContentRepresentation } from '@alfresco/js-api';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-create-process-attachment',
|
||||
@@ -40,7 +41,7 @@ export class CreateProcessAttachmentComponent implements OnChanges {
|
||||
* from within the component.
|
||||
*/
|
||||
@Output()
|
||||
success: EventEmitter<any> = new EventEmitter<any>();
|
||||
success = new EventEmitter<RelatedContentRepresentation>();
|
||||
|
||||
constructor(private activitiContentService: ProcessContentService) {}
|
||||
|
||||
|
@@ -24,7 +24,6 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ProcessContentService } from '../form/services/process-content.service';
|
||||
|
||||
describe('AttachmentComponent', () => {
|
||||
|
||||
let service: ProcessContentService;
|
||||
let component: AttachmentComponent;
|
||||
let fixture: ComponentFixture<AttachmentComponent>;
|
||||
@@ -32,30 +31,28 @@ describe('AttachmentComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessTestingModule
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), ProcessTestingModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(AttachmentComponent);
|
||||
component = fixture.componentInstance;
|
||||
service = fixture.debugElement.injector.get(ProcessContentService);
|
||||
|
||||
createTaskRelatedContentSpy = spyOn(service, 'createTaskRelatedContent').and.returnValue(of(
|
||||
{
|
||||
createTaskRelatedContentSpy = spyOn(service, 'createTaskRelatedContent').and.returnValue(
|
||||
of({
|
||||
status: true
|
||||
}));
|
||||
} as any)
|
||||
);
|
||||
});
|
||||
|
||||
it('should not call createTaskRelatedContent service when taskId changed', () => {
|
||||
const change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({taskId: change});
|
||||
component.ngOnChanges({ taskId: change });
|
||||
expect(createTaskRelatedContentSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call createTaskRelatedContent service when there is no file uploaded', () => {
|
||||
const change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({taskId: change});
|
||||
component.ngOnChanges({ taskId: change });
|
||||
const customEvent: any = {
|
||||
detail: {
|
||||
files: []
|
||||
@@ -67,13 +64,11 @@ describe('AttachmentComponent', () => {
|
||||
|
||||
it('should call createTaskRelatedContent service when there is a file uploaded', () => {
|
||||
const change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({taskId: change});
|
||||
component.ngOnChanges({ taskId: change });
|
||||
const file = new File([new Blob()], 'Test');
|
||||
const customEvent = {
|
||||
detail: {
|
||||
files: [
|
||||
file
|
||||
]
|
||||
files: [file]
|
||||
}
|
||||
};
|
||||
component.onFileUpload(customEvent);
|
||||
|
@@ -24,9 +24,12 @@ import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { mockEmittedProcessAttachments, mockProcessAttachments } from '../mock/process/process-attachments.mock';
|
||||
import { ProcessContentService } from '../form/services/process-content.service';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatMenuHarness } from '@angular/material/menu/testing';
|
||||
|
||||
describe('ProcessAttachmentListComponent', () => {
|
||||
|
||||
let loader: HarnessLoader;
|
||||
let service: ProcessContentService;
|
||||
let component: ProcessAttachmentListComponent;
|
||||
let fixture: ComponentFixture<ProcessAttachmentListComponent>;
|
||||
@@ -34,10 +37,7 @@ describe('ProcessAttachmentListComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessTestingModule
|
||||
]
|
||||
imports: [TranslateModule.forRoot(), ProcessTestingModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(ProcessAttachmentListComponent);
|
||||
component = fixture.componentInstance;
|
||||
@@ -48,6 +48,7 @@ describe('ProcessAttachmentListComponent', () => {
|
||||
|
||||
const blobObj = new Blob();
|
||||
spyOn(service, 'getFileRawContent').and.returnValue(of(blobObj));
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -101,17 +102,15 @@ describe('ProcessAttachmentListComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const actionButton = fixture.debugElement.nativeElement.querySelector('[data-automation-id="action_menu_0"]');
|
||||
actionButton.click();
|
||||
const menu = await loader.getHarness(MatMenuHarness);
|
||||
await menu.open();
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const menuItems = await menu.getItems();
|
||||
expect(menuItems.length).toBe(3);
|
||||
|
||||
const actionMenu = window.document.querySelectorAll('button.mat-menu-item').length;
|
||||
expect(window.document.querySelector('[data-automation-id="ADF_PROCESS_LIST.MENU_ACTIONS.VIEW_CONTENT"]')).not.toBeNull();
|
||||
expect(window.document.querySelector('[data-automation-id="ADF_PROCESS_LIST.MENU_ACTIONS.REMOVE_CONTENT"]')).not.toBeNull();
|
||||
expect(window.document.querySelector('[data-automation-id="ADF_PROCESS_LIST.MENU_ACTIONS.DOWNLOAD_CONTENT"]')).not.toBeNull();
|
||||
expect(actionMenu).toBe(3);
|
||||
expect(await menuItems[0].getText()).toBe('ADF_PROCESS_LIST.MENU_ACTIONS.VIEW_CONTENT');
|
||||
expect(await menuItems[1].getText()).toBe('ADF_PROCESS_LIST.MENU_ACTIONS.REMOVE_CONTENT');
|
||||
expect(await menuItems[2].getText()).toBe('ADF_PROCESS_LIST.MENU_ACTIONS.DOWNLOAD_CONTENT');
|
||||
});
|
||||
|
||||
it('should not display remove action if attachments are read only', async () => {
|
||||
@@ -122,39 +121,43 @@ describe('ProcessAttachmentListComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const actionButton = fixture.debugElement.nativeElement.querySelector('[data-automation-id="action_menu_0"]');
|
||||
actionButton.click();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const menu = await loader.getHarness(MatMenuHarness);
|
||||
await menu.open();
|
||||
|
||||
const actionMenu = window.document.querySelectorAll('button.mat-menu-item').length;
|
||||
expect(window.document.querySelector('[data-automation-id="ADF_PROCESS_LIST.MENU_ACTIONS.VIEW_CONTENT"]')).not.toBeNull();
|
||||
expect(window.document.querySelector('[data-automation-id="ADF_PROCESS_LIST.MENU_ACTIONS.DOWNLOAD_CONTENT"]')).not.toBeNull();
|
||||
expect(window.document.querySelector('[data-automation-id="ADF_PROCESS_LIST.MENU_ACTIONS.REMOVE_CONTENT"]')).toBeNull();
|
||||
expect(actionMenu).toBe(2);
|
||||
const menuItems = await menu.getItems();
|
||||
expect(menuItems.length).toBe(2);
|
||||
|
||||
expect(await menuItems[0].getText()).toBe('ADF_PROCESS_LIST.MENU_ACTIONS.VIEW_CONTENT');
|
||||
expect(await menuItems[1].getText()).toBe('ADF_PROCESS_LIST.MENU_ACTIONS.DOWNLOAD_CONTENT');
|
||||
});
|
||||
|
||||
it('should show the empty list component when the attachments list is empty', async () => {
|
||||
getProcessRelatedContentSpy.and.returnValue(of({
|
||||
getProcessRelatedContentSpy.and.returnValue(
|
||||
of({
|
||||
size: 0,
|
||||
total: 0,
|
||||
start: 0,
|
||||
data: []
|
||||
}));
|
||||
})
|
||||
);
|
||||
const change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ processInstanceId: change });
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual('ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.HEADER');
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual(
|
||||
'ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.HEADER'
|
||||
);
|
||||
});
|
||||
|
||||
it('should not show the empty list drag and drop component when is disabled', async () => {
|
||||
getProcessRelatedContentSpy.and.returnValue(of({
|
||||
getProcessRelatedContentSpy.and.returnValue(
|
||||
of({
|
||||
size: 0,
|
||||
total: 0,
|
||||
start: 0,
|
||||
data: []
|
||||
}));
|
||||
})
|
||||
);
|
||||
const change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ processInstanceId: change });
|
||||
component.disabled = true;
|
||||
@@ -162,16 +165,20 @@ describe('ProcessAttachmentListComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
expect(fixture.nativeElement.querySelector('adf-empty-list .adf-empty-list-drag_drop')).toBeNull();
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual('ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.HEADER');
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual(
|
||||
'ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.HEADER'
|
||||
);
|
||||
});
|
||||
|
||||
it('should show the empty list component when the attachments list is empty for completed process', async () => {
|
||||
getProcessRelatedContentSpy.and.returnValue(of({
|
||||
getProcessRelatedContentSpy.and.returnValue(
|
||||
of({
|
||||
size: 0,
|
||||
total: 0,
|
||||
start: 0,
|
||||
data: []
|
||||
}));
|
||||
})
|
||||
);
|
||||
const change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ processInstanceId: change });
|
||||
component.disabled = true;
|
||||
@@ -179,8 +186,9 @@ describe('ProcessAttachmentListComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim())
|
||||
.toEqual('ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.HEADER');
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual(
|
||||
'ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.HEADER'
|
||||
);
|
||||
});
|
||||
|
||||
it('should not show the empty list component when the attachments list is not empty for completed process', async () => {
|
||||
@@ -204,7 +212,6 @@ describe('ProcessAttachmentListComponent', () => {
|
||||
});
|
||||
|
||||
describe('change detection', () => {
|
||||
|
||||
const change = new SimpleChange('123', '456', true);
|
||||
const nullChange = new SimpleChange('123', null, true);
|
||||
|
||||
@@ -241,18 +248,14 @@ describe('ProcessAttachmentListComponent', () => {
|
||||
</adf-process-attachment-list>
|
||||
`
|
||||
})
|
||||
class CustomEmptyTemplateComponent {
|
||||
}
|
||||
class CustomEmptyTemplateComponent {}
|
||||
|
||||
describe('Custom CustomEmptyTemplateComponent', () => {
|
||||
let fixture: ComponentFixture<CustomEmptyTemplateComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessTestingModule
|
||||
],
|
||||
imports: [TranslateModule.forRoot(), ProcessTestingModule],
|
||||
declarations: [CustomEmptyTemplateComponent],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
});
|
||||
|
@@ -205,7 +205,7 @@ export class TaskAttachmentListComponent implements OnChanges, AfterContentInit
|
||||
this.reset();
|
||||
const isRelatedContent = 'true';
|
||||
this.activitiContentService.getTaskRelatedContent(taskId, { isRelatedContent }).subscribe(
|
||||
(res: any) => {
|
||||
(res) => {
|
||||
const attachList = [];
|
||||
res.data.forEach((content) => {
|
||||
attachList.push({
|
||||
|
@@ -15,9 +15,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AlfrescoApiService, LogService } from '@alfresco/adf-core';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivitiContentApi, RelatedContentRepresentation, ResultListDataRepresentationRelatedProcessTask } from '@alfresco/js-api';
|
||||
import {
|
||||
ActivitiContentApi,
|
||||
RelatedContentRepresentation,
|
||||
ResultListDataRepresentationRelatedProcessTask,
|
||||
ResultListDataRepresentationRelatedContentRepresentation
|
||||
} from '@alfresco/js-api';
|
||||
import { Observable, from, throwError } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
|
||||
@@ -25,7 +30,6 @@ import { catchError } from 'rxjs/operators';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ProcessContentService {
|
||||
|
||||
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
|
||||
static GENERIC_ERROR_MESSAGE: string = 'Server error';
|
||||
|
||||
@@ -35,9 +39,7 @@ export class ProcessContentService {
|
||||
return this._contentApi;
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService,
|
||||
private logService: LogService) {
|
||||
}
|
||||
constructor(private apiService: AlfrescoApiService) {}
|
||||
|
||||
/**
|
||||
* Create temporary related content from an uploaded file.
|
||||
@@ -46,8 +48,7 @@ export class ProcessContentService {
|
||||
* @returns The created content data
|
||||
*/
|
||||
createTemporaryRawRelatedContent(file: any): Observable<RelatedContentRepresentation> {
|
||||
return from(this.contentApi.createTemporaryRawRelatedContent(file))
|
||||
.pipe(catchError((err) => this.handleError(err)));
|
||||
return from(this.contentApi.createTemporaryRawRelatedContent(file)).pipe(catchError((err) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +58,7 @@ export class ProcessContentService {
|
||||
* @returns Metadata for the content
|
||||
*/
|
||||
getFileContent(contentId: number): Observable<RelatedContentRepresentation> {
|
||||
return from(this.contentApi.getContent(contentId))
|
||||
.pipe(catchError((err) => this.handleError(err)));
|
||||
return from(this.contentApi.getContent(contentId)).pipe(catchError((err) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,8 +68,7 @@ export class ProcessContentService {
|
||||
* @returns Binary data of the related content
|
||||
*/
|
||||
getFileRawContent(contentId: number): Observable<Blob> {
|
||||
return from(this.contentApi.getRawContent(contentId))
|
||||
.pipe(catchError((err) => this.handleError(err)));
|
||||
return from(this.contentApi.getRawContent(contentId)).pipe(catchError((err) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,8 +117,7 @@ export class ProcessContentService {
|
||||
* @returns Binary data of the thumbnail image
|
||||
*/
|
||||
getContentThumbnail(contentId: number): Observable<Blob> {
|
||||
return from(this.contentApi.getRawContent(contentId, 'thumbnail'))
|
||||
.pipe(catchError((err) => this.handleError(err)));
|
||||
return from(this.contentApi.getRawContent(contentId, 'thumbnail')).pipe(catchError((err) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,9 +127,8 @@ export class ProcessContentService {
|
||||
* @param opts Options supported by JS-API
|
||||
* @returns Metadata for the content
|
||||
*/
|
||||
getTaskRelatedContent(taskId: string, opts?: any): Observable<any> {
|
||||
return from(this.contentApi.getRelatedContentForTask(taskId, opts))
|
||||
.pipe(catchError((err) => this.handleError(err)));
|
||||
getTaskRelatedContent(taskId: string, opts?: any): Observable<ResultListDataRepresentationRelatedContentRepresentation> {
|
||||
return from(this.contentApi.getRelatedContentForTask(taskId, opts)).pipe(catchError((err) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,9 +138,8 @@ export class ProcessContentService {
|
||||
* @param opts Options supported by JS-API
|
||||
* @returns Metadata for the content
|
||||
*/
|
||||
getProcessRelatedContent(processId: string, opts?: any): Observable<any> {
|
||||
return from(this.contentApi.getRelatedContentForProcessInstance(processId, opts))
|
||||
.pipe(catchError((err) => this.handleError(err)));
|
||||
getProcessRelatedContent(processId: string, opts?: any): Observable<ResultListDataRepresentationRelatedContentRepresentation> {
|
||||
return from(this.contentApi.getRelatedContentForProcessInstance(processId, opts)).pipe(catchError((err) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,8 +149,7 @@ export class ProcessContentService {
|
||||
* @returns Null response that notifies when the deletion is complete
|
||||
*/
|
||||
deleteRelatedContent(contentId: number): Observable<any> {
|
||||
return from(this.contentApi.deleteContent(contentId))
|
||||
.pipe(catchError((err) => this.handleError(err)));
|
||||
return from(this.contentApi.deleteContent(contentId)).pipe(catchError((err) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,9 +160,10 @@ export class ProcessContentService {
|
||||
* @param opts Options supported by JS-API
|
||||
* @returns Details of created content
|
||||
*/
|
||||
createProcessRelatedContent(processInstanceId: string, content: any, opts?: any): Observable<any> {
|
||||
return from(this.contentApi.createRelatedContentOnProcessInstance(processInstanceId, content, opts))
|
||||
.pipe(catchError((err) => this.handleError(err)));
|
||||
createProcessRelatedContent(processInstanceId: string, content: any, opts?: any): Observable<RelatedContentRepresentation> {
|
||||
return from(this.contentApi.createRelatedContentOnProcessInstance(processInstanceId, content, opts)).pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,9 +174,8 @@ export class ProcessContentService {
|
||||
* @param opts Options supported by JS-API
|
||||
* @returns Details of created content
|
||||
*/
|
||||
createTaskRelatedContent(taskId: string, file: any, opts?: any) {
|
||||
return from(this.contentApi.createRelatedContentOnTask(taskId, file, opts))
|
||||
.pipe(catchError((err) => this.handleError(err)));
|
||||
createTaskRelatedContent(taskId: string, file: any, opts?: any): Observable<RelatedContentRepresentation> {
|
||||
return from(this.contentApi.createRelatedContentOnTask(taskId, file, opts)).pipe(catchError((err) => this.handleError(err)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,7 +187,12 @@ export class ProcessContentService {
|
||||
* @param page - page number
|
||||
* @returns Promise<ResultListDataRepresentationRelatedProcessTask>
|
||||
*/
|
||||
getProcessesAndTasksOnContent(sourceId: string, source: string, size?: number, page?: number): Observable<ResultListDataRepresentationRelatedProcessTask> {
|
||||
getProcessesAndTasksOnContent(
|
||||
sourceId: string,
|
||||
source: string,
|
||||
size?: number,
|
||||
page?: number
|
||||
): Observable<ResultListDataRepresentationRelatedProcessTask> {
|
||||
return from(this.contentApi.getProcessesAndTasksOnContent(sourceId, source, size, page)).pipe(catchError((err) => this.handleError(err)));
|
||||
}
|
||||
|
||||
@@ -231,11 +231,12 @@ export class ProcessContentService {
|
||||
handleError(error: any): Observable<any> {
|
||||
let errMsg = ProcessContentService.UNKNOWN_ERROR_MESSAGE;
|
||||
if (error) {
|
||||
errMsg = (error.message) ? error.message :
|
||||
error.status ? `${error.status} - ${error.statusText}` : ProcessContentService.GENERIC_ERROR_MESSAGE;
|
||||
errMsg = error.message
|
||||
? error.message
|
||||
: error.status
|
||||
? `${error.status} - ${error.statusText}`
|
||||
: ProcessContentService.GENERIC_ERROR_MESSAGE;
|
||||
}
|
||||
this.logService.error(errMsg);
|
||||
return throwError(errMsg);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const mockProcessAttachments = {
|
||||
export const mockProcessAttachments: any = {
|
||||
size: 2,
|
||||
total: 2,
|
||||
start: 0,
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const mockTaskAttachments = {
|
||||
export const mockTaskAttachments: any = {
|
||||
size: 2,
|
||||
total: 2,
|
||||
start: 0,
|
||||
|
Reference in New Issue
Block a user