-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TWNTY-3316 - Add tests for
modules/spreadsheet-import
(#4219)
Add tests for `modules/spreadsheet-import` Co-authored-by: gitstart-twenty <[email protected]> Co-authored-by: RubensRafael <[email protected]>
- Loading branch information
1 parent
bc11cf8
commit 68a8502
Showing
19 changed files
with
1,236 additions
and
0 deletions.
There are no files selected for viewing
67 changes: 67 additions & 0 deletions
67
...twenty-front/src/modules/spreadsheet-import/hooks/__tests__/useSpreadsheetImport.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { act, renderHook } from '@testing-library/react'; | ||
import { RecoilRoot, useRecoilState } from 'recoil'; | ||
|
||
import { useSpreadsheetImport } from '@/spreadsheet-import/hooks/useSpreadsheetImport'; | ||
import { spreadsheetImportState } from '@/spreadsheet-import/states/spreadsheetImportState'; | ||
import { StepType } from '@/spreadsheet-import/steps/components/UploadFlow'; | ||
import { RawData, SpreadsheetOptions } from '@/spreadsheet-import/types'; | ||
|
||
const Wrapper = ({ children }: { children: React.ReactNode }) => ( | ||
<RecoilRoot>{children}</RecoilRoot> | ||
); | ||
type SpreadsheetKey = 'spreadsheet_key'; | ||
|
||
export const mockedSpreadsheetOptions: SpreadsheetOptions<SpreadsheetKey> = { | ||
isOpen: true, | ||
onClose: () => {}, | ||
fields: [], | ||
uploadStepHook: async () => [], | ||
selectHeaderStepHook: async (headerValues: RawData, data: RawData[]) => ({ | ||
headerValues, | ||
data, | ||
}), | ||
matchColumnsStepHook: async () => [], | ||
rowHook: () => ({ spreadsheet_key: 'rowHook' }), | ||
tableHook: () => [{ spreadsheet_key: 'tableHook' }], | ||
onSubmit: async () => {}, | ||
allowInvalidSubmit: false, | ||
customTheme: {}, | ||
maxRecords: 10, | ||
maxFileSize: 50, | ||
autoMapHeaders: true, | ||
autoMapDistance: 1, | ||
initialStepState: { | ||
type: StepType.upload, | ||
}, | ||
dateFormat: 'MM/DD/YY', | ||
parseRaw: true, | ||
rtl: false, | ||
selectHeader: true, | ||
}; | ||
|
||
describe('useSpreadsheetImport', () => { | ||
it('should set isOpen to true, and update the options in the Recoil state', async () => { | ||
const { result } = renderHook( | ||
() => ({ | ||
useSpreadsheetImport: useSpreadsheetImport<SpreadsheetKey>(), | ||
spreadsheetImportState: useRecoilState(spreadsheetImportState)[0], | ||
}), | ||
{ | ||
wrapper: Wrapper, | ||
}, | ||
); | ||
expect(result.current.spreadsheetImportState).toStrictEqual({ | ||
isOpen: false, | ||
options: null, | ||
}); | ||
act(() => { | ||
result.current.useSpreadsheetImport.openSpreadsheetImport( | ||
mockedSpreadsheetOptions, | ||
); | ||
}); | ||
expect(result.current.spreadsheetImportState).toStrictEqual({ | ||
isOpen: true, | ||
options: mockedSpreadsheetOptions, | ||
}); | ||
}); | ||
}); |
47 changes: 47 additions & 0 deletions
47
...nt/src/modules/spreadsheet-import/hooks/__tests__/useSpreadsheetImportInitialStep.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { useState } from 'react'; | ||
import { act, renderHook } from '@testing-library/react'; | ||
|
||
import { useSpreadsheetImportInitialStep } from '@/spreadsheet-import/hooks/useSpreadsheetImportInitialStep'; | ||
import { StepType } from '@/spreadsheet-import/steps/components/UploadFlow'; | ||
|
||
describe('useSpreadsheetImportInitialStep', () => { | ||
it('should return correct number for each step type', async () => { | ||
const { result } = renderHook(() => { | ||
const [step, setStep] = useState<StepType | undefined>(); | ||
const { initialStep } = useSpreadsheetImportInitialStep(step); | ||
return { initialStep, setStep }; | ||
}); | ||
|
||
expect(result.current.initialStep).toBe(-1); | ||
|
||
act(() => { | ||
result.current.setStep(StepType.upload); | ||
}); | ||
|
||
expect(result.current.initialStep).toBe(0); | ||
|
||
act(() => { | ||
result.current.setStep(StepType.selectSheet); | ||
}); | ||
|
||
expect(result.current.initialStep).toBe(0); | ||
|
||
act(() => { | ||
result.current.setStep(StepType.selectHeader); | ||
}); | ||
|
||
expect(result.current.initialStep).toBe(0); | ||
|
||
act(() => { | ||
result.current.setStep(StepType.matchColumns); | ||
}); | ||
|
||
expect(result.current.initialStep).toBe(2); | ||
|
||
act(() => { | ||
result.current.setStep(StepType.validateData); | ||
}); | ||
|
||
expect(result.current.initialStep).toBe(3); | ||
}); | ||
}); |
19 changes: 19 additions & 0 deletions
19
...ront/src/modules/spreadsheet-import/hooks/__tests__/useSpreadsheetImportInternal.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { renderHook } from '@testing-library/react'; | ||
|
||
import { Providers } from '@/spreadsheet-import/components/Providers'; | ||
import { mockedSpreadsheetOptions } from '@/spreadsheet-import/hooks/__tests__/useSpreadsheetImport.test'; | ||
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal'; | ||
|
||
const Wrapper = ({ children }: { children: React.ReactNode }) => ( | ||
<Providers values={mockedSpreadsheetOptions}>{children}</Providers> | ||
); | ||
|
||
describe('useSpreadsheetImportInternal', () => { | ||
it('should return the value provided by provider component', async () => { | ||
const { result } = renderHook(() => useSpreadsheetImportInternal(), { | ||
wrapper: Wrapper, | ||
}); | ||
|
||
expect(result.current).toBe(mockedSpreadsheetOptions); | ||
}); | ||
}); |
File renamed without changes.
209 changes: 209 additions & 0 deletions
209
packages/twenty-front/src/modules/spreadsheet-import/utils/__tests__/dataMutations.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
import { | ||
Data, | ||
Field, | ||
Info, | ||
RowHook, | ||
TableHook, | ||
} from '@/spreadsheet-import/types'; | ||
import { addErrorsAndRunHooks } from '@/spreadsheet-import/utils/dataMutations'; | ||
|
||
describe('addErrorsAndRunHooks', () => { | ||
type FullData = Data<'name' | 'age' | 'country'>; | ||
const requiredField: Field<'name'> = { | ||
key: 'name', | ||
label: 'Name', | ||
validations: [{ rule: 'required' }], | ||
icon: null, | ||
fieldType: { type: 'input' }, | ||
}; | ||
|
||
const regexField: Field<'age'> = { | ||
key: 'age', | ||
label: 'Age', | ||
validations: [ | ||
{ rule: 'regex', value: '\\d+', errorMessage: 'Regex error' }, | ||
], | ||
icon: null, | ||
fieldType: { type: 'input' }, | ||
}; | ||
|
||
const uniqueField: Field<'country'> = { | ||
key: 'country', | ||
label: 'Country', | ||
validations: [{ rule: 'unique' }], | ||
icon: null, | ||
fieldType: { type: 'input' }, | ||
}; | ||
|
||
const functionValidationFieldTrue: Field<'email'> = { | ||
key: 'email', | ||
label: 'Email', | ||
validations: [ | ||
{ | ||
rule: 'function', | ||
isValid: () => true, | ||
errorMessage: 'Field is invalid', | ||
}, | ||
], | ||
icon: null, | ||
fieldType: { type: 'input' }, | ||
}; | ||
|
||
const functionValidationFieldFalse: Field<'email'> = { | ||
key: 'email', | ||
label: 'Email', | ||
validations: [ | ||
{ | ||
rule: 'function', | ||
isValid: () => false, | ||
errorMessage: 'Field is invalid', | ||
}, | ||
], | ||
icon: null, | ||
fieldType: { type: 'input' }, | ||
}; | ||
|
||
const validData: Data<'name' | 'age'> = { name: 'John', age: '30' }; | ||
const dataWithoutNameAndInvalidAge: Data<'name' | 'age'> = { | ||
name: '', | ||
age: 'Invalid', | ||
}; | ||
const dataWithDuplicatedValue: FullData = { | ||
name: 'Alice', | ||
age: '40', | ||
country: 'Brazil', | ||
}; | ||
|
||
const data: Data<'name' | 'age'>[] = [ | ||
validData, | ||
dataWithoutNameAndInvalidAge, | ||
]; | ||
|
||
const basicError: Info = { message: 'Field is invalid', level: 'error' }; | ||
const nameError: Info = { message: 'Name Error', level: 'error' }; | ||
const ageError: Info = { message: 'Age Error', level: 'error' }; | ||
const regexError: Info = { message: 'Regex error', level: 'error' }; | ||
const requiredError: Info = { message: 'Field is required', level: 'error' }; | ||
const duplicatedError: Info = { | ||
message: 'Field must be unique', | ||
level: 'error', | ||
}; | ||
|
||
const rowHook: RowHook<'name' | 'age'> = jest.fn((row, addError) => { | ||
addError('name', nameError); | ||
return row; | ||
}); | ||
const tableHook: TableHook<'name' | 'age'> = jest.fn((table, addError) => { | ||
addError(0, 'age', ageError); | ||
return table; | ||
}); | ||
|
||
it('should correctly call rowHook and tableHook and add errors', () => { | ||
const result = addErrorsAndRunHooks( | ||
data, | ||
[requiredField, regexField], | ||
rowHook, | ||
tableHook, | ||
); | ||
|
||
expect(rowHook).toHaveBeenCalled(); | ||
expect(tableHook).toHaveBeenCalled(); | ||
expect(result[0].__errors).toStrictEqual({ | ||
name: nameError, | ||
age: ageError, | ||
}); | ||
}); | ||
|
||
it('should overwrite hook errors with validation errors', () => { | ||
const result = addErrorsAndRunHooks( | ||
data, | ||
[requiredField, regexField], | ||
rowHook, | ||
tableHook, | ||
); | ||
|
||
expect(rowHook).toHaveBeenCalled(); | ||
expect(tableHook).toHaveBeenCalled(); | ||
expect(result[1].__errors).toStrictEqual({ | ||
name: requiredError, | ||
age: regexError, | ||
}); | ||
}); | ||
|
||
it('should add errors for required field', () => { | ||
const result = addErrorsAndRunHooks(data, [requiredField]); | ||
|
||
expect(result[1].__errors).toStrictEqual({ | ||
name: requiredError, | ||
}); | ||
}); | ||
|
||
it('should add errors for regex field', () => { | ||
const result = addErrorsAndRunHooks(data, [regexField]); | ||
|
||
expect(result[1].__errors).toStrictEqual({ | ||
age: regexError, | ||
}); | ||
}); | ||
|
||
it('should add errors for unique field', () => { | ||
const result = addErrorsAndRunHooks( | ||
[ | ||
dataWithDuplicatedValue, | ||
dataWithDuplicatedValue, | ||
] as unknown as FullData[], | ||
[uniqueField], | ||
); | ||
|
||
expect(result[0].__errors).toStrictEqual({ | ||
country: duplicatedError, | ||
}); | ||
expect(result[1].__errors).toStrictEqual({ | ||
country: duplicatedError, | ||
}); | ||
}); | ||
|
||
it('should add errors for unique field with empty values', () => { | ||
const result = addErrorsAndRunHooks( | ||
[{ country: '' }, { country: '' }], | ||
[uniqueField], | ||
); | ||
|
||
expect(result[0].__errors).toStrictEqual({ | ||
country: duplicatedError, | ||
}); | ||
expect(result[1].__errors).toStrictEqual({ | ||
country: duplicatedError, | ||
}); | ||
}); | ||
|
||
it('should not add errors for unique field with empty values if allowEmpty is true', () => { | ||
const result = addErrorsAndRunHooks( | ||
[{ country: '' }, { country: '' }], | ||
[{ ...uniqueField, validations: [{ rule: 'unique', allowEmpty: true }] }], | ||
); | ||
|
||
expect(result[0].__errors).toBeUndefined(); | ||
expect(result[1].__errors).toBeUndefined(); | ||
}); | ||
|
||
it('should add errors for function validation if result is false', () => { | ||
const result = addErrorsAndRunHooks( | ||
[{ email: 'email' }], | ||
[functionValidationFieldFalse], | ||
); | ||
|
||
expect(result[0].__errors).toStrictEqual({ | ||
email: basicError, | ||
}); | ||
}); | ||
|
||
it('should not add errors for function validation if result is true', () => { | ||
const result = addErrorsAndRunHooks( | ||
[{ email: 'email' }], | ||
[functionValidationFieldTrue], | ||
); | ||
|
||
expect(result[0].__errors).toBeUndefined(); | ||
}); | ||
}); |
45 changes: 45 additions & 0 deletions
45
...ges/twenty-front/src/modules/spreadsheet-import/utils/__tests__/exceedsMaxRecords.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { WorkSheet } from 'xlsx-ugnis'; | ||
|
||
import { exceedsMaxRecords } from '@/spreadsheet-import/utils/exceedsMaxRecords'; | ||
|
||
describe('exceedsMaxRecords', () => { | ||
const maxRecords = 5; | ||
|
||
it('should return true if the number of records exceeds the maximum limit', () => { | ||
const workSheet: WorkSheet = { | ||
'!ref': 'A1:A10', | ||
}; | ||
|
||
const result = exceedsMaxRecords(workSheet, maxRecords); | ||
|
||
expect(result).toBe(true); | ||
}); | ||
|
||
it('should return false if the number of records does not exceed the maximum limit', () => { | ||
const workSheet: WorkSheet = { | ||
'!ref': 'A1:A4', | ||
}; | ||
|
||
const result = exceedsMaxRecords(workSheet, maxRecords); | ||
|
||
expect(result).toBe(false); | ||
}); | ||
|
||
it('should return false if the number of records is equal to the maximum limit', () => { | ||
const workSheet: WorkSheet = { | ||
'!ref': 'A1:A5', | ||
}; | ||
|
||
const result = exceedsMaxRecords(workSheet, maxRecords); | ||
|
||
expect(result).toBe(false); | ||
}); | ||
|
||
it('should return false if the worksheet does not have a defined range', () => { | ||
const workSheet: WorkSheet = {}; | ||
|
||
const result = exceedsMaxRecords(workSheet, maxRecords); | ||
|
||
expect(result).toBe(false); | ||
}); | ||
}); |
Oops, something went wrong.