Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const fields = [

You can transform and validate data with custom hooks. There are hooks after each step:

- **fileSelectedHook** - runs only once after the file has been selected.
- **uploadStepHook** - runs only once after uploading the file.
- **selectHeaderStepHook** - runs only once after selecting the header row in spreadsheet.
- **matchColumnsStepHook** - runs only once after column matching. Operations on data that are expensive should be done here.
Expand Down
1 change: 1 addition & 0 deletions src/ReactSpreadsheetImport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const defaultRSIProps: Partial<RsiProps<any>> = {
autoMapDistance: 2,
isNavigationEnabled: false,
translations: translations,
fileSelectedHook: async (file) => {},
uploadStepHook: async (value) => value,
selectHeaderStepHook: async (headerValues, data) => ({ headerValues, data }),
matchColumnsStepHook: async (table) => table,
Expand Down
32 changes: 32 additions & 0 deletions src/steps/SelectSheetStep/tests/SelectSheetStep.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,35 @@ test("Should show error toast if error is thrown in uploadStepHook", async () =>
const errorToast = await screen.findAllByText(ERROR_MESSAGE, undefined, { timeout: 5000 })
expect(errorToast?.[0]).toBeInTheDocument()
})

test("Should show error toast if error is thrown in fileSelectedHook", async () => {
const fileSelectedHook = jest.fn(async () => {
throw new Error(ERROR_MESSAGE)
return undefined as any
})
render(<ReactSpreadsheetImport {...mockRsiValues} fileSelectedHook={fileSelectedHook} />)
const uploader = screen.getByTestId("rsi-dropzone")
const data = readFileSync(__dirname + "/../../../../static/Workbook1.xlsx")
fireEvent.drop(uploader, {
target: {
files: [
new File([data], "testFile.xlsx", {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
}),
],
},
})

const nextButton = await screen.findByRole(
"button",
{
name: "Next",
},
{ timeout: 5000 },
)

await userEvent.click(nextButton)

const errorToast = await screen.findAllByText(ERROR_MESSAGE, undefined, { timeout: 5000 })
expect(errorToast?.[0]).toBeInTheDocument()
})
6 changes: 6 additions & 0 deletions src/steps/UploadFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const UploadFlow = ({ state, onNext, onBack }: Props) => {
const {
maxRecords,
translations,
fileSelectedHook,
uploadStepHook,
selectHeaderStepHook,
matchColumnsStepHook,
Expand Down Expand Up @@ -87,6 +88,7 @@ export const UploadFlow = ({ state, onNext, onBack }: Props) => {
return
}
try {
await fileSelectedHook(file)
const mappedWorkbook = await uploadStepHook(mapWorkbook(workbook))
onNext({
type: StepType.selectHeader,
Expand All @@ -111,6 +113,10 @@ export const UploadFlow = ({ state, onNext, onBack }: Props) => {
return
}
try {
if (uploadedFile) {
await fileSelectedHook(uploadedFile)
}

const mappedWorkbook = await uploadStepHook(mapWorkbook(state.workbook, sheetName))
onNext({
type: StepType.selectHeader,
Expand Down
34 changes: 34 additions & 0 deletions src/steps/UploadStep/tests/UploadStep.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,37 @@ test("Should show error toast if error is thrown in uploadStepHook", async () =>
const errorToast = await screen.findAllByText(ERROR_MESSAGE, undefined, { timeout: 5000 })
expect(errorToast?.[0]).toBeInTheDocument()
})

test("Should call fileSelectedHook on file selection", async () => {
const file = new File(["Hello, Hello, Hello, Hello"], "test.csv", { type: "text/csv" })
const fileSelectedHook = jest.fn(async (file) => {})
render(<ReactSpreadsheetImport {...mockRsiValues} fileSelectedHook={fileSelectedHook} />)
const uploader = screen.getByTestId("rsi-dropzone")
fireEvent.drop(uploader, {
target: { files: [file] },
})

await waitFor(
() => {
expect(fileSelectedHook).toBeCalled()
},
{ timeout: 5000 },
)
})

test("Should show error toast if error is thrown in fileSelectedHook", async () => {
const file = new File(["Hello, Hello, Hello, Hello"], "test.csv", { type: "text/csv" })
const fileSelectedHook = jest.fn(async () => {
throw new Error(ERROR_MESSAGE)
return undefined as any
})
render(<ReactSpreadsheetImport {...mockRsiValues} fileSelectedHook={fileSelectedHook} />)

const uploader = screen.getByTestId("rsi-dropzone")
fireEvent.drop(uploader, {
target: { files: [file] },
})

const errorToast = await screen.findAllByText(ERROR_MESSAGE, undefined, { timeout: 5000 })
expect(errorToast?.[0]).toBeInTheDocument()
})
8 changes: 8 additions & 0 deletions src/stories/mockRsiValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ export const mockRsiValues = mockComponentBehaviourForTypes({
},
isOpen: true,
onClose: () => {},
// fileSelectedHook: async (file) => {
// await new Promise((resolve) => {
// setTimeout(() => {
// console.log(file);
// resolve();
// }, 4000)
// })
// },
// uploadStepHook: async (data) => {
// await new Promise((resolve) => {
// setTimeout(() => resolve(data), 4000)
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export type RsiProps<T extends string> = {
onClose: () => void
// Field description for requested data
fields: Fields<T>
// Runs after file selected for upload, receives the file data
fileSelectedHook?: (file: File) => Promise<void>
// Runs after file upload step, receives and returns raw sheet data
uploadStepHook?: (data: RawData[]) => Promise<RawData[]>
// Runs after header selection step, receives and returns raw sheet data
Expand Down