diff --git a/packages/rmf-dashboard-framework/src/components/tasks/types/delivery-custom.test.tsx b/packages/rmf-dashboard-framework/src/components/tasks/types/delivery-custom.test.tsx
index beb544ab2..2a6ae1724 100644
--- a/packages/rmf-dashboard-framework/src/components/tasks/types/delivery-custom.test.tsx
+++ b/packages/rmf-dashboard-framework/src/components/tasks/types/delivery-custom.test.tsx
@@ -1,20 +1,46 @@
-import { describe, expect, it } from 'vitest';
+import { fireEvent, render, screen, within } from '@testing-library/react';
+import { describe, expect, it, vi } from 'vitest';
import {
+ DeliveryAreaPickupTaskDefinition,
deliveryCustomInsertCartId,
deliveryCustomInsertDropoff,
deliveryCustomInsertOnCancel,
deliveryCustomInsertPickup,
DeliveryCustomTaskDescription,
+ DeliveryCustomTaskForm,
deliveryInsertCartId,
deliveryInsertDropoff,
deliveryInsertOnCancel,
deliveryInsertPickup,
+ DeliveryPickupTaskDefinition,
DeliveryPickupTaskDescription,
+ DeliveryPickupTaskForm,
+ DeliverySequentialLotPickupTaskDefinition,
+ isDeliveryCustomTaskDescriptionValid,
+ isDeliveryPickupTaskDescriptionValid,
makeDefaultDeliveryCustomTaskDescription,
makeDefaultDeliveryPickupTaskDescription,
+ makeDeliveryCustomTaskBookingLabel,
+ makeDeliveryCustomTaskShortDescription,
+ makeDeliveryPickupTaskBookingLabel,
+ makeDeliveryPickupTaskShortDescription,
} from '.';
+const mockPickupPoints = {
+ pickup_1: 'handler_1',
+ pickup_2: 'handler_2',
+};
+const mockCartIds = ['cart_1', 'cart_2', 'cart_3'];
+const mockDropoffPoints = {
+ dropoff_1: 'handler_3',
+ dropoff_2: 'handler_4',
+};
+const mockPickupZones = {
+ pickup_1: 'zone_1',
+ pickup_2: 'zone_2',
+};
+
describe('Custom deliveries', () => {
it('delivery pickup', () => {
let deliveryPickupTaskDescription: DeliveryPickupTaskDescription | null = null;
@@ -133,6 +159,89 @@ describe('Custom deliveries', () => {
expect(deliveryPickupTaskDescription).toEqual(description);
});
+ it('delivery pickup 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 cartId = screen.getByTestId('cart-id');
+ cartId.focus();
+ input = within(cartId).getByLabelText(/cart id/i);
+ 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 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;
+ });
+
+ it('delivery pickup booking label', () => {
+ let desc = makeDefaultDeliveryPickupTaskDescription();
+ desc = deliveryInsertPickup(desc, 'test_place', 'test_lot');
+ desc = deliveryInsertCartId(desc, 'test_cart_id');
+ desc = deliveryInsertDropoff(desc, 'test_dropoff');
+ const label = makeDeliveryPickupTaskBookingLabel(desc);
+ expect(label.task_definition_id).toBe(DeliveryPickupTaskDefinition.taskDefinitionId);
+ expect(label.pickup).toBe('test_lot');
+ expect(label.destination).toBe('test_dropoff');
+ expect(label.cart_id).toBe('test_cart_id');
+ });
+
+ it('delivery pickup validity', () => {
+ let desc = makeDefaultDeliveryPickupTaskDescription();
+ expect(
+ isDeliveryPickupTaskDescriptionValid(desc, mockPickupPoints, mockDropoffPoints),
+ ).not.toBeTruthy();
+ desc = deliveryInsertPickup(desc, 'pickup_1', 'handler_1');
+ desc = deliveryInsertCartId(desc, 'cart_1');
+ desc = deliveryInsertDropoff(desc, 'dropoff_1');
+ expect(
+ isDeliveryPickupTaskDescriptionValid(desc, mockPickupPoints, mockDropoffPoints),
+ ).toBeTruthy();
+ });
+
+ it('delivery pickup short description', () => {
+ let desc = makeDefaultDeliveryPickupTaskDescription();
+ desc = deliveryInsertPickup(desc, 'pickup_1', 'handler_1');
+ desc = deliveryInsertCartId(desc, 'cart_1');
+ desc = deliveryInsertDropoff(desc, 'dropoff_1');
+ expect(makeDeliveryPickupTaskShortDescription(desc, undefined)).toBe(
+ '[Delivery - 1:1] payload [cart_1] from [pickup_1] to [dropoff_1]',
+ );
+ });
+
it('delivery_sequential_lot_pickup', () => {
let deliveryCustomTaskDescription: DeliveryCustomTaskDescription | null = null;
try {
@@ -369,4 +478,107 @@ describe('Custom deliveries', () => {
]);
expect(deliveryCustomTaskDescription).toEqual(description);
});
+
+ it('delivery custom task form renders, changes and validates', async () => {
+ const onChange = vi.fn();
+ const onValidate = vi.fn();
+
+ render(
+ ,
+ );
+
+ let triggerCount = 1;
+
+ const pickupPlace = screen.getByTestId('pickup-zone');
+ let input = within(pickupPlace).getByLabelText(/pickup zone/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 cartId = screen.getByTestId('cart-id');
+ cartId.focus();
+ input = within(cartId).getByLabelText(/cart id/i);
+ 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 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;
+ });
+
+ it('delivery custom booking label', () => {
+ let desc = makeDefaultDeliveryCustomTaskDescription('delivery_sequential_lot_pickup');
+ desc = deliveryCustomInsertPickup(desc, 'test_place', 'test_lot');
+ desc = deliveryCustomInsertCartId(desc, 'test_cart_id');
+ desc = deliveryCustomInsertDropoff(desc, 'test_dropoff');
+ let label = makeDeliveryCustomTaskBookingLabel(desc);
+ expect(label.task_definition_id).toBe(
+ DeliverySequentialLotPickupTaskDefinition.taskDefinitionId,
+ );
+ expect(label.pickup).toBe('test_lot');
+ expect(label.destination).toBe('test_dropoff');
+ expect(label.cart_id).toBe('test_cart_id');
+
+ desc = makeDefaultDeliveryCustomTaskDescription('delivery_area_pickup');
+ desc = deliveryCustomInsertPickup(desc, 'test_place', 'test_lot');
+ desc = deliveryCustomInsertCartId(desc, 'test_cart_id');
+ desc = deliveryCustomInsertDropoff(desc, 'test_dropoff');
+ label = makeDeliveryCustomTaskBookingLabel(desc);
+ expect(label.task_definition_id).toBe(DeliveryAreaPickupTaskDefinition.taskDefinitionId);
+ expect(label.pickup).toBe('test_lot');
+ expect(label.destination).toBe('test_dropoff');
+ expect(label.cart_id).toBe('test_cart_id');
+ });
+
+ it('delivery custom validity', () => {
+ let desc = makeDefaultDeliveryCustomTaskDescription('delivery_sequential_lot_pickup');
+ expect(
+ isDeliveryCustomTaskDescriptionValid(
+ desc,
+ Object.values(mockPickupZones),
+ Object.keys(mockDropoffPoints),
+ ),
+ ).not.toBeTruthy();
+ desc = deliveryCustomInsertPickup(desc, 'pickup_1', 'zone_1');
+ desc = deliveryCustomInsertCartId(desc, 'cart_1');
+ desc = deliveryCustomInsertDropoff(desc, 'dropoff_1');
+ expect(
+ isDeliveryCustomTaskDescriptionValid(
+ desc,
+ Object.values(mockPickupZones),
+ Object.keys(mockDropoffPoints),
+ ),
+ ).toBeTruthy();
+ });
+
+ it('delivery custom short description', () => {
+ let desc = makeDefaultDeliveryCustomTaskDescription('delivery_sequential_lot_pickup');
+ desc = deliveryCustomInsertPickup(desc, 'pickup_1', 'zone_1');
+ desc = deliveryCustomInsertCartId(desc, 'cart_1');
+ desc = deliveryCustomInsertDropoff(desc, 'dropoff_1');
+ expect(makeDeliveryCustomTaskShortDescription(desc, undefined)).toBe(
+ '[Delivery - Sequential lot pick up] payload [cart_1] from [pickup_1] to [dropoff_1]',
+ );
+ });
});
diff --git a/packages/rmf-dashboard-framework/src/components/tasks/types/delivery-custom.tsx b/packages/rmf-dashboard-framework/src/components/tasks/types/delivery-custom.tsx
index 86f87fd7b..4d607bb5d 100644
--- a/packages/rmf-dashboard-framework/src/components/tasks/types/delivery-custom.tsx
+++ b/packages/rmf-dashboard-framework/src/components/tasks/types/delivery-custom.tsx
@@ -237,7 +237,7 @@ export function makeDeliveryCustomTaskShortDescription(
return '[Unknown] delivery pickup task';
}
-const isDeliveryPickupTaskDescriptionValid = (
+export const isDeliveryPickupTaskDescriptionValid = (
taskDescription: DeliveryPickupTaskDescription,
pickupPoints: Record,
dropoffPoints: Record,
@@ -255,7 +255,7 @@ const isDeliveryPickupTaskDescriptionValid = (
);
};
-const isDeliveryCustomTaskDescriptionValid = (
+export const isDeliveryCustomTaskDescriptionValid = (
taskDescription: DeliveryCustomTaskDescription,
pickupZones: string[],
dropoffPoints: string[],
@@ -365,6 +365,7 @@ export function DeliveryPickupTaskForm({