From 908f6ada4e4629fc02bc1a699f74c42a69a57ec4 Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Mon, 10 Aug 2026 10:53:43 +0800 Subject: [PATCH] fix(web): restore webapp password form submission (#40222) --- oxlint-suppressions.json | 3 - .../__tests__/mail-and-password-auth.spec.tsx | 76 +++++++++++++++++++ .../components/mail-and-password-auth.tsx | 20 ++--- 3 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 web/app/(shareLayout)/webapp-signin/components/__tests__/mail-and-password-auth.spec.tsx diff --git a/oxlint-suppressions.json b/oxlint-suppressions.json index 21fe1a65efb..9b760d2f0c5 100644 --- a/oxlint-suppressions.json +++ b/oxlint-suppressions.json @@ -139,9 +139,6 @@ } }, "web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx": { - "jsx_a11y/tabindex-no-positive": { - "count": 3 - }, "no-restricted-imports": { "count": 1 } diff --git a/web/app/(shareLayout)/webapp-signin/components/__tests__/mail-and-password-auth.spec.tsx b/web/app/(shareLayout)/webapp-signin/components/__tests__/mail-and-password-auth.spec.tsx new file mode 100644 index 00000000000..c8a7bda9c00 --- /dev/null +++ b/web/app/(shareLayout)/webapp-signin/components/__tests__/mail-and-password-auth.spec.tsx @@ -0,0 +1,76 @@ +import { render, screen, waitFor } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import MailAndPasswordAuth from '../mail-and-password-auth' + +const replaceMock = vi.fn() +const webAppLoginMock = vi.fn() +const fetchAccessTokenMock = vi.fn() +const searchParams = new URLSearchParams({ + redirect_url: encodeURIComponent('/chatbot/test-app'), +}) + +vi.mock('@/next/navigation', () => ({ + useRouter: () => ({ replace: replaceMock }), + useSearchParams: () => searchParams, +})) + +vi.mock('@/context/i18n', () => ({ + useLocale: () => 'en-US', +})) + +vi.mock('@/context/web-app-context', () => ({ + useWebAppStore: (selector: (state: { embeddedUserId: string }) => unknown) => + selector({ embeddedUserId: 'embedded-user-99' }), +})) + +vi.mock('@/service/common', () => ({ + webAppLogin: (...args: unknown[]) => webAppLoginMock(...args), +})) + +vi.mock('@/service/share', () => ({ + fetchAccessToken: (...args: unknown[]) => fetchAccessTokenMock(...args), +})) + +vi.mock('@/service/webapp-auth', () => ({ + setWebAppAccessToken: vi.fn(), + setWebAppPassport: vi.fn(), +})) + +describe('MailAndPasswordAuth', () => { + beforeEach(() => { + vi.clearAllMocks() + webAppLoginMock.mockResolvedValue({ + result: 'success', + data: { access_token: 'login-token' }, + }) + fetchAccessTokenMock.mockResolvedValue({ access_token: 'passport-token' }) + }) + + it('submits from the password field through the native form', async () => { + const user = userEvent.setup() + render() + + const emailInput = screen.getByRole('textbox', { name: 'login.email' }) + const passwordInput = screen.getByLabelText(/login\.password/) + const submitButton = screen.getByRole('button', { name: 'login.signBtn' }) + + expect(emailInput).toHaveAttribute('name', 'email') + expect(emailInput).toHaveAttribute('autocomplete', 'email') + expect(passwordInput).toHaveAttribute('name', 'password') + expect(passwordInput).toHaveAttribute('autocomplete', 'current-password') + expect(submitButton).toHaveAttribute('type', 'submit') + + await user.tab() + expect(emailInput).toHaveFocus() + await user.type(emailInput, 'user@example.com') + await user.tab() + expect(screen.getByRole('link', { name: 'login.forget' })).toHaveFocus() + await user.tab() + expect(passwordInput).toHaveFocus() + await user.type(passwordInput, 'strong-password{Enter}') + + await waitFor(() => { + expect(webAppLoginMock).toHaveBeenCalledTimes(1) + }) + }) +}) diff --git a/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx b/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx index 343643374d9..f52a78f100a 100644 --- a/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx +++ b/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx @@ -1,7 +1,6 @@ 'use client' import { Button } from '@langgenius/dify-ui/button' import { toast } from '@langgenius/dify-ui/toast' -import { noop } from 'es-toolkit/function' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { resolveWebAppLoginRedirect } from '@/app/(shareLayout)/webapp-signin/login-redirect' @@ -101,20 +100,26 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut } return ( -
+ { + event.preventDefault() + void handleEmailPasswordLogin() + }} + >
setEmail(e.target.value)} id="email" type="email" autoComplete="email" + spellCheck={false} placeholder={t(($) => $.emailPlaceholder, { ns: 'login' }) || ''} - tabIndex={1} />
@@ -135,16 +140,14 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
setPassword(e.target.value)} id="password" - onKeyDown={(e) => { - if (e.key === 'Enter') handleEmailPasswordLogin() - }} type={showPassword ? 'text' : 'password'} autoComplete="current-password" + spellCheck={false} placeholder={t(($) => $.passwordPlaceholder, { ns: 'login' }) || ''} - tabIndex={2} />