diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/CuratedAssets.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/CuratedAssets.spec.ts index 787fca35ed5..bb41dfeddbb 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/CuratedAssets.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/CuratedAssets.spec.ts @@ -35,6 +35,8 @@ const test = base.extend<{ page: Page }>({ }); base.beforeAll('Setup pre-requests', async ({ browser }) => { + test.slow(true); + const { afterAction, apiContext } = await performAdminLogin(browser); await adminUser.create(apiContext); await adminUser.setAdminRole(apiContext); @@ -43,6 +45,8 @@ base.beforeAll('Setup pre-requests', async ({ browser }) => { }); base.afterAll('Cleanup', async ({ browser }) => { + test.slow(true); + const { afterAction, apiContext } = await performAdminLogin(browser); await adminUser.delete(apiContext); await persona.delete(apiContext); @@ -50,7 +54,7 @@ base.afterAll('Cleanup', async ({ browser }) => { }); test.describe('Curated Assets', () => { - test.beforeEach(async ({ page }) => { + test.beforeAll(async ({ page }) => { test.slow(true); await redirectToHomePage(page); @@ -93,7 +97,7 @@ test.describe('Curated Assets', () => { await selectOption( page, ruleLocator.locator('.rule--operator .ant-select'), - '!=' + 'Not in' ); await selectOption( diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/Tour.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/Tour.spec.ts index 84e1dcb93bc..3c11ace51ef 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/Tour.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/Tour.spec.ts @@ -18,6 +18,9 @@ import { redirectToHomePage } from '../../utils/common'; const user = new UserClass(); const validateTourSteps = async (page: Page) => { + await page.waitForTimeout(1000); + await page.waitForSelector(`[data-tour-elem="badge"]`); + await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('1'); // step 1 @@ -30,8 +33,8 @@ const validateTourSteps = async (page: Page) => { await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('3'); - await page.getByTestId('customise-searchbox').fill('dim_a'); - await page.getByTestId('customise-searchbox').press('Enter'); + await page.getByTestId('searchBox').fill('dim_a'); + await page.getByTestId('searchBox').press('Enter'); await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('4'); @@ -108,7 +111,7 @@ const validateTourSteps = async (page: Page) => { await page.getByTestId('saveButton').click(); }; -test.describe.skip('Tour should work properly', () => { +test.describe('Tour should work properly', () => { test.beforeAll(async ({ browser }) => { const { apiContext, afterAction } = await performAdminLogin(browser); await user.create(apiContext); @@ -130,6 +133,9 @@ test.describe.skip('Tour should work properly', () => { await page.locator('[data-testid="help-icon"]').click(); await page.getByRole('link', { name: 'Tour', exact: true }).click(); await page.waitForURL('**/tour'); + + await page.waitForSelector('#feedWidgetData'); + await validateTourSteps(page); }); @@ -141,14 +147,17 @@ test.describe.skip('Tour should work properly', () => { await page.getByText('Take a product tour to get started!').click(); await page.waitForURL('**/tour'); + await page.waitForSelector('#feedWidgetData'); + await validateTourSteps(page); }); test('Tour should work from URL directly', async ({ page }) => { - await expect(page.getByTestId('global-search-selector')).toBeVisible(); - await page.goto('/tour'); await page.waitForURL('**/tour'); + + await page.waitForSelector('#feedWidgetData'); + await validateTourSteps(page); }); }); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/MyData.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/MyData.spec.ts deleted file mode 100644 index 098c1cbfa0d..00000000000 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/MyData.spec.ts +++ /dev/null @@ -1,122 +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 { expect, Page, test as base } from '@playwright/test'; -import { TableClass } from '../../support/entity/TableClass'; -import { UserClass } from '../../support/user/UserClass'; -import { performAdminLogin } from '../../utils/admin'; -import { redirectToHomePage, removeLandingBanner } from '../../utils/common'; -import { verifyEntities } from '../../utils/myData'; - -const user = new UserClass(); -const TableEntities = Array(20) - .fill(undefined) - .map(() => new TableClass()); - -const test = base.extend<{ page: Page }>({ - page: async ({ browser }, use) => { - const Page = await browser.newPage(); - await user.login(Page); - await use(Page); - await Page.close(); - }, -}); - -test.describe.serial('My Data page', () => { - test.beforeAll('Setup pre-requests', async ({ browser }) => { - const { apiContext, afterAction } = await performAdminLogin(browser); - await user.create(apiContext); - const tablePromises = TableEntities.map(async (table) => { - await table.create(apiContext); - await table.patch({ - apiContext, - patchData: [ - { - op: 'add', - path: '/owners/0', - value: { - id: user.responseData.id, - type: 'user', - deleted: false, - displayName: user.responseData.displayName, - fullyQualifiedName: user.responseData.fullyQualifiedName, - href: user.responseData['href'] ?? '', - name: user.responseData.name, - }, - }, - ], - }); - await table.followTable(apiContext, user.responseData.id); - }); - - await Promise.all(tablePromises); - - await afterAction(); - }); - - test.afterAll('Cleanup', async ({ browser }) => { - const { apiContext, afterAction } = await performAdminLogin(browser); - await user.delete(apiContext); - - await Promise.all(TableEntities.map((table) => table.delete(apiContext))); - await afterAction(); - }); - - test.beforeEach('Visit entity details page', async ({ page }) => { - await redirectToHomePage(page); - await removeLandingBanner(page); - }); - - test.skip('Verify my data widget', async ({ page }) => { - await page.waitForLoadState('networkidle'); - await page.waitForSelector('[data-testid="loader"]', { - state: 'detached', - }); - - // Verify total count - await expect( - page.locator('[data-testid="my-data-total-count"]') - ).toContainText('(20)'); - - await page - .locator('[data-testid="my-data-widget"] [data-testid="view-all-link"]') - .click(); - - await page.waitForLoadState('networkidle'); - await page.waitForSelector('[data-testid="loader"]', { - state: 'detached', - }); - - // Verify entities - await verifyEntities( - page, - '/api/v1/search/query?q=*&index=all&from=0&size=25*', - TableEntities - ); - }); - - test.skip('Verify following widget', async ({ page }) => { - // Verify total count - await expect( - page.locator('[data-testid="following-data-total-count"]') - ).toContainText('(20)'); - - await page.locator('[data-testid="following-data"]').click(); - - // Verify entities - await verifyEntities( - page, - '/api/v1/search/query?q=*followers:*&index=all&from=0&size=25*', - TableEntities - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/FeedWidget/FeedWidget.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/FeedWidget/FeedWidget.component.tsx index d22656cc1b5..c7f27caa276 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/FeedWidget/FeedWidget.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/FeedWidget/FeedWidget.component.tsx @@ -178,7 +178,7 @@ const MyFeedWidgetInternal = ({ dataTestId="KnowledgePanel.ActivityFeed" header={widgetHeader} loading={loading}> -
+
{widgetBody} { updateTourSearch, } = useTourProvider(); const { t } = useTranslation(); + const [isTourReady, setIsTourReady] = useState(false); const clearSearchTerm = () => { updateTourSearch(''); @@ -38,6 +39,21 @@ const TourPage = () => { useEffect(() => { updateIsTourOpen(true); + + let attempts = 0; + const maxAttempts = 10; + + const waitForElement = () => { + const el = document.querySelector('#feedWidgetData'); + if (el) { + setIsTourReady(true); + } else if (attempts < maxAttempts) { + attempts++; + setTimeout(waitForElement, 100); + } + }; + + waitForElement(); }, []); const currentPageComponent = useMemo(() => { @@ -58,15 +74,17 @@ const TourPage = () => { return ( <> - {currentPageComponent} + {isTourReady && ( + + )} ); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TourPage/TourPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TourPage/TourPage.test.tsx index 1dc39d5bbc9..45b35f1836c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TourPage/TourPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TourPage/TourPage.test.tsx @@ -17,11 +17,18 @@ import TourPage from './TourPage.component'; const mockUseTourProvider = { updateIsTourOpen: jest.fn(), - currentTourPage: '', + currentTourPage: CurrentTourPageType.MY_DATA_PAGE, updateActiveTab: jest.fn(), updateTourPage: jest.fn(), updateTourSearch: jest.fn(), }; + +const mockQuerySelector = jest.fn(); +Object.defineProperty(document, 'querySelector', { + value: mockQuerySelector, + writable: true, +}); + jest.mock('../../context/TourProvider/TourProvider', () => ({ useTourProvider: jest.fn().mockImplementation(() => mockUseTourProvider), })); @@ -53,6 +60,22 @@ jest.mock('../../utils/TourUtils', () => ({ })); describe('TourPage component', () => { + beforeEach(() => { + jest.useFakeTimers(); + mockQuerySelector.mockImplementation((selector) => { + if (selector === '#feedWidgetData') { + return document.createElement('div'); + } + + return null; + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + jest.useRealTimers(); + }); + it('should render correctly', async () => { render(); @@ -69,7 +92,8 @@ describe('TourPage component', () => { }); it('MyDataPage Component should be visible, if currentTourPage is myDataPage', async () => { - (useTourProvider as jest.Mock).mockImplementationOnce(() => ({ + (useTourProvider as jest.Mock).mockReset(); + (useTourProvider as jest.Mock).mockImplementation(() => ({ ...mockUseTourProvider, currentTourPage: CurrentTourPageType.MY_DATA_PAGE, })); @@ -79,7 +103,8 @@ describe('TourPage component', () => { }); it('ExplorePage Component should be visible, if currentTourPage is explorePage', async () => { - (useTourProvider as jest.Mock).mockImplementationOnce(() => ({ + (useTourProvider as jest.Mock).mockReset(); + (useTourProvider as jest.Mock).mockImplementation(() => ({ ...mockUseTourProvider, currentTourPage: CurrentTourPageType.EXPLORE_PAGE, })); @@ -91,7 +116,8 @@ describe('TourPage component', () => { }); it('TableDetailsPage Component should be visible, if currentTourPage is datasetPage', async () => { - (useTourProvider as jest.Mock).mockImplementationOnce(() => ({ + (useTourProvider as jest.Mock).mockReset(); + (useTourProvider as jest.Mock).mockImplementation(() => ({ ...mockUseTourProvider, currentTourPage: CurrentTourPageType.DATASET_PAGE, })); diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/TourUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/TourUtils.tsx index 5463b49cc78..aab82b3ba33 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/TourUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/TourUtils.tsx @@ -41,7 +41,7 @@ export const getTourSteps = ({ />

), - selector: '#feedData', + selector: '#feedWidgetData', stepInteraction: false, }, {