parent
86a49348e4
commit
24634bdeaf
@ -0,0 +1 @@ |
||||
node_modules/ |
@ -0,0 +1,4 @@ |
||||
#!/bin/sh |
||||
. "$(dirname "$0")/_/husky.sh" |
||||
|
||||
npx stop-only --folder cypress/integration |
@ -0,0 +1,8 @@ |
||||
# Prevent push when skipping Cypress tests pt.2 |
||||
|
||||
Make sure your Cypress testing pipeline never let's you push broken code |
||||
when accidentally skipping tests. |
||||
|
||||
Full details are described in the post: |
||||
|
||||
<https://peterbabic.dev/blog/prevent-push-when-skipping-cypress-tests-pt-2> |
@ -0,0 +1 @@ |
||||
{} |
@ -0,0 +1,5 @@ |
||||
{ |
||||
"name": "Using fixtures to represent data", |
||||
"email": "hello@cypress.io", |
||||
"body": "Fixtures are a great way to mock data for responses to routes" |
||||
} |
@ -0,0 +1,145 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
// Welcome to Cypress!
|
||||
//
|
||||
// This spec file contains a variety of sample tests
|
||||
// for a todo list app that are designed to demonstrate
|
||||
// the power of writing tests in Cypress.
|
||||
//
|
||||
// To learn more about how Cypress works and
|
||||
// what makes it such an awesome testing tool,
|
||||
// please read our getting started guide:
|
||||
// https://on.cypress.io/introduction-to-cypress
|
||||
|
||||
describe("example to-do app", () => { |
||||
beforeEach(() => { |
||||
// Cypress starts out with a blank slate for each test
|
||||
// so we must tell it to visit our website with the `cy.visit()` command.
|
||||
// Since we want to visit the same URL at the start of all our tests,
|
||||
// we include it in our beforeEach function so that it runs before each test
|
||||
cy.visit("https://example.cypress.io/todo") |
||||
}) |
||||
|
||||
it("displays two todo items by default", () => { |
||||
// We use the `cy.get()` command to get all elements that match the selector.
|
||||
// Then, we use `should` to assert that there are two matched items,
|
||||
// which are the two default items.
|
||||
cy.get(".todo-list li").should("have.length", 2) |
||||
|
||||
// We can go even further and check that the default todos each contain
|
||||
// the correct text. We use the `first` and `last` functions
|
||||
// to get just the first and last matched elements individually,
|
||||
// and then perform an assertion with `should`.
|
||||
cy.get(".todo-list li") |
||||
.first() |
||||
.should("have.text", "Pay electric bill") |
||||
cy.get(".todo-list li").last().should("have.text", "Walk the dog") |
||||
}) |
||||
|
||||
it("can add new todo items", () => { |
||||
// We'll store our item text in a variable so we can reuse it
|
||||
const newItem = "Feed the cat" |
||||
|
||||
// Let's get the input element and use the `type` command to
|
||||
// input our new list item. After typing the content of our item,
|
||||
// we need to type the enter key as well in order to submit the input.
|
||||
// This input has a data-test attribute so we'll use that to select the
|
||||
// element in accordance with best practices:
|
||||
// https://on.cypress.io/selecting-elements
|
||||
cy.get("[data-test=new-todo]").type(`${newItem}{enter}`) |
||||
|
||||
// Now that we've typed our new item, let's check that it actually was added to the list.
|
||||
// Since it's the newest item, it should exist as the last element in the list.
|
||||
// In addition, with the two default items, we should have a total of 3 elements in the list.
|
||||
// Since assertions yield the element that was asserted on,
|
||||
// we can chain both of these assertions together into a single statement.
|
||||
cy.get(".todo-list li") |
||||
.should("have.length", 3) |
||||
.last() |
||||
.should("have.text", newItem) |
||||
}) |
||||
|
||||
it("can check off an item as completed", () => { |
||||
// In addition to using the `get` command to get an element by selector,
|
||||
// we can also use the `contains` command to get an element by its contents.
|
||||
// However, this will yield the <label>, which is lowest-level element that contains the text.
|
||||
// In order to check the item, we'll find the <input> element for this <label>
|
||||
// by traversing up the dom to the parent element. From there, we can `find`
|
||||
// the child checkbox <input> element and use the `check` command to check it.
|
||||
cy.contains("Pay electric bill") |
||||
.parent() |
||||
.find("input[type=checkbox]") |
||||
.check() |
||||
|
||||
// Now that we've checked the button, we can go ahead and make sure
|
||||
// that the list element is now marked as completed.
|
||||
// Again we'll use `contains` to find the <label> element and then use the `parents` command
|
||||
// to traverse multiple levels up the dom until we find the corresponding <li> element.
|
||||
// Once we get that element, we can assert that it has the completed class.
|
||||
cy.contains("Pay electric bill") |
||||
.parents("li") |
||||
.should("have.class", "completed") |
||||
}) |
||||
|
||||
context("with a checked task", () => { |
||||
beforeEach(() => { |
||||
// We'll take the command we used above to check off an element
|
||||
// Since we want to perform multiple tests that start with checking
|
||||
// one element, we put it in the beforeEach hook
|
||||
// so that it runs at the start of every test.
|
||||
cy.contains("Pay electric bill") |
||||
.parent() |
||||
.find("input[type=checkbox]") |
||||
.check() |
||||
}) |
||||
|
||||
it("can filter for uncompleted tasks", () => { |
||||
// We'll click on the "active" button in order to
|
||||
// display only incomplete items
|
||||
cy.contains("Active").click() |
||||
|
||||
// After filtering, we can assert that there is only the one
|
||||
// incomplete item in the list.
|
||||
cy.get(".todo-list li") |
||||
.should("have.length", 1) |
||||
.first() |
||||
.should("have.text", "Walk the dog") |
||||
|
||||
// For good measure, let's also assert that the task we checked off
|
||||
// does not exist on the page.
|
||||
cy.contains("Pay electric bill").should("not.exist") |
||||
}) |
||||
|
||||
it("can filter for completed tasks", () => { |
||||
// We can perform similar steps as the test above to ensure
|
||||
// that only completed tasks are shown
|
||||
cy.contains("Completed").click() |
||||
|
||||
cy.get(".todo-list li") |
||||
.should("have.length", 1) |
||||
.first() |
||||
.should("have.text", "Pay electric bill") |
||||
|
||||
cy.contains("Walk the dog").should("not.exist") |
||||
}) |
||||
|
||||
it("can delete all completed tasks", () => { |
||||
// First, let's click the "Clear completed" button
|
||||
// `contains` is actually serving two purposes here.
|
||||
// First, it's ensuring that the button exists within the dom.
|
||||
// This button only appears when at least one task is checked
|
||||
// so this command is implicitly verifying that it does exist.
|
||||
// Second, it selects the button so we can click it.
|
||||
cy.contains("Clear completed").click() |
||||
|
||||
// Then we can make sure that there is only one element
|
||||
// in the list and our element does not exist
|
||||
cy.get(".todo-list li") |
||||
.should("have.length", 1) |
||||
.should("not.have.text", "Pay electric bill") |
||||
|
||||
// Finally, make sure that the clear button no longer exists.
|
||||
cy.contains("Clear completed").should("not.exist") |
||||
}) |
||||
}) |
||||
}) |
@ -0,0 +1,317 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
context("Actions", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/commands/actions") |
||||
}) |
||||
|
||||
// https://on.cypress.io/interacting-with-elements
|
||||
|
||||
it(".type() - type into a DOM element", () => { |
||||
// https://on.cypress.io/type
|
||||
cy.get(".action-email") |
||||
.type("fake@email.com") |
||||
.should("have.value", "fake@email.com") |
||||
|
||||
// .type() with special character sequences
|
||||
.type("{leftarrow}{rightarrow}{uparrow}{downarrow}") |
||||
.type("{del}{selectall}{backspace}") |
||||
|
||||
// .type() with key modifiers
|
||||
.type("{alt}{option}") //these are equivalent
|
||||
.type("{ctrl}{control}") //these are equivalent
|
||||
.type("{meta}{command}{cmd}") //these are equivalent
|
||||
.type("{shift}") |
||||
|
||||
// Delay each keypress by 0.1 sec
|
||||
.type("slow.typing@email.com", { delay: 100 }) |
||||
.should("have.value", "slow.typing@email.com") |
||||
|
||||
cy.get(".action-disabled") |
||||
// Ignore error checking prior to type
|
||||
// like whether the input is visible or disabled
|
||||
.type("disabled error checking", { force: true }) |
||||
.should("have.value", "disabled error checking") |
||||
}) |
||||
|
||||
it(".focus() - focus on a DOM element", () => { |
||||
// https://on.cypress.io/focus
|
||||
cy.get(".action-focus") |
||||
.focus() |
||||
.should("have.class", "focus") |
||||
.prev() |
||||
.should("have.attr", "style", "color: orange;") |
||||
}) |
||||
|
||||
it(".blur() - blur off a DOM element", () => { |
||||
// https://on.cypress.io/blur
|
||||
cy.get(".action-blur") |
||||
.type("About to blur") |
||||
.blur() |
||||
.should("have.class", "error") |
||||
.prev() |
||||
.should("have.attr", "style", "color: red;") |
||||
}) |
||||
|
||||
it(".clear() - clears an input or textarea element", () => { |
||||
// https://on.cypress.io/clear
|
||||
cy.get(".action-clear") |
||||
.type("Clear this text") |
||||
.should("have.value", "Clear this text") |
||||
.clear() |
||||
.should("have.value", "") |
||||
}) |
||||
|
||||
it(".submit() - submit a form", () => { |
||||
// https://on.cypress.io/submit
|
||||
cy.get(".action-form").find('[type="text"]').type("HALFOFF") |
||||
|
||||
cy.get(".action-form") |
||||
.submit() |
||||
.next() |
||||
.should("contain", "Your form has been submitted!") |
||||
}) |
||||
|
||||
it(".click() - click on a DOM element", () => { |
||||
// https://on.cypress.io/click
|
||||
cy.get(".action-btn").click() |
||||
|
||||
// You can click on 9 specific positions of an element:
|
||||
// -----------------------------------
|
||||
// | topLeft top topRight |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | left center right |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | bottomLeft bottom bottomRight |
|
||||
// -----------------------------------
|
||||
|
||||
// clicking in the center of the element is the default
|
||||
cy.get("#action-canvas").click() |
||||
|
||||
cy.get("#action-canvas").click("topLeft") |
||||
cy.get("#action-canvas").click("top") |
||||
cy.get("#action-canvas").click("topRight") |
||||
cy.get("#action-canvas").click("left") |
||||
cy.get("#action-canvas").click("right") |
||||
cy.get("#action-canvas").click("bottomLeft") |
||||
cy.get("#action-canvas").click("bottom") |
||||
cy.get("#action-canvas").click("bottomRight") |
||||
|
||||
// .click() accepts an x and y coordinate
|
||||
// that controls where the click occurs :)
|
||||
|
||||
cy.get("#action-canvas") |
||||
.click(80, 75) // click 80px on x coord and 75px on y coord
|
||||
.click(170, 75) |
||||
.click(80, 165) |
||||
.click(100, 185) |
||||
.click(125, 190) |
||||
.click(150, 185) |
||||
.click(170, 165) |
||||
|
||||
// click multiple elements by passing multiple: true
|
||||
cy.get(".action-labels>.label").click({ multiple: true }) |
||||
|
||||
// Ignore error checking prior to clicking
|
||||
cy.get(".action-opacity>.btn").click({ force: true }) |
||||
}) |
||||
|
||||
it(".dblclick() - double click on a DOM element", () => { |
||||
// https://on.cypress.io/dblclick
|
||||
|
||||
// Our app has a listener on 'dblclick' event in our 'scripts.js'
|
||||
// that hides the div and shows an input on double click
|
||||
cy.get(".action-div").dblclick().should("not.be.visible") |
||||
cy.get(".action-input-hidden").should("be.visible") |
||||
}) |
||||
|
||||
it(".rightclick() - right click on a DOM element", () => { |
||||
// https://on.cypress.io/rightclick
|
||||
|
||||
// Our app has a listener on 'contextmenu' event in our 'scripts.js'
|
||||
// that hides the div and shows an input on right click
|
||||
cy.get(".rightclick-action-div").rightclick().should("not.be.visible") |
||||
cy.get(".rightclick-action-input-hidden").should("be.visible") |
||||
}) |
||||
|
||||
it(".check() - check a checkbox or radio element", () => { |
||||
// https://on.cypress.io/check
|
||||
|
||||
// By default, .check() will check all
|
||||
// matching checkbox or radio elements in succession, one after another
|
||||
cy.get('.action-checkboxes [type="checkbox"]') |
||||
.not("[disabled]") |
||||
.check() |
||||
.should("be.checked") |
||||
|
||||
cy.get('.action-radios [type="radio"]') |
||||
.not("[disabled]") |
||||
.check() |
||||
.should("be.checked") |
||||
|
||||
// .check() accepts a value argument
|
||||
cy.get('.action-radios [type="radio"]') |
||||
.check("radio1") |
||||
.should("be.checked") |
||||
|
||||
// .check() accepts an array of values
|
||||
cy.get('.action-multiple-checkboxes [type="checkbox"]') |
||||
.check(["checkbox1", "checkbox2"]) |
||||
.should("be.checked") |
||||
|
||||
// Ignore error checking prior to checking
|
||||
cy.get(".action-checkboxes [disabled]") |
||||
.check({ force: true }) |
||||
.should("be.checked") |
||||
|
||||
cy.get('.action-radios [type="radio"]') |
||||
.check("radio3", { force: true }) |
||||
.should("be.checked") |
||||
}) |
||||
|
||||
it(".uncheck() - uncheck a checkbox element", () => { |
||||
// https://on.cypress.io/uncheck
|
||||
|
||||
// By default, .uncheck() will uncheck all matching
|
||||
// checkbox elements in succession, one after another
|
||||
cy.get('.action-check [type="checkbox"]') |
||||
.not("[disabled]") |
||||
.uncheck() |
||||
.should("not.be.checked") |
||||
|
||||
// .uncheck() accepts a value argument
|
||||
cy.get('.action-check [type="checkbox"]') |
||||
.check("checkbox1") |
||||
.uncheck("checkbox1") |
||||
.should("not.be.checked") |
||||
|
||||
// .uncheck() accepts an array of values
|
||||
cy.get('.action-check [type="checkbox"]') |
||||
.check(["checkbox1", "checkbox3"]) |
||||
.uncheck(["checkbox1", "checkbox3"]) |
||||
.should("not.be.checked") |
||||
|
||||
// Ignore error checking prior to unchecking
|
||||
cy.get(".action-check [disabled]") |
||||
.uncheck({ force: true }) |
||||
.should("not.be.checked") |
||||
}) |
||||
|
||||
it(".select() - select an option in a <select> element", () => { |
||||
// https://on.cypress.io/select
|
||||
|
||||
// at first, no option should be selected
|
||||
cy.get(".action-select").should("have.value", "--Select a fruit--") |
||||
|
||||
// Select option(s) with matching text content
|
||||
cy.get(".action-select").select("apples") |
||||
// confirm the apples were selected
|
||||
// note that each value starts with "fr-" in our HTML
|
||||
cy.get(".action-select").should("have.value", "fr-apples") |
||||
|
||||
cy.get(".action-select-multiple") |
||||
.select(["apples", "oranges", "bananas"]) |
||||
// when getting multiple values, invoke "val" method first
|
||||
.invoke("val") |
||||
.should("deep.equal", ["fr-apples", "fr-oranges", "fr-bananas"]) |
||||
|
||||
// Select option(s) with matching value
|
||||
cy.get(".action-select") |
||||
.select("fr-bananas") |
||||
// can attach an assertion right away to the element
|
||||
.should("have.value", "fr-bananas") |
||||
|
||||
cy.get(".action-select-multiple") |
||||
.select(["fr-apples", "fr-oranges", "fr-bananas"]) |
||||
.invoke("val") |
||||
.should("deep.equal", ["fr-apples", "fr-oranges", "fr-bananas"]) |
||||
|
||||
// assert the selected values include oranges
|
||||
cy.get(".action-select-multiple") |
||||
.invoke("val") |
||||
.should("include", "fr-oranges") |
||||
}) |
||||
|
||||
it(".scrollIntoView() - scroll an element into view", () => { |
||||
// https://on.cypress.io/scrollintoview
|
||||
|
||||
// normally all of these buttons are hidden,
|
||||
// because they're not within
|
||||
// the viewable area of their parent
|
||||
// (we need to scroll to see them)
|
||||
cy.get("#scroll-horizontal button").should("not.be.visible") |
||||
|
||||
// scroll the button into view, as if the user had scrolled
|
||||
cy.get("#scroll-horizontal button") |
||||
.scrollIntoView() |
||||
.should("be.visible") |
||||
|
||||
cy.get("#scroll-vertical button").should("not.be.visible") |
||||
|
||||
// Cypress handles the scroll direction needed
|
||||
cy.get("#scroll-vertical button").scrollIntoView().should("be.visible") |
||||
|
||||
cy.get("#scroll-both button").should("not.be.visible") |
||||
|
||||
// Cypress knows to scroll to the right and down
|
||||
cy.get("#scroll-both button").scrollIntoView().should("be.visible") |
||||
}) |
||||
|
||||
it(".trigger() - trigger an event on a DOM element", () => { |
||||
// https://on.cypress.io/trigger
|
||||
|
||||
// To interact with a range input (slider)
|
||||
// we need to set its value & trigger the
|
||||
// event to signal it changed
|
||||
|
||||
// Here, we invoke jQuery's val() method to set
|
||||
// the value and trigger the 'change' event
|
||||
cy.get(".trigger-input-range") |
||||
.invoke("val", 25) |
||||
.trigger("change") |
||||
.get("input[type=range]") |
||||
.siblings("p") |
||||
.should("have.text", "25") |
||||
}) |
||||
|
||||
it("cy.scrollTo() - scroll the window or element to a position", () => { |
||||
// https://on.cypress.io/scrollto
|
||||
|
||||
// You can scroll to 9 specific positions of an element:
|
||||
// -----------------------------------
|
||||
// | topLeft top topRight |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | left center right |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | bottomLeft bottom bottomRight |
|
||||
// -----------------------------------
|
||||
|
||||
// if you chain .scrollTo() off of cy, we will
|
||||
// scroll the entire window
|
||||
cy.scrollTo("bottom") |
||||
|
||||
cy.get("#scrollable-horizontal").scrollTo("right") |
||||
|
||||
// or you can scroll to a specific coordinate:
|
||||
// (x axis, y axis) in pixels
|
||||
cy.get("#scrollable-vertical").scrollTo(250, 250) |
||||
|
||||
// or you can scroll to a specific percentage
|
||||
// of the (width, height) of the element
|
||||
cy.get("#scrollable-both").scrollTo("75%", "25%") |
||||
|
||||
// control the easing of the scroll (default is 'swing')
|
||||
cy.get("#scrollable-vertical").scrollTo("center", { easing: "linear" }) |
||||
|
||||
// control the duration of the scroll (in ms)
|
||||
cy.get("#scrollable-both").scrollTo("center", { duration: 2000 }) |
||||
}) |
||||
}) |
@ -0,0 +1,43 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
context("Aliasing", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/commands/aliasing") |
||||
}) |
||||
|
||||
it(".as() - alias a DOM element for later use", () => { |
||||
// https://on.cypress.io/as
|
||||
|
||||
// Alias a DOM element for use later
|
||||
// We don't have to traverse to the element
|
||||
// later in our code, we reference it with @
|
||||
|
||||
cy.get(".as-table") |
||||
.find("tbody>tr") |
||||
.first() |
||||
.find("td") |
||||
.first() |
||||
.find("button") |
||||
.as("firstBtn") |
||||
|
||||
// when we reference the alias, we place an
|
||||
// @ in front of its name
|
||||
cy.get("@firstBtn").click() |
||||
|
||||
cy.get("@firstBtn") |
||||
.should("have.class", "btn-success") |
||||
.and("contain", "Changed") |
||||
}) |
||||
|
||||
it(".as() - alias a route for later use", () => { |
||||
// Alias the route to wait for its response
|
||||
cy.intercept("GET", "**/comments/*").as("getComment") |
||||
|
||||
// we have code that gets a comment when
|
||||
// the button is clicked in scripts.js
|
||||
cy.get(".network-btn").click() |
||||
|
||||
// https://on.cypress.io/wait
|
||||
cy.wait("@getComment").its("response.statusCode").should("eq", 200) |
||||
}) |
||||
}) |
@ -0,0 +1,181 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
context("Assertions", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/commands/assertions") |
||||
}) |
||||
|
||||
describe("Implicit Assertions", () => { |
||||
it(".should() - make an assertion about the current subject", () => { |
||||
// https://on.cypress.io/should
|
||||
cy.get(".assertion-table") |
||||
.find("tbody tr:last") |
||||
.should("have.class", "success") |
||||
.find("td") |
||||
.first() |
||||
// checking the text of the <td> element in various ways
|
||||
.should("have.text", "Column content") |
||||
.should("contain", "Column content") |
||||
.should("have.html", "Column content") |
||||
// chai-jquery uses "is()" to check if element matches selector
|
||||
.should("match", "td") |
||||
// to match text content against a regular expression
|
||||
// first need to invoke jQuery method text()
|
||||
// and then match using regular expression
|
||||
.invoke("text") |
||||
.should("match", /column content/i) |
||||
|
||||
// a better way to check element's text content against a regular expression
|
||||
// is to use "cy.contains"
|
||||
// https://on.cypress.io/contains
|
||||
cy.get(".assertion-table") |
||||
.find("tbody tr:last") |
||||
// finds first <td> element with text content matching regular expression
|
||||
.contains("td", /column content/i) |
||||
.should("be.visible") |
||||
|
||||
// for more information about asserting element's text
|
||||
// see https://on.cypress.io/using-cypress-faq#How-do-I-get-an-element’s-text-contents
|
||||
}) |
||||
|
||||
it(".and() - chain multiple assertions together", () => { |
||||
// https://on.cypress.io/and
|
||||
cy.get(".assertions-link") |
||||
.should("have.class", "active") |
||||
.and("have.attr", "href") |
||||
.and("include", "cypress.io") |
||||
}) |
||||
}) |
||||
|
||||
describe("Explicit Assertions", () => { |
||||
// https://on.cypress.io/assertions
|
||||
it("expect - make an assertion about a specified subject", () => { |
||||
// We can use Chai's BDD style assertions
|
||||
expect(true).to.be.true |
||||
const o = { foo: "bar" } |
||||
|
||||
expect(o).to.equal(o) |
||||
expect(o).to.deep.equal({ foo: "bar" }) |
||||
// matching text using regular expression
|
||||
expect("FooBar").to.match(/bar$/i) |
||||
}) |
||||
|
||||
it("pass your own callback function to should()", () => { |
||||
// Pass a function to should that can have any number
|
||||
// of explicit assertions within it.
|
||||
// The ".should(cb)" function will be retried
|
||||
// automatically until it passes all your explicit assertions or times out.
|
||||
cy.get(".assertions-p") |
||||
.find("p") |
||||
.should($p => { |
||||
// https://on.cypress.io/$
|
||||
// return an array of texts from all of the p's
|
||||
// @ts-ignore TS6133 unused variable
|
||||
const texts = $p.map((i, el) => Cypress.$(el).text()) |
||||
|
||||
// jquery map returns jquery object
|
||||
// and .get() convert this to simple array
|
||||
const paragraphs = texts.get() |
||||
|
||||
// array should have length of 3
|
||||
expect(paragraphs, "has 3 paragraphs").to.have.length(3) |
||||
|
||||
// use second argument to expect(...) to provide clear
|
||||
// message with each assertion
|
||||
expect( |
||||
paragraphs, |
||||
"has expected text in each paragraph" |
||||
).to.deep.eq([ |
||||
"Some text from first p", |
||||
"More text from second p", |
||||
"And even more text from third p", |
||||
]) |
||||
}) |
||||
}) |
||||
|
||||
it("finds element by class name regex", () => { |
||||
cy.get(".docs-header") |
||||
.find("div") |
||||
// .should(cb) callback function will be retried
|
||||
.should($div => { |
||||
expect($div).to.have.length(1) |
||||
|
||||
const className = $div[0].className |
||||
|
||||
expect(className).to.match(/heading-/) |
||||
}) |
||||
// .then(cb) callback is not retried,
|
||||
// it either passes or fails
|
||||
.then($div => { |
||||
expect($div, "text content").to.have.text("Introduction") |
||||
}) |
||||
}) |
||||
|
||||
it("can throw any error", () => { |
||||
cy.get(".docs-header") |
||||
.find("div") |
||||
.should($div => { |
||||
if ($div.length !== 1) { |
||||
// you can throw your own errors
|
||||
throw new Error("Did not find 1 element") |
||||
} |
||||
|
||||
const className = $div[0].className |
||||
|
||||
if (!className.match(/heading-/)) { |
||||
throw new Error( |
||||
`Could not find class "heading-" in ${className}` |
||||
) |
||||
} |
||||
}) |
||||
}) |
||||
|
||||
it("matches unknown text between two elements", () => { |
||||
/** |
||||
* Text from the first element. |
||||
* @type {string} |
||||
*/ |
||||
let text |
||||
|
||||
/** |
||||
* Normalizes passed text, |
||||
* useful before comparing text with spaces and different capitalization. |
||||
* @param {string} s Text to normalize |
||||
*/ |
||||
const normalizeText = s => s.replace(/\s/g, "").toLowerCase() |
||||
|
||||
cy.get(".two-elements") |
||||
.find(".first") |
||||
.then($first => { |
||||
// save text from the first element
|
||||
text = normalizeText($first.text()) |
||||
}) |
||||
|
||||
cy.get(".two-elements") |
||||
.find(".second") |
||||
.should($div => { |
||||
// we can massage text before comparing
|
||||
const secondText = normalizeText($div.text()) |
||||
|
||||
expect(secondText, "second text").to.equal(text) |
||||
}) |
||||
}) |
||||
|
||||
it("assert - assert shape of an object", () => { |
||||
const person = { |
||||
name: "Joe", |
||||
age: 20, |
||||
} |
||||
|
||||
assert.isObject(person, "value is object") |
||||
}) |
||||
|
||||
it("retries the should callback until assertions pass", () => { |
||||
cy.get("#random-number").should($div => { |
||||
const n = parseFloat($div.text()) |
||||
|
||||
expect(n).to.be.gte(1).and.be.lte(10) |
||||
}) |
||||
}) |
||||
}) |
||||
}) |
@ -0,0 +1,96 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
context("Connectors", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/commands/connectors") |
||||
}) |
||||
|
||||
it(".each() - iterate over an array of elements", () => { |
||||
// https://on.cypress.io/each
|
||||
cy.get(".connectors-each-ul>li").each(($el, index, $list) => { |
||||
console.log($el, index, $list) |
||||
}) |
||||
}) |
||||
|
||||
it(".its() - get properties on the current subject", () => { |
||||
// https://on.cypress.io/its
|
||||
cy.get(".connectors-its-ul>li") |
||||
// calls the 'length' property yielding that value
|
||||
.its("length") |
||||
.should("be.gt", 2) |
||||
}) |
||||
|
||||
it(".invoke() - invoke a function on the current subject", () => { |
||||
// our div is hidden in our script.js
|
||||
// $('.connectors-div').hide()
|
||||
|
||||
// https://on.cypress.io/invoke
|
||||
cy.get(".connectors-div") |
||||
.should("be.hidden") |
||||
// call the jquery method 'show' on the 'div.container'
|
||||
.invoke("show") |
||||
.should("be.visible") |
||||
}) |
||||
|
||||
it(".spread() - spread an array as individual args to callback function", () => { |
||||
// https://on.cypress.io/spread
|
||||
const arr = ["foo", "bar", "baz"] |
||||
|
||||
cy.wrap(arr).spread((foo, bar, baz) => { |
||||
expect(foo).to.eq("foo") |
||||
expect(bar).to.eq("bar") |
||||
expect(baz).to.eq("baz") |
||||
}) |
||||
}) |
||||
|
||||
describe(".then()", () => { |
||||
it("invokes a callback function with the current subject", () => { |
||||
// https://on.cypress.io/then
|
||||
cy.get(".connectors-list > li").then($lis => { |
||||
expect($lis, "3 items").to.have.length(3) |
||||
expect($lis.eq(0), "first item").to.contain("Walk the dog") |
||||
expect($lis.eq(1), "second item").to.contain("Feed the cat") |
||||
expect($lis.eq(2), "third item").to.contain("Write JavaScript") |
||||
}) |
||||
}) |
||||
|
||||
it("yields the returned value to the next command", () => { |
||||
cy.wrap(1) |
||||
.then(num => { |
||||
expect(num).to.equal(1) |
||||
|
||||
return 2 |
||||
}) |
||||
.then(num => { |
||||
expect(num).to.equal(2) |
||||
}) |
||||
}) |
||||
|
||||
it("yields the original subject without return", () => { |
||||
cy.wrap(1) |
||||
.then(num => { |
||||
expect(num).to.equal(1) |
||||
// note that nothing is returned from this callback
|
||||
}) |
||||
.then(num => { |
||||
// this callback receives the original unchanged value 1
|
||||
expect(num).to.equal(1) |
||||
}) |
||||
}) |
||||
|
||||
it("yields the value yielded by the last Cypress command inside", () => { |
||||
cy.wrap(1) |
||||
.then(num => { |
||||
expect(num).to.equal(1) |
||||
// note how we run a Cypress command
|
||||
// the result yielded by this Cypress command
|
||||
// will be passed to the second ".then"
|
||||
cy.wrap(2) |
||||
}) |
||||
.then(num => { |
||||
// this callback receives the value yielded by "cy.wrap(2)"
|
||||
expect(num).to.equal(2) |
||||
}) |
||||
}) |
||||
}) |
||||
}) |
@ -0,0 +1,79 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
context("Cookies", () => { |
||||
beforeEach(() => { |
||||
Cypress.Cookies.debug(true) |
||||
|
||||
cy.visit("https://example.cypress.io/commands/cookies") |
||||
|
||||
// clear cookies again after visiting to remove
|
||||
// any 3rd party cookies picked up such as cloudflare
|
||||
cy.clearCookies() |
||||
}) |
||||
|
||||
it("cy.getCookie() - get a browser cookie", () => { |
||||
// https://on.cypress.io/getcookie
|
||||
cy.get("#getCookie .set-a-cookie").click() |
||||
|
||||
// cy.getCookie() yields a cookie object
|
||||
cy.getCookie("token").should("have.property", "value", "123ABC") |
||||
}) |
||||
|
||||
it("cy.getCookies() - get browser cookies", () => { |
||||
// https://on.cypress.io/getcookies
|
||||
cy.getCookies().should("be.empty") |
||||
|
||||
cy.get("#getCookies .set-a-cookie").click() |
||||
|
||||
// cy.getCookies() yields an array of cookies
|
||||
cy.getCookies() |
||||
.should("have.length", 1) |
||||
.should(cookies => { |
||||
// each cookie has these properties
|
||||
expect(cookies[0]).to.have.property("name", "token") |
||||
expect(cookies[0]).to.have.property("value", "123ABC") |
||||
expect(cookies[0]).to.have.property("httpOnly", false) |
||||
expect(cookies[0]).to.have.property("secure", false) |
||||
expect(cookies[0]).to.have.property("domain") |
||||
expect(cookies[0]).to.have.property("path") |
||||
}) |
||||
}) |
||||
|
||||
it("cy.setCookie() - set a browser cookie", () => { |
||||
// https://on.cypress.io/setcookie
|
||||
cy.getCookies().should("be.empty") |
||||
|
||||
cy.setCookie("foo", "bar") |
||||
|
||||
// cy.getCookie() yields a cookie object
|
||||
cy.getCookie("foo").should("have.property", "value", "bar") |
||||
}) |
||||
|
||||
it("cy.clearCookie() - clear a browser cookie", () => { |
||||
// https://on.cypress.io/clearcookie
|
||||
cy.getCookie("token").should("be.null") |
||||
|
||||
cy.get("#clearCookie .set-a-cookie").click() |
||||
|
||||
cy.getCookie("token").should("have.property", "value", "123ABC") |
||||
|
||||
// cy.clearCookies() yields null
|
||||
cy.clearCookie("token").should("be.null") |
||||
|
||||
cy.getCookie("token").should("be.null") |
||||
}) |
||||
|
||||
it("cy.clearCookies() - clear browser cookies", () => { |
||||
// https://on.cypress.io/clearcookies
|
||||
cy.getCookies().should("be.empty") |
||||
|
||||
cy.get("#clearCookies .set-a-cookie").click() |
||||
|
||||
cy.getCookies().should("have.length", 1) |
||||
|
||||
// cy.clearCookies() yields null
|
||||
cy.clearCookies() |
||||
|
||||
cy.getCookies().should("be.empty") |
||||
}) |
||||
}) |
@ -0,0 +1,215 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
context("Cypress.Commands", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/cypress-api") |
||||
}) |
||||
|
||||
// https://on.cypress.io/custom-commands
|
||||
|
||||
it(".add() - create a custom command", () => { |
||||
Cypress.Commands.add( |
||||
"console", |
||||
{ |
||||
prevSubject: true, |
||||
}, |
||||
(subject, method) => { |
||||
// the previous subject is automatically received
|
||||
// and the commands arguments are shifted
|
||||
|
||||
// allow us to change the console method used
|
||||
method = method || "log" |
||||
|
||||
// log the subject to the console
|
||||
// @ts-ignore TS7017
|
||||
console[method]("The subject is", subject) |
||||
|
||||
// whatever we return becomes the new subject
|
||||
// we don't want to change the subject so
|
||||
// we return whatever was passed in
|
||||
return subject |
||||
} |
||||
) |
||||
|
||||
// @ts-ignore TS2339
|
||||
cy.get("button") |
||||
.console("info") |
||||
.then($button => { |
||||
// subject is still $button
|
||||
}) |
||||
}) |
||||
}) |
||||
|
||||
context("Cypress.Cookies", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/cypress-api") |
||||
}) |
||||
|
||||
// https://on.cypress.io/cookies
|
||||
it(".debug() - enable or disable debugging", () => { |
||||
Cypress.Cookies.debug(true) |
||||
|
||||
// Cypress will now log in the console when
|
||||
// cookies are set or cleared
|
||||
cy.setCookie("fakeCookie", "123ABC") |
||||
cy.clearCookie("fakeCookie") |
||||
cy.setCookie("fakeCookie", "123ABC") |
||||
cy.clearCookie("fakeCookie") |
||||
cy.setCookie("fakeCookie", "123ABC") |
||||
}) |
||||
|
||||
it(".preserveOnce() - preserve cookies by key", () => { |
||||
// normally cookies are reset after each test
|
||||
cy.getCookie("fakeCookie").should("not.be.ok") |
||||
|
||||
// preserving a cookie will not clear it when
|
||||
// the next test starts
|
||||
cy.setCookie("lastCookie", "789XYZ") |
||||
Cypress.Cookies.preserveOnce("lastCookie") |
||||
}) |
||||
|
||||
it(".defaults() - set defaults for all cookies", () => { |
||||
// now any cookie with the name 'session_id' will
|
||||
// not be cleared before each new test runs
|
||||
Cypress.Cookies.defaults({ |
||||
preserve: "session_id", |
||||
}) |
||||
}) |
||||
}) |
||||
|
||||
context("Cypress.arch", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/cypress-api") |
||||
}) |
||||
|
||||
it("Get CPU architecture name of underlying OS", () => { |
||||
// https://on.cypress.io/arch
|
||||
expect(Cypress.arch).to.exist |
||||
}) |
||||
}) |
||||
|
||||
context("Cypress.config()", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/cypress-api") |
||||
}) |
||||
|
||||
it("Get and set configuration options", () => { |
||||
// https://on.cypress.io/config
|
||||
let myConfig = Cypress.config() |
||||
|
||||
expect(myConfig).to.have.property("animationDistanceThreshold", 5) |
||||
expect(myConfig).to.have.property("baseUrl", null) |
||||
expect(myConfig).to.have.property("defaultCommandTimeout", 4000) |
||||
expect(myConfig).to.have.property("requestTimeout", 5000) |
||||
expect(myConfig).to.have.property("responseTimeout", 30000) |
||||
expect(myConfig).to.have.property("viewportHeight", 660) |
||||
expect(myConfig).to.have.property("viewportWidth", 1000) |
||||
expect(myConfig).to.have.property("pageLoadTimeout", 60000) |
||||
expect(myConfig).to.have.property("waitForAnimations", true) |
||||
|
||||
expect(Cypress.config("pageLoadTimeout")).to.eq(60000) |
||||
|
||||
// this will change the config for the rest of your tests!
|
||||
Cypress.config("pageLoadTimeout", 20000) |
||||
|
||||
expect(Cypress.config("pageLoadTimeout")).to.eq(20000) |
||||
|
||||
Cypress.config("pageLoadTimeout", 60000) |
||||
}) |
||||
}) |
||||
|
||||
context("Cypress.dom", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/cypress-api") |
||||
}) |
||||
|
||||
// https://on.cypress.io/dom
|
||||
it(".isHidden() - determine if a DOM element is hidden", () => { |
||||
let hiddenP = Cypress.$(".dom-p p.hidden").get(0) |
||||
let visibleP = Cypress.$(".dom-p p.visible").get(0) |
||||
|
||||
// our first paragraph has css class 'hidden'
|
||||
expect(Cypress.dom.isHidden(hiddenP)).to.be.true |
||||
expect(Cypress.dom.isHidden(visibleP)).to.be.false |
||||
}) |
||||
}) |
||||
|
||||
context("Cypress.env()", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/cypress-api") |
||||
}) |
||||
|
||||
// We can set environment variables for highly dynamic values
|
||||
|
||||
// https://on.cypress.io/environment-variables
|
||||
it("Get environment variables", () => { |
||||
// https://on.cypress.io/env
|
||||
// set multiple environment variables
|
||||
Cypress.env({ |
||||
host: "veronica.dev.local", |
||||
api_server: "http://localhost:8888/v1/", |
||||
}) |
||||
|
||||
// get environment variable
|
||||
expect(Cypress.env("host")).to.eq("veronica.dev.local") |
||||
|
||||
// set environment variable
|
||||
Cypress.env("api_server", "http://localhost:8888/v2/") |
||||
expect(Cypress.env("api_server")).to.eq("http://localhost:8888/v2/") |
||||
|
||||
// get all environment variable
|
||||
expect(Cypress.env()).to.have.property("host", "veronica.dev.local") |
||||
expect(Cypress.env()).to.have.property( |
||||
"api_server", |
||||
"http://localhost:8888/v2/" |
||||
) |
||||
}) |
||||
}) |
||||
|
||||
context("Cypress.log", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/cypress-api") |
||||
}) |
||||
|
||||
it("Control what is printed to the Command Log", () => { |
||||
// https://on.cypress.io/cypress-log
|
||||
}) |
||||
}) |
||||
|
||||
context("Cypress.platform", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/cypress-api") |
||||
}) |
||||
|
||||
it("Get underlying OS name", () => { |
||||
// https://on.cypress.io/platform
|
||||
expect(Cypress.platform).to.be.exist |
||||
}) |
||||
}) |
||||
|
||||
context("Cypress.version", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/cypress-api") |
||||
}) |
||||
|
||||
it("Get current version of Cypress being run", () => { |
||||
// https://on.cypress.io/version
|
||||
expect(Cypress.version).to.be.exist |
||||
}) |
||||
}) |
||||
|
||||
context("Cypress.spec", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/cypress-api") |
||||
}) |
||||
|
||||
it("Get current spec information", () => { |
||||
// https://on.cypress.io/spec
|
||||
// wrap the object so we can inspect it easily by clicking in the command log
|
||||
cy.wrap(Cypress.spec).should("include.keys", [ |
||||
"name", |
||||
"relative", |
||||
"absolute", |
||||
]) |
||||
}) |
||||
}) |
@ -0,0 +1,92 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
/// JSON fixture file can be loaded directly using
|
||||
// the built-in JavaScript bundler
|
||||
// @ts-ignore
|
||||
const requiredExample = require("../../fixtures/example") |
||||
|
||||
context("Files", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/commands/files") |
||||
}) |
||||
|
||||
beforeEach(() => { |
||||
// load example.json fixture file and store
|
||||
// in the test context object
|
||||
cy.fixture("example.json").as("example") |
||||
}) |
||||
|
||||
it("cy.fixture() - load a fixture", () => { |
||||
// https://on.cypress.io/fixture
|
||||
|
||||
// Instead of writing a response inline you can
|
||||
// use a fixture file's content.
|
||||
|
||||
// when application makes an Ajax request matching "GET **/comments/*"
|
||||
// Cypress will intercept it and reply with the object in `example.json` fixture
|
||||
cy.intercept("GET", "**/comments/*", { fixture: "example.json" }).as( |
||||
"getComment" |
||||
) |
||||
|
||||
// we have code that gets a comment when
|
||||
// the button is clicked in scripts.js
|
||||
cy.get(".fixture-btn").click() |
||||
|
||||
cy.wait("@getComment") |
||||
.its("response.body") |
||||
.should("have.property", "name") |
||||
.and("include", "Using fixtures to represent data") |
||||
}) |
||||
|
||||
it("cy.fixture() or require - load a fixture", function () { |
||||
// we are inside the "function () { ... }"
|
||||
// callback and can use test context object "this"
|
||||
// "this.example" was loaded in "beforeEach" function callback
|
||||
expect(this.example, "fixture in the test context").to.deep.equal( |
||||
requiredExample |
||||
) |
||||
|
||||
// or use "cy.wrap" and "should('deep.equal', ...)" assertion
|
||||
cy.wrap(this.example).should("deep.equal", requiredExample) |
||||
}) |
||||
|
||||
it("cy.readFile() - read file contents", () => { |
||||
// https://on.cypress.io/readfile
|
||||
|
||||
// You can read a file and yield its contents
|
||||
// The filePath is relative to your project's root.
|
||||
cy.readFile("cypress.json").then(json => { |
||||
expect(json).to.be.an("object") |
||||
}) |
||||
}) |
||||
|
||||
it("cy.writeFile() - write to a file", () => { |
||||
// https://on.cypress.io/writefile
|
||||
|
||||
// You can write to a file
|
||||
|
||||
// Use a response from a request to automatically
|
||||
// generate a fixture file for use later
|
||||
cy.request("https://jsonplaceholder.cypress.io/users").then( |
||||
response => { |
||||
cy.writeFile("cypress/fixtures/users.json", response.body) |
||||
} |
||||
) |
||||
|
||||
cy.fixture("users").should(users => { |
||||
expect(users[0].name).to.exist |
||||
}) |
||||
|
||||
// JavaScript arrays and objects are stringified
|
||||
// and formatted into text.
|
||||
cy.writeFile("cypress/fixtures/profile.json", { |
||||
id: 8739, |
||||
name: "Jane", |
||||
email: "jane@example.com", |
||||
}) |
||||
|
||||
cy.fixture("profile").should(profile => { |
||||
expect(profile.name).to.eq("Jane") |
||||
}) |
||||
}) |
||||
}) |
@ -0,0 +1,58 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
context("Local Storage", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/commands/local-storage") |
||||
}) |
||||
// Although local storage is automatically cleared
|
||||
// in between tests to maintain a clean state
|
||||
// sometimes we need to clear the local storage manually
|
||||
|
||||
it("cy.clearLocalStorage() - clear all data in local storage", () => { |
||||
// https://on.cypress.io/clearlocalstorage
|
||||
cy.get(".ls-btn") |
||||
.click() |
||||
.should(() => { |
||||
expect(localStorage.getItem("prop1")).to.eq("red") |
||||
expect(localStorage.getItem("prop2")).to.eq("blue") |
||||
expect(localStorage.getItem("prop3")).to.eq("magenta") |
||||
}) |
||||
|
||||
// clearLocalStorage() yields the localStorage object
|
||||
cy.clearLocalStorage().should(ls => { |
||||
expect(ls.getItem("prop1")).to.be.null |
||||
expect(ls.getItem("prop2")).to.be.null |
||||
expect(ls.getItem("prop3")).to.be.null |
||||
}) |
||||
|
||||
cy.get(".ls-btn") |
||||
.click() |
||||
.should(() => { |
||||
expect(localStorage.getItem("prop1")).to.eq("red") |
||||
expect(localStorage.getItem("prop2")).to.eq("blue") |
||||
expect(localStorage.getItem("prop3")).to.eq("magenta") |
||||
}) |
||||
|
||||
// Clear key matching string in Local Storage
|
||||
cy.clearLocalStorage("prop1").should(ls => { |
||||
expect(ls.getItem("prop1")).to.be.null |
||||
expect(ls.getItem("prop2")).to.eq("blue") |
||||
expect(ls.getItem("prop3")).to.eq("magenta") |
||||
}) |
||||
|
||||
cy.get(".ls-btn") |
||||
.click() |
||||
.should(() => { |
||||
expect(localStorage.getItem("prop1")).to.eq("red") |
||||
expect(localStorage.getItem("prop2")).to.eq("blue") |
||||
expect(localStorage.getItem("prop3")).to.eq("magenta") |
||||
}) |
||||
|
||||
// Clear keys matching regex in Local Storage
|
||||
cy.clearLocalStorage(/prop1|2/).should(ls => { |
||||
expect(ls.getItem("prop1")).to.be.null |
||||
expect(ls.getItem("prop2")).to.be.null |
||||
expect(ls.getItem("prop3")).to.eq("magenta") |
||||
}) |
||||
}) |
||||
}) |
@ -0,0 +1,34 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
context("Location", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/commands/location") |
||||
}) |
||||
|
||||
it("cy.hash() - get the current URL hash", () => { |
||||
// https://on.cypress.io/hash
|
||||
cy.hash().should("be.empty") |
||||
}) |
||||
|
||||
it("cy.location() - get window.location", () => { |
||||
// https://on.cypress.io/location
|
||||
cy.location().should(location => { |
||||
expect(location.hash).to.be.empty |
||||
expect(location.href).to.eq( |
||||
"https://example.cypress.io/commands/location" |
||||
) |
||||
expect(location.host).to.eq("example.cypress.io") |
||||
expect(location.hostname).to.eq("example.cypress.io") |
||||
expect(location.origin).to.eq("https://example.cypress.io") |
||||
expect(location.pathname).to.eq("/commands/location") |
||||
expect(location.port).to.eq("") |
||||
expect(location.protocol).to.eq("https:") |
||||
expect(location.search).to.be.empty |
||||
}) |
||||
}) |
||||
|
||||
it("cy.url() - get the current URL", () => { |
||||
// https://on.cypress.io/url
|
||||
cy.url().should("eq", "https://example.cypress.io/commands/location") |
||||
}) |
||||
}) |
@ -0,0 +1,102 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
context("Misc", () => { |
||||
beforeEach(() => { |
||||
cy.visit("https://example.cypress.io/commands/misc") |
||||
}) |
||||
|
||||
it(".end() - end the command chain", () => { |
||||
// https://on.cypress.io/end
|
||||
|
||||
// cy.end is useful when you want to end a chain of commands
|
||||
// and force Cypress to re-query from the root element
|
||||
cy.get(".misc-table").within(() => { |
||||
// ends the current chain and yields null
|
||||
cy.contains("Cheryl").click().end() |
||||
|
||||
// queries the entire table again
|
||||
cy.contains("Charles").click() |
||||
}) |
||||
}) |
||||
|
||||
it("cy.exec() - execute a system command", () => { |
||||
// execute a system command.
|
||||
// so you can take actions necessary for
|
||||
// your test outside the scope of Cypress.
|
||||
// https://on.cypress.io/exec
|
||||
|
||||
// we can use Cypress.platform string to
|
||||
// select appropriate command
|
||||
// https://on.cypress/io/platform
|
||||
cy.log(`Platform ${Cypress.platform} architecture ${Cypress.arch}`) |
||||
|
||||
// on CircleCI Windows build machines we have a failure to run bash shell
|
||||
// https://github.com/cypress-io/cypress/issues/5169
|
||||
// so skip some of the tests by passing flag "--env circle=true"
|
||||
const isCircleOnWindows = |
||||
Cypress.platform === "win32" && Cypress.env("circle") |
||||
|
||||
if (isCircleOnWindows) { |
||||
cy.log("Skipping test on CircleCI") |
||||
|
||||
return |
||||
} |
||||
|
||||
// cy.exec problem on Shippable CI
|
||||
// https://github.com/cypress-io/cypress/issues/6718
|
||||
const isShippable = |
||||
Cypress.platform === "linux" && Cypress.env("shippable") |
||||
|
||||
if (isShippable) { |
||||
cy.log("Skipping test on ShippableCI") |
||||
|
||||
return |
||||
} |
||||
|
||||
cy.exec("echo Jane Lane").its("stdout").should("contain", "Jane Lane") |
||||
|
||||
if (Cypress.platform === "win32") { |
||||
cy.exec("print cypress.json").its("stderr").should("be.empty") |
||||
} else { |
||||
cy.exec("cat cypress.json").its("stderr").should("be.empty") |
||||
|
||||
cy.exec("pwd").its("code").should("eq", 0) |
||||
} |
||||
}) |
||||
|
||||
it("cy.focused() - get the DOM element that has focus", () => { |
||||
// https://on.cypress.io/focused
|
||||
cy.get(".misc-form").find("#name").click() |
||||
cy.focused().should("have.id", "name") |
||||
|
||||
cy.get(".misc-form").find("#description").click() |
||||
cy.focused().should("have.id", "description") |
||||
}) |
||||
|
||||
context("Cypress.Screenshot", function () { |
||||
it("cy.screenshot() - take a screenshot", () => { |
||||
// https://on.cypress.io/screenshot
|
||||
cy.screenshot("my-image") |
||||
}) |
||||
|
||||
it("Cypress.Screenshot.defaults() - change default config of screenshots", function () { |
||||
Cypress.Screenshot.defaults({ |
||||
blackout: [".foo"], |
||||
capture: "viewport", |
||||
clip: { x: 0, y: 0, width: 200, height: 200 }, |
||||
scale: false, |
||||
disableTimersAndAnimations: true, |
||||
screenshotOnRunFailure: true, |
||||
onBeforeScreenshot() {}, |
||||
onAfterScreenshot() {}, |
||||
}) |
||||
}) |
||||
}) |
||||
|
||||
it("cy.wrap() - wrap an object", () => { |
||||
// https://on.cypress.io/wrap
|
||||
cy.wrap({ foo: "bar" }) |
||||
.should("have.property", "foo") |
||||
.and("include", "bar") |
||||
}) |
||||
}) |
@ -0,0 +1,56 @@ |
||||
/// <reference types="cypress" />
|
||||
|
||||
context( |