{
  "doc": {
    "id": "app/guides/migration/protractor-to-cypress",
    "title": "Migrating from Protractor to Cypress: A Guide",
    "description": "Migrate from Protractor to Cypress with this guide. Learn how to work with the DOM, write assertions, and use the Angular schematic to configure Cypress.",
    "section": "app",
    "source_path": "/llm/markdown/app/guides/migration/protractor-to-cypress.md",
    "version": "ce02913654e2655ee63448bdc92bb92c7b46a619",
    "updated_at": "2026-04-22T19:37:51.587Z",
    "headings": [
      {
        "id": "app/guides/migration/protractor-to-cypress#migrating-from-protractor-to-cypress",
        "text": "Migrating from Protractor to Cypress",
        "level": 1
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#what-youll-learn",
        "text": " What you'll learn",
        "level": 5
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#benefits-of-using-cypress",
        "text": "Benefits of Using Cypress",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#interact-with-your-tests-in-a-browser",
        "text": "Interact with your tests in a browser",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#faster-feedback-loops",
        "text": "Faster feedback loops",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#time-travel-through-tests",
        "text": "Time travel through tests",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#gain-visibility-in-headless-mode-with-screenshots-and-videos",
        "text": "Gain Visibility in Headless Mode with Screenshots and Videos",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#test-retries",
        "text": "Test Retries",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#getting-started",
        "text": "Getting Started",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#recommended-installation",
        "text": "Recommended Installation",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#manual-installation",
        "text": "Manual Installation",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#working-with-the-dom",
        "text": "Working with the DOM",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#how-to-get-dom-elements",
        "text": "How to Get DOM Elements",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#getting-a-single-element-on-the-page",
        "text": "Getting a single element on the page",
        "level": 4
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#getting-multiple-elements-on-a-page",
        "text": "Getting multiple elements on a page",
        "level": 4
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#how-to-interact-with-dom-elements",
        "text": "How to Interact with DOM Elements",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#assertions",
        "text": "Assertions",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#length",
        "text": "Length",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#class",
        "text": "Class",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#value",
        "text": "Value",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#text-content",
        "text": "Text Content",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#visibility",
        "text": "Visibility",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#existence",
        "text": "Existence",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#state",
        "text": "State",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#css",
        "text": "CSS",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#disabled-property",
        "text": "Disabled property",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#negative-assertions",
        "text": "Negative assertions",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#network-handling",
        "text": "Network Handling",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#network-spying",
        "text": "Network Spying",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#network-stubbing",
        "text": "Network Stubbing",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#navigating-websites",
        "text": "Navigating Websites",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#automatic-retrying-and-waiting",
        "text": "Automatic Retrying and Waiting",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#cypress-vs-webdriver-control-flow",
        "text": "Cypress vs WebDriver Control Flow",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#using-page-objects",
        "text": "Using Page Objects",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#protractor-without-page-objects",
        "text": "Protractor without Page Objects",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#protractor-with-page-objects",
        "text": "Protractor with Page Objects",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#cypress-without-page-objects",
        "text": "Cypress without Page Objects",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#cypress-with-page-objects",
        "text": "Cypress with Page Objects",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#continuous-integration",
        "text": "Continuous Integration",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#parallelization",
        "text": "Parallelization",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#angular-schematic-configuration",
        "text": "Angular Schematic Configuration",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#running-the-builder-with-a-specific-browser",
        "text": "Running the builder with a specific browser",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#recording-test-results-to-cypress-cloud",
        "text": "Recording test results to Cypress Cloud",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#specifying-a-custom-cypress-configuration-file",
        "text": "Specifying a custom Cypress configuration file",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#running-cypress-in-parallel-mode-within-ci",
        "text": "Running Cypress in parallel mode within CI",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#code-coverage",
        "text": "Code Coverage",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#questions-or-issues",
        "text": "Questions or Issues?",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#next-steps",
        "text": "Next Steps",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#faqs",
        "text": "FAQs",
        "level": 2
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#do-i-have-to-replace-all-of-my-tests-with-cypress-immediately",
        "text": "Do I have to replace all of my tests with Cypress immediately?",
        "level": 3
      },
      {
        "id": "app/guides/migration/protractor-to-cypress#can-protractor-and-cypress-coexist-in-the-same-app",
        "text": "Can Protractor and Cypress coexist in the same app?",
        "level": 3
      }
    ]
  },
  "content": {
    "type": "root",
    "children": [
      {
        "type": "heading",
        "depth": 1,
        "children": [
          {
            "type": "text",
            "value": "Migrating from Protractor to Cypress"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 5,
        "children": [
          {
            "type": "text",
            "value": " What you'll learn"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "How to migrate from Protractor to Cypress"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "The benefits of using Cypress for end-to-end testing"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "How to work with the DOM and write assertions in Cypress"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Using the Angular schematic to configure Cypress"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Protractor was a popular end-to-end testing tool for Angular and AngularJS\napps, but is\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://blog.angular.io/angular-v12-is-now-available-32ed51fbfd49",
            "children": [
              {
                "type": "text",
                "value": "no longer included"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nin new Angular projects as of Angular 12. We've got you covered here with this\nmigration guide to help you and your team transition from Protractor to Cypress."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "To start, let's look at a quick code sample to see how approachable Cypress is\ncoming from Protractor. In this scenario, we have a test to validate that a user\ncan sign up for a new account."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "To see how this conversion would work with some of your own test code, you can\npaste it into the interactive\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://migrator.cypress.io/",
            "children": [
              {
                "type": "text",
                "value": "Cypress Migrator tool"
              }
            ]
          },
          {
            "type": "text",
            "value": ", which will generate the\nequivalent Cypress code."
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "describe('Authorization tests', () => {\n  it('allows the user to signup for a new account', () => {\n    browser.get('/signup')\n    element(by.css('#email-field')).sendKeys('user@email.com')\n    element(by.css('#confirm-email-field')).sendKeys('user@email.com')\n    element(by.css('#password-field')).sendKeys('testPassword1234')\n    element(by.cssContainingText('button', 'Create new account')).click()\n\n    expect(browser.getCurrentUrl()).toEqual('/signup/success')\n  })\n})"
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "describe('Authorization Tests', () => {\n  it('allows the user to signup for a new account', () => {\n    cy.visit('/signup')\n    cy.get('#email-field').type('user@email.com')\n    cy.get('#confirm-email-field').type('user@email.com')\n    cy.get('#password-field').type('testPassword1234')\n    cy.get('button').contains('Create new account').click()\n\n    cy.url().should('include', '/signup/success')\n  })\n})"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Benefits of Using Cypress"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "As many developers can attest, end-to-end testing is one of those things that\nthey know they should do, but often don't. Or if they do run tests, the tests\nare often flaky and often very expensive due to how long it takes to run. And\nwhile there are often ideals of complete code coverage, the realities of\nbusiness and deadlines often take precedence and the tests are left unwritten,\nor worse, ignored when errors are being reported because they aren't reliable."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Not only does Cypress make sure that your tests will be reliable, but it\nprovides developers with tools that make e2e testing an asset to development\nrather than a hindrance."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Interact with your tests in a browser"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "When Protractor runs tests, the browser automation launches a browser instance\nand often runs through tests too fast for the human eye. Without additional\nconfiguration, this often leads to a reliance on lengthy terminal messages that\ncan be expensive from a context-switching perspective."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "With "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/open-mode.md",
            "children": [
              {
                "type": "text",
                "value": "Cypress"
              }
            ]
          },
          {
            "type": "text",
            "value": ", your tests run in an\ninteractive browser environment in real time. Cypress's\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/open-mode.md#Command-Log",
            "children": [
              {
                "type": "text",
                "value": "Command Log"
              }
            ]
          },
          {
            "type": "text",
            "value": " displays the tests\nfrom your test suite and their assertions. When you\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/open-mode.md#Command-Log",
            "children": [
              {
                "type": "text",
                "value": "click on a command or assertion"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nin the command log, a DOM snapshot displays so you can see what the application\nunder test looked like at the time of the test's execution. This allows you to\nsee the real rendered UI and the behavior of the app under real user\ninteractions. Since the app is loaded within a real browser, you can also\nmanually explore its behavior while it is under the state of a desired test\nscenario."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress also helps you to write your tests by making it as easy as possible to\nfind the right CSS selectors for the DOM elements in your application with "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/guides/cypress-studio.md",
            "children": [
              {
                "type": "text",
                "value": "Cypress Studio"
              }
            ]
          },
          {
            "type": "text",
            "value": ". With a "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/get-started/introduction.md",
            "children": [
              {
                "type": "text",
                "value": "Cypress Cloud"
              }
            ]
          },
          {
            "type": "text",
            "value": " account, Studio includes Studio AI, AI-powered assertion recommendations as you record."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "These tools help you cut down on time spent finding the right\nselectors so you can focus on what's important: writing tests that verify your\napp's logic."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Faster feedback loops"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "When it comes to your end-to-end or component tests, being able to see your tests as they run\nis critical to allowing you to confidently iterate faster. With Cypress, your\ntests are automatically re-run upon file save as you are iterating on them."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Having your code editor and application under test within a browser side-by-side\n(shown below) while re-running tests on save is a highly productive workflow. It\nprovides an instant feedback loop that allows you to iterate faster with\nconfidence."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Time travel through tests"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress gives you time travel capabilities to see exactly how your app was\nbehaving at any point during test execution. Cypress takes DOM snapshots of your\napplication under test as the commands and assertions in your tests are\nexecuted. This enables you to view the real UI of your application at any\npoint during your tests' execution. By clicking from one command to another in\nthe "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/open-mode.md#Command-Log",
            "children": [
              {
                "type": "text",
                "value": "command log"
              }
            ]
          },
          {
            "type": "text",
            "value": ", you can see\nwhich elements Cypress acted upon and how your application responded to the\nsimulated real user behavior."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Gain Visibility in Headless Mode with Screenshots and Videos"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Running browser tests in headless mode (locally or in continuous integration\npipeline) can be a bit of a black-box without much visibility. When tests fail,\nerror messages by themselves can often fall short in painting the picture of\nwhy something failed, especially if assertions were not explicit enough or\ntoo indirect. To understand the reason behind test failures it also helps to see\nthe state of the app UI at the point of failure or see the events that led up to\nthe failure."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress assists with debugging in headless mode, in numerous ways:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Replay the test as it executed during the recorded run with full debug capability using "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "/llm/markdown/cloud/features/test-replay.md",
                    "children": [
                      {
                        "type": "text",
                        "value": "Test Replay"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " in Cypress Cloud."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "By automatically taking a\nscreenshot of the app UI and command log at the exact point of test failure."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "To see everything that happened prior to test failure, enable the "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "/llm/markdown/app/references/configuration.md#Videos",
                    "children": [
                      {
                        "type": "text",
                        "value": "`video`"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": ".\nconfiguration option to record (as an MP4 file) the full test spec run."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Test Retries"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "End-to-end tests can be complicated because modern web applications are also\ncomplex. You may find that some features of your web application are challenging\nto test or the tests sporadically fail. We call these tests \"flaky.\" Cypress\nallows you to "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/guides/test-retries.md",
            "children": [
              {
                "type": "text",
                "value": "retry failed tests"
              }
            ]
          },
          {
            "type": "text",
            "value": ". Sometimes tests\nwill fail in a CI environment when they otherwise would pass on a developer's\nmachine. Enabling test retries in the Cypress configuration can help you to get\nunblocked when unpredictable, flaky tests are occasionally failing."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress Cloud goes a step further and helps you and your team to\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/features/flaky-test-management.md",
            "children": [
              {
                "type": "text",
                "value": "detect flaky tests"
              }
            ]
          },
          {
            "type": "text",
            "value": " that run in your CI/CD\npipeline."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Getting Started"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Recommended Installation"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "We recommend using our\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://www.npmjs.com/package/@cypress/schematic",
            "children": [
              {
                "type": "text",
                "value": "official Cypress Angular schematic"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nto add Cypress to your Angular project:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "shell",
        "meta": null,
        "value": "ng add @cypress/schematic"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "This will install Cypress, add scripts for running Cypress in `run` and `open`\nmode, scaffold base Cypress files and directories, and (optional) prompt you to\nremove Protractor and reconfigure the default `ng e2e` command to use Cypress."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "With our schematic installed and Protractor removed, you can run Cypress in\n`open` mode with the following command:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "shell",
        "meta": null,
        "value": "ng e2e"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You can also use the following command to start Cypress in `open` mode:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "shell",
        "meta": null,
        "value": "ng run {your-project-name}:cypress-open"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Both of these commands will launch Cypress in an Electron browser."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You can also launch Cypress via `run` mode, which runs headlessly:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "shell",
        "meta": null,
        "value": "ng run {your-project-name}:cypress-run"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Check out the\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "#Angular-Schematic-Configuration",
            "children": [
              {
                "type": "text",
                "value": "Cypress Angular Schematic Configuration section"
              }
            ]
          },
          {
            "type": "text",
            "value": "\ndocumentation for more details like how to\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "#Running-the-builder-with-a-specific-browser",
            "children": [
              {
                "type": "text",
                "value": "configure your tests to run in a specific browser"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nor "
          },
          {
            "type": "link",
            "title": null,
            "url": "#Recording-test-results-to-Cypress-Cloud",
            "children": [
              {
                "type": "text",
                "value": "record test results"
              }
            ]
          },
          {
            "type": "text",
            "value": " to\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/get-started/introduction.md",
            "children": [
              {
                "type": "text",
                "value": "Cypress Cloud"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://www.npmjs.com/package/@cypress/schematic",
            "children": [
              {
                "type": "text",
                "value": "Cypress Angular Schematic"
              }
            ]
          },
          {
            "type": "text",
            "value": "\npackage was made possible by the original work of the\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://briebug.com/",
            "children": [
              {
                "type": "text",
                "value": "Briebug"
              }
            ]
          },
          {
            "type": "text",
            "value": " team and the contributors of\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://www.npmjs.com/package/@briebug/cypress-schematic",
            "children": [
              {
                "type": "text",
                "value": "@briebug/cypress-schematic"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "@briebug/cypress-schematic served as the starting point for improvements and\nnew functionality the Cypress team will continue to develop along with the\ncommunity."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Manual Installation"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "While we recommend using our official Angular schematic, you can still install\nCypress manually."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Then, since Cypress can run in parallel with your application, let's install\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://www.npmjs.com/package/concurrently",
            "children": [
              {
                "type": "text",
                "value": "concurrently"
              }
            ]
          },
          {
            "type": "text",
            "value": " to simplify our npm\nscript. This is optional; however, you will need another way to serve your\nAngular app for Cypress to run tests against your application."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Then we will update our `package.json` with the following scripts:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "json",
        "meta": "title=\"package.json\"",
        "value": "{\n  \"scripts\": {\n    \"cy:open\": \"concurrently \\\"ng serve\\\" \\\"cypress open\\\"\",\n    \"cy:run\": \"concurrently \\\"ng serve\\\" \\\"cypress run\\\"\"\n  },\n  \"dependencies\": { ... },\n  \"devDependencies\": { ... }\n}"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Now, when we run:"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "It will start up Cypress and our Angular app at the same time."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Again, we highly recommend using our\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress/tree/develop/npm/cypress-schematic",
            "children": [
              {
                "type": "text",
                "value": "Angular Schematic"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nto install Cypress, and we plan on adding new capabilities to it over time."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Working with the DOM"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "How to Get DOM Elements"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 4,
        "children": [
          {
            "type": "text",
            "value": "Getting a single element on the page"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "When it comes to e2e tests, one of the most common things you'll need to do is\nget one or more HTML elements on a page. Rather than split element fetching into\nmultiple methods that you need to memorize, everything can be accomplished with\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/get.md",
            "children": [
              {
                "type": "text",
                "value": "`cy.get`"
              }
            ]
          },
          {
            "type": "text",
            "value": " while using CSS selectors or the preferred\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/best-practices.md#Selecting-Elements",
            "children": [
              {
                "type": "text",
                "value": "data attribute"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Get an element\nelement(by.tagName('h1'))\n\n/// Get an element using a CSS selector.\nelement(by.css('.my-class'))\n\n// Get an element with the given id.\nelement(by.id('my-id'))\n\n// Get an element using an input name selector.\nelement(by.name('field-name'))\n\n//Get an element by the text it contains within a certain CSS selector\nelement(by.cssContainingText('.my-class', 'text'))\n\n//Get the first element containing a specific text (only for link elements)\nelement(by.linkText('text'))"
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Get an element\ncy.get('h1')\n\n// Get an element using a CSS selector.\ncy.get('.my-class')\n\n// Get an element with the given id.\ncy.get('#my-id')\n\n// Get an element using an input name selector.\ncy.get('input[name=\"field-name\"]')\n\n//Get an element by the text it contains within a certain CSS selector\ncy.get('.my-class').contains('text')\n\n//Get the first element containing a specific text (available for any element)\ncy.contains('text')"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You can also get elements by their text value. This can be accomplished using\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/contains.md",
            "children": [
              {
                "type": "text",
                "value": "`cy.contains`"
              }
            ]
          },
          {
            "type": "text",
            "value": " while using CSS selectors to account for\nall use cases."
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Get an element by the text it contains within a certain CSS selector\nelement(by.cssContainingText('.my-class', 'text'))\n\n// Get the first element containing a specific text (only for link elements)\nelement(by.linkText('text'))"
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Get an element by the text it contains within a certain CSS selector\ncy.get('.my-class').contains('text')\n\n// Get the first element containing a specific text (available for any element)\ncy.contains('text')"
      },
      {
        "type": "heading",
        "depth": 4,
        "children": [
          {
            "type": "text",
            "value": "Getting multiple elements on a page"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "When you want to get access to more than one element on the page, you would need\nto chain the `.all()` method. However, in Cypress, no syntax change is\nnecessary!"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Get all list-item elements on the page\nelement.all(by.tagName('li'))\n\n/// Get all elements by using a CSS selector.\nelement.all(by.css('.list-item'))\n\n// Find an element using an input name selector.\nelement.all(by.name('field-name'))"
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Get all list-item elements on the page\ncy.get('li')\n\n/// Get all elements by using a CSS selector.\ncy.get('.list-item')\n\n// Find an element using an input name selector.\ncy.get('input[name=\"field-name\"]')"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Another plugin that we recommend for selecting multiple elements is the\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/testing-library/cypress-testing-library",
            "children": [
              {
                "type": "text",
                "value": "Cypress Testing Library"
              }
            ]
          },
          {
            "type": "text",
            "value": ".\nThis extends Cypress by adding `findBy` and `findAllBy` commands."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You can learn more about\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/get.md#Syntax",
            "children": [
              {
                "type": "text",
                "value": "how to get DOM elements in our official documentation"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "How to Interact with DOM Elements"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Click on the element\nelement(by.css('button')).click()\n\n// Send keys to the element (usually an input)\nelement(by.css('input')).sendKeys('my text')\n\n// Clear the text in an element (usually an input).\nelement(by.css('input')).clear()\n\n// Check the first checkbox on a page\nelement.all(by.css('[type=\"checkbox\"]')).first().click()\n\n// Check a radio button with the value \"radio1\"\nelement(by.css('[type=\"radio\"][value=\"radio1\"]')).click()\n\n// Uncheck the first checkbox that is checked\nelement.all(by.css('[type=\"checkbox\"][checked=\"true\"]')).first().click()\n\n// Select an option with the text value \"my value\" from a select list\nelement(by.cssContainingText('option', 'my value')).click()\n\n// Scroll an element into view\nbrowser\n  .actions()\n  .mouseMove(element(by.id('my-id')))\n  .perform()"
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Click on the element\ncy.get('button').click()\n\n// Send keys to the element (usually an input)\ncy.get('input').type('my text')\n\n// Clear the text in an element (usually an input)\ncy.get('input').clear()\n\n// Check the first checkbox on a page\ncy.get('[type=\"checkbox\"]').first().check()\n\n// Check a radio button with the value \"radio1\"\ncy.get('[type=\"radio\"]').check('radio1')\n\n// Uncheck the first checkbox that is not disabled\ncy.get('[type=\"checkbox\"]').not('[disabled]').first().uncheck()\n\n// Select an option with the text value \"my value\" from a select list\ncy.get('select[name=\"optionsList\"]').select('my value')\n\n// Scroll an element into view\ncy.get('#my-id').scrollIntoView()"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You can learn more about\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/interacting-with-elements.md",
            "children": [
              {
                "type": "text",
                "value": "interacting with DOM elements in our official documentation"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Assertions"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Similar to Protractor, Cypress enables use of human readable assertions."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Here are some common DOM element assertions with Cypress and equivalent\nassertions with Protractor."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Length"
          }
        ]
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "const list = element.all(by.css('li.selected'))\nexpect(list.count()).toBe(3)"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// retry until we find 3 matching <li.selected>\ncy.get('li.selected').should('have.length', 3)"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Class"
          }
        ]
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "expect(\n  element(by.tagName('form')).element(by.tagName('input')).getAttribute('class')\n).not.toContain('disabled')"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// retry until this input does not have class disabled\ncy.get('form').find('input').should('not.have.class', 'disabled')"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Value"
          }
        ]
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "expect(element(by.tagName('textarea'))).getAttribute('value')).toBe('foo bar baz')"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// retry until this textarea has the correct value\ncy.get('textarea').should('have.value', 'foo bar baz')"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Text Content"
          }
        ]
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// assert the element's text content is exactly the given text\nexpect(element(by.id('user-name')).getText()).toBe('Joe Smith')\n// assert the element's text includes the given substring\nexpect(element(by.id('address')).getText()).toContain('Atlanta')\n// assert the span does not contain 'click me'\nconst child = element(by.tagName('a')).getWebElement()\nconst parent = child.getDriver().findElement(by.css('span.help'))\nexpect(parent.getText()).not.toContain('click me')\n// assert that the greeting starts with \"Hello\"\nelement(by.id('greeting').getText()).toMatch(/^Hello/)"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// assert the element's text content is exactly the given text\ncy.get('#user-name').should('have.text', 'Joe Smith')\n// assert the element's text includes the given substring\ncy.get('#address').should('include.text', 'Atlanta')\n// retry until this span does not contain 'click me'\ncy.get('a').parent('span.help').should('not.contain', 'click me')\n// the element's text should start with \"Hello\"\ncy.get('#greeting')\n  .invoke('text')\n  .should('match', /^Hello/)\n// tip: use cy.contains to find element with its text\n// matching the given regular expression\ncy.contains('#a-greeting', /^Hello/)"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Visibility"
          }
        ]
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// assert button is visible\nexpect(element(by.tagName('button')).isDisplayed()).toBe(true)"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// retry until this button is visible\ncy.get('button').should('be.visible')"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Existence"
          }
        ]
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// assert the spinner no longer exists\nexpect(element(by.id('loading')).isPresent()).toBe(false)"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// retry until loading spinner no longer exists\ncy.get('#loading').should('not.exist')"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "State"
          }
        ]
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "expect(element('input[type=\"radio\"]').isSelected()).toBeTruthy()"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// retry until our radio is checked\ncy.get(':radio').should('be.checked')"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "CSS"
          }
        ]
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// assert .completed has css style \"line-through\" for \"text-decoration\" property\nexpect(element(by.css('.completed')).getCssValue('text-decoration')).toBe(\n  'line-through'\n)\n\n// assert the accordion does not have a \"display: none\"\nexpect(element(by.id('accordion')).getCssValue('display')).not.toBe('none')"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// retry until .completed has matching css\ncy.get('.completed').should('have.css', 'text-decoration', 'line-through')\n\n// retry while .accordion css has the \"display: none\" property\ncy.get('#accordion').should('not.have.css', 'display', 'none')"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Disabled property"
          }
        ]
      },
      {
        "type": "code",
        "lang": "html",
        "meta": null,
        "value": "<input type=\"text\" id=\"example-input\" disabled />"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "// assert the input is disabled\nexpect(element(by.id('example-input')).isEnabled()).toBe(false)"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "cy.get('#example-input')\n  .should('be.disabled')\n  // let's enable this element from the test\n  .invoke('prop', 'disabled', false)\n\ncy.get('#example-input')\n  // we can use \"enabled\" assertion\n  .should('be.enabled')\n  // or negate the \"disabled\" assertion\n  .and('not.be.disabled')"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress has one additional feature that can make a critical difference in the\nreliability of your tests' assertions:\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/retry-ability.md",
            "children": [
              {
                "type": "text",
                "value": "retry-ability"
              }
            ]
          },
          {
            "type": "text",
            "value": ".\nWhen your test fails an assertion or command, Cypress will mimic a real user\nwith build-in wait times and multiple attempts at asserting your tests in order\nto minimize the amount of false negatives / positives."
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "describe('verify elements on a page', () => {\n  it('verifies that a link is visible', () => {\n    expect($('a.submit-link').isDisplayed()).toBe(true)\n  })\n})"
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "describe('verify elements on a page', () => {\n  it('verifies that a link is visible', () => {\n    cy.get('a.submit-link').should('be.visible')\n  })\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In the example above, if the submit link does not appear on the page at the\nexact moment when Protractor runs the test (which can be due to any number of\nfactors including API calls, slow browser rendering, etc.), your test will fail.\nHowever, Cypress factors these conditions into its assertions and will only fail\nif the time goes beyond a reasonable amount."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Negative assertions"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "There are positive and negative assertions. Negative assertions have the \"not\"\nchainer prefixed to the assertion. Examples of negative assertions in both\nProtractor and Cypress:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "expect(\n  element(by.css('.todo'))\n    .getAttribute('class')\n    .then((classes) => {\n      return classes.split(' ').indexOf('completed') !== -1\n    })\n).not.toBe(true)\n\nexpect(element(by.id('loading')).isDisplayed()).not.toBe(true)"
      },
      {
        "type": "code",
        "lang": "javascript",
        "meta": null,
        "value": "cy.get('.todo').should('not.have.class', 'completed')\ncy.get('#loading').should('not.be.visible')"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Learn more about how Cypress handles\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/references/assertions.md",
            "children": [
              {
                "type": "text",
                "value": "assertions"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Network Handling"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Network Spying"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Protractor doesn't offer a built-in solution for network spying. With Cypress,\nyou can leverage the "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/intercept.md",
            "children": [
              {
                "type": "text",
                "value": "intercept API"
              }
            ]
          },
          {
            "type": "text",
            "value": " to spy on and\nmanage the behavior of any network request."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "For example, if you wanted to wait on a network request to complete before\ncontinuing your test, you could write the following:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "it('should display a Load More button after fetching and displaying a list of users', () => {\n  cy.visit('/users')\n  cy.intercept('/users/**')\n  cy.get('button').contains('Load More')\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress will automatically wait for any request to `/users/**` to complete\nbefore continuing your test."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Network Stubbing"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress's "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/intercept.md",
            "children": [
              {
                "type": "text",
                "value": "intercept API"
              }
            ]
          },
          {
            "type": "text",
            "value": " also allows you to stub any\nnetwork request for your app under test. You can use the\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/intercept.md",
            "children": [
              {
                "type": "text",
                "value": "intercept API"
              }
            ]
          },
          {
            "type": "text",
            "value": " to make assertions based on different\nsimulated responses for your network requests. For example, you might want to\nsimulate a 3rd-party API outage by forcing a network error and test your app\nunder those conditions. With Cypress's "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/intercept.md",
            "children": [
              {
                "type": "text",
                "value": "intercept API"
              }
            ]
          },
          {
            "type": "text",
            "value": ",\nthis and more is possible!"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "it('should display a warning when the third-party API is down', () => {\n  cy.intercept(\n    'GET',\n    'https://api.openweathermap.org/data/2.5/weather?q=Atlanta',\n    { statusCode: 500 }\n  )\n  cy.get('.weather-forecast').contains('Weather Forecast Unavailable')\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You can also use the intercept API to stub a custom response for specific\nnetwork requests:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "it('projects endpoint should return 2 projects', () => {\n  cy.intercept('/projects', {\n    body: [{ projectId: '1' }, { projectId: '2' }],\n  }).as('projects')\n  cy.wait('@projects').its('response.body').should('have.length', 2)\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "For more information, check out the\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/commands/intercept.md",
            "children": [
              {
                "type": "text",
                "value": "intercept API documentation"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Navigating Websites"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "When you want to visit a page, you can do so with the following code:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "it('visits a page', () => {\n  browser.get('/about')\n  browser.navigate().forward()\n  browser.navigate().back()\n})"
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "it('visits a page', () => {\n  cy.visit('/about')\n  cy.go('forward')\n  cy.go('back')\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "However, Protractor assumes that all websites you want to visit are Angular\napps. As a result, you have to take an extra step to disable this behavior. When\nyou write Cypress tests though, you don't need to do any extra work!"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "it('visit a non-Angular page', () => {\n  browser.waitForAngularEnabled(false)\n  browser.get('/about')\n})"
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "it('visit a non-Angular page', () => {\n  cy.visit('/about')\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "For more information, check out our\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://example.cypress.io/commands/navigation",
            "children": [
              {
                "type": "text",
                "value": "official documentation on navigation"
              }
            ]
          },
          {
            "type": "text",
            "value": "!"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Automatic Retrying and Waiting"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Web applications are usually rarely synchronous. With Protractor, you may be\naccustomed to adding arbitrary timeouts or using the\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://www.protractortest.org/#/api?view=ProtractorBrowser.prototype.waitForAngular",
            "children": [
              {
                "type": "text",
                "value": "waitForAngular"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nAPI to wait for Angular to finish rendering before attempting to interact with\nan element."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "With Cypress, commands that query the DOM are\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/retry-ability.md",
            "children": [
              {
                "type": "text",
                "value": "automatically retried"
              }
            ]
          },
          {
            "type": "text",
            "value": ". Cypress will\nautomatically wait and retry most commands until an element appears in the DOM.\nIf an element is not\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/interacting-with-elements.md#Actionability",
            "children": [
              {
                "type": "text",
                "value": "actionable"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nwithin the\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/retry-ability.md#Timeouts",
            "children": [
              {
                "type": "text",
                "value": "`defaultCommandTimeout`"
              }
            ]
          },
          {
            "type": "text",
            "value": " setting,\nthe command will fail. This enables you to write tests without the need for\narbitrary timeouts, enabling you to write more predictable tests."
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Clicking a button\nelement(by.css('button')).click()\n// Waiting for Angular to re-render the page\nbrowser.waitForAngular()\n// Make assertion after waiting for Angular to update\nexpect(by.css('.list-item').getText()).toEqual('my text')"
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Clicking a button\ncy.get('button').click()\n// Make assertion. No waiting necessary!\ncy.get('.list-item').contains('my text')"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Cypress vs WebDriver Control Flow"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress commands are similar to Protractor code at first glance. Cypress\ncommands are\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/introduction-to-cypress.md#Commands-Are-Asynchronous",
            "children": [
              {
                "type": "text",
                "value": "not invoked immediately"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nand are enqueued to run serially at a later time. Cypress commands might look\nlike promises, but the\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/introduction-to-cypress.md#The-Cypress-Command-Queue",
            "children": [
              {
                "type": "text",
                "value": "Cypress API is not an exact implementation of Promises"
              }
            ]
          },
          {
            "type": "text",
            "value": ".\nThe modern web is asynchronous, therefore you need to interact with modern web\napps in an asynchronous fashion. This is why the Cypress API is asynchronous.\nThis allows you to write deterministic tests since all of your commands are\nexecuted serially, enabling your tests to run predictably each time."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In comparison, Protractor's WebDriverJS API is based on promises, which is\nmanaged by a control flow. This\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://www.protractortest.org/#/control-flow",
            "children": [
              {
                "type": "text",
                "value": "Control Flow"
              }
            ]
          },
          {
            "type": "text",
            "value": " enables you to\nwrite asynchronous Protractor tests in a synchronous style."
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Click on the element\n// This code looks synchronous!\nelement(by.css('button')).click()\n\n// Send keys to the element (usually an input)\nelement(by.css('input')).sendKeys('my text')"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Protractor's Control Flow can be disabled, allowing you to write your test cases\nas asynchronous functions."
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Wait for the button to be found and click it\nawait element(by.css('button')).click()\n\n// Wait for the input to be found and type into the field\nawait element(by.css('input')).sendKeys('my text')"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The Control Flow example rewritten as a Cypress test would look something like\nthis:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Click on the element\ncy.get('button').click()\n\n// Send keys to the element (usually an input)\ncy.get('input').type('my text')"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Using Page Objects"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "A common pattern when writing end-to-end tests, especially with Protractor, is\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/SeleniumHQ/selenium/wiki/PageObjects",
            "children": [
              {
                "type": "text",
                "value": "Page Objects"
              }
            ]
          },
          {
            "type": "text",
            "value": ". Page\nObjects can simplify your test code by creating reusable methods if you find\nyourself writing the same test code across multiple test cases."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Protractor without Page Objects"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "// Type into username field\nelement(by.css('.username')).sendKeys('my username')\n// Type into password field\nelement(by.css('.password')).sendKeys('my password')\n// Click the login button\nelement(by.css('button')).click()"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Protractor with Page Objects"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "const page = {\n  login: () => {\n    element(by.css('.username')).sendKeys('my username')\n    element(by.css('.password')).sendKeys('my password')\n    element(by.css('button')).click()\n  },\n}\n\nit('should display the username of a logged in user', () => {\n  page.login()\n  expect(by.css('.username').getText()).toEqual('my username')\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You can use the same Page Object pattern within your Cypress tests:"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Cypress without Page Objects"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "cy.get('.username').type('my username')\ncy.get('.password').type('my password')\ncy.get('button').click()"
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Cypress with Page Objects"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "const page = {\n  login: () => {\n    cy.get('.username').type('my username')\n    cy.get('.password').type('my password')\n    cy.get('button').click()\n  },\n}\n\nit('should display the username of a logged in user', () => {\n  page.login()\n  cy.get('.username').contains('my username')\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress also provides a "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/api/cypress-api/custom-commands.md",
            "children": [
              {
                "type": "text",
                "value": "Custom Command"
              }
            ]
          },
          {
            "type": "text",
            "value": " API\nto enable you to add methods to the `cy` global directly:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "Cypress.Commands.add('login', (username, password) => {\n  cy.get('.username').type(username)\n  cy.get('.password').type(password)\n})"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You can use your own custom commands in any of your tests:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "js",
        "meta": null,
        "value": "it('should display the username of a logged in user', () => {\n  cy.env(['PASSWORD']).then(({ password }) => {\n    cy.login('Matt', password)\n  })\n  cy.get('.username').contains('Matt')\n})"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Continuous Integration"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress makes it easy to\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/continuous-integration/overview.md",
            "children": [
              {
                "type": "text",
                "value": "run your tests in all Continuous Integration environments"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Check out our in-depth guides to run your Cypress tests in\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/continuous-integration/github-actions.md",
            "children": [
              {
                "type": "text",
                "value": "GitHub Actions"
              }
            ]
          },
          {
            "type": "text",
            "value": ",\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/continuous-integration/circleci.md",
            "children": [
              {
                "type": "text",
                "value": "CircleCI"
              }
            ]
          },
          {
            "type": "text",
            "value": ",\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/continuous-integration/gitlab-ci.md",
            "children": [
              {
                "type": "text",
                "value": "GitLab CI"
              }
            ]
          },
          {
            "type": "text",
            "value": ",\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/continuous-integration/bitbucket-pipelines.md",
            "children": [
              {
                "type": "text",
                "value": "Bitbucket Pipeline"
              }
            ]
          },
          {
            "type": "text",
            "value": ", or\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/continuous-integration/aws-codebuild.md",
            "children": [
              {
                "type": "text",
                "value": "AWS CodeBuild"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "We also have code samples to get Cypress up and running in\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/continuous-integration/overview.md#CI-Examples",
            "children": [
              {
                "type": "text",
                "value": "many of the other popular CI environments"
              }
            ]
          },
          {
            "type": "text",
            "value": ".\nEven if your CI provider isn't listed, you can still run Cypress in your CI\nenvironment."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Parallelization"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/get-started/introduction.md",
            "children": [
              {
                "type": "text",
                "value": "Cypress Cloud"
              }
            ]
          },
          {
            "type": "text",
            "value": " allows you to run your test files in\nparallel across multiple CI machines."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "With Cypress, your tests can be\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/features/smart-orchestration/parallelization.md",
            "children": [
              {
                "type": "text",
                "value": "parallelized on a per spec file basis"
              }
            ]
          },
          {
            "type": "text",
            "value": ".\nThis is an important distinction between Protractor and Cypress parallelization.\nOne of the reasons why Cypress parallelizes tests per file is because some users\nmay write tests that build up state that subsequent tests, although we\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/best-practices.md#Having-Tests-Rely-On-The-State-Of-Previous-Tests",
            "children": [
              {
                "type": "text",
                "value": "do not recommend relying on the state of previous tests"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "With Cypress, all you need to do is pass the `--parallel` and `--record` flag to\n`cypress run`, and it will take care of the rest for you:"
          }
        ]
      },
      {
        "type": "code",
        "lang": "bash",
        "meta": null,
        "value": "cypress run --record --parallel"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "For more information, check out our\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/features/smart-orchestration/parallelization.md",
            "children": [
              {
                "type": "text",
                "value": "docs on parallelization"
              }
            ]
          },
          {
            "type": "text",
            "value": "!"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Debugging Cypress Cloud Test Runs?"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Don't rely on artifact representations or reproducing failing conditions locally. Replay the test as it executed during the recorded run with full debug capability using "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/features/test-replay.md",
            "children": [
              {
                "type": "text",
                "value": " Test Replay"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Angular Schematic Configuration"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress/tree/develop/npm/cypress-schematic#readme",
            "children": [
              {
                "type": "text",
                "value": "Cypress Angular Schematic"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nhas many configurable options to fit the needs of your project."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Running the builder with a specific browser"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Before running Cypress in `open` mode, ensure that you have started your\napplication server using `ng serve`."
          }
        ]
      },
      {
        "type": "code",
        "lang": "json",
        "meta": null,
        "value": "\"cypress-open\": {\n  \"builder\": \"@cypress/schematic:cypress\",\n  \"options\": {\n    \"watch\": true,\n    \"headless\": false,\n    \"browser\": \"chrome\"\n  },\n  \"configurations\": {\n    \"production\": {\n      \"devServerTarget\": \"{project-name}:serve:production\"\n    }\n  }\n}"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Read the docs on "
          },
          {
            "type": "link",
            "title": null,
            "url": "http://on.cypress.io/launching-browsers",
            "children": [
              {
                "type": "text",
                "value": "launching browsers"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nto learn more."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Recording test results to Cypress Cloud"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "We recommend setting your\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/get-started/introduction.md",
            "children": [
              {
                "type": "text",
                "value": "Cypress Cloud"
              }
            ]
          },
          {
            "type": "text",
            "value": " recording key\nas an environment variable and NOT as a builder option when running it in CI."
          }
        ]
      },
      {
        "type": "code",
        "lang": "json",
        "meta": null,
        "value": "\"cypress-run\": {\n  \"builder\": \"@cypress/schematic:cypress\",\n  \"options\": {\n    \"devServerTarget\": \"{project-name}:serve\",\n    \"record\": true,\n    \"key\": \"your-cypress-dashboard-recording-key\"\n  },\n  \"configurations\": {\n    \"production\": {\n      \"devServerTarget\": \"{project-name}:production\"\n    }\n  }\n}"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Read the docs on\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "http://on.cypress.io/recording-project-runs",
            "children": [
              {
                "type": "text",
                "value": "recording test results"
              }
            ]
          },
          {
            "type": "text",
            "value": " to\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/get-started/introduction.md",
            "children": [
              {
                "type": "text",
                "value": "Cypress Cloud"
              }
            ]
          },
          {
            "type": "text",
            "value": " to learn more."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Specifying a custom Cypress configuration file"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "It may be useful to have different Cypress configuration files per environment\n(ie. development, staging, production)."
          }
        ]
      },
      {
        "type": "code",
        "lang": "json",
        "meta": null,
        "value": "\"cypress-run\": {\n  \"builder\": \"@cypress/schematic:cypress\",\n  \"options\": {\n    \"devServerTarget\": \"{project-name}:serve\",\n    \"configFile\": \"cypress.production.config.js\"\n  },\n  \"configurations\": {\n    \"production\": {\n      \"devServerTarget\": \"{project-name}:production\"\n    }\n  }\n}"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Read our docs to learn more about all the\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "http://on.cypress.io/configuration",
            "children": [
              {
                "type": "text",
                "value": "configuration options"
              }
            ]
          },
          {
            "type": "text",
            "value": " Cypress offers."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Running Cypress in parallel mode within CI"
          }
        ]
      },
      {
        "type": "code",
        "lang": "json",
        "meta": null,
        "value": "\"cypress-run\": {\n  \"builder\": \"@cypress/schematic:cypress\",\n  \"options\": {\n    \"devServerTarget\": \"{project-name}:serve\",\n    \"parallel\": true,\n    \"record\": true,\n    \"key\": \"your-cypress-dashboard-recording-key\"\n  },\n  \"configurations\": {\n    \"production\": {\n      \"devServerTarget\": \"{project-name}:production\"\n    }\n  }\n}"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Read our docs to learn more about speeding up test execution in CI via\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "http://on.cypress.io/parallelization",
            "children": [
              {
                "type": "text",
                "value": "Cypress parallelization"
              }
            ]
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Code Coverage"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "As you write more and more end-to-end tests, you will find yourself wondering -\ndo I need to write more tests? Are there parts of the application still\nuntested? Are there parts of the application that perhaps are tested too much?\nThis "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/tooling/code-coverage.md",
            "children": [
              {
                "type": "text",
                "value": "code coverage guide"
              }
            ]
          },
          {
            "type": "text",
            "value": " is an excellent\nresource to learn how to add code coverage."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Questions or Issues?"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Visit our\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress/discussions/categories/plugins",
            "children": [
              {
                "type": "text",
                "value": "plugins discussion"
              }
            ]
          },
          {
            "type": "text",
            "value": "\nto ask questions or report issues related to our Cypress Angular Schematic."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Next Steps"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "For more information on how to create end-to-end tests with Cypress, be sure to\ncheck out "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/get-started/why-cypress.md",
            "children": [
              {
                "type": "text",
                "value": "our official documentation here"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "If you see any inaccuracies with this guide or feel like something has been\nmisrepresented, please\n"
          },
          {
            "type": "link",
            "title": null,
            "url": "https://github.com/cypress-io/cypress/discussions/new",
            "children": [
              {
                "type": "text",
                "value": "start a discussion here"
              }
            ]
          },
          {
            "type": "text",
            "value": "."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "FAQs"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Do I have to replace all of my tests with Cypress immediately?"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Absolutely not. While it might sound ideal to replace Protractor immediately,\nyou can gradually migrate Protractor tests over to Cypress."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Can Protractor and Cypress coexist in the same app?"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Yes! Your Protractor tests would continue to live in the `e2e` directory that\nAngular CLI scaffolded while all Cypress tests would live in a sibling folder\nnamed `cypress`."
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": ".\n├── cypress\n├── e2e\n├── src\n├── .editorconfig\n├── .gitignore\n├── angular.json\n├── browserslist\n├── cypress.config.js\n├── karma.conf.js\n├── package.json\n├── README.md\n├── tsconfig.app.json\n├── tsconfig.json\n├── tsconfig.spec.json\n└── tslint.json"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In fact, as you work through migrating to Cypress, we believe that progressively\nenhancing your e2e tests with Cypress is the best path forward to ensure that\nfeature development is not impacted."
          }
        ]
      }
    ]
  },
  "token_estimate": 5676
}