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: