Franknoirot/onboarding avatar text (#2726)

* Add failing playwright test

* Fix the problem to get the test passing

* Give the avatar button a tooltip too
This commit is contained in:
Frank Noirot
2024-06-20 14:06:11 -04:00
committed by GitHub
parent 6f76196b72
commit 2e7bdf02cf
4 changed files with 78 additions and 5 deletions

View File

@ -18,6 +18,7 @@ import {
TEST_SETTINGS_ONBOARDING_EXPORT, TEST_SETTINGS_ONBOARDING_EXPORT,
TEST_SETTINGS_ONBOARDING_START, TEST_SETTINGS_ONBOARDING_START,
TEST_CODE_GIZMO, TEST_CODE_GIZMO,
TEST_SETTINGS_ONBOARDING_USER_MENU,
} from './storageStates' } from './storageStates'
import * as TOML from '@iarna/toml' import * as TOML from '@iarna/toml'
import { LineInputsType } from 'lang/std/sketchcombos' import { LineInputsType } from 'lang/std/sketchcombos'
@ -1394,6 +1395,54 @@ test.describe('Onboarding tests', () => {
await page.locator('[data-testid="onboarding-next"]').click() await page.locator('[data-testid="onboarding-next"]').click()
await expect(page.locator('.cm-content')).toHaveText(/.+/) await expect(page.locator('.cm-content')).toHaveText(/.+/)
}) })
test('Avatar text updates depending on image load success', async ({
page,
}) => {
// Override beforeEach test setup
await page.addInitScript(
async ({ settingsKey, settings }) => {
localStorage.setItem(settingsKey, settings)
},
{
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({
settings: TEST_SETTINGS_ONBOARDING_USER_MENU,
}),
}
)
await page.setViewportSize({ width: 1200, height: 1080 })
await page.goto('/')
await page.waitForURL('**/file/**', { waitUntil: 'domcontentloaded' })
// Test that the text in this step is correct
const avatarLocator = page.getByTestId('user-sidebar-toggle').locator('img')
const onboardingOverlayLocator = page
.getByTestId('onboarding-content')
.locator('div')
.nth(1)
// Expect the avatar to be visible and for the text to reference it
await expect(avatarLocator).toBeVisible()
await expect(onboardingOverlayLocator).toBeVisible()
await expect(onboardingOverlayLocator).toContainText('your avatar')
await page.route('https://lh3.googleusercontent.com/**', async (route) => {
await route.fulfill({
status: 404,
contentType: 'text/plain',
body: 'Not Found!',
})
})
await page.reload({ waitUntil: 'domcontentloaded' })
// Now expect the text to be different
await expect(avatarLocator).not.toBeVisible()
await expect(onboardingOverlayLocator).toBeVisible()
await expect(onboardingOverlayLocator).toContainText('the menu button')
})
}) })
test.describe('Testing selections', () => { test.describe('Testing selections', () => {

View File

@ -1,5 +1,6 @@
import { SaveSettingsPayload } from 'lib/settings/settingsTypes' import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
import { Themes } from 'lib/theme' import { Themes } from 'lib/theme'
import { onboardingPaths } from 'routes/Onboarding/paths'
export const TEST_SETTINGS_KEY = '/settings.toml' export const TEST_SETTINGS_KEY = '/settings.toml'
export const TEST_SETTINGS = { export const TEST_SETTINGS = {
@ -22,9 +23,14 @@ export const TEST_SETTINGS = {
}, },
} satisfies Partial<SaveSettingsPayload> } satisfies Partial<SaveSettingsPayload>
export const TEST_SETTINGS_ONBOARDING_USER_MENU = {
...TEST_SETTINGS,
app: { ...TEST_SETTINGS.app, onboardingStatus: onboardingPaths.USER_MENU },
} satisfies Partial<SaveSettingsPayload>
export const TEST_SETTINGS_ONBOARDING_EXPORT = { export const TEST_SETTINGS_ONBOARDING_EXPORT = {
...TEST_SETTINGS, ...TEST_SETTINGS,
app: { ...TEST_SETTINGS.app, onboardingStatus: '/export' }, app: { ...TEST_SETTINGS.app, onboardingStatus: onboardingPaths.EXPORT },
} satisfies Partial<SaveSettingsPayload> } satisfies Partial<SaveSettingsPayload>
export const TEST_SETTINGS_ONBOARDING_START = { export const TEST_SETTINGS_ONBOARDING_START = {

View File

@ -39,7 +39,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
<Popover className="relative"> <Popover className="relative">
{user?.image && !imageLoadFailed ? ( {user?.image && !imageLoadFailed ? (
<Popover.Button <Popover.Button
className="border-0 rounded-full w-fit min-w-max p-0 group" className="relative border-0 rounded-full w-fit min-w-max p-0 group"
data-testid="user-sidebar-toggle" data-testid="user-sidebar-toggle"
> >
<div className="rounded-full border overflow-hidden"> <div className="rounded-full border overflow-hidden">
@ -51,6 +51,9 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
onError={() => setImageLoadFailed(true)} onError={() => setImageLoadFailed(true)}
/> />
</div> </div>
<Tooltip position="bottom-right" delay={1000}>
User menu
</Tooltip>
</Popover.Button> </Popover.Button>
) : ( ) : (
<ActionButton <ActionButton
@ -59,7 +62,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
className="border-transparent !px-0" className="border-transparent !px-0"
data-testid="user-sidebar-toggle" data-testid="user-sidebar-toggle"
> >
<Tooltip position="left" delay={1000}> <Tooltip position="bottom-right" delay={1000}>
User menu User menu
</Tooltip> </Tooltip>
</ActionButton> </ActionButton>

View File

@ -1,6 +1,7 @@
import { OnboardingButtons, useDismiss, useNextClick } from '.' import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths' import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from '../../useStore' import { useStore } from '../../useStore'
import { useEffect, useState } from 'react'
export default function UserMenu() { export default function UserMenu() {
const { buttonDownInStream } = useStore((s) => ({ const { buttonDownInStream } = useStore((s) => ({
@ -8,6 +9,20 @@ export default function UserMenu() {
})) }))
const dismiss = useDismiss() const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.PROJECT_MENU) const next = useNextClick(onboardingPaths.PROJECT_MENU)
const [avatarErrored, setAvatarErrored] = useState(false)
const buttonDescription = !avatarErrored ? 'your avatar' : 'the menu button'
// Set up error handling for the user's avatar image,
// so the onboarding text can be updated if it fails to load.
useEffect(() => {
const element = globalThis.document.querySelector(
'[data-testid="user-sidebar-toggle"] img'
)
if (element?.tagName === 'IMG') {
element.addEventListener('error', () => setAvatarErrored(true))
}
}, [])
return ( return (
<div className="fixed grid justify-center items-start inset-0 z-50 pointer-events-none"> <div className="fixed grid justify-center items-start inset-0 z-50 pointer-events-none">
@ -20,8 +35,8 @@ export default function UserMenu() {
<section className="flex-1"> <section className="flex-1">
<h2 className="text-2xl font-bold">User Menu</h2> <h2 className="text-2xl font-bold">User Menu</h2>
<p className="my-4"> <p className="my-4">
Click your avatar on the upper right to open the user menu. You can Click {buttonDescription} in the upper right to open the user menu.
change your settings, sign out, or request a feature. You can change your settings, sign out, or request a feature.
</p> </p>
<p className="my-4"> <p className="my-4">
We only support global settings at the moment, but we are working to We only support global settings at the moment, but we are working to