Skip to content

Commit

Permalink
ALD-11 | Add reCAPTCHA component (#198)
Browse files Browse the repository at this point in the history
* feat: remove stuff

* chore: allow conditionally recaptcha and call submit when completes

* feat: separate recaptcha into component and added tests

* feat: get recaptcha key from question data

* feat: add ReCAPTCHA usage info to readme

* feat: add imports

* fix: address comments

---------

Co-authored-by: Jesus Sabroso <jesussabroso@one-beyonds.com>
  • Loading branch information
NuriaExtremadouro and Jesus Sabroso committed Feb 29, 2024
1 parent 1499d19 commit d166e60
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 21 deletions.
56 changes: 38 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ http://guidesmiths-react-form-builder.s3-website.eu-central-1.amazonaws.com/


##### CountryAndRegionsData example:
```yaml
```json
[
{ "cn": "MyOwnCountry1", "cs": "MC1" },
{ "cn": "MyOwnCountry2", "cs": "MC2" },
Expand Down Expand Up @@ -114,7 +114,7 @@ Reminder: A custom link it will be indicated by the start of a '#' in the markdo

#### Checkbox example

```yaml
```json
{
"name": "terms_and_conditions",
"label": "This is the label of the checkbox with a [customLink](#customLink) and [normalLink](https://www.dcsl.com/careers/)",
Expand Down Expand Up @@ -155,7 +155,7 @@ https://user-images.githubusercontent.com/79102959/134894112-e4f38ced-0992-428c-
Reminder: the 'countryAndRegions' prop that can be sent in the ReactFormBuilder will be rendered in this component and will replace the default list.

### Country example:
```yaml
```json
{
"name": "country_of_residence",
"type": "country",
Expand Down Expand Up @@ -230,7 +230,7 @@ https://user-images.githubusercontent.com/79102959/134897712-95e4391c-cfbb-42cd-

### Date examples
Basic date example
```yaml
```json
{
"name": "dob",
"type": "date",
Expand All @@ -246,7 +246,7 @@ Basic date example
}
```
Under age date example
```yaml
```json
{
"name": "dob",
"type": "date",
Expand Down Expand Up @@ -292,7 +292,7 @@ https://user-images.githubusercontent.com/79102959/134897303-817957ba-12d1-4c0c-

### Input examples
Basic input example
```yaml
```json
{
"name": "email",
"type": "input",
Expand All @@ -308,7 +308,7 @@ Basic input example

```
Input with pattern control example
```yaml
```json
{
"name": "email",
"type": "input",
Expand All @@ -326,7 +326,7 @@ Input with pattern control example

```
Input with custom error (for example, if the user tries to sign up with an email that has already beeen used)
```yaml
```json
{
"name": "email",
"type": "input",
Expand All @@ -346,7 +346,7 @@ Input with custom error (for example, if the user tries to sign up with an email
```

Input with field descriptions
```yaml
```json
{
"name": "password",
"type": "password",
Expand Down Expand Up @@ -432,7 +432,7 @@ Markdown example

#### Multiplecheckbox examples
Basic multiplecheckbox
```yaml
```json
{
"name": "multiplecheckbox_name",
"type": "multiple_checkboxes",
Expand Down Expand Up @@ -465,7 +465,7 @@ Basic multiplecheckbox
```
Multiplecheckbox with images and labels

```yaml
```json
{
"name": "multiplecheckbox_name",
"type": "multiple_checkboxes",
Expand Down Expand Up @@ -499,7 +499,7 @@ Multiplecheckbox with images and labels
```

Multiplecheckbox with minimumLen
```yaml
```json
{
"name": "multiplecheckbox_name",
"type": "multiple_checkboxes",
Expand Down Expand Up @@ -555,7 +555,7 @@ Reminder: The isoCode prop that can also be sent in the ReactFormBuilder compone

Basic phone

```yaml
```json
{
"name": "phone",
"type": "phone",
Expand Down Expand Up @@ -592,7 +592,7 @@ https://user-images.githubusercontent.com/79102959/134948115-4f461d76-8d06-4cb8-

#### RadioButton example
Basic radiobutton
```yaml
```json
{
"name": "radio_name",
"label": "este es el texto de la pregunta",
Expand Down Expand Up @@ -649,7 +649,7 @@ https://user-images.githubusercontent.com/79102959/134948337-03618f4c-6cc7-409a-

Select basic example:

```yaml
```json
{
"name": "color",
"type": "select",
Expand Down Expand Up @@ -683,7 +683,7 @@ Select basic example:

Select example with custom arrows in the `public/icons` folder:

```yaml
```json
{
"name": "color",
"type": "select",
Expand Down Expand Up @@ -746,7 +746,7 @@ It works the same as select field, but searchable option is available.

Autocomplete basic example

```yaml
```json
{
"name": "color",
"type": "autocomplete",
Expand Down Expand Up @@ -778,6 +778,26 @@ Autocomplete basic example

```

## ReCAPTCHA

| Option | Description | Type | Default |
|--- |--- |:---: |:---: |
| name* | ReCAPTCHA name | string | - |
| type* | Must be `recaptcha`| string | - |
| recaptchaKey* | Key to make ReCAPTCHA work. Failing to provide this will lead to the ReCAPTCHA element showing with an error text inside. | string | - |

This feature is implemented using `react-google-recaptcha`. By default it shows at the bottom-right of your app and will only show the ReCAPTCHA modal when bot-like behavior is detected filling the form.

#### ReCAPTCHA example

```json
{
"name": "my-recaptcha",
"type": "recaptcha",
"recaptchaKey": "your-recaptcha-key"
}
```

# Accessibility

The accessibility requirements for all the form tags are already configured in the library. For components (input, checkbox, select, radio…) different attributes have been introduced that can be configured through props.
Expand All @@ -803,7 +823,7 @@ Next, we can see different attributes and tags to adjust the accessibility of th

### Main form

```yaml
```json
{
"en": {
"contact": {
Expand Down
3 changes: 2 additions & 1 deletion example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"debounce-promise": "^3.1.2",
"install": "^0.13.0",
"react-datepicker": "^4.23.0",
"react-google-recaptcha": "^3.1.0",
"react-hook-form": "^7.49.3",
"react-markdown": "^5.0.3",
"react-phone-number-input": "^3.3.9",
Expand Down
27 changes: 27 additions & 0 deletions src/Questions/Recaptcha/__tests__/recaptcha.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react'
import { render } from '@testing-library/react'
import '@testing-library/jest-dom'

import QuestionRecaptcha from '..'

const formDataValues = {}
const recaptchaRef = React.createRef(null)
const onSubmitForm = () => {}
const question = {
name: 'recaptcha',
type: 'recaptcha',
recaptchaKey: 'random'
}

test('renders a reCAPTCHA', () => {
const { getByTestId } = render(
<QuestionRecaptcha
ref={recaptchaRef}
formDataValues={formDataValues}
onSubmitForm={onSubmitForm}
question={question}
/>
)

expect(getByTestId('recaptcha-test')).toBeTruthy()
})
29 changes: 29 additions & 0 deletions src/Questions/Recaptcha/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { forwardRef } from 'react'
import ReCAPTCHA from 'react-google-recaptcha'

/** @jsxRuntime classic */
/** @jsx jsx */
import { jsx } from 'theme-ui'

const QuestionRecaptcha = forwardRef(({ formDataValues, onSubmitForm, question }, ref) => {
const onReCAPTCHAChange = async (captchaCode) => {
if (!captchaCode) {
return
}

ref?.current?.reset()
onSubmitForm(formDataValues)
}

return (
<ReCAPTCHA
ref={ref}
size="invisible"
sitekey={question.recaptchaKey}
onChange={onReCAPTCHAChange}
data-testid="recaptcha-test"
/>
)
})

export default QuestionRecaptcha
31 changes: 31 additions & 0 deletions src/__tests__/builder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,34 @@ describe('form builder with custom errors', () => {
expect(doesNotMatchError).not.toBe(null)
})
})

describe('form builder with reCAPTCHA', () => {
beforeEach(() => {
mockHandler = jest.fn()
component = render(
<FormBuilder
idForm={forms.recaptcha.id}
form={forms.recaptcha}
isoCode='ES'
onSubmit={mockHandler}
/>
)
})

afterEach(cleanup)

test('check it does not submit forms when they have a reCAPTCHA', async () => {
const button = component.getByText('Submit')
fireEvent.click(button)
expect(mockHandler).toHaveBeenCalledTimes(0)

const inputComponents = component.getAllByTestId('question-input')
fireEvent.change(inputComponents[0], { target: { value: 'name testing' } })
expect(inputComponents[0].value).toBe('name testing')

await act(async () => {
fireEvent.click(button)
})
expect(mockHandler).toHaveBeenCalledTimes(0)
})
})
Loading

0 comments on commit d166e60

Please sign in to comment.