diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d3a1a8..5ef697d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog
+## 2026-06-06
+
+### Changes
+- [Tester] Checkboxes and other toggle controls (switches, selectable rows/items) are no longer flipped back off by accident. The Tester now sets a checkbox with the idempotent `I.checkOption` / `I.uncheckOption` commands instead of `I.click`, so selecting an already-selected checkbox keeps it selected. It also reads the page state after each click and stops re-clicking a control once it already shows the wanted result (checked, selected, or a count/label confirming success). Previously a second click on a selected checkbox could toggle it off — for example dropping a "Select 32 tests" selection back to "Select 0 tests" and saving an empty result.
+- [Tester] Before filling a form that saves data (create/update), the Tester now reads each field's requirements — required, type/format, length, and placeholder/hint text — and enters values that satisfy them, instead of submitting and discovering validation errors. Search, filter, and sort forms that only change the view are skipped.
+
## 2026-06-04
### Changes
diff --git a/src/ai/rules.ts b/src/ai/rules.ts
index fe40137..bc4d41e 100644
--- a/src/ai/rules.ts
+++ b/src/ai/rules.ts
@@ -131,6 +131,12 @@ export const fileUploadRule = dedent`
`;
+export const formRequirementsRule = dedent`
+
+ Before filling a form that persists data (create/update), read each control's requirements (required, type/format, length, placeholder/aria-describedby hints) from and page HTML — call context() if not visible — and enter values that satisfy them. Search/filter/sort forms that only change the view do not need this.
+
+`;
+
// in rage mode we do not protect from irreversible actions
export const protectionRule = dedent`
@@ -270,6 +276,8 @@ export const actionRule = dedent`
If locator doesn't work, try CSS or XPath locators.
If nothing works, use I.clickXY(x, y) as last resort.
+ For checkboxes, prefer I.checkOption/I.uncheckOption over I.click.
+
### I.fillField
@@ -356,6 +364,19 @@ export const actionRule = dedent`
I.selectOption('form select[name=account]', 'Premium');
+ ### I.checkOption / I.uncheckOption
+
+ Set a checkbox/radio to a definite state — idempotent, never toggles. Use for checkboxes instead of I.click. Run via form(), not click().
+
+ I.checkOption(, )
+ I.uncheckOption(, )
+
+
+ I.checkOption('Subscribe');
+ I.checkOption({ role: 'checkbox', text: 'Agree' });
+ I.uncheckOption('Subscribe', '.preferences');
+
+
### I.attachFile
Attaches a file to a file input element.
diff --git a/src/ai/tester.ts b/src/ai/tester.ts
index bb634b7..4b63990 100644
--- a/src/ai/tester.ts
+++ b/src/ai/tester.ts
@@ -25,7 +25,7 @@ import { Navigator } from './navigator.ts';
import type { Pilot } from './pilot.ts';
import { Provider } from './provider.ts';
import { Researcher } from './researcher.ts';
-import { actionRule, focusedElementRule, locatorRule, multipleTabsRule, protectionRule, sectionContextRule } from './rules.ts';
+import { actionRule, focusedElementRule, formRequirementsRule, locatorRule, multipleTabsRule, protectionRule, sectionContextRule } from './rules.ts';
import { TaskAgent } from './task-agent.ts';
import { createCodeceptJSTools, createSpecialContextTools } from './tools.ts';
@@ -773,6 +773,8 @@ export class Tester extends TaskAgent implements Agent {
${sectionContextRule}
+ ${formRequirementsRule}
+
${this.provider.getSystemPromptForAgent('tester', this.explorer.getStateManager().getCurrentState()?.url) || ''}
`;
}
diff --git a/src/ai/tools.ts b/src/ai/tools.ts
index e31100a..961cd49 100644
--- a/src/ai/tools.ts
+++ b/src/ai/tools.ts
@@ -307,6 +307,7 @@ export function createCodeceptJSTools(explorer: Explorer, task: Task) {
Use cases:
- Typing into input fields (I.fillField, I.type)
+ - Setting checkboxes/radios to a definite state (I.checkOption, I.uncheckOption)
- Working with iframes (switch context with I.switchTo)
- Performing multiple form actions in a single batch
- Complex interactions requiring sequential commands
@@ -314,6 +315,7 @@ export function createCodeceptJSTools(explorer: Explorer, task: Task) {
Example - filling a form with context (PREFERRED):
I.fillField('Username', 'John', '.login-form')
I.selectOption('Country', 'USA', '.address-section')
+ I.checkOption('Agree', '.terms-section')
I.attachFile('input[type="file"]', 'path/to/file', '.upload-section')
Example - filling a form with ARIA locators: