common-ui/src/lib/permissions/services/permissions-guard.service.spec.ts
2022-10-14 18:12:55 +03:00

463 lines
16 KiB
TypeScript

import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { IqserActivatedRouteSnapshot, IqserPermissionsModule } from '..';
import { IqserPermissionsService } from './permissions.service';
import { IqserRolesService } from './roles.service';
import { IqserPermissionsGuard } from './permissions-guard.service';
const ADMIN = 'ADMIN' as const;
const defaultRouterState = {} as RouterStateSnapshot;
const defaultRouter: Partial<Router> = {
navigate: () => Promise.resolve(true),
};
let router: Router;
let routerNavigationSpy: jest.SpyInstance;
let testRoute: Partial<IqserActivatedRouteSnapshot>;
let permissionGuard: IqserPermissionsGuard;
let permissionsService: IqserPermissionsService;
function configureTestBed() {
router = { ...defaultRouter } as Router;
routerNavigationSpy = jest.spyOn(router, 'navigate');
TestBed.configureTestingModule({
imports: [IqserPermissionsModule.forRoot()],
providers: [
{
provide: Router,
useValue: router,
},
],
});
permissionGuard = TestBed.inject(IqserPermissionsGuard);
permissionsService = TestBed.inject(IqserPermissionsService);
}
describe('Permissions guard', () => {
beforeEach(async () => {
configureTestBed();
permissionsService.add([ADMIN]);
});
it('should create an instance', () => {
expect(permissionGuard).toBeTruthy();
});
it('should return true when only fulfils', async () => {
testRoute = {
data: {
permissions: {
allow: ADMIN,
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(routerNavigationSpy).not.toHaveBeenCalled();
expect(result).toEqual(true);
});
it('should return true when only is empty array', async () => {
testRoute = {
data: {
permissions: {
allow: [],
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(routerNavigationSpy).not.toHaveBeenCalled();
expect(result).toEqual(true);
});
it('should return true when no permissions specified', async () => {
testRoute = {};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(routerNavigationSpy).not.toHaveBeenCalled();
expect(result).toEqual(true);
});
it('should return false when allow doesnt match', async () => {
testRoute = {
data: {
permissions: {
allow: 'DOESNT MATCH',
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(routerNavigationSpy).not.toHaveBeenCalled();
expect(result).toEqual(false);
});
it('should return false when no permission match', async () => {
testRoute = {
data: {
permissions: {
allow: ['DOESNT MATCH', 'DOESNT MATCH 2'],
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(routerNavigationSpy).not.toHaveBeenCalled();
expect(result).toEqual(false);
});
it('should return false when only doesnt match and navigate to 404', async () => {
testRoute = {
data: {
permissions: {
allow: 'DOESNT MATCH',
redirectTo: './404',
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['./404']);
});
it('should return false when only doesnt match and navigate to array 404', async () => {
testRoute = {
data: {
permissions: {
allow: 'DOESNT MATCH',
redirectTo: ['./404'],
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['./404']);
});
it('should return false when only doesnt match and navigate to redirectTo function', async () => {
testRoute = {
data: {
permissions: {
allow: 'DOESNT MATCH',
redirectTo: () => ['./403'],
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['./403']);
});
});
describe('Permissions guard dynamically', () => {
beforeEach(async () => {
configureTestBed();
permissionsService.add(ADMIN);
});
it('should return true when only function matches', async () => {
testRoute = {
params: {
id: 44,
},
data: {
permissions: {
allow: route => {
if ((route as ActivatedRouteSnapshot).params['id'] === 44) {
return [ADMIN];
}
return 'notManager';
},
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(routerNavigationSpy).not.toHaveBeenCalled();
expect(result).toEqual(true);
});
it('should return false when only function is called and should redirect', async () => {
testRoute = {
params: {
id: 100,
},
data: {
permissions: {
allow: route => {
if ((route as ActivatedRouteSnapshot).params['id'] === 44) {
return [ADMIN];
}
return 'notManager';
},
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(routerNavigationSpy).not.toHaveBeenCalled();
expect(result).toEqual(false);
});
});
describe('Permissions guard dynamic redirectTo', () => {
beforeEach(() => {
configureTestBed();
permissionsService.add(ADMIN);
});
it('should redirect to parameters from navigationCommands and navigationExtras', async () => {
testRoute = {
data: {
permissions: {
allow: 'TIED',
redirectTo: {
navigationCommands: ['123'],
navigationExtras: {
skipLocationChange: true,
},
},
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['123'], { skipLocationChange: true });
});
it('should redirect to function parameters from navigationCommands and navigationExtras', async () => {
testRoute = {
data: {
permissions: {
allow: 'TIED',
redirectTo: {
navigationCommands: () => ['123'],
navigationExtras: () => ({
skipLocationChange: true,
}),
},
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['123'], { skipLocationChange: true });
});
});
describe('Permissions guard with multiple redirectTo rules', () => {
beforeEach(() => {
configureTestBed();
permissionsService.add('canReadAgenda');
});
it('should fail on canEditAgenda and redirect to dashboard', async () => {
testRoute = {
data: {
permissions: {
allow: ['canReadAgenda', 'canEditAgenda', 'canRun'],
redirectTo: {
canReadAgenda: 'agendaList',
canEditAgenda: 'dashboard',
default: 'login',
},
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['dashboard']);
});
it('should redirect to dashboard when canEditAgenda fails', async () => {
testRoute = {
data: {
permissions: {
allow: ['canReadAgenda', 'canEditAgenda', 'canRun'],
redirectTo: {
canReadAgenda: 'agendaList',
canEditAgenda: () => 'dashboard',
default: 'login',
},
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['dashboard']);
});
it('should redirect to 123 when canEditAgenda fails with navigation parameters', async () => {
testRoute = {
data: {
permissions: {
allow: ['canEditAgenda', 'canRun'],
redirectTo: {
canReadAgenda: 'agendaList',
canEditAgenda: {
navigationCommands: ['123'],
navigationExtras: {
skipLocationChange: true,
},
},
default: 'login',
},
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['123'], { skipLocationChange: true });
});
it('should redirect to 123 when canEditAgenda returns parameters from function', async () => {
testRoute = {
data: {
permissions: {
allow: ['canReadAgenda', 'canEditAgenda', 'canRun'],
redirectTo: {
canReadAgenda: 'agendaList',
canEditAgenda: () => {
return {
navigationCommands: ['123'],
navigationExtras: {
skipLocationChange: true,
},
};
},
default: 'login',
},
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['123'], { skipLocationChange: true });
});
it('should redirect to default when a permission fails with no redirection rule', async () => {
permissionsService.add(['canEditAgenda']);
testRoute = {
data: {
permissions: {
allow: ['canEditAgenda', 'Can run'],
redirectTo: {
canEditAgenda: 'dashboard',
default: 'login',
},
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['login']);
expect(routerNavigationSpy).toHaveBeenCalledTimes(1);
});
it('should activate path when nothing fails', async () => {
permissionsService.add('canEditAgenda');
testRoute = {
data: {
permissions: {
allow: ['canEditAgenda'],
redirectTo: {
canReadAgenda: 'agendaList',
canEditAgenda: 'dashboard',
canRun: 'run',
default: 'login',
},
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(true);
expect(routerNavigationSpy).not.toHaveBeenCalled();
});
});
describe('Permissions guard redirectTo as function', () => {
beforeEach(() => {
configureTestBed();
permissionsService.add('canReadAgenda');
});
it('should dynamically redirect', async () => {
testRoute = {
data: {
permissions: {
allow: ['canRun'],
redirectTo: failedPermission => failedPermission,
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(false);
expect(routerNavigationSpy).toHaveBeenCalledWith(['canRun']);
expect(routerNavigationSpy).toHaveBeenCalledTimes(1);
});
it('should allow to pass when at least one of parameters allow passing', async () => {
testRoute = {
data: {
permissions: {
allow: ['canReadAgenda', 'CAN_SWIM'],
redirectTo: () => 'login',
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(true);
expect(routerNavigationSpy).not.toHaveBeenCalled();
});
});
describe('Role guard with redirectTo as function', () => {
let roleService: IqserRolesService;
beforeEach(() => {
configureTestBed();
roleService = TestBed.inject(IqserRolesService);
permissionsService.add('canReadAgenda');
permissionsService.add('AWESOME');
roleService.add({ ADMIN: ['AWESOME', 'canReadAgenda'] });
});
it('should dynamically pass if one satisfies', async () => {
roleService.add({ RUN: ['BLABLA', 'BLABLA2'] });
testRoute = {
data: {
permissions: {
allow: ['RUN', 'AWESOME'],
redirectTo: failedPermission => failedPermission,
},
},
};
const result = await permissionGuard.canActivate(testRoute as ActivatedRouteSnapshot, defaultRouterState);
expect(result).toEqual(true);
expect(routerNavigationSpy).not.toHaveBeenCalled();
});
});