diff --git a/lib/idx/remediators/GenericRemediator/util.ts b/lib/idx/remediators/GenericRemediator/util.ts index b527b1ee0..32b9cbe9a 100644 --- a/lib/idx/remediators/GenericRemediator/util.ts +++ b/lib/idx/remediators/GenericRemediator/util.ts @@ -41,21 +41,19 @@ export function unwrapFormValue(remediation): Input { export function hasValidInputValue(input, values) { const fn = (input, values, requiredTracker) => { const { name, value, required } = input; - const isRequired = required - || requiredTracker - // TODO: confirm with backend why `required` meta is missing for authenticator remediation - || name === 'authenticator'; - if (!isRequired) { - return true; - } + const isRequired = required || requiredTracker; if (Array.isArray(value)) { return value.reduce((acc, item) => { return acc && fn(item, values[name], isRequired); }, true); - } else { - return !!(values && values[name]); } + + if (!isRequired) { + return true; + } + + return !!(values && values[name]); }; return fn(input, values, false); diff --git a/lib/idx/types/api.ts b/lib/idx/types/api.ts index fa451d94a..7cf5cf9ab 100644 --- a/lib/idx/types/api.ts +++ b/lib/idx/types/api.ts @@ -45,6 +45,9 @@ export type Input = { secret?: boolean; required?: boolean; options?: IdxOption[]; + relatesTo?: IdxAuthenticator; + mutable?: boolean; + visible?: boolean; } diff --git a/test/spec/idx/remediators/util/hasValidInputValue.ts b/test/spec/idx/remediators/util/hasValidInputValue.ts index 19f110df1..05583bd77 100644 --- a/test/spec/idx/remediators/util/hasValidInputValue.ts +++ b/test/spec/idx/remediators/util/hasValidInputValue.ts @@ -1,64 +1,320 @@ import { hasValidInputValue } from '../../../../../lib/idx/remediators/GenericRemediator/util'; describe('hasValidInputValue - validate each input with inputValues', () => { - + describe('primitive input', () => { - let input; - beforeAll(() => { - input = { name: 'identifier', required: true }; - }); + describe('value can be found', () => { + it('returns true when field is required', () => { + const input = { name: 'identifier', required: true }; + const values = { 'identifier': 'test@acme.com' }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); - it('returns false when required input is missing from values', () => { - const values = { 'identifier': undefined }; - const res = hasValidInputValue(input, values); - expect(res).toBe(false); + it('returns true when field is not required', () => { + const input = { name: 'identifier' }; + const values = { 'identifier': 'test@acme.com' }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); }); - it('returns true when required input can be found from values', () => { - const values = { 'identifier': 'test@acme.com' }; - const res = hasValidInputValue(input, values); - expect(res).toBe(true); + describe('value cannot be found', () => { + it('returns false when field is required', () => { + const input = { name: 'identifier', required: true }; + const values = { 'identifier': undefined }; + const res = hasValidInputValue(input, values); + expect(res).toBe(false); + }); + + it('returns true when field is not required', () => { + const input = { name: 'identifier' }; + const values = { 'identifier': 'test@acme.com' }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); }); }); - describe('object type input with values', () => { - let input; - beforeAll(() => { - input = { - name: 'credentials', - type: 'object', - required: true, - value: [{ - name: 'passcode', - }] - }; + describe('object type with required field at top level', () => { + describe('value can be found', () => { + it('returns true when field is required', () => { + const input = { + name: 'credentials', + type: 'object', + required: true, + value: [{ + name: 'passcode', + }] + }; + const values = { + credentials: { + passcode: 'abcd' + } + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); + + it('returns true if field is not required', () => { + const input = { + name: 'credentials', + type: 'object', + value: [{ + name: 'passcode', + }] + }; + const values = { + credentials: { + passcode: 'abcd' + } + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); + }); - it('returns true if values can be found', () => { - const values = { - credentials: { - passcode: 'abcd' - } - }; - const res = hasValidInputValue(input, values); - expect(res).toBe(true); + describe('value cannot be found', () => { + it('required - returns false ', () => { + const input = { + name: 'credentials', + type: 'object', + required: true, + value: [{ + name: 'passcode', + }] + }; + const values = { credentials: undefined }; + const res = hasValidInputValue(input, values); + expect(res).toBe(false); + }); + + it('required - returns false if nested name field is undefined', () => { + const input = { + name: 'credentials', + type: 'object', + required: true, + value: [{ + name: 'passcode', + }] + }; + const values = { + credentials: { + passcode: undefined + } + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(false); + }); + + it('required - returns false if main field is undefined', () => { + const input = { + name: 'credentials', + type: 'object', + required: true, + value: [{ + name: 'passcode', + }] + }; + const values = { + credentials: undefined + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(false); + }); + + it('not required - returns true if main field is undefined', () => { + const input = { + name: 'credentials', + type: 'object', + value: [{ + name: 'passcode', + }] + }; + const values = { + credentials: undefined + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); + + it('not required - returns true if nested field is undefined', () => { + const input = { + name: 'credentials', + type: 'object', + value: [{ + name: 'passcode', + }] + }; + const values = { + credentials: { + passcode: undefined + } + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); }); + }); - it('returns false if top level name field is undefined', () => { - const values = { credentials: undefined }; - const res = hasValidInputValue(input, values); - expect(res).toBe(false); + describe('nested fields with required', () => { + + describe('value can be found', () => { + it('all fields are required - returns true', () => { + const input = { + name: 'userProfile', + value: [ + { name: 'firstName', required: true }, + { name: 'email', required: true } + ] + }; + const values = { + userProfile: { + firstName: 'firstName', + email: 'email' + } + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); + + it('partial fields are required, all values are available - returns true', () => { + const input = { + name: 'userProfile', + value: [ + { name: 'firstName', required: true }, + { name: 'email' } + ] + }; + const values = { + userProfile: { + firstName: 'firstName', + email: 'email' + } + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); + + it('partial fields are required, only required values are available - returns true', () => { + const input = { + name: 'userProfile', + value: [ + { name: 'firstName', required: true }, + { name: 'email' } + ] + }; + const values = { + userProfile: { + firstName: 'firstName', + } + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); }); - it('returns false if nested name field is undefined', () => { - const values = { - credentials: { - passcode: undefined - } - }; - const res = hasValidInputValue(input, values); - expect(res).toBe(false); + describe('value cannnot be found', () => { + it('all fields are required, one required field is missing - returns false', () => { + const input = { + name: 'userProfile', + value: [ + { name: 'firstName', required: true }, + { name: 'email', required: true } + ] + }; + const values = { + userProfile: { + firstName: 'firstName', + } + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(false); + }); + + it('all fields are required, all required fields are missing - returns false', () => { + const input = { + name: 'userProfile', + value: [ + { name: 'firstName', required: true }, + { name: 'email', required: true } + ] + }; + const values = { + userProfile: {} + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(false); + }); + + it('all fields are required, top level field is missing - returns false', () => { + const input = { + name: 'userProfile', + value: [ + { name: 'firstName', required: true }, + { name: 'email', required: true } + ] + }; + const values = { + userProfile: undefined + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(false); + }); + + describe('not required', () => { + it('returns true when fields are available', () => { + const input = { + name: 'userProfile', + value: [ + { name: 'firstName' }, + { name: 'email' } + ] + }; + const values = { + userProfile: { + firstName: 'firstName', + email: 'email' + } + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); + + it('returns true when fields are missing', () => { + const input = { + name: 'userProfile', + value: [ + { name: 'firstName' }, + { name: 'email' } + ] + }; + const values = { + userProfile: {} + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); + + it('returns true when top level field is missing', () => { + const input = { + name: 'userProfile', + value: [ + { name: 'firstName' }, + { name: 'email' } + ] + }; + const values = { + userProfile: undefined + }; + const res = hasValidInputValue(input, values); + expect(res).toBe(true); + }); + }); + }); + }); });