import { action } from 'storybook/actions'; import { Meta, StoryObj } from '@storybook/react-webpack5'; import { Status } from '../common'; import UploadInput, { UploadInputProps } from './UploadInput'; import { UploadedFile, UploadResponse } from './types'; import { userEvent } from 'storybook/test'; const meta: Meta = { title: 'Forms/UploadInput/Tests', tags: ['!manifest'], component: UploadInput, }; export default meta; type Story = StoryObj; const files: UploadedFile[] = [ { id: '0hd8hf8', filename: 'purchase-receipt-0.pdf', url: 'https://wise.com/public-resources/assets/logos/wise/brand_logo_inverse.svg', }, { id: '1r7hgc83', filename: 'purchase-receipt-1.pdf', }, { id: '2nhc7387hc8h', filename: 'purchase-receipt-2.pdf', url: 'https://wise.com/public-resources/assets/logos/wise/brand_logo_inverse.svg', }, { id: '39wd8uc', filename: 'receipt failed.png', status: Status.FAILED, }, { id: '437yyf8hf', filename: 'receipt failed With error string.png', status: Status.FAILED, error: 'Something went wrong', }, { id: '5biehveifh', filename: 'receipt failed With error object.png', status: Status.FAILED, error: { message: 'Something went wrong' }, }, ]; const createDelayedPromise = async ({ successful = true, delaySeconds = 3, response = { id: Math.round(Math.random() * 10000), url: '#' }, }: { successful?: boolean; delaySeconds?: number; response?: UploadResponse; } = {}): Promise => new Promise((resolve, reject) => { setTimeout( () => (successful ? resolve(response) : reject(new Error('Unexpected error'))), delaySeconds * 1000, ); }); const props = { onUploadFile: async () => createDelayedPromise(), onDeleteFile: async () => createDelayedPromise(), }; export const UploadInputWithDescriptionFromProps: Story = { args: { ...props, multiple: true, description: 'Custom file description from prop', }, }; export const Disabled: Story = { args: { ...props, disabled: true, }, }; export const WithAnyFileType: Story = { args: { ...props, fileTypes: '*', }, }; export const WithSingleFileType: Story = { args: { ...props, fileTypes: '.zip,application/zip', }, }; export const WithMultipleExistingFiles: Story = { args: { ...props, files, multiple: true, }, }; export const WithFileErrors: Story = { args: { ...props, files: [ { id: 1, filename: 'Error with default message.png', status: Status.FAILED }, { id: 2, filename: 'Error with `string` error.png', status: Status.FAILED, error: 'Single string error', }, { id: 3, filename: 'Error with `obj` error ({ message : `string` }).png', status: Status.FAILED, error: { message: 'Single obj error' }, }, { id: 4, filename: 'Error with single error passed in `array`.png', status: Status.FAILED, errors: ['Single error in array'], }, { id: 5, filename: 'Error with multiple `string` errors passed in `array`.png', status: Status.FAILED, errors: [ 'Error 1', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'Error 3', ], }, { id: 6, filename: 'Error with multiple `obj` errors passed in `array`.png', status: Status.FAILED, errors: [ { message: 'Error 1' }, { message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', }, { message: 'Error 3' }, ], }, ], multiple: true, }, }; export const WithoutDelete: Story = { args: { ...props, files, onDeleteFile: undefined, multiple: true, }, }; export const WithUploadFailed: Story = { args: { ...props, files: files.slice(0), onUploadFile: async () => createDelayedPromise({ successful: false }), multiple: true, }, }; export const WithDeleteFailed: Story = { args: { ...props, files: files.slice(0), onDeleteFile: async () => createDelayedPromise({ successful: false }), multiple: true, }, }; export const CustomConfirmMessage: Story = { args: { ...props, files: files.slice(0), deleteConfirm: { title: 'Sure you want to remove this invoice?', body: ( brand logo ), }, }, }; export const WithManualDownloadHandler: Story = { args: { ...props, files, onDownload: action('Manual download handler'), }, }; export const WithFilesChangeHandler: Story = { args: { ...props, files, onFilesChange: action('Files change handler'), }, }; export const WithMaxFilesToUploadLimit: Story = { args: { ...props, multiple: true, maxFiles: 5, maxFilesErrorMessage: "Can't upload as maximum number of files allowed are already uploaded", }, }; export const WithFileSizeErrorMessage: Story = { args: { ...props, sizeLimit: 1, sizeLimitErrorMessage: 'The file is oversized', }, }; export const WithNoSizeLimit: Story = { args: { ...props, sizeLimit: null, }, }; export const WithCustomUploadButtonTitle: Story = { args: { ...props, uploadButtonTitle: 'Upload the VAT receipts for FY 2022-23', }, }; const triggerModalAndConfirm = async ({ isLink = true } = {}) => { if (isLink) { await wait(); await userEvent.tab(); } await wait(); await userEvent.keyboard('{Enter}'); await wait(); await userEvent.tab(); await wait(); await userEvent.tab(); await wait(); await userEvent.tab(); await wait(); await userEvent.keyboard('{Enter}'); await wait(); }; const wait = async (time = 250) => new Promise((resolve) => { setTimeout(resolve, time); }); export const DeletingTop: Story = { args: { ...props, files: [files[0], files[1], files[2]], multiple: true, }, play: async () => { await userEvent.tab(); await triggerModalAndConfirm(); await triggerModalAndConfirm({ isLink: false }); await triggerModalAndConfirm(); }, }; export const DeletingBottom: Story = { args: { ...props, files: [files[0], files[1], files[2]], multiple: true, }, play: async () => { await userEvent.tab(); await userEvent.tab(); await userEvent.tab(); await userEvent.tab(); await triggerModalAndConfirm(); await triggerModalAndConfirm({ isLink: false }); await triggerModalAndConfirm(); }, };