diff --git a/docs.md b/docs.md index 291ffaf..e771507 100644 --- a/docs.md +++ b/docs.md @@ -18,7 +18,7 @@ A wrapper around the `reduxForm` HOC exported from [redux-form](https://www.npmjs.com/package/redux-form) that gives it some extra functionality: 1. Makes extra options available for configuring the form -2. Wraps every `onSubmit` result in a promise. Additionally, wraps rejected `onSubmit` results in a `SubmissionError`. If the thrown error has an `errors` property, its value will be passed to `SubmissionError`. The original error will be accessible via the `SubmissionError`s `meta.error` property. This enables developers to access useful information regarding the origin of the failure, e.g., HTTP status. +2. Wraps every `onSubmit` result in a promise. Additionally, wraps rejected `onSubmit` results in a `SubmissionError`. If the thrown error has an `errors` property, its value will be passed to `SubmissionError`. Else, if the thrown error has a `message` property, this will be passed to a `SubmissionError` as a form-wide error. The original error will be accessible via the `SubmissionError`s `meta.error` property. This enables developers to access useful information regarding the origin of the failure, e.g., HTTP status. 3. Provides a default `onSubmit` function that resolves successfully and logs a warning. 4. Ignores any `onChange` events that occur on a pristine and untouched form, patching a bug in `redux-form v8`. diff --git a/package.json b/package.json index 9bc1a7a..52bd824 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@launchpadlab/lp-form", - "version": "2.9.0", + "version": "2.10.0", "description": "Extensions for the reduxForm HOC", "main": "lib/index.js", "scripts": { diff --git a/src/lpForm.js b/src/lpForm.js index ebcd0e8..252192d 100644 --- a/src/lpForm.js +++ b/src/lpForm.js @@ -24,7 +24,7 @@ import { * {@link https://www.npmjs.com/package/redux-form|redux-form} that gives it some extra functionality: * * 1. Makes extra options available for configuring the form - * 2. Wraps every `onSubmit` result in a promise. Additionally, wraps rejected `onSubmit` results in a `SubmissionError`. If the thrown error has an `errors` property, its value will be passed to `SubmissionError`. The original error will be accessible via the `SubmissionError`s `meta.error` property. This enables developers to access useful information regarding the origin of the failure, e.g., HTTP status. + * 2. Wraps every `onSubmit` result in a promise. Additionally, wraps rejected `onSubmit` results in a `SubmissionError`. If the thrown error has an `errors` property, its value will be passed to `SubmissionError`. Else, if the thrown error has a `message` property, this will be passed to a `SubmissionError` as a form-wide error. The original error will be accessible via the `SubmissionError`s `meta.error` property. This enables developers to access useful information regarding the origin of the failure, e.g., HTTP status. * 3. Provides a default `onSubmit` function that resolves successfully and logs a warning. * 4. Ignores any `onChange` events that occur on a pristine and untouched form, patching a bug in `redux-form v8`. * diff --git a/src/middleware/wrapSubmissionPromise.js b/src/middleware/wrapSubmissionPromise.js index f650f91..bb386b1 100644 --- a/src/middleware/wrapSubmissionPromise.js +++ b/src/middleware/wrapSubmissionPromise.js @@ -1,7 +1,7 @@ import { withPropsOnChange } from 'recompose' import { SubmissionError } from 'redux-form' import isPromise from 'is-promise' -import { getOr } from 'lodash/fp' +import { get } from 'lodash/fp' // Wrap submission results in a redux-form SubmissionError. // Also ensures that the return value of onSubmit is a promise. @@ -12,17 +12,31 @@ const wrapSubmissionPromise = withPropsOnChange( onSubmit: (...args) => { const result = onSubmit(...args) if (!isPromise(result)) return Promise.resolve(result) - return result.catch(err => { - const messages = getOr({}, 'errors', err) - const submissionError = new SubmissionError(messages) - - // Retain metadata (e.g., status code) about the original error - submissionError.meta = { error: err } - throw submissionError - }) + return result.catch(wrapSubmissionError) } } } ) +// Attempts to grab the errors or error message provided and wraps it in a redux-form SubmissionError +// The original error is stored in the error's `meta` key to retain metadata (e.g., status code) +function wrapSubmissionError (error) { + const messages = getErrorMessages(error) + const submissionError = new SubmissionError(messages) + + submissionError.meta = { error } + throw submissionError +} + +// Checks for an error that matches LPL's default standard for mapping error messages (HttpError). +// Else defaults to the standard error API and maps to a redux-form "form-wide" error key. +function getErrorMessages (err) { + const messages = get('errors', err) + + if (messages) return messages + + const formWideError = get('message', err) + return formWideError ? { _error: formWideError } : {} +} + export default wrapSubmissionPromise diff --git a/test/lpForm.test.js b/test/lpForm.test.js index cef3544..e1585ec 100644 --- a/test/lpForm.test.js +++ b/test/lpForm.test.js @@ -103,6 +103,39 @@ test('lpForm: retains information about the originating error during submit', () }) }) +test('lpForm: maps generic error messages to form-wide errors', () => { + expect.assertions(1) + const ERROR = "Unprocessable Entity" + const onSubmit = () => { + const error = new Error("Unprocessable Entity") + return Promise.reject(error) + } + const Wrapped = () =>