Skip to content

Commit

Permalink
Add a hidden honeypot field to all forms
Browse files Browse the repository at this point in the history
  • Loading branch information
lortimer committed Jan 26, 2024
1 parent 551935d commit 2c0d375
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
19 changes: 18 additions & 1 deletion src/components/form/Form.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ describe(Form.name, () => {
});

describe("without errors", () => {
let honeypotContainer: HTMLDivElement;
let honeypotInput: HTMLInputElement;
const honeypotValue = "I'm a robot";

beforeEach(async () => {
render(<FormWithInputs/>);

Expand All @@ -145,17 +149,30 @@ describe(Form.name, () => {

nameInput = within(form).getByRole("textbox", { name: "Name" });
ageInput = within(form).getByRole("textbox", { name: "Age" });
honeypotContainer = within(form).getByTestId("honeypot");
honeypotInput = within(honeypotContainer).getByRole("textbox", { name: "Robot Input" });
const radioButton: HTMLInputElement = within(form).getByRole("radio", { name: color });
submitButton = within(form).getByRole("button", { name: "Submit" });

await user.type(nameInput, name);
await user.type(ageInput, age);
await user.click(radioButton);
honeypotInput.value = honeypotValue;

submitButton.focus();
await user.keyboard(USER_EVENT_KEYS_FOR_TESTING_ONLY.enter);
});

test("has a hidden honeypot input with a description in case someone finds it", () => {
expect(honeypotContainer.className).toContain("display-none");

let honeypotDescriptionId = "honeypot-description";
expect(honeypotInput.getAttribute("aria-describedby")).toEqual(honeypotDescriptionId);

const honeypotDescription = within(honeypotContainer).getByText("This field is a trap for robots to prevent spam. Please don't fill it out.");
expect(honeypotDescription.id).toEqual(honeypotDescriptionId);
});

test("the submit button is aria-disabled", async () => {
await waitFor(() => {
expect(submitButton.className).toContain("disabled-form-submit");
Expand All @@ -180,7 +197,7 @@ describe(Form.name, () => {
});

test("the form's data is sent to the server", async () => {
expect(capturedFormData).toEqual({ name, age, color });
expect(capturedFormData).toEqual({ name, age, color, honeypotValue });
});

describe("when form submission succeeds", () => {
Expand Down
9 changes: 9 additions & 0 deletions src/components/form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ export const Form = ({ children, ariaLabelledBy, submitEndpoint, successMessage
{liveRegionText}
</div>
</div>
<div className={"display-none"} data-testid={"honeypot"}>
<label htmlFor={"robot-input"}>
Robot Input
<input name={"honeypotValue"} id={"robot-input"} aria-describedby={"honeypot-description"}/>
</label>
<p id={"honeypot-description"}>
This field is a trap for robots to prevent spam. Please don't fill it out.
</p>
</div>
</form>
</div>
);
Expand Down
4 changes: 4 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,7 @@ fieldset {
top: -10000px;
width: 1px;
}

.display-none {
display: none;
}

0 comments on commit 2c0d375

Please sign in to comment.