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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, update the CHANGELOG as well.

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