

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
123456# E2E Authoring Rules78Use this rule when writing or modifying E2E tests, Cypress/Cucumber feature files, step definitions, page objects, or E2E assertions. For OCR-specific canvas assertions, use `e2e-ocr.mdc`.910## Environment Assumption1112Assume the developer has already started services with `pnpm sut`, including backend auto-reload, frontend HMR, and Mountebank. Services automatically restart when code changes are made.1314If services are not running, suggest starting `pnpm sut` in a separate terminal.1516## Cypress Origin1718`http://localhost:5173` is always the Cypress app origin through the local load balancer. CI vs `pnpm sut`, `wait-on`, `NO_PROXY`, and env vars are documented in `docs/gcp/prod_env.md`, Local dev / Cypress under section 6.1920## Run E2E Tests2122Agents should default to `pnpm cypress run --spec` with one or more `.feature` paths tied to the changed capability. Add adjacent specs only when regression risk warrants it. Do not run bare `pnpm cypress run`, `pnpm verify`, or the whole suite unless the user explicitly asks for a full E2E run or the instructions require reproducing CI.2324```bash25CURSOR_DEV=true nix develop -c pnpm cypress run --spec e2e_test/features/ai_generated_recall_questions/question_contest.feature26```2728Important notes:2930- Do not use `cypress run -- --spec`; the empty `--` causes the `--spec` parameter to be ignored.31- The default tag filter is `tags` in `e2e_test/config/ci.ts`, for example `not @ignore`. Override per run with `--env tags='...'` when needed.32- `@skipOptimizationDueToKnownNecessarySlowness` on a Scenario or Feature marks known-necessary slowness. Test-optimization profiles exclude it with `--env tags='not @ignore and not @skipOptimizationDueToKnownNecessarySlowness'`. Normal CI/dev runs still execute these scenarios. Do not add this tag without developer review.33- `@focus` and `@only` are local debugging aids only. Do not commit them; CI runs `./scripts/check_focus_tags.sh` on `.feature` files to block `@focus`, and `@only` should be treated the same.34- If any node in a feature file is tagged `@focus` or `@only`, `@badeball/cypress-cucumber-preprocessor` filters scenarios in that file to `@focus or @only` only.3536## Debugging3738Use the canonical log-tail command for backend E2E log inspection:3940```bash41CURSOR_DEV=true nix develop -c pnpm logs:tail backend-e2e42```4344Frontend Vite checker terminal errors still matter even though the browser overlay is disabled for E2E stability. For canonical lint and format commands, use `linting_formating.mdc`.4546## Technology And Structure4748- Cypress for E2E testing.49- Cucumber plugin for BDD-style tests.50- TypeScript for type safety.51- Mountebank mocks external services.52- `e2e_test/features` contains BDD-style tests.53- `e2e_test/step_definitions` contains step definitions.54- `e2e_test/start/` contains page objects.55- `e2e_test/start/pageObjects/cli/` contains CLI page objects with the `cli.xxx` prefix.56- `e2e_test/support/` contains support files.5758## Gherkin5960- Write features in Gherkin syntax focused on business value.61- Group related features in domain-specific folders.62- Name feature files and titles by domain/capability, such as `note_creation.feature` or `spaced_repetition.feature`. Never name them by phase or delivery order.63- Use tags, such as `@usingMockedOpenAiService` or `@mockBrowserTime`, to control test execution.64- Keep scenarios focused and concise.6566## Step Definitions6768- Keep step definitions lightweight.69- Delegate implementation details to page objects, preferably as fluent chains.70- When user-visible behavior differs, use different steps and thin implementations. Do not hide variants behind one parameterized step.71- Use TypeScript and reuse steps where practical.72- Use parameter types for complex objects.7374```typescript75When("I start a conversation about the note {string}", (noteTopology: string) => {76 start.jumpToNotePage(noteTopology).startAConversationAboutNote()77})78```7980## Page Objects8182Use page objects with a fluent interface: methods perform an action and return the next page object, or `this` when staying on the same screen. This keeps step definitions short and navigation explicit in the types.8384- Centralize UI interactions in page objects.85- Prefer fluent chaining over one-off helpers that do not return a navigable object.86- Keep page objects focused on a single responsibility.87- Use meaningful method names that reflect user actions.8889```typescript90const notePage = {91 startAConversationAboutNote() {92 this.toolbarButton("Start a conversation").click()93 return conversationPage()94 },95}96```9798CLI steps use `cli.xxx` page objects, not `start.xxx`. For the install feature, use `cli.backend()`, `cli.installation()`, and `cli.nonInteractiveOutput()` for spawned `version` / `update` stdout. Other `features/cli/*.feature` files are `@ignore` in CI; extend Vitest under `cli/tests/interactive/` for interactive TTY coverage instead of adding a second Cypress PTY harness.99100```typescript101Then("I should see {string} in the non-interactive output", (expected: string) => {102 cli.nonInteractiveOutput().expectContains(expected)103})104```105106## Waiting until the app is not busy107108Product loading UI that means unfinished work marks itself with `data-app-busy` (`LoadingThinBar` from `apiCallWithLoading`, `ContentLoader` for pending page data, `LoadingModal` for `blockUi`). See `.cursor/rules/frontend-api.mdc`.109110E2E waits with `waitUntilAppIsNotBusy()` from `e2e_test/start/pageBase.ts` (also `start.waitUntilAppIsNotBusy()`):111112```typescript113import { waitUntilAppIsNotBusy } from '../pageBase'114115cy.findByRole('button', { name: 'Submit' }).click()116waitUntilAppIsNotBusy()117```118119Rules of thumb:120121- Call `waitUntilAppIsNotBusy()` in the page object **on the action that starts loading**, before the next step that needs that work’s result.122- Prefer asserting a **user-visible** success outcome when the product provides one; use the waiter for “busy cleared,” not as a substitute for success.123- Do not use hardcoded waits (`cy.wait(ms)`) for this.124- Do not skip the wait and rely on a later navigation’s loading check alone — that races when the next step does not go through busy UI.125- Network `cy.intercept` / `cy.wait('@…')` is optional; it is not the documented default stand-in for this product/E2E pair.126127## Test Data And Service Mocking128129- Use Given steps to set up test data.130- Mock external services, such as OpenAI, for reliable tests.131- Use tags to indicate when mocks are required.132- Keep mock responses consistent with real service behavior.133- Store mock data separately from test code.134- Clean up test data after each test.135- Use data tables for complex test data.136137```gherkin138Given I have a notebook "Geometry set" with notes:139 | Title |140 | Shape |141 | Square |142```143144Square is placed under Shape when the notebook is created in one inject batch. Do not add a `Folder` column; see testability inject ordering.145146```typescript147Given("OpenAI assistant will reply below for user messages in a stream run:", (data: DataTable) => {148 mock_services149 .openAi()150 .stubCreateThread("thread-123")151 .createThreadAndStubMessages("thread-123", data.hashes())152})153```154155## Assertions156157Error messages must be immediately actionable:1581591. Assert with clear domain meaning, not just technical selectors.1602. Show expected and actual values when they differ.1613. Include relevant context, such as page content or API response, when helpful.1624. Given, When, and Then steps should be assertive and fail early.1635. Put assertions inside page objects where that keeps step definitions simple.164165```typescript166expectQuizScore(expectedScore?: string) {167 if (expectedScore) {168 cy.get("[data-test='quiz-score']").should(($score) => {169 const actualScore = $score.text().trim()170 expect(171 actualScore,172 `Expected quiz score to be ${expectedScore}, but found ${actualScore}`173 ).to.equal(expectedScore)174 })175 }176 return this177}178```179180## Explicit Conditions181182A scenario describes one fixed path. Prefer dumb automation: the path is visible in Gherkin and in small, purpose-named page-object methods, not inferred at runtime from a string or flag.183184- Avoid large `if` / `switch` trees, parameter sniffing, and mode flags in steps and page objects except when the branch exists only to assert or fail fast with a clear error.185- Distinguish variants at the caller with different steps and/or page-object methods, not one smart API.186- State the condition in step wording when behavior differs, for example slash command vs plain line vs Enter alone vs ESC.187- For CLI TTY sequences, add or extend Vitest under `cli/tests/interactive/` instead of adding a second Cypress PTY stack.188189## Before hook order190191`@badeball/cypress-cucumber-preprocessor` defaults Before hooks to order `10000`. The shared DB reset Before uses **`order: 0`** so it runs before tagged setup. Hooks that start long-lived side effects (e.g. `@interactiveCLI` PTY at order `2`) must stay **after** that reset; otherwise truncate can block on MySQL locks held by the PTY’s HTTP traffic.192193## Pitfalls194195- Do not put complex logic in step definitions.196- Do not create long scenarios with many steps.197- Do not rely on test order.198- Do not use hardcoded waits.199- Do not fire a user action that starts app-busy loading and then assert domain state without `waitUntilAppIsNotBusy()` (or a clearer user-visible success signal) first.200- Do not skip error handling.201- Do not mix different levels of abstraction in scenarios.202- Do not ignore linting errors that appear in the terminal.203- Do not add OCR or DOM text layers to production just to satisfy E2E; run OCR in Cypress Node tasks instead.204
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| nerds-odd-e/doughnut.cursor/rules/general.mdc · 49 | Cursor rules | styledo-not | 49/100 | 14 days ago | |
| nerds-odd-e/doughnut.clinerules/daisyui.md · 49 | Cline rules | setuplint-formatstyleui+1 | 57/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/architecture-decisions.mdc · 49 | Cursor rules | no sections | 16/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/backend-code.mdc · 49 | Cursor rules | styletypesdatabasedo-not | 61/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/backend-testing.mdc · 49 | Cursor rules | buildteststyletesting-strategy+2 | 73/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/cli.mdc · 49 | Cursor rules | setupbuildteststyle+4 | 96/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/db-migration.mdc · 49 | Cursor rules | stylearchdatabasedeployment | 64/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/e2e-ocr.mdc · 49 | Cursor rules | setuptesting-strategydo-not | 46/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/frontend-api.mdc · 49 | Cursor rules | styletesting-strategyapido-not | 57/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/frontend-component.mdc · 49 | Cursor rules | testlint-formatstylearch+2 | 76/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/frontend-storybook.mdc · 49 | Cursor rules | buildteststyletesting-strategy+1 | 69/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/frontend-testing.mdc · 49 | Cursor rules | buildteststyletesting-strategy+2 | 89/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/gsd-coexistence.mdc · 49 | Cursor rules | style | 60/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/linting_formating.mdc · 49 | Cursor rules | testlint-formatstylearch+6 | 88/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/mcp-server.mdc · 49 | Cursor rules | buildtestlint-formatarch+2 | 85/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/planning.mdc · 49 | Cursor rules | teststylearchdo-not+1 | 75/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/script.mdc · 49 | Cursor rules | testarch | 58/100 | 14 days ago | |
| nerds-odd-e/doughnutAGENTS.md · 49 | AGENTS.md | no sections | 47/100 | 14 days ago | |
| nerds-odd-e/doughnutCLAUDE.md · 49 | CLAUDE.md | agent-behaviour | 47/100 | 14 days ago |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 46 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 14 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 14 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 46 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/nerds-odd-e-doughnut-cursor-rules-e2e-authoring)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.