mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-16 10:08:08 +00:00
fetch domains before any widget is loaded (#17695)
* fix domain init ordering * move domains call at the beginning * fix tests * fix tests * fix flaky tests * fix flaky tests (cherry picked from commit 1dc15bc49376d2c117dcc297c05f120f1f595bad)
This commit is contained in:
parent
32a85c0c96
commit
d46540ea0f
@ -1,442 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2023 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 {
|
|
||||||
addTableFieldTags,
|
|
||||||
deleteEntity,
|
|
||||||
interceptURL,
|
|
||||||
removeTableFieldTags,
|
|
||||||
updateTableFieldDescription,
|
|
||||||
verifyResponseStatusCode,
|
|
||||||
} from '../../common/common';
|
|
||||||
import {
|
|
||||||
createSingleLevelEntity,
|
|
||||||
hardDeleteService,
|
|
||||||
} from '../../common/EntityUtils';
|
|
||||||
import { visitEntityDetailsPage } from '../../common/Utils/Entity';
|
|
||||||
import { getToken } from '../../common/Utils/LocalStorage';
|
|
||||||
import { BASE_URL } from '../../constants/constants';
|
|
||||||
import { EntityType } from '../../constants/Entity.interface';
|
|
||||||
import {
|
|
||||||
POLICY_DETAILS,
|
|
||||||
ROLE_DETAILS,
|
|
||||||
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST,
|
|
||||||
SEARCH_INDEX_DISPLAY_NAME,
|
|
||||||
SEARCH_SERVICE_DETAILS,
|
|
||||||
TAG_1,
|
|
||||||
UPDATE_FIELD_DESCRIPTION,
|
|
||||||
USER_CREDENTIALS,
|
|
||||||
} from '../../constants/SearchIndexDetails.constants';
|
|
||||||
|
|
||||||
const performCommonOperations = () => {
|
|
||||||
// User should be able to edit search index field tags
|
|
||||||
addTableFieldTags(
|
|
||||||
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.fields[0].fullyQualifiedName,
|
|
||||||
TAG_1.classification,
|
|
||||||
TAG_1.tag,
|
|
||||||
'searchIndexes'
|
|
||||||
);
|
|
||||||
removeTableFieldTags(
|
|
||||||
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.fields[0].fullyQualifiedName,
|
|
||||||
TAG_1.classification,
|
|
||||||
TAG_1.tag,
|
|
||||||
'searchIndexes'
|
|
||||||
);
|
|
||||||
|
|
||||||
// User should be able to edit search index field description
|
|
||||||
updateTableFieldDescription(
|
|
||||||
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.fields[0].fullyQualifiedName,
|
|
||||||
UPDATE_FIELD_DESCRIPTION,
|
|
||||||
'searchIndexes'
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(
|
|
||||||
`[data-row-key="${SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.fields[0].fullyQualifiedName}"] [data-testid="description"]`
|
|
||||||
).contains(UPDATE_FIELD_DESCRIPTION);
|
|
||||||
|
|
||||||
updateTableFieldDescription(
|
|
||||||
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.fields[0].fullyQualifiedName,
|
|
||||||
' ',
|
|
||||||
'searchIndexes'
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(
|
|
||||||
`[data-row-key="${SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.fields[0].fullyQualifiedName}"] [data-testid="description"]`
|
|
||||||
).contains('No Description');
|
|
||||||
};
|
|
||||||
|
|
||||||
describe(
|
|
||||||
'SearchIndexDetails page should work properly for data consumer role',
|
|
||||||
{ tags: 'DataAssets' },
|
|
||||||
() => {
|
|
||||||
const data = { user: { id: '' } };
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
cy.login();
|
|
||||||
cy.getAllLocalStorage().then((storageData) => {
|
|
||||||
const token = getToken(storageData);
|
|
||||||
|
|
||||||
// Create search index entity
|
|
||||||
createSingleLevelEntity({
|
|
||||||
token,
|
|
||||||
...SEARCH_SERVICE_DETAILS,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a new user
|
|
||||||
cy.request({
|
|
||||||
method: 'POST',
|
|
||||||
url: `/api/v1/users/signup`,
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
body: USER_CREDENTIALS,
|
|
||||||
}).then((response) => {
|
|
||||||
data.user = response.body;
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.logout();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
cy.login();
|
|
||||||
|
|
||||||
cy.getAllLocalStorage().then((storageData) => {
|
|
||||||
const token = getToken(storageData);
|
|
||||||
|
|
||||||
// Delete search index
|
|
||||||
hardDeleteService({
|
|
||||||
token,
|
|
||||||
serviceFqn: SEARCH_SERVICE_DETAILS.service.name,
|
|
||||||
serviceType: SEARCH_SERVICE_DETAILS.serviceType,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete created user
|
|
||||||
cy.request({
|
|
||||||
method: 'DELETE',
|
|
||||||
url: `/api/v1/users/${data.user.id}?hardDelete=true&recursive=false`,
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// Login with the created user
|
|
||||||
cy.login(USER_CREDENTIALS.email, USER_CREDENTIALS.password);
|
|
||||||
|
|
||||||
cy.url().should('eq', `${BASE_URL}/my-data`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('All permissible actions on search index details page should work properly', () => {
|
|
||||||
visitEntityDetailsPage({
|
|
||||||
term: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.name,
|
|
||||||
serviceName: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.service,
|
|
||||||
entity: EntityType.SearchIndex,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Edit domain option should not be available
|
|
||||||
cy.get(
|
|
||||||
`[data-testid="entity-page-header"] [data-testid="add-domain"]`
|
|
||||||
).should('not.exist');
|
|
||||||
|
|
||||||
// Manage button should not be visible on service page
|
|
||||||
cy.get(
|
|
||||||
'[data-testid="asset-header-btn-group"] [data-testid="manage-button"]'
|
|
||||||
).should('not.exist');
|
|
||||||
|
|
||||||
performCommonOperations();
|
|
||||||
|
|
||||||
cy.logout();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
describe('SearchIndexDetails page should work properly for data steward role', () => {
|
|
||||||
const data = {
|
|
||||||
user: { id: '' },
|
|
||||||
policy: { id: '' },
|
|
||||||
role: { id: '', name: '' },
|
|
||||||
};
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
cy.login();
|
|
||||||
cy.getAllLocalStorage().then((storageData) => {
|
|
||||||
const token = getToken(storageData);
|
|
||||||
|
|
||||||
// Create search index entity
|
|
||||||
createSingleLevelEntity({
|
|
||||||
token,
|
|
||||||
...SEARCH_SERVICE_DETAILS,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create Data Steward Policy
|
|
||||||
cy.request({
|
|
||||||
method: 'POST',
|
|
||||||
url: `/api/v1/policies`,
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
body: POLICY_DETAILS,
|
|
||||||
}).then((policyResponse) => {
|
|
||||||
data.policy = policyResponse.body;
|
|
||||||
|
|
||||||
// Create Data Steward Role
|
|
||||||
cy.request({
|
|
||||||
method: 'POST',
|
|
||||||
url: `/api/v1/roles`,
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
body: ROLE_DETAILS,
|
|
||||||
}).then((roleResponse) => {
|
|
||||||
data.role = roleResponse.body;
|
|
||||||
|
|
||||||
// Create a new user
|
|
||||||
cy.request({
|
|
||||||
method: 'POST',
|
|
||||||
url: `/api/v1/users/signup`,
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
body: USER_CREDENTIALS,
|
|
||||||
}).then((userResponse) => {
|
|
||||||
data.user = userResponse.body;
|
|
||||||
|
|
||||||
// Assign data steward role to the user
|
|
||||||
cy.request({
|
|
||||||
method: 'PATCH',
|
|
||||||
url: `/api/v1/users/${data.user.id}`,
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json-patch+json',
|
|
||||||
},
|
|
||||||
body: [
|
|
||||||
{
|
|
||||||
op: 'add',
|
|
||||||
path: '/roles/0',
|
|
||||||
value: {
|
|
||||||
id: data.role.id,
|
|
||||||
type: 'role',
|
|
||||||
name: data.role.name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.logout();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
cy.login();
|
|
||||||
|
|
||||||
cy.getAllLocalStorage().then((storageData) => {
|
|
||||||
const token = getToken(storageData);
|
|
||||||
|
|
||||||
// Delete created user
|
|
||||||
cy.request({
|
|
||||||
method: 'DELETE',
|
|
||||||
url: `/api/v1/users/${data.user.id}?hardDelete=true&recursive=false`,
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete policy
|
|
||||||
cy.request({
|
|
||||||
method: 'DELETE',
|
|
||||||
url: `/api/v1/policies/${data.policy.id}?hardDelete=true&recursive=false`,
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete role
|
|
||||||
cy.request({
|
|
||||||
method: 'DELETE',
|
|
||||||
url: `/api/v1/roles/${data.role.id}?hardDelete=true&recursive=false`,
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete search index
|
|
||||||
hardDeleteService({
|
|
||||||
token,
|
|
||||||
serviceFqn: SEARCH_SERVICE_DETAILS.service.name,
|
|
||||||
serviceType: SEARCH_SERVICE_DETAILS.serviceType,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// Login with the created user
|
|
||||||
cy.login(USER_CREDENTIALS.email, USER_CREDENTIALS.password);
|
|
||||||
|
|
||||||
cy.url().should('eq', `${BASE_URL}/my-data`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('All permissible actions on search index details page should work properly', () => {
|
|
||||||
visitEntityDetailsPage({
|
|
||||||
term: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.name,
|
|
||||||
serviceName: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.service,
|
|
||||||
entity: EntityType.SearchIndex,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Edit domain option should not be available
|
|
||||||
cy.get(`[data-testid="entity-page-header"]`).then(($body) => {
|
|
||||||
const editDomain = $body.find(`[data-testid="add-domain"]`);
|
|
||||||
|
|
||||||
expect(editDomain.length).to.equal(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Manage button should be visible on service page
|
|
||||||
cy.get('[data-testid="manage-button"]').click();
|
|
||||||
|
|
||||||
// Announcement and Delete options should not be visible
|
|
||||||
cy.get('.manage-dropdown-list-container').then(($body) => {
|
|
||||||
const announcementButton = $body.find(
|
|
||||||
`[data-testid="announcement-button"]`
|
|
||||||
);
|
|
||||||
const deleteButton = $body.find(`[data-testid="delete-button"]`);
|
|
||||||
|
|
||||||
expect(announcementButton.length).to.equal(0);
|
|
||||||
expect(deleteButton.length).to.equal(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Rename search index flow should work properly
|
|
||||||
cy.get('[data-testid="rename-button"]').click({ waitForAnimations: true });
|
|
||||||
|
|
||||||
cy.get('#displayName').clear().type(SEARCH_INDEX_DISPLAY_NAME);
|
|
||||||
|
|
||||||
interceptURL('PATCH', `/api/v1/searchIndexes/*`, 'updateDisplayName');
|
|
||||||
|
|
||||||
cy.get('[data-testid="save-button"]').click();
|
|
||||||
|
|
||||||
verifyResponseStatusCode('@updateDisplayName', 200);
|
|
||||||
|
|
||||||
cy.get('[data-testid="entity-header-display-name"]').contains(
|
|
||||||
SEARCH_INDEX_DISPLAY_NAME
|
|
||||||
);
|
|
||||||
|
|
||||||
performCommonOperations();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('SearchIndexDetails page should work properly for admin role', () => {
|
|
||||||
before(() => {
|
|
||||||
cy.login();
|
|
||||||
cy.getAllLocalStorage().then((storageData) => {
|
|
||||||
const token = getToken(storageData);
|
|
||||||
|
|
||||||
// Create search index entity
|
|
||||||
createSingleLevelEntity({
|
|
||||||
token,
|
|
||||||
...SEARCH_SERVICE_DETAILS,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
cy.login();
|
|
||||||
|
|
||||||
cy.getAllLocalStorage().then((storageData) => {
|
|
||||||
const token = getToken(storageData);
|
|
||||||
|
|
||||||
// Delete search index
|
|
||||||
hardDeleteService({
|
|
||||||
token,
|
|
||||||
serviceFqn: SEARCH_SERVICE_DETAILS.service.name,
|
|
||||||
serviceType: SEARCH_SERVICE_DETAILS.serviceType,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
cy.login();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('All permissible actions on search index details page should work properly', () => {
|
|
||||||
visitEntityDetailsPage({
|
|
||||||
term: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.name,
|
|
||||||
serviceName: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.service,
|
|
||||||
entity: EntityType.SearchIndex,
|
|
||||||
});
|
|
||||||
performCommonOperations();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Soft delete workflow should work properly', () => {
|
|
||||||
visitEntityDetailsPage({
|
|
||||||
term: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.name,
|
|
||||||
serviceName: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.service,
|
|
||||||
entity: EntityType.SearchIndex,
|
|
||||||
});
|
|
||||||
deleteEntity(
|
|
||||||
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.name,
|
|
||||||
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.service,
|
|
||||||
EntityType.SearchIndex,
|
|
||||||
'Search Index',
|
|
||||||
'soft'
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('[data-testid="deleted-badge"]').should('be.visible');
|
|
||||||
|
|
||||||
// Edit options for domain owner and tier should not be visible
|
|
||||||
cy.get('[data-testid="add-domain"]').should('not.exist');
|
|
||||||
cy.get('[data-testid="edit-owner"]').should('not.exist');
|
|
||||||
cy.get('[data-testid="edit-tier"]').should('not.exist');
|
|
||||||
|
|
||||||
// Edit description button should not be visible
|
|
||||||
cy.get('[data-testid="edit-description"]').should('not.exist');
|
|
||||||
|
|
||||||
// Edit tags button should not be visible
|
|
||||||
cy.get(
|
|
||||||
`[data-testid="entity-right-panel"] [data-testid="tags-container"] [data-testid="add-tag"]`
|
|
||||||
).should('not.exist');
|
|
||||||
|
|
||||||
// Edit description and tags button for fields should not be visible
|
|
||||||
cy.get(
|
|
||||||
`[data-row-key="${SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.fields[0].fullyQualifiedName}"]`
|
|
||||||
).then(($body) => {
|
|
||||||
const addTag = $body.find(
|
|
||||||
`[data-testid="tags-container"] [data-testid="add-tag"]`
|
|
||||||
);
|
|
||||||
const editDescription = $body.find(
|
|
||||||
`[data-testid="description"] [data-testid="edit-button"]`
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(addTag.length).to.equal(0);
|
|
||||||
expect(editDescription.length).to.equal(0);
|
|
||||||
|
|
||||||
// Restore search index flow should work properly
|
|
||||||
cy.get('[data-testid="manage-button"]').click();
|
|
||||||
|
|
||||||
cy.get('[data-testid="restore-button"]').click();
|
|
||||||
|
|
||||||
interceptURL(
|
|
||||||
'PUT',
|
|
||||||
`/api/v1/searchIndexes/restore`,
|
|
||||||
'restoreSearchIndex'
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get('[data-testid="restore-asset-modal"] .ant-btn-primary')
|
|
||||||
.contains('Restore')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
verifyResponseStatusCode('@restoreSearchIndex', 200);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Hard delete workflow should work properly', () => {
|
|
||||||
visitEntityDetailsPage({
|
|
||||||
term: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.name,
|
|
||||||
serviceName: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.service,
|
|
||||||
entity: EntityType.SearchIndex,
|
|
||||||
});
|
|
||||||
deleteEntity(
|
|
||||||
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.name,
|
|
||||||
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.service,
|
|
||||||
EntityType.SearchIndex,
|
|
||||||
'Search Index'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -181,12 +181,13 @@ test.describe('Domains', () => {
|
|||||||
await afterAction();
|
await afterAction();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Switch domain from navbar and check domain query call warp in quotes', async ({
|
test('Switch domain from navbar and check domain query call wrap in quotes', async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
const { afterAction, apiContext } = await getApiContext(page);
|
const { afterAction, apiContext } = await getApiContext(page);
|
||||||
const domain = new Domain();
|
const domain = new Domain();
|
||||||
await domain.create(apiContext);
|
await domain.create(apiContext);
|
||||||
|
await page.reload();
|
||||||
await page.getByTestId('domain-dropdown').click();
|
await page.getByTestId('domain-dropdown').click();
|
||||||
await page
|
await page
|
||||||
.locator(
|
.locator(
|
||||||
@ -217,8 +218,8 @@ test.describe('Domains', () => {
|
|||||||
const { assets, assetCleanup } = await setupAssetsForDomain(page);
|
const { assets, assetCleanup } = await setupAssetsForDomain(page);
|
||||||
const domain = new Domain();
|
const domain = new Domain();
|
||||||
await domain.create(apiContext);
|
await domain.create(apiContext);
|
||||||
await sidebarClick(page, SidebarItem.DOMAIN);
|
|
||||||
await page.reload();
|
await page.reload();
|
||||||
|
await sidebarClick(page, SidebarItem.DOMAIN);
|
||||||
await addAssetsToDomain(page, domain.data, assets);
|
await addAssetsToDomain(page, domain.data, assets);
|
||||||
await page.getByTestId('documentation').click();
|
await page.getByTestId('documentation').click();
|
||||||
const updatedDomainName = 'PW Domain Updated';
|
const updatedDomainName = 'PW Domain Updated';
|
||||||
@ -275,10 +276,12 @@ test.describe('Domains Rbac', () => {
|
|||||||
|
|
||||||
test.beforeAll('Setup pre-requests', async ({ browser }) => {
|
test.beforeAll('Setup pre-requests', async ({ browser }) => {
|
||||||
const { apiContext, afterAction, page } = await performAdminLogin(browser);
|
const { apiContext, afterAction, page } = await performAdminLogin(browser);
|
||||||
await domain1.create(apiContext);
|
await Promise.all([
|
||||||
await domain2.create(apiContext);
|
domain1.create(apiContext),
|
||||||
await domain3.create(apiContext);
|
domain2.create(apiContext),
|
||||||
await user1.create(apiContext);
|
domain3.create(apiContext),
|
||||||
|
user1.create(apiContext),
|
||||||
|
]);
|
||||||
|
|
||||||
const domainPayload: Operation[] = [
|
const domainPayload: Operation[] = [
|
||||||
{
|
{
|
||||||
@ -322,6 +325,8 @@ test.describe('Domains Rbac', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Domain Rbac', async ({ browser }) => {
|
test('Domain Rbac', async ({ browser }) => {
|
||||||
|
test.slow(true);
|
||||||
|
|
||||||
const { page, afterAction, apiContext } = await performAdminLogin(browser);
|
const { page, afterAction, apiContext } = await performAdminLogin(browser);
|
||||||
const { page: userPage, afterAction: afterActionUser1 } =
|
const { page: userPage, afterAction: afterActionUser1 } =
|
||||||
await performUserLogin(browser, user1);
|
await performUserLogin(browser, user1);
|
||||||
@ -363,6 +368,19 @@ test.describe('Domains Rbac', () => {
|
|||||||
.locator('span')
|
.locator('span')
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
|
|
||||||
|
// Visit explore page and verify if domain is passed in the query
|
||||||
|
const queryRes = userPage.waitForResponse(
|
||||||
|
'/api/v1/search/query?*index=dataAsset*'
|
||||||
|
);
|
||||||
|
await sidebarClick(userPage, SidebarItem.EXPLORE);
|
||||||
|
await queryRes.then(async (res) => {
|
||||||
|
const queryString = new URL(res.request().url()).search;
|
||||||
|
const urlParams = new URLSearchParams(queryString);
|
||||||
|
const qParam = urlParams.get('q');
|
||||||
|
|
||||||
|
await expect(qParam).toContain(`domain.fullyQualifiedName:`);
|
||||||
|
});
|
||||||
|
|
||||||
for (const asset of domainAssset2) {
|
for (const asset of domainAssset2) {
|
||||||
const fqn = encodeURIComponent(
|
const fqn = encodeURIComponent(
|
||||||
get(asset, 'entityResponseData.fullyQualifiedName', '')
|
get(asset, 'entityResponseData.fullyQualifiedName', '')
|
||||||
@ -384,10 +402,13 @@ test.describe('Domains Rbac', () => {
|
|||||||
await afterActionUser1();
|
await afterActionUser1();
|
||||||
});
|
});
|
||||||
|
|
||||||
await domain1.delete(apiContext);
|
await Promise.all([
|
||||||
await domain2.delete(apiContext);
|
domain1.delete(apiContext),
|
||||||
await domain3.delete(apiContext);
|
domain2.delete(apiContext),
|
||||||
await user1.delete(apiContext);
|
domain3.delete(apiContext),
|
||||||
|
user1.delete(apiContext),
|
||||||
|
]);
|
||||||
|
|
||||||
await assetCleanup1();
|
await assetCleanup1();
|
||||||
await assetCleanup2();
|
await assetCleanup2();
|
||||||
await afterAction();
|
await afterAction();
|
||||||
|
|||||||
@ -179,6 +179,10 @@ entities.forEach((EntityClass) => {
|
|||||||
await entity.followUnfollowEntity(page, entityName);
|
await entity.followUnfollowEntity(page, entityName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(`Update displayName`, async ({ page }) => {
|
||||||
|
await entity.renameEntity(page, entity.entity.name);
|
||||||
|
});
|
||||||
|
|
||||||
test.afterAll('Cleanup', async ({ browser }) => {
|
test.afterAll('Cleanup', async ({ browser }) => {
|
||||||
const { apiContext, afterAction } = await performAdminLogin(browser);
|
const { apiContext, afterAction } = await performAdminLogin(browser);
|
||||||
await user.delete(apiContext);
|
await user.delete(apiContext);
|
||||||
|
|||||||
@ -182,7 +182,7 @@ export const fillRule = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.locator(`.ant-select-dropdown [title="${searchData}"]`)
|
.locator(`.ant-select-dropdown:visible [title="${searchData}"]`)
|
||||||
.click();
|
.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -299,7 +299,10 @@ export const addAssetsToDomain = async (
|
|||||||
const searchRes = page.waitForResponse(
|
const searchRes = page.waitForResponse(
|
||||||
`/api/v1/search/query?q=${name}&index=all&from=0&size=25&*`
|
`/api/v1/search/query?q=${name}&index=all&from=0&size=25&*`
|
||||||
);
|
);
|
||||||
await page.getByTestId('searchbar').fill(name);
|
await page
|
||||||
|
.getByTestId('asset-selection-modal')
|
||||||
|
.getByTestId('searchbar')
|
||||||
|
.fill(name);
|
||||||
await searchRes;
|
await searchRes;
|
||||||
|
|
||||||
await page.locator(`[data-testid="table-data-card_${fqn}"] input`).check();
|
await page.locator(`[data-testid="table-data-card_${fqn}"] input`).check();
|
||||||
@ -380,14 +383,18 @@ export const setupAssetsForDomain = async (page: Page) => {
|
|||||||
const table = new TableClass();
|
const table = new TableClass();
|
||||||
const topic = new TopicClass();
|
const topic = new TopicClass();
|
||||||
const dashboard = new DashboardClass();
|
const dashboard = new DashboardClass();
|
||||||
await table.create(apiContext);
|
await Promise.all([
|
||||||
await topic.create(apiContext);
|
table.create(apiContext),
|
||||||
await dashboard.create(apiContext);
|
topic.create(apiContext),
|
||||||
|
dashboard.create(apiContext),
|
||||||
|
]);
|
||||||
|
|
||||||
const assetCleanup = async () => {
|
const assetCleanup = async () => {
|
||||||
await table.create(apiContext);
|
await Promise.all([
|
||||||
await topic.create(apiContext);
|
table.delete(apiContext),
|
||||||
await dashboard.create(apiContext);
|
topic.delete(apiContext),
|
||||||
|
dashboard.delete(apiContext),
|
||||||
|
]);
|
||||||
await afterAction();
|
await afterAction();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,6 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { getDomainList } from '../../rest/domainAPI';
|
|
||||||
import { getLimitConfig } from '../../rest/limitsAPI';
|
import { getLimitConfig } from '../../rest/limitsAPI';
|
||||||
import applicationsClassBase from '../Settings/Applications/AppDetails/ApplicationsClassBase';
|
import applicationsClassBase from '../Settings/Applications/AppDetails/ApplicationsClassBase';
|
||||||
import AppContainer from './AppContainer';
|
import AppContainer from './AppContainer';
|
||||||
@ -85,14 +84,4 @@ describe('AppContainer', () => {
|
|||||||
|
|
||||||
expect(getLimitConfig).toHaveBeenCalled();
|
expect(getLimitConfig).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call domain list to cache domains', () => {
|
|
||||||
render(
|
|
||||||
<MemoryRouter>
|
|
||||||
<AppContainer />
|
|
||||||
</MemoryRouter>
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(getDomainList).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -15,11 +15,8 @@ import { Layout } from 'antd';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ES_MAX_PAGE_SIZE } from '../../constants/constants';
|
|
||||||
import { useLimitStore } from '../../context/LimitsProvider/useLimitsStore';
|
import { useLimitStore } from '../../context/LimitsProvider/useLimitsStore';
|
||||||
import { useApplicationStore } from '../../hooks/useApplicationStore';
|
import { useApplicationStore } from '../../hooks/useApplicationStore';
|
||||||
import { useDomainStore } from '../../hooks/useDomainStore';
|
|
||||||
import { getDomainList } from '../../rest/domainAPI';
|
|
||||||
import { getLimitConfig } from '../../rest/limitsAPI';
|
import { getLimitConfig } from '../../rest/limitsAPI';
|
||||||
import applicationRoutesClass from '../../utils/ApplicationRoutesClassBase';
|
import applicationRoutesClass from '../../utils/ApplicationRoutesClassBase';
|
||||||
import Appbar from '../AppBar/Appbar';
|
import Appbar from '../AppBar/Appbar';
|
||||||
@ -32,27 +29,11 @@ const AppContainer = () => {
|
|||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const { Header, Sider, Content } = Layout;
|
const { Header, Sider, Content } = Layout;
|
||||||
const { currentUser } = useApplicationStore();
|
const { currentUser } = useApplicationStore();
|
||||||
const { updateDomains, updateDomainLoading } = useDomainStore();
|
|
||||||
const AuthenticatedRouter = applicationRoutesClass.getRouteElements();
|
const AuthenticatedRouter = applicationRoutesClass.getRouteElements();
|
||||||
const ApplicationExtras = applicationsClassBase.getApplicationExtension();
|
const ApplicationExtras = applicationsClassBase.getApplicationExtension();
|
||||||
const isDirectionRTL = useMemo(() => i18n.dir() === 'rtl', [i18n]);
|
const isDirectionRTL = useMemo(() => i18n.dir() === 'rtl', [i18n]);
|
||||||
const { setConfig, bannerDetails } = useLimitStore();
|
const { setConfig, bannerDetails } = useLimitStore();
|
||||||
|
|
||||||
const fetchDomainList = useCallback(async () => {
|
|
||||||
try {
|
|
||||||
updateDomainLoading(true);
|
|
||||||
const { data } = await getDomainList({
|
|
||||||
limit: ES_MAX_PAGE_SIZE,
|
|
||||||
fields: 'parent',
|
|
||||||
});
|
|
||||||
updateDomains(data);
|
|
||||||
} catch (error) {
|
|
||||||
// silent fail
|
|
||||||
} finally {
|
|
||||||
updateDomainLoading(false);
|
|
||||||
}
|
|
||||||
}, [currentUser]);
|
|
||||||
|
|
||||||
const fetchLimitConfig = useCallback(async () => {
|
const fetchLimitConfig = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const response = await getLimitConfig();
|
const response = await getLimitConfig();
|
||||||
@ -65,7 +46,6 @@ const AppContainer = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentUser?.id) {
|
if (currentUser?.id) {
|
||||||
fetchDomainList();
|
|
||||||
fetchLimitConfig();
|
fetchLimitConfig();
|
||||||
}
|
}
|
||||||
}, [currentUser?.id]);
|
}, [currentUser?.id]);
|
||||||
|
|||||||
@ -41,6 +41,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useHistory, useLocation } from 'react-router-dom';
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
DEFAULT_DOMAIN_VALUE,
|
DEFAULT_DOMAIN_VALUE,
|
||||||
|
ES_MAX_PAGE_SIZE,
|
||||||
REDIRECT_PATHNAME,
|
REDIRECT_PATHNAME,
|
||||||
ROUTES,
|
ROUTES,
|
||||||
} from '../../../constants/constants';
|
} from '../../../constants/constants';
|
||||||
@ -56,6 +57,7 @@ import { AuthProvider as AuthProviderEnum } from '../../../generated/settings/se
|
|||||||
import { useApplicationStore } from '../../../hooks/useApplicationStore';
|
import { useApplicationStore } from '../../../hooks/useApplicationStore';
|
||||||
import { useDomainStore } from '../../../hooks/useDomainStore';
|
import { useDomainStore } from '../../../hooks/useDomainStore';
|
||||||
import axiosClient from '../../../rest';
|
import axiosClient from '../../../rest';
|
||||||
|
import { getDomainList } from '../../../rest/domainAPI';
|
||||||
import {
|
import {
|
||||||
fetchAuthenticationConfig,
|
fetchAuthenticationConfig,
|
||||||
fetchAuthorizerConfig,
|
fetchAuthorizerConfig,
|
||||||
@ -135,7 +137,7 @@ export const AuthProvider = ({
|
|||||||
isApplicationLoading,
|
isApplicationLoading,
|
||||||
setApplicationLoading,
|
setApplicationLoading,
|
||||||
} = useApplicationStore();
|
} = useApplicationStore();
|
||||||
const { activeDomain } = useDomainStore();
|
const { updateDomains, updateDomainLoading } = useDomainStore();
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@ -183,6 +185,21 @@ export const AuthProvider = ({
|
|||||||
return authenticatorRef.current?.renewIdToken();
|
return authenticatorRef.current?.renewIdToken();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchDomainList = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
updateDomainLoading(true);
|
||||||
|
const { data } = await getDomainList({
|
||||||
|
limit: ES_MAX_PAGE_SIZE,
|
||||||
|
fields: 'parent',
|
||||||
|
});
|
||||||
|
updateDomains(data);
|
||||||
|
} catch (error) {
|
||||||
|
// silent fail
|
||||||
|
} finally {
|
||||||
|
updateDomainLoading(false);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handledVerifiedUser = () => {
|
const handledVerifiedUser = () => {
|
||||||
if (!isProtectedRoute(location.pathname)) {
|
if (!isProtectedRoute(location.pathname)) {
|
||||||
history.push(ROUTES.HOME);
|
history.push(ROUTES.HOME);
|
||||||
@ -223,6 +240,8 @@ export const AuthProvider = ({
|
|||||||
if (res) {
|
if (res) {
|
||||||
setCurrentUser(res);
|
setCurrentUser(res);
|
||||||
setIsAuthenticated(true);
|
setIsAuthenticated(true);
|
||||||
|
// Fetch domains at the start
|
||||||
|
await fetchDomainList();
|
||||||
} else {
|
} else {
|
||||||
resetUserDetails();
|
resetUserDetails();
|
||||||
}
|
}
|
||||||
@ -397,6 +416,9 @@ export const AuthProvider = ({
|
|||||||
setCurrentUser(res);
|
setCurrentUser(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch domains at the start
|
||||||
|
await fetchDomainList();
|
||||||
|
|
||||||
handledVerifiedUser();
|
handledVerifiedUser();
|
||||||
// Start expiry timer on successful login
|
// Start expiry timer on successful login
|
||||||
startTokenExpiryTimer();
|
startTokenExpiryTimer();
|
||||||
@ -470,6 +492,7 @@ export const AuthProvider = ({
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const withDomainFilter = (config: InternalAxiosRequestConfig<any>) => {
|
const withDomainFilter = (config: InternalAxiosRequestConfig<any>) => {
|
||||||
const isGetRequest = config.method === 'get';
|
const isGetRequest = config.method === 'get';
|
||||||
|
const activeDomain = useDomainStore.getState().activeDomain;
|
||||||
const hasActiveDomain = activeDomain !== DEFAULT_DOMAIN_VALUE;
|
const hasActiveDomain = activeDomain !== DEFAULT_DOMAIN_VALUE;
|
||||||
const currentPath = window.location.pathname;
|
const currentPath = window.location.pathname;
|
||||||
const shouldNotIntercept = [
|
const shouldNotIntercept = [
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user