From 2ac7e96d67e2bd5fad59b5d205e5031842353e81 Mon Sep 17 00:00:00 2001 From: Aaron Chong Date: Fri, 6 Dec 2024 16:25:30 +0800 Subject: [PATCH] delivery Signed-off-by: Aaron Chong --- .../tasks/types/delivery.stories.tsx | 20 +++ .../components/tasks/types/delivery.test.tsx | 163 ++++++++++++++++++ .../src/components/tasks/types/delivery.tsx | 10 +- .../src/components/tasks/types/patrol.tsx | 1 - 4 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 packages/rmf-dashboard-framework/src/components/tasks/types/delivery.stories.tsx create mode 100644 packages/rmf-dashboard-framework/src/components/tasks/types/delivery.test.tsx diff --git a/packages/rmf-dashboard-framework/src/components/tasks/types/delivery.stories.tsx b/packages/rmf-dashboard-framework/src/components/tasks/types/delivery.stories.tsx new file mode 100644 index 000000000..88870ee22 --- /dev/null +++ b/packages/rmf-dashboard-framework/src/components/tasks/types/delivery.stories.tsx @@ -0,0 +1,20 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { DeliveryTaskForm, makeDefaultDeliveryTaskDescription } from './delivery'; + +export default { + title: 'Tasks/DeliveryTaskForm', + component: DeliveryTaskForm, +} satisfies Meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + taskDesc: makeDefaultDeliveryTaskDescription(), + pickupPoints: { pickup_1: 'handler_1', pickup_2: 'handler_2' }, + dropoffPoints: { dropoff_1: 'handler_3', dropoff_2: 'handler_4' }, + onChange: () => {}, + onValidate: () => {}, + }, +}; diff --git a/packages/rmf-dashboard-framework/src/components/tasks/types/delivery.test.tsx b/packages/rmf-dashboard-framework/src/components/tasks/types/delivery.test.tsx new file mode 100644 index 000000000..4407c46d7 --- /dev/null +++ b/packages/rmf-dashboard-framework/src/components/tasks/types/delivery.test.tsx @@ -0,0 +1,163 @@ +import { fireEvent, render, screen, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { describe, expect, it, vi } from 'vitest'; + +import { + DeliveryTaskDefinition, + DeliveryTaskForm, + isDeliveryTaskDescriptionValid, + makeDefaultDeliveryTaskDescription, + makeDeliveryTaskBookingLabel, + makeDeliveryTaskShortDescription, +} from './delivery'; + +const mockPickupPoints = { + pickup_1: 'handler_1', + pickup_2: 'handler_2', +}; +const mockDropoffPoints = { + dropoff_1: 'handler_3', + dropoff_2: 'handler_4', +}; + +describe('Delivery task form', () => { + it('Delivery task form renders, changes and validates', async () => { + const onChange = vi.fn(); + const onValidate = vi.fn(); + + render( + , + ); + + let triggerCount = 1; + + const pickupPlace = screen.getByTestId('pickup-location'); + let input = within(pickupPlace).getByLabelText(/pickup location/i); + pickupPlace.focus(); + fireEvent.change(input, { target: { value: 'a' } }); + fireEvent.keyDown(pickupPlace, { key: 'ArrowDown' }); + fireEvent.keyDown(pickupPlace, { key: 'Enter' }); + expect(onChange).toHaveBeenCalledTimes(triggerCount); + expect(onValidate).toHaveBeenCalledTimes(triggerCount); + triggerCount += 1; + + const pickupPayload = screen.getByTestId('pickup-sku'); + pickupPayload.focus(); + input = within(pickupPayload).getByLabelText(/pickup sku/i); + fireEvent.change(input, { target: { value: 'coke' } }); + expect(onChange).toHaveBeenCalledTimes(triggerCount); + expect(onValidate).toHaveBeenCalledTimes(triggerCount); + triggerCount += 1; + + const pickupQuantity = screen.getByTestId('pickup-quantity'); + pickupQuantity.focus(); + input = within(pickupQuantity).getByLabelText(/quantity/i); + await userEvent.type(input, '1'); + expect(onChange).toHaveBeenCalledTimes(triggerCount); + expect(onValidate).toHaveBeenCalledTimes(triggerCount); + triggerCount += 1; + + const dropoffPlace = screen.getByTestId('dropoff-location'); + dropoffPlace.focus(); + input = within(dropoffPlace).getByLabelText(/dropoff location/i); + fireEvent.change(input, { target: { value: 'a' } }); + fireEvent.keyDown(dropoffPlace, { key: 'ArrowDown' }); + fireEvent.keyDown(dropoffPlace, { key: 'Enter' }); + expect(onChange).toHaveBeenCalledTimes(triggerCount); + expect(onValidate).toHaveBeenCalledTimes(triggerCount); + triggerCount += 1; + + const dropoffPayload = screen.getByTestId('dropoff-sku'); + dropoffPayload.focus(); + input = within(dropoffPayload).getByLabelText(/dropoff sku/i); + fireEvent.change(input, { target: { value: 'coke' } }); + expect(onChange).toHaveBeenCalledTimes(triggerCount); + expect(onValidate).toHaveBeenCalledTimes(triggerCount); + triggerCount += 1; + + const dropoffQuantity = screen.getByTestId('dropoff-quantity'); + pickupQuantity.focus(); + input = within(dropoffQuantity).getByLabelText(/quantity/i); + await userEvent.type(input, '1'); + expect(onChange).toHaveBeenCalledTimes(triggerCount); + expect(onValidate).toHaveBeenCalledTimes(triggerCount); + triggerCount += 1; + }); + + it('booking label', () => { + const desc = makeDefaultDeliveryTaskDescription(); + desc.pickup = { + handler: 'handler_1', + place: 'pickup_1', + payload: { + sku: 'coke', + quantity: 1, + }, + }; + desc.dropoff = { + handler: 'handler_3', + place: 'dropoff_1', + payload: { + sku: 'coke', + quantity: 1, + }, + }; + const label = makeDeliveryTaskBookingLabel(desc); + expect(label.task_definition_id).toBe(DeliveryTaskDefinition.taskDefinitionId); + expect(label.pickup).toBe('pickup_1'); + expect(label.destination).toBe('dropoff_1'); + expect(label.payload).toBe('coke'); + }); + + it('validity', () => { + const desc = makeDefaultDeliveryTaskDescription(); + expect(isDeliveryTaskDescriptionValid(desc)).not.toBeTruthy(); + + desc.pickup = { + handler: 'handler_1', + place: 'pickup_1', + payload: { + sku: 'coke', + quantity: 1, + }, + }; + desc.dropoff = { + handler: 'handler_3', + place: 'dropoff_1', + payload: { + sku: 'coke', + quantity: 1, + }, + }; + expect(isDeliveryTaskDescriptionValid(desc)).toBeTruthy(); + }); + + it('short description', () => { + const desc = makeDefaultDeliveryTaskDescription(); + desc.pickup = { + handler: 'handler_1', + place: 'pickup_1', + payload: { + sku: 'coke', + quantity: 1, + }, + }; + desc.dropoff = { + handler: 'handler_3', + place: 'dropoff_1', + payload: { + sku: 'coke', + quantity: 1, + }, + }; + expect(makeDeliveryTaskShortDescription(desc, undefined)).toBe( + '[Delivery] Pickup [coke] from [pickup_1], dropoff [coke] at [dropoff_1]', + ); + }); +}); diff --git a/packages/rmf-dashboard-framework/src/components/tasks/types/delivery.tsx b/packages/rmf-dashboard-framework/src/components/tasks/types/delivery.tsx index 46a3134a7..8badd3cef 100644 --- a/packages/rmf-dashboard-framework/src/components/tasks/types/delivery.tsx +++ b/packages/rmf-dashboard-framework/src/components/tasks/types/delivery.tsx @@ -34,7 +34,7 @@ export function makeDeliveryTaskBookingLabel( task_definition_id: DeliveryTaskDefinition.taskDefinitionId, pickup: task_description.pickup.place, destination: task_description.dropoff.place, - cart_id: task_description.pickup.payload.sku, + payload: task_description.pickup.payload.sku, }; } @@ -47,7 +47,7 @@ function isTaskPlaceValid(place: TaskPlace): boolean { ); } -function isDeliveryTaskDescriptionValid(taskDescription: DeliveryTaskDescription): boolean { +export function isDeliveryTaskDescriptionValid(taskDescription: DeliveryTaskDescription): boolean { return isTaskPlaceValid(taskDescription.pickup) && isTaskPlaceValid(taskDescription.dropoff); } @@ -107,6 +107,7 @@ export function DeliveryTaskForm({ { @@ -183,6 +186,7 @@ export function DeliveryTaskForm({ { diff --git a/packages/rmf-dashboard-framework/src/components/tasks/types/patrol.tsx b/packages/rmf-dashboard-framework/src/components/tasks/types/patrol.tsx index eb3cd20d8..550601170 100644 --- a/packages/rmf-dashboard-framework/src/components/tasks/types/patrol.tsx +++ b/packages/rmf-dashboard-framework/src/components/tasks/types/patrol.tsx @@ -76,7 +76,6 @@ interface PlaceListProps { function PlaceList({ places, onClick }: PlaceListProps) { const theme = useTheme(); - console.log(places); return (