Bird
Raised Fist0
Cypresstesting~15 mins

Custom plugin development in Cypress - Deep Dive

Choose your learning style10 modes available
Overview - Custom plugin development
What is it?
Custom plugin development in Cypress means creating your own reusable code pieces that extend Cypress's abilities. Plugins let you add new commands, modify how tests run, or connect with other tools. This helps you tailor Cypress to fit your project's unique needs. It’s like building your own tools inside Cypress to make testing easier and more powerful.
Why it matters
Without custom plugins, you would have to repeat the same code in many tests or miss out on automating complex tasks. Custom plugins save time, reduce errors, and let your tests do more by adding features Cypress doesn’t have by default. This makes your testing faster, more reliable, and easier to maintain.
Where it fits
Before learning custom plugins, you should understand basic Cypress test writing and commands. After mastering plugins, you can explore advanced test architecture, continuous integration, and complex test automation strategies.
Mental Model
Core Idea
Custom plugins are like adding your own special tools inside Cypress to make testing tasks easier and more tailored to your needs.
Think of it like...
Imagine Cypress as a toolbox with standard tools. Custom plugins are like crafting your own custom screwdriver or wrench that fits a unique screw or bolt you often encounter, making your work smoother and faster.
┌───────────────────────────────┐
│          Cypress Core          │
├─────────────┬─────────────────┤
│ Built-in    │ Custom Plugins  │
│ Commands    │ (Your Extensions)│
├─────────────┴─────────────────┤
│         Test Scripts          │
└───────────────────────────────┘
Build-Up - 6 Steps
1
FoundationUnderstanding Cypress Plugins Basics
🤔
Concept: Learn what Cypress plugins are and where they live in the project.
Cypress plugins are JavaScript files that run in the Node environment, separate from your test code. They live in the 'cypress/plugins' folder. Plugins can modify how Cypress works by listening to events or adding new commands.
Result
You know where to find and place plugin files and understand their role in Cypress.
Knowing the separation between test code and plugins helps you organize your project and avoid confusion about where code runs.
2
FoundationSetting Up a Simple Plugin
🤔
Concept: Create a basic plugin that logs a message when tests start.
In 'cypress/plugins/index.js', add a function that listens to the 'before:run' event and logs 'Tests are starting'. This shows how plugins hook into Cypress lifecycle events.
Result
When you run tests, the console shows 'Tests are starting' before tests begin.
Understanding event hooks lets you customize Cypress behavior at key moments during test runs.
3
IntermediateAdding Custom Tasks for Node Operations
🤔Before reading on: do you think plugins can run code outside the browser context? Commit to your answer.
Concept: Use plugins to run Node.js code like reading files or accessing databases during tests.
Define a 'task' in the plugin file that reads a file from disk. In your test, call cy.task('readFile', 'path/to/file'). This bridges browser tests with Node capabilities.
Result
Your test can access file contents or perform backend operations not possible in the browser.
Knowing plugins can run Node code expands what your tests can do beyond browser limitations.
4
IntermediateCreating Custom Cypress Commands
🤔Before reading on: do you think custom commands belong in plugins or support files? Commit to your answer.
Concept: Add new commands to Cypress to reuse complex actions easily.
In 'cypress/support/commands.js', define a custom command like cy.login() that fills login form fields and submits. This is different from plugins but often used together.
Result
Tests become cleaner and easier to read by using your own commands.
Separating custom commands and plugins clarifies their roles: commands extend test syntax, plugins extend Cypress internals.
5
AdvancedModifying Browser Launch Behavior
🤔Before reading on: can plugins change browser settings before tests run? Commit to your answer.
Concept: Use plugins to customize browser launch options, like setting viewport size or disabling security features.
In the plugin file, listen to 'before:browser:launch' event and modify launch arguments. For example, add '--disable-web-security' to Chrome launch args.
Result
Tests run with customized browser settings, enabling scenarios like cross-origin testing.
Controlling browser launch lets you test edge cases and environments not possible with default settings.
6
ExpertHandling Complex Plugin Communication
🤔Before reading on: do you think plugins can communicate asynchronously with tests? Commit to your answer.
Concept: Manage asynchronous communication between plugins and tests using tasks and events.
Implement a plugin task that performs a long-running operation and returns a promise. Your test waits for the result via cy.task(). This pattern handles complex workflows like database seeding or API mocking.
Result
Tests can coordinate with external systems reliably and asynchronously.
Mastering async plugin communication unlocks powerful integrations and robust test setups.
Under the Hood
Cypress plugins run in a separate Node.js process from the browser tests. They listen to events emitted by Cypress and can define tasks that tests call asynchronously. This separation allows plugins to perform operations outside the browser, like file system access or modifying browser launch options. Communication between tests and plugins happens via a messaging system where tests send requests (tasks) and plugins respond.
Why designed this way?
Cypress separates plugins to keep browser tests fast and isolated from system-level operations. Running plugins in Node allows access to OS features without compromising browser security. This design balances power and safety, unlike older tools that mixed test and system code.
┌───────────────┐       ┌───────────────┐
│   Test Code   │ <---> │  Cypress Core │
└──────┬────────┘       └──────┬────────┘
       │                       │
       │ cy.task() calls       │
       ▼                       ▼
┌───────────────┐       ┌───────────────┐
│  Browser Run  │       │ Plugin Process│
│ (Runs Tests)  │       │ (Node.js Env) │
└───────────────┘       └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do you think custom commands and plugins are the same thing? Commit to yes or no.
Common Belief:Custom commands and plugins are the same because both add new features to Cypress.
Tap to reveal reality
Reality:Custom commands extend the test syntax and run in the browser context, while plugins run in Node and handle system-level tasks.
Why it matters:Confusing them leads to placing code in the wrong files, causing errors or unexpected behavior.
Quick: Can plugins directly manipulate the browser DOM? Commit to yes or no.
Common Belief:Plugins can directly change the browser page content because they are part of Cypress.
Tap to reveal reality
Reality:Plugins run outside the browser and cannot access the DOM; only test code can do that.
Why it matters:Expecting plugins to manipulate the page causes confusion and wasted debugging time.
Quick: Do you think plugin tasks run synchronously? Commit to yes or no.
Common Belief:Plugin tasks run instantly and block tests until done.
Tap to reveal reality
Reality:Plugin tasks run asynchronously and return promises; tests wait for their completion.
Why it matters:Misunderstanding async behavior can cause flaky tests or race conditions.
Quick: Can you use plugins to add new Cypress commands? Commit to yes or no.
Common Belief:Plugins are the place to add new Cypress commands.
Tap to reveal reality
Reality:New commands belong in support files, not plugins.
Why it matters:Putting commands in plugins breaks Cypress’s architecture and causes errors.
Expert Zone
1
Plugins can modify browser launch arguments dynamically based on environment variables, enabling flexible test setups.
2
Tasks can be chained and composed to build complex workflows, but managing their asynchronous nature requires careful promise handling.
3
Plugins can cache expensive operations between test runs to improve performance, but this requires understanding Cypress’s lifecycle events.
When NOT to use
Avoid custom plugins when simple custom commands or fixtures suffice. For UI interactions, use commands. For small reusable code, prefer support files. Use plugins only when you need Node-level access or to modify Cypress internals.
Production Patterns
In real projects, plugins often handle database seeding, API mocking, or environment setup before tests. Teams create shared plugin libraries for common tasks to keep tests DRY. Plugins also customize browser behavior for cross-browser testing and CI environments.
Connections
Middleware in Web Servers
Similar pattern of intercepting and modifying requests or behavior before main processing.
Understanding middleware helps grasp how Cypress plugins intercept events and extend functionality in a modular way.
Browser Extensions
Both inject custom code to extend browser capabilities but operate in different contexts.
Knowing how browser extensions work clarifies why Cypress plugins run outside the browser and communicate asynchronously.
Operating System Device Drivers
Both act as intermediaries between core systems and hardware or external resources.
Seeing plugins as drivers helps understand their role in bridging Cypress tests with system-level operations safely.
Common Pitfalls
#1Trying to add a custom command inside the plugin file.
Wrong approach:module.exports = (on, config) => { Cypress.Commands.add('login', () => { // login steps }) }
Correct approach:In cypress/support/commands.js: Cypress.Commands.add('login', () => { // login steps })
Root cause:Confusing the plugin environment (Node) with the test/support environment (browser).
#2Calling cy.task() with a task name not defined in plugins.
Wrong approach:cy.task('undefinedTask')
Correct approach:In cypress/plugins/index.js: module.exports = (on) => { on('task', { definedTask() { return null } }) } In test: cy.task('definedTask')
Root cause:Not registering tasks properly in the plugin file before calling them in tests.
#3Modifying browser launch options without returning the modified options.
Wrong approach:on('before:browser:launch', (browser = {}, launchOptions) => { launchOptions.args.push('--disable-web-security') })
Correct approach:on('before:browser:launch', (browser = {}, launchOptions) => { launchOptions.args.push('--disable-web-security') return launchOptions })
Root cause:Forgetting that the event handler must return the updated launch options object.
Key Takeaways
Custom plugins let you extend Cypress beyond its built-in features by running Node.js code alongside your tests.
Plugins and custom commands serve different purposes and live in separate parts of the Cypress project.
Plugins communicate asynchronously with tests using tasks and events, enabling powerful integrations.
Properly structuring plugins and commands prevents common errors and keeps your test suite maintainable.
Mastering plugins unlocks advanced testing scenarios like environment setup, browser customization, and external system integration.

Practice

(1/5)
1. What is the main purpose of creating a custom plugin in Cypress?
easy
A. To add new commands or tasks that extend Cypress functionality
B. To change the browser's default behavior during tests
C. To write test cases in a different programming language
D. To speed up the execution of all tests automatically

Solution

  1. Step 1: Understand what plugins do in Cypress

    Plugins allow adding new commands or tasks that Cypress does not provide by default.
  2. Step 2: Differentiate from other options

    Changing browser behavior or writing tests in other languages is not the role of plugins. Speeding up tests automatically is not guaranteed by plugins.
  3. Final Answer:

    To add new commands or tasks that extend Cypress functionality -> Option A
  4. Quick Check:

    Plugins extend Cypress features = D [OK]
Hint: Plugins add new commands or tasks to Cypress [OK]
Common Mistakes:
  • Thinking plugins change browser behavior directly
  • Confusing plugins with test case languages
  • Assuming plugins automatically speed up tests
2. Which file is typically used to define custom plugins in a Cypress project?
easy
A. cypress/plugins/index.js
B. cypress/support/commands.js
C. cypress/integration/spec.js
D. cypress.json

Solution

  1. Step 1: Identify the plugin file location

    Custom plugins are defined in the cypress/plugins/index.js file where Node.js code runs.
  2. Step 2: Differentiate from support and config files

    support/commands.js is for custom commands in browser tests, integration/spec.js is for test specs, and cypress.json is config.
  3. Final Answer:

    cypress/plugins/index.js -> Option A
  4. Quick Check:

    Plugins file = C [OK]
Hint: Plugins go in cypress/plugins/index.js file [OK]
Common Mistakes:
  • Confusing plugins file with support commands file
  • Choosing test spec files for plugins
  • Selecting config file for plugin code
3. Given this plugin code snippet in cypress/plugins/index.js:
module.exports = (on, config) => {
  on('task', {
    logMessage(message) {
      console.log(message)
      return null
    }
  })
}
What happens when the test calls cy.task('logMessage', 'Hello')?
medium
A. The test fails because 'logMessage' is not a valid Cypress command
B. The message 'Hello' is printed in the browser console, and the task returns undefined
C. The message 'Hello' is printed in the Node.js console, and the task returns null
D. Nothing happens because tasks cannot receive arguments

Solution

  1. Step 1: Understand the plugin task definition

    The plugin defines a task named 'logMessage' that logs the message to the Node.js console and returns null.
  2. Step 2: Understand cy.task behavior

    Calling cy.task('logMessage', 'Hello') sends 'Hello' to the plugin task, which logs it in Node.js, not browser, and returns null.
  3. Final Answer:

    The message 'Hello' is printed in the Node.js console, and the task returns null -> Option C
  4. Quick Check:

    cy.task logs in Node.js console = A [OK]
Hint: cy.task runs plugin code in Node.js, not browser console [OK]
Common Mistakes:
  • Thinking console.log prints in browser console
  • Assuming tasks cannot take arguments
  • Confusing tasks with custom commands
4. Identify the error in this plugin code snippet:
module.exports = (on, config) => {
  on('task', {
    multiplyNumbers(a, b) {
      return a * b
    }
  })
}
And select the correct fix.
medium
A. No error, the code is correct as is
B. Change the task to accept a single argument object like {a, b} instead of two arguments
C. Replace 'on' with 'off' to register the task properly
D. Return a Promise instead of a direct value

Solution

  1. Step 1: Understand how Cypress tasks receive arguments

    Cypress tasks accept only one argument. Multiple arguments must be wrapped in an object.
  2. Step 2: Identify the error and fix

    The function multiplyNumbers expects two arguments, but Cypress will pass only one. Fix by accepting a single object with properties a and b.
  3. Final Answer:

    Change the task to accept a single argument object like {a, b} instead of two arguments -> Option B
  4. Quick Check:

    Tasks accept one argument object = B [OK]
Hint: Tasks get one argument; use object to pass multiple values [OK]
Common Mistakes:
  • Defining task functions with multiple parameters
  • Using 'off' instead of 'on' to register tasks
  • Thinking tasks must return Promises always
5. You want to create a custom plugin that reads a JSON file from disk and returns its content to your test. Which approach correctly implements this plugin task?
hard
A. Use console.log to print file content and return undefined
B. Use cy.readFile inside the plugin task to read the file asynchronously
C. Use browser fetch API inside the plugin task to get the file content
D. Use Node.js fs.readFileSync inside the plugin task and return parsed JSON

Solution

  1. Step 1: Understand plugin environment

    Plugins run in Node.js, so Node.js modules like fs can be used to read files synchronously or asynchronously.
  2. Step 2: Choose correct method to read file

    cy.readFile is a test command, not available in plugins. Browser fetch is not available in Node.js plugin context. Using fs.readFileSync and returning parsed JSON is correct.
  3. Final Answer:

    Use Node.js fs.readFileSync inside the plugin task and return parsed JSON -> Option D
  4. Quick Check:

    Plugins use Node.js fs to read files = A [OK]
Hint: Use Node.js fs module in plugins, not cy commands [OK]
Common Mistakes:
  • Trying to use cy commands inside plugins
  • Using browser APIs in Node.js plugin code
  • Returning undefined instead of file content
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard