Writing & Maintaining Tests - vanderbilt-redcap/redcap_cypress GitHub Wiki

Best Practices Guide

Goal: Make tests easy to write, easy to understand, and easy to maintain. Maximize reuse.

Topics:


1. Step Discoverability: Step Generator and VS Code Cucumber Hints

To keep language consistent, avoid reinventing steps, and improve developer experience, use a step discoverability option:

Option A: RCTF Step Generator

  • Use the RCTF Step Generator to review which steps already exist in the RCTF library and how they’re parameterized.
  • Benefits:
    • Prevents duplicate steps.
    • Ensures consistent wording across scenarios.
    • Makes reusability natural and obvious
  • Reference:

Option B: VS Code Snippets

  • When developing using VS Code and the REDCap Cypress Developer Toolkit, a number of code snippets will automatically be suggested when editing .feature files and typing common keywords like login, project, etc.:
    • The tab key can be used to quickly navigate to the portions of the snippet that will need to be edited.
    • All code snippets can be listed by via View -> Command Pallete -> Snippets: Insert Snippet
    • Code snippets can be added or edited by modifying this file and submitting a pull request
    • Code snippets are validated to make sure they stay in sync with recommended steps via get-step-usage.sh

Option C: VS Code + cucumberopen.cucumber-official Hints

  • Use the built-in .vscode configuration to enable Cucumber hints, step navigation, and auto-complete so authors can discover and use existing steps. This is enabled automatically when using the REDCap Cypress Developer Toolkit.

2. Usability Best Practices

  • Follow a Clean Given–When–Then Flow

    • Given: set up state & preconditions.
    • When: perform a single action or user event.
    • Then: assert one clear outcome (UI state, data state, etc.).
    • Keep steps atomic—avoid compound actions in one step.
  • Single-Outcome Scenarios

    • Where possible, scenarios should validate one behavior (e.g., “saving a completed instrument creates a record”).
    • This isn't always possible or practical, but it's a good guideline to aim for if in doubt

3. Reusability Best Practices

  • Reuse Existing RCTF Steps Where Possible

    • Before writing a new step definition or issuing a pull request on RCTF, search via the Step Generator or VS Code hints.
  • Use Background carefully

    • RCTF only resets database on individual .feature files
    • State is held between Scenarios on the same .feature file.
    • If you do choose to use Background steps, realize that it is repeated in front of EVERY Scenario
  • Organize by Functional Area for a set of Feature Tests

    • Create .feature files by domain (e.g., Survey Management, Data Entry, Longitudinal Events, User Rights, EM Hooks).
  • Centralize Complex Actions in Custom Commands

    • For multi-step workflows, prefer a single reusable command behind a small number of Gherkin steps.

4. Readability Best Practices

Add in 3-4 examples below:

  • Consistent Naming

    • Feature: Feature: Survey Response Validation
    • Scenario: Scenario: Completed survey creates a response record
  • One Action per Step

    When I click on the button labeled "Save"
    Then I should see "Record created"
    
  • Use Tables for Structured Input

    Then I should see a table header and rows containing the following values in a table:
      | First Name      | Last name |
      | Jane            | Doe       |
    
  • Comments to Clarify Intent

    • Most powerful use of comments is to clarify why - what steps do is mostly self-evident

    • Comment anything surprising, unexpected, or unclear

    • For Functional Requirements, comments can also be used to outline a functional requirement block, for example:

    #FUNCTIONAL_REQUIREMENT

    ##ACTION Restore deleted file
        When I click on the icon labeled "Restore deleted file" in the row labeled "testusers_bulkupload.csv"
        Then I should see a dialog containing the following text: "File: testusers_bulkupload.csv"
        When I click on the button labeled "Restore"
        Then I should see a dialog containing the following text: "SUCCESS!"
        And I click on the button labeled "Close"
   
    ##VERIFY file in File Repository
        When I click on the link labeled "File Repository"
        Then I should see a table header and rows containing the following values in the file repository table:
            | Name                     | Time Uploaded    | Comments                |
            | Data Export Files        |                  |                         |
            | PDF Snapshot Archive     |                  |                         |
            | Recycle Bin              |                  |                         |
            | testusers_bulkupload.csv | mm/dd/yyyy hh:mm | Uploaded by test_admin. |

5. Metadata and Data Considerations

  • PHI & Sensitive Data

    • Never hard-code real PHI. Use synthetic, anonymized datasets and safe fixtures.
  • Sample file from RSVC: https://github.com/aldefouw/redcap_rsvc/tree/main/Files

  • Store discrete copies of files for specific REDCap version

  • Project Types and Modes

    • Test classic vs. longitudinal differences explicitly.
  • Stability Over Brittle Assertions

    • Assert semantic outcomes rather than brittle selectors. In other words, look for text that is meaningful and distinct - focusing on the behaviors and what the user sees / experiences rather than how the page itself is built. Most steps are robust enough to handle proper selection.

6. Step Authoring Guidance

  • Write Steps at the Right Abstraction Level

    • Gherkin steps = behavioral language. This is why Gherkin is often used in Behavior Driven Development. Even if you are writing them for your own feature, avoid using specific selectors and instead focus on the behavior that drives a feature to work.
  • Design Steps to Be Composable

    • Steps should be building blocks usable in different workflows. Build steps that do a few things well rather than trying to do everything at once.
  • Keep Parameter Types Strict

    • Define clear parameter types in support to avoid ambiguous parsing. For example {yourCustomParameterTypeHere}
  • Document New Steps

    • Refer to the Step Generator for examples and use the JS Docs formatting to support automatic format:
/**
 * @module CSV
 * @author Tintin Nguyen <[email protected]>
 * @param {string} filename - the filename the downloaded CSV
 * @param {int} num_rows - the number of row sthe CSV file should have
 * @description Verifies number of rows the CSV file should have.
 */

7. Operational Tips

  • Flake Hunts: Stabilize commands and look for on screen elements instead of adding sleeps for timing issues. Only use sleeps for initial troubleshooting, if at all.
  • Selective Runs: Use tags to control CI pipelines.
  • Version Awareness: Annotate scenarios that require specific versions.

8. Best Practice Checklist

  • Use Step Generator or VS Code cucumber hints.
  • Add .vscode/settings.json with cucumber.features and cucumber.glue.
  • Enforce Given–When–Then structure.
  • Parameterize new steps and use Background only when appropriate.
  • Tag scenarios for scope control.
  • Centralize complex workflows in Cypress commands.
  • Use tables for structured data input.
  • Prefer semantic assertions over brittle UI selectors.