Skip to content

Commit

Permalink
fix(select): support string type (#54)
Browse files Browse the repository at this point in the history
* feat(select) - support string type

* address comments

* chore: revert version

---------

Co-authored-by: Joe Ng'ethe <joe@remote.com>
  • Loading branch information
joeynimu and joe-ngethe-remote committed Oct 31, 2023
1 parent 445c128 commit b00f877
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 23 deletions.
81 changes: 62 additions & 19 deletions src/tests/createHeadlessForm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
schemaInputTypeRadioOptionsWithDetails,
schemaInputTypeSelectSoloDeprecated,
schemaInputTypeSelectSolo,
schemaInputTypeSelectString,
schemaInputTypeSelectMultipleDeprecated,
schemaInputTypeSelectMultiple,
schemaInputTypeSelectMultipleOptional,
Expand Down Expand Up @@ -430,35 +431,42 @@ describe('createHeadlessForm', () => {
});

describe('field support', () => {
function assertOptionsAllowed({ handleValidation, fieldName, validOptions }) {
function assertOptionsAllowed({ handleValidation, fieldName, validOptions, isString = false }) {
const validateForm = (vals) => friendlyError(handleValidation(vals));

// All allowed options are valid
validOptions.forEach((value) => {
expect(validateForm({ [fieldName]: value })).toBeUndefined();
});

// Any other arbitrary value is not valid.
expect(validateForm({ [fieldName]: 'blah-blah' })).toEqual({
[fieldName]: 'The option "blah-blah" is not valid.',
});
if (!isString) {
// Any other arbitrary value is not valid.
expect(validateForm({ [fieldName]: 'blah-blah' })).toEqual({
[fieldName]: 'The option "blah-blah" is not valid.',
});

// Given undefined, it says it's a required field.
expect(validateForm({})).toEqual({
[fieldName]: 'Required field',
});
// Given undefined, it says it's a required field.
expect(validateForm({})).toEqual({
[fieldName]: 'Required field',
});

// As required field, empty string ("") is also considered empty. @BUG RMT-518
// Expectation: The error to be "The option '' is not valid."
expect(validateForm({ [fieldName]: '' })).toEqual({
[fieldName]: 'Required field',
});
// As required field, empty string ("") is also considered empty. @BUG RMT-518
// Expectation: The error to be "The option '' is not valid."
expect(validateForm({ [fieldName]: '' })).toEqual({
[fieldName]: 'Required field',
});

// As required field, null is also considered empty @BUG RMT-518
// Expectation: The error to be "The option null is not valid."
expect(validateForm({ [fieldName]: null })).toEqual({
[fieldName]: 'Required field',
});
// As required field, null is also considered empty @BUG RMT-518
// Expectation: The error to be "The option null is not valid."
expect(validateForm({ [fieldName]: null })).toEqual({
[fieldName]: 'Required field',
});
}

if (isString) {
// Any other arbitrary value is valid.
expect(validateForm({ [fieldName]: 'blah-blah' })).toBeUndefined();
}
}

it('support "text" field type', () => {
Expand Down Expand Up @@ -630,6 +638,41 @@ describe('createHeadlessForm', () => {
});
});

it('supports "select" field type with string option', () => {
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeSelectString);
const fieldSelect = fields[0];
expect(fieldSelect).toMatchObject({
name: 'browsers',
label: 'Browsers (solo)',
description: 'This solo select also includes a disabled option.',
options: [
{
value: 'chr',
label: 'Chrome',
},
{
value: 'ff',
label: 'Firefox',
},
{
value: 'ie',
label: 'Internet Explorer',
disabled: true,
},
{ value: undefined, type: 'string', label: '{Create another}' },
],
});

expect(fieldSelect).not.toHaveProperty('multiple');

assertOptionsAllowed({
handleValidation,
fieldName: 'browsers',
validOptions: ['chr', 'ff', 'ie'],
isString: true,
});
});

it('supports "select" field type with multiple options @deprecated', () => {
const result = createHeadlessForm(schemaInputTypeSelectMultipleDeprecated);
expect(result).toMatchObject({
Expand Down
9 changes: 9 additions & 0 deletions src/tests/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ export const mockSelectInputSolo = {
},
};

export const mockSelectInputSoloCreatable = {
...mockSelectInputSolo,
oneOf: [...mockSelectInputSolo.oneOf, { type: 'string', title: '{Create another}' }],
};

export const mockSelectInputMultiple = {
title: 'Browsers (multiple)',
description: 'This multi-select also includes a disabled option.',
Expand Down Expand Up @@ -897,6 +902,10 @@ export const schemaInputTypeSelectSolo = JSONSchemaBuilder()
.setRequiredFields(['browsers'])
.build();

export const schemaInputTypeSelectString = JSONSchemaBuilder().addInput({
browsers: mockSelectInputSoloCreatable,
});

/** @deprecated */
export const schemaInputTypeSelectMultipleDeprecated = JSONSchemaBuilder()
.addInput({
Expand Down
13 changes: 9 additions & 4 deletions src/yupSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@ const validateMaxDate = (value, minDate) => {

const yupSchemas = {
text: validateOnlyStrings,
radioOrSelect: (options) =>
string()
radioOrSelect: (options, isString) => {
if (isString) {
return string().nullable();
}
return string()
.nullable()
.transform((value) => {
if (value === '') {
Expand Down Expand Up @@ -98,7 +101,8 @@ const yupSchemas = {
})
.oneOf(options, ({ value }) => {
return `The option ${JSON.stringify(value)} is not valid.`;
}),
});
},
date: ({ minDate, maxDate }) => {
let dateString = string()
.nullable()
Expand Down Expand Up @@ -182,8 +186,9 @@ const getYupSchema = ({ inputType, ...field }) => {
const jsonType = getJsonTypeInArray(field.jsonType);

if (field.options?.length > 0) {
const isString = field.options?.findIndex((option) => option.type === 'string') > -1;
const optionValues = getOptions(field);
return yupSchemas.radioOrSelect(optionValues);
return yupSchemas.radioOrSelect(optionValues, isString);
}

if (field.format === 'date') {
Expand Down

0 comments on commit b00f877

Please sign in to comment.