common-ui/src/lib/permissions/directives/allow.directive.spec.ts
2023-03-26 14:50:45 +03:00

807 lines
25 KiB
TypeScript

import { ChangeDetectionStrategy, Component, Type } from '@angular/core';
import { ComponentFixture, ComponentFixtureAutoDetect, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { IqserPermissionsService } from '../services/permissions.service';
import { IqserRolesService } from '../services/roles.service';
import { BehaviorSubject } from 'rxjs';
import { IqserAllowDirective } from './allow.directive';
class BaseTestComponent {
isAuthorized() {}
isUnauthorized() {}
}
const ADMIN = 'ADMIN' as const;
const GUEST = 'GUEST' as const;
let fixture: ComponentFixture<BaseTestComponent>;
let permissionsService: IqserPermissionsService;
let rolesService: IqserRolesService;
let isAuthorizedSpy: jest.SpyInstance;
let isUnauthorizedSpy: jest.SpyInstance;
function configureTestBed(component: Type<BaseTestComponent>) {
TestBed.configureTestingModule({
declarations: [component],
imports: [IqserAllowDirective],
providers: [{ provide: ComponentFixtureAutoDetect, useValue: true }],
});
fixture = TestBed.createComponent(component);
isAuthorizedSpy = jest.spyOn(fixture.componentInstance, 'isAuthorized');
isUnauthorizedSpy = jest.spyOn(fixture.componentInstance, 'isUnauthorized');
permissionsService = TestBed.inject(IqserPermissionsService);
rolesService = TestBed.inject(IqserRolesService);
}
function getFixtureContent(): HTMLElement {
return fixture.debugElement.nativeElement.querySelector('div');
}
describe('Permission directive', () => {
@Component({
template: ` <ng-template [allow]="'ADMIN'" (authorized)="isAuthorized()" (unauthorized)="isUnauthorized()">
<div>123</div>
</ng-template>`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should show the component and emit permissionAuthorized', fakeAsync(() => {
permissionsService.load([ADMIN, GUEST]);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
expect(isAuthorizedSpy).toHaveBeenCalledTimes(1);
}));
it('should not show the component', fakeAsync(() => {
permissionsService.load([GUEST]);
tick();
expect(getFixtureContent()).toEqual(null);
expect(isAuthorizedSpy).toHaveBeenCalledTimes(0);
}));
it('should show component when permission added', fakeAsync(() => {
permissionsService.load([GUEST]);
tick();
expect(getFixtureContent()).toEqual(null);
permissionsService.add(ADMIN);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
expect(isAuthorizedSpy).toHaveBeenCalledTimes(1);
}));
it('should hide component when permission removed', fakeAsync(() => {
permissionsService.load([ADMIN, GUEST]);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
expect(isAuthorizedSpy).toHaveBeenCalledTimes(1);
permissionsService.remove(ADMIN);
tick();
expect(getFixtureContent()).toEqual(null);
expect(isUnauthorizedSpy).toHaveBeenCalledTimes(1);
expect(isAuthorizedSpy).toHaveBeenCalledTimes(1);
}));
});
describe('Permission directive with roles', () => {
@Component({
template: ` <ng-template [allow]="'ADMIN'">
<div>123</div>
</ng-template>`,
})
class TestComponent extends BaseTestComponent {}
const awesomePermissions = 'AWESOME';
beforeEach(() => configureTestBed(TestComponent));
it('should show the component when key of role is the same', fakeAsync(() => {
rolesService.add({ ADMIN: [awesomePermissions] });
permissionsService.add(awesomePermissions);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
}));
it('should show the component when permissions array is the same', fakeAsync(() => {
rolesService.add({ ADMIN: [awesomePermissions] });
permissionsService.add(awesomePermissions);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
}));
it('should hide the component when user deletes all roles', fakeAsync(() => {
permissionsService.add(awesomePermissions);
rolesService.add({ ADMIN: [awesomePermissions] });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
rolesService.clear();
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should hide the component when user deletes one role', fakeAsync(() => {
permissionsService.add(awesomePermissions);
rolesService.add({ ADMIN: [awesomePermissions] });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
rolesService.remove(ADMIN);
tick();
expect(getFixtureContent()).toEqual(null);
}));
});
describe('Permission directive with roles array', () => {
@Component({
template: ` <ng-template [allow]="['ADMIN', 'GUEST']">
<div>123</div>
</ng-template>`,
})
class TestComponent extends BaseTestComponent {}
const awesomePermission = 'AWESOME';
beforeEach(() => configureTestBed(TestComponent));
it('should show the component when key of role is the same', fakeAsync(() => {
permissionsService.add(awesomePermission);
rolesService.add({ ADMIN: [awesomePermission] });
rolesService.add({ GUEST: [awesomePermission] });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
}));
it('should hide the component when user deletes all roles', fakeAsync(() => {
permissionsService.add(awesomePermission);
rolesService.add({ ADMIN: [awesomePermission] });
rolesService.add({ GUEST: [awesomePermission] });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
rolesService.clear();
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should hide the component when user deletes one role', fakeAsync(() => {
permissionsService.add(awesomePermission);
rolesService.add({ ADMIN: [awesomePermission] });
rolesService.add({ GUEST: [awesomePermission] });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
rolesService.remove(ADMIN);
tick();
expect(getFixtureContent()).toEqual(null);
}));
});
describe('Permission directive testing different selectors *allow', () => {
@Component({
template: ` <div *allow="['ADMIN']; deny: 'GUEST'">
<div>123</div>
</div>`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('Should show the component when key of role is the same', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
permissionsService.add('AWESOME');
rolesService.add({ ADMIN: ['AWESOME'] });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('<div>123</div>');
}));
it('should hide the component when key of role is the same', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
rolesService.add({ GG: ['Awsesome'] });
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should hide the component when deny permission is added', fakeAsync(() => {
permissionsService.add(ADMIN);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('<div>123</div>');
permissionsService.add(GUEST);
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should hide the component when deny role is added', fakeAsync(() => {
permissionsService.add(ADMIN);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('<div>123</div>');
rolesService.add(GUEST);
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should show the component when deny permission is remove', fakeAsync(() => {
permissionsService.add([ADMIN, GUEST]);
tick();
expect(getFixtureContent()).toEqual(null);
permissionsService.remove(GUEST);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('<div>123</div>');
}));
});
describe('Permission directive angular testing different async functions in roles', () => {
@Component({
template: ` <div *allow="'ADMIN'">
<div>123</div>
</div>`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should show the component when promise returns truthy value', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
rolesService.add({ ADMIN: () => true });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('<div>123</div>');
}));
it('should not show the component when promise returns truthy value', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
rolesService.add({ ADMIN: () => false });
tick();
expect(getFixtureContent()).toEqual(null);
}));
});
describe('Permission directive angular testing different async functions in roles via array', () => {
@Component({
template: ` <div *allow="['ADMIN', 'GUEST']">
<div>123</div>
</div>`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should show the component when returns truthy value', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
rolesService.add({ ADMIN: () => true });
rolesService.add({ GUEST: () => true });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('<div>123</div>');
}));
it('should not show the component when returns false value', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
rolesService.add({ ADMIN: () => false });
rolesService.add({ GUEST: () => true });
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should hide the component when 1 passes second fails', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
rolesService.add({ ADMIN: () => false });
rolesService.add({ GUEST: ['AWESOME'] });
tick();
expect(getFixtureContent()).toEqual(null);
}));
});
describe('Permission directive with different async functions in permissions via array', () => {
@Component({
template: ` <div *allow="['ADMIN', 'GUEST']">
<div>123</div>
</div>`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should show the component when returns truthy value', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
permissionsService.add({ ADMIN: () => true });
permissionsService.add({ GUEST: () => true });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('<div>123</div>');
}));
it('should not show the component when returns false value', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
permissionsService.add({ ADMIN: () => false });
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should show the component when returns truthy value', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
permissionsService.add({
ADMIN: () => true,
GUEST: () => true,
});
tick();
const content2 = getFixtureContent();
expect(content2).toBeTruthy();
expect(content2.innerHTML).toEqual('<div>123</div>');
}));
it('should not show the component when functions with name and store fulfils', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
permissionsService.add({
ADMIN: (name, store) => {
expect(name).toBeTruthy();
expect(store[name].name).toBeTruthy();
return name === ADMIN;
},
});
permissionsService.add({ GUEST: () => false });
tick();
expect(getFixtureContent()).toEqual(null);
}));
});
describe('Permission directive testing different async functions in permissions via string', () => {
@Component({
template: ` <div *allow="'ADMIN'">
<div>123</div>
</div>`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should show the component when promise returns truthy value', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
permissionsService.add({ ADMIN: () => true });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('<div>123</div>');
}));
it('should not show the component when promise returns false value', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
permissionsService.add({ ADMIN: () => false });
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should not show the component when only one of the promises fulfills', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
permissionsService.add({ ADMIN: () => false });
permissionsService.add({ GUEST: () => true });
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should not show the component when all promises fails', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
permissionsService.add({ ADMIN: () => false });
permissionsService.add({ GUEST: () => false });
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should show the component when functions with name and store fulfils', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
permissionsService.add({
ADMIN: (name, store) => {
expect(name).toBeTruthy();
expect(store[name].name).toBeTruthy();
return name === ADMIN;
},
});
permissionsService.add({ GUEST: () => false });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('<div>123</div>');
}));
});
describe('Permissions directive with else block', () => {
@Component({
template: `
<div *allow="['FAILED_BLOCK']; else elseBlock">main</div>
<ng-template #elseBlock>
<div>elseBlockContent</div>
</ng-template>
<ng-template #thenBlock>
<div>thenBlockContent</div>
</ng-template>
`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should show else block when permissions fail', () => {
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`elseBlockContent`);
});
it('should show else block when permissions change', fakeAsync(() => {
rolesService.add({ FAILED_BLOCK: () => true });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('main');
rolesService.remove('FAILED_BLOCK');
tick();
const content2 = getFixtureContent();
expect(content2).toBeTruthy();
expect(content2.innerHTML).toEqual(`elseBlockContent`);
}));
});
describe('Permissions directive with then block', () => {
@Component({
template: `
<div *allow="['THEN_BLOCK']; else elseBlock; then: thenBlock">main</div>
<ng-template #elseBlock>
<div>elseBlockContent</div>
</ng-template>
<ng-template #thenBlock>
<div>thenBlockContent</div>
</ng-template>
`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should fail and show then block', fakeAsync(() => {
rolesService.add({ THEN_BLOCK: () => true });
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`thenBlockContent`);
}));
});
describe('Permissions directive with empty argument', () => {
@Component({
template: `
<ng-template [allow]="">
<div>123</div>
</ng-template>
`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should succeed and show the component', () => {
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`123`);
});
});
describe('Permissions directive with an empty array', () => {
@Component({
template: `
<ng-template [allow]="[]">
<div>123</div>
</ng-template>
`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should succeed and show the component', () => {
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`123`);
});
});
describe('Permission directive with true if condition', () => {
@Component({
template: ` <ng-template [allow]="'ADMIN'" [allowIf]="true">
<div>123</div>
</ng-template>`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should show the component when permission is present', fakeAsync(() => {
permissionsService.add(ADMIN);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
}));
it('should hide the component when permission is absent', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
}));
});
describe('Permission directive with true if condition', () => {
@Component({
template: ` <ng-template [allow]="'ADMIN'" [allowIf]="false">
<div>123</div>
</ng-template>`,
})
class TestComponent extends BaseTestComponent {}
beforeEach(() => configureTestBed(TestComponent));
it('should hide the component when permission is present', fakeAsync(() => {
permissionsService.add(ADMIN);
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should hide the component when permission is absent', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
}));
});
describe('Permission directive with true promise if condition', () => {
@Component({
template: ` <ng-template [allow]="'ADMIN'" [allowIf]="condition">
<div>123</div>
</ng-template>`,
})
class TestComponent extends BaseTestComponent {
condition = Promise.resolve(true);
}
beforeEach(() => configureTestBed(TestComponent));
it('should show the component when permission is present', fakeAsync(() => {
permissionsService.add(ADMIN);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual('123');
}));
it('should hide the component when permission is absent', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
}));
});
describe('Permission directive with false promise if condition', () => {
@Component({
template: ` <div *allow="'ADMIN'; if: condition">
<div>123</div>
</div>`,
})
class TestComponent extends BaseTestComponent {
condition = Promise.resolve(false);
}
beforeEach(() => configureTestBed(TestComponent));
it('should hide the component when permission is present', fakeAsync(() => {
permissionsService.add(ADMIN);
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should hide the component when permission is absent', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
}));
});
describe('Permissions directive with then block and if condition', () => {
@Component({
template: `
<div *allow="['THEN_BLOCK']; if: condition; else: elseBlock; then: thenBlock">main</div>
<ng-template #elseBlock>
<div>elseBlockContent</div>
</ng-template>
<ng-template #thenBlock>
<div>thenBlockContent</div>
</ng-template>
`,
})
class TestComponent extends BaseTestComponent {
condition = new BehaviorSubject(true);
}
beforeEach(() => configureTestBed(TestComponent));
it('should show else block when permission missing', fakeAsync(() => {
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`elseBlockContent`);
}));
it('should show then block when permission added', fakeAsync(() => {
permissionsService.add('THEN_BLOCK');
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`thenBlockContent`);
}));
it('should show else block when permission added but condition is false', fakeAsync(() => {
permissionsService.add('THEN_BLOCK');
(fixture.componentInstance as TestComponent).condition.next(false);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`elseBlockContent`);
}));
it('should show else block when permission is missing and condition is false', fakeAsync(() => {
(fixture.componentInstance as TestComponent).condition.next(false);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`elseBlockContent`);
}));
});
describe('Permission directive with false promise, if condition and change detection on push', () => {
@Component({
template: ` <div *allow="'ADMIN'; if: condition; deny: 'GUEST'">
<div>123</div>
</div>`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
class TestComponent extends BaseTestComponent {
condition = new BehaviorSubject(false);
}
beforeEach(() => configureTestBed(TestComponent));
it('should hide the component when permission is present', fakeAsync(() => {
permissionsService.add(ADMIN);
tick();
expect(getFixtureContent()).toEqual(null);
}));
it('should hide the component when permission is absent', fakeAsync(() => {
expect(getFixtureContent()).toEqual(null);
}));
it('should show component when permission is added and condition is true', fakeAsync(() => {
permissionsService.add(ADMIN);
(fixture.componentInstance as TestComponent).condition.next(true);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`<div>123</div>`);
}));
it('should hide component when permission is present, condition is true and deny permission is present', fakeAsync(() => {
permissionsService.add(ADMIN);
(fixture.componentInstance as TestComponent).condition.next(true);
tick();
const content = getFixtureContent();
expect(content).toBeTruthy();
expect(content.innerHTML).toEqual(`<div>123</div>`);
permissionsService.add(GUEST);
tick();
expect(getFixtureContent()).toEqual(null);
}));
});