playwright: migrate permission spec to playwright (#17795)

* playwright: remove organisation policy and role before staring the playwright test

* added default role as data consumer

* fixed failing test

* keeping org policies as it is.

* migrate permission spec

---------

Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
This commit is contained in:
Shailesh Parmar 2024-09-13 11:24:28 +05:30 committed by GitHub
parent 75588cf364
commit 0e75a9cceb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 472 additions and 462 deletions

View File

@ -1,439 +0,0 @@
/*
* Copyright 2024 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
interceptURL,
uuid,
verifyResponseStatusCode,
} from '../../common/common';
import UsersTestClass from '../../common/Entities/UserClass';
import { hardDeleteService } from '../../common/EntityUtils';
import {
createEntityTableViaREST,
visitEntityDetailsPage,
} from '../../common/Utils/Entity';
import { getToken } from '../../common/Utils/LocalStorage';
import { EntityType } from '../../constants/Entity.interface';
import { DATABASE_SERVICE, USER_DETAILS } from '../../constants/EntityConstant';
import { SERVICE_CATEGORIES } from '../../constants/service.constants';
type RoleType = {
name: string;
policies: string[];
id?: string;
};
type PolicyType = {
name: string;
rules: {
name: string;
resources: string[];
operations: string[];
effect: string;
}[];
id?: string;
};
type OrganizationTeamType = {
id: string;
policies: {
id: string;
type: string;
}[];
defaultRoles: {
id: string;
type: string;
}[];
};
const entity = new UsersTestClass();
const policy: PolicyType = {
name: `cy-permission-policy-${uuid()}`,
rules: [
{
name: `cy-permission-rule-${uuid()}`,
resources: ['All'],
operations: ['ViewBasic'],
effect: 'allow',
},
],
};
const role: RoleType = {
name: `cy-permission-role-${uuid()}`,
policies: [policy.name],
};
const tableFqn = `${DATABASE_SERVICE.entity.databaseSchema}.${DATABASE_SERVICE.entity.name}`;
const testSuite = {
name: `${tableFqn}.testSuite`,
executableEntityReference: tableFqn,
};
const testCase = {
name: `user_tokens_table_column_name_to_exist_${uuid()}`,
entityLink: `<#E::table::${testSuite.executableEntityReference}>`,
parameterValues: [{ name: 'columnName', value: 'id' }],
testDefinition: 'tableColumnNameToExist',
description: 'test case description',
testSuite: testSuite.name,
};
let organizationTeam = {} as OrganizationTeamType;
let userId = '';
let teamId = '';
const viewPermissions = [
{
title: 'ViewBasic, ViewSampleData & ViewQueries permission',
data: {
patch: [
{ op: 'add', path: '/rules/0/operations/1', value: 'ViewSampleData' },
{ op: 'add', path: '/rules/0/operations/2', value: 'ViewQueries' },
],
permission: { viewSampleData: true, viewQueries: true },
},
},
{
title: 'ViewBasic, ViewSampleData, ViewQueries & ViewTests permission',
data: {
patch: [{ op: 'add', path: '/rules/0/operations/3', value: 'ViewTests' }],
permission: {
viewSampleData: true,
viewQueries: true,
viewTests: true,
},
},
},
{
title: 'EditDisplayName permission',
data: {
patch: [
{ op: 'add', path: '/rules/0/operations/4', value: 'EditDisplayName' },
],
permission: {
viewSampleData: true,
viewQueries: true,
viewTests: true,
editDisplayName: true,
},
},
},
];
const createViewBasicRoleViaREST = ({ token }) => {
cy.request({
method: 'POST',
url: `/api/v1/policies`,
headers: { Authorization: `Bearer ${token}` },
body: policy,
}).then((policyResponse) => {
policy.id = policyResponse.body.id;
cy.request({
method: 'POST',
url: `/api/v1/roles`,
headers: { Authorization: `Bearer ${token}` },
body: role,
}).then((roleResponse) => {
role.id = roleResponse.body.id;
cy.request({
method: 'GET',
url: `/api/v1/teams/name/Organization?fields=defaultRoles,policies`,
headers: { Authorization: `Bearer ${token}` },
}).then((orgResponse) => {
organizationTeam = orgResponse.body;
cy.request({
method: 'PATCH',
url: `/api/v1/teams/${orgResponse.body.id}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json-patch+json',
},
body: [
{
op: 'replace',
path: '/policies',
value: [
{
id: policyResponse.body.id,
type: 'policy',
},
],
},
{
op: 'replace',
path: '/defaultRoles',
value: [
{
id: roleResponse.body.id,
type: 'role',
},
],
},
],
});
cy.request({
method: 'POST',
url: `/api/v1/users/signup`,
headers: { Authorization: `Bearer ${token}` },
body: USER_DETAILS,
}).then((userResponse) => {
userId = userResponse.body.id;
cy.request({
method: 'POST',
url: `/api/v1/teams`,
headers: { Authorization: `Bearer ${token}` },
body: {
name: `teamBasic-${uuid()}`,
description: 'teamBasic',
teamType: 'Group',
defaultRoles: [roleResponse.body.id],
policies: [policyResponse.body.id],
users: [userResponse.body.id],
},
}).then((teamResponse) => {
teamId = teamResponse.body.id;
});
});
});
});
});
};
const preRequisite = () => {
cy.login();
cy.getAllLocalStorage().then((data) => {
const token = getToken(data);
createViewBasicRoleViaREST({
token,
});
createEntityTableViaREST({
token,
...DATABASE_SERVICE,
tables: [],
});
cy.request({
method: 'POST',
url: `/api/v1/tables`,
headers: { Authorization: `Bearer ${token}` },
body: DATABASE_SERVICE.entity,
}).then((response) => {
cy.request({
method: 'POST',
url: `/api/v1/queries`,
headers: { Authorization: `Bearer ${token}` },
body: {
query: `select * from dim_address_${uuid()}`,
queryUsedIn: [{ id: response.body.id, type: 'table' }],
queryDate: Date.now(),
service: 'sample_data',
},
});
cy.request({
method: 'POST',
url: `/api/v1/dataQuality/testSuites/executable`,
headers: { Authorization: `Bearer ${token}` },
body: testSuite,
}).then(() => {
cy.request({
method: 'POST',
url: `/api/v1/dataQuality/testCases`,
headers: { Authorization: `Bearer ${token}` },
body: testCase,
});
});
});
});
cy.logout();
};
const cleanUp = () => {
cy.login();
cy.getAllLocalStorage().then((data) => {
const token = getToken(data);
hardDeleteService({
token,
serviceFqn: DATABASE_SERVICE.service.name,
serviceType: SERVICE_CATEGORIES.DATABASE_SERVICES,
});
cy.request({
method: 'DELETE',
url: `/api/v1/roles/${role.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
cy.request({
method: 'DELETE',
url: `/api/v1/policies/${policy.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
cy.request({
method: 'PATCH',
url: `/api/v1/teams/${organizationTeam.id}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json-patch+json',
},
body: [
{
op: 'replace',
path: '/policies',
value: organizationTeam.policies,
},
{
op: 'add',
path: '/defaultRoles',
value: organizationTeam.defaultRoles,
},
],
});
// Delete created user
cy.request({
method: 'DELETE',
url: `/api/v1/users/${userId}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
// Delete created team
cy.request({
method: 'DELETE',
url: `/api/v1/teams/${teamId}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
});
};
const checkPermission = (permission?: {
viewSampleData?: boolean;
viewQueries?: boolean;
viewTests?: boolean;
editDisplayName?: boolean;
}) => {
cy.login(USER_DETAILS.email, USER_DETAILS.password);
visitEntityDetailsPage({
term: DATABASE_SERVICE.entity.name,
serviceName: DATABASE_SERVICE.service.name,
entity: EntityType.Table,
});
entity.viewPermissions(permission);
cy.logout();
};
const updatePolicy = (
patch: { op: string; path: string; value: unknown }[]
) => {
cy.login();
cy.getAllLocalStorage().then((data) => {
const token = getToken(data);
cy.request({
method: 'PATCH',
url: `/api/v1/policies/${policy.id}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json-patch+json',
},
body: patch,
});
});
cy.logout();
cy.reload();
};
describe('Permissions', { tags: 'Settings' }, () => {
before(preRequisite);
after(cleanUp);
it('ViewBasic permission', () => {
checkPermission();
});
viewPermissions.forEach((permissionData) => {
it(`check ${permissionData.title}`, () => {
updatePolicy(permissionData.data.patch);
checkPermission(permissionData.data.permission);
});
});
it('EditQuery permission', () => {
updatePolicy([
{
op: 'add',
path: '/rules/1',
value: {
name: `cy-edit-query-rule-${uuid()}`,
resources: ['query'],
operations: ['ViewAll', 'EditAll'],
effect: 'allow',
},
},
{ op: 'add', path: '/rules/0/operations/5', value: 'EditQueries' },
]);
cy.login(USER_DETAILS.email, USER_DETAILS.password);
visitEntityDetailsPage({
term: DATABASE_SERVICE.entity.name,
serviceName: DATABASE_SERVICE.service.name,
entity: EntityType.Table,
});
interceptURL(
'GET',
'/api/v1/search/query?q=*&index=query_search_index*',
'getQueries'
);
cy.get('[data-testid="table_queries"]').click();
verifyResponseStatusCode('@getQueries', 200);
cy.get('[data-testid="query-btn"]').click();
cy.get('[data-menu-id*="edit-query"]').click();
interceptURL('PATCH', '/api/v1/queries/*', 'updateQuery');
cy.get('.CodeMirror-line').click().type('updated');
cy.get('[data-testid="save-query-btn"]').click();
verifyResponseStatusCode('@updateQuery', 200);
cy.logout();
});
it('EditTest permission', () => {
updatePolicy([
{ op: 'add', path: '/rules/1/operations/6', value: 'EditTests' },
{
op: 'add',
path: '/rules/2',
value: {
name: `cy-edit-test-case-rule-${uuid()}`,
resources: ['testCase'],
operations: ['ViewAll', 'EditAll'],
effect: 'allow',
},
},
]);
cy.login(USER_DETAILS.email, USER_DETAILS.password);
visitEntityDetailsPage({
term: DATABASE_SERVICE.entity.name,
serviceName: DATABASE_SERVICE.service.name,
entity: EntityType.Table,
});
interceptURL(
'GET',
'/api/v1/dataQuality/testCases/search/list?fields=*',
'testCase'
);
cy.get('[data-testid="profiler"]').click();
cy.get('[data-testid="profiler-tab-left-panel"]')
.contains('Data Quality')
.click();
verifyResponseStatusCode('@testCase', 200);
cy.get(`[data-testid="edit-${testCase.name}"]`).click();
cy.get('#tableTestForm_params_columnName')
.scrollIntoView()
.clear()
.type('test');
interceptURL('PATCH', '/api/v1/dataQuality/testCases/*', 'updateTest');
cy.get('.ant-modal-footer').contains('Submit').click();
verifyResponseStatusCode('@updateTest', 200);
});
});

View File

@ -0,0 +1,271 @@
/*
* Copyright 2024 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Page, test as base } from '@playwright/test';
import { Operation } from 'fast-json-patch';
import { PolicyClass } from '../../support/access-control/PoliciesClass';
import { RolesClass } from '../../support/access-control/RolesClass';
import { TableClass } from '../../support/entity/TableClass';
import { UserClass } from '../../support/user/UserClass';
import { performAdminLogin } from '../../utils/admin';
import { getApiContext, redirectToHomePage, uuid } from '../../utils/common';
import { validateViewPermissions } from '../../utils/permission';
const policy = new PolicyClass();
const policy2 = new PolicyClass();
const role = new RolesClass();
const role2 = new RolesClass();
const user = new UserClass();
const table = new TableClass();
const viewPermissionsData = [
{
title: 'ViewBasic, ViewSampleData & ViewQueries permission',
data: {
patch: [
{ op: 'add', path: '/rules/0/operations/1', value: 'ViewSampleData' },
{ op: 'add', path: '/rules/0/operations/2', value: 'ViewQueries' },
],
permission: { viewSampleData: true, viewQueries: true },
},
},
{
title: 'ViewBasic, ViewSampleData, ViewQueries & ViewTests permission',
data: {
patch: [{ op: 'add', path: '/rules/0/operations/3', value: 'ViewTests' }],
permission: {
viewSampleData: true,
viewQueries: true,
viewTests: true,
},
},
},
{
title: 'EditDisplayName permission',
data: {
patch: [
{ op: 'add', path: '/rules/0/operations/4', value: 'EditDisplayName' },
],
permission: {
viewSampleData: true,
viewQueries: true,
viewTests: true,
editDisplayName: true,
},
},
},
];
const test = base.extend<{
adminPage: Page;
userPage: Page;
}>({
adminPage: async ({ browser }, use) => {
const { page } = await performAdminLogin(browser);
await use(page);
await page.close();
},
userPage: async ({ browser }, use) => {
const page = await browser.newPage();
await user.login(page);
await use(page);
await page.close();
},
});
test.beforeAll(async ({ browser }) => {
const { apiContext, afterAction } = await performAdminLogin(browser);
await user.create(apiContext);
const policyResponse = await policy.create(apiContext, [
{
name: `pw-permission-rule-${uuid()}`,
resources: ['All'],
operations: ['ViewBasic'],
effect: 'allow',
},
]);
const policyResponse2 = await policy2.create(apiContext, [
{
name: `pw-permission-rule-${uuid()}`,
resources: ['All'],
operations: ['EditOwners'],
effect: 'deny',
},
]);
await table.create(apiContext);
await table.createTestCase(apiContext);
await table.createQuery(apiContext);
const roleResponse = await role.create(apiContext, [
policyResponse.fullyQualifiedName,
]);
const roleResponse2 = await role2.create(apiContext, [
policyResponse2.fullyQualifiedName,
]);
await user.patch({
apiContext,
patchData: [
{
op: 'replace',
path: '/roles',
value: [
{
id: roleResponse.id,
type: 'role',
name: roleResponse.name,
},
{
id: roleResponse2.id,
type: 'role',
name: roleResponse2.name,
},
],
},
],
});
await afterAction();
});
test.afterAll(async ({ browser }) => {
const { apiContext, afterAction } = await performAdminLogin(browser);
await user.delete(apiContext);
await role.delete(apiContext);
await policy.delete(apiContext);
await table.delete(apiContext);
await afterAction();
});
test('Permissions', async ({ userPage, adminPage }) => {
test.slow();
await redirectToHomePage(userPage);
await test.step('ViewBasic permission', async () => {
await table.visitEntityPage(userPage);
await userPage.waitForSelector('[data-testid="loader"]', {
state: 'detached',
});
await validateViewPermissions(userPage);
});
for (const viewPermission of viewPermissionsData) {
await test.step(viewPermission.title, async () => {
const { apiContext, afterAction } = await getApiContext(adminPage);
await policy.patch(apiContext, viewPermission.data.patch as Operation[]);
await afterAction();
await redirectToHomePage(userPage);
await userPage.reload();
const permissionResponse = userPage.waitForResponse(
`/api/v1/permissions/table/name/${encodeURIComponent(
table.entityResponseData?.['fullyQualifiedName']
)}`
);
await table.visitEntityPage(userPage);
await permissionResponse;
await userPage.waitForSelector('[data-testid="loader"]', {
state: 'detached',
});
await validateViewPermissions(userPage, viewPermission.data.permission);
});
}
await test.step('EditQuery permission', async () => {
const { apiContext, afterAction } = await getApiContext(adminPage);
await policy.patch(apiContext, [
{
op: 'add',
path: '/rules/1',
value: {
name: `pw-edit-query-rule-${uuid()}`,
resources: ['query'],
operations: ['ViewAll', 'EditAll'],
effect: 'allow',
},
},
{ op: 'add', path: '/rules/0/operations/5', value: 'EditQueries' },
]);
await afterAction();
await redirectToHomePage(userPage);
await userPage.reload();
const permissionResponse = userPage.waitForResponse(
`/api/v1/permissions/table/name/${encodeURIComponent(
table.entityResponseData?.['fullyQualifiedName']
)}`
);
await table.visitEntityPage(userPage);
await permissionResponse;
await userPage.waitForSelector('[data-testid="loader"]', {
state: 'detached',
});
const queryListResponse = userPage.waitForResponse(
'/api/v1/search/query?q=*&index=query_search_index*'
);
await userPage.click('[data-testid="table_queries"]');
await queryListResponse;
await userPage.click('[data-testid="query-btn"]');
await userPage.click('[data-menu-id*="edit-query"]');
await userPage.locator('.CodeMirror-line').click();
await userPage.keyboard.type('updated');
const saveQueryResponse = userPage.waitForResponse('/api/v1/queries/*');
await userPage.click('[data-testid="save-query-btn"]');
await saveQueryResponse;
});
await test.step('EditTest permission', async () => {
const testCaseName = table.testCasesResponseData[0]?.['name'];
const { apiContext, afterAction } = await getApiContext(adminPage);
await policy.patch(apiContext, [
{ op: 'add', path: '/rules/1/operations/6', value: 'EditTests' },
{
op: 'add',
path: '/rules/2',
value: {
name: `cy-edit-test-case-rule-${uuid()}`,
resources: ['testCase'],
operations: ['ViewAll', 'EditAll'],
effect: 'allow',
},
},
]);
await afterAction();
await redirectToHomePage(userPage);
await userPage.reload();
const permissionResponse = userPage.waitForResponse(
`/api/v1/permissions/table/name/${encodeURIComponent(
table.entityResponseData?.['fullyQualifiedName']
)}`
);
await table.visitEntityPage(userPage);
await permissionResponse;
await userPage.waitForSelector('[data-testid="loader"]', {
state: 'detached',
});
await userPage.getByTestId('profiler').click();
const testCaseResponse = userPage.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?fields=*'
);
await userPage
.getByTestId('profiler-tab-left-panel')
.getByText('Data Quality')
.click();
await testCaseResponse;
await userPage.getByTestId(`edit-${testCaseName}`).click();
await userPage.locator('#tableTestForm_displayName').clear();
await userPage.fill('#tableTestForm_displayName', 'Update_display_name');
const saveTestResponse = userPage.waitForResponse(
'/api/v1/dataQuality/testCases/*'
);
await userPage.locator('.ant-modal-footer').getByText('Submit').click();
await saveTestResponse;
});
});

View File

@ -63,27 +63,6 @@ entities.forEach((EntityClass) => {
await user.create(apiContext); await user.create(apiContext);
const dataConsumerRoleResponse = await apiContext.get(
'/api/v1/roles/name/DataConsumer'
);
const dataConsumerRole = await dataConsumerRoleResponse.json();
await user.patch({
apiContext,
patchData: [
{
op: 'add',
path: '/roles/0',
value: {
id: dataConsumerRole.id,
type: 'role',
name: dataConsumerRole.name,
},
},
],
});
await EntityDataClass.preRequisitesForTests(apiContext); await EntityDataClass.preRequisitesForTests(apiContext);
await entity.create(apiContext); await entity.create(apiContext);
await afterAction(); await afterAction();

View File

@ -15,6 +15,7 @@ import { JWT_EXPIRY_TIME_MAP } from '../constant/login';
import { AdminClass } from '../support/user/AdminClass'; import { AdminClass } from '../support/user/AdminClass';
import { getApiContext } from '../utils/common'; import { getApiContext } from '../utils/common';
import { updateJWTTokenExpiryTime } from '../utils/login'; import { updateJWTTokenExpiryTime } from '../utils/login';
import { removeOrganizationPolicyAndRole } from '../utils/team';
const adminFile = 'playwright/.auth/admin.json'; const adminFile = 'playwright/.auth/admin.json';
setup('authenticate as admin', async ({ page }) => { setup('authenticate as admin', async ({ page }) => {
@ -25,6 +26,7 @@ setup('authenticate as admin', async ({ page }) => {
await page.waitForURL('**/my-data'); await page.waitForURL('**/my-data');
const { apiContext, afterAction } = await getApiContext(page); const { apiContext, afterAction } = await getApiContext(page);
await updateJWTTokenExpiryTime(apiContext, JWT_EXPIRY_TIME_MAP['4 hours']); await updateJWTTokenExpiryTime(apiContext, JWT_EXPIRY_TIME_MAP['4 hours']);
await removeOrganizationPolicyAndRole(apiContext);
await afterAction(); await afterAction();
await admin.logout(page); await admin.logout(page);
await page.waitForURL('**/signin'); await page.waitForURL('**/signin');

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { APIRequestContext } from '@playwright/test'; import { APIRequestContext } from '@playwright/test';
import { Operation } from 'fast-json-patch';
import { uuid } from '../../utils/common'; import { uuid } from '../../utils/common';
type ResponseDataType = { type ResponseDataType = {
@ -55,6 +56,22 @@ export class PolicyClass {
return data; return data;
} }
async patch(apiContext: APIRequestContext, patchData: Operation[]) {
const response = await apiContext.patch(
`/api/v1/policies/${this.responseData.id}`,
{
data: patchData,
headers: {
'Content-Type': 'application/json-patch+json',
},
}
);
const data = await response.json();
this.responseData = data;
return data;
}
async delete(apiContext: APIRequestContext) { async delete(apiContext: APIRequestContext) {
const response = await apiContext.delete( const response = await apiContext.delete(
`/api/v1/policies/${this.responseData.id}?hardDelete=true&recursive=true` `/api/v1/policies/${this.responseData.id}?hardDelete=true&recursive=true`

View File

@ -110,6 +110,7 @@ export class TableClass extends EntityClass {
testSuiteResponseData: unknown; testSuiteResponseData: unknown;
testSuitePipelineResponseData: unknown[] = []; testSuitePipelineResponseData: unknown[] = [];
testCasesResponseData: unknown[] = []; testCasesResponseData: unknown[] = [];
queryResponseData: unknown[] = [];
constructor(name?: string) { constructor(name?: string) {
super(EntityTypeEndpoint.Table); super(EntityTypeEndpoint.Table);
@ -172,6 +173,25 @@ export class TableClass extends EntityClass {
}); });
} }
async createQuery(apiContext: APIRequestContext, queryText?: string) {
const queryResponse = await apiContext.post('/api/v1/queries', {
data: {
query:
queryText ??
`select * from ${this.entityResponseData?.['fullyQualifiedName']}`,
queryUsedIn: [{ id: this.entityResponseData?.['id'], type: 'table' }],
queryDate: Date.now(),
service: this.serviceResponseData?.['name'],
},
});
const query = await queryResponse.json();
this.queryResponseData.push(query);
return query;
}
async createTestSuiteAndPipelines( async createTestSuiteAndPipelines(
apiContext: APIRequestContext, apiContext: APIRequestContext,
testSuite?: TestSuiteData testSuite?: TestSuiteData

View File

@ -48,13 +48,33 @@ export class UserClass {
} }
async create(apiContext: APIRequestContext) { async create(apiContext: APIRequestContext) {
const dataConsumerRoleResponse = await apiContext.get(
'/api/v1/roles/name/DataConsumer'
);
const dataConsumerRole = await dataConsumerRoleResponse.json();
const response = await apiContext.post('/api/v1/users/signup', { const response = await apiContext.post('/api/v1/users/signup', {
data: this.data, data: this.data,
}); });
this.responseData = await response.json(); this.responseData = await response.json();
const { entity } = await this.patch({
apiContext,
patchData: [
{
op: 'add',
path: '/roles/0',
value: {
id: dataConsumerRole.id,
type: 'role',
name: dataConsumerRole.name,
},
},
],
});
return response.body; return entity;
} }
async patch({ async patch({

View File

@ -0,0 +1,119 @@
/*
* Copyright 2024 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { expect, Page } from '@playwright/test';
export const checkNoPermissionPlaceholder = async (
page: Page,
label: string | RegExp,
permission = false
) => {
const placeholder = page
.getByLabel(label)
.locator('[data-testid="permission-error-placeholder"]');
if (permission) {
await expect(placeholder).not.toBeVisible();
} else {
await expect(placeholder).toBeVisible();
await expect(placeholder).toContainText(
'You dont have access, please check with the admin to get permissions'
);
}
};
export const validateViewPermissions = async (
page: Page,
permission?: {
viewSampleData?: boolean;
viewQueries?: boolean;
viewTests?: boolean;
editDisplayName?: boolean;
}
) => {
// check Add domain permission
await expect(page.locator('[data-testid="add-domain"]')).not.toBeVisible();
await expect(
page.locator('[data-testid="edit-displayName-button"]')
).toHaveCount(permission?.editDisplayName ? 6 : 0);
// check edit owner permission
await expect(page.locator('[data-testid="edit-owner"]')).not.toBeVisible();
// check edit description permission
await expect(
page.locator('[data-testid="edit-description"]')
).not.toBeVisible();
// check edit tier permission
await expect(page.locator('[data-testid="edit-tier"]')).not.toBeVisible();
// check add tags button
await expect(
page.locator(
'[data-testid="tags-container"] > [data-testid="entity-tags"] .ant-tag'
)
).not.toBeVisible();
// check add glossary term button
await expect(
page.locator(
'[data-testid="glossary-container"] > [data-testid="entity-tags"] .ant-tag'
)
).not.toBeVisible();
// check manage button
await expect(page.locator('[data-testid="manage-button"]')).toHaveCount(
permission?.editDisplayName ? 1 : 0
);
if (permission?.editDisplayName) {
await page.click('[data-testid="manage-button"]');
await page.click('[data-testid="rename-button"]');
await page.fill('#displayName', 'updated-table-name');
const updateDisplayNameResponse = page.waitForResponse(
(response) =>
response.url().includes('api/v1/tables/') && response.status() === 200
);
await page.click('[data-testid="save-button"]');
await updateDisplayNameResponse;
await expect(
page.locator('[data-testid="entity-header-display-name"]')
).toContainText('updated-table-name');
}
await page.click('[data-testid="sample_data"]');
await page.waitForLoadState('domcontentloaded');
await checkNoPermissionPlaceholder(
page,
/Sample Data/,
permission?.viewSampleData
);
await page.click('[data-testid="table_queries"]');
await page.waitForLoadState('domcontentloaded');
await checkNoPermissionPlaceholder(page, /Queries/, permission?.viewQueries);
await page.click('[data-testid="profiler"]');
await page.waitForLoadState('domcontentloaded');
await checkNoPermissionPlaceholder(
page,
/Profiler & Data Quality/,
permission?.viewTests
);
await page.click('[data-testid="lineage"]');
await page.waitForLoadState('domcontentloaded');
await expect(page.locator('[data-testid="edit-lineage"]')).toBeDisabled();
await page.click('[data-testid="custom_properties"]');
await page.waitForLoadState('domcontentloaded');
await checkNoPermissionPlaceholder(page, /Custom Properties/);
};

View File

@ -10,7 +10,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { expect, Page } from '@playwright/test'; import { APIRequestContext, expect, Page } from '@playwright/test';
import { descriptionBox, toastNotification, uuid } from './common'; import { descriptionBox, toastNotification, uuid } from './common';
import { validateFormNameFieldInput } from './form'; import { validateFormNameFieldInput } from './form';
@ -204,3 +204,24 @@ export const addTeamHierarchy = async (
await page.click('[form="add-team-form"]'); await page.click('[form="add-team-form"]');
await saveTeamResponse; await saveTeamResponse;
}; };
export const removeOrganizationPolicyAndRole = async (
apiContext: APIRequestContext
) => {
const organizationTeamResponse = await apiContext
.get(`/api/v1/teams/name/Organization`)
.then((res) => res.json());
await apiContext.patch(`/api/v1/teams/${organizationTeamResponse.id}`, {
data: [
{
op: 'replace',
path: '/defaultRoles',
value: [],
},
],
headers: {
'Content-Type': 'application/json-patch+json',
},
});
};