Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING: 13.0 Docs #5315

Merged
merged 30 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
610348c
BREAKING: update documentation by setting default video: false for v1…
AtofStryker Jun 15, 2023
c94c9b3
Merge branch 'main' into v13.0.0
mjhenkes Jun 15, 2023
48c2a95
breaking: update documentation by setting videoCompression: false (#5…
AtofStryker Jun 20, 2023
8f1fc89
BREAKING: remove the videoUploadOnPasses configuration option (#5306)
AtofStryker Jun 20, 2023
674419f
.readFile() is now a query (#5017) (#5316)
mjhenkes Jun 20, 2023
7d78203
Update guides for Cy 13, where assertions are now commands (#5081)
BlueWinds Jul 12, 2023
dcea3ed
Apply suggestions from code review
mjhenkes Jul 12, 2023
a0fcdf8
Remove nodeVersion documentation (#5318)
mjhenkes Jul 19, 2023
dd27a62
docs: v13 video and TR migration info (#5383)
jaffrepaul Jul 24, 2023
9eb430c
Update results for module API and after:spec handler (#5379)
chrisbreiding Aug 16, 2023
f391fef
Merge branch 'main' into v13.0.0
jennifer-shehane Aug 18, 2023
fc9304f
docs: adding documentation for runner-ui cli flags (#5424)
mschile Aug 18, 2023
7829170
docs: test replay docs (#5349)
jaffrepaul Aug 22, 2023
f99749f
Merge branch 'main' into v13.0.0
jennifer-shehane Aug 22, 2023
5051c43
Fix JavaScript caps
jennifer-shehane Aug 22, 2023
939111a
Fix caps of JavaScript
jennifer-shehane Aug 22, 2023
2929a65
Fix typo
jennifer-shehane Aug 22, 2023
2348408
Write a document around Cloud data storage and controls (#5425)
jennifer-shehane Aug 24, 2023
0eb47b4
add changelog, remove node 16 support, and update docker image refere…
AtofStryker Aug 25, 2023
f877204
docs: minor v13 updates (#5438)
jaffrepaul Aug 25, 2023
0b7948d
docs: update v13 content urls (#5428)
jaffrepaul Aug 25, 2023
79fe056
docs: v13 changelog summary (#5441)
jaffrepaul Aug 25, 2023
ff326c4
Merge branch 'main' into v13.0.0
jaffrepaul Aug 25, 2023
2ec3eb4
Apply suggestions from code review
jaffrepaul Aug 25, 2023
009f44b
lint
jaffrepaul Aug 25, 2023
e683686
Update docs/faq/questions/cloud-faq.mdx
jaffrepaul Aug 28, 2023
6e0e27c
include TR note in cypress screenshot api options (#5445)
jaffrepaul Aug 28, 2023
4b850a4
docs: additional test replay content (#5447)
jaffrepaul Aug 28, 2023
cc14939
sync up changelog
chrisbreiding Aug 29, 2023
e09fac2
Update _cloud_free_plan.mdx
jaffrepaul Aug 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/api/commands/screenshot.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,8 @@ Another potential problem to be aware of is that our own Command Log is using
React under the hood and only rendering asynchronously during an animation
frame. It is possible you will see screenshots taken before our Command Log is
done rendering. This means you may not see the **error displayed** in the
screenshot. But this is also why we take a video - to show you the complete
failure.
screenshot. But this is also why we allow taking a video - to show you the
complete failure.

We make our best effort to synchronize taking a screenshot with our renderer,
but the current state of your application under test could have changed in the
Expand Down
1 change: 0 additions & 1 deletion docs/api/plugins/after-spec-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ on('after:spec', (spec, results) => {
// {
// title: ['login', 'logs user in'],
// state: 'passed',
// body: 'function () {}',
// // ...more properties...
// }
// ],
Expand Down
16 changes: 14 additions & 2 deletions docs/api/commands/readfile.mdx → docs/api/queries/readfile.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
title: readFile
slug: /api/commands/readfile
---

Read a file and yield its contents.
Expand Down Expand Up @@ -62,8 +63,8 @@ Pass in an options object to change the default behavior of `cy.readFile()`.
### Yields [<Icon name="question-circle"/>](/guides/core-concepts/introduction-to-cypress#Subject-Management)

- `cy.readFile()` yields the contents of the file.
- The file will not be read from disk again if the results are stored in an
alias.
- The file will be read from disk again if any upcoming command (such as an
assertion) in the chain fails.

## Examples

Expand Down Expand Up @@ -195,6 +196,15 @@ assertions.
cy.readFile('some/nested/path/story.txt').should('eq', 'Once upon a time...')
```

Starting in Cypress 13, `cy.readFile()` is a query, and will continue to read
jaffrepaul marked this conversation as resolved.
Show resolved Hide resolved
the file until all chained commands of any type pass, not just assertions.

```javascript
// will retry until the json file has a `users[123].name` field, and
// the assertion passes
cy.readFile('users.json').its('users.123.name').should('eq', 'John Doe')
```

## Rules

### Requirements [<Icon name="question-circle"/>](/guides/core-concepts/introduction-to-cypress#Chains-of-Commands)
Expand Down Expand Up @@ -247,6 +257,7 @@ outputs the following:

| Version | Changes |
| --------------------------------------------- | ----------------------------------------- |
| [13.0.0](/guides/references/changelog#13-0-0) | `cy.readFile()` became a query |
| [9.0.0](/guides/references/changelog#9-0-0) | Changed `null` encoding to read as Buffer |
| [0.17.2](/guides/references/changelog#0-17-2) | Improved error messaging |
| [0.17.1](/guides/references/changelog#0-17-1) | `cy.readFile()` command added |
Expand All @@ -255,5 +266,6 @@ outputs the following:

- [`cy.exec()`](/api/commands/exec)
- [`cy.fixture()`](/api/commands/fixture) for a similar command with caching
that does not retry
- [`cy.task()`](/api/commands/task)
- [`cy.writeFile()`](/api/commands/writefile)
4 changes: 3 additions & 1 deletion docs/guides/continuous-integration/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ insight into what happened when your tests ran.
- Get the entire stack trace of failed tests.
- View screenshots taken when tests fail and when using
[`cy.screenshot()`](/api/commands/screenshot).
- Watch a video of your entire test run or a clip at the point of test failure.
- Watch a video of your entire test run or a clip at the point of test failure
when the `video` configuration is enabled.
- See which machines ran each test when
[parallelized](/guides/cloud/smart-orchestration/parallelization).

Expand Down Expand Up @@ -376,6 +377,7 @@ values in the Cypress configuration.
**_Typical use cases would be modifying things like:_**

- `CYPRESS_BASE_URL`
- `CYPRESS_VIDEO`
- `CYPRESS_VIDEO_COMPRESSION`
- `CYPRESS_REPORTER`
- `CYPRESS_INSTALL_BINARY`
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/core-concepts/interacting-with-elements.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Cypress will watch the DOM - re-running the queries that yielded the current
subject - until an element passes all of these checks for the duration of the
[`defaultCommandTimeout`](/guides/references/configuration#Timeouts) (described
in depth in the
[Default Assertions](/guides/core-concepts/introduction-to-cypress#Default-Assertions)
[Implicit Assertions](/guides/core-concepts/introduction-to-cypress#Implicit-Assertions)
core concept guide).

**_Checks and Actions Performed_**
Expand Down
146 changes: 55 additions & 91 deletions docs/guides/core-concepts/introduction-to-cypress.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ just in case".
:::

Later in this guide we'll go into much more detail about
[Default Assertions](#Default-Assertions) and [Timeouts](#Timeouts).
[Implicit Assertions](#Implicit-Assertions) and [Timeouts](#Timeouts).

## Chains of Commands

Expand Down Expand Up @@ -912,11 +912,10 @@ randomly fail. This would lead to flaky, inconsistent results.

:::info

While Cypress is built using Promises that come from
[Bluebird](http://bluebirdjs.com/), these are not what we expose as commands and
assertions on `cy`. If you'd like to learn more about handling asynchronous
Cypress Commands please read our
[Core Concept Guide](/guides/core-concepts/variables-and-aliases).
While Cypress does have a [`.then()`](/api/commands/then) command, Cypress
commands are not Promises and cannot be `await`ed. If you'd like to learn more
about handling asynchronous Cypress Commands please read our
[Variables and Aliases Guide](/guides/core-concepts/variables-and-aliases).

:::

Expand Down Expand Up @@ -958,24 +957,22 @@ model after a real user working step by step.
#### You cannot add a `.catch` error handler to a failed command

In Cypress there is no built in error recovery from a failed command. A command
and its assertions all _eventually_ pass, or if one fails, all remaining
commands are not executed, and the test fails.
_eventually_ passes, or if it fails, all remaining commands are not executed,
and the test as a whole fails.

You might be wondering:

> How do I create conditional control flow, using if/else? So that if an element
> does (or doesn't) exist, I choose what to do?

The problem with this question is that this type of conditional control flow
ends up being non-deterministic. This means different test runs may behave
differently, which makes them less deterministic and consistent. In general,
there are only a handful of very specific situations where you _can_ create
control flow using Cypress commands.
Cypress does not support this type of conditional control flow because it leads
to non-deterministic tests - different runs may behave differently, which makes
them less consistent and useful for verifying your application's correctness. In
general, there are only a handful of very specific situations where you can or
should create control flow using Cypress commands.

With that said, as long as you are aware of the potential pitfalls with control
flow, it is possible to do this in Cypress!

You can read all about how to do
flow, it is possible to do this in Cypress! You can read all about how to do
[conditional testing](/guides/core-concepts/conditional-testing) here.

## Assertions
Expand All @@ -989,33 +986,18 @@ Assertions describe the **desired** state of your **elements**, your

:::

What makes Cypress unique from other testing tools is that commands
**automatically retry** their assertions. In fact, they will look "downstream"
at what you're expressing and modify their behavior to make your assertions
pass.

You should think of assertions as **guards**.

Use your **guards** to describe what your application should look like, and
Cypress will automatically **block, wait, and retry** until it reaches that
state.

:::tip

<strong>Core Concept</strong>

Each command documents its behavior with assertions - such as how it retries or
waits for assertions to pass.

:::
What makes Cypress unique from other testing tools is that assertions
**automatically retry**. Think of them as **guards** - assertions describe what
your application should look like, and Cypress will automatically **block, wait,
and retry** until it reaches that state.

### Asserting in English

Let's look at how you'd describe an assertion in English:

:::note

After clicking on this `<button>`, I expect its class to eventually be `active`.
After clicking on this `<button>`, I expect its class to be `active`.

:::

Expand All @@ -1027,7 +1009,9 @@ cy.get('button').should('have.class', 'active')
```

This above test will pass even if the `.active` class is applied to the button
asynchronously - or after an indeterminate period of time.
asynchronously, after an indeterminate period of time or even if the button is
removed from the DOM entirely for a while (replaced with a waiting spinner, for
example).

```javascript
// even though we are adding the class
Expand Down Expand Up @@ -1078,7 +1062,7 @@ cy.get('form').submit()
:::

Without a single explicit assertion, there are dozens of ways this test can
fail! Here's a few:
fail. Here's a few:

- The initial [`cy.mount()`](/api/commands/mount) or
[`cy.visit()`](/api/commands/visit) could respond with something other than
Expand All @@ -1096,17 +1080,16 @@ fail! Here's a few:

<strong>Core Concept</strong>

With Cypress, you don't have to assert to have a useful test. Even without
assertions, a few lines of Cypress can ensure thousands of lines of code are
working properly across the client and server!
With Cypress, you don't have to write explicit assertions to have a useful test.
Without a single `expect()` or `.should()`, a few lines of Cypress can ensure
thousands of lines of code are working properly across the client and server.

This is because many commands have a built in
[Default Assertion](#Default-Assertions) which offer you a high level of
guarantee.
This is because many commands have a built in Implicit Assertions which offer
jennifer-shehane marked this conversation as resolved.
Show resolved Hide resolved
you a high level of confidence that your application is working as expected.

:::

### Default Assertions
### Implicit Assertions

Many commands have default, built-in assertions, or rather have requirements
that may cause it to fail without needing an explicit assertion you've added.
Expand Down Expand Up @@ -1159,7 +1142,7 @@ they can fail, typically by passing a `{force: true}` option.

```js
cy
// there is a default assertion that this
// there is an implicit assertion that this
// button must exist in the DOM before proceeding
.get('button')

Expand All @@ -1168,16 +1151,16 @@ cy
.click()
```

Cypress will automatically _wait_ for elements to pass their default assertions.
Like with the explicit assertions you've added, all of these assertions share
the _same_ timeout values.
Cypress will automatically _wait_ for elements to pass their implicit
assertions. See [Timeouts](#Timeouts) below for more on how timeouts are
determined.

#### Example #2: Reversing the Default Assertion
#### Example #2: Reversing the Implicit Assertion

Most of the time, when querying for elements, you expect them to eventually
exist. But sometimes you wish to wait until they _don't_ exist.

All you have to do is add that assertion and Cypress will **reverse** its rules
All you have to do is add that assertion and Cypress will **skip** implicitly
waiting for elements to exist.

```js
Expand All @@ -1196,15 +1179,14 @@ cy.get('#modal').should('not.exist')

<strong>Core Concept</strong>

By adding [`.should('not.exist')`](/api/commands/should) to any DOM command,
Cypress will reverse its default assertion and automatically wait until the
element does not exist.
If you want to disable the default existence assertion, you can add
[`.should('not.exist')`](/api/commands/should) to any DOM command.

:::

#### Example #3: Other Default Assertions
#### Example #3: Other Implicit Assertions

Other commands have other default assertions not related to the DOM.
Other commands have other implicit assertions not related to the DOM.

For instance, [`.its()`](/api/commands/its) requires that the property you're
asking about exists on the object.
Expand Down Expand Up @@ -1236,20 +1218,20 @@ use them in Cypress.

There are two ways to write assertions in Cypress:

1. **Implicit Subjects:** Using [`.should()`](/api/commands/should) or
1. **As Cypress Commands:** Using [`.should()`](/api/commands/should) or
[`.and()`](/api/commands/and).
2. **Explicit Subjects:** Using `expect`.
2. **As Mocha Assertions:** Using `expect`.

### Implicit Subjects
### Command Assertions

Using [`.should()`](/api/commands/should) or [`.and()`](/api/commands/and)
commands is the preferred way of making assertions in Cypress. These are typical
Cypress commands, which means they apply to the currently yielded subject in the
command chain.

```javascript
// the implicit subject here is the first <tr>
// this asserts that the <tr> has an .active class
// The subject here is the first <tr>.
// This asserts that the <tr> has an .active class
cy.get('tbody tr:first').should('have.class', 'active')
```

Expand All @@ -1268,29 +1250,11 @@ subject, [`.and('have.attr')`](/api/commands/and) is executed against the same
element. This is handy when you need to assert multiple things against a single
subject quickly.

If we wrote this assertion in the explicit form "the long way", it would look
like this:

```js
cy.get('tbody tr:first').should(($tr) => {
expect($tr).to.have.class('active')
expect($tr).to.have.attr('href', '/users')
})
```

The implicit form is much shorter! So when would you want to use the explicit
form?

Typically when you want to:

- Assert multiple things about the same subject
- Massage the subject in some way prior to making the assertion

### Explicit Subjects
### Mocha Assertions

Using `expect` allows you to pass in a specific subject and make an assertion
about it. This is probably how you're used to seeing assertions written in unit
tests:
Using `expect` allows you to assert on any javascript object, not just the
jennifer-shehane marked this conversation as resolved.
Show resolved Hide resolved
current subject. This is probably how you're used to seeing assertions written
in unit tests:

```js
// the explicit subject here is the boolean: true
Expand All @@ -1306,7 +1270,7 @@ Check out our example recipes for [unit testing](/examples/recipes) and

:::

Explicit assertions are great when you want to:
Mocha assertions are great when you want to:

- Perform custom logic prior to making the assertion.
- Make multiple assertions against the same subject.
Expand Down Expand Up @@ -1361,7 +1325,7 @@ cy.get('p').should(($p) => {

When using a callback function with [`.should()`](/api/commands/should), be sure
that the entire function can be executed multiple times without side effects.
Cypress applies its [retry](/guides/core-concepts/retry-ability) logic to these
Cypress applies its [retry logic](/guides/core-concepts/retry-ability) to these
functions: if there's a failure, it will repeatedly rerun the assertions until
the timeout is reached. That means your code should be retry-safe. The technical
term for this means your code must be **idempotent**.
Expand All @@ -1384,10 +1348,10 @@ Remember because assertions are used to describe a condition of the previous
commands - the `timeout` modification goes on the previous commands _not the
assertions_.

#### Example #1: Default Assertion
#### Example #1: Implicit Assertion

```js
// because .get() has a default assertion
// because .get() has an implicit assertion
// that this element exists, it can time out and fail
cy.get('.mobile-nav')
```
Expand Down Expand Up @@ -1416,14 +1380,14 @@ The _total_ amount of time Cypress will wait for _all_ of the assertions to pass
is for the duration of the [cy.get()](/api/commands/get) `timeout` (which is 4
seconds).

Timeouts can be modified per command and this will affect all default assertions
and any assertions chained after that command.
Timeouts can be modified per command and this will affect all implicit
assertions and any assertions chained after that command.

#### Example #3: Modifying Timeouts

```js
// we've modified the timeout which affects default
// plus all added assertions
// we've modified the timeout which affects the implicit
// assertions as well as all explicit ones.
cy.get('.mobile-nav', { timeout: 10000 })
.should('be.visible')
.and('contain', 'Home')
Expand Down