Send With Confidence
Partner with the email service trusted by developers and marketers for time-savings, scalability, and delivery expertise.
Time to read: 15 minutes
cy.get(“[data-hook=’someSelector’]”)
or cy.find(“.selector”)
.cy.contains(“someText”)
or getting an element with a certain selector that contains some text such as cy.contains(“.selector”, “someText”)
.cy.get(“.selector”).within(() => { cy.get(“.child”) })
.cy.get(“tr”).each(($tableRow) => { cy.wrap($tableRow).find(‘td’).eq(1).should(“contain”, “someText” })
.cy.get(“.buttonFarBelow”).scrollIntoView()
.{ timeout: timeoutInMs }
like cy.get(“.someElement”, { timeout: 10000 })
.{ force: true }
property in those function calls to bypass some checks with the elements. This often occurs when an element is covered in some way or derived from an external library that you do not have much control over in terms of how it renders elements.
cy.get(“.button”).click()
.cy.get(“input”).type(“somekeyboardtyping”)
and we may need to clear out some default values of inputs by clearing it first like cy.get(“input”).clear().type(“somenewinput”)
. There are also cool ways to type other keys like {enter}
for the Enter key when you do cy.get(“input”).type(“text{enter}”)
.cy.get(“select”).select(“value”)
and checkboxes like cy.get(“.checkbox”).check()
.cy.get(“.selector”).should(“be.visible”)
and cy.get(“.selector”).should(“not.be.visible”)
.cy.get(“.element”).should(“exist”)
or cy.get(“.element”).should(“not.exist”)
.cy.get(“button”).should(“contain”, “someText”)
and cy.get(“button”).should(“not.contain”, “someText”)
.cy.get(“button”).should(“be.disabled”)
.cy.get(“.checkbox”).should(“be.checked”)
.cy.get(“element”).should(“have.class”, “class-name”)
. There are other similar ways to test attributes as well with .should(“have.attr”, “attribute”)
.cy.get(“div”).should(“be.visible”).and(“contain”, “text”)
.cy.request(...)
to make HTTP requests to your backend endpoints with auth headers. Another alternative is you can build out cy.task(...)
plugins that can be called from any spec file to cover other functionality that can be best handled in a Node server with other libraries such as connecting to an email inbox and finding a matching email or having more control over the responses and polling of certain API calls before returning back some values for the tests to use.
cy.request()
to make HTTP requests to your backend API to set up or tear down data before your test cases run. You usually pass in the endpoint URL, HTTP method such as “GET” or “POST”, headers, and sometimes a request body to send to the backend API. You can then chain this with a .then((response) => { })
to gain access to the network response through properties such as “status” and “body”. An example of making a cy.request()
call is demonstrated here.
cy.request(...)
will fail with a 4xx or 5xx status code during the clean up before a test runs. One scenario where you may choose to ignore the failing status code is when your test makes a GET request to check whether an item still exists and was already deleted. The item may already be cleaned up and the GET request will fail with a 404 not found status code. In this case, you would set another option of failOnStatusCode: false
so your Cypress tests do not fail before even running the test steps.
cy.task()
plugin for it. We create plugin functions in module files and import them in the plugins/index.ts
where we define the task plugins with the arguments we need to run the functions as shown below.
cy.task(“pluginName”, { ...args })
anywhere in your spec files and you can expect the same functionality to happen. Whereas, if you used cy.request()
, you have less reusability unless you wrapped those calls themselves in page objects or helper files to be imported everywhere.
Cypress.env(“apiHost”)
or cy.getCookie(‘auth_token’)
. You pass in things such as the auth token string or backend API host to your plugin function’s argument object in addition to things required for the request body if it needs to talk to your backend API.
cy.server()
and cy.route()
to listen for routes to mock out responses for any state you want. Here’s an example:
cy.server()
, cy.route()
, and cy.wait()
together to listen and wait for network requests to finish before doing next steps. Usually, after loading a page or doing some sort of action on the page, an intuitive visual cue will signal that something is complete or ready for us to assert and act on. For the cases where you don’t have such a visible cue, you can explicitly wait for an API call to finish like this.
window.fetch
with an XHR polyfill and doing some setup and cleanup steps before your tests run as recorded in these issues. There is also an experimentalFetchPolyfill
property as of Cypress 4.9.0 that may work for you, but overall, we are still looking for better methods to handle network stubbing across fetch and XHR usage in our applications without things breaking. As of Cypress 5.1.0, there is a promising new cy.route2()
function (see the Cypress docs) for experimental network stubbing of both XHR and fetch requests, so we plan to upgrade our Cypress version and experiment with it to see if it solves our issues.
support/commands.ts
, you can access the functions like cy.customCommand()
or cy.login()
. Writing up a custom command for logging in looks like this.
open()
for inherited page classes to share and extend from. Derived page classes define their own getter functions for selectors and other helper functions while reusing the base classes’ functionality through calls like super.open()
as shown here.
window.Cypress
check.
window.Cypress
property added to the browser. In your client-side code, you can choose to check if there is no Cypress property on the window object, then carry out the download as usual. But, if it’s being run in a Cypress test, do not actually download the file. We also took advantage of checking the window.Cypress
property for our A/B experiments running in our web app. We did not want to add more flakiness and non-deterministic behavior from A/B experiments potentially showing different experiences to our test users, so we first checked the property is not present before running the experiment logic as highlighted below.
cy.iframe(iframeSelector)
custom command to encapsulate dealing with iframes. Passing in a selector to the iframe will then check the iframe’s body contents until it is no longer empty and then return back the body contents for it to be chained with more Cypress commands as shown below:
index.d.ts
file:
cy.find(...).type(...)
and other alternatives not working, but thankfully we found a workaround by changing the values of the inputs and selects directly with the invoke command i.e. cy.get(selector).invoke(‘val’, ‘some value’)
. You’ll also need ”chromeWebSecurity”: false
in your cypress.json
configuration file to allow you to bypass any cross-origin errors. A sample snippet of its usage with filler selectors is provided below:
Cypress.config(“baseUrl”)
to match those URLs such as https://staging.app.com or https://testing.app.com. This changes up the base URL for all of your cy.visit(...)
calls to append their paths to. There are multiple ways to set this such as setting CYPRESS_BASE_URL=<frontend_url>
before running your Cypress command or setting --config baseUrl=<frontend_url>
.
Cypress.env(“apiHost”)
. These will be used for your cy.request(...)
calls to make HTTP requests to certain paths like “<apiHost>/some/endpoint” or passed through to your cy.task(...)
function calls as another argument property to know which backend to hit. These authenticated calls would also need to know the auth token you most likely are storing in localStorage or a cookie through cy.getCookie(“auth_token”)
. Make sure this auth token is eventually passed in as part of the “Authorization” header or through some other means as part of your request. There are a multitude of ways to set these environment variables such as directly in the cypress.json
file or in --env
command-line options where you can reference them in the Cypress documentation.
fixtures
folder and import them in for you to use based on the “testEnv” value such as cy.fixture(`${testEnv}.json`).then(...)
. However, you cannot type out the JSON files well and there is much more room for mistakes in syntax and in writing out all the properties required per test. The JSON files are also farther away from the test code, so you would have to manage at least two files when editing the tests. Similar maintenance issues would occur if all the environment test data were set in environment variables directly in your cypress.json
and there would be too many to manage across a plethora of tests.
Cypress.env(“testEnv”)
to see which test environment you are running against and use that value to extract out the corresponding environment’s test fixture from the overall test fixture object and use those values in your test. The general idea of the test fixtures object is summarized in the code snippet underneath.
package.json
. You can also set up multiple JSON files for each environment’s configuration, but for simplicity, you will see the commands with the options and values inline.
package.json
scripts that your frontend “baseUrl” ranges from “http://localhost:9001” for when you start up your app locally to the deployed application URL such as “https://staging.app.com”. You can set the backend “apiHost” and “testEnv” variables to help with making requests to a backend endpoint and loading up a specific test fixture object. You may also create special “cicd” commands for when you need to run your tests in a Docker container with the recording key.
cy.get()
, cy.contains()
, .click()
, .type()
, .should(‘be.visible’)
.
cy.request()
, run arbitrary code in a Node server with cy.task()
, and stub out network requests using cy.server()
and cy.route()
. You can even create your own custom command like cy.login()
to help you log in to a user through the API. All these things help to reset a user to the proper starting point before tests run. Wrap these selectors and functions altogether in a file and you’ve created reusable page objects to use in your specs.
npm run cypress:open:staging
in your package.json
will load up the proper environment variable values and run the tests for the environment you chose to run against.
Partner with the email service trusted by developers and marketers for time-savings, scalability, and delivery expertise.