跳到正文
cccskills
免费在 GitHub 公开

verify-pagination

Prove the next page of a list, or the next batch of an infinite scroll, loads NEW rows from the server, repeats none, and that the end of the list is handled. Use when pagination or infinite scroll was added or changed, when a list shows the same rows twice or skips some, or when the last page still offers a next control.

中文简介正在准备中。当前显示原文说明。

查看安装方法

包含的文件(1)

  • SKILL.md5.7 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

The second page is where lists break

A list that renders its first page proves the first request works. The second page is where the offset is off by one, the cursor is reused, the same rows come back, or the append replaces what was there. The last page is where the "Next" button still fires a request for rows that do not exist.

Reticle can check all of that in the running app, against the requests the page really made. Not installed? RETICLE_INSTALL_SOURCE=npx_skill npx @reticlehq/server@latest init, then the install-and-verify skill.

Confirm the session can observe

reticle_session({ action: "list" })

A hidden or throttled tab can accept a click and render nothing, and an infinite scroll that loads on an intersection observer may never fire at all. If the session is not healthy, get a context that is, for example a leased tab (reticle_run({ tool: "reticle_lease", args: { action: "acquire", url } })). Otherwise report the run as blocked, not passed.

1. Record the first page

Write down what is on screen before you touch anything, or you have nothing to compare the next page against:

reticle_look({ action: "find", sessionId, by: "role", value: "row" })

Use whatever the rows really are (row, listitem, article, or a testid). Keep the visible text of every row, not a sample: a repeat from the middle of page 1 is as much a bug as one from the top. If the result says it was truncated, scope the find to the list (scope: "<the list's ref>") until it is not, or say which rows you could not see.

2. Load the next page, and name the consequence first

Name what must happen before the click, not after. For numbered or next/previous pagination, the page is replaced, so the first page's rows must be gone once the new request has answered:

reticle_act_and_wait({ sessionId, ref: "<next control>", action: "click", until: { kind: "allOf", predicates: [
  { kind: "net", urlContains: "/api/items", ok: true },
  { kind: "text", contains: "<first row of page 1>", absent: true },
  { kind: "text", contains: "<last row of page 1>", absent: true },
]}})

For "Load more" or infinite scroll, the page is appended, so the first page must still be there and the request must have answered. Use the action that really triggers the load: click for a "Load more" button, scrollIntoView on the list's end for a list that loads when scrolled.

reticle_act_and_wait({ sessionId, ref: "<load more button>", action: "click", until: { kind: "allOf", predicates: [
  { kind: "net", urlContains: "/api/items", ok: true },
  { kind: "text", contains: "<first row of page 1>" },
]}})

If the list pages on the client (all rows arrive in one response and the page only slices them), no request fires, and a net clause would wait for one that never comes. Drop it, keep the text clauses, and say in your report that the server's paging was not exercised.

urlContains must name the list's own endpoint. A predicate that any request satisfies proves nothing about this list.

3. Prove the rows are new, and none repeat

Read the rows again:

reticle_look({ action: "find", sessionId, by: "role", value: "row" })

Compare the text with what you recorded in step 1:

  • Paged: no row of page 2 may be any row of page 1. An overlap anywhere in the list means the offset or cursor did not move.
  • Appended: every page-1 row appears once, and the new ones follow them. A page-1 row that now appears twice means the batch was appended twice or re-fetched.

That comparison is evidence you read, so turn the result into a verdict. Take one row that is only on the new page and assert it:

reticle_assert({ sessionId, predicate: { kind: "text", contains: "<a row only on the new page>" } })

If the lists overlap, you have found the bug. Report which rows repeated, and do not report a pass.

4. Prove the end of the list is handled

Go to the last page (or scroll until the list stops growing) and prove the control is off:

reticle_assert({ sessionId, predicate: { kind: "anyOf", predicates: [
  { kind: "element", query: { role: "button", name: "Next" }, state: "disabled" },
  { kind: "element", query: { role: "button", name: "Next" }, absent: true },
]}})

For an infinite scroll, scroll to the end once more, then let the page go quiet before you claim it asked for nothing. An observer that fires after a delay would otherwise land after a zero reading had already passed:

reticle_act({ sessionId, ref: "<the list end>", action: "scrollIntoView" })
reticle_assert({ sessionId, timeout_ms: 5000, predicate: { kind: "allOf", predicates: [
  { kind: "settled", quietMs: 1500 },
  { kind: "net", urlContains: "/api/items", count: 0 },
]}})

A list that keeps requesting pages past the end is a real finding even when nothing new renders.

Honesty

Only verified: "yes" is a pass. For a client-side list, a yes covers the rows you asserted and nothing about the server: say so. Say which endpoint you asserted on, and report any step you could not reach as unknown, not passed.


Capability reference: curl https://docs.reticle.sh/capabilities.md. Everything else: curl https://docs.reticle.sh/llms.txt.

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Test-driven development for behaviour a unit test cannot reach, by writing the expectation against the running app before writing the code. Declare the consequence first, watch it fail, implement, watch it pass. Use when building a user-facing feature, when the user asks for TDD on UI or full-stack work, when a unit test cannot express the outcome that matters, or when you want a red-green loop that runs against the real app instead of mocks.

中文简介正在准备中。当前显示原文说明。

reticlehq/reticle12792026年10月21日 更新

Sweep a whole running web app for what is broken, without writing a script or knowing the codebase. Clicks every reachable control and reports dead buttons, console errors, failed requests, and places where the API and the screen disagree. Use on an unfamiliar codebase, before a release, after a big merge or dependency bump, when the user asks for a smoke test or a health check, or when someone says "just check everything still works".

中文简介正在准备中。当前显示原文说明。

reticlehq/reticle12792026年10月21日 更新

Find out why something in a running web app does not work, when the console is empty and the code looks correct. Reads the click, the request, the store and the console together and returns the file:line to open. Use when a button does nothing, a form will not submit, data will not load, a page renders blank or stale, a modal will not close, or the user says "it's broken" and the code review says it is fine.

中文简介正在准备中。当前显示原文说明。

reticlehq/reticle12792026年10月21日 更新

Check that the UI you actually rendered uses the design system, by reading computed styles in the running app against the project's design tokens. Catches hardcoded hex colors, off-palette backgrounds, invisible or unusable controls, and animations that never ran. Use after building or restyling a component, when a design review is wanted, when a UI looks slightly off but nobody can say why, or when a design system exists and nothing checks whether the code follows it.

中文简介正在准备中。当前显示原文说明。

reticlehq/reticle12792026年10月21日 更新

Drive and verify an Electron or Tauri desktop app from the inside, including the main-process and Rust IPC calls a browser tool cannot see. Use when a desktop app needs testing, when a feature works in the browser but not in the packaged app, when an IPC or invoke call needs proving, when a desktop screenshot or visual diff is wanted, or when you need a headless run of a desktop UI in CI.

中文简介正在准备中。当前显示原文说明。

reticlehq/reticle12792026年10月21日 更新

Find out why the tests pass but the app is broken. Catches false greens: a green suite over a feature that does not work, a mocked API standing in for a real one, an assertion that holds no matter what the app does, a click handler wired to nothing. Use when the suite is green and the user says it is broken, when a test never fails, when coverage looks fine but bugs still ship, or before trusting a passing run you did not watch.

中文简介正在准备中。当前显示原文说明。

reticlehq/reticle12792026年10月21日 更新

查看 reticlehq 的全部技能

报告此技能的问题