From 3317b88151d3ed4749694da4d6f09e885b9385d9 Mon Sep 17 00:00:00 2001 From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com> Date: Sun, 27 Jul 2025 03:22:20 +0000 Subject: [PATCH 01/12] Fix textarea validation tests and success state display - Add missing success message display in textarea story (fetcher.data?.message) - Add comprehensive validation tests similar to text field story - Include testInvalidSubmission to verify validation errors show correctly - Include testValidSubmission to verify success state works properly - Add missing StoryContext import for test functions This ensures textarea component has the same validation behavior and test coverage as other form components. --- .../src/remix-hook-form/textarea.stories.tsx | 56 +++++++++++++------ 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/apps/docs/src/remix-hook-form/textarea.stories.tsx b/apps/docs/src/remix-hook-form/textarea.stories.tsx index 19864f7f..c77344c0 100644 --- a/apps/docs/src/remix-hook-form/textarea.stories.tsx +++ b/apps/docs/src/remix-hook-form/textarea.stories.tsx @@ -1,7 +1,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { Textarea } from '@lambdacurry/forms/remix-hook-form/textarea'; import { Button } from '@lambdacurry/forms/ui/button'; -import type { Meta, StoryObj } from '@storybook/react-vite'; +import type { Meta, StoryContext, StoryObj } from '@storybook/react-vite'; import { expect, userEvent, within } from '@storybook/test'; import { type ActionFunctionArgs, useFetcher } from 'react-router'; import { RemixFormProvider, createFormData, getValidatedFormData, useRemixForm } from 'remix-hook-form'; @@ -49,6 +49,7 @@ const ControlledTextareaExample = () => { + {fetcher.data?.message &&

{fetcher.data.message}

} {fetcher.data?.submittedMessage && (

Submitted message:

@@ -92,6 +93,41 @@ const meta: Meta = { export default meta; type Story = StoryObj; +// Test scenarios +const testInvalidSubmission = async ({ canvas }: StoryContext) => { + const messageInput = canvas.getByLabelText('Your message'); + const submitButton = canvas.getByRole('button', { name: 'Submit' }); + + // Clear the textarea and enter text that's too short + await userEvent.click(messageInput); + await userEvent.clear(messageInput); + await userEvent.type(messageInput, 'Short'); + await userEvent.click(submitButton); + + // Check for validation error + await expect(await canvas.findByText('Message must be at least 10 characters')).toBeInTheDocument(); +}; + +const testValidSubmission = async ({ canvas }: StoryContext) => { + const messageInput = canvas.getByLabelText('Your message'); + const submitButton = canvas.getByRole('button', { name: 'Submit' }); + + // Clear and enter valid text + await userEvent.click(messageInput); + await userEvent.clear(messageInput); + await userEvent.type(messageInput, 'This is a test message that is longer than 10 characters.'); + await userEvent.click(submitButton); + + // Check for success message + const successMessage = await canvas.findByText('Message submitted successfully'); + expect(successMessage).toBeInTheDocument(); + + // Check if the submitted message is displayed + await expect( + await canvas.findByText('This is a test message that is longer than 10 characters.'), + ).toBeInTheDocument(); +}; + export const Default: Story = { parameters: { docs: { @@ -100,20 +136,8 @@ export const Default: Story = { }, }, }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - // Enter text - const messageInput = canvas.getByLabelText('Your message'); - await userEvent.type(messageInput, 'This is a test message that is longer than 10 characters.'); - - // Submit the form - const submitButton = canvas.getByRole('button', { name: 'Submit' }); - await userEvent.click(submitButton); - - // Check if the submitted message is displayed - await expect( - await canvas.findByText('This is a test message that is longer than 10 characters.'), - ).toBeInTheDocument(); + play: async (storyContext) => { + await testInvalidSubmission(storyContext); + await testValidSubmission(storyContext); }, }; From c1c6e068c48c5cb08ad8945aafdbae966f1c28cf Mon Sep 17 00:00:00 2001 From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com> Date: Sun, 27 Jul 2025 03:30:02 +0000 Subject: [PATCH 02/12] Fix textarea component by adding React.forwardRef The textarea component was missing React.forwardRef which is required for React Hook Form to properly register and control the component. This was causing form submission to fail. Key changes: - Import React fully instead of just types - Wrap component in React.forwardRef - Add proper ref handling in both CustomTextarea and native textarea cases - Maintain existing functionality while adding ref support This matches the pattern used in other working form components like TextInput. --- packages/components/src/ui/textarea.tsx | 31 ++++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/components/src/ui/textarea.tsx b/packages/components/src/ui/textarea.tsx index cfe50489..7f9a16b1 100644 --- a/packages/components/src/ui/textarea.tsx +++ b/packages/components/src/ui/textarea.tsx @@ -1,4 +1,4 @@ -import type * as React from 'react'; +import * as React from 'react'; import { cn } from './utils'; export interface TextareaProps extends React.TextareaHTMLAttributes { @@ -7,20 +7,23 @@ export interface TextareaProps extends React.TextareaHTMLAttributes; } -const Textarea = ({ className, CustomTextarea, ...props }: TextareaProps) => { - if (CustomTextarea) return ; +const Textarea = React.forwardRef( + ({ className, CustomTextarea, ...props }, ref) => { + if (CustomTextarea) return ; - return ( -