Typorithm · medium

8. Form validation and keyboard behavior

qatestingplaywrightindependent-practice
Saved on this device
Full lesson · 4 learning steps Open any exercise for focused practice
1

Step 1 of 4 · intro card

8. Form validation and keyboard behavior

0%

Concept and contract

Verify input boundaries and accessible feedback through real controls.

A form test should observe how a user enters, submits and corrects data. Static prop types do not parse text, enforce server policy or prove that error feedback is accessible. Start with one field and a documented acceptance range before adding a large form fixture.

The lab’s Page limit accepts decimal integer text from one to three. Empty, fractional and out-of-range values receive visible feedback. This is a teaching contract; a real product may need different parsing, localization and server validation rules.

Mechanism and worked example

The worked test submits zero, observes the named error and confirms success feedback is absent.

The worked test submits zero, observes the named error and confirms success feedback is absent. It then corrects the value and submits again. This tests recovery as well as rejection, which a single invalid submission would not establish.

Use the label to locate the input and a role/name to locate the submit button. Keyboard interaction adds evidence that the control is usable without relying on a pointer. Automated checks still do not replace a complete accessibility review.

Complete worked example

typescript

import { test, expect } from "../support/test.js";
test("invalid limit can be corrected", async ({page}) => {
  await page.goto("/");
  const field = page.getByLabel("Page limit");
  await field.fill("0");
  await page.getByRole("button", {name:"Check limit",exact:true}).click();
  await expect(page.getByText("Enter a whole number from 1 to 3")).toBeVisible();
  await field.fill("2");
  await field.press("Enter");
  await expect(page.getByText("Limit accepted", {exact:true})).toBeVisible();
});
Reasoning
The test observes both invalid feedback and successful correction through the actual form.

Counterexamples and common mistakes

The weak test verifies only that an input element exists.

The weak test verifies only that an input element exists. The field could accept an invalid value, fail to submit or display an unlabeled error while that check remains green. Presence is not the same contract as validation and correction.

Do not test only HTML attributes and assume server validation is covered. A client can be bypassed, and attributes may not represent the full business rule. Keep a separate API validation check for the actual server boundary when one exists.

Counterexample: what this check misses

typescript

import { test, expect } from "../support/test.js";
test("weak field presence", async ({page}) => {
  await page.goto("/");
  await expect(page.getByLabel("Page limit")).toBeVisible();
});
Reasoning
Presence alone says nothing about submission or validation behavior.

Independent practice: small task

Write a test that enters the upper accepted value three and submits with the keyboard.

Write a test that enters the upper accepted value three and submits with the keyboard. Verify Limit accepted and no visible range error. Then try four and require the error. Begin with the valid submission before adding the adjacent invalid value.

Optional extension: inspect focus after an error. Keep that policy explicit rather than assuming every form must move focus in the same way. The basic task is a short boundary-and-recovery interaction.

Step 1: Submit three using Enter. Step 2: Submit four and require the range error.

Practice starter: solve before reading the solution

typescript

import { test, expect } from "../support/test.js";
test("upper form boundary", async ({page}) => {
  await page.goto("/");
  // TODO: submit three, then four, and compare visible feedback.
});
Reasoning
Start with the accepted endpoint and add its outside neighbor.
  • Hint 1: Use the input label, not a DOM position.
  • Hint 2: Keep client and server validation evidence separate.

Solution, tests and trade-offs

The solution uses Enter in the input to submit the form and observes visible feedback.

The solution uses Enter in the input to submit the form and observes visible feedback. It checks both the accepted endpoint and its nearest outside neighbor. The API’s own limit checks remain separate because this form is an isolated client validation exercise.

Run the browser interaction rather than evaluating the form handler directly. That keeps labels, submission wiring and visible state in the exercised path. A pure parser test can complement it but cannot establish those UI connections.

Practice solution and acceptance checks

typescript

import { test, expect } from "../support/test.js";
test("upper form boundary", async ({page}) => {
  await page.goto("/");
  const field = page.getByLabel("Page limit");
  await field.fill("3"); await field.press("Enter");
  await expect(page.getByText("Limit accepted", {exact:true})).toBeVisible();
  await expect(page.getByText("Enter a whole number from 1 to 3")).toBeHidden();
  await field.fill("4"); await field.press("Enter");
  await expect(page.getByText("Enter a whole number from 1 to 3")).toBeVisible();
});
Reasoning
Keyboard submission and visible feedback remain part of the exercised path.

Interview reasoning and next step

In interviews, describe which evidence comes from parser tests, API tests and browser interaction.

In interviews, describe which evidence comes from parser tests, API tests and browser interaction. Show one valid boundary and one correction path. Explain why an element-exists assertion is too weak for a validation requirement.

Next, control network failures and time-dependent behavior so asynchronous UI tests remain deterministic without live provider calls.

Optional stretch — after the core task works: Define and verify the desired focus behavior after an error.

Computer practice: download the companion lab at https://applydjinn.com/typorithm/qa-lab-20261105.zip. Read its README, install the pinned tools and run the accepted examples before attempting a starter. The mobile reader preserves your reading and self-check progress; the local lab runs browser tests separately.

Verify input boundaries and accessible feedback through real controls.