fix(ui): tour page issue clicking on tour from welcome screen (#20038)

* fix(ui): tour page issue clicking on tour from welcome screen

* fix infinite login for unauthenticated router

* improve tour tests
This commit is contained in:
Chirag Madlani 2025-03-02 13:00:33 +05:30 committed by GitHub
parent 1cbbe9a7c0
commit 9331a526ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 117 additions and 112 deletions

View File

@ -10,13 +10,102 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { expect, test } from '@playwright/test';
import { expect, Page, test } from '@playwright/test';
import { UserClass } from '../../support/user/UserClass';
import { performAdminLogin } from '../../utils/admin';
import { redirectToHomePage } from '../../utils/common';
const user = new UserClass();
const validateTourSteps = async (page: Page) => {
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('1');
// step 1
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('2');
// step 2
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('3');
await page.getByTestId('searchBox').fill('dim_a');
await page.getByTestId('searchBox').press('Enter');
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('4');
// step 3
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('5');
await expect(
page.getByTestId('sample_data.ecommerce_db.shopify.dim_address')
).toBeVisible();
// step 4
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('6');
// step 5
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('7');
// step 6
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('8');
// step 7
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('9');
// step 8
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('10');
await expect(
page.getByTestId('sample_data').getByText('Sample Data')
).toBeVisible();
// step 9
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('11');
// step 10
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('12');
await expect(page.getByText('Data Observability')).toBeVisible();
// step 11
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('13');
// step 12
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('14');
await expect(page.getByTestId('lineage').getByText('Lineage')).toBeVisible();
// step 13
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('15');
await page.getByTestId('last-step-button').click();
await page.getByTestId('saveButton').click();
};
test.describe('Tour should work properly', () => {
test.beforeAll(async ({ browser }) => {
const { apiContext, afterAction } = await performAdminLogin(browser);
@ -35,98 +124,23 @@ test.describe('Tour should work properly', () => {
await redirectToHomePage(page);
});
test('All tour steps should work', async ({ page }) => {
test('Tour should work from help section', async ({ page }) => {
await page.locator('[data-testid="help-icon"]').click();
await page.getByRole('link', { name: 'Tour', exact: true }).click();
await page.waitForURL('**/tour');
await validateTourSteps(page);
});
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('1');
test('Tour should work from welcome screen', async ({ page }) => {
await page.getByText('Take a product tour to get started!').click();
await page.waitForURL('**/tour');
// step 1
await page.locator('[data-tour-elem="right-arrow"]').click();
await validateTourSteps(page);
});
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('2');
// step 2
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('3');
await page.getByTestId('searchBox').fill('dim_a');
await page.getByTestId('searchBox').press('Enter');
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('4');
// step 3
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('5');
await expect(
page.getByTestId('sample_data.ecommerce_db.shopify.dim_address')
).toBeVisible();
// step 4
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('6');
// step 5
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('7');
// step 6
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('8');
// step 7
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('9');
// step 8
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('10');
await expect(
page.getByTestId('sample_data').getByText('Sample Data')
).toBeVisible();
// step 9
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('11');
// step 10
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('12');
await expect(page.getByText('Data Observability')).toBeVisible();
// step 11
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('13');
// step 12
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('14');
await expect(
page.getByTestId('lineage').getByText('Lineage')
).toBeVisible();
// step 13
await page.locator('[data-tour-elem="right-arrow"]').click();
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('15');
await page.getByTestId('last-step-button').click();
await page.getByTestId('saveButton').click();
test('Tour should work from URL directly', async ({ page }) => {
await page.goto('/tour');
await page.waitForURL('**/tour');
await validateTourSteps(page);
});
});

View File

@ -14,5 +14,4 @@ import { App } from '../../../../generated/entity/applications/app';
export type ApplicationsContextType = {
applications: App[];
loading: boolean;
};

View File

@ -24,13 +24,14 @@ import { usePermissionProvider } from '../../../../context/PermissionProvider/Pe
import { App } from '../../../../generated/entity/applications/app';
import { useApplicationStore } from '../../../../hooks/useApplicationStore';
import { getApplicationList } from '../../../../rest/applicationAPI';
import Loader from '../../../common/Loader/Loader';
import { ApplicationsContextType } from './ApplicationsProvider.interface';
export const ApplicationsContext = createContext({} as ApplicationsContextType);
export const ApplicationsProvider = ({ children }: { children: ReactNode }) => {
const [applications, setApplications] = useState<App[]>([]);
const [loading, setLoading] = useState(false);
const [loading, setLoading] = useState(true);
const { permissions } = usePermissionProvider();
const { setApplicationsName } = useApplicationStore();
@ -54,16 +55,18 @@ export const ApplicationsProvider = ({ children }: { children: ReactNode }) => {
useEffect(() => {
if (!isEmpty(permissions)) {
fetchApplicationList();
} else {
setLoading(false);
}
}, [permissions]);
const appContext = useMemo(() => {
return { applications, loading };
}, [applications, loading]);
return { applications };
}, [applications]);
return (
<ApplicationsContext.Provider value={appContext}>
{children}
{loading ? <Loader /> : children}
</ApplicationsContext.Provider>
);
};

View File

@ -98,7 +98,7 @@ const PermissionProvider: FC<PermissionProviderProps> = ({ children }) => {
} finally {
setLoading(false);
}
}, [setLoading, setPermissions, redirectToStoredPath]);
}, [redirectToStoredPath]);
const fetchEntityPermission = useCallback(
async (resource: ResourceEntity, entityId: string) => {

View File

@ -19,7 +19,6 @@ import { useHistory } from 'react-router-dom';
import ErrorPlaceHolder from '../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
import PageHeader from '../../components/PageHeader/PageHeader.component';
import PageLayoutV1 from '../../components/PageLayoutV1/PageLayoutV1';
import { useApplicationsProvider } from '../../components/Settings/Applications/ApplicationsProvider/ApplicationsProvider';
import SettingItemCard from '../../components/Settings/SettingItemCard/SettingItemCard.component';
import { PAGE_HEADERS } from '../../constants/PageHeaders.constant';
import { usePermissionProvider } from '../../context/PermissionProvider/PermissionProvider';
@ -39,7 +38,6 @@ const GlobalSettingPage = () => {
const { permissions } = usePermissionProvider();
const { isAdminUser } = useAuth();
const { loading } = useApplicationsProvider();
const settingItems = useMemo(
() =>
@ -58,7 +56,7 @@ const GlobalSettingPage = () => {
return false;
}),
[permissions, isAdminUser, loading]
[permissions, isAdminUser]
);
const handleSettingItemClick = useCallback((category: string) => {

View File

@ -13,20 +13,13 @@
import { AxiosError } from 'axios';
import { isEmpty } from 'lodash';
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import RGL, { WidthProvider } from 'react-grid-layout';
import { useTranslation } from 'react-i18next';
import { withActivityFeed } from '../../components/AppRouter/withActivityFeed';
import Loader from '../../components/common/Loader/Loader';
import WelcomeScreen from '../../components/MyData/WelcomeScreen/WelcomeScreen.component';
import PageLayoutV1 from '../../components/PageLayoutV1/PageLayoutV1';
import { useApplicationsProvider } from '../../components/Settings/Applications/ApplicationsProvider/ApplicationsProvider';
import {
KNOWLEDGE_LIST_LENGTH,
LOGGED_IN_USER_STORAGE_KEY,
@ -54,14 +47,13 @@ const ReactGridLayout = WidthProvider(RGL);
const MyDataPage = () => {
const { t } = useTranslation();
const { currentUser, selectedPersona } = useApplicationStore();
const { loading: applicationsLoading } = useApplicationsProvider();
const { isWelcomeVisible } = useWelcomeStore();
const [followedData, setFollowedData] = useState<Array<EntityReference>>([]);
const [followedDataCount, setFollowedDataCount] = useState(0);
const [isLoadingOwnedData, setIsLoadingOwnedData] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState(true);
const [layout, setLayout] = useState<Array<WidgetConfig>>([]);
const isMounted = useRef(false);
const [showWelcomeScreen, setShowWelcomeScreen] = useState(false);
const [isAnnouncementLoading, setIsAnnouncementLoading] =
useState<boolean>(true);
@ -116,15 +108,14 @@ const MyDataPage = () => {
};
useEffect(() => {
!applicationsLoading && fetchDocument();
}, [selectedPersona, applicationsLoading]);
fetchDocument();
}, [selectedPersona]);
useEffect(() => {
isMounted.current = true;
updateWelcomeScreen(!usernameExistsInCookie && isWelcomeVisible);
return () => updateWelcomeScreen(false);
}, [isWelcomeVisible]);
}, []);
const fetchUserFollowedData = async () => {
if (!currentUser?.id) {
@ -205,7 +196,7 @@ const MyDataPage = () => {
// call the hook to set the direction of the grid layout
useGridLayoutDirection(isLoading);
if (isLoading || applicationsLoading) {
if (isLoading) {
return <Loader fullScreen />;
}