mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-05 03:54:23 +00:00
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:
parent
1cbbe9a7c0
commit
9331a526ea
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@ -14,5 +14,4 @@ import { App } from '../../../../generated/entity/applications/app';
|
||||
|
||||
export type ApplicationsContextType = {
|
||||
applications: App[];
|
||||
loading: boolean;
|
||||
};
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -98,7 +98,7 @@ const PermissionProvider: FC<PermissionProviderProps> = ({ children }) => {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [setLoading, setPermissions, redirectToStoredPath]);
|
||||
}, [redirectToStoredPath]);
|
||||
|
||||
const fetchEntityPermission = useCallback(
|
||||
async (resource: ResourceEntity, entityId: string) => {
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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 />;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user