Skip to content

Commit

Permalink
feat: #652 Upload CSV should validate before submit (#750)
Browse files Browse the repository at this point in the history
* feat: #652 upload CSV should validate before submit
  • Loading branch information
Cuong Vu authored Mar 30, 2020
1 parent 986f5eb commit 25dc1f2
Show file tree
Hide file tree
Showing 20 changed files with 930 additions and 176 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react'
import { Cell, SetData, SetSelected, SetContextMenuProp, AfterCellsChanged } from '../types'
import { Cell, SetData, SetSelected, SetUploadData, SetContextMenuProp, AfterCellsChanged } from '../types'

export const parseResult = {
data: [
Expand Down Expand Up @@ -112,6 +112,7 @@ export const setData: SetData = jest.fn()

export const setSelected: SetSelected = jest.fn()
export const setContextMenuProp: SetContextMenuProp = jest.fn()
export const setUploadData: SetUploadData = jest.fn()

export const selectedMatrix = {
start: { i: 0, j: 1 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ exports[`Spreadsheet should match snapshot with default props 1`] = `
selected={null}
setContextMenuProp={[Function]}
/>
<Component
setUploadData={[Function]}
uploadData={
Object {
"exceedMaxRow": false,
"invalidIndies": Array [],
"isModalOpen": false,
"shouldProcess": false,
"totalRow": 0,
"validatedData": Array [
Array [],
],
}
}
/>
</div>
`;

Expand Down Expand Up @@ -138,6 +153,21 @@ exports[`Spreadsheet should match snapshot with full props 1`] = `
selected={null}
setContextMenuProp={[Function]}
/>
<Component
setUploadData={[Function]}
uploadData={
Object {
"exceedMaxRow": false,
"invalidIndies": Array [],
"isModalOpen": false,
"shouldProcess": false,
"totalRow": 0,
"validatedData": Array [
Array [],
],
}
}
/>
</div>
`;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ModalUpload should match snapshot with default prop 1`] = `
<Component
afterClose={[Function]}
footerItems={
<React.Fragment>
<Unknown
onClick={[Function]}
type="button"
variant="secondary"
>
Close
</Unknown>
<Unknown
onClick={[Function]}
type="button"
variant="primary"
>
Process valid rows
</Unknown>
</React.Fragment>
}
tapOutsideToDissmiss={false}
title="Process with 1 valid rows?"
visible={true}
>
<div>
<Component
className="has-text-info"
>
All rows are valid!
</Component>
<ul />
</div>
</Component>
`;

exports[`ModalUpload should match snapshot with modified props 1`] = `
<Component
afterClose={[Function]}
footerItems={
<React.Fragment>
<Unknown
onClick={[Function]}
type="button"
variant="secondary"
>
Close
</Unknown>
<Unknown
onClick={[Function]}
type="button"
variant="primary"
>
Process valid rows
</Unknown>
</React.Fragment>
}
tapOutsideToDissmiss={false}
title="Process with 4 valid rows?"
visible={true}
>
<div>
<Component
className="has-text-danger"
>
Found 2 invalid rows
</Component>
<ul>
<li
key="0"
>
Row:
<span
className="has-text-danger"
>
2
</span>
, Columns:
<span
className="has-text-danger"
>
3
</span>
, Value:
<span
className="has-text-danger"
>
hi
</span>
</li>
<li
key="1"
>
Row:
<span
className="has-text-danger"
>
3
</span>
, Columns:
<span
className="has-text-danger"
>
3
</span>
, Value:
<span
className="has-text-danger"
>
hi
</span>
</li>
<li
key="2"
>
Row:
<span
className="has-text-danger"
>
2
</span>
, Columns:
<span
className="has-text-danger"
>
5
</span>
, Value:
<span
className="has-text-danger"
>
hi
</span>
</li>
<li
key="3"
>
Row:
<span
className="has-text-danger"
>
2
</span>
, Columns:
<span
className="has-text-danger"
>
6
</span>
, Value:
<span
className="has-text-danger"
>
hi
</span>
</li>
</ul>
</div>
</Component>
`;
116 changes: 104 additions & 12 deletions packages/elements/src/components/Spreadsheet/__tests__/handlers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import {
hideContextMenu,
handleSetContextMenu,
handleInitialDataChanged,
setUploadDataCallback,
handleCloseUploadModal,
handleProcessValidRows,
} from '../handlers'
import {
data,
Expand All @@ -25,8 +28,17 @@ import {
parseResult,
setContextMenuProp,
afterCellsChanged,
setUploadData,
} from '../__stubs__'
import { getMaxRowAndCol, convertDataToCsv, unparseDataToCsvString, validatedDataGenerate } from '../utils'
import {
getMaxRowAndCol,
convertDataToCsv,
unparseDataToCsvString,
validatedDataGenerate,
parseCsvFile,
convertToCompatibleData,
createDataWithInvalidRowsRemoved,
} from '../utils'

const onDoubleClickDefault = jest.fn()

Expand Down Expand Up @@ -123,15 +135,23 @@ jest.mock('../utils', () => {
return {
getMaxRowAndCol: jest.fn().mockReturnValue({ maxRow: data.length, maxCol: data[0].length }),
parseCsvFile: jest.fn().mockResolvedValue(parseResult),
convertToCompatibleData: jest.fn(() => parseResult.data),
convertToCompatibleData: jest.fn().mockReturnValue(data),
convertDataToCsv: jest.fn().mockReturnValue(parseResult.data),
unparseDataToCsvString: jest.fn().mockReturnValue('unparse data'),
validatedDataGenerate: jest.fn().mockReturnValue('validated data'),
changedCellsGenerate: jest.fn().mockReturnValue('changes'),
createDataWithInvalidRowsRemoved: jest.fn().mockReturnValue([...data[0], ...data[1]]),
}
})

const validate = jest.fn()
const validateMatrix = [
[true, true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true, false],
[true, true, true, true, true, true, true, true, true, true, false],
]

const validate = jest.fn(() => validateMatrix)

afterEach(() => {
jest.clearAllMocks()
Expand Down Expand Up @@ -474,27 +494,64 @@ describe('handleCellsChanged', () => {
})

describe('handleOnChangeInput', () => {
it('should return with correct value when have target', async () => {
const fn = handleOnChangeInput(data, setData, validate)
afterAll(() => {
;(createDataWithInvalidRowsRemoved as jest.Mocked<any>).mockReturnValue([...data[0], ...data[1]])
})

it('should return correctly when dont have validation function', async () => {
const fn = handleOnChangeInput({ maxUploadRow: 1, setUploadData, validate: undefined })
const eventMock: any = {
target: {
files: ['data'],
},
}
const returnData = await fn(eventMock)
expect(validatedDataGenerate).toHaveBeenCalledWith(parseResult.data, validate)
expect(returnData).toBe('validated')
const result = await fn(eventMock)
expect(parseCsvFile).toHaveBeenCalledWith('data')
expect(convertToCompatibleData).toHaveBeenCalledWith(parseResult)
expect(setUploadData).toHaveBeenCalled()
expect(result).toBe('not validated')
})

it('should return with correct value when dont have file', async () => {
const fn = handleOnChangeInput(data, setData, validate)
it('should return correctly when have validation function', async () => {
const fn = handleOnChangeInput({ maxUploadRow: 3, setUploadData, validate })
const eventMock: any = {
target: {
files: ['data'],
},
}
const result = await fn(eventMock)
expect(parseCsvFile).toHaveBeenCalledWith('data')
expect(convertToCompatibleData).toHaveBeenCalledWith(parseResult)
expect(validate).toHaveBeenCalledWith(data.slice(0, 3))
expect(createDataWithInvalidRowsRemoved).toHaveBeenCalledWith(data.slice(0, 3), validateMatrix)
expect(setUploadData).toHaveBeenCalled()
expect(result).toBe('validated')
})

it('should return correctly when dont have target file', async () => {
const fn = handleOnChangeInput({ maxUploadRow: 30, setUploadData, validate })
const eventMock: any = {
target: {
files: null,
},
}
const returnData = await fn(eventMock)
expect(returnData).toBe(false)
const result = await fn(eventMock)
expect(result).toBe(false)
})

it('should return correctly when error', async () => {
;(createDataWithInvalidRowsRemoved as jest.Mocked<any>).mockImplementation(() => {
throw new Error('error1')
})
const fn = handleOnChangeInput({ maxUploadRow: 30, setUploadData, validate: () => [[true]] })
const eventMock: any = {
target: {
files: ['data'],
},
}
const result = await fn(eventMock)
expect(setUploadData).toHaveBeenCalled()
expect(result).toBe('error')
})
})

Expand Down Expand Up @@ -631,3 +688,38 @@ describe('handleInitialDataChanged', () => {
expect(setDataMock).toHaveBeenCalledWith('validated data')
})
})

describe('handleCloseUploadModal', () => {
it('should call setUploadData', () => {
const fn = handleCloseUploadModal(setUploadData)
fn()
expect(setUploadData).toHaveBeenCalled()
})
})

describe('handleProcessValidRows', () => {
it('should call setUploadData', () => {
const fn = handleProcessValidRows(setUploadData)
fn()
expect(setUploadData).toHaveBeenCalled()
})
})

describe('setUploadDataCallback', () => {
it('should return correct value', () => {
const prevUploadData = {
totalRow: 0,
validatedData: [[]],
invalidIndies: [],
shouldProcess: false,
isModalOpen: false,
exceedMaxRow: false,
}
const partialData = {
isModalOpen: true,
}
const fn = setUploadDataCallback(partialData)
const result = fn(prevUploadData)
expect(result).toEqual({ ...prevUploadData, isModalOpen: true })
})
})
Loading

0 comments on commit 25dc1f2

Please sign in to comment.