{"_id":"56954a97fe18811700c9c020","version":{"_id":"56954a94fe18811700c9bfda","project":"568fde81b700ce0d002f4b43","__v":6,"createdAt":"2016-01-12T18:48:52.007Z","releaseDate":"2016-01-12T18:48:52.007Z","categories":["56954a95fe18811700c9bfdb","56954a95fe18811700c9bfdc","56954a95fe18811700c9bfdd","56954a95fe18811700c9bfde","56954a95fe18811700c9bfdf","56954a95fe18811700c9bfe0","56954a95fe18811700c9bfe1","56954a95fe18811700c9bfe2","56954a95fe18811700c9bfe3","56954a95fe18811700c9bfe4","5695649fdcaf0d1700cb8721","5696c1168560a60d00e2c1d6","56a7a32e79395317007c1ad6","5898fc3eec49fb0f004c2663","589cc675ea37da23004e05e1"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"foo","version_clean":"0.0.0","version":"0.0"},"project":"568fde81b700ce0d002f4b43","category":{"_id":"56954a95fe18811700c9bfdf","pages":["56954a97fe18811700c9c01d","56954a97fe18811700c9c01e","56954a97fe18811700c9c01f","56954a97fe18811700c9c020","56954a97fe18811700c9c021","56954a97fe18811700c9c022","56954a97fe18811700c9c023","56954a97fe18811700c9c024","56954a97fe18811700c9c025","56954a97fe18811700c9c026","56954a97fe18811700c9c027","56954a97fe18811700c9c028","56954a97fe18811700c9c029","5696cda524490c3700170a05","5697efe61c4dc8230054268e","5697efe72cf4060d004eaa75","56993ff47465970d00650b8f","56a7a155dfdabc0d000ae910","56a7a155b5d0920d0051cd81","56a7a1a6cf6d771700baeee3","56a7a1a63d33bc2100793d5d","56a7a23097e8b00d0096d209","56a7a230ea3e3417000df4b1","56a7a25acf6d771700baeee6","56a7a25a03f28c0d00a545bf","56a7a2b83d33bc2100793d60","56a7a2b8b5d0920d0051cd82","56b27fe42db51f0d0044e566"],"project":"568fde81b700ce0d002f4b43","__v":16,"version":"56954a94fe18811700c9bfda","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-01-09T16:40:53.584Z","from_sync":false,"order":4,"slug":"guides","title":"Guides"},"user":"568fffce769f210d0013258f","__v":0,"parentDoc":null,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-01-09T16:41:26.906Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":3,"body":"# Contents\n\n- :fa-angle-right: [Writing an Assertion](#section-writing-an-assertion)\n  - [Implicit Subjects with `cy.should` or `cy.and`](#section-implicit-subjects-with-cy-should-or-cy-and-)\n  - [Explicit Subjects with `expect` and `assert`](#section-explicit-subjects-with-expect-and-assert-)\n- :fa-angle-right: [Available Assertions](#section-available-assertions)\n  - [Chai](#section-chai)\n  - [Chai-jQuery](#section-chai-jquery)\n  - [Chai-Sinon](#section-chai-sinon)\n- :fa-angle-right: [Using Chainers with Implicit Subjects](#section-using-chainers-with-implicit-subjects)\n  - [Assertions that Change the Subject](#section-assertions-that-change-the-subject)\n  - [How do I know which assertions change the subject and which keep it the same?](#section-how-do-i-know-which-assertions-change-the-subject-and-which-keep-it-the-same-)\n- :fa-angle-right: [Negating Assertions](#section-negating-assertions)\n- :fa-angle-right: [Resolving Assertions](#section-resolving-assertions)\n- :fa-angle-right: [Increasing timeouts of Assertions](#section-increasing-timeouts)\n\n***\n\n# Writing an Assertion\n\nThere are two ways to write an assertion in Cypress.\n\n1. **Implicit Subjects:** Using [`cy.should`](https://on.cypress.io/api/should) or [`cy.and`](https://on.cypress.io/api/and)\n2. **Explicit Subjects:** Using `expect`\n\n***\n\n## Implicit Subjects with [`cy.should`](https://on.cypress.io/api/should) or [`cy.and`](https://on.cypress.io/api/and)\n\nUsing [`cy.should`](https://on.cypress.io/api/should) or [`cy.and`](https://on.cypress.io/api/and) commands is the preferred way of making an assertion in Cypress. The subject of the assertion is inferred from the subject of the last Cypress command, which is why this is called an **implicit subject**.\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"// the implicit subject here is the first <tr>\\n// this asserts that the <tr> has an .active class\\ncy.get(\\\"tbody tr:first\\\").should(\\\"have.class\\\", \\\"active\\\")\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\n![implicit_assertion_class_active](https://cloud.githubusercontent.com/assets/1271364/12554600/4cb4115c-c34b-11e5-891c-84ff176ea38f.jpg)\n\n***\n\n## Explicit Subjects with `expect`\n\nUsing `expect` allows you to pass in a specific subject and make an assertion on the specified subject.\n\nThese assertions are more commonly used when writing unit tests, but can also be used when writing integration tests. Cypress comes bundled with some existing tools that handle assertions such as:\n\n* [Chai](https://on.cypress.io/guides/bundled-tools#section-chai)\n* [Chai-jQuery](https://on.cypress.io/guides/bundled-tools#section-chai-jquery)\n* [Chai-Sinon](https://on.cypress.io/guides/bundled-tools#section-sinon-chai)\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"// the explicit subject here is the boolean: true\\nexpect(true).to.be.true\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Check out our example recipes for [unit testing](https://github.com/cypress-io/cypress-example-recipes/blob/master/cypress/integration/unit_test_application_code_spec.js) and [unit testing React components](https://github.com/cypress-io/cypress-example-recipes/blob/master/cypress/integration/unit_test_react_enzyme_spec.js)\",\n  \"title\": \"Unit Testing\"\n}\n[/block]\n\nExplicit assertions are great when you want to perform custom logic prior to making the assertion.\n\nThere is an [open issue](https://github.com/cypress-io/cypress/issues/101) for supporting `assert`.\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy\\n  .get(\\\"p\\\")\\n  .should(function($p){\\n    // return an array of texts from all of the p's\\n    var texts = $p.map(function(i, el){\\n      return cy.$(el).text()\\n    })\\n\\n    // jquery map returns jquery object\\n    // and .get() convert this to simple array\\n    var texts = texts.get()\\n\\n    // array should have length of 3\\n    expect(texts).to.have.length(3)\\n\\n    // set this specific subject\\n    expect(texts).to.deep.eq([\\n      \\\"Some text from first p\\\",\\n      \\\"More text from second p\\\",\\n      \\\"And even more text from third p\\\"\\n    ])\\n})\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\n***\n\n# Available Assertions\n\nAn assertion is comprised of a subject, chainer methods, and an optional value.\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"expect({foo: \\\"bar\\\"}).to.have.property(\\\"foo\\\")\\n           ↲              ↲            ↲\\n        subject        chainers      value\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nThe following chainers are available for your use:\n\n- [Chai](#section-chai)\n- [Chai-jQuery](#section-chai-jquery)\n- [Chai-Sinon](#section-chai-sinon)\n\n***\n\n## Chai\n\n[Chai](http://chaijs.com/) chainers are available for assertions.\n\n| Chainable getters |\n| --- |\n| to |\n| be |\n| been |\n| is |\n| that |\n| which |\n| and |\n| has |\n| have |\n| with |\n| at |\n| of |\n| same |\n\n| Assertion | Example |\n| --- | --- |\n| not | `expect(foo).to.not.equal('bar')` |\n| deep | `expect(foo).to.deep.equal({ bar: 'baz' })` |\n| any | `expect(foo).to.have.any.keys('bar', 'baz')` |\n| all | `expect(foo).to.have.all.keys('bar', 'baz')` |\n| a( *type* ) | `expect('test').to.be.a('string')` |\n| an( *type* ) | `expect(undefined).to.be.an('undefined')` |\n| include( *value* )  | `expect([1,2,3]).to.include(2)` |\n| contain( *value* )  | `expect('foobar').to.contain('foo')` |\n| includes( *value* )  | `expect([1,2,3]).includes(2)` |\n| contains( *value* ) | `expect('foobar').contains('foo')` |\n| ok | `expect(undefined).to.not.be.ok` |\n| true | `expect(true).to.be.true` |\n| false | `expect(false).to.be.false` |\n| null | `expect(null).to.be.null` |\n| undefined | `expect(undefined).to.be.undefined` |\n| exist | `expect(foo).to.exist` |\n| empty | `expect([]).to.be.empty` |\n| arguments | `expect(arguments).to.be.arguments` |\n| equal( *value* )  | `expect(42).to.equal(42)` |\n| equals( *value* )  | `expect(42).equals(42)` |\n| eq( *value* )  | `expect(42).to.eq(42)` |\n| deep.equal( *value* ) | `expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' })` |\n| eql( *value* )  | `expect({ foo: 'bar' }).to.eql({ foo: 'bar' })` |\n| eqls( *value* )  | `expect([ 1, 2, 3 ]).eqls([ 1, 2, 3 ])` |\n| above( *value* )  | `expect(10).to.be.above(5)` |\n| gt( *value* )  | `expect(10).to.be.gt(5)` |\n| greaterThan( *value* ) | `expect(10).to.be.greaterThan(5)` |\n| least( *value* ) | `expect(10).to.be.at.least(10)` |\n| gte( *value* ) | `expect(10).to.be.gte(10)` |\n| below( *value* ) | `expect('foo').to.have.length.below(4)` |\n| lt( *value* )  | `expect(3).to.be.ls(4)` |\n| lessThan( *value* ) | `expect(5).to.be.lessThan(10)` |\n| most( *value* ) | `expect('foo').to.have.length.of.at.most(4)` |\n| lte( *value* ) | `expect(5).to.be.lte(5)` |\n| within( *start*, *finish* ) | `expect(7).to.be.within(5,10)` |\n| instanceof( *constructor* )| `expect([ 1, 2, 3 ]).to.be.instanceof(Array)` |\n| instanceOf( *constructor* ) | `expect([ 1, 2, 3 ]).to.be.instanceOf(Array)` |\n| property( *name*, *[value]* ) | `expect(obj).to.have.property('foo')` |\n| deep.property( *name*, *[value]* ) | `expect(deepObj).to.have.deep.property('teas[1]', 'matcha')` |\n| ownProperty( *name* )  | `expect('test').to.have.ownProperty('length')` |\n| haveOwnProperty( *name* ) | `expect('test').to.haveOwnProperty('length')` |\n| length( *value* )  | `expect('foo').to.have.length.above(2)` |\n| lengthOf( *value* ) | `expect('foo').to.have.lengthOf(3)` |\n| match( *regexp* ) | `expect('foobar').to.match(/^foo/)` |\n| string( *string* ) | `expect('foobar').to.have.string('bar')` |\n| keys( *key1*, *[key2]*, *[...]* ) | `expect({ foo: 1, bar: 2 }).to.have.key('foo')` |\n| key( *key1*, *[key2]*, *[...]* ) | `expect({ foo: 1, bar: 2 }).to.have.any.keys('foo')` |\n| throw( *constructor* ) | `expect(fn).to.throw(Error)` |\n| throws( *constructor* ) | `expect(fn).throws(ReferenceError, /bad function/)` |\n| respondTo( *method* ) | `expect(obj).to.respondTo('bar')` |\n| itself | `expect(Foo).itself.to.respondTo('bar')` |\n| satisfy( *method* ) | `expect(1).to.satisfy(function(num) { return num > 0; })` |\n| closeTo( *expected*, *delta*) | `expect(1.5).to.be.closeTo(1, 0.5)` |\n| members( *set* ) | `expect([1, 2, 3]).to.include.members([3, 2])` |\n| change( *function* )  | `expect(fn).to.change(obj, 'val')` |\n| changes( *function* ) | `expect(fn).changes(obj, 'val')` |\n| increase( *function* )  | `expect(fn).to.increase(obj, 'val')` |\n| increases( *function* ) | `expect(fn).increases(obj, 'val')` |\n| decrease( *function* )  | `expect(fn).to.decrease(obj, 'val')` |\n| decreases( *function* ) | `expect(fn).decreases(obj, 'val')` |\n\n***\n\n## Chai-jQuery\n\n[Chai-jQuery](https://github.com/chaijs/chai-jquery) chainers are available when asserting about a DOM object.\n\n| Chainers | Assertion |\n| --- | --- |\n| attr( *name*, *[value]*) | `expect($('body')).to.have.attr('foo', 'bar')` |\n| prop( *name*, *[value]*) | `expect($('body')).to.have.prop('disabled', false)` |\n| css( *name*, *[value]*) | `expect($('body')).to.have.css('background-color', 'rgb(0, 0, 0)')` |\n| data( *name*, *[value]*) | `expect($('body')).to.have.data('foo', 'bar')` |\n| class( *className* ) | `expect($('body')).to.have.class('foo')` |\n| id( *id* ) | `expect($('body')).to.have.id('foo')` |\n| html( *html*)  | `expect($('#title')).to.have.html('Chai Tea')` |\n| text( *text* ) | `expect($('#title')).to.have.text('Chai Tea')` |\n| value( *value* ) | `expect($('.year')).to.have.value('2012')` |\n| visible | `expect($('.year')).to.be.visible` |\n| hidden | `expect($('.year')).to.be.hidden` |\n| selected | `expect($('option')).not.to.be.selected` |\n| checked | `expect($('input')).not.to.be.checked` |\n| enabled | `expect($('enabled')).to.be.enabled` |\n| disabled | `expect($('input')).not.to.be.disabled` |\n| empty | `expect($('body')).not.to.be.empty` |\n| exist | `expect($('#nonexistent')).not.to.exist` |\n| match( *selector* ) | `expect($('#empty')).to.match(':empty')` |\n| contain( *text* ) | `expect($('#content')).to.contain('text')` |\n| descendents( *selector* ) | `expect($('#content')).to.have.descendants('div')` |\n\nYou will commonly use these chainers after using DOM commands like: [`cy.get`](https://on.cypress.io/api/get), [`cy.contains`](https://on.cypress.io/api/contains), etc.\n\n***\n\n## Chai-Sinon\n\nAll Sinon assertions are available in [Sinon–Chai](https://github.com/domenic/sinon-chai).\n\n| Sinon.JS property/method | Assertion |\n| -- | -- |\n| called |  `expect(spy).to.be.called` |\n| callCount | `expect(spy).to.have.callCount(n)` |\n| calledOnce |  `expect(spy).to.be.calledOnce` |\n| calledTwice | `expect(spy).to.be.calledTwice` |\n| calledThrice |  `expect(spy).to.be.calledThrice` |\n| calledBefore |  `expect(spy1).to.be.calledBefore(spy2)` |\n| calledAfter | `expect(spy1).to.be.calledAfter(spy2)` |\n| calledWithNew | `expect(spy).to.be.calledWithNew` |\n| alwaysCalledWithNew | `expect(spy).to.always.be.calledWithNew` |\n| calledOn |  `expect(spy).to.be.calledOn(context)` |\n| alwaysCalledOn |  `expect(spy).to.always.be.calledOn(context)` |\n| calledWith |  `expect(spy).to.be.calledWith(...args)` |\n| alwaysCalledWith |  `expect(spy).to.always.be.calledWith(...args)` |\n| calledWithExactly | `expect(spy).to.be.calledWithExactly(...args)` |\n| alwaysCalledWithExactly | `expect(spy).to.always.be.calledWithExactly(...args)` |\n| calledWithMatch | `expect(spy).to.be.calledWithMatch(...args)` |\n| alwaysCalledWithMatch | `expect(spy).to.always.be.calledWithMatch(...args)` |\n| returned |  `expect(spy).to.have.returned(returnVal)` |\n| alwaysReturned |  `expect(spy).to.have.always.returned(returnVal)` |\n| threw | `expect(spy).to.have.thrown(errorObjOrErrorTypeStringOrNothing)` |\n| alwaysThrew | `expect(spy).to.have.always.thrown(errorObjOrErrorTypeStringOrNothing)` |\n\n***\n\n# Using Chainers with Implicit Subjects\n\nWhen utilizing [`cy.should`](https://on.cypress.io/api/should) or [`cy.and`](https://on.cypress.io/api/should), instead of writing chainers as properties and methods, they are instead transformed into a string argument.\n\nIf we convert the previous example to use [`cy.should`](https://on.cypress.io/api/should), it would look like:\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy.wrap({foo: \\\"bar\\\"}).should(\\\"have.property\\\", \\\"foo\\\")\\n           ↲                      ↲            ↲\\n        subject                chainers       value\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nThe chainers are shifted and become the first argument to [`cy.should`](https://on.cypress.io/api/should), with values simply being passed in as additional arguments.\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"// we can additionally continue to chain and add\\n// multiple assertions about our <button> subject\\ncy.get(\\\"button\\\").should(\\\"have.class\\\", \\\"active\\\").and(\\\"be.visible\\\")\\n          ↲                  ↲          ↲             ↲\\n        subject           chainers     value         chainers\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nIf we converted the above example to use an explicit subject, this is what it would look like:\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy.get(\\\"button\\\").should(function($button){\\n  expect($button).to.have.class(\\\"active\\\")\\n  expect($button).to.be.visible\\n})\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nThis example above may be more familiar to you if you've written tests in JavaScript before.\n\nIf you look closely, you'll see that we've passed a callback function to the [`cy.should`](https://on.cypress.io/api/should) method. This allows us to write expectations inside of that callback function, yet still receive all of the wonderful benefits of [`cy.should`](https://on.cypress.io/api/should).\n\nRead about [resolving assertions](https://on.cypress.io/guides/making-assertions#section-resolving-assertions) below to learn how [`cy.should`](https://on.cypress.io/api/should) works under the hood.\n\n***\n\n## Assertions that change the subject\n\nSometimes using a specific chainer will automatically change the assertion subject.\n\nFor instance in `chai`, the method [`have.property(\"...\")`](http://chaijs.com/api/bdd/) will automatically change the subject.\n\nAdditionally in [`Chai-jQuery`](https://github.com/chaijs/chai-jquery#attrname-value), the methods: `attr`, `prop`, `css`, and `data` also change the subject.\n\nThis allows you to utilize other `chainer` methods such as `match` when making assertions about values.\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"// in this example our subject changed to the string 'sans-serif' because\\n// have.css(\\\"font-family\\\") returned a string instead of the <body> element\\ncy\\n  // subject is <body>\\n  .get(\\\"body\\\")\\n\\n  // subject changes to the string return value of 'font-family'\\n  .should(\\\"have.css\\\", \\\"font-family\\\")\\n\\n  // use match to assert the string matches a regular expression\\n  .and(\\\"match\\\", /sans-serif/)\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"// in this example our subject changed to the string '/users' because\\n// have.attr, href, /users returned a string instead of the <a> element\\ncy\\n  // subject is <a>\\n  .get(\\\"a\\\")\\n\\n  // subject changes to the string 'users'\\n  .should(\\\"have.attr\\\", \\\"href\\\", \\\"/users\\\")\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\n***\n\n## How do I know which assertions change the subject and which keep it the same?\n\nThe chainers that come from [Chai](https://on.cypress.io/guides/bundled-tools#section-chai) or [Chai-jQuery](https://on.cypress.io/guides/bundled-tools#section-chai-jquery) will always document what they return.\n\nAlternatively, it is very easy to use Cypress itself to figure this out.\n\nYou can [read more about debugging assertions](https://on.cypress.io/guides/making-assertions#sections-debugging-assertions) here.\n\n***\n\n# Negating assertions\n\nEvery assertion can be chained with `.not` to assert the opposite behavior on a subject.\n\n**Negating Assertion Examples**\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy.get(\\\"button.disabled\\\").should(\\\"be.disabled\\\")             // assertion\\ncy.get(\\\"button.active\\\").should(\\\"not.be.disabled\\\")           // negating assertion\\n\\ncy.title().should(\\\"eq\\\", \\\"My Awesome App\\\")                   // assertion\\ncy.title().should(\\\"not.eq\\\", \\\"My Not So Awesome App\\\")        // negating assertion\\n\\ncy.get(\\\"a\\\").should(\\\"have.attr\\\", \\\"popover\\\", \\\"Help\\\")          // assertion\\ncy.get(\\\"a\\\").should(\\\"not.have.attr\\\", \\\"popover\\\", \\\"I'm lost\\\")  // negating assertion\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\n***\n\n# Resolving Assertions\n\nKnowing when and how to resolve assertions is can be challenging, made even more difficult by modern JavaScript frameworks. Yet accurately resolving assertions is the key for preventing flaky and brittle tests.\n\nCypress's API is built to consistently pass or fail every time. As part of this strategy, Cypress will automatically look downstream at assertions and modify its behavior based on upcoming assertions.\n\nInternally, Cypress will retry commands which are associated to assertions, and will not continue until **all** assertions pass. Using assertions as guards enables you to specify conditions that must be resolved prior to moving on.\n\nWhat conditions should you specify? Anything that guarantees your app is in the correct state.\n\n**Here are some scenarios of using assertions as guards:**\n\n* Clicking an `<a>` then verifying the url is correct after you expect your server to redirect.\n* Focusing, then blurring on an `<input>` and expecting an error message with a specific class to be visible.\n* Clicking a `<button>` and waiting for a modal to animate in.\n* Typing into a `<form>` and verifying an element should not exist or not be visible.\n\nEvery command that comes before a [`cy.should`](https://on.cypress.io/api/should) will not resolve until **all** of its associated assertions pass. This enables you to accurately test the following situation:\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"<!-- Our App Code -->\\n<form>\\n  <input name=\\\"name\\\" placeholder=\\\"What is your name?\\\" />\\n  <span id=\\\"error\\\" style=\\\"display: none;\\\"></span>\\n</form>\\n\",\n            \"language\": \"html\"\n        }\n    ]\n}\n[/block]\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"// Our App Code\\nfunction waitRandomlyThen(fn){\\n  setTimeout(fn, Math.random() * 3000)\\n}\\n\\n$(\\\"form\\\").submit(function(e){\\n  e.preventDefault()\\n\\n  waitRandomlyThen(function(){\\n    $(\\\"#error\\\").show()\\n  })\\n\\n  waitRandomlyThen(function(){\\n    $(\\\"#error\\\").addClass(\\\"alert-danger\\\")\\n  })\\n\\n  waitRandomlyThen(function(){\\n    $(\\\"#error\\\").html(\\\"Your <strong>name</strong> is required.\\\")\\n  })\\n})\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nThe above app code could can be tested with the following assertions:\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy\\n  .get(\\\"form\\\").submit()\\n  .get(\\\"#error\\\")\\n    .should(\\\"be.visible\\\")\\n    .and(\\\"have.class\\\", \\\"alert-danger\\\")\\n    .and(\\\"contain\\\", \\\"Your name is required.\\\")\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nOur tests' code is insulated from flaky failures because it is not coupled to any specific timing mechanism. If you look closely, our application code is written in such a way that introduces random wait times - yet Cypress will pass 100% of the time, without any explicit `wait` calls. The moment all 3 of the assertions pass, Cypress will resolve.\n\n![assertions](https://cloud.githubusercontent.com/assets/1268976/10004440/b1c53294-607f-11e5-8d7d-3f5694a1fb1a.gif)\n\nIn modern JavaScript frameworks, and in many common web-based actions, there is usually an *indeterminate* amount of time between an action and a side effect such as:\n\n* Network Requests\n* Redirects\n* Form Submissions\n* AJAX Requests\n* Websockets\n* Page Navigation\n* setTimeout's\n* DOM Events\n\nCypress makes it easy to test and make assertions about all of these.\n\n***\n\n## Increasing timeouts\n\nYou have two ways of increasing the amount of time Cypress waits for assertions to pass.\n\n1. Change the [`defaultCommandTimeout`](https://on.cypress.io/guides/configuration#section-timeouts) globally\n2. Override the timeout option on a previous command before the assertion command.\n\nOverriding the timeout option on a specific command looks like this:\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy\\n  .find(\\\"input\\\", {timeout: 10000}) // <-- wait up to 10 seconds for this 'input' to be found\\n    .should(\\\"have.value\\\", \\\"foo\\\")   // <-- and to have the value 'foo'\\n    .and(\\\"have.class\\\", \\\"radio\\\")    // <-- and to have the class 'radio'\\n\\n  .parents(\\\"#foo\\\", {timeout: 2000}) // <--\\n    .should(\\\"not.exist\\\")            // <-- wait up to 2 seconds for this element NOT to be found\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nIt's important to note that timeouts will automatically flow down to their cooresponding assertions.\n\n**In the example we wait up to a total of 10 seconds to:**\n\n1. find the `<input>`\n2. ensure it has a value of `foo`\n3. ensure it has a class of `radio`\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy.find(\\\"input\\\", {timeout: 10000}).should(\\\"have.value\\\", \\\"foo\\\").and(\\\"have.class\\\", \\\"radio\\\")\\n                         ↲\\n      // adding the timeout here will automatically\\n      // flow down to the assertions, and they will\\n      // be retried for up to 10 seconds\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"Assuming you have two assertions, if one passes, and one fails, Cypress will continue to retry until they **both** pass. If Cypress eventually times out you'll get a visual indicator in your Command Log to know which specific assertion failed.\"\n}\n[/block]","excerpt":"Assertions verify an expectation.","slug":"making-assertions","type":"basic","title":"Making Assertions"}

Making Assertions

Assertions verify an expectation.

# Contents - :fa-angle-right: [Writing an Assertion](#section-writing-an-assertion) - [Implicit Subjects with `cy.should` or `cy.and`](#section-implicit-subjects-with-cy-should-or-cy-and-) - [Explicit Subjects with `expect` and `assert`](#section-explicit-subjects-with-expect-and-assert-) - :fa-angle-right: [Available Assertions](#section-available-assertions) - [Chai](#section-chai) - [Chai-jQuery](#section-chai-jquery) - [Chai-Sinon](#section-chai-sinon) - :fa-angle-right: [Using Chainers with Implicit Subjects](#section-using-chainers-with-implicit-subjects) - [Assertions that Change the Subject](#section-assertions-that-change-the-subject) - [How do I know which assertions change the subject and which keep it the same?](#section-how-do-i-know-which-assertions-change-the-subject-and-which-keep-it-the-same-) - :fa-angle-right: [Negating Assertions](#section-negating-assertions) - :fa-angle-right: [Resolving Assertions](#section-resolving-assertions) - :fa-angle-right: [Increasing timeouts of Assertions](#section-increasing-timeouts) *** # Writing an Assertion There are two ways to write an assertion in Cypress. 1. **Implicit Subjects:** Using [`cy.should`](https://on.cypress.io/api/should) or [`cy.and`](https://on.cypress.io/api/and) 2. **Explicit Subjects:** Using `expect` *** ## Implicit Subjects with [`cy.should`](https://on.cypress.io/api/should) or [`cy.and`](https://on.cypress.io/api/and) Using [`cy.should`](https://on.cypress.io/api/should) or [`cy.and`](https://on.cypress.io/api/and) commands is the preferred way of making an assertion in Cypress. The subject of the assertion is inferred from the subject of the last Cypress command, which is why this is called an **implicit subject**. [block:code] { "codes": [ { "code": "// the implicit subject here is the first <tr>\n// this asserts that the <tr> has an .active class\ncy.get(\"tbody tr:first\").should(\"have.class\", \"active\")\n", "language": "javascript" } ] } [/block] ![implicit_assertion_class_active](https://cloud.githubusercontent.com/assets/1271364/12554600/4cb4115c-c34b-11e5-891c-84ff176ea38f.jpg) *** ## Explicit Subjects with `expect` Using `expect` allows you to pass in a specific subject and make an assertion on the specified subject. These assertions are more commonly used when writing unit tests, but can also be used when writing integration tests. Cypress comes bundled with some existing tools that handle assertions such as: * [Chai](https://on.cypress.io/guides/bundled-tools#section-chai) * [Chai-jQuery](https://on.cypress.io/guides/bundled-tools#section-chai-jquery) * [Chai-Sinon](https://on.cypress.io/guides/bundled-tools#section-sinon-chai) [block:code] { "codes": [ { "code": "// the explicit subject here is the boolean: true\nexpect(true).to.be.true\n", "language": "javascript" } ] } [/block] [block:callout] { "type": "info", "body": "Check out our example recipes for [unit testing](https://github.com/cypress-io/cypress-example-recipes/blob/master/cypress/integration/unit_test_application_code_spec.js) and [unit testing React components](https://github.com/cypress-io/cypress-example-recipes/blob/master/cypress/integration/unit_test_react_enzyme_spec.js)", "title": "Unit Testing" } [/block] Explicit assertions are great when you want to perform custom logic prior to making the assertion. There is an [open issue](https://github.com/cypress-io/cypress/issues/101) for supporting `assert`. [block:code] { "codes": [ { "code": "cy\n .get(\"p\")\n .should(function($p){\n // return an array of texts from all of the p's\n var texts = $p.map(function(i, el){\n return cy.$(el).text()\n })\n\n // jquery map returns jquery object\n // and .get() convert this to simple array\n var texts = texts.get()\n\n // array should have length of 3\n expect(texts).to.have.length(3)\n\n // set this specific subject\n expect(texts).to.deep.eq([\n \"Some text from first p\",\n \"More text from second p\",\n \"And even more text from third p\"\n ])\n})\n", "language": "javascript" } ] } [/block] *** # Available Assertions An assertion is comprised of a subject, chainer methods, and an optional value. [block:code] { "codes": [ { "code": "expect({foo: \"bar\"}).to.have.property(\"foo\")\n ↲ ↲ ↲\n subject chainers value\n", "language": "javascript" } ] } [/block] The following chainers are available for your use: - [Chai](#section-chai) - [Chai-jQuery](#section-chai-jquery) - [Chai-Sinon](#section-chai-sinon) *** ## Chai [Chai](http://chaijs.com/) chainers are available for assertions. | Chainable getters | | --- | | to | | be | | been | | is | | that | | which | | and | | has | | have | | with | | at | | of | | same | | Assertion | Example | | --- | --- | | not | `expect(foo).to.not.equal('bar')` | | deep | `expect(foo).to.deep.equal({ bar: 'baz' })` | | any | `expect(foo).to.have.any.keys('bar', 'baz')` | | all | `expect(foo).to.have.all.keys('bar', 'baz')` | | a( *type* ) | `expect('test').to.be.a('string')` | | an( *type* ) | `expect(undefined).to.be.an('undefined')` | | include( *value* ) | `expect([1,2,3]).to.include(2)` | | contain( *value* ) | `expect('foobar').to.contain('foo')` | | includes( *value* ) | `expect([1,2,3]).includes(2)` | | contains( *value* ) | `expect('foobar').contains('foo')` | | ok | `expect(undefined).to.not.be.ok` | | true | `expect(true).to.be.true` | | false | `expect(false).to.be.false` | | null | `expect(null).to.be.null` | | undefined | `expect(undefined).to.be.undefined` | | exist | `expect(foo).to.exist` | | empty | `expect([]).to.be.empty` | | arguments | `expect(arguments).to.be.arguments` | | equal( *value* ) | `expect(42).to.equal(42)` | | equals( *value* ) | `expect(42).equals(42)` | | eq( *value* ) | `expect(42).to.eq(42)` | | deep.equal( *value* ) | `expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' })` | | eql( *value* ) | `expect({ foo: 'bar' }).to.eql({ foo: 'bar' })` | | eqls( *value* ) | `expect([ 1, 2, 3 ]).eqls([ 1, 2, 3 ])` | | above( *value* ) | `expect(10).to.be.above(5)` | | gt( *value* ) | `expect(10).to.be.gt(5)` | | greaterThan( *value* ) | `expect(10).to.be.greaterThan(5)` | | least( *value* ) | `expect(10).to.be.at.least(10)` | | gte( *value* ) | `expect(10).to.be.gte(10)` | | below( *value* ) | `expect('foo').to.have.length.below(4)` | | lt( *value* ) | `expect(3).to.be.ls(4)` | | lessThan( *value* ) | `expect(5).to.be.lessThan(10)` | | most( *value* ) | `expect('foo').to.have.length.of.at.most(4)` | | lte( *value* ) | `expect(5).to.be.lte(5)` | | within( *start*, *finish* ) | `expect(7).to.be.within(5,10)` | | instanceof( *constructor* )| `expect([ 1, 2, 3 ]).to.be.instanceof(Array)` | | instanceOf( *constructor* ) | `expect([ 1, 2, 3 ]).to.be.instanceOf(Array)` | | property( *name*, *[value]* ) | `expect(obj).to.have.property('foo')` | | deep.property( *name*, *[value]* ) | `expect(deepObj).to.have.deep.property('teas[1]', 'matcha')` | | ownProperty( *name* ) | `expect('test').to.have.ownProperty('length')` | | haveOwnProperty( *name* ) | `expect('test').to.haveOwnProperty('length')` | | length( *value* ) | `expect('foo').to.have.length.above(2)` | | lengthOf( *value* ) | `expect('foo').to.have.lengthOf(3)` | | match( *regexp* ) | `expect('foobar').to.match(/^foo/)` | | string( *string* ) | `expect('foobar').to.have.string('bar')` | | keys( *key1*, *[key2]*, *[...]* ) | `expect({ foo: 1, bar: 2 }).to.have.key('foo')` | | key( *key1*, *[key2]*, *[...]* ) | `expect({ foo: 1, bar: 2 }).to.have.any.keys('foo')` | | throw( *constructor* ) | `expect(fn).to.throw(Error)` | | throws( *constructor* ) | `expect(fn).throws(ReferenceError, /bad function/)` | | respondTo( *method* ) | `expect(obj).to.respondTo('bar')` | | itself | `expect(Foo).itself.to.respondTo('bar')` | | satisfy( *method* ) | `expect(1).to.satisfy(function(num) { return num > 0; })` | | closeTo( *expected*, *delta*) | `expect(1.5).to.be.closeTo(1, 0.5)` | | members( *set* ) | `expect([1, 2, 3]).to.include.members([3, 2])` | | change( *function* ) | `expect(fn).to.change(obj, 'val')` | | changes( *function* ) | `expect(fn).changes(obj, 'val')` | | increase( *function* ) | `expect(fn).to.increase(obj, 'val')` | | increases( *function* ) | `expect(fn).increases(obj, 'val')` | | decrease( *function* ) | `expect(fn).to.decrease(obj, 'val')` | | decreases( *function* ) | `expect(fn).decreases(obj, 'val')` | *** ## Chai-jQuery [Chai-jQuery](https://github.com/chaijs/chai-jquery) chainers are available when asserting about a DOM object. | Chainers | Assertion | | --- | --- | | attr( *name*, *[value]*) | `expect($('body')).to.have.attr('foo', 'bar')` | | prop( *name*, *[value]*) | `expect($('body')).to.have.prop('disabled', false)` | | css( *name*, *[value]*) | `expect($('body')).to.have.css('background-color', 'rgb(0, 0, 0)')` | | data( *name*, *[value]*) | `expect($('body')).to.have.data('foo', 'bar')` | | class( *className* ) | `expect($('body')).to.have.class('foo')` | | id( *id* ) | `expect($('body')).to.have.id('foo')` | | html( *html*) | `expect($('#title')).to.have.html('Chai Tea')` | | text( *text* ) | `expect($('#title')).to.have.text('Chai Tea')` | | value( *value* ) | `expect($('.year')).to.have.value('2012')` | | visible | `expect($('.year')).to.be.visible` | | hidden | `expect($('.year')).to.be.hidden` | | selected | `expect($('option')).not.to.be.selected` | | checked | `expect($('input')).not.to.be.checked` | | enabled | `expect($('enabled')).to.be.enabled` | | disabled | `expect($('input')).not.to.be.disabled` | | empty | `expect($('body')).not.to.be.empty` | | exist | `expect($('#nonexistent')).not.to.exist` | | match( *selector* ) | `expect($('#empty')).to.match(':empty')` | | contain( *text* ) | `expect($('#content')).to.contain('text')` | | descendents( *selector* ) | `expect($('#content')).to.have.descendants('div')` | You will commonly use these chainers after using DOM commands like: [`cy.get`](https://on.cypress.io/api/get), [`cy.contains`](https://on.cypress.io/api/contains), etc. *** ## Chai-Sinon All Sinon assertions are available in [Sinon–Chai](https://github.com/domenic/sinon-chai). | Sinon.JS property/method | Assertion | | -- | -- | | called | `expect(spy).to.be.called` | | callCount | `expect(spy).to.have.callCount(n)` | | calledOnce | `expect(spy).to.be.calledOnce` | | calledTwice | `expect(spy).to.be.calledTwice` | | calledThrice | `expect(spy).to.be.calledThrice` | | calledBefore | `expect(spy1).to.be.calledBefore(spy2)` | | calledAfter | `expect(spy1).to.be.calledAfter(spy2)` | | calledWithNew | `expect(spy).to.be.calledWithNew` | | alwaysCalledWithNew | `expect(spy).to.always.be.calledWithNew` | | calledOn | `expect(spy).to.be.calledOn(context)` | | alwaysCalledOn | `expect(spy).to.always.be.calledOn(context)` | | calledWith | `expect(spy).to.be.calledWith(...args)` | | alwaysCalledWith | `expect(spy).to.always.be.calledWith(...args)` | | calledWithExactly | `expect(spy).to.be.calledWithExactly(...args)` | | alwaysCalledWithExactly | `expect(spy).to.always.be.calledWithExactly(...args)` | | calledWithMatch | `expect(spy).to.be.calledWithMatch(...args)` | | alwaysCalledWithMatch | `expect(spy).to.always.be.calledWithMatch(...args)` | | returned | `expect(spy).to.have.returned(returnVal)` | | alwaysReturned | `expect(spy).to.have.always.returned(returnVal)` | | threw | `expect(spy).to.have.thrown(errorObjOrErrorTypeStringOrNothing)` | | alwaysThrew | `expect(spy).to.have.always.thrown(errorObjOrErrorTypeStringOrNothing)` | *** # Using Chainers with Implicit Subjects When utilizing [`cy.should`](https://on.cypress.io/api/should) or [`cy.and`](https://on.cypress.io/api/should), instead of writing chainers as properties and methods, they are instead transformed into a string argument. If we convert the previous example to use [`cy.should`](https://on.cypress.io/api/should), it would look like: [block:code] { "codes": [ { "code": "cy.wrap({foo: \"bar\"}).should(\"have.property\", \"foo\")\n ↲ ↲ ↲\n subject chainers value\n", "language": "javascript" } ] } [/block] The chainers are shifted and become the first argument to [`cy.should`](https://on.cypress.io/api/should), with values simply being passed in as additional arguments. [block:code] { "codes": [ { "code": "// we can additionally continue to chain and add\n// multiple assertions about our <button> subject\ncy.get(\"button\").should(\"have.class\", \"active\").and(\"be.visible\")\n ↲ ↲ ↲ ↲\n subject chainers value chainers\n", "language": "javascript" } ] } [/block] If we converted the above example to use an explicit subject, this is what it would look like: [block:code] { "codes": [ { "code": "cy.get(\"button\").should(function($button){\n expect($button).to.have.class(\"active\")\n expect($button).to.be.visible\n})\n", "language": "javascript" } ] } [/block] This example above may be more familiar to you if you've written tests in JavaScript before. If you look closely, you'll see that we've passed a callback function to the [`cy.should`](https://on.cypress.io/api/should) method. This allows us to write expectations inside of that callback function, yet still receive all of the wonderful benefits of [`cy.should`](https://on.cypress.io/api/should). Read about [resolving assertions](https://on.cypress.io/guides/making-assertions#section-resolving-assertions) below to learn how [`cy.should`](https://on.cypress.io/api/should) works under the hood. *** ## Assertions that change the subject Sometimes using a specific chainer will automatically change the assertion subject. For instance in `chai`, the method [`have.property("...")`](http://chaijs.com/api/bdd/) will automatically change the subject. Additionally in [`Chai-jQuery`](https://github.com/chaijs/chai-jquery#attrname-value), the methods: `attr`, `prop`, `css`, and `data` also change the subject. This allows you to utilize other `chainer` methods such as `match` when making assertions about values. [block:code] { "codes": [ { "code": "// in this example our subject changed to the string 'sans-serif' because\n// have.css(\"font-family\") returned a string instead of the <body> element\ncy\n // subject is <body>\n .get(\"body\")\n\n // subject changes to the string return value of 'font-family'\n .should(\"have.css\", \"font-family\")\n\n // use match to assert the string matches a regular expression\n .and(\"match\", /sans-serif/)\n", "language": "javascript" } ] } [/block] [block:code] { "codes": [ { "code": "// in this example our subject changed to the string '/users' because\n// have.attr, href, /users returned a string instead of the <a> element\ncy\n // subject is <a>\n .get(\"a\")\n\n // subject changes to the string 'users'\n .should(\"have.attr\", \"href\", \"/users\")\n", "language": "javascript" } ] } [/block] *** ## How do I know which assertions change the subject and which keep it the same? The chainers that come from [Chai](https://on.cypress.io/guides/bundled-tools#section-chai) or [Chai-jQuery](https://on.cypress.io/guides/bundled-tools#section-chai-jquery) will always document what they return. Alternatively, it is very easy to use Cypress itself to figure this out. You can [read more about debugging assertions](https://on.cypress.io/guides/making-assertions#sections-debugging-assertions) here. *** # Negating assertions Every assertion can be chained with `.not` to assert the opposite behavior on a subject. **Negating Assertion Examples** [block:code] { "codes": [ { "code": "cy.get(\"button.disabled\").should(\"be.disabled\") // assertion\ncy.get(\"button.active\").should(\"not.be.disabled\") // negating assertion\n\ncy.title().should(\"eq\", \"My Awesome App\") // assertion\ncy.title().should(\"not.eq\", \"My Not So Awesome App\") // negating assertion\n\ncy.get(\"a\").should(\"have.attr\", \"popover\", \"Help\") // assertion\ncy.get(\"a\").should(\"not.have.attr\", \"popover\", \"I'm lost\") // negating assertion\n", "language": "javascript" } ] } [/block] *** # Resolving Assertions Knowing when and how to resolve assertions is can be challenging, made even more difficult by modern JavaScript frameworks. Yet accurately resolving assertions is the key for preventing flaky and brittle tests. Cypress's API is built to consistently pass or fail every time. As part of this strategy, Cypress will automatically look downstream at assertions and modify its behavior based on upcoming assertions. Internally, Cypress will retry commands which are associated to assertions, and will not continue until **all** assertions pass. Using assertions as guards enables you to specify conditions that must be resolved prior to moving on. What conditions should you specify? Anything that guarantees your app is in the correct state. **Here are some scenarios of using assertions as guards:** * Clicking an `<a>` then verifying the url is correct after you expect your server to redirect. * Focusing, then blurring on an `<input>` and expecting an error message with a specific class to be visible. * Clicking a `<button>` and waiting for a modal to animate in. * Typing into a `<form>` and verifying an element should not exist or not be visible. Every command that comes before a [`cy.should`](https://on.cypress.io/api/should) will not resolve until **all** of its associated assertions pass. This enables you to accurately test the following situation: [block:code] { "codes": [ { "code": "<!-- Our App Code -->\n<form>\n <input name=\"name\" placeholder=\"What is your name?\" />\n <span id=\"error\" style=\"display: none;\"></span>\n</form>\n", "language": "html" } ] } [/block] [block:code] { "codes": [ { "code": "// Our App Code\nfunction waitRandomlyThen(fn){\n setTimeout(fn, Math.random() * 3000)\n}\n\n$(\"form\").submit(function(e){\n e.preventDefault()\n\n waitRandomlyThen(function(){\n $(\"#error\").show()\n })\n\n waitRandomlyThen(function(){\n $(\"#error\").addClass(\"alert-danger\")\n })\n\n waitRandomlyThen(function(){\n $(\"#error\").html(\"Your <strong>name</strong> is required.\")\n })\n})\n", "language": "javascript" } ] } [/block] The above app code could can be tested with the following assertions: [block:code] { "codes": [ { "code": "cy\n .get(\"form\").submit()\n .get(\"#error\")\n .should(\"be.visible\")\n .and(\"have.class\", \"alert-danger\")\n .and(\"contain\", \"Your name is required.\")\n", "language": "javascript" } ] } [/block] Our tests' code is insulated from flaky failures because it is not coupled to any specific timing mechanism. If you look closely, our application code is written in such a way that introduces random wait times - yet Cypress will pass 100% of the time, without any explicit `wait` calls. The moment all 3 of the assertions pass, Cypress will resolve. ![assertions](https://cloud.githubusercontent.com/assets/1268976/10004440/b1c53294-607f-11e5-8d7d-3f5694a1fb1a.gif) In modern JavaScript frameworks, and in many common web-based actions, there is usually an *indeterminate* amount of time between an action and a side effect such as: * Network Requests * Redirects * Form Submissions * AJAX Requests * Websockets * Page Navigation * setTimeout's * DOM Events Cypress makes it easy to test and make assertions about all of these. *** ## Increasing timeouts You have two ways of increasing the amount of time Cypress waits for assertions to pass. 1. Change the [`defaultCommandTimeout`](https://on.cypress.io/guides/configuration#section-timeouts) globally 2. Override the timeout option on a previous command before the assertion command. Overriding the timeout option on a specific command looks like this: [block:code] { "codes": [ { "code": "cy\n .find(\"input\", {timeout: 10000}) // <-- wait up to 10 seconds for this 'input' to be found\n .should(\"have.value\", \"foo\") // <-- and to have the value 'foo'\n .and(\"have.class\", \"radio\") // <-- and to have the class 'radio'\n\n .parents(\"#foo\", {timeout: 2000}) // <--\n .should(\"not.exist\") // <-- wait up to 2 seconds for this element NOT to be found\n", "language": "javascript" } ] } [/block] It's important to note that timeouts will automatically flow down to their cooresponding assertions. **In the example we wait up to a total of 10 seconds to:** 1. find the `<input>` 2. ensure it has a value of `foo` 3. ensure it has a class of `radio` [block:code] { "codes": [ { "code": "cy.find(\"input\", {timeout: 10000}).should(\"have.value\", \"foo\").and(\"have.class\", \"radio\")\n ↲\n // adding the timeout here will automatically\n // flow down to the assertions, and they will\n // be retried for up to 10 seconds\n", "language": "javascript" } ] } [/block] [block:callout] { "type": "warning", "body": "Assuming you have two assertions, if one passes, and one fails, Cypress will continue to retry until they **both** pass. If Cypress eventually times out you'll get a visual indicator in your Command Log to know which specific assertion failed." } [/block]