diff --git a/packages/frontend/core/src/components/doc-properties/types/text.tsx b/packages/frontend/core/src/components/doc-properties/types/text.tsx index 6c11da3f2f..77daba5cf8 100644 --- a/packages/frontend/core/src/components/doc-properties/types/text.tsx +++ b/packages/frontend/core/src/components/doc-properties/types/text.tsx @@ -78,7 +78,7 @@ const MobileTextValue = ({ }: PropertyValueProps) => { const [open, setOpen] = useState(false); - const [tempValue, setTempValue] = useState(value); + const [tempValue, setTempValue] = useState(value || ''); const handleClick = useCallback((e: React.MouseEvent) => { e.stopPropagation(); setOpen(true); @@ -111,20 +111,21 @@ const MobileTextValue = ({ }, [onChange, tempValue]); const t = useI18n(); useEffect(() => { - setTempValue(value); + setTempValue(value || ''); }, [value]); return ( - -
- {tempValue || - t['com.affine.page-properties.property-value-placeholder']()} -
- + <> + +
+ {tempValue || + t['com.affine.page-properties.property-value-placeholder']()} +
+
-
+ ); }; diff --git a/packages/frontend/core/src/components/mobile/config-modal/index.tsx b/packages/frontend/core/src/components/mobile/config-modal/index.tsx index 2e0c07a173..7a4d080eb4 100644 --- a/packages/frontend/core/src/components/mobile/config-modal/index.tsx +++ b/packages/frontend/core/src/components/mobile/config-modal/index.tsx @@ -44,9 +44,6 @@ export const ConfigModal = ({ animation="slideBottom" withoutCloseButton contentOptions={{ - onClick: e => { - e.stopPropagation(); - }, className: variant === 'page' ? styles.pageModalContent diff --git a/packages/frontend/core/src/mobile/dialogs/setting/dropdown-select.tsx b/packages/frontend/core/src/mobile/dialogs/setting/dropdown-select.tsx index ba350cb6fb..a73f66b389 100644 --- a/packages/frontend/core/src/mobile/dialogs/setting/dropdown-select.tsx +++ b/packages/frontend/core/src/mobile/dialogs/setting/dropdown-select.tsx @@ -64,7 +64,11 @@ export const SettingDropdownSelect = < ))} {...menuOptions} > -
+
{selectedItem?.label ?? ''} diff --git a/packages/frontend/core/src/mobile/dialogs/setting/row.layout.tsx b/packages/frontend/core/src/mobile/dialogs/setting/row.layout.tsx index a5a82df9e9..e287f9e5b9 100644 --- a/packages/frontend/core/src/mobile/dialogs/setting/row.layout.tsx +++ b/packages/frontend/core/src/mobile/dialogs/setting/row.layout.tsx @@ -10,7 +10,10 @@ export const RowLayout = ({ href, }: PropsWithChildren<{ label: ReactNode; href?: string }>) => { const content = ( - +
{label}
{children || diff --git a/packages/frontend/core/src/mobile/views/home-header/index.tsx b/packages/frontend/core/src/mobile/views/home-header/index.tsx index 9ed72f1ea7..f526e3d241 100644 --- a/packages/frontend/core/src/mobile/views/home-header/index.tsx +++ b/packages/frontend/core/src/mobile/views/home-header/index.tsx @@ -75,6 +75,7 @@ export const HomeHeader = () => { onClick={openSetting} size={28} icon={} + data-testid="settings-button" /> diff --git a/packages/frontend/core/src/modules/doc-info/views/database-properties/cells/rich-text.tsx b/packages/frontend/core/src/modules/doc-info/views/database-properties/cells/rich-text.tsx index 1f00afa71c..665c00ee2a 100644 --- a/packages/frontend/core/src/modules/doc-info/views/database-properties/cells/rich-text.tsx +++ b/packages/frontend/core/src/modules/doc-info/views/database-properties/cells/rich-text.tsx @@ -97,7 +97,8 @@ const MobileRichTextCell = ({ const [open, setOpen] = useState(false); const name = useLiveData(cell.property.name$); return ( - setOpen(true)}> + <> + setOpen(true)}> setOpen(false)} open={open} @@ -125,7 +126,7 @@ const MobileRichTextCell = ({ onChange={onChange} rowId={rowId} /> - + ); }; diff --git a/tests/affine-mobile/e2e/settings.spec.ts b/tests/affine-mobile/e2e/settings.spec.ts new file mode 100644 index 0000000000..5110ecf89c --- /dev/null +++ b/tests/affine-mobile/e2e/settings.spec.ts @@ -0,0 +1,60 @@ +import { test } from '@affine-test/kit/mobile'; +import { expect, type Page } from '@playwright/test'; + +const openSettings = async (page: Page) => { + await page.getByTestId('settings-button').click(); + await expect(page.getByRole('dialog')).toBeVisible(); + await expect(page.locator('header:has-text("Settings")')).toBeVisible(); +}; + +test('can open settings', async ({ page }) => { + await openSettings(page); +}); + +test('can change theme', async ({ page }) => { + await openSettings(page); + await page + .getByTestId('setting-row') + .filter({ + hasText: 'Color mode', + }) + .getByTestId('dropdown-select-trigger') + .click(); + + await expect( + page.getByRole('dialog').filter({ + has: page.getByRole('menuitem', { name: 'Light' }), + }) + ).toBeVisible(); + + await page.getByRole('menuitem', { name: 'Dark' }).click(); + + await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark'); +}); + +test('can close change theme popover by clicking outside', async ({ page }) => { + await openSettings(page); + await page + .getByTestId('setting-row') + .filter({ + hasText: 'Color mode', + }) + .getByTestId('dropdown-select-trigger') + .click(); + + const themePopover = page.getByRole('dialog').filter({ + has: page.getByRole('menuitem', { name: 'Light' }), + }); + + await expect(themePopover).toBeVisible(); + + // get a mouse position that is 10px offset to the top of theme popover + // and click + const mousePosition = await themePopover.boundingBox(); + if (!mousePosition) { + throw new Error('theme popover is not visible'); + } + await page.mouse.click(mousePosition.x, mousePosition.y - 10); + + await expect(themePopover).not.toBeVisible(); +}); diff --git a/tests/affine-mobile/playwright.config.ts b/tests/affine-mobile/playwright.config.ts index 6d94a072b2..a9939684c1 100644 --- a/tests/affine-mobile/playwright.config.ts +++ b/tests/affine-mobile/playwright.config.ts @@ -10,19 +10,21 @@ const config: PlaywrightTestConfig = { timeout: process.env.CI ? 60_000 : 30_000, outputDir: testResultDir, projects: [ - { - name: 'Mobile Safari', - use: { - ...devices['iPhone 14'], - }, - }, + process.env.CI + ? { + name: 'Mobile Safari', + use: { + ...devices['iPhone 14'], + }, + } + : undefined, { name: 'Mobile Chrome', use: { ...devices['Pixel 5'], }, }, - ], + ].filter(config => config !== undefined), expect: { timeout: process.env.CI ? 15_000 : 5_000, },