diff --git a/packages/rmf-dashboard-framework/src/components/tasks/types/compose-clean.test.tsx b/packages/rmf-dashboard-framework/src/components/tasks/types/compose-clean.test.tsx
index 91683bcd1..074a341e3 100644
--- a/packages/rmf-dashboard-framework/src/components/tasks/types/compose-clean.test.tsx
+++ b/packages/rmf-dashboard-framework/src/components/tasks/types/compose-clean.test.tsx
@@ -45,6 +45,8 @@ describe('Compose clean task form', () => {
it('Validate task description', () => {
const desc = makeDefaultComposeCleanTaskDescription();
+ const emptyZoneDesc = insertCleaningZone(desc, '');
+ expect(isComposeCleanTaskDescriptionValid(emptyZoneDesc)).not.toBeTruthy();
const insertedDesc = insertCleaningZone(desc, 'clean_zone_3');
expect(isComposeCleanTaskDescriptionValid(insertedDesc)).toBeTruthy();
});
diff --git a/packages/rmf-dashboard-framework/src/components/tasks/types/custom-compose.test.tsx b/packages/rmf-dashboard-framework/src/components/tasks/types/custom-compose.test.tsx
new file mode 100644
index 000000000..718a93d6f
--- /dev/null
+++ b/packages/rmf-dashboard-framework/src/components/tasks/types/custom-compose.test.tsx
@@ -0,0 +1,31 @@
+import { fireEvent, render, screen } from '@testing-library/react';
+import { describe, expect, it, vi } from 'vitest';
+
+import { CustomComposeTaskForm } from './custom-compose';
+
+describe('Custom compose task form', () => {
+ it('Renders custom compose task form', async () => {
+ const onChange = vi.fn();
+ const onValidate = vi.fn();
+
+ render();
+ });
+
+ it('CustomComposeTaskForm validates input', () => {
+ const onChange = vi.fn();
+ const onValidate = vi.fn();
+
+ render();
+
+ const textArea = screen.getByRole('textbox', { name: /multiline/i });
+
+ // Invalid input (invalid JSON)
+ fireEvent.change(textArea, { target: { value: 'invalid json' } });
+ expect(onValidate).toHaveBeenCalledWith(false);
+
+ // Valid input
+ const validTaskDesc = '{"valid": "json"}';
+ fireEvent.change(textArea, { target: { value: validTaskDesc } });
+ expect(onValidate).toHaveBeenCalledWith(true);
+ });
+});
diff --git a/packages/rmf-dashboard-framework/src/components/tasks/types/cutsom-compose.stories.tsx b/packages/rmf-dashboard-framework/src/components/tasks/types/cutsom-compose.stories.tsx
new file mode 100644
index 000000000..f31f76dff
--- /dev/null
+++ b/packages/rmf-dashboard-framework/src/components/tasks/types/cutsom-compose.stories.tsx
@@ -0,0 +1,18 @@
+import { Meta, StoryObj } from '@storybook/react';
+
+import { CustomComposeTaskForm } from './custom-compose';
+
+export default {
+ title: 'Tasks/CustomComposeTaskForm',
+ component: CustomComposeTaskForm,
+} satisfies Meta;
+
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ taskDesc: '',
+ onChange: () => {},
+ onValidate: () => {},
+ },
+};