From 2c626df672b65c2526c3f777258b254d7f86075a Mon Sep 17 00:00:00 2001 From: DavertMik Date: Wed, 23 Sep 2026 15:09:43 +0300 Subject: [PATCH] Update CodeceptJS to 4.2 and teach the tester clipboard checks CodeceptJS 4.2 adds seeInClipboard, seeClipboardEquals and clearClipboard (codeceptjs/CodeceptJS#5718). The action rules now offer them so a copy control can be verified by what it actually put into the clipboard. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + bun.lock | 4 ++-- package.json | 2 +- src/ai/rules.ts | 13 +++++++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38e69d5e..7dfbf0af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2026-09-23 ### Changes +- [Tester] Can now check what a copy button put into the clipboard: whether it contains a text or equals it exactly. The tester clears the clipboard before copying, so an old value cannot pass the check. Needs CodeceptJS 4.2. - [Tester] A test now starts from a page loaded after planning, so data prepared for it through the API is on screen from the first step. Previously the tester read the page as it looked before the data was prepared, concluded the item was missing, and went off to create its own through the UI. - [Pilot] When Pilot prepares data for a test, it now tells the tester what was created — type, name and id — and to use it rather than create the same thing through the UI. This arrives even when Pilot spends its whole turn on tool calls and writes no plan. - [Pilot] Data prepared while a test is already running now comes with a request to reload the page, since the open page cannot show it yet. diff --git a/bun.lock b/bun.lock index 23e3692c..0902b47b 100644 --- a/bun.lock +++ b/bun.lock @@ -31,7 +31,7 @@ "bash-tool": "^1.3.15", "chalk": "^5.6.2", "cli-highlight": "^2.1.11", - "codeceptjs": "^4.2.0-beta.3", + "codeceptjs": "^4.2.0", "commander": "^14.0.1", "debug": "^4.4.3", "dedent": "^1.6.0", @@ -1103,7 +1103,7 @@ "code-excerpt": ["code-excerpt@4.0.0", "", { "dependencies": { "convert-to-spaces": "^2.0.1" } }, "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA=="], - "codeceptjs": ["codeceptjs@4.2.0-beta.3", "", { "dependencies": { "@codeceptjs/configure": "^4.0.0-beta.4", "@codeceptjs/helper": "2.0.4", "@cucumber/cucumber-expressions": "18", "@cucumber/gherkin": "38.0.0", "@cucumber/messages": "32.3.1", "@modelcontextprotocol/sdk": "^1.26.0", "@xmldom/xmldom": "0.9.10", "acorn": "8.15.0", "ai": "^6.0.43", "arrify": "3.0.0", "axios": "1.16.1", "chalk": "4.1.2", "cheerio": "^1.0.0", "chokidar": "^5.0.0", "commander": "15.0.0", "cross-spawn": "7.0.6", "css-to-xpath": "0.1.0", "csstoxpath": "1.6.0", "envinfo": "7.21.0", "escape-string-regexp": "4.0.0", "figures": "3.2.0", "fn-args": "4.0.0", "fs-extra": "11.3.3", "fuse.js": "^7.0.0", "glob": ">=9.0.0 <14", "html-minifier-terser": "7.2.0", "inquirer": "^8.2.7", "invisi-data": "^1.0.0", "js-beautify": "1.15.4", "lodash.clonedeep": "4.5.0", "lodash.merge": "4.6.2", "lodash.shuffle": "4.2.0", "mkdirp": "3.0.1", "mocha": "11.7.5", "monocart-coverage-reports": "2.12.12", "ms": "2.1.3", "multer": "^2.0.2", "ora-classic": "5.4.2", "parse-function": "5.6.10", "parse5": "7.3.0", "promise-retry": "1.1.1", "sprintf-js": "1.1.3", "uuid": "11.1.0", "ws": "^8.21.2", "xpath": "0.0.34", "zod": "^4.1.11" }, "peerDependencies": { "tsx": "^4.0.0" }, "optionalPeers": ["tsx"], "bin": { "codeceptq": "bin/codeceptq.js", "codeceptjs": "bin/codecept.js", "codeceptjs-mcp": "bin/mcp-server.js" } }, "sha512-U9KU1VDWidaNNQ38WBYLnKnRlNkbfhu4XYD9BernsIyyb5u0SkzeZmDknpegUHS5KDWMMFP4EoD16xHOkmQU2g=="], + "codeceptjs": ["codeceptjs@4.2.0", "", { "dependencies": { "@codeceptjs/configure": "^4.0.0-beta.4", "@codeceptjs/helper": "2.0.4", "@cucumber/cucumber-expressions": "18", "@cucumber/gherkin": "38.0.0", "@cucumber/messages": "32.3.1", "@modelcontextprotocol/sdk": "^1.26.0", "@xmldom/xmldom": "0.9.10", "acorn": "8.15.0", "ai": "^6.0.43", "arrify": "3.0.0", "axios": "1.16.1", "chalk": "4.1.2", "cheerio": "^1.0.0", "chokidar": "^5.0.0", "commander": "15.0.0", "cross-spawn": "7.0.6", "css-to-xpath": "0.1.0", "csstoxpath": "1.6.0", "envinfo": "7.21.0", "escape-string-regexp": "4.0.0", "figures": "3.2.0", "fn-args": "4.0.0", "fs-extra": "11.3.3", "fuse.js": "^7.0.0", "glob": ">=9.0.0 <14", "html-minifier-terser": "7.2.0", "inquirer": "^8.2.7", "invisi-data": "^1.0.0", "js-beautify": "1.15.4", "lodash.clonedeep": "4.5.0", "lodash.merge": "4.6.2", "lodash.shuffle": "4.2.0", "mkdirp": "3.0.1", "mocha": "11.7.5", "monocart-coverage-reports": "2.12.12", "ms": "2.1.3", "multer": "^2.0.2", "ora-classic": "5.4.2", "parse-function": "5.6.10", "parse5": "7.3.0", "promise-retry": "1.1.1", "sprintf-js": "1.1.3", "uuid": "11.1.0", "ws": "^8.21.2", "xpath": "0.0.34", "zod": "^4.1.11" }, "peerDependencies": { "tsx": "^4.0.0" }, "optionalPeers": ["tsx"], "bin": { "codeceptq": "bin/codeceptq.js", "codeceptjs": "bin/codecept.js", "codeceptjs-mcp": "bin/mcp-server.js" } }, "sha512-eHhm0G9/0kRbEpEu/hA4vWtgVAV/hH/JKzxlN5zE1wM1KGnoPMJ+kBqboeNucDff9OK+sSW11BemijzGJmhpuA=="], "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], diff --git a/package.json b/package.json index b75e5d9d..b27923af 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "bash-tool": "^1.3.15", "chalk": "^5.6.2", "cli-highlight": "^2.1.11", - "codeceptjs": "^4.2.0-beta.3", + "codeceptjs": "^4.2.0", "commander": "^14.0.1", "debug": "^4.4.3", "dedent": "^1.6.0", diff --git a/src/ai/rules.ts b/src/ai/rules.ts index 3fa0e959..4e06403c 100644 --- a/src/ai/rules.ts +++ b/src/ai/rules.ts @@ -497,6 +497,19 @@ export const actionRule = dedent` After hovering, use see() or context() to check what appeared. + ### I.seeInClipboard / I.seeClipboardEquals / I.clearClipboard + + Check what a copy control put into the system clipboard. Run via form(), not click(). + I.seeInClipboard asserts the clipboard contains the text, I.seeClipboardEquals asserts an exact match, + I.clearClipboard empties it — call it before copying so a stale value can't pass the check. + + + I.clearClipboard(); + I.click({ role: 'button', text: 'Copy link' }); + I.seeInClipboard('/invite/'); + I.seeClipboardEquals('ABC-123'); + + [DO NEVER USE OTHER CODECEPTJS COMMANDS THAN PROPOSED HERE] [INTERACT ONLY WITH ELEMENTS THAT ARE ON THE PAGE HTML] [DO NOT USE WAIT FUNCTIONS]