test(e2e): acl e2e test (#3249)

* test: acl test

* test: acl action test

* test: acl test

* test: acl test

* test: acl collection block test

* test: acl e2e test

* test: acl e2e test

* test: acl test

* test: acl collection test

* test: acl collectin test

* test: acl association test

* test: association acl test

* test: collection acl test

* test: collection acl test

* test: acl test

* test: acl updateRole test

* test: menu permission test

* test: menu permission test

* test: menu permission test

* test: menu permission test

* test: acl test

* test: acl test

* test: acl test

* test: acl test

* test: acl test

* test: menu acl test

* test: acl test

* refactor: setDefaultRole

* fix: merge bug

* fix: merge bug

* test: acl test
This commit is contained in:
katherinehhh 2023-12-29 09:15:57 +08:00 committed by GitHub
parent 4121075a98
commit c9d5292d03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 3588 additions and 3 deletions

View File

@ -193,6 +193,7 @@ export const RolesResourcesActions = connect((props) => {
render: (checked, field) => ( render: (checked, field) => (
<Checkbox <Checkbox
checked={checked} checked={checked}
aria-label={`${action.name}_checkbox`}
onChange={() => { onChange={() => {
const item = actionMap[action.name] || { const item = actionMap[action.name] || {
name: action.name, name: action.name,

View File

@ -67,6 +67,7 @@ export const StrategyActions = connect((props) => {
render: (enabled, action) => ( render: (enabled, action) => (
<Checkbox <Checkbox
checked={enabled} checked={enabled}
aria-label={`${action.name}_checkbox`}
onChange={(e) => { onChange={(e) => {
if (enabled) { if (enabled) {
delete scopes[action.name]; delete scopes[action.name];

View File

@ -100,8 +100,8 @@ function ButtonEditor(props) {
default: fieldSchema?.['x-component-props']?.danger default: fieldSchema?.['x-component-props']?.danger
? 'danger' ? 'danger'
: fieldSchema?.['x-component-props']?.type === 'primary' : fieldSchema?.['x-component-props']?.type === 'primary'
? 'primary' ? 'primary'
: 'default', : 'default',
enum: [ enum: [
{ value: 'default', label: '{{t("Default")}}' }, { value: 'default', label: '{{t("Default")}}' },
{ value: 'primary', label: '{{t("Highlight")}}' }, { value: 'primary', label: '{{t("Highlight")}}' },

View File

@ -89,6 +89,38 @@ export interface CollectionSetting {
}>; }>;
} }
interface AclActionsSetting {
name: string; //操作标识如cretae
fields?: any[]; //有该操作权限的字段
scope?: any; // 数据范围
}
interface AclResourcesSetting {
name: string; //数据表标识
usingActionsConfig: boolean; //是否开启单独配置
actions?: AclActionsSetting[];
}
interface AclRoleSetting {
name?: string;
title?: string;
/**
* @default true
*/
allowNewMenu?: boolean;
//配置权限,如 ["app", "pm", "pm.*", "ui.*"]
snippets?: string[];
//操作权限策略
strategy?: any;
//数据表单独操作权限配置
resources?: AclResourcesSetting[];
/**
* @default false
*/
default?: boolean;
key?: string;
//菜单权限配置
menuUiSchemas?: string[];
}
export interface PageConfig { export interface PageConfig {
/** /**
* *
@ -188,6 +220,14 @@ interface ExtendUtils {
* @returns * @returns
*/ */
deletePage: (pageName: string) => Promise<void>; deletePage: (pageName: string) => Promise<void>;
/**
* admin关联上
*/
mockRole: <T = any>(roleSetting: AclRoleSetting) => Promise<T>;
/**
*
*/
updateRole: <T = any>(roleSetting: AclRoleSetting) => Promise<T>;
} }
const PORT = process.env.APP_PORT || 20000; const PORT = process.env.APP_PORT || 20000;
@ -232,7 +272,10 @@ export class NocoPage {
await this._waitForInit; await this._waitForInit;
return this.url; return this.url;
} }
async getUid() {
await this._waitForInit;
return this.uid;
}
async waitForInit(this: NocoPage) { async waitForInit(this: NocoPage) {
await this._waitForInit; await this._waitForInit;
return this; return this;
@ -267,6 +310,7 @@ const _test = base.extend<ExtendUtils>({
// 测试运行完自动销毁页面 // 测试运行完自动销毁页面
for (const nocoPage of nocoPages) { for (const nocoPage of nocoPages) {
await nocoPage.destroy(); await nocoPage.destroy();
await setDefaultRole('root');
} }
}, },
mockManualDestroyPage: async ({ browser }, use) => { mockManualDestroyPage: async ({ browser }, use) => {
@ -378,6 +422,20 @@ const _test = base.extend<ExtendUtils>({
]; ];
await Promise.all(deletePromises); await Promise.all(deletePromises);
}, },
mockRole: async ({ page }, use) => {
const mockRole = async (roleSetting: AclRoleSetting) => {
return createRole(roleSetting);
};
await use(mockRole);
},
updateRole: async ({ page }, use) => {
async (roleSetting: AclRoleSetting) => {
return updateRole(roleSetting);
};
await use(updateRole);
},
}); });
export const test = Object.assign(_test, { export const test = Object.assign(_test, {
@ -592,6 +650,76 @@ const createCollections = async (collectionSettings: CollectionSetting | Collect
return (await result.json()).data; return (await result.json()).data;
}; };
/**
* superAdmin且切换到新角色
* @param page page
* @param AclRoleSetting
* @returns
*/
const createRole = async (roleSetting: AclRoleSetting) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
const name = roleSetting.name || uid();
const result = await api.post(`/api/users/1/roles:create`, {
headers,
data: { ...roleSetting, name, title: name },
});
if (!result.ok()) {
throw new Error(await result.text());
}
const roleData = (await result.json()).data;
await setDefaultRole(name);
return roleData;
};
/**
*
* @param page page
* @param AclRoleSetting
* @returns
*/
const updateRole = async (roleSetting: AclRoleSetting) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
const name = roleSetting.name;
const result = await api.post(`/api/users/1/roles:update?filterByTk=${name}`, {
headers,
data: { ...roleSetting },
});
if (!result.ok()) {
throw new Error(await result.text());
}
const roleData = (await result.json()).data;
return roleData;
};
/**
*
* @param name
*/
const setDefaultRole = async (name) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
await api.post(`/api/users:setDefaultRole`, {
headers,
data: { roleName: name },
});
};
/** /**
* collection Faker * collection Faker
* @param collectionSetting * @param collectionSetting

View File

@ -0,0 +1,242 @@
import { expect, test } from '@nocobase/test/e2e';
import { oneTableBlock } from './utils';
test.describe('view', () => {
//关系字段有权限,关系目标表无权限
test('association field accept, target collection denied', async ({ page, mockPage, mockRole, mockRecord }) => {
await mockPage(oneTableBlock).goto();
await mockRecord('general');
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'users',
},
{
usingActionsConfig: true,
name: 'general',
actions: [{ name: 'view', fields: ['oneToOneBelongsTo'] }],
},
],
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
//关系字段可见
await expect(page.getByRole('button', { name: 'oneToOneBelongsTo' })).toBeVisible();
await expect(page.getByRole('button', { name: 'phone' })).not.toBeVisible();
await page.getByLabel('action-Action.Link-Association block-customize:popup-general-table').click();
//关系区块不可见
await expect(await page.getByLabel('block-item-CardItem-users-form')).not.toBeVisible();
});
//关系字段有权限,关系目标表个别字段有权限
test('association field accept, target collection accept with fields', async ({
page,
mockPage,
mockRole,
mockRecord,
}) => {
await mockPage(oneTableBlock).goto();
await mockRecord('general');
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'users',
actions: [{ name: 'view', fields: ['email'] }],
},
{
usingActionsConfig: true,
name: 'general',
actions: [{ name: 'view', fields: ['oneToOneBelongsTo'] }],
},
],
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
//关系字段可见
await expect(page.getByRole('button', { name: 'oneToOneBelongsTo' })).toBeVisible();
await expect(page.getByRole('button', { name: 'phone' })).not.toBeVisible();
await page.getByLabel('action-Action.Link-Association block-customize:popup-general-table').click();
//关系区块可见,个别字段可见
await expect(await page.getByLabel('block-item-CardItem-users-form')).toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.nickname')).not.toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.email')).toBeVisible();
});
});
test.describe('update', () => {
//关系字段有权限,关系目标表无权限
test('association field accept,target collection denied', async ({ page, mockPage, mockRole, mockRecord }) => {
await mockPage(oneTableBlock).goto();
await mockRecord('general');
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'users',
},
{
usingActionsConfig: true,
name: 'general',
actions: [
{ name: 'view', fields: ['oneToOneBelongsTo'] },
{ name: 'update', fields: ['oneToOneBelongsTo'] },
],
},
],
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
await page.getByLabel('action-Action.Link-Association field-customize:popup-general-table').click();
//关系字段组件可见,子表单/子表格中字段不可见
await expect(
await page.getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo'),
).toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.email-Email')).not.toBeVisible();
});
//关系字段有权限,关系目标表个别字段有权限
test('association field accept, target collection accept with fields', async ({
page,
mockPage,
mockRole,
mockRecord,
}) => {
await mockPage(oneTableBlock).goto();
await mockRecord('general');
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'users',
actions: [{ name: 'view' }, { name: 'update', fields: ['email'] }],
},
{
usingActionsConfig: true,
name: 'general',
actions: [
{ name: 'view', fields: ['oneToOneBelongsTo'] },
{ name: 'update', fields: ['oneToOneBelongsTo'] },
],
},
],
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
await page.getByLabel('action-Action.Link-Association field-customize:popup-general-table').click();
//关系字段组件可见,子表单/子表格中个别字段可见
await expect(
await page.getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo'),
).toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.email')).toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.phone')).not.toBeVisible();
});
});
test.describe('create', () => {
//关系字段有权限,关系目标表无权限
test('association field accept,target collection denied', async ({ page, mockPage, mockRole, mockRecord }) => {
await mockPage(oneTableBlock).goto();
await mockRecord('general');
//新建角色并切换到新角色
const roleData = await mockRole({
default: true,
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'users',
},
{
usingActionsConfig: true,
name: 'general',
actions: [
{ name: 'view', fields: ['oneToOneBelongsTo'] },
{ name: 'create', fields: ['oneToOneBelongsTo'] },
],
},
],
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
await page.getByLabel('action-Action-Add new-create').click();
//关系字段组件可见,子表单/子表格中字段不可见
await expect(
await page.getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo'),
).toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.email')).not.toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.phone')).not.toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.username')).not.toBeVisible();
});
//关系字段有权限,关系目标表个别字段有权限
test('association field accept, target collection accept with fields', async ({
page,
mockPage,
mockRole,
mockRecord,
}) => {
await mockPage(oneTableBlock).goto();
await mockRecord('general');
//新建角色并切换到新角色
const roleData = await mockRole({
default: true,
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'users',
actions: [{ name: 'view' }, { name: 'create', fields: ['email'] }],
},
{
usingActionsConfig: true,
name: 'general',
actions: [
{ name: 'view', fields: ['oneToOneBelongsTo'] },
{ name: 'create', fields: ['oneToOneBelongsTo'] },
],
},
],
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
await page.getByLabel('action-Action-Add new-create').click();
//关系字段组件可见,子表单/子表格中个别字段可见
await expect(
await page.getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo'),
).toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.email')).toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.phone')).not.toBeVisible();
await expect(await page.getByLabel('block-item-CollectionField-users-form-users.username')).not.toBeVisible();
});
});

View File

@ -0,0 +1,461 @@
import { expect, test } from '@nocobase/test/e2e';
import { oneTableBlock } from './utils';
test.describe('view', () => {
test('general permission', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage(oneTableBlock).goto();
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).not.toBeVisible();
await updateRole({
name: roleData.name,
strategy: {
actions: ['view'],
},
});
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
});
test('individual collection permission', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage(oneTableBlock).goto();
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
strategy: {
actions: ['view'],
},
resources: [
{
usingActionsConfig: true,
name: 'general',
},
],
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).not.toBeVisible();
await updateRole({
name: roleData.name,
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [{ name: 'view', fields: [] }],
},
],
});
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
await expect(page.getByRole('button', { name: 'singleLineText' })).not.toBeVisible();
await expect(page.getByRole('button', { name: 'phone' })).not.toBeVisible();
});
test('individual collection permission with fields', async ({ page, mockPage, mockRole }) => {
await mockPage(oneTableBlock).goto();
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [{ name: 'view', fields: ['singleLineText'] }],
},
],
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
//特定字段有权限
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
await expect(page.getByRole('button', { name: 'singleLineText' })).toBeVisible();
await expect(page.getByRole('button', { name: 'phone' })).not.toBeVisible();
});
});
test.describe('create', () => {
test('general permission', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage(oneTableBlock).goto();
//新建角色并切换到新角色
const roleData = await mockRole({
strategy: {
actions: ['view'],
},
allowNewMenu: true,
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
await expect(await page.getByLabel('action-Action-Add new-create-general-table')).not.toBeVisible();
await updateRole({
name: roleData.name,
strategy: {
actions: ['view', 'create'],
},
});
await page.reload();
await expect(await page.getByLabel('action-Action-Add new-create-general-table')).toBeVisible();
});
test('individual collection permission', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage(oneTableBlock).goto();
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
strategy: {
actions: ['create'],
},
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [
{
name: 'view',
},
],
},
],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await mockPage(oneTableBlock).goto();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
await expect(await page.getByLabel('action-Action-Add new-create-general-table')).not.toBeVisible();
await updateRole({
name: roleData.name,
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [
{
name: 'view',
},
{ name: 'create' },
],
},
],
});
await page.reload();
await expect(await page.getByLabel('action-Action-Add new-create-general-table')).toBeVisible();
});
test('individual collection permission width fields', async ({ page, mockPage, mockRole }) => {
await mockPage(oneTableBlock).goto();
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [
{
name: 'view',
fields: ['id', 'singleLineText'],
scope: null,
},
{
name: 'create',
fields: ['singleLineText'],
scope: null,
},
],
},
],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await mockPage(oneTableBlock).goto();
await expect(await page.getByLabel('action-Action-Add new-create-general-table')).toBeVisible();
await await page.getByLabel('action-Action-Add new-create-general-table').click();
await expect(page.getByLabel('block-item-CollectionField-general-form-general.singleLineText')).toBeVisible();
});
});
test.describe('update', () => {
test('general permission', async ({ page, mockPage, mockRole, mockRecord, updateRole }) => {
await mockPage(oneTableBlock).goto();
await mockRecord('general');
//新建角色并切换到新角色
const roleData = await mockRole({
strategy: {
actions: ['view'],
},
allowNewMenu: true,
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(await page.getByLabel('action-Action.Link-Edit')).not.toBeVisible();
await updateRole({
name: roleData.name,
strategy: {
actions: ['view', 'update'],
},
});
await page.reload();
await expect(await page.getByLabel('action-Action.Link-Edit')).toBeVisible();
});
test('individual collection permission', async ({ page, mockPage, mockRole, mockRecord, updateRole }) => {
await mockPage(oneTableBlock).goto();
await mockRecord('general');
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
strategy: {
actions: ['update'],
},
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [{ name: 'view' }],
},
],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await mockPage(oneTableBlock).goto();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
await expect(await page.getByLabel('action-Action.Link-Edit')).not.toBeVisible();
await updateRole({
name: roleData.name,
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [
{
name: 'view',
},
{ name: 'update' },
],
},
],
});
await page.reload();
await expect(await page.getByLabel('action-Action.Link-Edit')).toBeVisible();
});
test('individual collection permission with fields', async ({ page, mockPage, mockRole, mockRecord }) => {
await mockPage(oneTableBlock).goto();
await mockRecord('general');
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [{ name: 'view' }, { name: 'update', fields: ['singleLineText', 'phone', 'email'] }],
},
],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await mockPage(oneTableBlock).goto();
await expect(await page.getByLabel('action-Action.Link-Edit')).toBeVisible();
await page.getByLabel('action-Action.Link-Edit').click();
await expect(page.getByLabel('block-item-CollectionField-general-form-general.singleLineText')).toBeVisible();
await expect(page.getByLabel('block-item-CollectionField-general-form-general.phone')).toBeVisible();
await expect(page.getByLabel('block-item-CollectionField-general-form-general.email')).toBeVisible();
await expect(page.getByLabel('block-item-CollectionField-general-form-general.number')).not.toBeVisible();
});
});
test.describe('destroy', () => {
test('general permission', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage(oneTableBlock).goto();
//新建角色并切换到新角色
const roleData = await mockRole({
strategy: {
actions: ['view'],
},
allowNewMenu: true,
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(await page.getByLabel('action-Action-Delete-destroy-general-table')).not.toBeVisible();
await updateRole({
name: roleData.name,
strategy: {
actions: ['view', 'destroy'],
},
});
await page.reload();
await expect(await page.getByLabel('action-Action-Delete-destroy-general-table')).toBeVisible();
});
test('individual collection permission', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage().goto();
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
strategy: {
actions: ['destroy'],
},
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [{ name: 'view' }],
},
],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await mockPage(oneTableBlock).goto();
await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible();
await expect(await page.getByLabel('action-Action-Delete-destroy-general-table')).not.toBeVisible();
await updateRole({
name: roleData.name,
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [
{
name: 'view',
},
{ name: 'destroy' },
],
},
],
});
await page.reload();
await expect(await page.getByLabel('action-Action-Delete-destroy-general-table')).toBeVisible();
});
});
test.describe('export', () => {
test('general permission', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage(oneTableBlock).goto();
//新建角色并切换到新角色
const roleData = await mockRole({
strategy: {
actions: ['view'],
},
allowNewMenu: true,
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(await page.getByLabel('action-Action-Export')).not.toBeVisible();
await updateRole({
name: roleData.name,
strategy: {
actions: ['view', 'export'],
},
});
await page.reload();
await expect(await page.getByLabel('action-Action-Export')).toBeVisible();
});
test('individual collection permission', async ({ page, mockPage, mockRole }) => {
await mockPage().goto();
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [
{ name: 'view' },
{
name: 'export',
scope: null,
},
],
},
],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await mockPage(oneTableBlock).goto();
await expect(await page.getByLabel('action-Action-Export')).toBeVisible();
});
});
test.describe('import', () => {
test('general permission', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage().goto();
//新建角色并切换到新角色
const roleData = await mockRole({
strategy: {
actions: ['view'],
},
allowNewMenu: true,
});
await mockPage(oneTableBlock).goto();
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(await page.getByLabel('action-Action-Import')).not.toBeVisible();
await updateRole({
name: roleData.name,
strategy: {
actions: ['view', 'importXlsx'],
},
});
await page.reload();
await expect(await page.getByLabel('action-Action-Import')).toBeVisible();
});
test('individual collection permission', async ({ page, mockPage, mockRole }) => {
await mockPage().goto();
//新建角色并切换到新角色
const roleData = await mockRole({
allowNewMenu: true,
resources: [
{
usingActionsConfig: true,
name: 'general',
actions: [
{ name: 'view' },
{
name: 'importXlsx',
scope: null,
},
],
},
],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await mockPage(oneTableBlock).goto();
await expect(await page.getByLabel('action-Action-Import')).toBeVisible();
});
});

View File

@ -0,0 +1,151 @@
import { expect, test } from '@nocobase/test/e2e';
import { oneTableBlock } from './utils';
test('allows to configure interface', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage().goto();
//新建角色并切换到新角色
const roleData = await mockRole({
snippets: ['ui.*'],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(await page.getByTestId('ui-editor-button')).toBeVisible();
await expect(await page.getByTestId('schema-initializer-Menu-header')).toBeVisible();
//更新权限,无ui配置权限
await updateRole({
name: roleData.name,
snippets: ['!ui.*'],
});
await page.reload();
await expect(await page.getByTestId('ui-editor-button')).not.toBeVisible();
await expect(await page.getByTestId('schema-initializer-Menu-header')).not.toBeVisible();
});
test('allows to install ,install,disabled plugins ', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage().goto();
//新建角色并切换到新角色
const roleData = await mockRole({
snippets: ['pm'],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(await page.getByTestId('plugin-manager-button')).toBeVisible();
await page.getByTestId('plugin-manager-button').click();
await expect(await page.url()).toContain('/pm/list/local');
await expect(
await page.locator('.ant-page-header-heading').getByTitle('Plugin manager', { exact: true }),
).toBeVisible();
//无插件管理权限时访问直接路由访问时404
await updateRole({
name: roleData.name,
snippets: ['!pm'],
});
await page.reload();
await expect(await page.getByTestId('plugin-manager-button')).not.toBeVisible();
await page.goto('/pm/list/local');
await expect(await page.getByText('Sorry, the page you visited')).toBeVisible();
await expect(await page.getByRole('button', { name: 'Back Home' })).toBeVisible();
});
test('allows to confgiure plugins ', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage().goto();
//新建角色并切换到新角色
const roleData = await mockRole({
snippets: ['pm.*'],
strategy: {
actions: ['view', 'update'],
},
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await page.getByTestId('plugin-settings-button').click();
await page.getByLabel('acl').click();
await page.getByLabel(`action-Action.Link-Configure-roles-${roleData.name}`).click();
await expect(page.getByRole('tab').getByText('Plugin settings permissions')).toBeVisible();
await updateRole({
name: roleData.name,
snippets: ['!pm.*'],
});
await page.reload();
await expect(page.getByTestId('plugin-settings-button')).not.toBeVisible();
});
test('allows to clear cache,reboot application ', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage().goto();
//新建角色并切换到新角色
const roleData = await mockRole({
snippets: ['app'],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await page.getByTestId('user-center-button').hover();
await expect(await page.getByRole('menuitem', { name: 'Clear cache' })).toBeVisible();
await expect(await page.getByRole('menuitem', { name: 'Restart application' })).toBeVisible();
await updateRole({
name: roleData.name,
snippets: ['!app'],
});
await page.reload();
await page.getByTestId('user-center-button').hover();
await expect(await page.getByRole('menuitem', { name: 'Clear cache' })).not.toBeVisible();
await expect(await page.getByRole('menuitem', { name: 'Restart application' })).not.toBeVisible();
});
test('new menu items allow to be asscessed by default ', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage().goto();
//新建角色并切换到新角色
const roleData = await mockRole({
snippets: ['ui.*'],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await mockPage({ ...oneTableBlock, name: 'new page' }).goto();
await expect(page.getByLabel('new page')).not.toBeVisible();
await updateRole({
name: roleData.name,
allowNewMenu: true,
});
await mockPage({ ...oneTableBlock, name: 'new page' }).goto();
await expect(page.getByLabel('new page')).toBeVisible();
});
test('plugin settings permissions', async ({ page, mockPage, mockRole, updateRole }) => {
await mockPage().goto();
//新建角色并切换到新角色
const roleData = await mockRole({
snippets: ['pm', 'pm.*', '!pm.auth.authenticators', '!pm.collection-manager', '!pm.collection-manager.collections'],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await page.getByTestId('plugin-settings-button').hover();
await expect(await page.getByLabel('acl')).toBeVisible();
await expect(await page.getByLabel('auth')).not.toBeVisible();
await expect(await page.getByLabel('collection-manager')).not.toBeVisible();
await page.getByLabel('acl').click();
await expect(await page.getByRole('menuitem', { name: 'login Authentication' })).not.toBeVisible();
await expect(await page.getByRole('menuitem', { name: 'database Collection manager' })).not.toBeVisible();
await updateRole({
name: roleData.name,
snippets: ['pm', 'pm.*', 'pm.auth.authenticators', 'pm.collection-manager', 'pm.collection-manager.collections'],
});
await page.reload();
await page.getByTestId('plugin-settings-button').hover();
await expect(await page.getByLabel('acl')).toBeVisible();
await expect(await page.getByLabel('auth')).toBeVisible();
await expect(await page.getByLabel('collection-manager')).toBeVisible();
await page.getByLabel('acl').click();
await expect(await page.getByRole('menuitem', { name: 'login Authentication' })).toBeVisible();
await expect(await page.getByRole('menuitem', { name: 'database Collection manager' })).toBeVisible();
});

View File

@ -0,0 +1,50 @@
import { expect, test } from '@nocobase/test/e2e';
test('menu permission ', async ({ page, mockPage, mockRole, updateRole }) => {
const page2 = await mockPage({ name: 'page2' });
const page1 = await mockPage({ name: 'page1' });
await page1.goto();
const uid1 = await page1.getUid();
const uid2 = await page2.getUid();
//新建角色并切换到新角色page1有权限,page2无权限
const roleData = await mockRole({
snippets: ['pm.*'],
strategy: {
actions: ['view', 'update'],
},
menuUiSchemas: [uid1],
});
await page.evaluate((roleData) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(await page.getByLabel('page1')).toBeVisible();
await expect(await page.getByLabel('page2')).not.toBeVisible();
await page.getByTestId('plugin-settings-button').hover();
await page.getByLabel('acl').click();
await page.getByLabel(`action-Action.Link-Configure-roles-${roleData.name}`).click();
await page.getByRole('tab').getByText('Menu permissions').click();
await page.waitForSelector('.ant-table');
const page1Menu = await page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input');
const page2Menu = await page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input');
await expect(await page1Menu.isChecked()).toBe(true);
await expect(await page2Menu.isChecked()).toBe(false);
//修改菜单权限page1无权限,page2有权限
await updateRole({ name: roleData.name, menuUiSchemas: [uid2] });
await page.reload();
await expect(await page.getByLabel('page2')).toBeVisible();
await expect(await page.getByLabel('page1')).not.toBeVisible();
await page.getByTestId('plugin-settings-button').hover();
await page.getByLabel('acl').click();
await page.getByLabel(`action-Action.Link-Configure-roles-${roleData.name}`).click();
await page.getByRole('tab').getByText('Menu permissions').click();
await page.waitForSelector('.ant-table');
const page1Menu1 = await page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input');
const page2Menu1 = await page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input');
await expect(await page1Menu1.isChecked()).toBe(false);
await expect(await page2Menu1.isChecked()).toBe(true);
//通过路由访问无权限的菜单,跳到有权限的第一个菜单
await page.goto(`/admin/${uid1}`);
await page.waitForSelector('.nb-page-wrapper');
await expect(await page.url()).toContain(uid2);
});

File diff suppressed because it is too large Load Diff