mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-08-14 17:58:21 +00:00
[ACS-9758][ACS-9719] Refactor Folder Rules unit tests (#4709)
* [ACS-9758][ACS-9719] Refactor Folder Rules unit tests * [ACS-9758] sonar issues * [ACS-9758] fix test naming * [ACS-9758] fix test naming * [ACS-9758] cr fixes
This commit is contained in:
committed by
GitHub
parent
1b84ed7a17
commit
b7dcb3b333
@@ -23,29 +23,33 @@
|
||||
*/
|
||||
|
||||
import { isFolderRulesEnabled } from './folder-rules.rules';
|
||||
import { AcaRuleContext } from '@alfresco/aca-shared/rules';
|
||||
import { AppConfigService } from '@alfresco/adf-core';
|
||||
|
||||
describe('Folder Rules Visibility Rules', () => {
|
||||
describe('isFolderRulesEnabled', () => {
|
||||
it('should have the feature enabled', () => {
|
||||
const context: any = {
|
||||
appConfig: {
|
||||
get: () => true
|
||||
}
|
||||
};
|
||||
let mockAppConfig: jasmine.SpyObj<AppConfigService>;
|
||||
let context: Partial<AcaRuleContext>;
|
||||
|
||||
const result = isFolderRulesEnabled(context);
|
||||
expect(result).toEqual(true);
|
||||
beforeEach(() => {
|
||||
mockAppConfig = jasmine.createSpyObj<AppConfigService>('AppConfigService', ['get']);
|
||||
context = {
|
||||
appConfig: mockAppConfig
|
||||
};
|
||||
});
|
||||
|
||||
it('should have the feature disabled', () => {
|
||||
const context: any = {
|
||||
appConfig: {
|
||||
get: () => false
|
||||
}
|
||||
};
|
||||
it('should return true when plugin is enabled in app config', () => {
|
||||
mockAppConfig.get.and.returnValue(true);
|
||||
const result = isFolderRulesEnabled(context as AcaRuleContext);
|
||||
|
||||
const result = isFolderRulesEnabled(context);
|
||||
expect(result).toEqual(false);
|
||||
expect(context.appConfig.get).toHaveBeenCalledWith('plugins.folderRules', false);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when plugin is disabled in app config', () => {
|
||||
mockAppConfig.get.and.returnValue(false);
|
||||
const result = isFolderRulesEnabled(context as AcaRuleContext);
|
||||
|
||||
expect(context.appConfig.get).toHaveBeenCalledWith('plugins.folderRules', false);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@@ -22,9 +22,8 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { ManageRulesSmartComponent } from './manage-rules.smart-component';
|
||||
import { DebugElement, Predicate } from '@angular/core';
|
||||
import { FolderRulesService } from '../services/folder-rules.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { BehaviorSubject, of, Subject } from 'rxjs';
|
||||
@@ -35,32 +34,69 @@ import {
|
||||
ownedRuleSetMock,
|
||||
ruleSetWithLinkMock
|
||||
} from '../mock/rule-sets.mock';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { getOwningFolderEntryMock, owningFolderIdMock, owningFolderMock } from '../mock/node.mock';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { owningFolderIdMock, owningFolderMock } from '../mock/node.mock';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import { ActionsService } from '../services/actions.service';
|
||||
import { FolderRuleSetsService } from '../services/folder-rule-sets.service';
|
||||
import { ruleMock, ruleSettingsMock } from '../mock/rules.mock';
|
||||
import { AppService } from '@alfresco/aca-shared';
|
||||
import { AppService, GenericErrorComponent } from '@alfresco/aca-shared';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatProgressBarHarness } from '@angular/material/progress-bar/testing';
|
||||
import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
|
||||
import { provideHttpClient } from '@angular/common/http';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { EmptyContentComponent, NoopTranslateModule, NotificationService, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { Location } from '@angular/common';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { EditRuleDialogUiComponent } from '../rule-details/edit-rule-dialog.ui-component';
|
||||
import { Rule } from '../model/rule.model';
|
||||
import { RuleDetailsUiComponent } from '../rule-details/rule-details.ui-component';
|
||||
|
||||
describe('ManageRulesSmartComponent', () => {
|
||||
let fixture: ComponentFixture<ManageRulesSmartComponent>;
|
||||
let component: ManageRulesSmartComponent;
|
||||
let debugElement: DebugElement;
|
||||
let loader: HarnessLoader;
|
||||
let dialog: MatDialog;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
let folderRuleSetsService: FolderRuleSetsService;
|
||||
let folderRulesService: FolderRulesService;
|
||||
let actionsService: ActionsService;
|
||||
let callApiSpy: jasmine.Spy;
|
||||
|
||||
const setupBasicObservables = () => {
|
||||
folderRuleSetsService.folderInfo$ = of(owningFolderMock);
|
||||
folderRuleSetsService.isLoading$ = of(false);
|
||||
actionsService.loading$ = of(false);
|
||||
folderRulesService.deletedRuleId$ = of(null);
|
||||
};
|
||||
|
||||
const setupWithMainRuleSet = (ruleSet = ownedRuleSetMock) => {
|
||||
setupBasicObservables();
|
||||
folderRuleSetsService.mainRuleSet$ = of(ruleSet);
|
||||
folderRuleSetsService.inheritedRuleSets$ = of([inheritedRuleSetMock]);
|
||||
folderRulesService.selectedRule$ = of(ruleMock('owned-rule-1'));
|
||||
};
|
||||
|
||||
const setupWithoutMainRuleSet = (inheritedRuleSets = [inheritedRuleSetWithEmptyRulesMock]) => {
|
||||
setupBasicObservables();
|
||||
folderRuleSetsService.mainRuleSet$ = of(null);
|
||||
folderRuleSetsService.inheritedRuleSets$ = of(inheritedRuleSets);
|
||||
folderRulesService.selectedRule$ = of(ruleMock('owned-rule-1'));
|
||||
};
|
||||
|
||||
const setupLoadingState = () => {
|
||||
folderRuleSetsService.folderInfo$ = of(null);
|
||||
folderRuleSetsService.mainRuleSet$ = of(null);
|
||||
folderRuleSetsService.inheritedRuleSets$ = of([]);
|
||||
folderRuleSetsService.isLoading$ = of(true);
|
||||
actionsService.loading$ = of(true);
|
||||
};
|
||||
|
||||
const getRules = (): DebugElement[] => unitTestingUtils.getAllByCSS('.aca-rule-list-item');
|
||||
const getRuleSets = (): DebugElement[] => unitTestingUtils.getAllByCSS(`[data-automation-id="rule-set-list-item"]`);
|
||||
const getRuleDetails = (): DebugElement => unitTestingUtils.getByDirective(RuleDetailsUiComponent);
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -81,9 +117,10 @@ describe('ManageRulesSmartComponent', () => {
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(ManageRulesSmartComponent);
|
||||
dialog = TestBed.inject(MatDialog);
|
||||
component = fixture.componentInstance;
|
||||
debugElement = fixture.debugElement;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
|
||||
folderRuleSetsService = TestBed.inject(FolderRuleSetsService);
|
||||
folderRulesService = TestBed.inject(FolderRulesService);
|
||||
@@ -91,85 +128,84 @@ describe('ManageRulesSmartComponent', () => {
|
||||
|
||||
spyOn(actionsService, 'loadActionDefinitions').and.stub();
|
||||
spyOn(folderRulesService, 'getRuleSettings').and.returnValue(Promise.resolve(ruleSettingsMock));
|
||||
callApiSpy = spyOn<any>(folderRuleSetsService, 'callApi');
|
||||
callApiSpy
|
||||
.withArgs(`/nodes/${owningFolderIdMock}/rule-sets?include=isLinkedTo,owningFolder,linkedToBy&skipCount=0&maxItems=100`, 'GET')
|
||||
.and.returnValue(Promise.resolve(ownedRuleSetMock))
|
||||
.withArgs(`/nodes/${owningFolderIdMock}/rule-sets/-default-?include=isLinkedTo,owningFolder,linkedToBy`, 'GET')
|
||||
.and.returnValue(Promise.resolve(ownedRuleSetMock))
|
||||
.withArgs(`/nodes/${owningFolderIdMock}?include=path%2Cproperties%2CallowableOperations%2Cpermissions`, 'GET')
|
||||
.and.returnValue(Promise.resolve(getOwningFolderEntryMock));
|
||||
spyOn(folderRuleSetsService, 'loadRuleSets');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should call location.back() when goBack is called', () => {
|
||||
const locationService = TestBed.inject(Location);
|
||||
spyOn(locationService, 'back');
|
||||
component.goBack();
|
||||
|
||||
expect(locationService.back).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call folderRulesService.selectRule with provided rule on rule select', () => {
|
||||
const testRule = ruleMock('test-rule-1');
|
||||
spyOn(folderRulesService, 'selectRule');
|
||||
|
||||
component.onSelectRule(testRule);
|
||||
|
||||
expect(folderRulesService.selectRule).toHaveBeenCalledWith(testRule);
|
||||
});
|
||||
|
||||
it('should call loadMoreInheritedRuleSets on load more rule sets', () => {
|
||||
spyOn(folderRuleSetsService, 'loadMoreInheritedRuleSets');
|
||||
component.onLoadMoreRuleSets();
|
||||
expect(folderRuleSetsService.loadMoreInheritedRuleSets).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should load rules for the given rule set', () => {
|
||||
spyOn(folderRulesService, 'loadRules');
|
||||
const ruleSet = inheritedRuleSetMock;
|
||||
component.onLoadMoreRules(ruleSet);
|
||||
expect(folderRulesService.loadRules).toHaveBeenCalledWith(ruleSet);
|
||||
});
|
||||
|
||||
it('should show a list of rule sets and rules', () => {
|
||||
const loadRuleSetsSpy = spyOn(folderRuleSetsService, 'loadRuleSets').and.stub();
|
||||
|
||||
folderRuleSetsService.folderInfo$ = of(owningFolderMock);
|
||||
folderRuleSetsService.mainRuleSet$ = of(ownedRuleSetMock);
|
||||
folderRuleSetsService.inheritedRuleSets$ = of([inheritedRuleSetMock]);
|
||||
folderRuleSetsService.isLoading$ = of(false);
|
||||
folderRulesService.selectedRule$ = of(ruleMock('owned-rule-1'));
|
||||
actionsService.loading$ = of(false);
|
||||
|
||||
setupWithMainRuleSet();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component).toBeTruthy();
|
||||
expect(folderRuleSetsService.loadRuleSets).toHaveBeenCalledOnceWith(component.nodeId);
|
||||
|
||||
expect(loadRuleSetsSpy).toHaveBeenCalledOnceWith(component.nodeId);
|
||||
const ruleGroupingSections = unitTestingUtils.getAllByCSS(`[data-automation-id="rule-list-item"]`);
|
||||
|
||||
const ruleGroupingSections = debugElement.queryAll(By.css(`[data-automation-id="rule-list-item"]`));
|
||||
const rules = debugElement.queryAll(By.css('.aca-rule-list-item'));
|
||||
const ruleDetails = debugElement.query(By.css('aca-rule-details'));
|
||||
const deleteRuleBtn = debugElement.query(By.css('#delete-rule-btn'));
|
||||
const deleteRuleBtn = unitTestingUtils.getByCSS('#delete-rule-btn');
|
||||
|
||||
expect(ruleGroupingSections.length).toBe(2, 'unexpected number of rule sections');
|
||||
expect(rules.length).toBe(4, 'unexpected number of aca-rule-list-item');
|
||||
expect(ruleDetails).toBeTruthy('aca-rule-details was not rendered');
|
||||
expect(getRules().length).toBe(4, 'unexpected number of aca-rule-list-item');
|
||||
expect(getRuleDetails()).toBeTruthy('aca-rule-details was not rendered');
|
||||
expect(deleteRuleBtn).toBeTruthy('no delete rule button');
|
||||
});
|
||||
|
||||
it('should show adf-empty-content if node has no rules defined yet', () => {
|
||||
folderRuleSetsService.folderInfo$ = of(owningFolderMock);
|
||||
folderRuleSetsService.mainRuleSet$ = of(null);
|
||||
folderRuleSetsService.inheritedRuleSets$ = of([inheritedRuleSetWithEmptyRulesMock]);
|
||||
folderRuleSetsService.isLoading$ = of(false);
|
||||
actionsService.loading$ = of(false);
|
||||
|
||||
setupWithoutMainRuleSet();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component).toBeTruthy();
|
||||
|
||||
const adfEmptyContent = debugElement.query(By.css('adf-empty-content'));
|
||||
const ruleSets = debugElement.queryAll(By.css(`[data-automation-id="rule-set-list-item"]`));
|
||||
const ruleDetails = debugElement.query(By.css('aca-rule-details'));
|
||||
const adfEmptyContent = unitTestingUtils.getByDirective(EmptyContentComponent);
|
||||
|
||||
expect(adfEmptyContent).toBeTruthy();
|
||||
expect(ruleSets.length).toBe(0);
|
||||
expect(ruleDetails).toBeFalsy();
|
||||
expect(getRuleSets().length).toBe(0);
|
||||
expect(getRuleDetails()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should show adf-empty-content if there are only inherited disabled rules', () => {
|
||||
folderRuleSetsService.folderInfo$ = of(owningFolderMock);
|
||||
folderRuleSetsService.mainRuleSet$ = of(null);
|
||||
folderRuleSetsService.inheritedRuleSets$ = of([inheritedRuleSetWithOnlyDisabledRulesMock]);
|
||||
folderRuleSetsService.isLoading$ = of(false);
|
||||
actionsService.loading$ = of(false);
|
||||
|
||||
setupWithoutMainRuleSet([inheritedRuleSetWithOnlyDisabledRulesMock]);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component).toBeTruthy();
|
||||
|
||||
const adfEmptyContent = debugElement.query(By.css('adf-empty-content'));
|
||||
const ruleSets = debugElement.queryAll(By.css(`[data-automation-id="rule-set-list-item"]`));
|
||||
const ruleDetails = debugElement.query(By.css('aca-rule-details'));
|
||||
const adfEmptyContent = unitTestingUtils.getByDirective(EmptyContentComponent);
|
||||
|
||||
expect(adfEmptyContent).toBeTruthy();
|
||||
expect(ruleSets.length).toBe(0);
|
||||
expect(ruleDetails).toBeFalsy();
|
||||
expect(getRuleSets().length).toBe(0);
|
||||
expect(getRuleDetails()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should only show aca-generic-error if the non-existing node was provided', () => {
|
||||
@@ -183,129 +219,203 @@ describe('ManageRulesSmartComponent', () => {
|
||||
|
||||
expect(component).toBeTruthy();
|
||||
|
||||
const acaGenericError = debugElement.query(By.css('aca-generic-error'));
|
||||
const rules = debugElement.query(By.css('.aca-rule-list-item'));
|
||||
const ruleDetails = debugElement.query(By.css('aca-rule-details'));
|
||||
const acaGenericError = unitTestingUtils.getByDirective(GenericErrorComponent);
|
||||
|
||||
expect(acaGenericError).toBeTruthy();
|
||||
expect(rules).toBeFalsy();
|
||||
expect(ruleDetails).toBeFalsy();
|
||||
expect(getRules().length).toBeFalsy();
|
||||
expect(getRuleDetails()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should only show progress bar while loading', async () => {
|
||||
folderRuleSetsService.folderInfo$ = of(null);
|
||||
folderRuleSetsService.mainRuleSet$ = of(null);
|
||||
folderRuleSetsService.inheritedRuleSets$ = of([]);
|
||||
folderRuleSetsService.isLoading$ = of(true);
|
||||
actionsService.loading$ = of(true);
|
||||
|
||||
setupLoadingState();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component).toBeTruthy();
|
||||
|
||||
const matProgressBar = loader.getHarness(MatProgressBarHarness);
|
||||
const rules = debugElement.query(By.css('.aca-rule-list-item'));
|
||||
const ruleDetails = debugElement.query(By.css('aca-rule-details'));
|
||||
|
||||
expect(matProgressBar).toBeTruthy();
|
||||
expect(rules).toBeFalsy();
|
||||
expect(ruleDetails).toBeFalsy();
|
||||
expect(getRules().length).toBeFalsy();
|
||||
expect(getRuleDetails()).toBeFalsy();
|
||||
});
|
||||
|
||||
// TODO: [ACS-9719] flaky test that needs review
|
||||
// eslint-disable-next-line ban/ban
|
||||
xit('should call deleteRule() if confirmation dialog returns true', () => {
|
||||
const dialog = TestBed.inject(MatDialog);
|
||||
folderRuleSetsService.folderInfo$ = of(owningFolderMock);
|
||||
folderRuleSetsService.mainRuleSet$ = of(ownedRuleSetMock);
|
||||
folderRuleSetsService.inheritedRuleSets$ = of([inheritedRuleSetMock]);
|
||||
folderRuleSetsService.isLoading$ = of(false);
|
||||
folderRulesService.selectedRule$ = of(ruleMock('owned-rule-1'));
|
||||
folderRulesService.deletedRuleId$ = of(null);
|
||||
actionsService.loading$ = of(false);
|
||||
it('should call deleteRule() if confirmation dialog returns true', () => {
|
||||
setupWithMainRuleSet();
|
||||
fixture.detectChanges();
|
||||
|
||||
const onRuleDeleteButtonClickedSpy = spyOn(component, 'onRuleDeleteButtonClicked').and.callThrough();
|
||||
|
||||
const dialogResult: any = {
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => of(true)
|
||||
};
|
||||
const dialogOpenSpy = spyOn(dialog, 'open').and.returnValue(dialogResult);
|
||||
} as MatDialogRef<boolean>);
|
||||
const deleteRuleSpy = spyOn(folderRulesService, 'deleteRule');
|
||||
const onRuleDeleteSpy = spyOn(component, 'onRuleDelete').and.callThrough();
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(component).toBeTruthy('expected component');
|
||||
|
||||
const rules = debugElement.queryAll(By.css('.aca-rule-list-item'));
|
||||
const ruleDetails = debugElement.query(By.css('aca-rule-details'));
|
||||
const deleteRuleBtn = fixture.debugElement.nativeElement.querySelector('#delete-rule-btn');
|
||||
|
||||
deleteRuleBtn.click();
|
||||
component.onRuleDeleteButtonClicked(ruleMock('owned-rule-1'));
|
||||
|
||||
fixture.detectChanges();
|
||||
folderRulesService.deletedRuleId$ = of('owned-rule-1-id');
|
||||
|
||||
expect(onRuleDeleteButtonClickedSpy).toHaveBeenCalled();
|
||||
expect(dialogOpenSpy).toHaveBeenCalled();
|
||||
expect(dialog.open).toHaveBeenCalled();
|
||||
expect(deleteRuleSpy).toHaveBeenCalled();
|
||||
expect(onRuleDeleteSpy).toHaveBeenCalledTimes(1);
|
||||
expect(rules).toBeTruthy('expected rules');
|
||||
expect(ruleDetails).toBeTruthy('expected ruleDetails');
|
||||
expect(deleteRuleBtn).toBeTruthy();
|
||||
expect(getRules()).toBeTruthy('expected rules');
|
||||
expect(getRuleDetails()).toBeTruthy('expected ruleDetails');
|
||||
});
|
||||
|
||||
it('should refresh main rule set when link rules dialog is closed', () => {
|
||||
setupWithMainRuleSet();
|
||||
fixture.detectChanges();
|
||||
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => of(true)
|
||||
} as MatDialogRef<boolean>);
|
||||
const refreshMainRuleSetSpy = spyOn(folderRuleSetsService, 'refreshMainRuleSet');
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(component).toBeTruthy('expected component');
|
||||
|
||||
component.openLinkRulesDialog();
|
||||
|
||||
fixture.detectChanges();
|
||||
folderRulesService.deletedRuleId$ = of('owned-rule-1-id');
|
||||
|
||||
expect(dialog.open).toHaveBeenCalled();
|
||||
expect(refreshMainRuleSetSpy).toHaveBeenCalled();
|
||||
expect(getRules()).toBeTruthy('expected rules');
|
||||
expect(getRuleDetails()).toBeTruthy('expected ruleDetails');
|
||||
});
|
||||
|
||||
it('should call deleteRuleSetLink when onRuleSetUnlinkClicked is called', () => {
|
||||
setupWithMainRuleSet();
|
||||
fixture.detectChanges();
|
||||
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed: () => of(true)
|
||||
} as MatDialogRef<boolean>);
|
||||
const deleteRuleSetLinkSpy = spyOn(folderRuleSetsService, 'deleteRuleSetLink');
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(component).toBeTruthy('expected component');
|
||||
|
||||
component.onRuleSetUnlinkClicked(ruleSetWithLinkMock);
|
||||
|
||||
fixture.detectChanges();
|
||||
folderRulesService.deletedRuleId$ = of('owned-rule-1-id');
|
||||
|
||||
expect(dialog.open).toHaveBeenCalled();
|
||||
expect(deleteRuleSetLinkSpy).toHaveBeenCalled();
|
||||
expect(getRules()).toBeTruthy('expected rules');
|
||||
expect(getRuleDetails()).toBeTruthy('expected ruleDetails');
|
||||
});
|
||||
|
||||
describe('EditRuleDialog', () => {
|
||||
let submit$: Subject<Partial<Rule>>;
|
||||
let dialogRefMock: jasmine.SpyObj<MatDialogRef<EditRuleDialogUiComponent, boolean>>;
|
||||
|
||||
beforeEach(() => {
|
||||
submit$ = new Subject<Partial<Rule>>();
|
||||
dialogRefMock = jasmine.createSpyObj<MatDialogRef<EditRuleDialogUiComponent, boolean>>('MatDialogRef', ['close', 'afterClosed']);
|
||||
dialogRefMock.afterClosed.and.returnValue(of(true));
|
||||
dialogRefMock.componentInstance = { submitted: submit$ } as EditRuleDialogUiComponent;
|
||||
spyOn(dialog, 'open').and.returnValue(dialogRefMock as MatDialogRef<EditRuleDialogUiComponent, boolean>);
|
||||
});
|
||||
|
||||
it('should open EditRuleDialogUiComponent with correct config', () => {
|
||||
const model = { name: 'bar' } as Rule;
|
||||
component.openCreateUpdateRuleDialog(model);
|
||||
|
||||
expect(dialog.open).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create a new rule and close dialog when submitted without id', async () => {
|
||||
const newRuleParams = { name: 'NewRule' } as Rule;
|
||||
const createdRule = ruleMock('new-id');
|
||||
spyOn(folderRulesService, 'createRule').and.returnValue(Promise.resolve(createdRule));
|
||||
const addOrUpdateSpy = spyOn(folderRuleSetsService, 'addOrUpdateRuleInMainRuleSet');
|
||||
|
||||
component.openCreateUpdateRuleDialog();
|
||||
submit$.next(newRuleParams);
|
||||
await Promise.resolve();
|
||||
|
||||
expect(folderRulesService.createRule).toHaveBeenCalledWith(component.nodeId, newRuleParams);
|
||||
expect(addOrUpdateSpy).toHaveBeenCalledWith(createdRule);
|
||||
});
|
||||
|
||||
it('should update existing rule when submitted with id', async () => {
|
||||
const updatedRuleParams = { id: '123', name: 'Test' } as Rule;
|
||||
const updatedRule = ruleMock('123');
|
||||
spyOn(folderRulesService, 'updateRule').and.returnValue(Promise.resolve(updatedRule));
|
||||
const addOrUpdateSpy = spyOn(folderRuleSetsService, 'addOrUpdateRuleInMainRuleSet');
|
||||
|
||||
component.openCreateUpdateRuleDialog();
|
||||
submit$.next(updatedRuleParams);
|
||||
await Promise.resolve();
|
||||
|
||||
expect(folderRulesService.updateRule).toHaveBeenCalled();
|
||||
expect(addOrUpdateSpy).toHaveBeenCalledWith(updatedRule);
|
||||
});
|
||||
|
||||
it('should show error notification if submission fails', fakeAsync(() => {
|
||||
const notificationService = TestBed.inject(NotificationService);
|
||||
const params = { name: 'Bad' } as Rule;
|
||||
const error = new Error('Test error');
|
||||
(error as any).response = { body: { error: { errorKey: 'ERROR_KEY' } } };
|
||||
spyOn(folderRulesService, 'createRule').and.returnValue(Promise.reject(error));
|
||||
spyOn(notificationService, 'showError');
|
||||
|
||||
component.openCreateUpdateRuleDialog();
|
||||
submit$.next(params);
|
||||
tick();
|
||||
|
||||
expect(notificationService.showError).toHaveBeenCalledWith('ERROR_KEY');
|
||||
expect(dialogRefMock.close).not.toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('Create rule & link rules buttons visibility', () => {
|
||||
let createButtonPredicate: Predicate<DebugElement>;
|
||||
let linkButtonPredicate: Predicate<DebugElement>;
|
||||
const getCreateButton = (): DebugElement => unitTestingUtils.getByDataAutomationId('manage-rules-create-button');
|
||||
const getLinkButton = (): DebugElement => unitTestingUtils.getByDataAutomationId('manage-rules-link-button');
|
||||
|
||||
beforeEach(() => {
|
||||
folderRuleSetsService.folderInfo$ = of(owningFolderMock);
|
||||
folderRuleSetsService.inheritedRuleSets$ = of([]);
|
||||
folderRuleSetsService.isLoading$ = of(false);
|
||||
actionsService.loading$ = of(false);
|
||||
|
||||
createButtonPredicate = By.css(`[data-automation-id="manage-rules-create-button"]`);
|
||||
linkButtonPredicate = By.css(`[data-automation-id="manage-rules-link-button"]`);
|
||||
});
|
||||
|
||||
it('should show the create rule button if there is no main rule set', () => {
|
||||
folderRuleSetsService.mainRuleSet$ = of(null);
|
||||
fixture.detectChanges();
|
||||
|
||||
const createButton = debugElement.query(createButtonPredicate);
|
||||
expect(createButton).toBeTruthy();
|
||||
expect(getCreateButton()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show the link rules button if there is no main rule set', () => {
|
||||
folderRuleSetsService.mainRuleSet$ = of(null);
|
||||
fixture.detectChanges();
|
||||
|
||||
const linkButton = debugElement.query(linkButtonPredicate);
|
||||
expect(linkButton).toBeTruthy();
|
||||
expect(getLinkButton()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show the create rule button if the main rule set is owned', () => {
|
||||
folderRuleSetsService.mainRuleSet$ = of(ownedRuleSetMock);
|
||||
fixture.detectChanges();
|
||||
|
||||
const createButton = debugElement.query(createButtonPredicate);
|
||||
expect(createButton).toBeTruthy();
|
||||
expect(getCreateButton()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not show the create rule button if the main rule set is linked', () => {
|
||||
folderRuleSetsService.mainRuleSet$ = of(ruleSetWithLinkMock);
|
||||
fixture.detectChanges();
|
||||
|
||||
const createButton = debugElement.query(createButtonPredicate);
|
||||
expect(createButton).toBeFalsy();
|
||||
expect(getCreateButton()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not show the link rules button if the folder has a main rule set', () => {
|
||||
folderRuleSetsService.mainRuleSet$ = of(ownedRuleSetMock);
|
||||
fixture.detectChanges();
|
||||
|
||||
const linkButton = debugElement.query(linkButtonPredicate);
|
||||
expect(linkButton).toBeFalsy();
|
||||
expect(getLinkButton()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -331,22 +441,36 @@ describe('ManageRulesSmartComponent', () => {
|
||||
expect(await createButton.isDisabled()).toBeTrue();
|
||||
});
|
||||
|
||||
it('should call onInheritanceToggleChange() on change', () => {
|
||||
const onInheritanceToggleChangeSpy = spyOn(component, 'onInheritanceToggleChange').and.callThrough();
|
||||
it('should call onInheritanceToggleChange() on change', fakeAsync(() => {
|
||||
const updateRuleSettingsSpy = spyOn(folderRulesService, 'updateRuleSettings').and.returnValue(Promise.resolve(ruleSettingsMock));
|
||||
const loadRuleSetsSpy = spyOn(folderRuleSetsService, 'loadRuleSets').and.callThrough();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const inheritanceToggleBtn = fixture.debugElement.query(By.css(`[data-automation-id="manage-rules-inheritance-toggle-button"]`));
|
||||
const inheritanceToggleBtn = unitTestingUtils.getByDataAutomationId('manage-rules-inheritance-toggle-button');
|
||||
|
||||
inheritanceToggleBtn.nativeElement.dispatchEvent(new Event('change'));
|
||||
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(onInheritanceToggleChangeSpy).toHaveBeenCalled();
|
||||
expect(updateRuleSettingsSpy).toHaveBeenCalledTimes(1);
|
||||
expect(loadRuleSetsSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
expect(updateRuleSettingsSpy).toHaveBeenCalled();
|
||||
expect(folderRuleSetsService.loadRuleSets).toHaveBeenCalled();
|
||||
expect(folderRuleSetsService.loadRuleSets).toHaveBeenCalledWith(component.nodeId);
|
||||
expect(component.isInheritanceToggleDisabled).toBeFalse();
|
||||
}));
|
||||
|
||||
it('should update rule enabled state and add or update it in main rule set', fakeAsync(() => {
|
||||
const original = ruleMock('test');
|
||||
const toggled: Rule = { ...original, isEnabled: !original.isEnabled };
|
||||
spyOn(folderRulesService, 'updateRule').and.returnValue(Promise.resolve(toggled));
|
||||
const addOrUpdateSpy = spyOn(folderRuleSetsService, 'addOrUpdateRuleInMainRuleSet');
|
||||
component.nodeId = 'node-123';
|
||||
|
||||
component.onRuleEnabledToggle(original, toggled.isEnabled);
|
||||
tick();
|
||||
|
||||
expect(folderRulesService.updateRule).toHaveBeenCalledWith('node-123', original.id, { ...original, isEnabled: toggled.isEnabled });
|
||||
expect(addOrUpdateSpy).toHaveBeenCalledWith(toggled);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
@@ -31,7 +31,7 @@ import { ActivatedRoute, RouterModule } from '@angular/router';
|
||||
import { NodeInfo } from '@alfresco/aca-shared/store';
|
||||
import { delay } from 'rxjs/operators';
|
||||
import { EditRuleDialogUiComponent } from '../rule-details/edit-rule-dialog.ui-component';
|
||||
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ConfirmDialogComponent, EmptyContentComponent, NotificationService, ToolbarComponent, ToolbarTitleComponent } from '@alfresco/adf-core';
|
||||
import { ActionDefinitionTransformed } from '../model/rule-action.model';
|
||||
import { ActionsService } from '../services/actions.service';
|
||||
@@ -64,7 +64,6 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
RouterModule,
|
||||
GenericErrorComponent,
|
||||
RuleDetailsUiComponent,
|
||||
MatDialogModule,
|
||||
EmptyContentComponent,
|
||||
ToolbarTitleComponent,
|
||||
ToolbarComponent
|
||||
|
@@ -52,6 +52,7 @@ export interface RuleForForm {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
isShared: boolean;
|
||||
triggers: RuleTrigger[];
|
||||
conditions: RuleCompositeCondition;
|
||||
actions: RuleAction[];
|
||||
|
@@ -23,9 +23,8 @@
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { RuleActionListUiComponent } from './rule-action-list.ui-component';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { RuleActionUiComponent } from './rule-action.ui-component';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
|
||||
@@ -33,9 +32,10 @@ import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-conten
|
||||
describe('RuleActionListUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleActionListUiComponent>;
|
||||
let component: RuleActionListUiComponent;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
const getByDataAutomationId = (dataAutomationId: string, index = 0): DebugElement =>
|
||||
fixture.debugElement.queryAll(By.css(`[data-automation-id="${dataAutomationId}"]`))[index];
|
||||
unitTestingUtils.getAllByCSS(`[data-automation-id="${dataAutomationId}"]`)[index];
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -45,13 +45,14 @@ describe('RuleActionListUiComponent', () => {
|
||||
|
||||
fixture = TestBed.createComponent(RuleActionListUiComponent);
|
||||
component = fixture.componentInstance;
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
|
||||
component.writeValue([]);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should default to 1 empty action when an empty array of actions is written', () => {
|
||||
const acaRuleActions = fixture.debugElement.queryAll(By.directive(RuleActionUiComponent));
|
||||
const acaRuleActions = unitTestingUtils.getAllByDirective(RuleActionUiComponent);
|
||||
expect(acaRuleActions.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -60,7 +61,7 @@ describe('RuleActionListUiComponent', () => {
|
||||
addActionButton.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
const acaRuleActions = fixture.debugElement.queryAll(By.directive(RuleActionUiComponent));
|
||||
const acaRuleActions = unitTestingUtils.getAllByDirective(RuleActionUiComponent);
|
||||
expect(acaRuleActions.length).toBe(2);
|
||||
});
|
||||
|
||||
@@ -99,7 +100,7 @@ describe('RuleActionListUiComponent', () => {
|
||||
removeActionButton.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
const acaRuleActions = fixture.debugElement.queryAll(By.directive(RuleActionUiComponent));
|
||||
const acaRuleActions = unitTestingUtils.getAllByDirective(RuleActionUiComponent);
|
||||
expect(acaRuleActions.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
@@ -23,7 +23,14 @@
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CardViewBoolItemModel, CardViewComponent, CardViewSelectItemModel, CardViewTextItemModel, NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import {
|
||||
CardViewBoolItemModel,
|
||||
CardViewComponent,
|
||||
CardViewSelectItemModel,
|
||||
CardViewTextItemModel,
|
||||
NoopTranslateModule,
|
||||
UnitTestingUtils
|
||||
} from '@alfresco/adf-core';
|
||||
import { RuleActionUiComponent } from './rule-action.ui-component';
|
||||
import {
|
||||
actionLinkToCategoryTransformedMock,
|
||||
@@ -31,20 +38,35 @@ import {
|
||||
actionsTransformedListMock,
|
||||
securityActionTransformedMock
|
||||
} from '../../mock/actions.mock';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { dummyCategoriesConstraints, dummyConstraints, dummyTagsConstraints } from '../../mock/action-parameter-constraints.mock';
|
||||
import { securityMarksResponseMock, updateNotificationMock } from '../../mock/security-marks.mock';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock, CategoryService, NodeAction, TagService } from '@alfresco/adf-content-services';
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import {
|
||||
AlfrescoApiService,
|
||||
AlfrescoApiServiceMock,
|
||||
CategoryService,
|
||||
ContentNodeSelectorComponent,
|
||||
NodeAction,
|
||||
SecurityControlsService,
|
||||
TagService
|
||||
} from '@alfresco/adf-content-services';
|
||||
import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatSelectHarness } from '@angular/material/select/testing';
|
||||
import { of, Subject } from 'rxjs';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
import { SimpleChanges } from '@angular/core';
|
||||
|
||||
describe('RuleActionUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleActionUiComponent>;
|
||||
let component: RuleActionUiComponent;
|
||||
let loader: HarnessLoader;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
let securityControlsService: SecurityControlsService;
|
||||
|
||||
const clickActionItem = () => {
|
||||
unitTestingUtils.getByCSS('.adf-textitem-action').nativeElement.click();
|
||||
};
|
||||
|
||||
const changeMatSelectValue = async (value: string) => {
|
||||
const matSelect = await loader.getHarness(MatSelectHarness);
|
||||
@@ -52,14 +74,7 @@ describe('RuleActionUiComponent', () => {
|
||||
fixture.detectChanges();
|
||||
};
|
||||
|
||||
const getPropertiesCardView = (): CardViewComponent => fixture.debugElement.query(By.directive(CardViewComponent)).componentInstance;
|
||||
|
||||
function setInputValue(value: string) {
|
||||
const input = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
input.value = value;
|
||||
input.dispatchEvent(new Event('input'));
|
||||
fixture.detectChanges();
|
||||
}
|
||||
const getPropertiesCardView = (): CardViewComponent => unitTestingUtils.getByDirective(CardViewComponent).componentInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -69,7 +84,9 @@ describe('RuleActionUiComponent', () => {
|
||||
|
||||
fixture = TestBed.createComponent(RuleActionUiComponent);
|
||||
component = fixture.componentInstance;
|
||||
securityControlsService = TestBed.inject(SecurityControlsService);
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
});
|
||||
|
||||
it('should not accept empty parameters', async () => {
|
||||
@@ -79,12 +96,12 @@ describe('RuleActionUiComponent', () => {
|
||||
|
||||
await changeMatSelectValue('mock-action-1-definition');
|
||||
|
||||
setInputValue('test');
|
||||
await unitTestingUtils.fillMatInput('test');
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(component.parameters).toEqual({ 'mock-action-parameter-boolean': false, 'mock-action-parameter-text': 'test' });
|
||||
|
||||
setInputValue('');
|
||||
await unitTestingUtils.fillMatInput('');
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(component.parameters).toEqual({ 'mock-action-parameter-boolean': false });
|
||||
@@ -119,7 +136,7 @@ describe('RuleActionUiComponent', () => {
|
||||
expect(cardView.properties[4]).toBeInstanceOf(CardViewSelectItemModel);
|
||||
|
||||
await changeMatSelectValue('mock-action-2-definition');
|
||||
expect(fixture.debugElement.query(By.directive(CardViewComponent))).toBeNull();
|
||||
expect(unitTestingUtils.getByDirective(CardViewComponent)).toBeNull();
|
||||
});
|
||||
|
||||
it('should create category-value action parameter as a text box rather than node picker', async () => {
|
||||
@@ -138,21 +155,21 @@ describe('RuleActionUiComponent', () => {
|
||||
});
|
||||
|
||||
it('should open category selector dialog on category-value action parameter clicked', async () => {
|
||||
const dialog = fixture.debugElement.injector.get(MatDialog);
|
||||
const dialog = TestBed.inject(MatDialog);
|
||||
component.actionDefinitions = [actionLinkToCategoryTransformedMock];
|
||||
component.parameterConstraints = dummyConstraints;
|
||||
spyOn(dialog, 'open');
|
||||
fixture.detectChanges();
|
||||
|
||||
await changeMatSelectValue('mock-action-3-definition');
|
||||
fixture.debugElement.query(By.css('.adf-textitem-action')).nativeElement.click();
|
||||
clickActionItem();
|
||||
|
||||
expect(dialog.open).toHaveBeenCalledTimes(1);
|
||||
expect(dialog.open['calls'].argsFor(0)[0].name).toBe('CategorySelectorDialogComponent');
|
||||
});
|
||||
|
||||
it('should open node selector dialog with correct parameters', async () => {
|
||||
const dialog = fixture.debugElement.injector.get(MatDialog);
|
||||
const dialog = TestBed.inject(MatDialog);
|
||||
component.actionDefinitions = [actionNodeTransformedMock];
|
||||
const expectedData = {
|
||||
selectionMode: 'single',
|
||||
@@ -165,7 +182,7 @@ describe('RuleActionUiComponent', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
await changeMatSelectValue('mock-action-5-definition');
|
||||
fixture.debugElement.query(By.css('.adf-textitem-action')).nativeElement.click();
|
||||
clickActionItem();
|
||||
|
||||
expect(dialog.open).toHaveBeenCalledTimes(1);
|
||||
expect(dialogSpy.calls.mostRecent().args[1].data).toEqual(expectedData);
|
||||
@@ -248,6 +265,23 @@ describe('RuleActionUiComponent', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should load security mark options when writeValue is called with securityGroupId parameter', async () => {
|
||||
component.actionDefinitions = [securityActionTransformedMock];
|
||||
spyOn(securityControlsService, 'getSecurityMark').and.returnValue(Promise.resolve(securityMarksResponseMock));
|
||||
fixture.detectChanges();
|
||||
|
||||
await changeMatSelectValue('mock-action-4-definition');
|
||||
|
||||
component.writeValue({
|
||||
actionDefinitionId: 'mock-action-4-definition',
|
||||
params: { securityGroupId: 'group-1' }
|
||||
});
|
||||
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(securityControlsService.getSecurityMark).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Security mark actions', () => {
|
||||
@@ -280,4 +314,125 @@ describe('RuleActionUiComponent', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ContentNodeSelectorComponent dialog', () => {
|
||||
let mockDialogRef: jasmine.SpyObj<MatDialogRef<ContentNodeSelectorComponent, Node[]>>;
|
||||
let dialogOpenSpy: jasmine.Spy<
|
||||
(component: typeof ContentNodeSelectorComponent, config?: MatDialogConfig) => MatDialogRef<ContentNodeSelectorComponent, Node[]>
|
||||
>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockDialogRef = jasmine.createSpyObj('MatDialogRef', ['afterClosed']);
|
||||
dialogOpenSpy = spyOn(TestBed.inject(MatDialog), 'open').and.returnValue(mockDialogRef);
|
||||
spyOn(TestBed.inject(MatDialog), 'closeAll');
|
||||
spyOn(console, 'error');
|
||||
});
|
||||
|
||||
it('should open dialog when node selector is clicked', async () => {
|
||||
component.actionDefinitions = [actionNodeTransformedMock];
|
||||
component.nodeId = 'test-folder-id';
|
||||
fixture.detectChanges();
|
||||
|
||||
await changeMatSelectValue('mock-action-5-definition');
|
||||
clickActionItem();
|
||||
|
||||
expect(dialogOpenSpy).toHaveBeenCalledWith(ContentNodeSelectorComponent, {
|
||||
data: {
|
||||
selectionMode: 'single',
|
||||
title: 'ACA_FOLDER_RULES.RULE_DETAILS.PLACEHOLDER.CHOOSE_FOLDER',
|
||||
actionName: NodeAction.CHOOSE,
|
||||
currentFolderId: 'test-folder-id',
|
||||
select: jasmine.any(Subject)
|
||||
},
|
||||
panelClass: 'adf-content-node-selector-dialog',
|
||||
width: '630px'
|
||||
});
|
||||
});
|
||||
|
||||
it('should update component when valid node is selected through dialog', async () => {
|
||||
component.actionDefinitions = [actionNodeTransformedMock];
|
||||
fixture.detectChanges();
|
||||
|
||||
await changeMatSelectValue('mock-action-5-definition');
|
||||
|
||||
component.parameters = { existingParam: 'value' };
|
||||
|
||||
clickActionItem();
|
||||
|
||||
const dialogData = dialogOpenSpy.calls.mostRecent().args[1].data;
|
||||
const selectedNode = { id: 'selected-node-123', name: 'Test Folder' } as Node;
|
||||
dialogData.select.next([selectedNode]);
|
||||
|
||||
expect(component.parameters).toEqual({
|
||||
existingParam: 'value',
|
||||
'aspect-name': 'selected-node-123'
|
||||
});
|
||||
});
|
||||
|
||||
it('should log error when dialog selection encounters error', async () => {
|
||||
component.actionDefinitions = [actionNodeTransformedMock];
|
||||
fixture.detectChanges();
|
||||
|
||||
await changeMatSelectValue('mock-action-5-definition');
|
||||
clickActionItem();
|
||||
|
||||
const dialogData = dialogOpenSpy.calls.mostRecent().args[1].data;
|
||||
const testError = new Error('Selection failed');
|
||||
dialogData.select.error(testError);
|
||||
|
||||
expect(console.error).toHaveBeenCalledWith(testError);
|
||||
});
|
||||
|
||||
it('should close all dialogs when selection completes', async () => {
|
||||
const dialogService = TestBed.inject(MatDialog);
|
||||
component.actionDefinitions = [actionNodeTransformedMock];
|
||||
fixture.detectChanges();
|
||||
|
||||
await changeMatSelectValue('mock-action-5-definition');
|
||||
clickActionItem();
|
||||
|
||||
const dialogData = dialogOpenSpy.calls.mostRecent().args[1].data;
|
||||
dialogData.select.complete();
|
||||
|
||||
expect(dialogService.closeAll).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should enable form when readOnly changes from true to false', () => {
|
||||
component.readOnly = true;
|
||||
component.form.disable();
|
||||
|
||||
const changes: SimpleChanges = {
|
||||
readOnly: {
|
||||
currentValue: false,
|
||||
previousValue: true,
|
||||
firstChange: false,
|
||||
isFirstChange: () => false
|
||||
}
|
||||
};
|
||||
|
||||
component.ngOnChanges(changes);
|
||||
|
||||
expect(component.readOnly).toBe(false);
|
||||
expect(component.form.enabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should disable form when readOnly changes from false to true', () => {
|
||||
component.readOnly = false;
|
||||
component.form.enable();
|
||||
|
||||
const changes: SimpleChanges = {
|
||||
readOnly: {
|
||||
currentValue: true,
|
||||
previousValue: false,
|
||||
firstChange: false,
|
||||
isFirstChange: () => false
|
||||
}
|
||||
};
|
||||
|
||||
component.ngOnChanges(changes);
|
||||
|
||||
expect(component.readOnly).toBe(true);
|
||||
expect(component.form.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
@@ -24,8 +24,7 @@
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RuleCompositeConditionUiComponent } from './rule-composite-condition.ui-component';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import {
|
||||
compositeConditionWithNestedGroupsMock,
|
||||
@@ -37,6 +36,10 @@ import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-conten
|
||||
|
||||
describe('RuleCompositeConditionUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleCompositeConditionUiComponent>;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
const getSimpleConditionComponents = (): DebugElement[] => unitTestingUtils.getAllByCSS(`.aca-rule-simple-condition`);
|
||||
const getCompositeConditionComponents = (): DebugElement[] => unitTestingUtils.getAllByCSS(`.aca-rule-composite-condition`);
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -45,18 +48,18 @@ describe('RuleCompositeConditionUiComponent', () => {
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(RuleCompositeConditionUiComponent);
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
});
|
||||
|
||||
describe('No conditions', () => {
|
||||
let noConditionsElement: DebugElement;
|
||||
const getNoConditionsElementInnerText = (): string => unitTestingUtils.getInnerTextByDataAutomationId('no-conditions');
|
||||
|
||||
beforeEach(() => {
|
||||
fixture.detectChanges();
|
||||
noConditionsElement = fixture.debugElement.query(By.css(`[data-automation-id="no-conditions"]`));
|
||||
});
|
||||
|
||||
it('should default to no conditions', () => {
|
||||
const rowElements = fixture.debugElement.queryAll(By.css(`.aca-rule-composite-condition__form__row`));
|
||||
const rowElements = unitTestingUtils.getAllByCSS(`.aca-rule-composite-condition__form__row`);
|
||||
|
||||
expect(rowElements.length).toBe(0);
|
||||
});
|
||||
@@ -65,14 +68,14 @@ describe('RuleCompositeConditionUiComponent', () => {
|
||||
fixture.componentInstance.childCondition = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect((noConditionsElement.nativeElement as HTMLElement).innerText.trim()).toBe('ACA_FOLDER_RULES.RULE_DETAILS.NO_CONDITIONS');
|
||||
expect(getNoConditionsElementInnerText()).toBe('ACA_FOLDER_RULES.RULE_DETAILS.NO_CONDITIONS');
|
||||
});
|
||||
|
||||
it('should show a different message if the component is not a root condition group', () => {
|
||||
fixture.componentInstance.childCondition = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect((noConditionsElement.nativeElement as HTMLElement).innerText.trim()).toBe('ACA_FOLDER_RULES.RULE_DETAILS.NO_CONDITIONS_IN_GROUP');
|
||||
expect(getNoConditionsElementInnerText()).toBe('ACA_FOLDER_RULES.RULE_DETAILS.NO_CONDITIONS_IN_GROUP');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -80,64 +83,52 @@ describe('RuleCompositeConditionUiComponent', () => {
|
||||
it('should hide the add buttons in read only mode', () => {
|
||||
fixture.componentInstance.readOnly = true;
|
||||
fixture.detectChanges();
|
||||
const actionsElement = fixture.debugElement.query(By.css(`[data-automation-id="add-actions"]`));
|
||||
|
||||
expect(actionsElement).toBeNull();
|
||||
expect(unitTestingUtils.getByDataAutomationId('add-actions')).toBeNull();
|
||||
});
|
||||
|
||||
it('should hide the more actions button on the right side of the condition', () => {
|
||||
fixture.componentInstance.writeValue(compositeConditionWithOneGroupMock);
|
||||
fixture.componentInstance.readOnly = true;
|
||||
fixture.detectChanges();
|
||||
const actionsButtonElements = fixture.debugElement.queryAll(By.css(`[data-automation-id="condition-actions-button"]`));
|
||||
|
||||
expect(actionsButtonElements.length).toBe(0);
|
||||
expect(unitTestingUtils.getAllByCSS(`[data-automation-id="condition-actions-button"]`).length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have as many simple condition components as defined in the simpleConditions array', () => {
|
||||
fixture.componentInstance.writeValue(compositeConditionWithThreeConditionMock);
|
||||
fixture.detectChanges();
|
||||
const simpleConditionComponents = fixture.debugElement.queryAll(By.css(`.aca-rule-simple-condition`));
|
||||
|
||||
expect(simpleConditionComponents.length).toBe(3);
|
||||
expect(getSimpleConditionComponents().length).toBe(3);
|
||||
});
|
||||
|
||||
it('should have as many composite condition components as defined in the compositeConditions array, including nested', () => {
|
||||
fixture.componentInstance.writeValue(compositeConditionWithNestedGroupsMock);
|
||||
fixture.detectChanges();
|
||||
const compositeConditionComponents = fixture.debugElement.queryAll(By.css(`.aca-rule-composite-condition`));
|
||||
|
||||
expect(compositeConditionComponents.length).toBe(3);
|
||||
expect(getCompositeConditionComponents().length).toBe(3);
|
||||
});
|
||||
|
||||
it('should add a simple condition component on click of add condition button', () => {
|
||||
fixture.detectChanges();
|
||||
const predicate = By.css(`.aca-rule-simple-condition`);
|
||||
const simpleConditionComponentsBeforeClick = fixture.debugElement.queryAll(predicate);
|
||||
|
||||
expect(simpleConditionComponentsBeforeClick.length).toBe(0);
|
||||
expect(getSimpleConditionComponents().length).toBe(0);
|
||||
|
||||
const addConditionButton = fixture.debugElement.query(By.css(`[data-automation-id="add-condition-button"]`));
|
||||
(addConditionButton.nativeElement as HTMLButtonElement).click();
|
||||
unitTestingUtils.clickByDataAutomationId('add-condition-button');
|
||||
fixture.detectChanges();
|
||||
const simpleConditionComponentsAfterClick = fixture.debugElement.queryAll(predicate);
|
||||
|
||||
expect(simpleConditionComponentsAfterClick.length).toBe(1);
|
||||
expect(getSimpleConditionComponents().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should add a composite condition component on click of add group button', () => {
|
||||
fixture.detectChanges();
|
||||
const predicate = By.css(`.aca-rule-composite-condition`);
|
||||
const compositeConditionComponentsBeforeClick = fixture.debugElement.queryAll(predicate);
|
||||
|
||||
expect(compositeConditionComponentsBeforeClick.length).toBe(0);
|
||||
expect(getCompositeConditionComponents().length).toBe(0);
|
||||
|
||||
const addGroupButton = fixture.debugElement.query(By.css(`[data-automation-id="add-group-button"]`));
|
||||
(addGroupButton.nativeElement as HTMLButtonElement).click();
|
||||
unitTestingUtils.clickByDataAutomationId('add-group-button');
|
||||
fixture.detectChanges();
|
||||
const compositeConditionComponentsAfterClick = fixture.debugElement.queryAll(predicate);
|
||||
|
||||
expect(compositeConditionComponentsAfterClick.length).toBe(1);
|
||||
expect(getCompositeConditionComponents().length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
@@ -24,8 +24,6 @@
|
||||
|
||||
import { ComponentFixture, discardPeriodicTasks, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { RuleSimpleConditionUiComponent } from './rule-simple-condition.ui-component';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { tagMock, mimeTypeMock, simpleConditionUnknownFieldMock, categoriesListMock } from '../../mock/conditions.mock';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock, CategoryService, TagService } from '@alfresco/adf-content-services';
|
||||
import { of } from 'rxjs';
|
||||
@@ -37,19 +35,24 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatSelectHarness } from '@angular/material/select/testing';
|
||||
import { MatAutocompleteHarness } from '@angular/material/autocomplete/testing';
|
||||
import { AlfrescoMimeType } from '@alfresco/aca-shared';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
|
||||
describe('RuleSimpleConditionUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleSimpleConditionUiComponent>;
|
||||
let categoryService: CategoryService;
|
||||
let loader: HarnessLoader;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
const fieldSelectAutomationId = 'field-select';
|
||||
const comparatorSelectAutomationId = 'comparator-select';
|
||||
const comparatorFormFieldAutomationId = 'comparator-form-field';
|
||||
const unknownFieldOptionAutomationId = 'unknown-field-option';
|
||||
const simpleConditionValueAutomationId = 'simple-condition-value-select';
|
||||
const autoCompleteInputFieldAutomationId = 'auto-complete-input-field';
|
||||
const autoCompleteSpinnerAutomationId = 'auto-complete-loading-spinner';
|
||||
const valueInputAutomationId = 'value-input';
|
||||
const folderRulesBaseLabel = 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS';
|
||||
|
||||
const getByDataAutomationId = (dataAutomationId: string): DebugElement =>
|
||||
fixture.debugElement.query(By.css(`[data-automation-id="${dataAutomationId}"]`));
|
||||
|
||||
const changeMatSelectValue = async (dataAutomationId: string, value: string) => {
|
||||
const matSelect = await loader.getHarness(MatSelectHarness.with({ selector: `[data-automation-id="${dataAutomationId}"]` }));
|
||||
await matSelect.clickOptions({ selector: `[ng-reflect-value="${value}"]` });
|
||||
@@ -62,13 +65,6 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
fixture.detectChanges();
|
||||
};
|
||||
|
||||
const setValueInInputField = (inputFieldDataAutomationId: string, value: string) => {
|
||||
const inputField = fixture.debugElement.query(By.css(`[data-automation-id="${inputFieldDataAutomationId}"]`)).nativeElement;
|
||||
inputField.value = value;
|
||||
inputField.dispatchEvent(new Event('input'));
|
||||
fixture.detectChanges();
|
||||
};
|
||||
|
||||
const expectConditionFieldsDisplayedAsOptions = async (conditionFields: RuleConditionField[]): Promise<void> => {
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
const select = await loader.getHarness(MatSelectHarness);
|
||||
@@ -90,20 +86,21 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
fixture = TestBed.createComponent(RuleSimpleConditionUiComponent);
|
||||
categoryService = TestBed.inject(CategoryService);
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
});
|
||||
|
||||
it('should default the field to the name, the comparator to equals and the value empty', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId(fieldSelectAutomationId).componentInstance.value).toBe('cm:name');
|
||||
expect(getByDataAutomationId('comparator-select').componentInstance.value).toBe('equals');
|
||||
expect(getByDataAutomationId('value-input').nativeElement.value).toBe('');
|
||||
expect(unitTestingUtils.getByDataAutomationId(fieldSelectAutomationId).componentInstance.value).toBe('cm:name');
|
||||
expect(unitTestingUtils.getByDataAutomationId(comparatorSelectAutomationId).componentInstance.value).toBe('equals');
|
||||
expect(unitTestingUtils.getByDataAutomationId(valueInputAutomationId).nativeElement.value).toBe('');
|
||||
});
|
||||
|
||||
it('should hide the comparator select box if the type of the field is mimeType', async () => {
|
||||
fixture.componentInstance.mimeTypes = [{ value: '', label: '' } as AlfrescoMimeType];
|
||||
fixture.detectChanges();
|
||||
const comparatorFormField = getByDataAutomationId('comparator-form-field').nativeElement;
|
||||
const comparatorFormField = unitTestingUtils.getByDataAutomationId(comparatorFormFieldAutomationId).nativeElement;
|
||||
|
||||
expect(fixture.componentInstance.isComparatorHidden).toBeFalsy();
|
||||
expect(getComputedStyle(comparatorFormField).display).not.toBe('none');
|
||||
@@ -116,9 +113,9 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
|
||||
it('should set the comparator to equals if the field is set to a type with different comparators', async () => {
|
||||
spyOn(fixture.componentInstance, 'onChangeField').and.callThrough();
|
||||
const comparatorSelect = await loader.getHarness(MatSelectHarness.with({ selector: '[data-automation-id="comparator-select"]' }));
|
||||
const comparatorSelect = await loader.getHarness(MatSelectHarness.with({ selector: `[data-automation-id="${comparatorSelectAutomationId}"]` }));
|
||||
|
||||
await changeMatSelectValue('comparator-select', 'contains');
|
||||
await changeMatSelectValue(comparatorSelectAutomationId, 'contains');
|
||||
expect(await comparatorSelect.getValueText()).toBe(folderRulesBaseLabel + '.CONTAINS');
|
||||
|
||||
await changeMatSelectValue(fieldSelectAutomationId, 'size');
|
||||
@@ -130,25 +127,23 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
fixture.componentInstance.writeValue(simpleConditionUnknownFieldMock);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId(fieldSelectAutomationId).componentInstance.value).toBe(simpleConditionUnknownFieldMock.field);
|
||||
const matSelect = getByDataAutomationId(fieldSelectAutomationId).nativeElement;
|
||||
expect(unitTestingUtils.getByDataAutomationId(fieldSelectAutomationId).componentInstance.value).toBe(simpleConditionUnknownFieldMock.field);
|
||||
const matSelect = unitTestingUtils.getByDataAutomationId(fieldSelectAutomationId).nativeElement;
|
||||
matSelect.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
const unknownOptionMatOption = getByDataAutomationId('unknown-field-option');
|
||||
expect(unknownOptionMatOption).not.toBeNull();
|
||||
expect((unknownOptionMatOption.nativeElement as HTMLElement).innerText.trim()).toBe(simpleConditionUnknownFieldMock.field);
|
||||
expect(unitTestingUtils.getInnerTextByDataAutomationId(unknownFieldOptionAutomationId).trim()).toBe(simpleConditionUnknownFieldMock.field);
|
||||
});
|
||||
|
||||
it('should remove the option for the unknown field as soon as another option is selected', async () => {
|
||||
fixture.componentInstance.writeValue(simpleConditionUnknownFieldMock);
|
||||
fixture.detectChanges();
|
||||
await changeMatSelectValue(fieldSelectAutomationId, 'cm:name');
|
||||
const matSelect = getByDataAutomationId(fieldSelectAutomationId).nativeElement;
|
||||
const matSelect = unitTestingUtils.getByDataAutomationId(fieldSelectAutomationId).nativeElement;
|
||||
matSelect.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
const unknownOptionMatOption = getByDataAutomationId('unknown-field-option');
|
||||
const unknownOptionMatOption = unitTestingUtils.getByDataAutomationId(unknownFieldOptionAutomationId);
|
||||
expect(unknownOptionMatOption).toBeNull();
|
||||
});
|
||||
|
||||
@@ -178,7 +173,7 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
fixture.componentInstance.onChangeField();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('simple-condition-value-select')).toBeTruthy();
|
||||
expect(unitTestingUtils.getByDataAutomationId(simpleConditionValueAutomationId)).toBeTruthy();
|
||||
expect(fixture.componentInstance.form.get('parameter').value).toEqual(mockMimeTypes[0].value);
|
||||
});
|
||||
|
||||
@@ -186,12 +181,12 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
fixture.componentInstance.writeValue(mimeTypeMock);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('simple-condition-value-select')).toBeTruthy();
|
||||
expect(unitTestingUtils.getByDataAutomationId(simpleConditionValueAutomationId)).toBeTruthy();
|
||||
|
||||
fixture.componentInstance.writeValue(tagMock);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('value-input').nativeElement.value).toBe('');
|
||||
expect(unitTestingUtils.getByDataAutomationId(valueInputAutomationId).nativeElement.value).toBe('');
|
||||
});
|
||||
|
||||
it('should show loading spinner while auto-complete options are fetched, and then remove it once it is received', fakeAsync(async () => {
|
||||
@@ -199,12 +194,12 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await changeMatSelectValue(fieldSelectAutomationId, 'category');
|
||||
tick(500);
|
||||
getByDataAutomationId('auto-complete-input-field')?.nativeElement?.click();
|
||||
let loadingSpinner = getByDataAutomationId('auto-complete-loading-spinner');
|
||||
unitTestingUtils.getByDataAutomationId(autoCompleteInputFieldAutomationId)?.nativeElement?.click();
|
||||
let loadingSpinner = unitTestingUtils.getByDataAutomationId(autoCompleteSpinnerAutomationId);
|
||||
expect(loadingSpinner).not.toBeNull();
|
||||
tick(1000);
|
||||
fixture.detectChanges();
|
||||
loadingSpinner = getByDataAutomationId('auto-complete-loading-spinner');
|
||||
loadingSpinner = unitTestingUtils.getByDataAutomationId(autoCompleteSpinnerAutomationId);
|
||||
expect(loadingSpinner).toBeNull();
|
||||
discardPeriodicTasks();
|
||||
}));
|
||||
@@ -217,7 +212,7 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
it('should hide the comparator select box if the type of the field is autoComplete', async () => {
|
||||
const autoCompleteField = 'category';
|
||||
fixture.detectChanges();
|
||||
const comparatorFormField = getByDataAutomationId('comparator-form-field').nativeElement;
|
||||
const comparatorFormField = unitTestingUtils.getByDataAutomationId(comparatorFormFieldAutomationId).nativeElement;
|
||||
|
||||
expect(fixture.componentInstance.isComparatorHidden).toBeFalsy();
|
||||
expect(getComputedStyle(comparatorFormField).display).not.toBe('none');
|
||||
@@ -230,7 +225,7 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
|
||||
it('should hide the comparator select box if the type of the field is special', async () => {
|
||||
fixture.detectChanges();
|
||||
const comparatorFormField = getByDataAutomationId('comparator-form-field').nativeElement;
|
||||
const comparatorFormField = unitTestingUtils.getByDataAutomationId(comparatorFormFieldAutomationId).nativeElement;
|
||||
|
||||
expect(fixture.componentInstance.isComparatorHidden).toBeFalsy();
|
||||
expect(getComputedStyle(comparatorFormField).display).not.toBe('none');
|
||||
@@ -245,7 +240,7 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await changeMatSelectValue(fieldSelectAutomationId, 'category');
|
||||
|
||||
expect(getByDataAutomationId('auto-complete-input-field')).toBeTruthy();
|
||||
expect(unitTestingUtils.getByDataAutomationId(autoCompleteInputFieldAutomationId)).toBeTruthy();
|
||||
expect(fixture.componentInstance.form.get('parameter').value).toEqual('');
|
||||
});
|
||||
|
||||
@@ -265,7 +260,7 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
tick(500);
|
||||
expect(categoryService.searchCategories).toHaveBeenCalledWith('');
|
||||
|
||||
setValueInInputField('auto-complete-input-field', categoryValue);
|
||||
unitTestingUtils.fillInputByDataAutomationId(autoCompleteInputFieldAutomationId, categoryValue);
|
||||
tick(500);
|
||||
expect(categoryService.searchCategories).toHaveBeenCalledWith(categoryValue);
|
||||
}));
|
||||
@@ -274,9 +269,9 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await changeMatSelectValue(fieldSelectAutomationId, 'category');
|
||||
tick(500);
|
||||
getByDataAutomationId('auto-complete-input-field')?.nativeElement?.click();
|
||||
unitTestingUtils.getByDataAutomationId(autoCompleteInputFieldAutomationId)?.nativeElement?.click();
|
||||
await changeMatAutocompleteValue(categoriesListMock.list.entries[0].entry.id);
|
||||
const displayValue = getByDataAutomationId('auto-complete-input-field')?.nativeElement?.value;
|
||||
const displayValue = unitTestingUtils.getByDataAutomationId(autoCompleteInputFieldAutomationId)?.nativeElement?.value;
|
||||
expect(displayValue).toBe('category/path/1/FakeCategory1');
|
||||
discardPeriodicTasks();
|
||||
}));
|
||||
@@ -285,7 +280,7 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await changeMatSelectValue(fieldSelectAutomationId, 'category');
|
||||
tick(500);
|
||||
const autoCompleteInputField = getByDataAutomationId('auto-complete-input-field')?.nativeElement;
|
||||
const autoCompleteInputField = unitTestingUtils.getByDataAutomationId(autoCompleteInputFieldAutomationId)?.nativeElement;
|
||||
autoCompleteInputField.value = 'FakeCat';
|
||||
autoCompleteInputField.dispatchEvent(new Event('focusout'));
|
||||
const parameterValue = fixture.componentInstance.form.get('parameter').value;
|
||||
|
@@ -24,21 +24,26 @@
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { EditRuleDialogOptions, EditRuleDialogUiComponent } from './edit-rule-dialog.ui-component';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RuleDetailsUiComponent } from './rule-details.ui-component';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { of, timer } from 'rxjs';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
|
||||
import { Rule } from '../model/rule.model';
|
||||
|
||||
describe('EditRuleDialogSmartComponent', () => {
|
||||
let fixture: ComponentFixture<EditRuleDialogUiComponent>;
|
||||
let component: EditRuleDialogUiComponent;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
const dialogRef = {
|
||||
close: jasmine.createSpy('close'),
|
||||
open: jasmine.createSpy('open')
|
||||
};
|
||||
|
||||
const getDialogSubmit = (): HTMLButtonElement => unitTestingUtils.getByDataAutomationId('edit-rule-dialog-submit').nativeElement;
|
||||
const getDialogTitle = (): HTMLDivElement => unitTestingUtils.getByDataAutomationId('edit-rule-dialog-title').nativeElement;
|
||||
|
||||
const setupBeforeEach = (dialogOptions: EditRuleDialogOptions = { actionDefinitions$: of([]), parameterConstraints$: of([]) }) => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [NoopTranslateModule, EditRuleDialogUiComponent],
|
||||
@@ -51,6 +56,8 @@ describe('EditRuleDialogSmartComponent', () => {
|
||||
|
||||
fixture = TestBed.createComponent(EditRuleDialogUiComponent);
|
||||
fixture.detectChanges();
|
||||
component = fixture.componentInstance;
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
};
|
||||
|
||||
describe('No dialog options passed / indifferent', () => {
|
||||
@@ -59,38 +66,33 @@ describe('EditRuleDialogSmartComponent', () => {
|
||||
});
|
||||
|
||||
it('should activate the submit button only when a valid state is received', async () => {
|
||||
const submitButton = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-submit"]')).nativeElement as HTMLButtonElement;
|
||||
const ruleDetails = fixture.debugElement.query(By.directive(RuleDetailsUiComponent)).componentInstance as RuleDetailsUiComponent;
|
||||
const ruleDetails = unitTestingUtils.getByDirective(RuleDetailsUiComponent).componentInstance as RuleDetailsUiComponent;
|
||||
ruleDetails.formValidationChanged.emit(true);
|
||||
|
||||
fixture.detectChanges();
|
||||
// timer needed to wait for the next tick to avoid ExpressionChangedAfterItHasBeenCheckedError
|
||||
await timer(1).toPromise();
|
||||
fixture.detectChanges();
|
||||
expect(submitButton.disabled).toBeFalsy();
|
||||
expect(getDialogSubmit().disabled).toBeFalsy();
|
||||
ruleDetails.formValidationChanged.emit(false);
|
||||
|
||||
fixture.detectChanges();
|
||||
await timer(1).toPromise();
|
||||
fixture.detectChanges();
|
||||
expect(submitButton.disabled).toBeTruthy();
|
||||
expect(getDialogSubmit().disabled).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show a "create" label in the title', () => {
|
||||
const titleElement = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-title"]')).nativeElement as HTMLDivElement;
|
||||
|
||||
expect(titleElement.innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.CREATE_TITLE');
|
||||
expect(getDialogTitle().innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.CREATE_TITLE');
|
||||
});
|
||||
|
||||
it('should show a "create" label in the submit button', () => {
|
||||
const titleElement = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-submit"]')).nativeElement as HTMLButtonElement;
|
||||
|
||||
expect(titleElement.innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.CREATE');
|
||||
expect(getDialogSubmit().innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.CREATE');
|
||||
});
|
||||
|
||||
it('should set correct title and submitLabel for create mode', () => {
|
||||
expect(fixture.componentInstance.title).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.CREATE_TITLE');
|
||||
expect(fixture.componentInstance.submitLabel).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.CREATE');
|
||||
expect(component.title).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.CREATE_TITLE');
|
||||
expect(component.submitLabel).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.CREATE');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -108,20 +110,36 @@ describe('EditRuleDialogSmartComponent', () => {
|
||||
});
|
||||
|
||||
it('should show an "update" label in the title', () => {
|
||||
const titleElement = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-title"]')).nativeElement as HTMLDivElement;
|
||||
|
||||
expect(titleElement.innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE_TITLE');
|
||||
expect(getDialogTitle().innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE_TITLE');
|
||||
});
|
||||
|
||||
it('should show an "update" label in the submit button', () => {
|
||||
const titleElement = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-submit"]')).nativeElement as HTMLButtonElement;
|
||||
|
||||
expect(titleElement.innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE');
|
||||
expect(getDialogSubmit().innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE');
|
||||
});
|
||||
|
||||
it('should set correct title and submitLabel for update mode', () => {
|
||||
expect(fixture.componentInstance.title).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE_TITLE');
|
||||
expect(fixture.componentInstance.submitLabel).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE');
|
||||
expect(component.title).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE_TITLE');
|
||||
expect(component.submitLabel).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE');
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit submitted event with form value when onSubmit is called', () => {
|
||||
setupBeforeEach();
|
||||
let emittedValue: Partial<Rule> | undefined;
|
||||
|
||||
const testFormValue: Partial<Rule> = {
|
||||
id: 'test-id',
|
||||
name: 'Test Rule',
|
||||
description: 'Test description'
|
||||
};
|
||||
|
||||
component.submitted.subscribe((value) => {
|
||||
emittedValue = value;
|
||||
});
|
||||
|
||||
component.formValue = testFormValue;
|
||||
component.onSubmit();
|
||||
|
||||
expect(emittedValue).toEqual(testFormValue);
|
||||
});
|
||||
});
|
@@ -25,8 +25,7 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { DebugElement, SimpleChange } from '@angular/core';
|
||||
import { RuleOptionsUiComponent } from './rule-options.ui-component';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { errorScriptConstraintMock } from '../../mock/actions.mock';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
@@ -37,23 +36,27 @@ describe('RuleOptionsUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleOptionsUiComponent>;
|
||||
let component: RuleOptionsUiComponent;
|
||||
let loader: HarnessLoader;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
const getByDataAutomationId = (dataAutomationId: string): DebugElement =>
|
||||
fixture.debugElement.query(By.css(`[data-automation-id="${dataAutomationId}"]`));
|
||||
const errorScriptSelectAutomationId = 'rule-option-select-errorScript';
|
||||
const asynchronousCheckboxAutomationId = 'rule-option-checkbox-asynchronous';
|
||||
|
||||
const getErrorScriptSelect = (): DebugElement => unitTestingUtils.getByDataAutomationId(errorScriptSelectAutomationId);
|
||||
const getAsynchronousCheckbox = (): DebugElement => unitTestingUtils.getByDataAutomationId(asynchronousCheckboxAutomationId);
|
||||
const getErrorScriptFormField = (): DebugElement => unitTestingUtils.getByDataAutomationId('rule-option-form-field-errorScript');
|
||||
const getInheritableCheckbox = (): DebugElement => unitTestingUtils.getByDataAutomationId('rule-option-checkbox-inheritable');
|
||||
const getDisabledCheckbox = (): DebugElement => unitTestingUtils.getByDataAutomationId('rule-option-checkbox-disabled');
|
||||
const getEnabledCheckbox = (): DebugElement => unitTestingUtils.getByDataAutomationId('rule-option-checkbox-enabled');
|
||||
|
||||
const toggleMatCheckbox = (dataAutomationId: string) => {
|
||||
(getByDataAutomationId(dataAutomationId).nativeElement as HTMLElement).querySelector('input').click();
|
||||
(unitTestingUtils.getByDataAutomationId(dataAutomationId).nativeElement as HTMLElement).querySelector('input').click();
|
||||
};
|
||||
|
||||
const testErrorScriptFormFieldVisibility = (isVisible: boolean) => {
|
||||
if (isVisible) {
|
||||
expect((getByDataAutomationId('rule-option-form-field-errorScript').nativeElement as HTMLElement).classList).not.toContain(
|
||||
'aca-hide-error-script-dropdown'
|
||||
);
|
||||
expect((getErrorScriptFormField().nativeElement as HTMLElement).classList).not.toContain('aca-hide-error-script-dropdown');
|
||||
} else {
|
||||
expect((getByDataAutomationId('rule-option-form-field-errorScript').nativeElement as HTMLElement).classList).toContain(
|
||||
'aca-hide-error-script-dropdown'
|
||||
);
|
||||
expect((getErrorScriptFormField().nativeElement as HTMLElement).classList).toContain('aca-hide-error-script-dropdown');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -66,6 +69,7 @@ describe('RuleOptionsUiComponent', () => {
|
||||
fixture = TestBed.createComponent(RuleOptionsUiComponent);
|
||||
component = fixture.componentInstance;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
|
||||
component.writeValue({
|
||||
isEnabled: true,
|
||||
@@ -78,9 +82,9 @@ describe('RuleOptionsUiComponent', () => {
|
||||
it('should be able to write to the component', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('rule-option-checkbox-asynchronous').componentInstance.checked).toBeFalsy();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-inheritable').componentInstance.checked).toBeFalsy();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-disabled').componentInstance.checked).toBeFalsy();
|
||||
expect(getAsynchronousCheckbox().componentInstance.checked).toBeFalsy();
|
||||
expect(getInheritableCheckbox().componentInstance.checked).toBeFalsy();
|
||||
expect(getDisabledCheckbox().componentInstance.checked).toBeFalsy();
|
||||
testErrorScriptFormFieldVisibility(false);
|
||||
|
||||
component.writeValue({
|
||||
@@ -91,29 +95,29 @@ describe('RuleOptionsUiComponent', () => {
|
||||
});
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('rule-option-checkbox-asynchronous').componentInstance.checked).toBeTruthy();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-inheritable').componentInstance.checked).toBeTruthy();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-disabled').componentInstance.checked).toBeTruthy();
|
||||
expect(getAsynchronousCheckbox().componentInstance.checked).toBeTruthy();
|
||||
expect(getInheritableCheckbox().componentInstance.checked).toBeTruthy();
|
||||
expect(getDisabledCheckbox().componentInstance.checked).toBeTruthy();
|
||||
testErrorScriptFormFieldVisibility(true);
|
||||
});
|
||||
|
||||
it('should enable selector when async checkbox is truthy', () => {
|
||||
fixture.detectChanges();
|
||||
toggleMatCheckbox('rule-option-checkbox-asynchronous');
|
||||
toggleMatCheckbox(asynchronousCheckboxAutomationId);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('rule-option-checkbox-asynchronous').componentInstance.checked).toBeTruthy();
|
||||
expect(getByDataAutomationId('rule-option-select-errorScript').componentInstance.disabled).toBeFalsy();
|
||||
expect(getAsynchronousCheckbox().componentInstance.checked).toBeTruthy();
|
||||
expect(getErrorScriptSelect().componentInstance.disabled).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should hide disabled checkbox and unselected checkboxes in read-only mode', () => {
|
||||
component.readOnly = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('rule-option-checkbox-asynchronous')).toBeFalsy();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-inheritable')).toBeFalsy();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-enabled')).toBeFalsy();
|
||||
expect(getByDataAutomationId('rule-option-select-errorScript')).toBeFalsy();
|
||||
expect(getAsynchronousCheckbox()).toBeFalsy();
|
||||
expect(getInheritableCheckbox()).toBeFalsy();
|
||||
expect(getEnabledCheckbox()).toBeFalsy();
|
||||
expect(getErrorScriptSelect()).toBeFalsy();
|
||||
|
||||
component.writeValue({
|
||||
isEnabled: false,
|
||||
@@ -123,10 +127,10 @@ describe('RuleOptionsUiComponent', () => {
|
||||
});
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('rule-option-checkbox-asynchronous')).toBeTruthy();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-inheritable')).toBeTruthy();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-enabled')).toBeFalsy();
|
||||
expect(getByDataAutomationId('rule-option-select-errorScript')).toBeTruthy();
|
||||
expect(getAsynchronousCheckbox()).toBeTruthy();
|
||||
expect(getInheritableCheckbox()).toBeTruthy();
|
||||
expect(getEnabledCheckbox()).toBeFalsy();
|
||||
expect(getErrorScriptSelect()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should populate the error script dropdown with scripts', async () => {
|
||||
@@ -140,7 +144,7 @@ describe('RuleOptionsUiComponent', () => {
|
||||
component.ngOnChanges({ errorScriptConstraint: {} as SimpleChange });
|
||||
fixture.detectChanges();
|
||||
|
||||
(getByDataAutomationId('rule-option-select-errorScript').nativeElement as HTMLElement).click();
|
||||
unitTestingUtils.clickByDataAutomationId(errorScriptSelectAutomationId);
|
||||
fixture.detectChanges();
|
||||
|
||||
const selection = await loader.getHarness(MatSelectHarness);
|
||||
@@ -161,7 +165,7 @@ describe('RuleOptionsUiComponent', () => {
|
||||
component.errorScriptConstraint = errorScriptConstraintMock;
|
||||
fixture.detectChanges();
|
||||
|
||||
const matFormField = fixture.debugElement.query(By.css('[data-automation-id="rule-option-form-field-errorScript"'));
|
||||
const matFormField = getErrorScriptFormField();
|
||||
fixture.detectChanges();
|
||||
expect(matFormField).not.toBeNull();
|
||||
expect(matFormField.componentInstance['floatLabel']).toBe('always');
|
||||
@@ -177,10 +181,10 @@ describe('RuleOptionsUiComponent', () => {
|
||||
});
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('rule-option-checkbox-asynchronous').componentInstance.checked).toBeTrue();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-inheritable').componentInstance.checked).toBeTrue();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-disabled').componentInstance.checked).toBeTrue();
|
||||
expect(getByDataAutomationId('rule-option-select-errorScript').componentInstance.value).toEqual('1234');
|
||||
expect(getAsynchronousCheckbox().componentInstance.checked).toBeTrue();
|
||||
expect(getInheritableCheckbox().componentInstance.checked).toBeTrue();
|
||||
expect(getDisabledCheckbox().componentInstance.checked).toBeTrue();
|
||||
expect(getErrorScriptSelect().componentInstance.value).toEqual('1234');
|
||||
|
||||
component.writeValue({
|
||||
isEnabled: false,
|
||||
@@ -190,9 +194,9 @@ describe('RuleOptionsUiComponent', () => {
|
||||
});
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('rule-option-checkbox-asynchronous').componentInstance.checked).toBeFalse();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-inheritable').componentInstance.checked).toBeTrue();
|
||||
expect(getByDataAutomationId('rule-option-checkbox-disabled').componentInstance.checked).toBeTrue();
|
||||
expect(getAsynchronousCheckbox().componentInstance.checked).toBeFalse();
|
||||
expect(getInheritableCheckbox().componentInstance.checked).toBeTrue();
|
||||
expect(getDisabledCheckbox().componentInstance.checked).toBeTrue();
|
||||
testErrorScriptFormFieldVisibility(false);
|
||||
});
|
||||
});
|
||||
|
@@ -25,21 +25,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RuleDetailsUiComponent } from './rule-details.ui-component';
|
||||
import { Rule } from '../model/rule.model';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RuleTriggersUiComponent } from './triggers/rule-triggers.ui-component';
|
||||
import { RuleOptionsUiComponent } from './options/rule-options.ui-component';
|
||||
import { RuleActionListUiComponent } from './actions/rule-action-list.ui-component';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock, CategoryService } from '@alfresco/adf-content-services';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { ActionParameterConstraint } from '../model/action-parameter-constraint.model';
|
||||
|
||||
describe('RuleDetailsUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleDetailsUiComponent>;
|
||||
let component: RuleDetailsUiComponent;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
const testValue: Partial<Rule> = {
|
||||
id: 'rule-id',
|
||||
name: 'Rule name',
|
||||
description: 'This is the description of the rule',
|
||||
isShared: false,
|
||||
triggers: ['update', 'outbound'],
|
||||
isAsynchronous: true,
|
||||
isInheritable: true,
|
||||
@@ -47,11 +49,8 @@ describe('RuleDetailsUiComponent', () => {
|
||||
errorScript: ''
|
||||
};
|
||||
|
||||
const getHtmlElement = <T>(dataAutomationId: string) =>
|
||||
fixture.debugElement.query(By.css(`[data-automation-id="${dataAutomationId}"]`))?.nativeElement as T;
|
||||
|
||||
const getComponentInstance = <T>(dataAutomationId: string) =>
|
||||
fixture.debugElement.query(By.css(`[data-automation-id="${dataAutomationId}"]`))?.componentInstance as T;
|
||||
const getHtmlElement = <T>(dataAutomationId: string): T => unitTestingUtils.getByDataAutomationId(dataAutomationId)?.nativeElement as T;
|
||||
const getComponentInstance = <T>(dataAutomationId: string): T => unitTestingUtils.getByDataAutomationId(dataAutomationId)?.componentInstance as T;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -61,6 +60,7 @@ describe('RuleDetailsUiComponent', () => {
|
||||
|
||||
fixture = TestBed.createComponent(RuleDetailsUiComponent);
|
||||
component = fixture.componentInstance;
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
});
|
||||
|
||||
it('should fill the form out with initial values', () => {
|
||||
@@ -147,8 +147,7 @@ describe('RuleDetailsUiComponent', () => {
|
||||
describe('RuleActionListUiComponent', () => {
|
||||
let categoryService: CategoryService;
|
||||
|
||||
const getRuleActionsListComponent = (): RuleActionListUiComponent =>
|
||||
fixture.debugElement.query(By.directive(RuleActionListUiComponent)).componentInstance;
|
||||
const getRuleActionsListComponent = (): RuleActionListUiComponent => unitTestingUtils.getByDirective(RuleActionListUiComponent).componentInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
categoryService = TestBed.inject(CategoryService);
|
||||
@@ -193,4 +192,25 @@ describe('RuleDetailsUiComponent', () => {
|
||||
expect(getRuleActionsListComponent().actionDefinitions).toBe(component.actionDefinitions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return description form control', () => {
|
||||
component.value = testValue;
|
||||
fixture.detectChanges();
|
||||
|
||||
const descriptionControl = component.description;
|
||||
|
||||
expect(descriptionControl.value).toBe(testValue.description);
|
||||
});
|
||||
|
||||
it('should set errorScriptConstraint when parameterConstraints contains script-ref', () => {
|
||||
const mockConstraints: ActionParameterConstraint[] = [
|
||||
{ name: 'script-ref', constraints: [] },
|
||||
{ name: 'other-constraint', constraints: [] }
|
||||
];
|
||||
|
||||
component.parameterConstraints = mockConstraints;
|
||||
component.ngOnInit();
|
||||
|
||||
expect(component.errorScriptConstraint).toBe(mockConstraints[0]);
|
||||
});
|
||||
});
|
||||
|
@@ -84,6 +84,7 @@ export class RuleDetailsUiComponent implements OnInit {
|
||||
id: newValue.id || FolderRulesService.emptyRule.id,
|
||||
name: newValue.name || FolderRulesService.emptyRule.name,
|
||||
description: newValue.description || FolderRulesService.emptyRule.description,
|
||||
isShared: newValue.isShared || FolderRulesService.emptyRule.isShared,
|
||||
triggers: newValue.triggers || FolderRulesService.emptyRule.triggers,
|
||||
conditions: newValue.conditions || FolderRulesService.emptyRule.conditions,
|
||||
actions: newValue.actions || FolderRulesService.emptyRule.actions,
|
||||
@@ -146,6 +147,7 @@ export class RuleDetailsUiComponent implements OnInit {
|
||||
id: new UntypedFormControl(this.value.id),
|
||||
name: new UntypedFormControl(this.value.name || '', Validators.required),
|
||||
description: new UntypedFormControl(this.value.description || ''),
|
||||
isShared: new UntypedFormControl(this.value.isShared || false),
|
||||
triggers: new UntypedFormControl(this.value.triggers || ['inbound'], Validators.required),
|
||||
conditions: new UntypedFormControl(
|
||||
this.value.conditions || {
|
||||
|
@@ -24,20 +24,27 @@
|
||||
|
||||
import { RuleTriggersUiComponent } from './rule-triggers.ui-component';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { DebugElement } from '@angular/core';
|
||||
|
||||
describe('RuleTriggerUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleTriggersUiComponent>;
|
||||
let component: RuleTriggersUiComponent;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
let loader: HarnessLoader;
|
||||
|
||||
const getByDataAutomationId = (dataAutomationId: string): DebugElement =>
|
||||
fixture.debugElement.query(By.css(`[data-automation-id="${dataAutomationId}"]`));
|
||||
const checkboxUpdateAutomationId = 'rule-trigger-checkbox-update';
|
||||
const checkboxInboundAutomationId = 'rule-trigger-checkbox-inbound';
|
||||
const getCheckboxInbound = (): DebugElement => unitTestingUtils.getByDataAutomationId(checkboxInboundAutomationId);
|
||||
const getCheckboxUpdate = (): DebugElement => unitTestingUtils.getByDataAutomationId(checkboxUpdateAutomationId);
|
||||
const getCheckboxOutbound = (): DebugElement => unitTestingUtils.getByDataAutomationId('rule-trigger-checkbox-outbound');
|
||||
|
||||
const toggleMatCheckbox = (dataAutomationId: string) => {
|
||||
(getByDataAutomationId(dataAutomationId).nativeElement as HTMLElement).querySelector('input').click();
|
||||
const toggleMatCheckbox = async (dataAutomationId: string) => {
|
||||
const checkbox = await unitTestingUtils.getMatCheckboxByDataAutomationId(dataAutomationId);
|
||||
await checkbox.toggle();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -48,15 +55,17 @@ describe('RuleTriggerUiComponent', () => {
|
||||
|
||||
fixture = TestBed.createComponent(RuleTriggersUiComponent);
|
||||
component = fixture.componentInstance;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
});
|
||||
|
||||
it('should default to only the inbound checkbox', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.value).toEqual(['inbound']);
|
||||
expect(getByDataAutomationId('rule-trigger-checkbox-inbound').componentInstance.checked).toBeTruthy();
|
||||
expect(getByDataAutomationId('rule-trigger-checkbox-update').componentInstance.checked).toBeFalsy();
|
||||
expect(getByDataAutomationId('rule-trigger-checkbox-outbound').componentInstance.checked).toBeFalsy();
|
||||
expect(getCheckboxInbound().componentInstance.checked).toBeTruthy();
|
||||
expect(getCheckboxUpdate().componentInstance.checked).toBeFalsy();
|
||||
expect(getCheckboxOutbound().componentInstance.checked).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should change the checked boxes when the value is written to', () => {
|
||||
@@ -65,25 +74,25 @@ describe('RuleTriggerUiComponent', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.value).toEqual(['update', 'outbound']);
|
||||
expect(getByDataAutomationId('rule-trigger-checkbox-inbound').componentInstance.checked).toBeFalsy();
|
||||
expect(getByDataAutomationId('rule-trigger-checkbox-update').componentInstance.checked).toBeTruthy();
|
||||
expect(getByDataAutomationId('rule-trigger-checkbox-outbound').componentInstance.checked).toBeTruthy();
|
||||
expect(getCheckboxInbound().componentInstance.checked).toBeFalsy();
|
||||
expect(getCheckboxUpdate().componentInstance.checked).toBeTruthy();
|
||||
expect(getCheckboxOutbound().componentInstance.checked).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update the value when a checkbox is checked', () => {
|
||||
it('should update the value when a checkbox is checked', async () => {
|
||||
const onChangeSpy = spyOn(component, 'onChange');
|
||||
fixture.detectChanges();
|
||||
toggleMatCheckbox('rule-trigger-checkbox-update');
|
||||
await toggleMatCheckbox(checkboxUpdateAutomationId);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.value).toEqual(['inbound', 'update']);
|
||||
expect(onChangeSpy).toHaveBeenCalledWith(['inbound', 'update']);
|
||||
});
|
||||
|
||||
it('should update the value when a checkbox is unchecked', () => {
|
||||
it('should update the value when a checkbox is unchecked', async () => {
|
||||
const onChangeSpy = spyOn(component, 'onChange');
|
||||
fixture.detectChanges();
|
||||
toggleMatCheckbox('rule-trigger-checkbox-inbound');
|
||||
await toggleMatCheckbox(checkboxInboundAutomationId);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.value).toEqual([]);
|
||||
@@ -95,12 +104,12 @@ describe('RuleTriggerUiComponent', () => {
|
||||
component.writeValue(['update', 'outbound']);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('rule-trigger-checkbox-inbound')).toBeNull();
|
||||
expect(getByDataAutomationId('rule-trigger-checkbox-update')).toBeNull();
|
||||
expect(getByDataAutomationId('rule-trigger-checkbox-outbound')).toBeNull();
|
||||
expect(getCheckboxInbound()).toBeNull();
|
||||
expect(getCheckboxUpdate()).toBeNull();
|
||||
expect(getCheckboxOutbound()).toBeNull();
|
||||
|
||||
expect(getByDataAutomationId('rule-trigger-value-inbound')).toBeNull();
|
||||
expect(getByDataAutomationId('rule-trigger-value-update')).not.toBeNull();
|
||||
expect(getByDataAutomationId('rule-trigger-value-outbound')).not.toBeNull();
|
||||
expect(unitTestingUtils.getByDataAutomationId('rule-trigger-value-inbound')).toBeNull();
|
||||
expect(unitTestingUtils.getByDataAutomationId('rule-trigger-value-update')).not.toBeNull();
|
||||
expect(unitTestingUtils.getByDataAutomationId('rule-trigger-value-outbound')).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
@@ -0,0 +1,80 @@
|
||||
/*!
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { FormControl, ValidatorFn } from '@angular/forms';
|
||||
import { ruleCompositeConditionValidator } from './rule-composite-condition.validator';
|
||||
import { RuleCompositeCondition } from '../../model/rule-composite-condition.model';
|
||||
|
||||
describe('ruleCompositeConditionValidator', () => {
|
||||
let validatorFn: ValidatorFn;
|
||||
|
||||
beforeEach(() => {
|
||||
validatorFn = ruleCompositeConditionValidator();
|
||||
});
|
||||
|
||||
it('should return null for root condition with empty compositeConditions and empty simpleConditions', () => {
|
||||
const mockCondition = {
|
||||
compositeConditions: [],
|
||||
simpleConditions: []
|
||||
} as RuleCompositeCondition;
|
||||
|
||||
const control = new FormControl(mockCondition);
|
||||
expect(validatorFn(control)).toBeNull();
|
||||
});
|
||||
|
||||
it('should return validation error for nested condition with empty simpleConditions and no nested compositeConditions', () => {
|
||||
const mockCondition = {
|
||||
compositeConditions: [
|
||||
{
|
||||
compositeConditions: [],
|
||||
simpleConditions: []
|
||||
}
|
||||
],
|
||||
simpleConditions: []
|
||||
} as RuleCompositeCondition;
|
||||
|
||||
const control = new FormControl(mockCondition);
|
||||
expect(validatorFn(control)).toEqual({ ruleCompositeConditionInvalid: true });
|
||||
});
|
||||
|
||||
it('should return validation error for deeply nested invalid composite conditions', () => {
|
||||
const mockCondition = {
|
||||
compositeConditions: [
|
||||
{
|
||||
compositeConditions: [
|
||||
{
|
||||
compositeConditions: [],
|
||||
simpleConditions: []
|
||||
}
|
||||
],
|
||||
simpleConditions: []
|
||||
}
|
||||
],
|
||||
simpleConditions: []
|
||||
} as RuleCompositeCondition;
|
||||
|
||||
const control = new FormControl(mockCondition);
|
||||
expect(validatorFn(control)).toEqual({ ruleCompositeConditionInvalid: true });
|
||||
});
|
||||
});
|
@@ -25,14 +25,13 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RuleListGroupingUiComponent } from './rule-list-grouping.ui-component';
|
||||
import { ruleListGroupingItemsMock, rulesMock } from '../../mock/rules.mock';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { RuleSet } from '../../model/rule-set.model';
|
||||
|
||||
describe('RuleListGroupingUiComponent', () => {
|
||||
let component: RuleListGroupingUiComponent;
|
||||
let fixture: ComponentFixture<RuleListGroupingUiComponent>;
|
||||
let debugElement: DebugElement;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -41,7 +40,7 @@ describe('RuleListGroupingUiComponent', () => {
|
||||
|
||||
fixture = TestBed.createComponent(RuleListGroupingUiComponent);
|
||||
component = fixture.componentInstance;
|
||||
debugElement = fixture.debugElement;
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
});
|
||||
|
||||
it('should display the list of rules', () => {
|
||||
@@ -51,16 +50,78 @@ describe('RuleListGroupingUiComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const rules = debugElement.queryAll(By.css('.aca-rule-list-item'));
|
||||
const rules = unitTestingUtils.getAllByCSS('.aca-rule-list-item');
|
||||
|
||||
expect(rules).toBeTruthy('Could not find rules');
|
||||
expect(rules.length).toBe(2, 'Unexpected number of rules');
|
||||
|
||||
const rule = debugElement.query(By.css('.aca-rule-list-item:first-child'));
|
||||
const name = rule.query(By.css('.aca-rule-list-item__header__name'));
|
||||
const description = rule.query(By.css('.aca-rule-list-item__description'));
|
||||
const name = unitTestingUtils.getByCSS('.aca-rule-list-item:first-child .aca-rule-list-item__header__name');
|
||||
const description = unitTestingUtils.getByCSS('.aca-rule-list-item:first-child .aca-rule-list-item__description');
|
||||
|
||||
expect(name.nativeElement.textContent).toBe(rulesMock[0].name);
|
||||
expect(description.nativeElement.textContent).toBe(rulesMock[0].description);
|
||||
});
|
||||
|
||||
it('should emit selectRule event with rule when onRuleClicked is called', () => {
|
||||
spyOn(component.selectRule, 'emit');
|
||||
const mockRule = rulesMock[0];
|
||||
|
||||
component.onRuleClicked(mockRule);
|
||||
|
||||
expect(component.selectRule.emit).toHaveBeenCalledWith(mockRule);
|
||||
});
|
||||
|
||||
it('should return true when rule is selected', () => {
|
||||
const mockRule = rulesMock[0];
|
||||
component.selectedRule = mockRule;
|
||||
|
||||
const result = component.isSelected(mockRule);
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when rule is not selected', () => {
|
||||
const [mockRule, differentRule] = rulesMock;
|
||||
component.selectedRule = mockRule;
|
||||
|
||||
const result = component.isSelected(differentRule);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when no rule is selected', () => {
|
||||
const mockRule = rulesMock[0];
|
||||
component.selectedRule = null;
|
||||
|
||||
const result = component.isSelected(mockRule);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should emit ruleEnabledChanged event with tuple when onEnabledChanged is called', () => {
|
||||
spyOn(component.ruleEnabledChanged, 'emit');
|
||||
const mockRule = rulesMock[0];
|
||||
const isEnabled = true;
|
||||
|
||||
component.onEnabledChanged(mockRule, isEnabled);
|
||||
|
||||
expect(component.ruleEnabledChanged.emit).toHaveBeenCalledWith([mockRule, isEnabled]);
|
||||
});
|
||||
|
||||
it('should emit loadMoreRules event with ruleSet when onClickLoadMoreRules is called', () => {
|
||||
spyOn(component.loadMoreRules, 'emit');
|
||||
const mockRuleSet = { id: 'test-rule-set' } as RuleSet;
|
||||
|
||||
component.onClickLoadMoreRules(mockRuleSet);
|
||||
|
||||
expect(component.loadMoreRules.emit).toHaveBeenCalledWith(mockRuleSet);
|
||||
});
|
||||
|
||||
it('should emit loadMoreRuleSets event when onClickLoadMoreRuleSets is called', () => {
|
||||
spyOn(component.loadMoreRuleSets, 'emit');
|
||||
|
||||
component.onClickLoadMoreRuleSets();
|
||||
|
||||
expect(component.loadMoreRuleSets.emit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@@ -0,0 +1,116 @@
|
||||
/*!
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RuleListItemUiComponent } from './rule-list-item.ui-component';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { Rule } from '../../model/rule.model';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing';
|
||||
|
||||
describe('RuleListItemUiComponent', () => {
|
||||
let component: RuleListItemUiComponent;
|
||||
let fixture: ComponentFixture<RuleListItemUiComponent>;
|
||||
let loader: HarnessLoader;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
const mockRule = {
|
||||
id: 'test-rule-id',
|
||||
name: 'Test Rule',
|
||||
description: 'Test rule description',
|
||||
isEnabled: true
|
||||
} as Rule;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [NoopTranslateModule, RuleListItemUiComponent]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(RuleListItemUiComponent);
|
||||
component = fixture.componentInstance;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
component.rule = mockRule;
|
||||
});
|
||||
|
||||
it('should display rule name and description', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const nameElement = unitTestingUtils.getByCSS('.aca-rule-list-item__header__name');
|
||||
const descriptionElement = unitTestingUtils.getByCSS('.aca-rule-list-item__description');
|
||||
|
||||
expect(nameElement.nativeElement.textContent.trim()).toBe(mockRule.name);
|
||||
expect(descriptionElement.nativeElement.textContent.trim()).toBe(mockRule.description);
|
||||
});
|
||||
|
||||
it('should show slide toggle when showEnabledToggle is true', async () => {
|
||||
component.showEnabledToggle = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
const toggleHarness = await loader.getHarnessOrNull(MatSlideToggleHarness);
|
||||
expect(toggleHarness).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should hide slide toggle when showEnabledToggle is false', async () => {
|
||||
component.showEnabledToggle = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
const toggleHarness = await loader.getHarnessOrNull(MatSlideToggleHarness);
|
||||
expect(toggleHarness).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should set toggle checked state based on rule.isEnabled', async () => {
|
||||
component.showEnabledToggle = true;
|
||||
component.rule.isEnabled = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
const toggleHarness = await loader.getHarness(MatSlideToggleHarness);
|
||||
expect(await toggleHarness.isChecked()).toBe(true);
|
||||
});
|
||||
|
||||
describe('onToggleClick', () => {
|
||||
it('should stop event propagation and emit enabledChanged with isEnabled value', () => {
|
||||
spyOn(component.enabledChanged, 'emit');
|
||||
const mockEvent = jasmine.createSpyObj<Event>('Event', ['stopPropagation']);
|
||||
const isEnabled = true;
|
||||
|
||||
component.onToggleClick(isEnabled, mockEvent);
|
||||
|
||||
expect(mockEvent.stopPropagation).toHaveBeenCalled();
|
||||
expect(component.enabledChanged.emit).toHaveBeenCalledWith(isEnabled);
|
||||
});
|
||||
|
||||
it('should stop event propagation and emit enabledChanged with false value', () => {
|
||||
spyOn(component.enabledChanged, 'emit');
|
||||
const mockEvent = jasmine.createSpyObj<Event>('Event', ['stopPropagation']);
|
||||
const isEnabled = false;
|
||||
|
||||
component.onToggleClick(isEnabled, mockEvent);
|
||||
|
||||
expect(mockEvent.stopPropagation).toHaveBeenCalled();
|
||||
expect(component.enabledChanged.emit).toHaveBeenCalledWith(isEnabled);
|
||||
});
|
||||
});
|
||||
});
|
@@ -24,18 +24,20 @@
|
||||
|
||||
import { RuleListUiComponent } from './rule-list.ui-component';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { ownedRuleSetMock, ruleSetsMock, ruleSetWithLinkMock } from '../../mock/rule-sets.mock';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { owningFolderIdMock } from '../../mock/node.mock';
|
||||
import { of } from 'rxjs';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
|
||||
import { Rule } from '../../model/rule.model';
|
||||
import { RuleSet } from '../../model/rule-set.model';
|
||||
|
||||
describe('RuleListUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleListUiComponent>;
|
||||
let component: RuleListUiComponent;
|
||||
let debugElement: DebugElement;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
const getMainRuleSetTitleText = (): string => unitTestingUtils.getInnerTextByDataAutomationId('main-rule-set-title');
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -45,7 +47,7 @@ describe('RuleListUiComponent', () => {
|
||||
|
||||
fixture = TestBed.createComponent(RuleListUiComponent);
|
||||
component = fixture.componentInstance;
|
||||
debugElement = fixture.debugElement;
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
|
||||
component.folderId = owningFolderIdMock;
|
||||
component.inheritedRuleSets = ruleSetsMock;
|
||||
@@ -55,15 +57,117 @@ describe('RuleListUiComponent', () => {
|
||||
component.mainRuleSet$ = of(ownedRuleSetMock);
|
||||
fixture.detectChanges();
|
||||
|
||||
const mainRuleSetTitleElement = debugElement.query(By.css(`[data-automation-id="main-rule-set-title"]`));
|
||||
expect((mainRuleSetTitleElement.nativeElement as HTMLDivElement).innerText.trim()).toBe('ACA_FOLDER_RULES.RULE_LIST.OWNED_RULES');
|
||||
expect(getMainRuleSetTitleText()).toBe('ACA_FOLDER_RULES.RULE_LIST.OWNED_RULES');
|
||||
});
|
||||
|
||||
it('should show "Rules from linked folder" as a title if the main rule set is linked', () => {
|
||||
component.mainRuleSet$ = of(ruleSetWithLinkMock);
|
||||
fixture.detectChanges();
|
||||
|
||||
const mainRuleSetTitleElement = debugElement.query(By.css(`[data-automation-id="main-rule-set-title"]`));
|
||||
expect((mainRuleSetTitleElement.nativeElement as HTMLDivElement).innerText.trim()).toBe('ACA_FOLDER_RULES.RULE_LIST.LINKED_RULES');
|
||||
expect(getMainRuleSetTitleText()).toBe('ACA_FOLDER_RULES.RULE_LIST.LINKED_RULES');
|
||||
});
|
||||
|
||||
it('should add loading item when both ruleSetsLoading and hasMoreRuleSets are true', () => {
|
||||
component.inheritedRuleSets = ruleSetsMock;
|
||||
component.mainRuleSet$ = of(ruleSetWithLinkMock);
|
||||
component.ruleSetsLoading = true;
|
||||
component.hasMoreRuleSets = true;
|
||||
|
||||
component.ngOnInit();
|
||||
|
||||
const loadingItem = component.inheritedRuleSetGroupingItems.find((item) => item.type === 'loading');
|
||||
expect(loadingItem).toBeDefined();
|
||||
expect(loadingItem.type).toBe('loading');
|
||||
|
||||
const loadMoreItem = component.inheritedRuleSetGroupingItems.find((item) => item.type === 'load-more-rule-sets');
|
||||
expect(loadMoreItem).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should add loading item when both loadingRules and hasMoreRules are true', () => {
|
||||
const ruleSetWithBothFlags: RuleSet = {
|
||||
...ownedRuleSetMock,
|
||||
loadingRules: true,
|
||||
hasMoreRules: true
|
||||
};
|
||||
|
||||
const result = component.getRuleSetGroupingItems(ruleSetWithBothFlags, false);
|
||||
|
||||
const loadingItem = result.find((item) => item.type === 'loading');
|
||||
expect(loadingItem).toBeDefined();
|
||||
expect(loadingItem.type).toBe('loading');
|
||||
|
||||
const loadMoreItem = result.find((item) => item.type === 'load-more-rules');
|
||||
expect(loadMoreItem).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not add any special items when neither loadingRules nor hasMoreRules are true', () => {
|
||||
const ruleSetWithoutFlags: RuleSet = {
|
||||
...ownedRuleSetMock,
|
||||
loadingRules: false,
|
||||
hasMoreRules: false
|
||||
};
|
||||
|
||||
const result = component.getRuleSetGroupingItems(ruleSetWithoutFlags, false);
|
||||
|
||||
const specialItems = result.filter((item) => item.type === 'loading' || item.type === 'load-more-rules');
|
||||
expect(specialItems.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should emit loadMoreRuleSets event when onLoadMoreRuleSets is called', () => {
|
||||
spyOn(component.loadMoreRuleSets, 'emit');
|
||||
|
||||
component.onLoadMoreRuleSets();
|
||||
|
||||
expect(component.loadMoreRuleSets.emit).toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
it('should emit loadMoreRules event with ruleSet when onLoadMoreRules is called', () => {
|
||||
spyOn(component.loadMoreRules, 'emit');
|
||||
const mockRuleSet = ownedRuleSetMock;
|
||||
|
||||
component.onLoadMoreRules(mockRuleSet);
|
||||
|
||||
expect(component.loadMoreRules.emit).toHaveBeenCalledWith(mockRuleSet);
|
||||
});
|
||||
|
||||
it('should emit selectRule event with rule when onSelectRule is called', () => {
|
||||
spyOn(component.selectRule, 'emit');
|
||||
const mockRule = ownedRuleSetMock.rules[0];
|
||||
|
||||
component.onSelectRule(mockRule);
|
||||
|
||||
expect(component.selectRule.emit).toHaveBeenCalledWith(mockRule);
|
||||
});
|
||||
|
||||
it('should stop event propagation and emit ruleSetEditLinkClicked with mainRuleSet when onRuleSetEditLinkClicked is called', () => {
|
||||
spyOn(component.ruleSetEditLinkClicked, 'emit');
|
||||
const mockEvent = jasmine.createSpyObj<Event>('Event', ['stopPropagation']);
|
||||
component.mainRuleSet = ownedRuleSetMock;
|
||||
|
||||
component.onRuleSetEditLinkClicked(mockEvent);
|
||||
|
||||
expect(mockEvent.stopPropagation).toHaveBeenCalled();
|
||||
expect(component.ruleSetEditLinkClicked.emit).toHaveBeenCalledWith(ownedRuleSetMock);
|
||||
});
|
||||
|
||||
it('should emit ruleEnabledChanged event with tuple when onRuleEnabledChanged is called', () => {
|
||||
spyOn(component.ruleEnabledChanged, 'emit');
|
||||
const mockRule = ownedRuleSetMock.rules[0];
|
||||
const event: [Rule, boolean] = [mockRule, true];
|
||||
|
||||
component.onRuleEnabledChanged(event);
|
||||
|
||||
expect(component.ruleEnabledChanged.emit).toHaveBeenCalledWith(event);
|
||||
});
|
||||
|
||||
it('should stop event propagation and emit ruleSetUnlinkClicked with mainRuleSet when onRuleSetUnlinkClicked is called', () => {
|
||||
spyOn(component.ruleSetUnlinkClicked, 'emit');
|
||||
const mockEvent = jasmine.createSpyObj<Event>('Event', ['stopPropagation']);
|
||||
component.mainRuleSet = ownedRuleSetMock;
|
||||
|
||||
component.onRuleSetUnlinkClicked(mockEvent);
|
||||
|
||||
expect(mockEvent.stopPropagation).toHaveBeenCalled();
|
||||
expect(component.ruleSetUnlinkClicked.emit).toHaveBeenCalledWith(ownedRuleSetMock);
|
||||
});
|
||||
});
|
||||
|
@@ -22,26 +22,44 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { RuleSetPickerOptions, RuleSetPickerSmartComponent } from './rule-set-picker.smart-component';
|
||||
import { NoopAuthModule, NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { NoopAuthModule, NoopTranslateModule, NotificationService, UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { folderToLinkMock, otherFolderMock } from '../mock/node.mock';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { FolderRuleSetsService } from '../services/folder-rule-sets.service';
|
||||
import { of } from 'rxjs';
|
||||
import { ownedRuleSetMock, ruleSetWithLinkMock, ruleSetWithNoRulesToLinkMock, ruleSetWithOwnedRulesToLinkMock } from '../mock/rule-sets.mock';
|
||||
import { ruleSetWithLinkMock, ruleSetWithNoRulesToLinkMock, ruleSetWithOwnedRulesToLinkMock } from '../mock/rule-sets.mock';
|
||||
import { ContentApiService } from '@alfresco/aca-shared';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
|
||||
import {
|
||||
AlfrescoApiService,
|
||||
AlfrescoApiServiceMock,
|
||||
ContentNodeSelectorPanelComponent,
|
||||
NodeEntryEvent,
|
||||
SitesService
|
||||
} from '@alfresco/adf-content-services';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { Component, DebugElement, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { RuleSet } from '../model/rule-set.model';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-content-node-selector-panel',
|
||||
template: '<div data-automation-id="mock-content-node-selector"></div>',
|
||||
standalone: true
|
||||
})
|
||||
class MockContentNodeSelectorPanelComponent {
|
||||
@Input() currentFolderId: string;
|
||||
@Output() folderLoaded = new EventEmitter<void>();
|
||||
@Output() navigationChange = new EventEmitter<NodeEntryEvent>();
|
||||
@Output() siteChange = new EventEmitter<string>();
|
||||
}
|
||||
|
||||
describe('RuleSetPickerSmartComponent', () => {
|
||||
let fixture: ComponentFixture<RuleSetPickerSmartComponent>;
|
||||
let component: RuleSetPickerSmartComponent;
|
||||
let folderRuleSetsService: FolderRuleSetsService;
|
||||
|
||||
let loadRuleSetsSpy: jasmine.Spy;
|
||||
let callApiSpy: jasmine.Spy;
|
||||
let sitesService: SitesService;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
const dialogRef = {
|
||||
close: jasmine.createSpy('close'),
|
||||
@@ -53,6 +71,9 @@ describe('RuleSetPickerSmartComponent', () => {
|
||||
defaultNodeId: 'folder-1-id'
|
||||
};
|
||||
|
||||
const getItems = (): DebugElement[] => unitTestingUtils.getAllByCSS('.aca-rule-set-picker__content__rule-list aca-rule-list-item');
|
||||
const getEmptyList = (): DebugElement => unitTestingUtils.getByCSS('adf-empty-content');
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [NoopTranslateModule, NoopAuthModule, RuleSetPickerSmartComponent],
|
||||
@@ -73,27 +94,37 @@ describe('RuleSetPickerSmartComponent', () => {
|
||||
}
|
||||
}
|
||||
]
|
||||
}).overrideComponent(RuleSetPickerSmartComponent, {
|
||||
remove: {
|
||||
imports: [ContentNodeSelectorPanelComponent]
|
||||
},
|
||||
add: {
|
||||
imports: [MockContentNodeSelectorPanelComponent]
|
||||
}
|
||||
});
|
||||
|
||||
folderRuleSetsService = TestBed.inject(FolderRuleSetsService);
|
||||
fixture = TestBed.createComponent(RuleSetPickerSmartComponent);
|
||||
component = fixture.componentInstance;
|
||||
sitesService = TestBed.inject(SitesService);
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
|
||||
loadRuleSetsSpy = spyOn(component.folderRuleSetsService, 'loadRuleSets').and.callThrough();
|
||||
callApiSpy = spyOn<any>(folderRuleSetsService, 'callApi');
|
||||
callApiSpy
|
||||
.withArgs(`/nodes/${dialogOptions.nodeId}/rule-sets?include=isLinkedTo,owningFolder,linkedToBy&skipCount=0&maxItems=100`, 'GET')
|
||||
.and.returnValue(Promise.resolve(ownedRuleSetMock))
|
||||
.withArgs(`/nodes/${dialogOptions.nodeId}/rule-sets/-default-?include=isLinkedTo,owningFolder,linkedToBy`, 'GET')
|
||||
.and.returnValue(Promise.resolve(ownedRuleSetMock))
|
||||
.withArgs(`/nodes/${folderToLinkMock.id}?include=path%2Cproperties%2CallowableOperations%2Cpermissions`, 'GET')
|
||||
.and.returnValue(Promise.resolve({ entry: folderToLinkMock }));
|
||||
loadRuleSetsSpy = spyOn(component.folderRuleSetsService, 'loadRuleSets');
|
||||
spyOn(sitesService, 'getSites');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should set true to rulesLoading$ when rulesLoading or folderLoading is true', (done) => {
|
||||
component.setFolderLoading(true);
|
||||
|
||||
component.rulesLoading$.subscribe((result) => {
|
||||
expect(result).toBe(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should load the rule sets of a node once it has been selected', () => {
|
||||
expect(loadRuleSetsSpy).not.toHaveBeenCalled();
|
||||
component.onNodeSelect([folderToLinkMock]);
|
||||
@@ -108,11 +139,8 @@ describe('RuleSetPickerSmartComponent', () => {
|
||||
component.onNodeSelect([folderToLinkMock]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const items = fixture.debugElement.queryAll(By.css('.aca-rule-set-picker__content__rule-list aca-rule-list-item'));
|
||||
expect(items.length).toBe(0);
|
||||
|
||||
const emptyList = fixture.debugElement.query(By.css('adf-empty-content'));
|
||||
expect(emptyList).not.toBeNull();
|
||||
expect(getItems().length).toBe(0);
|
||||
expect(getEmptyList()).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should show an empty list message if a selected folder has linked rules', () => {
|
||||
@@ -121,11 +149,8 @@ describe('RuleSetPickerSmartComponent', () => {
|
||||
component.onNodeSelect([folderToLinkMock]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const items = fixture.debugElement.queryAll(By.css('.aca-rule-set-picker__content__rule-list aca-rule-list-item'));
|
||||
expect(items.length).toBe(0);
|
||||
|
||||
const emptyList = fixture.debugElement.query(By.css('adf-empty-content'));
|
||||
expect(emptyList).not.toBeNull();
|
||||
expect(getItems().length).toBe(0);
|
||||
expect(getEmptyList()).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should show a list of items if a selected folder has owned rules', () => {
|
||||
@@ -134,10 +159,62 @@ describe('RuleSetPickerSmartComponent', () => {
|
||||
component.onNodeSelect([folderToLinkMock]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const items = fixture.debugElement.queryAll(By.css('.aca-rule-set-picker__content__rule-list aca-rule-list-item'));
|
||||
expect(items.length).toBe(2);
|
||||
expect(getItems().length).toBe(2);
|
||||
expect(getEmptyList()).toBeNull();
|
||||
});
|
||||
|
||||
const emptyList = fixture.debugElement.query(By.css('adf-empty-content'));
|
||||
expect(emptyList).toBeNull();
|
||||
describe('onSubmit', () => {
|
||||
let deleteRuleSetLinkSpy: jasmine.Spy<(nodeId: string, ruleSetId: string) => Promise<void>>;
|
||||
let createRuleSetLinkSpy: jasmine.Spy<(nodeId: string, linkedNodeId: string) => Promise<void>>;
|
||||
|
||||
beforeEach(() => {
|
||||
deleteRuleSetLinkSpy = spyOn(component.folderRuleSetsService, 'deleteRuleSetLink').and.returnValue(Promise.resolve());
|
||||
createRuleSetLinkSpy = spyOn(component.folderRuleSetsService, 'createRuleSetLink').and.returnValue(Promise.resolve());
|
||||
component['selectedNodeId'] = 'selected-node-id';
|
||||
});
|
||||
|
||||
it('should set isBusy to true and create rule set link when no existing rule set', fakeAsync(() => {
|
||||
component.existingRuleSet = null;
|
||||
|
||||
component.onSubmit();
|
||||
|
||||
expect(component.isBusy).toBe(true);
|
||||
expect(deleteRuleSetLinkSpy).not.toHaveBeenCalled();
|
||||
|
||||
tick();
|
||||
|
||||
expect(createRuleSetLinkSpy).toHaveBeenCalledWith(component.nodeId, 'selected-node-id');
|
||||
expect(dialogRef.close).toHaveBeenCalledWith(true);
|
||||
expect(component.isBusy).toBe(false);
|
||||
}));
|
||||
|
||||
it('should delete existing rule set link then create new one when existing rule set provided', fakeAsync(() => {
|
||||
component.existingRuleSet = { id: 'existing-rule-set-id' } as RuleSet;
|
||||
|
||||
component.onSubmit();
|
||||
|
||||
expect(component.isBusy).toBe(true);
|
||||
expect(deleteRuleSetLinkSpy).toHaveBeenCalledWith(component.nodeId, 'existing-rule-set-id');
|
||||
|
||||
tick();
|
||||
|
||||
expect(createRuleSetLinkSpy).toHaveBeenCalledWith(component.nodeId, 'selected-node-id');
|
||||
expect(dialogRef.close).toHaveBeenCalledWith(true);
|
||||
expect(component.isBusy).toBe(false);
|
||||
}));
|
||||
|
||||
it('should handle error and call handleError when deleteRuleSetLink fails', fakeAsync(() => {
|
||||
const notificationService = TestBed.inject(NotificationService);
|
||||
spyOn(notificationService, 'showError');
|
||||
|
||||
deleteRuleSetLinkSpy.and.returnValue(Promise.reject(new Error('delete error')));
|
||||
component.existingRuleSet = { id: 'existing-rule-set-id' } as RuleSet;
|
||||
|
||||
component.onSubmit();
|
||||
tick();
|
||||
|
||||
expect(component.isBusy).toBe(false);
|
||||
expect(notificationService.showError).toHaveBeenCalledWith('ACA_FOLDER_RULES.LINK_RULES_DIALOG.ERRORS.REQUEST_FAILED');
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
@@ -27,38 +27,76 @@ import { TestBed } from '@angular/core/testing';
|
||||
import { FolderRulesService } from './folder-rules.service';
|
||||
import { ContentApiService } from '@alfresco/aca-shared';
|
||||
import { getOtherFolderEntryMock, getOwningFolderEntryMock, otherFolderIdMock, owningFolderIdMock, owningFolderMock } from '../mock/node.mock';
|
||||
import { of } from 'rxjs';
|
||||
import { filter, firstValueFrom, lastValueFrom, of, skip, throwError } from 'rxjs';
|
||||
import { getDefaultRuleSetResponseMock, getRuleSetsResponseMock, inheritedRuleSetMock, ownedRuleSetMock } from '../mock/rule-sets.mock';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { inheritedRulesMock, linkedRulesMock, ownedRulesMock, ruleMock } from '../mock/rules.mock';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-content-services';
|
||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Rule } from '../model/rule.model';
|
||||
|
||||
describe('FolderRuleSetsService', () => {
|
||||
let folderRuleSetsService: FolderRuleSetsService;
|
||||
let folderRulesService: FolderRulesService;
|
||||
let contentApiService: ContentApiService;
|
||||
|
||||
let callApiSpy: jasmine.Spy;
|
||||
let apiClientSpy: jasmine.SpyObj<{ callApi: jasmine.Spy }>;
|
||||
let getRulesSpy: jasmine.Spy;
|
||||
let getNodeSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(() => {
|
||||
apiClientSpy = jasmine.createSpyObj('contentPrivateClient', ['callApi']);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [NoopTranslateModule],
|
||||
providers: [FolderRuleSetsService, FolderRulesService, ContentApiService, { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }]
|
||||
providers: [
|
||||
ContentApiService,
|
||||
{
|
||||
provide: AlfrescoApiService,
|
||||
useValue: {
|
||||
getInstance: () => ({
|
||||
contentPrivateClient: apiClientSpy
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
folderRuleSetsService = TestBed.inject(FolderRuleSetsService);
|
||||
folderRulesService = TestBed.inject(FolderRulesService);
|
||||
contentApiService = TestBed.inject(ContentApiService);
|
||||
|
||||
callApiSpy = spyOn<any>(folderRuleSetsService, 'callApi')
|
||||
.withArgs(`/nodes/${owningFolderIdMock}/rule-sets/-default-?include=isLinkedTo,owningFolder,linkedToBy`, 'GET')
|
||||
apiClientSpy.callApi
|
||||
.withArgs(
|
||||
`/nodes/${owningFolderIdMock}/rule-sets/-default-?include=isLinkedTo,owningFolder,linkedToBy`,
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
)
|
||||
.and.returnValue(of(getDefaultRuleSetResponseMock))
|
||||
.withArgs(`/nodes/${owningFolderIdMock}/rule-sets?include=isLinkedTo,owningFolder,linkedToBy&skipCount=0&maxItems=100`, 'GET')
|
||||
.withArgs(
|
||||
`/nodes/${owningFolderIdMock}/rule-sets?include=isLinkedTo,owningFolder,linkedToBy&skipCount=0&maxItems=100`,
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
)
|
||||
.and.returnValue(of(getRuleSetsResponseMock))
|
||||
.and.stub();
|
||||
.withArgs('/nodes/folder-1-id/rule-set-links', 'POST', {}, {}, {}, {}, { id: 'folder-2-id' }, ['application/json'], ['application/json'])
|
||||
.and.returnValue(of({}))
|
||||
.withArgs('/nodes/folder-1-id/rule-set-links/rule-set-1-id', 'DELETE', {}, {}, {}, {}, {}, ['application/json'], ['application/json'])
|
||||
.and.returnValue(of({}));
|
||||
|
||||
getRulesSpy = spyOn<any>(folderRulesService, 'getRules')
|
||||
.withArgs(jasmine.anything(), 'rule-set-no-links')
|
||||
.and.returnValue(of({ rules: ownedRulesMock, hasMoreRules: false }))
|
||||
@@ -72,17 +110,37 @@ describe('FolderRuleSetsService', () => {
|
||||
.and.returnValue(of(getOwningFolderEntryMock))
|
||||
.withArgs(otherFolderIdMock)
|
||||
.and.returnValue(of(getOtherFolderEntryMock));
|
||||
|
||||
spyOn(folderRulesService, 'selectRule');
|
||||
});
|
||||
|
||||
it('should have an initial value of null for selectedRuleSet$', async () => {
|
||||
const selectedRuleSetPromise = folderRuleSetsService.selectedRuleSet$.pipe(take(1)).toPromise();
|
||||
const selectedRuleSetPromise = firstValueFrom(folderRuleSetsService.selectedRuleSet$.pipe(take(1)));
|
||||
const selectedRuleSet = await selectedRuleSetPromise;
|
||||
expect(selectedRuleSet).toBeNull();
|
||||
});
|
||||
|
||||
it('should select the first rule of the owned rule set of the folder', async () => {
|
||||
// take(3), because: 1 = init of the BehaviourSubject, 2 = reinitialise at beginning of loadRuleSets, 3 = in subscribe
|
||||
const mainRuleSetPromise = firstValueFrom(folderRuleSetsService.mainRuleSet$.pipe(skip(3), take(1)));
|
||||
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock);
|
||||
folderRuleSetsService.removeRuleFromMainRuleSet('owned-rule-1-id');
|
||||
const mainRuleSet = await mainRuleSetPromise;
|
||||
|
||||
expect(mainRuleSet.rules[0].id).toBe('owned-rule-2-id');
|
||||
expect(folderRulesService.selectRule).toHaveBeenCalledWith(ruleMock('owned-rule-1'));
|
||||
});
|
||||
|
||||
it('should not call selectRule on removeRuleFromMainRuleSet if mainRuleSet not set', async () => {
|
||||
folderRuleSetsService.removeRuleFromMainRuleSet('owned-rule-1-id');
|
||||
|
||||
expect(folderRulesService.selectRule).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it(`should load node info when loading the node's rule sets`, async () => {
|
||||
// take(2), because: 1 = init of the BehaviourSubject, 2 = in subscribe
|
||||
const folderInfoPromise = folderRuleSetsService.folderInfo$.pipe(take(2)).toPromise();
|
||||
const folderInfoPromise = lastValueFrom(folderRuleSetsService.folderInfo$.pipe(take(2)));
|
||||
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock);
|
||||
const folderInfo = await folderInfoPromise;
|
||||
@@ -93,68 +151,303 @@ describe('FolderRuleSetsService', () => {
|
||||
|
||||
it('should load the main rule set (main or linked)', async () => {
|
||||
// take(3), because: 1 = init of the BehaviourSubject, 2 = reinitialise at beginning of loadRuleSets, 3 = in subscribe
|
||||
const mainRuleSetPromise = folderRuleSetsService.mainRuleSet$.pipe(take(3)).toPromise();
|
||||
const mainRuleSetPromise = lastValueFrom(folderRuleSetsService.mainRuleSet$.pipe(take(3)));
|
||||
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock);
|
||||
const ruleSet = await mainRuleSetPromise;
|
||||
|
||||
expect(callApiSpy).toHaveBeenCalledWith(`/nodes/${owningFolderIdMock}/rule-sets/-default-?include=isLinkedTo,owningFolder,linkedToBy`, 'GET');
|
||||
expect(apiClientSpy.callApi).toHaveBeenCalledWith(
|
||||
`/nodes/${owningFolderIdMock}/rule-sets/-default-?include=isLinkedTo,owningFolder,linkedToBy`,
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
expect(ruleSet).toEqual(ownedRuleSetMock);
|
||||
});
|
||||
|
||||
it('should load inherited rule sets of a node and filter out owned or inherited rule sets', async () => {
|
||||
// take(3), because: 1 = init of the BehaviourSubject, 2 = reinitialise at beginning of loadRuleSets, 3 = in subscribe
|
||||
const inheritedRuleSetsPromise = folderRuleSetsService.inheritedRuleSets$.pipe(take(3)).toPromise();
|
||||
const hasMoreRuleSetsPromise = folderRuleSetsService.hasMoreRuleSets$.pipe(take(3)).toPromise();
|
||||
const inheritedRuleSetsPromise = lastValueFrom(folderRuleSetsService.inheritedRuleSets$.pipe(take(3)));
|
||||
const hasMoreRuleSetsPromise = lastValueFrom(folderRuleSetsService.hasMoreRuleSets$.pipe(take(3)));
|
||||
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock);
|
||||
const ruleSets = await inheritedRuleSetsPromise;
|
||||
const hasMoreRuleSets = await hasMoreRuleSetsPromise;
|
||||
|
||||
expect(callApiSpy).toHaveBeenCalledWith(
|
||||
expect(apiClientSpy.callApi).toHaveBeenCalledWith(
|
||||
`/nodes/${owningFolderIdMock}/rule-sets?include=isLinkedTo,owningFolder,linkedToBy&skipCount=0&maxItems=100`,
|
||||
'GET'
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
expect(ruleSets).toEqual([inheritedRuleSetMock]);
|
||||
expect(getRulesSpy).toHaveBeenCalledWith(owningFolderIdMock, jasmine.anything());
|
||||
expect(hasMoreRuleSets).toEqual(false);
|
||||
});
|
||||
|
||||
it('should select the first rule of the owned rule set of the folder', async () => {
|
||||
const selectRuleSpy = spyOn(folderRulesService, 'selectRule');
|
||||
// take(3), because: 1 = init of the BehaviourSubject, 2 = reinitialise at beginning of loadRuleSets, 3 = in subscribe
|
||||
const ruleSetListingPromise = folderRuleSetsService.inheritedRuleSets$.pipe(take(3)).toPromise();
|
||||
|
||||
it('should append additional inherited rule sets on loadMoreInheritedRuleSets', (done) => {
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock);
|
||||
await ruleSetListingPromise;
|
||||
|
||||
expect(selectRuleSpy).toHaveBeenCalledWith(ruleMock('owned-rule-1'));
|
||||
folderRuleSetsService.inheritedRuleSets$.pipe(take(3)).subscribe(async () => {
|
||||
const additionalRuleSet = {
|
||||
...inheritedRuleSetMock,
|
||||
id: 'additional-inherited-rule-set',
|
||||
owningFolder: otherFolderIdMock
|
||||
};
|
||||
|
||||
apiClientSpy.callApi
|
||||
.withArgs(
|
||||
`/nodes/${owningFolderIdMock}/rule-sets?include=isLinkedTo,owningFolder,linkedToBy&skipCount=1&maxItems=100`,
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
)
|
||||
.and.returnValue(
|
||||
of({
|
||||
list: {
|
||||
entries: [{ entry: additionalRuleSet }],
|
||||
pagination: { hasMoreItems: false }
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
getRulesSpy
|
||||
.withArgs(jasmine.anything(), 'additional-inherited-rule-set')
|
||||
.and.returnValue(of({ rules: inheritedRulesMock, hasMoreRules: false }));
|
||||
|
||||
let updateCount = 0;
|
||||
const subscription = folderRuleSetsService.inheritedRuleSets$.subscribe((ruleSets) => {
|
||||
updateCount++;
|
||||
if (updateCount === 2) {
|
||||
subscription.unsubscribe();
|
||||
|
||||
expect(ruleSets[0]).toEqual(inheritedRuleSetMock);
|
||||
expect(ruleSets[1].id).toBe('additional-inherited-rule-set');
|
||||
|
||||
expect(apiClientSpy.callApi).toHaveBeenCalledWith(
|
||||
`/nodes/${owningFolderIdMock}/rule-sets?include=isLinkedTo,owningFolder,linkedToBy&skipCount=1&maxItems=100`,
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('should select a different rule when removing a rule', () => {
|
||||
const selectRuleSpy = spyOn(folderRulesService, 'selectRule');
|
||||
folderRuleSetsService['mainRuleSet'] = JSON.parse(JSON.stringify(ownedRuleSetMock));
|
||||
folderRuleSetsService['inheritedRuleSets'] = JSON.parse(JSON.stringify([inheritedRuleSetMock]));
|
||||
folderRuleSetsService.loadMoreInheritedRuleSets();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error handling', () => {
|
||||
function testRuleSetApiError(status: number, statusText: string, errorMessage: string, done: DoneFn) {
|
||||
const httpError = new HttpErrorResponse({
|
||||
status,
|
||||
statusText,
|
||||
error: { message: errorMessage }
|
||||
});
|
||||
|
||||
apiClientSpy.callApi
|
||||
.withArgs(
|
||||
`/nodes/${owningFolderIdMock}/rule-sets/-default-?include=isLinkedTo,owningFolder,linkedToBy`,
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
)
|
||||
.and.returnValue(throwError(() => httpError));
|
||||
|
||||
folderRuleSetsService.mainRuleSet$.pipe(skip(1), take(1)).subscribe((value) => {
|
||||
expect(value).toBeNull();
|
||||
done();
|
||||
});
|
||||
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock, false);
|
||||
}
|
||||
|
||||
function testNodeInfoError(service: FolderRuleSetsService, status: number, expectedValue: null | undefined, done: DoneFn) {
|
||||
const httpError = new HttpErrorResponse({ status, statusText: status === 404 ? 'Not Found' : 'Failed' });
|
||||
getNodeSpy.withArgs(owningFolderIdMock).and.returnValue(throwError(() => httpError));
|
||||
|
||||
service.folderInfo$.pipe(skip(1), take(1)).subscribe((info) => {
|
||||
expect(info).toEqual(expectedValue);
|
||||
done();
|
||||
});
|
||||
|
||||
service.loadRuleSets(owningFolderIdMock, false);
|
||||
}
|
||||
|
||||
it('should set main rule set to null on 404 error', (done) => {
|
||||
testRuleSetApiError(404, 'Not Found', 'Rule set not found', done);
|
||||
});
|
||||
|
||||
it('should set mainRuleSet$ to null on non-404 error', (done) => {
|
||||
testRuleSetApiError(400, 'Failed', 'Failed to fetch main rule set', done);
|
||||
});
|
||||
|
||||
it('should emit null folderInfo when getNodeInfo fails with 404', (done) => {
|
||||
testNodeInfoError(folderRuleSetsService, 404, null, done);
|
||||
});
|
||||
|
||||
it('should emit undefined folderInfo on getNodeInfo non-404 error', (done) => {
|
||||
testNodeInfoError(folderRuleSetsService, 400, undefined, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit null folderInfo when nodeId is empty', (done) => {
|
||||
apiClientSpy.callApi
|
||||
.withArgs(
|
||||
`/nodes//rule-sets/-default-?include=isLinkedTo,owningFolder,linkedToBy`,
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
)
|
||||
.and.returnValue(throwError(() => new Error('Node ID is empty')));
|
||||
folderRuleSetsService.folderInfo$.pipe(skip(1), take(1)).subscribe((info) => {
|
||||
expect(info).toBeNull();
|
||||
expect(getNodeSpy).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
|
||||
folderRuleSetsService.loadRuleSets('', false);
|
||||
});
|
||||
|
||||
it('should add new rule to main rule set', async () => {
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock);
|
||||
const newRule = ruleMock('new-rule');
|
||||
|
||||
await firstValueFrom(
|
||||
folderRuleSetsService.isLoading$.pipe(
|
||||
filter((loading) => !loading),
|
||||
take(1)
|
||||
)
|
||||
);
|
||||
|
||||
folderRuleSetsService.addOrUpdateRuleInMainRuleSet(newRule);
|
||||
const main = await firstValueFrom(folderRuleSetsService.mainRuleSet$.pipe(take(1)));
|
||||
expect(main.rules[2]).toEqual(newRule);
|
||||
});
|
||||
|
||||
it('should update existing rule in main rule set', async () => {
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock);
|
||||
const newRule = { ...ownedRulesMock[0], description: 'new description' } as Rule;
|
||||
folderRuleSetsService.addOrUpdateRuleInMainRuleSet(newRule);
|
||||
const main = await firstValueFrom(folderRuleSetsService.mainRuleSet$.pipe(take(1)));
|
||||
|
||||
expect(main.rules[0].description).toEqual(newRule.description);
|
||||
});
|
||||
|
||||
it('should set main rule set to null if last rules was removed', async () => {
|
||||
getRulesSpy.withArgs(jasmine.anything(), 'rule-set-no-links').and.returnValue(of({ rules: [ownedRulesMock[0]], hasMoreRules: false }));
|
||||
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock);
|
||||
|
||||
await firstValueFrom(
|
||||
folderRuleSetsService.isLoading$.pipe(
|
||||
filter((loading) => !loading),
|
||||
take(1)
|
||||
)
|
||||
);
|
||||
|
||||
folderRuleSetsService.removeRuleFromMainRuleSet('owned-rule-1-id');
|
||||
|
||||
expect(selectRuleSpy).toHaveBeenCalledWith(ruleMock('owned-rule-2'));
|
||||
const main = await lastValueFrom(folderRuleSetsService.mainRuleSet$.pipe(take(1)));
|
||||
|
||||
selectRuleSpy.calls.reset();
|
||||
folderRuleSetsService.removeRuleFromMainRuleSet('owned-rule-2-id');
|
||||
|
||||
expect(selectRuleSpy).toHaveBeenCalledWith(ruleMock('inherited-rule-1'));
|
||||
expect(main).toBe(null);
|
||||
});
|
||||
|
||||
it('should send a POST request to create a new link between two folders', async () => {
|
||||
await folderRuleSetsService.createRuleSetLink('folder-1-id', 'folder-2-id');
|
||||
expect(callApiSpy).toHaveBeenCalledWith('/nodes/folder-1-id/rule-set-links', 'POST', {
|
||||
id: 'folder-2-id'
|
||||
});
|
||||
expect(apiClientSpy.callApi).toHaveBeenCalledWith(
|
||||
'/nodes/folder-1-id/rule-set-links',
|
||||
'POST',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ id: 'folder-2-id' },
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
});
|
||||
|
||||
it('should send a DELETE request to delete a link between two folders', async () => {
|
||||
it('should call refreshMainRuleSet when main rule set is empty', (done) => {
|
||||
const newRule = ruleMock('owned-rule-33');
|
||||
apiClientSpy.callApi
|
||||
.withArgs(
|
||||
`/nodes/${owningFolderIdMock}/rule-sets/-default-?include=isLinkedTo,owningFolder,linkedToBy`,
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
)
|
||||
.and.returnValue(throwError(() => new Error('Main rule set not found')));
|
||||
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock);
|
||||
|
||||
folderRuleSetsService.mainRuleSet$.pipe(skip(0), take(1)).subscribe((ruleSet) => {
|
||||
expect(ruleSet).toBeNull();
|
||||
done();
|
||||
});
|
||||
|
||||
folderRuleSetsService.addOrUpdateRuleInMainRuleSet(newRule);
|
||||
});
|
||||
|
||||
it('should refreshMainRuleSet and select a rule when main rule set exists', () => {
|
||||
folderRuleSetsService.loadRuleSets(owningFolderIdMock);
|
||||
const newRule = ruleMock('new-rule');
|
||||
|
||||
folderRuleSetsService.refreshMainRuleSet(newRule);
|
||||
|
||||
expect(folderRulesService.selectRule).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should send a DELETE request to remove a rule set link', async () => {
|
||||
await folderRuleSetsService.deleteRuleSetLink('folder-1-id', 'rule-set-1-id');
|
||||
expect(callApiSpy).toHaveBeenCalledWith('/nodes/folder-1-id/rule-set-links/rule-set-1-id', 'DELETE');
|
||||
|
||||
expect(apiClientSpy.callApi).toHaveBeenCalledWith(
|
||||
'/nodes/folder-1-id/rule-set-links/rule-set-1-id',
|
||||
'DELETE',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -194,7 +194,7 @@ export class FolderRuleSetsService {
|
||||
}
|
||||
return combineLatest(
|
||||
this.currentFolder?.id === entry.owningFolder ? of(this.currentFolder) : this.getNodeInfo(entry.owningFolder || ''),
|
||||
this.folderRulesService.getRules(this.currentFolder.id || '', entry.id)
|
||||
this.folderRulesService.getRules(this.currentFolder?.id || '', entry.id)
|
||||
).pipe(
|
||||
map(([owningFolderNodeInfo, getRulesRes]) => ({
|
||||
id: entry.id,
|
||||
@@ -209,28 +209,28 @@ export class FolderRuleSetsService {
|
||||
}
|
||||
|
||||
removeRuleFromMainRuleSet(ruleId: string) {
|
||||
if (this.mainRuleSet) {
|
||||
const index = this.mainRuleSet.rules.findIndex((rule: Rule) => rule.id === ruleId);
|
||||
if (index > -1) {
|
||||
if (this.mainRuleSet.rules.length > 1) {
|
||||
this.mainRuleSet.rules.splice(index, 1);
|
||||
} else {
|
||||
this.mainRuleSet = null;
|
||||
}
|
||||
this.mainRuleSetSource.next(this.mainRuleSet);
|
||||
this.folderRulesService.selectRule(this.mainRuleSet?.rules[0] ?? this.inheritedRuleSets[0]?.rules[0] ?? null);
|
||||
}
|
||||
if (!this.mainRuleSet) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedRules = this.mainRuleSet.rules.filter((rule) => rule.id !== ruleId);
|
||||
const newMainRuleSet: RuleSet = updatedRules.length ? { ...this.mainRuleSet, rules: updatedRules } : null;
|
||||
|
||||
this.mainRuleSet = newMainRuleSet;
|
||||
this.mainRuleSetSource.next(newMainRuleSet);
|
||||
|
||||
const nextRule = newMainRuleSet?.rules[0] ?? this.inheritedRuleSets[0]?.rules[0] ?? null;
|
||||
|
||||
this.folderRulesService.selectRule(nextRule);
|
||||
}
|
||||
|
||||
addOrUpdateRuleInMainRuleSet(newRule: Rule) {
|
||||
if (this.mainRuleSet) {
|
||||
const index = this.mainRuleSet.rules.findIndex((rule: Rule) => rule.id === newRule.id);
|
||||
if (index > -1) {
|
||||
this.mainRuleSet.rules.splice(index, 1, newRule);
|
||||
} else {
|
||||
this.mainRuleSet.rules.push(newRule);
|
||||
}
|
||||
const updatedRules = this.mainRuleSet.rules.some((rule) => rule.id === newRule.id)
|
||||
? this.mainRuleSet.rules.map((rule) => (rule.id === newRule.id ? newRule : rule))
|
||||
: [...this.mainRuleSet.rules, newRule];
|
||||
|
||||
this.mainRuleSet = { ...this.mainRuleSet, rules: updatedRules };
|
||||
this.mainRuleSetSource.next(this.mainRuleSet);
|
||||
this.folderRulesService.selectRule(newRule);
|
||||
} else {
|
||||
|
@@ -38,13 +38,13 @@ import {
|
||||
import { ruleSetMock } from '../mock/rule-sets.mock';
|
||||
import { owningFolderIdMock } from '../mock/node.mock';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-content-services';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-content-services';
|
||||
|
||||
describe('FolderRulesService', () => {
|
||||
let folderRulesService: FolderRulesService;
|
||||
let notificationService: NotificationService;
|
||||
|
||||
let callApiSpy: jasmine.Spy;
|
||||
let apiClientSpy: jasmine.SpyObj<{ callApi: jasmine.Spy }>;
|
||||
|
||||
const nodeId = owningFolderIdMock;
|
||||
const ruleSetId = 'rule-set-id';
|
||||
@@ -56,20 +56,30 @@ describe('FolderRulesService', () => {
|
||||
const key = ruleSettingsMock.key;
|
||||
|
||||
beforeEach(() => {
|
||||
apiClientSpy = jasmine.createSpyObj('contentPrivateClient', ['callApi']);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [NoopTranslateModule],
|
||||
providers: [FolderRulesService, { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }]
|
||||
providers: [
|
||||
FolderRulesService,
|
||||
{
|
||||
provide: AlfrescoApiService,
|
||||
useValue: {
|
||||
getInstance: () => ({
|
||||
contentPrivateClient: apiClientSpy
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
folderRulesService = TestBed.inject(FolderRulesService);
|
||||
notificationService = TestBed.inject(NotificationService);
|
||||
|
||||
callApiSpy = spyOn<any>(folderRulesService, 'callApi');
|
||||
});
|
||||
|
||||
it('should load some rules into a rule set', () => {
|
||||
const ruleSet = ruleSetMock();
|
||||
callApiSpy.and.returnValue(of(getRulesResponseMock));
|
||||
apiClientSpy.callApi.and.returnValue(of(getRulesResponseMock));
|
||||
|
||||
expect(ruleSet.rules.length).toBe(0);
|
||||
expect(ruleSet.hasMoreRules).toBeTrue();
|
||||
@@ -77,7 +87,17 @@ describe('FolderRulesService', () => {
|
||||
|
||||
folderRulesService.loadRules(ruleSet);
|
||||
|
||||
expect(callApiSpy).toHaveBeenCalledWith(`/nodes/${ruleSet.owningFolder.id}/rule-sets/${ruleSet.id}/rules?skipCount=0&maxItems=100`, 'GET');
|
||||
expect(apiClientSpy.callApi).toHaveBeenCalledWith(
|
||||
`/nodes/${ruleSet.owningFolder.id}/rule-sets/${ruleSet.id}/rules?skipCount=0&maxItems=100`,
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
expect(ruleSet.rules.length).toBe(2);
|
||||
expect(ruleSet.rules).toEqual(rulesMock);
|
||||
expect(ruleSet.hasMoreRules).toBeFalse();
|
||||
@@ -85,14 +105,24 @@ describe('FolderRulesService', () => {
|
||||
|
||||
it('should load more rules if it still has some more to load', () => {
|
||||
const ruleSet = ruleSetMock(rulesMock);
|
||||
callApiSpy.and.returnValue(of(getMoreRulesResponseMock));
|
||||
apiClientSpy.callApi.and.returnValue(of(getMoreRulesResponseMock));
|
||||
|
||||
expect(ruleSet.rules.length).toBe(2);
|
||||
expect(ruleSet.hasMoreRules).toBeTrue();
|
||||
|
||||
folderRulesService.loadRules(ruleSet);
|
||||
|
||||
expect(callApiSpy).toHaveBeenCalledWith(`/nodes/${ruleSet.owningFolder.id}/rule-sets/${ruleSet.id}/rules?skipCount=2&maxItems=100`, 'GET');
|
||||
expect(apiClientSpy.callApi).toHaveBeenCalledWith(
|
||||
`/nodes/${ruleSet.owningFolder.id}/rule-sets/${ruleSet.id}/rules?skipCount=2&maxItems=100`,
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
expect(ruleSet.rules.length).toBe(4);
|
||||
expect(ruleSet.rules).toEqual([...rulesMock, ...moreRulesMock]);
|
||||
expect(ruleSet.hasMoreRules).toBeFalse();
|
||||
@@ -120,7 +150,9 @@ describe('FolderRulesService', () => {
|
||||
});
|
||||
|
||||
it('should delete a rule and return its id', async () => {
|
||||
callApiSpy.withArgs(`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules/${ruleId}`, 'DELETE').and.returnValue(ruleId);
|
||||
apiClientSpy.callApi
|
||||
.withArgs(`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules/${ruleId}`, 'DELETE', {}, {}, {}, {}, {}, ['application/json'], ['application/json'])
|
||||
.and.returnValue(ruleId);
|
||||
const deletedRulePromise = folderRulesService.deletedRuleId$.pipe(take(2)).toPromise();
|
||||
|
||||
folderRulesService.deleteRule(nodeId, ruleId, ruleSetId);
|
||||
@@ -128,13 +160,82 @@ describe('FolderRulesService', () => {
|
||||
|
||||
expect(deletedRule).toBeTruthy('rule has not been deleted');
|
||||
expect(deletedRule).toBe(ruleId, 'wrong id of deleted rule');
|
||||
expect(callApiSpy).toHaveBeenCalledTimes(1);
|
||||
expect(callApiSpy).toHaveBeenCalledWith(`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules/${ruleId}`, 'DELETE');
|
||||
expect(apiClientSpy.callApi).toHaveBeenCalledTimes(1);
|
||||
expect(apiClientSpy.callApi).toHaveBeenCalledWith(
|
||||
`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules/${ruleId}`,
|
||||
'DELETE',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
});
|
||||
|
||||
it('should emit error when deleting rule fails', (done) => {
|
||||
const errorMessage = 'Delete failed';
|
||||
const mockError = new Error(errorMessage);
|
||||
|
||||
apiClientSpy.callApi
|
||||
.withArgs(`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules/${ruleId}`, 'DELETE', {}, {}, {}, {}, {}, ['application/json'], ['application/json'])
|
||||
.and.returnValue(Promise.reject(mockError));
|
||||
|
||||
folderRulesService.deletedRuleId$.pipe(take(2)).subscribe((value) => {
|
||||
if (value !== null) {
|
||||
expect(value as unknown as Error).toEqual(mockError);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
folderRulesService.deleteRule(nodeId, ruleId, ruleSetId);
|
||||
});
|
||||
|
||||
it('should format simple conditions with default values when properties are missing', () => {
|
||||
const mockResponse = {
|
||||
list: {
|
||||
entries: [
|
||||
{
|
||||
entry: {
|
||||
id: 'test-rule',
|
||||
name: 'Test Rule',
|
||||
conditions: {
|
||||
simpleConditions: [{}]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
pagination: { hasMoreItems: false }
|
||||
}
|
||||
};
|
||||
|
||||
apiClientSpy.callApi.and.returnValue(of(mockResponse));
|
||||
|
||||
folderRulesService.getRules('folder-id', 'ruleset-id').subscribe((result) => {
|
||||
const conditions = result.rules[0].conditions.simpleConditions;
|
||||
|
||||
expect(conditions[0]).toEqual({
|
||||
field: 'cm:name',
|
||||
comparator: 'equals',
|
||||
parameter: ''
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send correct POST request and return created rule', async () => {
|
||||
callApiSpy
|
||||
.withArgs(`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules`, 'POST', mockedRuleWithoutId)
|
||||
apiClientSpy.callApi
|
||||
.withArgs(
|
||||
`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules`,
|
||||
'POST',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
mockedRuleWithoutId,
|
||||
['application/json'],
|
||||
['application/json']
|
||||
)
|
||||
.and.returnValue(Promise.resolve(mockedRuleEntry));
|
||||
const result = await folderRulesService.createRule(nodeId, mockedRuleWithoutId, ruleSetId);
|
||||
|
||||
@@ -142,8 +243,18 @@ describe('FolderRulesService', () => {
|
||||
});
|
||||
|
||||
it('should send correct PUT request to update rule and return it', async () => {
|
||||
callApiSpy
|
||||
.withArgs(`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules/${ruleId}`, 'PUT', mockedRule)
|
||||
apiClientSpy.callApi
|
||||
.withArgs(
|
||||
`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules/${ruleId}`,
|
||||
'PUT',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
mockedRule,
|
||||
['application/json'],
|
||||
['application/json']
|
||||
)
|
||||
.and.returnValue(Promise.resolve(mockedRuleEntry));
|
||||
|
||||
const result = await folderRulesService.updateRule(nodeId, ruleId, mockedRule, ruleSetId);
|
||||
@@ -151,8 +262,18 @@ describe('FolderRulesService', () => {
|
||||
});
|
||||
|
||||
it('should display error message and revert enabled state when updating rule fails', async () => {
|
||||
callApiSpy
|
||||
.withArgs(`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules/${ruleId}`, 'PUT', mockedRule)
|
||||
apiClientSpy.callApi
|
||||
.withArgs(
|
||||
`/nodes/${nodeId}/rule-sets/${ruleSetId}/rules/${ruleId}`,
|
||||
'PUT',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
mockedRule,
|
||||
['application/json'],
|
||||
['application/json']
|
||||
)
|
||||
.and.returnValue(Promise.reject(new Error(JSON.stringify({ error: { briefSummary: 'Error updating rule' } }))));
|
||||
spyOn(notificationService, 'showError');
|
||||
|
||||
@@ -162,16 +283,119 @@ describe('FolderRulesService', () => {
|
||||
});
|
||||
|
||||
it('should send correct GET request and return rule settings', async () => {
|
||||
callApiSpy.withArgs(`/nodes/${nodeId}/rule-settings/${key}`, 'GET').and.returnValue(Promise.resolve(mockedRuleSettingsEntry));
|
||||
apiClientSpy.callApi
|
||||
.withArgs(`/nodes/${nodeId}/rule-settings/${key}`, 'GET', {}, {}, {}, {}, {}, ['application/json'], ['application/json'])
|
||||
.and.returnValue(Promise.resolve(mockedRuleSettingsEntry));
|
||||
|
||||
const result = await folderRulesService.getRuleSettings(nodeId, key);
|
||||
expect(result).toEqual(ruleSettingsMock);
|
||||
});
|
||||
|
||||
it('should send correct PUT request to update rule settings and return them', async () => {
|
||||
callApiSpy.withArgs(`/nodes/${nodeId}/rule-settings/${key}`, 'PUT', ruleSettingsMock).and.returnValue(Promise.resolve(mockedRuleSettingsEntry));
|
||||
apiClientSpy.callApi
|
||||
.withArgs(`/nodes/${nodeId}/rule-settings/${key}`, 'PUT', {}, {}, {}, {}, ruleSettingsMock, ['application/json'], ['application/json'])
|
||||
.and.returnValue(Promise.resolve(mockedRuleSettingsEntry));
|
||||
|
||||
const result = await folderRulesService.updateRuleSettings(nodeId, key, ruleSettingsMock);
|
||||
expect(result).toEqual(ruleSettingsMock);
|
||||
});
|
||||
|
||||
it('should handle rule with null simpleConditions', () => {
|
||||
const mockResponse = {
|
||||
list: {
|
||||
entries: [
|
||||
{
|
||||
entry: {
|
||||
id: 'test-rule',
|
||||
name: 'Test Rule',
|
||||
conditions: {
|
||||
simpleConditions: null
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
pagination: { hasMoreItems: false }
|
||||
}
|
||||
};
|
||||
|
||||
apiClientSpy.callApi.and.returnValue(of(mockResponse));
|
||||
|
||||
folderRulesService.getRules('folder-id', 'ruleset-id').subscribe((result) => {
|
||||
expect(result.rules[0].conditions.simpleConditions).toEqual([]);
|
||||
});
|
||||
|
||||
expect(apiClientSpy.callApi).toHaveBeenCalledWith(
|
||||
'/nodes/folder-id/rule-sets/ruleset-id/rules?skipCount=0&maxItems=100',
|
||||
'GET',
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle nested composite conditions when getting rules', () => {
|
||||
const mockResponse = {
|
||||
list: {
|
||||
entries: [
|
||||
{
|
||||
entry: {
|
||||
id: 'test-rule',
|
||||
name: 'Test Rule',
|
||||
conditions: {
|
||||
inverted: false,
|
||||
booleanMode: 'and',
|
||||
simpleConditions: [],
|
||||
compositeConditions: [
|
||||
{
|
||||
inverted: true,
|
||||
booleanMode: 'or',
|
||||
simpleConditions: [{ field: 'cm:title', comparator: 'contains', parameter: 'test' }],
|
||||
compositeConditions: [
|
||||
{
|
||||
inverted: false,
|
||||
booleanMode: 'and',
|
||||
simpleConditions: [{ field: 'cm:description', comparator: 'equals', parameter: 'nested' }],
|
||||
compositeConditions: []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
pagination: { hasMoreItems: false }
|
||||
}
|
||||
};
|
||||
|
||||
apiClientSpy.callApi.and.returnValue(of(mockResponse));
|
||||
|
||||
folderRulesService.getRules('folder-id', 'ruleset-id').subscribe((result) => {
|
||||
const conditions = result.rules[0].conditions;
|
||||
|
||||
expect(conditions.compositeConditions[0].inverted).toBe(true);
|
||||
expect(conditions.compositeConditions[0].booleanMode).toBe('or');
|
||||
expect(conditions.compositeConditions[0].compositeConditions[0].inverted).toBe(false);
|
||||
expect(conditions.compositeConditions[0].compositeConditions[0].booleanMode).toBe('and');
|
||||
});
|
||||
});
|
||||
|
||||
it('should create empty rule for form with options properties removed', () => {
|
||||
const result = FolderRulesService.emptyRuleForForm;
|
||||
|
||||
expect(result).toEqual({
|
||||
id: '',
|
||||
name: '',
|
||||
description: '',
|
||||
isShared: false,
|
||||
triggers: ['inbound'],
|
||||
conditions: FolderRulesService.emptyCompositeCondition,
|
||||
actions: [],
|
||||
options: FolderRulesService.emptyRuleOptions
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user