NextJS 13.4客户端组件在Playwright测试中表单异常提交问题
解决Next.js 13.4 App Router中表单意外提交导致Playwright测试失败的问题
问题分析
点击type="button"的按钮本不应触发表单默认提交,但测试中出现页面刷新,大概率是以下几个原因:
- 客户端组件未正确标记
'use client',导致React hooks失效、事件处理逻辑未执行 - 表单元素存在属性错误,干扰了表单行为
- Playwright测试未等待组件完成hydration,操作时机过早
具体修复步骤
1. 确保所有客户端组件添加'use client'指令
在Next.js 13.4 App Router中,使用useState、自定义hooks(如useModal)的组件必须显式声明为客户端组件,否则会被当作服务器组件执行,导致hooks报错、事件逻辑失效。
在InitialForm.jsx、Modal.jsx、SignUpForm.jsx的顶部添加:
'use client'; // 后续导入和组件代码
2. 修正表单元素的属性错误
你的InitialForm中第二个输入框的name属性写错为"name",这会导致表单数据异常,甚至干扰默认行为,修正为:
<input name="name" onChange={(e) => setName(e.target.value)} /> <input name="email" onChange={(e) => setEmail(e.target.value)} />
3. 简化按钮事件逻辑,移除多余的preventDefault
type="button"的按钮默认不会触发表单提交,因此无需在onClick中调用event.preventDefault(),直接调用toggle即可:
<button type="button" data-testid="open-signup-modal-button" onClick={toggle} > Continue </button>
同时可以移除<form>上的onSubmit处理,因为没有触发提交的场景。
4. 验证useModal的正确性
确保自定义useModal hook正确切换状态:
'use client'; import { useState } from 'react'; export function useModal() { const [isVisible, setIsVisible] = useState(false); const toggle = () => setIsVisible(prev => !prev); return [isVisible, toggle]; }
5. 优化Playwright测试,适配Next.js Hydration
Next.js的App Router在页面加载时会进行hydration,过早操作元素可能导致逻辑未生效。修改测试代码,等待元素可交互后再操作:
test('should display SignUpForm on button clicked', async ({ page }) => { await page.goto('/'); // 等待按钮完全加载并可交互 await page.getByTestId('open-signup-modal-button').waitFor({ state: 'enabled' }); await page.getByTestId('open-signup-modal-button').click(); // 延长超时时间,确保模态框有足够时间渲染 await expect(page.getByTestId('modal-signup')).toBeVisible({ timeout: 5000 }); });
同时确保Modal组件的根元素添加了data-testid="modal-signup":
export default function Modal({ isVisible, hide, children }) { if (!isVisible) return null; return ( <div data-testid="modal-signup" className="modal-container"> {children} <button onClick={hide}>Close</button> </div> ); }
验证修复
完成上述修改后,重新运行Playwright测试,此时点击按钮会正确触发模态框显示,不会触发表单刷新。
内容的提问来源于stack exchange,提问作者Alejandro Bar
相关产品推荐
相关产品推荐

