import { dataTypes, Location, BindingType, Binding } from '@adalo/constants' import { IObject } from 'interfaces' import { formatLocation, getBindingData, getColumnStyle, getShouldFreezeFirstColumn, getColumnTypeDefaultAlignment, getColumnStyleAlignItemProp, } from './utils' import { Field, BindingDataItem, CellData } from './TableTypes' import { mockTableWithFrozenFirstColumn, mockTableWithNotFrozenFirstColumn, } from './__mocks__/tableObjects' jest.mock('../../utils/formats', () => ({ formatNumber: jest.fn().mockImplementation(value => `formatted ${value}`), formatDate: jest.fn().mockImplementation(value => `formatted date ${value}`), formatDateOnly: jest .fn() .mockImplementation(value => `formatted date only ${value}`), })) jest.mock('react-native', () => ({ Platform: { OS: 'web' }, })) const baseDefaultColumnStyle = getColumnStyle() const getDefaultColumnStyle = (fieldType?: Field['type']) => { const columnAlignment = getColumnTypeDefaultAlignment(fieldType) const alignItems = getColumnStyleAlignItemProp(columnAlignment) return { ...baseDefaultColumnStyle, alignItems } } const getColumnDefaultProps = (label: string, fieldType?: Field['type']) => ({ label, style: getDefaultColumnStyle(fieldType), sort: null, }) describe('Tables - utils', () => { describe('#formatLocation', () => { const formatLocationCases: [string, CellData, string | number][] = [ [ 'should return the city', { fieldId: 'field1', label: 'City', type: dataTypes.LOCATION, value: { addressElements: { address1: '', address2: '', city: 'San Francisco', state: 'CA', region: '', postalCode: '', }, placeId: '', fullAddress: '', coordinates: { latitude: 10, longitude: 10, }, } as Location, binding: { bindingType: 'property' as BindingType, format: { locationFormat: 'addressElements.city', }, source: { dataType: 'number', datasourceId: '5f2e8b6f3c5d6f001f2d9c8c', tableId: '5f2e8b6f3c5d6f001f2d9c9', type: 'field', }, type: 'binding', }, } as CellData, 'San Francisco', ], [ 'should return the state', { fieldId: 'field2', label: 'State', type: dataTypes.LOCATION, value: { addressElements: { address1: '', address2: '', city: '', state: 'CA', region: '', postalCode: '', }, placeId: '', fullAddress: '', coordinates: { latitude: 10, longitude: 10, }, } as Location, binding: { bindingType: 'property' as BindingType, format: { locationFormat: 'addressElements.state', }, source: { dataType: 'number', datasourceId: '5f2e8b6f3c5d6f001f2d9c8c', tableId: '5f2e8b6f3c5d6f001f2d9c9', type: 'field', }, type: 'binding', }, } as CellData, 'CA', ], [ 'should return the latitude', { fieldId: 'field3', label: 'Latitude', type: dataTypes.LOCATION, value: { addressElements: { address1: '', address2: '', city: '', state: '', region: '', postalCode: '', }, placeId: '', fullAddress: '', coordinates: { latitude: 37.7749, longitude: -122.4194, }, } as Location, binding: { bindingType: 'property' as BindingType, format: { locationFormat: 'coordinates.latitude', }, source: { dataType: 'number', datasourceId: '5f2e8b6f3c5d6f001f2d9c8c', tableId: '5f2e8b6f3c5d6f001f2d9c9', type: 'field', }, type: 'binding', }, } as CellData, 37.7749, ], [ 'should return empty string for missing path', { fieldId: 'field4', label: 'Country', type: dataTypes.LOCATION, value: { addressElements: { address1: '', address2: '', city: '', state: '', region: '', postalCode: '', }, placeId: '', fullAddress: '', coordinates: { latitude: 37.7749, longitude: -122.4194, }, } as Location, binding: { bindingType: 'property' as BindingType, format: { locationFormat: 'addressElements.country', }, source: { dataType: 'number', datasourceId: '5f2e8b6f3c5d6f001f2d9c8c', tableId: '5f2e8b6f3c5d6f001f2d9c9', type: 'field', }, type: 'binding', }, } as CellData, '', ], [ 'should return empty string for field with no format', { fieldId: 'field5', label: 'No Format', type: dataTypes.LOCATION, value: { addressElements: { address1: '', address2: '', city: '', state: '', region: '', postalCode: '', }, placeId: '', fullAddress: '', coordinates: { latitude: 37.7749, longitude: -122.4194, }, } as Location, binding: { bindingType: 'property' as BindingType, format: { type: '', }, source: { dataType: 'number', datasourceId: '5f2e8b6f3c5d6f001f2d9c8c', tableId: '5f2e8b6f3c5d6f001f2d9c9', type: 'field', }, type: 'binding', }, } as CellData, '', ], [ 'should return the whole location prop for field with no dot separated values', { fieldId: 'field6', label: 'Full Address', type: dataTypes.LOCATION, value: { addressElements: { address1: '', address2: '', city: '', state: '', region: '', postalCode: '', }, placeId: '', fullAddress: 'myfulladdress', coordinates: { latitude: 37.7749, longitude: -122.4194, }, } as Location, binding: { bindingType: 'property' as BindingType, format: { locationFormat: 'fullAddress', }, source: { dataType: 'number', datasourceId: '5f2e8b6f3c5d6f001f2d9c8c', tableId: '5f2e8b6f3c5d6f001f2d9c9', type: 'field', }, type: 'binding', }, } as CellData, 'myfulladdress', ], [ 'should return empty string for missing format', { fieldId: 'field7', label: 'No Format 2', type: dataTypes.LOCATION, value: { addressElements: { address1: '', address2: '', city: 'San Francisco', state: 'CA', region: '', postalCode: '', }, placeId: '', fullAddress: '', coordinates: { latitude: 10, longitude: 10, }, } as Location, binding: { bindingType: 'property' as BindingType, format: { type: '', }, source: { dataType: 'number', datasourceId: '5f2e8b6f3c5d6f001f2d9c8c', tableId: '5f2e8b6f3c5d6f001f2d9c9', type: 'field', }, type: 'binding', }, } as CellData, '', ], ] test.each(formatLocationCases)('%s', (_, field, expected) => { expect(formatLocation(field)).toEqual(expected) }) }) describe('#getBindingData', () => { const fields: Field[] = [ { fieldId: 'field1', label: 'Number Field', type: dataTypes.NUMBER, binding: { bindingType: 'property', format: { type: 'commas', currency: 'usd', columnWidth: 'standard', }, source: { dataType: 'number', datasourceId: '5f2e8b6f3c5d6f001f2d9c8c', tableId: '5f2e8b6f3c5d6f001f2d9c9', type: 'field', fieldId: 'field1', }, type: 'binding', } as Binding, }, { fieldId: 'field2', label: 'Date Field', type: dataTypes.DATE, binding: { bindingType: 'property', format: { type: 'relativeDate', columnWidth: 'standard', }, source: { dataType: 'date', datasourceId: '5f2e8b6f3c5d6f001f2d9c8c', tableId: '5f2e8b6f3c5d6f001f2d9c9', type: 'field', fieldId: 'field2', }, type: 'binding', } as Binding, }, { fieldId: 'field3', label: 'Boolean Field', type: dataTypes.BOOLEAN, binding: { bindingType: 'property', format: { columnWidth: 'standard', }, source: { dataType: 'boolean', datasourceId: '5f2e8b6f3c5d6f001f2d9c8c', tableId: '5f2e8b6f3c5d6f001f2d9c9', type: 'field', fieldId: 'field3', }, type: 'binding', } as Binding, }, ] const bindingData: BindingDataItem[] = [ { id: 1, field1: 123, field2: '2023-01-01T00:00:00Z', field3: true, }, { id: 2, field1: 456, field2: '2023-01-02T00:00:00Z', field3: false, }, ] const expected = { columns: [ { label: 'Number Field', type: dataTypes.NUMBER }, { label: 'Date Field', type: dataTypes.DATE }, { label: 'Boolean Field', type: dataTypes.BOOLEAN }, ].map(({ label, type }) => { const defaults = getColumnDefaultProps(label, type) if (label === 'Number Field') { return { ...defaults, sort: 'asc', } } return defaults }), data: [ { id: 1, cells: [ { fieldId: 'field1', type: dataTypes.NUMBER, value: 123, label: 'Number Field', binding: fields[0].binding, style: getDefaultColumnStyle(dataTypes.NUMBER), }, { fieldId: 'field2', type: dataTypes.DATE, value: '2023-01-01T00:00:00Z', label: 'Date Field', binding: fields[1].binding, style: getDefaultColumnStyle(dataTypes.DATE), }, { fieldId: 'field3', type: dataTypes.BOOLEAN, value: true, label: 'Boolean Field', binding: fields[2].binding, style: getDefaultColumnStyle(dataTypes.BOOLEAN), }, ], }, { id: 2, cells: [ { fieldId: 'field1', type: dataTypes.NUMBER, value: 456, label: 'Number Field', binding: fields[0].binding, style: getDefaultColumnStyle(dataTypes.NUMBER), }, { fieldId: 'field2', type: dataTypes.DATE, value: '2023-01-02T00:00:00Z', label: 'Date Field', binding: fields[1].binding, style: getDefaultColumnStyle(dataTypes.DATE), }, { fieldId: 'field3', type: dataTypes.BOOLEAN, value: false, label: 'Boolean Field', binding: fields[2].binding, style: getDefaultColumnStyle(dataTypes.BOOLEAN), }, ], }, ], } // @ts-expect-error need to add update `sort` in constants lib const object = { attributes: { fields, }, dataBinding: { source: { sort: { direction: 'asc', fieldId: 'field1', type: dataTypes.NUMBER, }, }, }, } as IObject it('should return the correct columns and data', () => { const result = getBindingData(object, bindingData) expect(result).toEqual(expected) }) it('should return empty arrays when bindingData is empty', () => { const result = getBindingData(object, []) expect(result).toEqual({ columns: [ { label: 'Number Field', type: dataTypes.NUMBER }, { label: 'Date Field', type: dataTypes.DATE }, { label: 'Boolean Field', type: dataTypes.BOOLEAN }, ].map(({ label, type }) => { const defaults = getColumnDefaultProps(label, type) if (label === 'Number Field') { return { ...defaults, sort: 'asc', } } return defaults }), data: [], }) }) it('should return empty arrays when fields are empty', () => { const objectNoFields = { attributes: {}, } as IObject const result = getBindingData(objectNoFields, bindingData) expect(result).toEqual({ columns: [], data: [] }) }) }) describe('#getShouldFreezeFirstColumn', () => { it('should return true if the first field has shouldFreezeFirstColumn set to true', () => { const result = getShouldFreezeFirstColumn(mockTableWithFrozenFirstColumn) expect(result).toBe(true) }) it('should return false if the first field has no shouldFreezeFirstColumn set', () => { const result = getShouldFreezeFirstColumn( mockTableWithNotFrozenFirstColumn ) expect(result).toBe(false) }) }) })