Skip to content
This repository has been archived by the owner on Mar 4, 2024. It is now read-only.

Initial FreeformInputWidget #48

Merged
merged 16 commits into from
Oct 5, 2023
8 changes: 7 additions & 1 deletion .nycrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@
"statements": 90,
"lines": 90,
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["cypress/**/*.*", "**/*.d.ts", "**/*.cy.tsx", "**/*.cy.ts","src/utils"]
"exclude": [
"cypress/**/*.*",
"**/*.d.ts",
"**/*.cy.tsx",
"**/*.cy.ts",
"src/utils"
]
}
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Fixed

- `StringListArrayWidget`, `StringListWidget`, `StringChoiceWidget` now fail gracefully in case of a mismatched persisted selection
- `StringListArrayWidget`, `StringListWidget`, `StringChoiceWidget` now fail gracefully in case of a mismatched persisted selection

## [6.1.14] 2023-06-14

Expand Down
13 changes: 13 additions & 0 deletions __tests__/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,16 @@ export const getStringChoiceWidgetConfiguration = () => {
type: 'StringChoiceWidget' as const
}
}

export const getFreeformInputWidgetConfiguration = () => {
return {
type: 'FreeformInputWidget' as const,
label: 'Freeform input',
name: 'freeform_input',
help: 'Enter a freeform input',
details: {
dtype: 'string' as const
},
required: true
}
}
81 changes: 81 additions & 0 deletions __tests__/widgets/FreeformInputWidget.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* Unit tests for FreeformInputWidget validation: string, integer and float values.
*/
import { expect } from '@jest/globals'

import { isDigitKey, isInteger, isFloat, keyDownHandler } from '../../src'

const asEvent = (key: string): React.KeyboardEvent<HTMLInputElement> => {
return {
key,
preventDefault: jest.fn(),
stopPropagation: jest.fn()
} as unknown as React.KeyboardEvent<HTMLInputElement>
}

describe('<FreeformInputWidget/>', () => {
describe('Validation', () => {
describe('Input validation', () => {
it('accepts digit input', () => {
expect(isDigitKey('1')).toBeTruthy()
expect(isDigitKey('0')).toBeTruthy()
expect(isDigitKey('9')).toBeTruthy()
})

it('accepts float input', () => {
expect(isFloat('Delete')).toBeTruthy()
expect(isFloat('Backspace')).toBeTruthy()
expect(isFloat('ArrowLeft')).toBeTruthy()
expect(isFloat('ArrowRight')).toBeTruthy()
expect(isFloat('ArrowUp')).toBeTruthy()
expect(isFloat('ArrowDown')).toBeTruthy()

expect(isFloat('.')).toBeTruthy()
expect(isFloat('0')).toBeTruthy()
expect(isFloat('1')).toBeTruthy()
expect(isFloat('9')).toBeTruthy()
})

it('accepts integer input', () => {
expect(isInteger('Delete')).toBeTruthy()
expect(isInteger('Backspace')).toBeTruthy()
expect(isInteger('ArrowLeft')).toBeTruthy()
expect(isInteger('ArrowRight')).toBeTruthy()
expect(isInteger('ArrowUp')).toBeTruthy()
expect(isInteger('ArrowDown')).toBeTruthy()

expect(isInteger('1')).toBeTruthy()
expect(isInteger('0')).toBeTruthy()
expect(isInteger('9')).toBeTruthy()
})

it('rejects digit input', () => {
expect(isDigitKey('a')).toBeFalsy()
expect(isDigitKey('b')).toBeFalsy()
expect(isDigitKey('A')).toBeFalsy()
})

it('rejects not int input', () => {
expect(isInteger('.')).toBeFalsy()
expect(isInteger('a')).toBeFalsy()
expect(isInteger('_')).toBeFalsy()
})

it('rejects not float input', () => {
expect(isFloat('a')).toBeFalsy()
expect(isFloat('_')).toBeFalsy()
})

it('keyDownHandler works as expected', () => {
const validator = keyDownHandler(isFloat)
let ev = asEvent('A')
expect(validator(ev))
expect(ev.preventDefault).toBeCalled()

ev = asEvent('2')
expect(validator(ev))
expect(ev.preventDefault).not.toBeCalled()
})
})
})
})
200 changes: 199 additions & 1 deletion cypress/component/ExclusiveGroupWidget.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
getStringListArrayWidgetConfiguration,
getGeographicExtentWidgetConfiguration,
getTextWidgetConfiguration,
getStringChoiceWidgetConfiguration
getStringChoiceWidgetConfiguration,
getFreeformInputWidgetConfiguration
} from '../../__tests__/factories'

const Form = ({
Expand Down Expand Up @@ -384,6 +385,202 @@ describe('<ExclusiveGroupWidget/>', () => {
])
})

it('with FreeformInputWidget and StringListArrayWidget', () => {
const configuration = {
type: 'ExclusiveGroupWidget' as const,
label: 'Generic selections',
help: null,
name: 'checkbox_groups',
children: ['variable', 'freeform_input'],
details: {
default: 'variable'
}
}

const formConfiguration = [
configuration,
getStringListArrayWidgetConfiguration(),
getFreeformInputWidgetConfiguration()
]

const stubbedHandleSubmit = cy.stub().as('stubbedHandleSubmit')

cy.viewport(800, 600)
cy.mount(
<TooltipProvider>
<Form handleSubmit={stubbedHandleSubmit}>
<ExclusiveGroupWidget
configuration={configuration}
childrenGetter={getExclusiveGroupChildren(
formConfiguration,
'checkbox_groups',
null,
{
renderActiveSelectionsCount: true
}
)}
/>
</Form>
</TooltipProvider>
).then(({ rerender }) => {
cy.findByLabelText('Lake shape factor').click()
cy.findByLabelText('Soil temperature level 3').click()

cy.findByText('submit').click()

cy.get('@stubbedHandleSubmit').should('have.been.calledOnceWith', [
['variable', 'soil_temperature_level_3'],
['variable', 'lake_shape_factor']
])

cy.log('Re-render with constraints.')
rerender(
<TooltipProvider>
<Form handleSubmit={stubbedHandleSubmit}>
<ExclusiveGroupWidget
configuration={configuration}
childrenGetter={getExclusiveGroupChildren(
formConfiguration,
'checkbox_groups',
{
variable: [
'lake_bottom_temperature',
'lake_ice_depth',
'lake_ice_temperature'
]
},
{
renderActiveSelectionsCount: true
}
)}
/>
</Form>
</TooltipProvider>
)

cy.findByLabelText('2m dewpoint temperature').should('be.disabled')
cy.findByLabelText('Lake bottom temperature').should('not.be.disabled')

cy.findByLabelText('Lake ice depth').click()
cy.findByText('Lakes').click()
cy.findByText('1 selected item')
})
})

it('with FreeformInputWidget and StringListWidget', () => {
const stubbedHandleSubmit = cy.stub().as('stubbedHandleSubmit')

cy.viewport(1200, 900)
const configuration = {
type: 'ExclusiveGroupWidget' as const,
label: 'Generic selections',
help: null,
name: 'checkbox_groups',
children: ['freeform_input', 'product_type'],
details: {
default: 'freeform_input'
}
}

const formConfiguration = [
configuration,
getFreeformInputWidgetConfiguration(),
getStringListWidgetConfiguration()
]

cy.mount(
<TooltipProvider>
<Form handleSubmit={stubbedHandleSubmit}>
<ExclusiveGroupWidget
configuration={configuration}
childrenGetter={getExclusiveGroupChildren(
formConfiguration,
'checkbox_groups'
)}
/>
</Form>
</TooltipProvider>
)

cy.findByLabelText('Freeform input')

cy.get('input[name="freeform_input"]').type('a value')

cy.findByText('submit').click()

cy.get('@stubbedHandleSubmit').should('have.been.calledOnceWith', [
['freeform_input', 'a value']
])
})

it('with FreeformInputWidget and TextWidget', () => {
cy.viewport(1200, 900)
const configuration = {
type: 'ExclusiveGroupWidget' as const,
label: 'Generic selections',
help: null,
name: 'checkbox_groups',
children: ['freeform_input', 'surface_help'],
details: {
default: 'freeform_input'
}
}

const formConfiguration = [
configuration,
getFreeformInputWidgetConfiguration(),
getTextWidgetConfiguration()
]

cy.mount(
<TooltipProvider>
<ExclusiveGroupWidget
configuration={configuration}
childrenGetter={getExclusiveGroupChildren(
formConfiguration,
'checkbox_groups'
)}
/>
</TooltipProvider>
)

cy.findByLabelText('Freeform input')
})

it('with FreeformInputWidget and StringChoiceWidget', () => {
cy.viewport(1200, 900)
const configuration = {
type: 'ExclusiveGroupWidget' as const,
label: 'Generic selections',
help: null,
name: 'checkbox_groups',
children: ['freeform_input', 'format'],
details: {
default: 'freeform_input'
}
}

const formConfiguration = [
configuration,
getFreeformInputWidgetConfiguration(),
getStringChoiceWidgetConfiguration()
]

cy.mount(
<TooltipProvider>
<ExclusiveGroupWidget
configuration={configuration}
childrenGetter={getExclusiveGroupChildren(
formConfiguration,
'checkbox_groups'
)}
/>
</TooltipProvider>
)

cy.findByLabelText('Freeform input')
})

it('multiple ExclusiveGroupWidget', () => {
const thisExclusive = {
type: 'ExclusiveGroupWidget' as const,
Expand Down Expand Up @@ -412,6 +609,7 @@ describe('<ExclusiveGroupWidget/>', () => {
otherExclusive,
getStringChoiceWidgetConfiguration(),
getTextWidgetConfiguration(),
getFreeformInputWidgetConfiguration(),
getStringListWidgetConfiguration(),
getGeographicExtentWidgetConfiguration(),
{
Expand Down
Loading