mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-23 08:50:20 -05:00
Merge branch 'develop' into 9.0-release
This commit is contained in:
+63
-57
@@ -4,17 +4,17 @@ Thanks for taking the time to contribute! :smile:
|
||||
|
||||
**Once you learn how to use Cypress, you can contribute in many ways:**
|
||||
|
||||
- Join the [Cypress Gitter chat](https://on.cypress.io/chat) and answer questions. Teaching others how to use Cypress is a great way to learn more about how it works.
|
||||
- Join the [Cypress Gitter chat](https://on.cypress.io/chat) or [Discord](https://on.cypress.io/discord) and answer questions. Teaching others how to use Cypress is a great way to learn more about how it works.
|
||||
- Blog about Cypress. We display blogs featuring Cypress on our [Examples](https://on.cypress.io/examples) page. If you'd like your blog featured, [open a PR to add it to our docs](https://github.com/cypress-io/cypress-documentation/blob/develop/CONTRIBUTING.md#adding-examples).
|
||||
- Write some documentation or improve our existing docs. Know another language? You can help us translate them. See our [guide to contributing to our docs](https://github.com/cypress-io/cypress-documentation/blob/master/CONTRIBUTING.md).
|
||||
- Write some documentation or improve our existing docs. See our [guide to contributing to our docs](https://github.com/cypress-io/cypress-documentation/blob/master/CONTRIBUTING.md).
|
||||
- Give a talk about Cypress. [Contact us](mailto:support@cypress.io) ahead of time and we'll send you some swag. :shirt:
|
||||
|
||||
**Want to dive deeper into how Cypress works? There are several ways you can help with the development of Cypress:**
|
||||
|
||||
- [Report bugs](https://github.com/cypress-io/cypress/issues/new?template=1-bug-report.md) by opening an issue.
|
||||
- [Request features](https://github.com/cypress-io/cypress/issues/new?template=3-feature.md) by opening an issue.
|
||||
- [Help triage existing issue](#triaging-issues).
|
||||
- Write code to address an issue. We have some issues labeled as [`first-timers-only`](https://github.com/cypress-io/cypress/labels/first-timers-only) that are good place to start. [Please thoroughly read our writing code guide](#writing-code).
|
||||
- [Report bugs](https://github.com/cypress-io/cypress/issues/new) by opening an issue.
|
||||
- [Request features](https://github.com/cypress-io/cypress/issues/new) by opening an issue.
|
||||
- [Help triage existing issues](#triaging-issues).
|
||||
- Write code to address an issue. We have some issues labeled as [`first-timers-only`](https://github.com/cypress-io/cypress/labels/first-timers-only) that are a good place to start. Please thoroughly read our [Writing Code guide](#writing-code).
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -82,21 +82,21 @@ Before filing a bug, make sure you are up to date. Your issue may have already b
|
||||
|
||||
### Getting more information
|
||||
|
||||
For some issues, there are places you can check for more information. This may help you resolve the issue yourself. Even if it does not, this information can help us figure out and resolve an issue.
|
||||
For some issues, there are places you can check for more information. This may help you resolve the issue yourself. Even if it doesn't, this information can help us figure out and resolve an issue.
|
||||
|
||||
- For issues in the web browser, check the JavaScript console and your Network tab in your DevTools.
|
||||
- Click on any command in the Command Log where the failure occurred, this will log more information about the error to the JavaScript console.
|
||||
- Use Cypress [`debug`](https://on.cypress.io/debug) or [`pause`](https://on.cypress.io/pause) commands to step through your commands.
|
||||
- Ask other Cypress users for help in our [chat](https://on.cypress.io/chat).
|
||||
- Ask other Cypress users for help in our [chat](https://on.cypress.io/chat) or [Discord](https://on.cypress.io/discord).
|
||||
- Try more advanced troubleshooting from [troubleshooting Cypress](https://on.cypress.io/debugging#Troubleshooting-Cypress) doc.
|
||||
|
||||
### Fill out our Issue Template
|
||||
|
||||
When opening an issue, there is a provided [issue template](./.github/ISSUE_TEMPLATE). Fill out the information according to the template. This is information needed for Cypress to continue forward with your problem. Any issues that do not follow the issue template will be closed.
|
||||
When opening an issue, there is a provided issue template. Fill out the information according to the template. This is information needed for Cypress to continue forward with your problem. Any issues that don't fill out the issue template will be closed.
|
||||
|
||||
### Describe Problems
|
||||
|
||||
When you file a feature request or bug, we need you to **describe the problem you are facing first**, not just your desired solution.
|
||||
When you file a feature request or bug, it's best to **describe the problem you are facing first**, not just your desired solution.
|
||||
|
||||
Often, your problem may have a lot in common with other similar problems. If we understand your use case, we can compare it to other use cases and sometimes find a more powerful or more general solution which solves several problems at once. Understanding the root issue can let us merge and contextualize things. Sometimes there's already a way to solve your problem that might just not be obvious.
|
||||
|
||||
@@ -104,27 +104,27 @@ Also, your proposed solution may not be compatible with the direction we want to
|
||||
|
||||
### Reproducibility
|
||||
|
||||
**It is nearly impossible for us to resolve many issues if we can not reproduce them. Your best chance of getting a bug looked at quickly is to provide a repository with a reproducible bug that can be cloned and run.**
|
||||
**It is nearly impossible for us to resolve issues if we can not reproduce them. Your best chance of getting a bug looked at quickly is to provide a repository with a reproducible bug that can be cloned and run.**
|
||||
|
||||
## Common issues
|
||||
|
||||
Label | Description | Main issue | Issues
|
||||
--- | --- | --- | ---
|
||||
browser detection | Local browser is not detected | [8541](https://github.com/cypress-io/cypress/issues/8541) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20browser%20detection), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+browser+detection%22+is%3Aclosed)
|
||||
cross-origin | Getting cross-origin error | [944](https://github.com/cypress-io/cypress/issues/944) |[open](https://github.com/cypress-io/cypress/labels/topic%3A%20cross-origin%20%E2%A4%AD), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+cross-origin+%E2%A4%AD%22+is%3Aclosed)
|
||||
cy.request | Issues related to cy.request command | [1647](https://github.com/cypress-io/cypress/issues/1647) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20cy.request), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+cy.request%22+is%3Aclosed)
|
||||
Label | Description | Issues
|
||||
--- | --- | ---
|
||||
browser detection | Local browser is not detected | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20browser%20detection), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+browser+detection%22+is%3Aclosed)
|
||||
cross-origin | Getting cross-origin error | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20cross-origin%20%E2%A4%AD), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+cross-origin+%E2%A4%AD%22+is%3Aclosed)
|
||||
cy.request | Issues related to cy.request command | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20cy.request), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+cy.request%22+is%3Aclosed)
|
||||
fixtures | Fixture loading and usage | | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20fixtures), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+fixtures%22+is%3Aclosed)
|
||||
hooks | Issues related to hooks | [4703](https://github.com/cypress-io/cypress/issues/4703), [665](https://github.com/cypress-io/cypress/issues/665) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20hooks%20%E2%86%AA), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+hooks+%E2%86%AA%22+is%3Aclosed)
|
||||
iframes | Working with iframes | [136](https://github.com/cypress-io/cypress/issues/136) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20iframes), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+iframes%22+is%3Aclosed)
|
||||
installation | Cypress cannot be downloaded or installed | [8392](https://github.com/cypress-io/cypress/issues/8392) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20installation), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+installation%22+is%3Aclosed)
|
||||
network | Controlling network requests | [3427](https://github.com/cypress-io/cypress/issues/3427), [3083](https://github.com/cypress-io/cypress/issues/3083), [1773](https://github.com/cypress-io/cypress/issues/1773) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20network), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+network%22+is%3Aclosed)
|
||||
performance | Slow loading, slow network, etc | [1305](https://github.com/cypress-io/cypress/issues/1305) | [open](https://github.com/cypress-io/cypress/labels/type%3A%20performance%20%F0%9F%8F%83%E2%80%8D%E2%99%80%EF%B8%8F), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22type%3A+performance+%F0%9F%8F%83%E2%80%8D%E2%99%80%EF%B8%8F%22+is%3Aclosed)
|
||||
screenshots | Taking image screenshots | [2102](https://github.com/cypress-io/cypress/issues/2102) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20screenshots%20%F0%9F%93%B8), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+screenshots+%F0%9F%93%B8%22+is%3Aclosed)
|
||||
scrolling | Scrolling elements into view | [871](https://github.com/cypress-io/cypress/issues/871) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20scrolling%20%E2%86%95%EF%B8%8F), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+scrolling+%E2%86%95%EF%B8%8F%22+is%3Aclosed)
|
||||
spec execution | Running all specs or some specs in some specific order | [390](https://github.com/cypress-io/cypress/issues/390) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20spec%20execution) | [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+spec+execution%22+is%3Aclosed)
|
||||
test execution | Running tests inside a single spec | [2908](https://github.com/cypress-io/cypress/issues/2908) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20test%20execution), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+test+execution%22+is%3Aclosed)
|
||||
typescript | Transpiling or bundling TypeScript | [7435](https://github.com/cypress-io/cypress/issues/7435) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20typescript), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+typescript%22+is%3Aclosed)
|
||||
video | Problems with video recordings | [2522](https://github.com/cypress-io/cypress/issues/2522) | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20video%20%F0%9F%93%B9), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+video+%F0%9F%93%B9%22+is%3Aclosed)
|
||||
hooks | Issues related to hooks | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20hooks%20%E2%86%AA), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+hooks+%E2%86%AA%22+is%3Aclosed)
|
||||
iframes | Working with iframes | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20iframes), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+iframes%22+is%3Aclosed)
|
||||
installation | Cypress cannot be downloaded or installed | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20installation), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+installation%22+is%3Aclosed)
|
||||
network | Controlling network requests | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20network), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+network%22+is%3Aclosed)
|
||||
performance | Slow loading, slow network, etc | [open](https://github.com/cypress-io/cypress/labels/type%3A%20performance%20%F0%9F%8F%83%E2%80%8D%E2%99%80%EF%B8%8F), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22type%3A+performance+%F0%9F%8F%83%E2%80%8D%E2%99%80%EF%B8%8F%22+is%3Aclosed)
|
||||
screenshots | Taking image screenshots | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20screenshots%20%F0%9F%93%B8), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+screenshots+%F0%9F%93%B8%22+is%3Aclosed)
|
||||
scrolling | Scrolling elements into view | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20scrolling%20%E2%86%95%EF%B8%8F), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+scrolling+%E2%86%95%EF%B8%8F%22+is%3Aclosed)
|
||||
spec execution | Running all specs or some specs in some specific order | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20spec%20execution) | [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+spec+execution%22+is%3Aclosed)
|
||||
test execution | Running tests inside a single spec | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20test%20execution), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+test+execution%22+is%3Aclosed)
|
||||
typescript | Transpiling or bundling TypeScript | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20typescript), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+typescript%22+is%3Aclosed)
|
||||
video | Problems with video recordings | [open](https://github.com/cypress-io/cypress/labels/topic%3A%20video%20%F0%9F%93%B9), [closed](https://github.com/cypress-io/cypress/issues?q=label%3A%22topic%3A+video+%F0%9F%93%B9%22+is%3Aclosed)
|
||||
|
||||
## Triaging Issues
|
||||
|
||||
@@ -132,13 +132,12 @@ When an issue is opened in [cypress](https://github.com/cypress-io/cypress), we
|
||||
|
||||
### Is this a question?
|
||||
|
||||
Some opened issue are questions, not bug reports or feature requests. Issues are reserved for potential bugs or feature requests *only*. If this is the case, you should:
|
||||
Some opened issues are questions, not bug reports or feature requests. Issues are reserved for potential bugs or feature requests *only*. If this is the case, you should:
|
||||
|
||||
- Explain that issues in our GitHub repo are reserved for potential bugs or feature requests and that the issue will be closed since it appears to be neither a bug nor a feature request.
|
||||
- Guide them to existing resources where their questions can be asked like our [community chat](https://on.cypress.io/chat), our [documentation](https://docs.cypress.io), or [Stack Overflow](https://stackoverflow.com/questions/tagged/cypress).
|
||||
- Guide them to existing resources where their questions can be asked like our [Discussions](https://github.com/cypress-io/cypress/discussions), [community chat](https://on.cypress.io/chat), [Discord](https://on.cypress.io/discord),, or [Stack Overflow](https://stackoverflow.com/questions/tagged/cypress).
|
||||
- Cypress offers support via email when signing up for any of our our [paid plans](https://www.cypress.io/pricing/), so remind them that this is an option if they already have a paid account.
|
||||
- Add the `type: question` label to the issue.
|
||||
- Close the issue.
|
||||
- Move the issue to [Discussions](https://github.com/cypress-io/cypress/discussions).
|
||||
|
||||
### Does this issue belong in this repository?
|
||||
|
||||
@@ -147,18 +146,23 @@ Some opened issue are questions, not bug reports or feature requests. Issues are
|
||||
Issues may be opened about wanting changes to our [documentation](https://github.com/cypress-io/cypress-documentation), our [example-kitchensink app](https://github.com/cypress-io/cypress-example-kitchensink), or [another repository](https://github.com/cypress-io). In this case you should:
|
||||
|
||||
- Thank them for their contribution.
|
||||
- Explain that this repo is only for bugs or feature requests of the Cypress product.
|
||||
- Explain that this repo is only for bugs or feature requests of the Cypress App.
|
||||
- If you have permission to 'Transfer the issue', do so. If not, explain that they can open an issue in our other repository and link to the repository.
|
||||
- Close the issue (if not already transferred).
|
||||
|
||||
#### Our Dashboard Service
|
||||
#### Cypress Dashboard
|
||||
|
||||
Issues may be opened about wanting features in our Dashboard Service. In this case you should:
|
||||
|
||||
- Thank them for expressing interest in a new feature.
|
||||
- Refer them to the Dashboard ProductBoard: "You can express interest and see progress for this feature on our Roadmap from our Dashboard's product board here: https://portal.productboard.com/cypress-io/1-cypress-dashboard All related work for the Dashboard features is handled in that ProductBoard and will be handled by the Dashboard team directly when you comment there."
|
||||
- Close the issue
|
||||
- Close the issue to comments
|
||||
- Thank them for opening an issue.
|
||||
- Add the `external: dashboard` label.
|
||||
|
||||
#### Component Testing
|
||||
|
||||
Issues may be opened about wanting features in Component Testing. In this case you should:
|
||||
|
||||
- Thank them for opening an issue.
|
||||
- Add the `component testing` label.
|
||||
|
||||
### Is this already an open issue?
|
||||
|
||||
@@ -173,9 +177,9 @@ If an issue already exists you should:
|
||||
|
||||
### Does the issue provide all the information from our issue template?
|
||||
|
||||
When opening an issue, there is a provided [issue template](./.github/ISSUE_TEMPLATE). If the opened issue does not provide enough information asked from the issue template you should:
|
||||
When opening an issue, there is a provided issue template based on the type of issue. If the opened issue does not provide enough information asked from the issue template you should:
|
||||
|
||||
- Explain that we require new issues follow our provided [issue template](./.github/ISSUE_TEMPLATE) and that issues that are opened without this information are automatically closed per our [contributing guidelines](#fill-out-our-issue-template).
|
||||
- Explain that we require new issues follow our provided issue template and that issues that are opened without this information are automatically closed per our [contributing guidelines](#fill-out-our-issue-template).
|
||||
- Close the issue.
|
||||
|
||||
### Are they running the current version of Cypress?
|
||||
@@ -190,24 +194,23 @@ If they listed an older version of Cypress in their issue. We don't want to spen
|
||||
There will inevitably be suggestions that will not fit within the scope of Cypress's vision for our product. If an issue or pull request falls under this category you should:
|
||||
|
||||
- Thank them for their contribution.
|
||||
- Explain why it doesn’t fit into the scope of Cypress, and offer clear suggestions for improvement, if you’re able. Be kind, but firm.
|
||||
- Link to relevant documentation, if there is any. If you notice repeated requests for things you don’t want to accept, add them into the [documentation](https://github.com/cypress-io/cypress-documentation) to avoid repeating yourself.
|
||||
- Explain why it doesn't fit into the scope at Cypress, and offer clear suggestions for improvement, if you're able. Be kind, but firm.
|
||||
- Link to relevant documentation, if there is any. If you notice repeated requests for things that are not within scope, add them into the [documentation](https://github.com/cypress-io/cypress-documentation) to avoid repeating yourself.
|
||||
- Add the `stage: wontfix` label to the issue.
|
||||
- Close the issue/pull request
|
||||
- Close the issue/pull request.
|
||||
|
||||
### Is what they are describing actually happening?
|
||||
### Is what they're describing actually happening?
|
||||
|
||||
The best way to determine the validity of a bug is to recreate it yourself. Follow the directions or information provided to recreate the bug that is described. Did they provide a repository that demonstrates the bug? Great - fork it and run the project and steps required. If they did not provide a repository, the best way to reproduce the issue is to have a 'sandbox' project up and running locally for Cypress. This is just a simple project with Cypress installed where you can freely edit the application under test and the tests themselves to recreate the problem.
|
||||
The best way to determine the validity of a bug is to recreate it yourself. Follow the directions or information provided to recreate the bug that is described. Did they provide a repository that demonstrates the bug? Great - fork it and run the project and steps required. If they didn't provide a repository, the best way to reproduce the issue is to have a 'sandbox' project up and running locally for Cypress. This is just a simple project with Cypress installed where you can freely edit the application under test and the tests themselves to recreate the problem.
|
||||
|
||||
**Attempting to recreate the bug will lead to a few scenarios:**
|
||||
|
||||
#### 1. You can not recreate the bug
|
||||
#### 1. You can't recreate the bug
|
||||
|
||||
If you cannot recreate the situation happening you should:
|
||||
If you can't recreate the situation happening you should:
|
||||
|
||||
- Thank them for their contribution.
|
||||
- Explain that there is not enough information to reproduce the bug. Provide information on how you went about recreating the scenario, if you’re able. Note your OS, Browser, Cypress version and any other information.
|
||||
- Link them to our contributing guideline for [opening issues](#opening-issues).
|
||||
- Explain that there isn't enough information to reproduce the bug. Provide information on how you went about recreating the scenario, if you're able. Note your OS, Browser, Cypress version and any other information.
|
||||
- Note that if no reproducible example is provided, we will unfortunately have to close the issue.
|
||||
- Add the `stage: needs information` label to the issue.
|
||||
|
||||
@@ -216,7 +219,7 @@ The best way to determine the validity of a bug is to recreate it yourself. Foll
|
||||
If you can recreate the bug you should:
|
||||
|
||||
- Thank them for their contribution.
|
||||
- Explain that you were able to recreate the bug. Provide the exact test code ran and the versions of Cypress, OS, and browser you used to recreate it.
|
||||
- Explain that you're' able to recreate the bug. Provide the exact test code ran and the versions of Cypress, OS, and browser you used to recreate it.
|
||||
- If you know where the code is that could possibly fix this issue - link to the file or line of code from the [cypress](https://github.com/cypress-io/cypress) repo and remind the user that we are open source and that we gladly accept PRs, even if they are a work in progress.
|
||||
- Add the `stage: ready for work` label to the issue.
|
||||
|
||||
@@ -234,7 +237,7 @@ Some issues are opened and sadly forgotten about by the person originally openin
|
||||
|
||||
#### Not enough information ever provided
|
||||
|
||||
Sometimes we request more information to be provided (label `stage: needs information`) for an open issue, but no one is able to provide a reproducible example or they simply never respond. **This does not mean that we don't believe that there is a bug!** We just, unfortunately, do not have a path forward to fix it without this information. In this case you should:
|
||||
Sometimes we request more information to be provided (label `stage: needs information`) for an open issue, but no one is able to provide a reproducible example or they simply never respond. **This does not mean that we don't believe that there is a bug!** We just, unfortunately, don't have a path forward to fix it without this information. In this case you should:
|
||||
|
||||
- Add a comment reminding them or our request for more information and that the issue will be closed if it is not provided. Sometimes issues get forgotten about, and all the person needs is a gentle reminder.
|
||||
- If there is still no response after a weeks time, explain that you are closing the issue due to not enough information or inactivity and that they can comment in the issue with a reproducible example and we will reopen the issue.
|
||||
@@ -247,7 +250,6 @@ Some issues are resolved by the community, by giving some guidance or a workarou
|
||||
- Explain that you are closing the issue as resolved and that they can comment if they are still having the issue and we will consider reopening it.
|
||||
- Close the issue.
|
||||
|
||||
|
||||
## Writing Documentation
|
||||
|
||||
Cypress documentation lives in a separate repository with its own dependencies and build tools.
|
||||
@@ -312,7 +314,7 @@ We try to tag all issues with a `pkg/` or `npm/` tag describing the appropriate
|
||||
|
||||
### Requirements
|
||||
|
||||
You must have the following installed on your system to run the project:
|
||||
You must have the following installed on your system to contribute locally:
|
||||
|
||||
- [`Node.js`](https://nodejs.org/en/) (See the root [.node-version](.node-version) file for minimum version requirements. You can use [avn](https://github.com/wbyoung/avn) to automatically switch to the right version of Node.js for this repo.)
|
||||
- [`yarn`](https://yarnpkg.com/en/docs/install)
|
||||
@@ -372,7 +374,7 @@ $ yarn workspace @packages/server add my-new-dep1
|
||||
$ yarn workspace @packages/server add --dev my-new-dep1
|
||||
```
|
||||
|
||||
Alternatively, you can directly add the dependency to the corresponding `package.json`.
|
||||
Alternatively, you can directly add the dependency to the corresponding `package.json` and run `yarn`.
|
||||
|
||||
#### Tasks
|
||||
|
||||
@@ -477,7 +479,7 @@ When adding links to outside resources within the Cypress Test Runner (including
|
||||
This is to ensure that links do not go dead in older versions of Cypress when the location of the link has changed. To add a new link:
|
||||
|
||||
- Make up a new slug for the linked resource like `https://on.cypress.io/my-special-link`.
|
||||
- Open a PR adding the new slug in [links.yml](https://github.com/cypress-io/cypress-services/blob/develop/packages/on/data/links.yml) with the href of the resource it should redirect to. *Note: this requires access to the internal [cypress-services](https://github.com/cypress-io/cypress-services) repo which is only granted to employees. If you're an outside contributor and need a link reroute added, please comment in the relevant PR asking for assistance.*
|
||||
- Open a PR adding the new slug in [links.yml](https://github.com/cypress-io/cypress-services/blob/develop/packages/on/data/links.yml) with the href of the resource it should redirect to. *Note: this requires access to the internal [cypress-services](https://github.com/cypress-io/cypress-services) repo which is only granted to Cypress employees. If you're an outside contributor and need a link reroute added, please comment in the relevant PR asking for assistance.*
|
||||
- Wait for the PR to be reviewed and **deployed** from [cypress-services](https://github.com/cypress-io/cypress-services). This is required before your changes can be merged into the `cypress` project.
|
||||
|
||||
### Tests
|
||||
@@ -562,10 +564,13 @@ Independent packages are automatically released when code is merged into `master
|
||||
|
||||
### Pull Requests
|
||||
|
||||
- When opening a PR for a specific issue already open, please name the branch you are working on using the convention `issue-[issue number]`. For example, if your PR fixes Issue #803, name your branch `issue-803`. If the PR is a larger issue, you can add more context like `issue-803-new-scrollable-area` If there is not an associated open issue, **create an issue using our [Issue Template](./.github/ISSUE_TEMPLATE)**.
|
||||
- Break down pull requests into the smallest necessary parts to address the original issue or feature. This helps you get a timely review and helps the reviewer clearly understand which pieces of the code changes are relevant.
|
||||
- When opening a PR for a specific issue already open, please name the branch you are working on using the convention `issue-[issue number]`. For example, if your PR fixes Issue #803, name your branch `issue-803`. If the PR is a larger issue, you can add more context like `issue-803-new-scrollable-area`. If there's not an associated open issue, **[create an issue](https://github.com/cypress-io/cypress/issues/new/choose)**.
|
||||
- PR's can be opened before all the work is finished. In fact we encourage this! Please create a [Draft Pull Request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests) if your PR is not ready for review. [Mark the PR as **Ready for Review**](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/changing-the-stage-of-a-pull-request#marking-a-pull-request-as-ready-for-review) when you're ready for a Cypress team member to review the PR.
|
||||
- Prefix the title of the Pull Request using [semantic-release](https://github.com/semantic-release/semantic-release)'s format as defined [here](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#type). For example, if your PR is fixing a bug, you should prefix the PR title with `fix:`.
|
||||
- Fill out the [Pull Request Template](./.github/PULL_REQUEST_TEMPLATE.md) completely within the body of the PR. If you feel some areas are not relevant add `N/A` as opposed to deleting those sections. PR's will not be reviewed if this template is not filled in.
|
||||
- If the PR is a user facing change and you're a Cypress team member that has logged into [ZenHub](https://www.zenhub.com/) and downloaded the [ZenHub for GitHub extension](https://www.zenhub.com/extension), set the release the PR is intended to ship in from the sidebar of the PR. Follow semantic versioning to select the intended release. This is used to generate the changelog for the release. If you don't tag a PR for release, it won't be mentioned in the changelog.
|
||||

|
||||
- Please check the "Allow edits from maintainers" checkbox when submitting your PR. This will make it easier for the maintainers to make minor adjustments, to help with tests or any other changes we may need.
|
||||

|
||||
|
||||
@@ -589,7 +594,7 @@ If any of the Pull Request Review guidelines can't be met, a comment should be l
|
||||
- Run the code and use it as the end user would.
|
||||
- Double check the issue and PR description to ensure it is meeting the original requirements.
|
||||
- Read through every line of changed code (Yes, we know this could be a LOT).
|
||||
- If you don’t understand why some piece of code is required, ask for clarification! Likely the contributor had a reason and can provide the answer quicker than investigating yourself.
|
||||
- If you don't understand why some piece of code is required, ask for clarification! Likely the contributor had a reason and can provide the answer quicker than investigating yourself.
|
||||
|
||||
### Code Review Checklist
|
||||
|
||||
@@ -621,7 +626,8 @@ Below are guidelines to help during code review. If any of the following require
|
||||
- [ ] There's not a module from the ecosystem that should be used instead.
|
||||
- [ ] There is no redundant or duplicate code.
|
||||
- [ ] There are no irrelevant comments left in the code.
|
||||
- [ ] Tests are testing the code’s intended functionality in the best way possible.
|
||||
- [ ] There is no irrelevant code to the issue being addressed. If there is, ask the contributor to break the work out into a separate PR.
|
||||
- [ ] Tests are testing the code's intended functionality in the best way possible.
|
||||
|
||||
#### Internal
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"chrome:beta": "95.0.4638.32",
|
||||
"chrome:stable": "94.0.4606.71"
|
||||
"chrome:beta": "95.0.4638.49",
|
||||
"chrome:stable": "94.0.4606.81"
|
||||
}
|
||||
|
||||
+14
-1
@@ -425,7 +425,20 @@ commands:
|
||||
steps:
|
||||
- restore_cached_workspace
|
||||
- run:
|
||||
command: yarn workspace @packages/server test ./test/e2e/$(( $CIRCLE_NODE_INDEX ))_*spec* --browser <<parameters.browser>>
|
||||
command: |
|
||||
ALL_SPECS=`circleci tests glob "/root/cypress/packages/server/test/e2e/*spec*"`
|
||||
SPECS=
|
||||
for file in $ALL_SPECS; do
|
||||
# filter out non_root tests, they have their own stage
|
||||
if [[ "$file" == *"non_root"* ]]; then
|
||||
echo "Skipping $file"
|
||||
continue
|
||||
fi
|
||||
SPECS="$SPECS $file"
|
||||
done
|
||||
SPECS=`echo $SPECS | xargs -n 1 | circleci tests split --split-by=timings`
|
||||
echo SPECS=$SPECS
|
||||
yarn workspace @packages/server test $SPECS --browser <<parameters.browser>>
|
||||
- verify-mocha-results
|
||||
- store_test_results:
|
||||
path: /tmp/cypress
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ yarn test-watch --scope cypress
|
||||
yarn test-debug --scope cypress
|
||||
```
|
||||
|
||||
### Updating snaphots
|
||||
### Updating snapshots
|
||||
|
||||
Prepend `SNAPSHOT_UPDATE=1` to any test command. See [`snap-shot-it` instructions](https://github.com/bahmutov/snap-shot-it#advanced-use) for more info.
|
||||
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@
|
||||
"@types/jquery": "3.3.31",
|
||||
"@types/lodash": "4.14.168",
|
||||
"@types/minimatch": "3.0.3",
|
||||
"@types/mocha": "5.2.7",
|
||||
"@types/mocha": "8.0.3",
|
||||
"@types/sinon": "7.5.1",
|
||||
"@types/sinon-chai": "3.2.5",
|
||||
"chai": "3.5.0",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
const { includeTypes } = require('./utils')
|
||||
const shell = require('shelljs')
|
||||
const fs = require('fs')
|
||||
const { join } = require('path')
|
||||
const resolvePkg = require('resolve-pkg')
|
||||
|
||||
@@ -72,3 +73,23 @@ shell.sed('-i', 'from \'sinon\';', 'from \'../sinon\';', sinonChaiFilename)
|
||||
// copy experimental network stubbing type definitions
|
||||
// so users can import: `import 'cypress/types/net-stubbing'`
|
||||
shell.cp(resolvePkg('@packages/net-stubbing/lib/external-types.ts'), 'types/net-stubbing.ts')
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/18069
|
||||
// To avoid type clashes, some files should be commented out entirely by patch-package
|
||||
// and uncommented here.
|
||||
|
||||
const filesToUncomment = [
|
||||
'mocha/index.d.ts',
|
||||
'jquery/JQuery.d.ts',
|
||||
'jquery/legacy.d.ts',
|
||||
'jquery/misc.d.ts',
|
||||
]
|
||||
|
||||
filesToUncomment.forEach((file) => {
|
||||
const filePath = join(__dirname, '../types', file)
|
||||
const str = fs.readFileSync(filePath).toString()
|
||||
|
||||
const result = str.split('\n').map((line) => line.substring(3)).join('\n')
|
||||
|
||||
fs.writeFileSync(filePath, result)
|
||||
})
|
||||
|
||||
Vendored
+3
-2
@@ -1,11 +1,12 @@
|
||||
// Shim definition to export a namespace. Cypress is actually a global module
|
||||
// so import/export isn't allowed there. We import here and define a global module
|
||||
// so that Cypress can get and use the Blob type
|
||||
import BluebirdStatic = require('./bluebird')
|
||||
import ImportedBluebird = require('./bluebird')
|
||||
|
||||
export = Bluebird
|
||||
export as namespace Bluebird
|
||||
|
||||
declare namespace Bluebird {
|
||||
type BluebirdStatic = typeof BluebirdStatic
|
||||
type BluebirdStatic = typeof ImportedBluebird
|
||||
interface Promise<T> extends ImportedBluebird<T> {}
|
||||
}
|
||||
|
||||
Vendored
+7
-2
@@ -170,6 +170,11 @@ declare namespace Cypress {
|
||||
*/
|
||||
interface ApplicationWindow { } // tslint:disable-line
|
||||
|
||||
/**
|
||||
* The configuration for Cypress.
|
||||
*/
|
||||
type Config = ResolvedConfigOptions & RuntimeConfigOptions
|
||||
|
||||
/**
|
||||
* Several libraries are bundled with Cypress by default.
|
||||
*
|
||||
@@ -297,7 +302,7 @@ declare namespace Cypress {
|
||||
/**
|
||||
* Fire automation:request event for internal use.
|
||||
*/
|
||||
automation(eventName: string, ...args: any[]): Promise<any>
|
||||
automation(eventName: string, ...args: any[]): Bluebird.Promise<any>
|
||||
|
||||
/**
|
||||
* Promise wrapper for certain internal tasks.
|
||||
@@ -313,7 +318,7 @@ declare namespace Cypress {
|
||||
// {defaultCommandTimeout: 10000, pageLoadTimeout: 30000, ...}
|
||||
```
|
||||
*/
|
||||
config(): ResolvedConfigOptions & RuntimeConfigOptions
|
||||
config(): Config
|
||||
/**
|
||||
* Returns one configuration value.
|
||||
* @see https://on.cypress.io/config
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/// <reference path="../../../../../cli/types/mocha/index.d.ts" />
|
||||
|
||||
import * as babel from '@babel/core'
|
||||
import { expect } from 'chai'
|
||||
import { createTransformPluginsFileBabelPlugin } from './babelTransform'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/// <reference path="../../../../../cli/types/mocha/index.d.ts" />
|
||||
|
||||
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'
|
||||
import { join, resolve } from 'path'
|
||||
import { expect } from 'chai'
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
# [@cypress/react-v5.10.1](https://github.com/cypress-io/cypress/compare/@cypress/react-v5.10.0...@cypress/react-v5.10.1) (2021-10-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* configure proper pages directory for next application ([#18009](https://github.com/cypress-io/cypress/issues/18009)) ([70c7c36](https://github.com/cypress-io/cypress/commit/70c7c3678180d5408c144fa37f94ba5f5f8ceeb8))
|
||||
* next trace error ([#18189](https://github.com/cypress-io/cypress/issues/18189)) ([db6f909](https://github.com/cypress-io/cypress/commit/db6f9096bd6668db1937d0e38d3928866f6cd5df))
|
||||
|
||||
# [@cypress/react-v5.10.0](https://github.com/cypress-io/cypress/compare/@cypress/react-v5.9.4...@cypress/react-v5.10.0) (2021-09-10)
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
# [@cypress/vite-dev-server-v2.1.1](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v2.1.0...@cypress/vite-dev-server-v2.1.1) (2021-10-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **vite-dev-server:** remove base and root from inlineVitConfig types ([#17180](https://github.com/cypress-io/cypress/issues/17180)) ([07e7d0e](https://github.com/cypress-io/cypress/commit/07e7d0ed252bf1a2bd3224f617e1fc2e64f19a06))
|
||||
* **vite-dev-server:** replace UserConfig with InlineConfig to allow correct `configFile` types ([#18167](https://github.com/cypress-io/cypress/issues/18167)) ([6e0c2c1](https://github.com/cypress-io/cypress/commit/6e0c2c1af81be750a74bad0528d52de45746a453))
|
||||
* **vite-dev-server:** windows `supportFile` + preserve optimize entries ([#18286](https://github.com/cypress-io/cypress/issues/18286)) ([ea2f6a4](https://github.com/cypress-io/cypress/commit/ea2f6a45c7057e51b2fc879ff70da75538fa1002))
|
||||
|
||||
# [@cypress/vite-dev-server-v2.1.0](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v2.0.8...@cypress/vite-dev-server-v2.1.0) (2021-09-10)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* This file is intended to test the new normalized signature
|
||||
* of devServers. To make the test shorter we only test
|
||||
* the smkoke test here
|
||||
*/
|
||||
|
||||
const path = require('path')
|
||||
const { devServer, defineDevServerConfig } = require('../../dist')
|
||||
|
||||
module.exports = (on, config) => {
|
||||
on('dev-server:start', async (options) => {
|
||||
return devServer(
|
||||
options,
|
||||
defineDevServerConfig({
|
||||
configFile: path.resolve(__dirname, '..', '..', 'vite.config.ts'),
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
config.testFiles = '**/smoke.spec.ts'
|
||||
|
||||
return config
|
||||
}
|
||||
@@ -8,7 +8,8 @@
|
||||
"build-prod": "tsc",
|
||||
"cy:open": "node ../../scripts/cypress.js open-ct --project ${PWD}",
|
||||
"cy:run": "node ../../scripts/cypress.js run-ct --project ${PWD}",
|
||||
"test": "yarn cy:run",
|
||||
"cy:run-signature": "yarn cy:run --config=\"{\\\"pluginsFile\\\":\\\"cypress/new-signature/plugins.js\\\"}\"",
|
||||
"test": "yarn cy:run && yarn cy:run-signature",
|
||||
"watch": "tsc -w"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { debug as debugFn } from 'debug'
|
||||
import { InlineConfig } from 'vite'
|
||||
import { start as createDevServer, StartDevServerOptions } from './startServer'
|
||||
const debug = debugFn('cypress:vite-dev-server:vite')
|
||||
|
||||
@@ -14,3 +15,13 @@ export async function startDevServer (startDevServerArgs: StartDevServerOptions)
|
||||
|
||||
return { port, close: app.httpServer!.close }
|
||||
}
|
||||
|
||||
export type CypressViteDevServerConfig = Omit<InlineConfig, 'base' | 'root'>
|
||||
|
||||
export function devServer (cypressDevServerConfig: Cypress.DevServerConfig, devServerConfig?: CypressViteDevServerConfig) {
|
||||
return startDevServer({ options: cypressDevServerConfig, viteConfig: devServerConfig })
|
||||
}
|
||||
|
||||
export function defineDevServerConfig (devServerConfig: CypressViteDevServerConfig) {
|
||||
return devServerConfig
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { debug as debugFn } from 'debug'
|
||||
import { AddressInfo } from 'net'
|
||||
import { Server } from 'http'
|
||||
import { start as createDevServer, StartDevServer } from './startServer'
|
||||
import { start as createDevServer, StartDevServer, WebpackConfigurationWithDevServer } from './startServer'
|
||||
import { webpackDevServerFacts } from './webpackDevServerFacts'
|
||||
|
||||
const debug = debugFn('cypress:webpack-dev-server:webpack')
|
||||
@@ -56,3 +56,22 @@ export async function startDevServer (startDevServerArgs: StartDevServer, exitPr
|
||||
reject(webpackDevServerFacts.unsupported())
|
||||
})
|
||||
}
|
||||
|
||||
export interface CypressWebpackDevServerConfig{
|
||||
/* support passing a path to the user's webpack config */
|
||||
webpackConfig?: WebpackConfigurationWithDevServer
|
||||
/* base html template to render in AUT */
|
||||
template?: string
|
||||
}
|
||||
|
||||
export function devServer (cypressDevServerConfig: Cypress.DevServerConfig, devServerConfig?: CypressWebpackDevServerConfig) {
|
||||
return startDevServer({
|
||||
options: cypressDevServerConfig,
|
||||
webpackConfig: devServerConfig?.webpackConfig,
|
||||
template: devServerConfig?.template,
|
||||
})
|
||||
}
|
||||
|
||||
export function defineDevServerConfig (devServerConfig: CypressWebpackDevServerConfig) {
|
||||
return devServerConfig
|
||||
}
|
||||
|
||||
@@ -7,12 +7,16 @@ import { webpackDevServerFacts } from './webpackDevServerFacts'
|
||||
export interface StartDevServer extends UserWebpackDevServerOptions {
|
||||
/* this is the Cypress dev server configuration object */
|
||||
options: Cypress.DevServerConfig
|
||||
/* support passing a path to the user's webpack config */
|
||||
webpackConfig?: Record<string, any>
|
||||
/* Base webpack config object used for loading component testing */
|
||||
webpackConfig?: WebpackConfigurationWithDevServer
|
||||
/* base html template to render in AUT */
|
||||
template?: string
|
||||
}
|
||||
|
||||
export interface WebpackConfigurationWithDevServer extends webpack.Configuration {
|
||||
devServer?: WebpackDevServer.Configuration
|
||||
}
|
||||
|
||||
const debug = Debug('cypress:webpack-dev-server:start')
|
||||
|
||||
export async function start ({ webpackConfig: userWebpackConfig, template, options, ...userOptions }: StartDevServer, exitProcess = process.exit): Promise<WebpackDevServer> {
|
||||
@@ -49,7 +53,7 @@ export async function start ({ webpackConfig: userWebpackConfig, template, optio
|
||||
|
||||
debug('starting webpack dev server')
|
||||
let webpackDevServerConfig: WebpackDevServer.Configuration = {
|
||||
...userWebpackConfig?.devServer,
|
||||
...(userWebpackConfig?.devServer || {}),
|
||||
hot: false,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import http from 'http'
|
||||
import fs from 'fs'
|
||||
import { webpackDevServerFacts } from '../src/webpackDevServerFacts'
|
||||
|
||||
import { startDevServer } from '../'
|
||||
import { defineDevServerConfig, devServer, startDevServer } from '../'
|
||||
|
||||
const requestSpecFile = (port: number) => {
|
||||
return new Promise((res) => {
|
||||
@@ -155,4 +155,24 @@ describe('#startDevServer', () => {
|
||||
close(() => res())
|
||||
})
|
||||
})
|
||||
|
||||
it('accepts the devServer signature', async function () {
|
||||
const devServerEvents = new EventEmitter()
|
||||
const { port, close } = await devServer(
|
||||
{
|
||||
config,
|
||||
specs,
|
||||
devServerEvents,
|
||||
},
|
||||
defineDevServerConfig({ webpackConfig }),
|
||||
)
|
||||
|
||||
const response = await requestSpecFile(port as number)
|
||||
|
||||
expect(response).to.eq('const foo = () => {}\n')
|
||||
|
||||
return new Promise((res) => {
|
||||
close(() => res())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cypress",
|
||||
"version": "8.5.0",
|
||||
"version": "8.6.0",
|
||||
"description": "Cypress.io end to end testing tool",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -90,7 +90,7 @@
|
||||
"@types/glob": "7.1.1",
|
||||
"@types/lodash": "4.14.168",
|
||||
"@types/markdown-it": "0.0.9",
|
||||
"@types/mini-css-extract-plugin": "1.4.2",
|
||||
"@types/mini-css-extract-plugin": "1.2.3",
|
||||
"@types/mocha": "8.0.3",
|
||||
"@types/node": "14.14.31",
|
||||
"@types/prismjs": "1.16.0",
|
||||
@@ -165,7 +165,7 @@
|
||||
"mock-fs": "4.9.0",
|
||||
"odiff-bin": "2.1.0",
|
||||
"parse-github-repo-url": "1.4.1",
|
||||
"patch-package": "6.2.2",
|
||||
"patch-package": "6.4.7",
|
||||
"plist": "3.0.1",
|
||||
"pluralize": "8.0.0",
|
||||
"postinstall-postinstall": "2.0.0",
|
||||
|
||||
@@ -437,11 +437,17 @@ describe('Project Nav', function () {
|
||||
cy.get('.browsers .fa-exclamation-triangle').trigger('mouseover')
|
||||
|
||||
cy.get('.cy-tooltip').should('contain', 'Cypress detected policy settings on your computer that may cause issues with using this browser. For more information, see')
|
||||
cy.get('.cy-tooltip a').click().then(function () {
|
||||
|
||||
// prevent tooltips from being hidden so we can snapshot the state
|
||||
// of the browser warning tooltip
|
||||
cy.percySnapshot({ elementOverrides: [] })
|
||||
|
||||
cy
|
||||
.get('.cy-tooltip a')
|
||||
.click()
|
||||
.then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWith('https://on.cypress.io/bad-browser-policy')
|
||||
})
|
||||
|
||||
cy.percySnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -98,5 +98,32 @@ describe('src/cy/commands/debugging', () => {
|
||||
expect(cy.state('onPaused')).to.be.null
|
||||
})
|
||||
})
|
||||
|
||||
it('can pause in run mode with --headed and --no-exit', function () {
|
||||
let didPause = false
|
||||
|
||||
Cypress.config('isInteractive', false)
|
||||
Cypress.config('browser').isHeaded = true
|
||||
Cypress.config('exit', false)
|
||||
|
||||
cy.once('paused', (name) => {
|
||||
cy.once('paused', (name) => {
|
||||
didPause = true
|
||||
|
||||
// resume the rest of the commands so this
|
||||
// test ends
|
||||
Cypress.emit('resume:all')
|
||||
})
|
||||
|
||||
Cypress.emit('resume:next')
|
||||
})
|
||||
|
||||
cy.pause().wrap({}).should('deep.eq', {}).then(function () {
|
||||
expect(didPause).to.be.true
|
||||
|
||||
// should no longer have onPaused
|
||||
expect(cy.state('onPaused')).to.be.null
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ const { Screenshot } = Cypress
|
||||
const DEFAULTS = {
|
||||
capture: 'fullPage',
|
||||
scale: false,
|
||||
overwrite: false,
|
||||
disableTimersAndAnimations: true,
|
||||
screenshotOnRunFailure: true,
|
||||
blackout: [],
|
||||
@@ -64,6 +65,14 @@ describe('src/cypress/screenshot', () => {
|
||||
expect(Screenshot.getConfig().scale).to.equal(true)
|
||||
})
|
||||
|
||||
it('sets overwrite if specified', () => {
|
||||
Screenshot.defaults({
|
||||
overwrite: true,
|
||||
})
|
||||
|
||||
expect(Screenshot.getConfig().overwrite).to.equal(true)
|
||||
})
|
||||
|
||||
it('sets disableTimersAndAnimations if specified', () => {
|
||||
Screenshot.defaults({
|
||||
disableTimersAndAnimations: false,
|
||||
@@ -187,6 +196,20 @@ describe('src/cypress/screenshot', () => {
|
||||
.and.eq('https://on.cypress.io/screenshot-api')
|
||||
})
|
||||
|
||||
it('throws if overwrite is not a boolean', () => {
|
||||
const fn = () => {
|
||||
Screenshot.defaults({ overwrite: 'foo' })
|
||||
}
|
||||
|
||||
expect(fn).to.throw()
|
||||
.with.property('message')
|
||||
.and.include('`Cypress.Screenshot.defaults()` `overwrite` option must be a boolean. You passed: `foo`')
|
||||
|
||||
expect(fn).to.throw()
|
||||
.with.property('docsUrl')
|
||||
.and.eq('https://on.cypress.io/screenshot-api')
|
||||
})
|
||||
|
||||
it('throws if disableTimersAndAnimations is not a boolean', () => {
|
||||
const fn = () => {
|
||||
Screenshot.defaults({ disableTimersAndAnimations: 'foo' })
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// @ts-ignore
|
||||
const { $, dom } = Cypress
|
||||
|
||||
describe('src/cypress/dom/visibility', () => {
|
||||
|
||||
Vendored
+3
-2
@@ -1,6 +1,7 @@
|
||||
/// <reference path="../../cli/types/index.d.ts" />
|
||||
/// <reference path="../ts/index.d.ts" />
|
||||
/// <reference path="../../cli/types/jquery/index.d.ts" />
|
||||
|
||||
export const $Cypress: Cypress.Cypress
|
||||
|
||||
export const $: typeof JQuery
|
||||
export const $: JQuery
|
||||
export default $Cypress
|
||||
@@ -1,3 +1,15 @@
|
||||
/// <reference path="../../cli/types/chai-jquery/index.d.ts" />
|
||||
/// <reference path="../../cli/types/sinon-chai/index.d.ts" />
|
||||
/// <reference path="../../cli/types/cypress-expect.d.ts" />
|
||||
|
||||
/// <reference path="../ts/index.d.ts" />
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
Cypress: Cypress.Cypress
|
||||
}
|
||||
}
|
||||
|
||||
import $Cypress from './src/main'
|
||||
|
||||
export default $Cypress
|
||||
|
||||
@@ -26,8 +26,10 @@
|
||||
"@sinonjs/fake-timers": "7.0.2",
|
||||
"@types/chalk": "^2.2.0",
|
||||
"@types/common-tags": "^1.8.0",
|
||||
"@types/jquery.scrollto": "1.4.29",
|
||||
"@types/lodash": "^4.14.168",
|
||||
"@types/mocha": "^8.0.3",
|
||||
"@types/underscore.string": "0.0.38",
|
||||
"angular": "1.8.0",
|
||||
"basic-auth": "2.0.1",
|
||||
"blob-util": "2.0.2",
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
* @version 2.1.3
|
||||
*/
|
||||
|
||||
/// <reference types="jquery.scrollto" />
|
||||
|
||||
/** eslint-disable */
|
||||
import $ from 'jquery'
|
||||
|
||||
@@ -109,7 +111,7 @@ export function scrollTo (target, duration, settings) {
|
||||
let max = $scrollTo.max(elem, axis)
|
||||
|
||||
if (toff) { // jQuery / DOMElement
|
||||
attr[key] = toff[pos] + (win ? 0 : prev - $elem.offset()[pos])
|
||||
attr[key] = toff[pos] + (win ? 0 : prev - $elem.offset()![pos])
|
||||
|
||||
// If it's a dom element, reduce the margin
|
||||
if (settings.margin) {
|
||||
@@ -192,18 +194,25 @@ function both (val) {
|
||||
return isFunction(val) || $.isPlainObject(val) ? val : { top: val, left: val }
|
||||
}
|
||||
|
||||
// TODO: find the type of _last in the JQuery code.
|
||||
interface Tween extends JQuery.Tween<JQuery.Node> {
|
||||
_last: any
|
||||
}
|
||||
|
||||
// Add special hooks so that window scroll properties can be animated
|
||||
$.Tween.propHooks.scrollLeft =
|
||||
$.Tween.propHooks.scrollTop = {
|
||||
get (t) {
|
||||
return $(t.elem)[t.prop]()
|
||||
},
|
||||
set (t) {
|
||||
set (t: Tween) {
|
||||
let curr = this.get(t)
|
||||
|
||||
// If interrupt is true and user scrolled, stop animating
|
||||
if (t.options.interrupt && t._last && t._last !== curr) {
|
||||
return $(t.elem).stop()
|
||||
$(t.elem).stop()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let next = Math.round(t.now)
|
||||
|
||||
@@ -10,3 +10,12 @@ _.mixin({
|
||||
})
|
||||
|
||||
export default _
|
||||
|
||||
declare module 'lodash' {
|
||||
interface LoDashStatic {
|
||||
clean: typeof clean
|
||||
count: typeof count
|
||||
isBlank: typeof isBlank
|
||||
toBoolean: typeof toBoolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,10 +33,21 @@ const formatMouseEvents = (events) => {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: remove any, Function, Record
|
||||
type MouseActionOptions = {
|
||||
subject: any
|
||||
positionOrX: string | number
|
||||
y: number
|
||||
userOptions: Record<string, any>
|
||||
onReady: Function
|
||||
onTable: Function
|
||||
defaultOptions?: Record<string, any>
|
||||
}
|
||||
|
||||
export default (Commands, Cypress, cy, state, config) => {
|
||||
const { mouse, keyboard } = cy.devices
|
||||
|
||||
const mouseAction = (eventName, { subject, positionOrX, y, userOptions, onReady, onTable, defaultOptions }) => {
|
||||
const mouseAction = (eventName, { subject, positionOrX, y, userOptions, onReady, onTable, defaultOptions }: MouseActionOptions) => {
|
||||
let position
|
||||
let x
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ import $elements from '../../../dom/elements'
|
||||
|
||||
export default (Commands, Cypress, cy) => {
|
||||
return Commands.addAll({ prevSubject: ['element', 'window'] }, {
|
||||
focus (subject, options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable & Cypress.Timeoutable>
|
||||
focus (subject, options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
// we should throw errors by default!
|
||||
@@ -84,7 +85,8 @@ export default (Commands, Cypress, cy) => {
|
||||
return verifyAssertions()
|
||||
},
|
||||
|
||||
blur (subject, options = {}) {
|
||||
// TODO: any -> Partial<Cypress.BlurOptions>
|
||||
blur (subject, options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
// we should throw errors by default!
|
||||
|
||||
@@ -30,7 +30,8 @@ const isNaNOrInfinity = (item) => {
|
||||
|
||||
export default (Commands, Cypress, cy, state) => {
|
||||
Commands.addAll({ prevSubject: 'element' }, {
|
||||
scrollIntoView (subject, options = {}) {
|
||||
// TODO: any -> Partial<Cypress.ScrollToOptions>
|
||||
scrollIntoView (subject, options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
if (!_.isObject(userOptions)) {
|
||||
@@ -114,6 +115,9 @@ export default (Commands, Cypress, cy, state) => {
|
||||
const scrollIntoView = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// scroll our axes
|
||||
// TODO: done() came from jQuery animate(), specifically, EffectsOptions at misc.d.ts
|
||||
// The type definition should be fixed at @types/jquery.scrollto.
|
||||
// @ts-ignore
|
||||
return $(options.$parent).scrollTo(options.$el, {
|
||||
axis: options.axis,
|
||||
easing: options.easing,
|
||||
@@ -132,7 +136,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
},
|
||||
always () {
|
||||
if (parentIsWin) {
|
||||
return delete options.$parent.contentWindow
|
||||
delete options.$parent.contentWindow
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -153,7 +157,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
})
|
||||
|
||||
Commands.addAll({ prevSubject: ['optional', 'element', 'window'] }, {
|
||||
scrollTo (subject, xOrPosition, yOrOptions, options = {}) {
|
||||
// TODO: any -> Partial<Cypress.ScrollToOptions>
|
||||
scrollTo (subject, xOrPosition, yOrOptions, options: any = {}) {
|
||||
let x; let y
|
||||
let userOptions = options
|
||||
|
||||
@@ -168,7 +173,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
y = yOrOptions
|
||||
}
|
||||
|
||||
let position = null
|
||||
let position: string | null = null
|
||||
|
||||
// we may be '50%' or 'bottomCenter'
|
||||
if (_.isString(xOrPosition)) {
|
||||
@@ -293,7 +298,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
$utils.filterOutOptions(options, { duration: 0, easing: 'swing' }),
|
||||
)
|
||||
|
||||
const messageArgs = []
|
||||
const messageArgs: string[] = []
|
||||
|
||||
if (position) {
|
||||
messageArgs.push(position)
|
||||
@@ -306,12 +311,12 @@ export default (Commands, Cypress, cy, state) => {
|
||||
messageArgs.push(deltaOptions)
|
||||
}
|
||||
|
||||
const log = {
|
||||
const log: Record<string, any> = {
|
||||
message: messageArgs.join(', '),
|
||||
timeout: options.timeout,
|
||||
consoleProps () {
|
||||
// merge into consoleProps without mutating it
|
||||
const obj = {}
|
||||
const obj: Record<string, any> = {}
|
||||
|
||||
if (position) {
|
||||
obj.Position = position
|
||||
@@ -357,10 +362,16 @@ export default (Commands, Cypress, cy, state) => {
|
||||
const scrollTo = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// scroll our axis'
|
||||
// TODO: done() came from jQuery animate(), specifically, EffectsOptions at misc.d.ts
|
||||
// The type definition should be fixed at @types/jquery.scrollto.
|
||||
// @ts-ignore
|
||||
$(options.$el).scrollTo({ left: x, top: y }, {
|
||||
axis: options.axis,
|
||||
easing: options.easing,
|
||||
duration: options.duration,
|
||||
// TODO: ensureScrollable option does not exist on jQuery or config/jquery.scrollto.ts.
|
||||
// It can be removed.
|
||||
// @ts-ignore
|
||||
ensureScrollable: options.ensureScrollable,
|
||||
done () {
|
||||
return resolve(options.$el)
|
||||
@@ -376,7 +387,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
})
|
||||
|
||||
if (isWin) {
|
||||
return delete options.$el.contentWindow
|
||||
delete options.$el.contentWindow
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ const newLineRe = /\n/g
|
||||
|
||||
export default (Commands, Cypress, cy) => {
|
||||
Commands.addAll({ prevSubject: 'element' }, {
|
||||
select (subject, valueOrTextOrIndex, options = {}) {
|
||||
// TODO: any -> Partial<Cypress.SelectOptions>
|
||||
select (subject, valueOrTextOrIndex, options: any = {}) {
|
||||
if (
|
||||
!_.isNumber(valueOrTextOrIndex)
|
||||
&& !_.isString(valueOrTextOrIndex)
|
||||
@@ -35,7 +36,7 @@ export default (Commands, Cypress, cy) => {
|
||||
force: false,
|
||||
})
|
||||
|
||||
const consoleProps = {}
|
||||
const consoleProps: Record<string, any> = {}
|
||||
|
||||
if (options.log) {
|
||||
// figure out the options which actually change the behavior of clicks
|
||||
@@ -80,7 +81,7 @@ export default (Commands, Cypress, cy) => {
|
||||
}
|
||||
|
||||
// normalize valueOrTextOrIndex if its not an array
|
||||
valueOrTextOrIndex = [].concat(valueOrTextOrIndex).map((v) => {
|
||||
valueOrTextOrIndex = [].concat(valueOrTextOrIndex).map((v: any) => {
|
||||
if (_.isNumber(v) && (!_.isInteger(v) || v < 0)) {
|
||||
$errUtils.throwErrByPath('select.invalid_number', { args: { index: v } })
|
||||
}
|
||||
@@ -108,8 +109,8 @@ export default (Commands, Cypress, cy) => {
|
||||
$errUtils.throwErrByPath('select.disabled', { args: { node } })
|
||||
}
|
||||
|
||||
const values = []
|
||||
const optionEls = []
|
||||
const values: string[] = []
|
||||
const optionEls: JQuery<any>[] = []
|
||||
const optionsObjects = options.$el.find('option').map((index, el) => {
|
||||
// push the value in values array if its
|
||||
// found within the valueOrText
|
||||
@@ -266,7 +267,7 @@ export default (Commands, Cypress, cy) => {
|
||||
let selectedIndex = 0
|
||||
|
||||
_.each(optionEls, ($el) => {
|
||||
const index = _.findIndex(optionsObjects, (optionObject) => {
|
||||
const index = _.findIndex(optionsObjects, (optionObject: any) => {
|
||||
return $el.text() === optionObject.originalText
|
||||
})
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ import $actionability from '../../actionability'
|
||||
|
||||
export default (Commands, Cypress, cy) => {
|
||||
Commands.addAll({ prevSubject: 'element' }, {
|
||||
submit (subject, options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable & Cypress.Timeoutable>
|
||||
submit (subject, options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
options = _.defaults({}, userOptions, {
|
||||
|
||||
@@ -47,8 +47,8 @@ export default (Commands, Cypress, cy, state, config) => {
|
||||
// pause should indefinitely pause until the user
|
||||
// presses a key or clicks in the UI to continue
|
||||
pause (subject, options = {}) {
|
||||
// bail if we're headless
|
||||
if (!config('isInteractive')) {
|
||||
// bail if we're in run mode, unless --headed and --no-exit flags are passed
|
||||
if (!config('isInteractive') && (!config('browser').isHeaded || config('exit'))) {
|
||||
return subject
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
})
|
||||
|
||||
Commands.addAll({
|
||||
clearLocalStorage (keys, options = {}) {
|
||||
clearLocalStorage (keys, options: Partial<Cypress.Loggable> = {}) {
|
||||
if (_.isPlainObject(keys)) {
|
||||
options = keys
|
||||
keys = null
|
||||
|
||||
@@ -10,7 +10,8 @@ import { getAliasedRequests, isDynamicAliasingPossible } from '../net-stubbing/a
|
||||
|
||||
export default (Commands, Cypress, cy, state) => {
|
||||
Commands.addAll({
|
||||
focused (options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable & Cypress.Timeoutable>
|
||||
focused (options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
options = _.defaults({}, userOptions, {
|
||||
@@ -71,7 +72,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
return resolveFocused()
|
||||
},
|
||||
|
||||
get (selector, options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable & Cypress.Timeoutable & Cypress.Withinable & Cypress.Shadow>
|
||||
get (selector, options: any = {}) {
|
||||
const userOptions = options
|
||||
const ctx = this
|
||||
|
||||
@@ -92,7 +94,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
options.includeShadowDom = resolveShadowDomInclusion(Cypress, userOptions.includeShadowDom)
|
||||
|
||||
let aliasObj
|
||||
const consoleProps = {}
|
||||
const consoleProps: Record<string, any> = {}
|
||||
const start = (aliasType) => {
|
||||
if (options.log === false) {
|
||||
return
|
||||
@@ -120,7 +122,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
start(aliasType)
|
||||
}
|
||||
|
||||
const obj = {}
|
||||
const obj: any = {}
|
||||
|
||||
if (aliasType === 'dom') {
|
||||
_.extend(obj, {
|
||||
@@ -226,7 +228,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
// within our subject then filter out
|
||||
// anything not currently in the DOM
|
||||
if ($dom.isDetached(subject)) {
|
||||
subject = subject.filter((index, el) => $dom.isAttached(el))
|
||||
subject = (subject as any).filter((index, el) => $dom.isAttached(el))
|
||||
|
||||
// if we have nothing left
|
||||
// just go replay the commands
|
||||
@@ -246,6 +248,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
if ((err.type === 'length') && (err.actual < err.expected)) {
|
||||
return replayFrom = true
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
onRetry () {
|
||||
if (replayFrom) {
|
||||
@@ -347,7 +351,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
if ($el.selector == null) {
|
||||
$el.selector = selector
|
||||
}
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
// this is usually a sizzle error (invalid selector)
|
||||
err.onFail = () => {
|
||||
if (options.log === false) {
|
||||
@@ -407,7 +411,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
return resolveElements()
|
||||
},
|
||||
|
||||
root (options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable & Cypress.Timeoutable>
|
||||
root (options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
options = _.defaults({}, userOptions, { log: true })
|
||||
@@ -438,7 +443,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
})
|
||||
|
||||
Commands.addAll({ prevSubject: ['optional', 'window', 'document', 'element'] }, {
|
||||
contains (subject, filter, text, options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable & Cypress.Timeoutable & Cypress.CaseMatchable & Cypress.Shadow>
|
||||
contains (subject, filter, text, options: any = {}) {
|
||||
let userOptions = options
|
||||
|
||||
// nuke our subject if its present but not an element.
|
||||
@@ -516,6 +522,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
|
||||
return `Expected to find content: '${text}' ${getPhrase()}but never did.`
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
let consoleProps
|
||||
@@ -583,6 +591,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
})
|
||||
})
|
||||
@@ -697,7 +707,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
|
||||
options = _.defaults({}, userOptions, { log: true })
|
||||
|
||||
const consoleProps = {
|
||||
const consoleProps: Record<string, any> = {
|
||||
'Applied To': $dom.getElements(subject),
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ const whichAreOptional = (val, key) => {
|
||||
return (val === null) && OPTIONAL_OPTS.includes(key)
|
||||
}
|
||||
|
||||
const needsFormSpecified = (options = {}) => {
|
||||
const needsFormSpecified = (options: any = {}) => {
|
||||
const { body, json, headers } = options
|
||||
|
||||
// json isn't true, and we have an object body and the user
|
||||
@@ -58,13 +58,19 @@ const needsFormSpecified = (options = {}) => {
|
||||
return (json !== true) && _.isObject(body) && hasFormUrlEncodedContentTypeHeader(headers)
|
||||
}
|
||||
|
||||
interface BackendError {
|
||||
backend: boolean
|
||||
message?: string
|
||||
stack?: any
|
||||
}
|
||||
|
||||
export default (Commands, Cypress, cy, state, config) => {
|
||||
Commands.addAll({
|
||||
// allow our signature to be similar to cy.route
|
||||
// METHOD / URL / BODY
|
||||
// or object literal with all expanded options
|
||||
request (...args) {
|
||||
const o = {}
|
||||
const o: any = {}
|
||||
const userOptions = o
|
||||
|
||||
if (_.isObject(args[0])) {
|
||||
@@ -297,7 +303,11 @@ export default (Commands, Cypress, cy, state, config) => {
|
||||
|
||||
// reset content-type
|
||||
if (requestOpts.headers) {
|
||||
delete requestOpts.headers[Object.keys(requestOpts).find((key) => key.toLowerCase() === 'content-type')]
|
||||
const contentTypeKey = Object.keys(requestOpts).find((key) => key.toLowerCase() === 'content-type')
|
||||
|
||||
if (contentTypeKey) {
|
||||
delete requestOpts.headers[contentTypeKey]
|
||||
}
|
||||
} else {
|
||||
requestOpts.headers = {}
|
||||
}
|
||||
@@ -308,7 +318,7 @@ export default (Commands, Cypress, cy, state, config) => {
|
||||
|
||||
// socket.io ignores FormData.
|
||||
// So, we need to encode the data into base64 string format.
|
||||
const formBody = []
|
||||
const formBody: string[] = []
|
||||
|
||||
requestOpts.body.forEach((value, key) => {
|
||||
// HTTP line break style is \r\n.
|
||||
@@ -373,7 +383,7 @@ export default (Commands, Cypress, cy, state, config) => {
|
||||
timeout: options.timeout,
|
||||
},
|
||||
})
|
||||
}).catch({ backend: true }, (err) => {
|
||||
}).catch<void, BackendError>({ backend: true }, (err: BackendError) => {
|
||||
$errUtils.throwErrByPath('request.loading_failed', {
|
||||
onFail: options._log,
|
||||
args: {
|
||||
|
||||
@@ -18,10 +18,10 @@ const getViewportWidth = (state) => {
|
||||
return Math.min(state('viewportWidth'), window.innerWidth)
|
||||
}
|
||||
|
||||
const automateScreenshot = (state, options = {}) => {
|
||||
const automateScreenshot = (state, options: TakeScreenshotOptions = {}) => {
|
||||
const { runnable, timeout } = options
|
||||
|
||||
const titles = []
|
||||
const titles: string[] = []
|
||||
|
||||
// if this a hook then push both the current test title
|
||||
// and our own hook title
|
||||
@@ -150,7 +150,7 @@ const takeFullPageScreenshot = (state, automationOptions) => {
|
||||
|
||||
const resetScrollOverrides = scrollOverrides(win, doc)
|
||||
|
||||
const docHeight = $(doc).height()
|
||||
const docHeight = $(doc).height() as number
|
||||
const viewportHeight = getViewportHeight(state)
|
||||
const numScreenshots = Math.ceil(docHeight / viewportHeight)
|
||||
|
||||
@@ -279,7 +279,18 @@ const getBlackout = ({ capture, blackout }) => {
|
||||
return isAppOnly({ capture }) ? blackout : []
|
||||
}
|
||||
|
||||
const takeScreenshot = (Cypress, state, screenshotConfig, options = {}) => {
|
||||
// TODO: anys should be removed.
|
||||
type TakeScreenshotOptions = {
|
||||
name?: string
|
||||
subject?: any
|
||||
simple?: boolean
|
||||
testFailure?: boolean
|
||||
runnable?: any
|
||||
log?: any
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
const takeScreenshot = (Cypress, state, screenshotConfig, options: TakeScreenshotOptions = {}) => {
|
||||
const {
|
||||
capture,
|
||||
padding,
|
||||
@@ -294,7 +305,8 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options = {}) => {
|
||||
|
||||
const startTime = new Date()
|
||||
|
||||
const send = (event, props, resolve) => {
|
||||
// TODO: is this ok to make `resolve` undefined?
|
||||
const send = (event, props, resolve?) => {
|
||||
Cypress.action(`cy:${event}`, props, resolve)
|
||||
}
|
||||
|
||||
@@ -323,6 +335,8 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options = {}) => {
|
||||
if (disableTimersAndAnimations) {
|
||||
return cy.pauseTimers(true)
|
||||
}
|
||||
|
||||
return null
|
||||
})
|
||||
.then(() => {
|
||||
return sendAsync('before:screenshot', getOptions(true))
|
||||
@@ -336,6 +350,8 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options = {}) => {
|
||||
if (disableTimersAndAnimations) {
|
||||
return cy.pauseTimers(false)
|
||||
}
|
||||
|
||||
return null
|
||||
})
|
||||
}
|
||||
|
||||
@@ -424,7 +440,8 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
})
|
||||
|
||||
Commands.addAll({ prevSubject: ['optional', 'element', 'window', 'document'] }, {
|
||||
screenshot (subject, name, options = {}) {
|
||||
// TODO: any -> Partial<Loggable & Timeoutable & ScreenshotOptions>
|
||||
screenshot (subject, name, options: any = {}) {
|
||||
let userOptions = options
|
||||
|
||||
if (_.isObject(name)) {
|
||||
@@ -453,7 +470,7 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
|
||||
const isWin = $dom.isWindow(subject)
|
||||
|
||||
let screenshotConfig = _.pick(options, 'capture', 'scale', 'disableTimersAndAnimations', 'overwrite', 'blackout', 'waitForCommandSynchronization', 'padding', 'clip', 'onBeforeScreenshot', 'onAfterScreenshot')
|
||||
let screenshotConfig: any = _.pick(options, 'capture', 'scale', 'disableTimersAndAnimations', 'overwrite', 'blackout', 'waitForCommandSynchronization', 'padding', 'clip', 'onBeforeScreenshot', 'onAfterScreenshot')
|
||||
|
||||
screenshotConfig = $Screenshot.validate(screenshotConfig, 'screenshot', options._log)
|
||||
screenshotConfig = _.extend($Screenshot.getConfig(), screenshotConfig)
|
||||
|
||||
@@ -7,7 +7,8 @@ import $stackUtils from '../../cypress/stack_utils'
|
||||
|
||||
export default (Commands, Cypress, cy) => {
|
||||
Commands.addAll({
|
||||
task (task, arg, options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable & Cypress.Timeoutable>
|
||||
task (task, arg, options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
options = _.defaults({}, userOptions, {
|
||||
|
||||
@@ -87,6 +87,13 @@ const autoShadowTraversals = {
|
||||
},
|
||||
}
|
||||
|
||||
type EachConsoleProps = {
|
||||
Selector: string
|
||||
'Applied To': any
|
||||
Yielded?: any
|
||||
Elements?: number | undefined
|
||||
}
|
||||
|
||||
export default (Commands, Cypress, cy) => {
|
||||
_.each(traversals, (traversal) => {
|
||||
Commands.add(traversal, { prevSubject: ['element', 'document'] }, (subject, arg1, arg2, options) => {
|
||||
@@ -110,7 +117,7 @@ export default (Commands, Cypress, cy) => {
|
||||
return args.join(', ')
|
||||
}
|
||||
|
||||
const consoleProps = {
|
||||
const consoleProps: EachConsoleProps = {
|
||||
Selector: getSelector(),
|
||||
'Applied To': $dom.getElements(subject),
|
||||
}
|
||||
@@ -166,7 +173,7 @@ export default (Commands, Cypress, cy) => {
|
||||
// normalize the selector since jQuery won't have it
|
||||
// or completely borks it
|
||||
$el.selector = getSelector()
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
e.onFail = () => {
|
||||
return options._log.error(e)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,12 @@ const throwErr = (arg) => {
|
||||
$errUtils.throwErrByPath('wait.invalid_1st_arg', { args: { arg } })
|
||||
}
|
||||
|
||||
type Alias = {
|
||||
name: string
|
||||
cardinal: number
|
||||
ordinal: number
|
||||
}
|
||||
|
||||
export default (Commands, Cypress, cy, state) => {
|
||||
const waitNumber = (subject, ms, options) => {
|
||||
// increase the timeout by the delta
|
||||
@@ -83,7 +89,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
return xhr
|
||||
}
|
||||
|
||||
const args = [alias, type, index, num, options]
|
||||
const args: [any, any, any, any, any] = [alias, type, index, num, options]
|
||||
|
||||
return cy.retry(() => {
|
||||
return checkForXhr.apply(window, args)
|
||||
@@ -147,7 +153,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
// because wait can reference an array of aliases
|
||||
if (log) {
|
||||
const referencesAlias = log.get('referencesAlias') || []
|
||||
const aliases = [].concat(referencesAlias)
|
||||
const aliases: Array<Alias> = [].concat(referencesAlias)
|
||||
|
||||
if (str) {
|
||||
aliases.push({
|
||||
@@ -279,7 +285,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
}
|
||||
|
||||
options = _.defaults({}, options, { log: true })
|
||||
const args = [subject, msOrAlias, options]
|
||||
const args: any = [subject, msOrAlias, options]
|
||||
|
||||
try {
|
||||
if (_.isFinite(msOrAlias)) {
|
||||
@@ -316,7 +322,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
}
|
||||
|
||||
return throwErr(arg)
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if (err.name === 'CypressError') {
|
||||
throw err
|
||||
} else {
|
||||
|
||||
@@ -26,15 +26,17 @@ const viewports = {
|
||||
|
||||
const validOrientations = ['landscape', 'portrait']
|
||||
|
||||
type CurrentViewport = Pick<Cypress.Config, 'viewportWidth' | 'viewportHeight'>
|
||||
|
||||
// NOTE: this is outside the function because its 'global' state to the
|
||||
// cypress application and not local to the specific run. the last
|
||||
// viewport set is always the 'current' viewport as opposed to the
|
||||
// config. there was a bug where re-running tests without a hard
|
||||
// refresh would cause viewport to hang
|
||||
let currentViewport = null
|
||||
let currentViewport: CurrentViewport | null = null
|
||||
|
||||
export default (Commands, Cypress, cy, state) => {
|
||||
const defaultViewport = _.pick(Cypress.config(), 'viewportWidth', 'viewportHeight')
|
||||
const defaultViewport: CurrentViewport = _.pick(Cypress.config() as Cypress.Config, 'viewportWidth', 'viewportHeight')
|
||||
|
||||
// currentViewport could already be set due to previous runs
|
||||
currentViewport = currentViewport || defaultViewport
|
||||
@@ -57,7 +59,7 @@ export default (Commands, Cypress, cy, state) => {
|
||||
state(viewport)
|
||||
|
||||
return new Promise((resolve) => {
|
||||
if (currentViewport.viewportWidth === width && currentViewport.viewportHeight === height) {
|
||||
if (currentViewport!.viewportWidth === width && currentViewport!.viewportHeight === height) {
|
||||
// noop if viewport won't change
|
||||
return resolve(currentViewport)
|
||||
}
|
||||
@@ -76,7 +78,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
}
|
||||
|
||||
Commands.addAll({
|
||||
title (options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable & Cypress.Timeoutable>
|
||||
title (options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
options = _.defaults({}, userOptions, { log: true })
|
||||
@@ -98,7 +101,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
return resolveTitle()
|
||||
},
|
||||
|
||||
window (options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable & Cypress.Timeoutable>
|
||||
window (options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
options = _.defaults({}, userOptions, { log: true })
|
||||
@@ -140,7 +144,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
return verifyAssertions()
|
||||
},
|
||||
|
||||
document (options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable & Cypress.Timeoutable>
|
||||
document (options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
options = _.defaults({}, userOptions, { log: true })
|
||||
@@ -183,7 +188,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
return verifyAssertions()
|
||||
},
|
||||
|
||||
viewport (presetOrWidth, heightOrOrientation, options = {}) {
|
||||
// TODO: any -> Partial<Cypress.Loggable>
|
||||
viewport (presetOrWidth, heightOrOrientation, options: any = {}) {
|
||||
const userOptions = options
|
||||
|
||||
if (_.isObject(heightOrOrientation)) {
|
||||
@@ -202,9 +208,12 @@ export default (Commands, Cypress, cy, state) => {
|
||||
const isPreset = typeof presetOrWidth === 'string'
|
||||
|
||||
options._log = Cypress.log({
|
||||
// TODO: timeout below should be removed
|
||||
// because cy.viewport option doesn't support `timeout`
|
||||
// @see https://docs.cypress.io/api/commands/viewport#Arguments
|
||||
timeout: options.timeout,
|
||||
consoleProps () {
|
||||
const obj = {}
|
||||
const obj: Record<string, string | number> = {}
|
||||
|
||||
if (isPreset) {
|
||||
obj.Preset = presetOrWidth
|
||||
|
||||
@@ -5,10 +5,10 @@ import Promise from 'bluebird'
|
||||
import $utils from '../../cypress/utils'
|
||||
import $errUtils from '../../cypress/error_utils'
|
||||
import $stackUtils from '../../cypress/stack_utils'
|
||||
import $Server from '../../cypress/server'
|
||||
import $Server, { Server } from '../../cypress/server'
|
||||
import { $Location } from '../../cypress/location'
|
||||
|
||||
let server = null
|
||||
let server: Server | null = null
|
||||
|
||||
const tryDecodeUri = (uri) => {
|
||||
try {
|
||||
@@ -85,6 +85,21 @@ const setResponse = (state, xhr) => {
|
||||
return state('responses', responses)
|
||||
}
|
||||
|
||||
type XHRConsoleProps = {
|
||||
Alias: string
|
||||
Method: string
|
||||
URL: string
|
||||
'Matched URL': string
|
||||
Status: string
|
||||
Duration: number
|
||||
Stubbed: 'Yes' | 'No'
|
||||
Request: object
|
||||
Response: object
|
||||
XHR: object
|
||||
Note?: string
|
||||
groups?: () => Array<object>
|
||||
}
|
||||
|
||||
const startXhrServer = (cy, state, config) => {
|
||||
const logs = {}
|
||||
|
||||
@@ -119,7 +134,7 @@ const startXhrServer = (cy, state, config) => {
|
||||
event: true,
|
||||
timeout: 0,
|
||||
consoleProps: () => {
|
||||
const consoleObj = {
|
||||
const consoleObj: XHRConsoleProps = {
|
||||
Alias: alias,
|
||||
Method: xhr.method,
|
||||
URL: xhr.url,
|
||||
|
||||
@@ -6,7 +6,7 @@ import $errUtils from '../cypress/error_utils'
|
||||
import { USKeyboard } from '../cypress/UsKeyboardLayout'
|
||||
import $dom from '../dom'
|
||||
import $document from '../dom/document'
|
||||
import $elements from '../dom/elements'
|
||||
import $elements, { HTMLTextLikeInputElement } from '../dom/elements'
|
||||
// eslint-disable-next-line no-duplicate-imports
|
||||
import type { HTMLTextLikeElement } from '../dom/elements'
|
||||
import $selection from '../dom/selection'
|
||||
@@ -803,7 +803,7 @@ export class Keyboard {
|
||||
debug('setting element value', valToSet, activeEl)
|
||||
|
||||
return $elements.setNativeProp(
|
||||
activeEl as $elements.HTMLTextLikeInputElement,
|
||||
activeEl as HTMLTextLikeInputElement,
|
||||
'value',
|
||||
valToSet,
|
||||
)
|
||||
|
||||
@@ -87,7 +87,7 @@ export default {
|
||||
padding: '20px',
|
||||
width: dimensions('outerWidth'),
|
||||
height: dimensions('outerHeight'),
|
||||
})
|
||||
}) as JQuery<HTMLIFrameElement>
|
||||
|
||||
$iframes.eq(idx).replaceWith($placeholder)
|
||||
const contents = `\
|
||||
|
||||
@@ -78,7 +78,7 @@ const getRedirects = (obj, phrase, listIndentSize) => {
|
||||
const getHttpProps = (fields: { value: string, key: string }[] = []) => {
|
||||
return _
|
||||
.chain(fields)
|
||||
.reduce(formatProp, [])
|
||||
.reduce<string[]>(formatProp, [])
|
||||
.join('\n')
|
||||
.value()
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ const isSpecError = (spec, err) => {
|
||||
return _.includes(err.stack, spec.relative)
|
||||
}
|
||||
|
||||
const mergeErrProps = (origErr, ...newProps) => {
|
||||
const mergeErrProps = (origErr: Error, ...newProps) => {
|
||||
return _.extend(origErr, ...newProps)
|
||||
}
|
||||
|
||||
@@ -262,6 +262,8 @@ export class InternalCypressError extends Error {
|
||||
}
|
||||
|
||||
export class CypressError extends Error {
|
||||
docsUrl?: string
|
||||
|
||||
constructor (message) {
|
||||
super(message)
|
||||
|
||||
@@ -283,13 +285,13 @@ const getUserInvocationStackFromError = (err) => {
|
||||
return err.userInvocationStack
|
||||
}
|
||||
|
||||
const internalErr = (err) => {
|
||||
const internalErr = (err): InternalCypressError => {
|
||||
const newErr = new InternalCypressError(err.message)
|
||||
|
||||
return mergeErrProps(newErr, err)
|
||||
}
|
||||
|
||||
const cypressErr = (err) => {
|
||||
const cypressErr = (err): CypressError => {
|
||||
const newErr = new CypressError(err.message)
|
||||
|
||||
return mergeErrProps(newErr, err)
|
||||
@@ -339,7 +341,7 @@ const docsUrlByParents = (msgPath) => {
|
||||
return docsUrlByParents(msgPath)
|
||||
}
|
||||
|
||||
const errByPath = (msgPath, args) => {
|
||||
const errByPath = (msgPath, args?) => {
|
||||
let msgValue = _.get($errorMessages, msgPath)
|
||||
|
||||
if (!msgValue) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import _ from 'lodash'
|
||||
import type { Interception, Route } from '@packages/net-stubbing/lib/types'
|
||||
import type { BrowserPreRequest, BrowserResponseReceived, RequestError } from '@packages/proxy/lib/types'
|
||||
import $errUtils from './error_utils'
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import _ from 'lodash'
|
||||
import type $Cypress from '../..'
|
||||
|
||||
/**
|
||||
* Fix property reads and writes that could potentially help the AUT to break out of its iframe.
|
||||
@@ -9,7 +8,7 @@ import type $Cypress from '../..'
|
||||
* @param accessedProp the property name being accessed (Symbol/number properties are not intercepted)
|
||||
* @param value the right-hand side of an assignment operation (accessedObject.accessedProp = value)
|
||||
*/
|
||||
export function resolveWindowReference (this: typeof $Cypress, currentWindow: Window, accessedObject: Window | any, accessedProp: string, value?: any) {
|
||||
export function resolveWindowReference (this: Cypress.Cypress, currentWindow: Window, accessedObject: Window | any, accessedProp: string, value?: any) {
|
||||
const { dom, state } = this
|
||||
|
||||
const getTargetValue = () => {
|
||||
|
||||
@@ -12,6 +12,7 @@ const _reset = () => {
|
||||
disableTimersAndAnimations: true,
|
||||
screenshotOnRunFailure: true,
|
||||
blackout: [],
|
||||
overwrite: false,
|
||||
onBeforeScreenshot () {},
|
||||
onAfterScreenshot () {},
|
||||
}
|
||||
|
||||
@@ -6,7 +6,12 @@ import $errUtils from './error_utils'
|
||||
|
||||
const SELECTOR_PRIORITIES = 'data-cy data-test data-testid id class tag attributes nth-child'.split(' ')
|
||||
|
||||
const reset = () => {
|
||||
type Defaults = {
|
||||
onElement: Cypress.SelectorPlaygroundDefaultsOptions['onElement'] | null
|
||||
selectorPriority: Cypress.SelectorPlaygroundDefaultsOptions['selectorPriority']
|
||||
}
|
||||
|
||||
const reset = (): Defaults => {
|
||||
return {
|
||||
onElement: null,
|
||||
selectorPriority: SELECTOR_PRIORITIES,
|
||||
|
||||
@@ -166,7 +166,15 @@ const defaults = (obj = {}) => {
|
||||
return _.extend(serverDefaults, obj)
|
||||
}
|
||||
|
||||
const create = (options = {}) => {
|
||||
// TODO: Convert it to a class.
|
||||
// It's written in this way to bypass type failures.
|
||||
export type Server = {
|
||||
restore: () => void
|
||||
cancelPendingXhrs: () => any[]
|
||||
bindTo: (win: Window) => void
|
||||
}
|
||||
|
||||
const create = (options = {}): Server => {
|
||||
options = _.defaults(options, serverDefaults)
|
||||
|
||||
const xhrs = {}
|
||||
|
||||
@@ -22,13 +22,44 @@ const getFirstValidSizedRect = (el) => {
|
||||
}) || el.getBoundingClientRect() // otherwise fall back to the parent client rect
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {JQuery<HTMLElement> | HTMLElement} $el
|
||||
*/
|
||||
const getElementPositioning = ($el) => {
|
||||
type ElementPositioning = {
|
||||
scrollTop: number
|
||||
scrollLeft: number
|
||||
width: number
|
||||
height: number
|
||||
fromElViewport: {
|
||||
doc: Document
|
||||
x?: number
|
||||
y?: number
|
||||
top: number
|
||||
left: number
|
||||
right: number
|
||||
bottom: number
|
||||
topCenter: number
|
||||
leftCenter: number
|
||||
}
|
||||
fromElWindow: {
|
||||
x?: number
|
||||
y?: number
|
||||
top: number
|
||||
left: number
|
||||
topCenter: number
|
||||
leftCenter: number
|
||||
}
|
||||
fromAutWindow: {
|
||||
x?: number
|
||||
y?: number
|
||||
top: number
|
||||
left: number
|
||||
topCenter: number
|
||||
leftCenter: number
|
||||
}
|
||||
}
|
||||
|
||||
const getElementPositioning = ($el: JQuery<HTMLElement> | HTMLElement): ElementPositioning => {
|
||||
let autFrame
|
||||
|
||||
const el = $jquery.isJquery($el) ? $el[0] : $el
|
||||
const el: HTMLElement = $jquery.isJquery($el) ? $el[0] : $el
|
||||
|
||||
const win = $window.getWindowByElement(el)
|
||||
|
||||
@@ -128,7 +159,12 @@ const getElementPositioning = ($el) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getCoordsByPosition = (left, top, xPosition = 'center', yPosition = 'center') => {
|
||||
const getCoordsByPosition = (
|
||||
left: number,
|
||||
top: number,
|
||||
xPosition: 'left' | 'center' | 'right' = 'center',
|
||||
yPosition: 'top' | 'center' | 'bottom' = 'center',
|
||||
) => {
|
||||
const getLeft = () => {
|
||||
/* eslint-disable default-case */
|
||||
switch (xPosition) {
|
||||
|
||||
@@ -18,7 +18,7 @@ const descriptor = <T extends keyof Window, K extends keyof Window[T]['prototype
|
||||
return desc
|
||||
}
|
||||
|
||||
const _getValue = function () {
|
||||
const _getValue = function (this: any) {
|
||||
if (isInput(this)) {
|
||||
return descriptor('HTMLInputElement', 'value').get
|
||||
}
|
||||
@@ -39,7 +39,7 @@ const _getValue = function () {
|
||||
return descriptor('HTMLOptionElement', 'value').get
|
||||
}
|
||||
|
||||
const _setValue = function () {
|
||||
const _setValue = function (this: any) {
|
||||
if (isInput(this)) {
|
||||
return descriptor('HTMLInputElement', 'value').set
|
||||
}
|
||||
@@ -60,7 +60,7 @@ const _setValue = function () {
|
||||
return descriptor('HTMLOptionElement', 'value').set
|
||||
}
|
||||
|
||||
const _getSelectionStart = function () {
|
||||
const _getSelectionStart = function (this: any) {
|
||||
if (isInput(this)) {
|
||||
return descriptor('HTMLInputElement', 'selectionStart').get
|
||||
}
|
||||
@@ -72,7 +72,7 @@ const _getSelectionStart = function () {
|
||||
throw new Error('this should never happen, cannot get selectionStart')
|
||||
}
|
||||
|
||||
const _getSelectionEnd = function () {
|
||||
const _getSelectionEnd = function (this: any) {
|
||||
if (isInput(this)) {
|
||||
return descriptor('HTMLInputElement', 'selectionEnd').get
|
||||
}
|
||||
@@ -84,7 +84,7 @@ const _getSelectionEnd = function () {
|
||||
throw new Error('this should never happen, cannot get selectionEnd')
|
||||
}
|
||||
|
||||
const _nativeFocus = function () {
|
||||
const _nativeFocus = function (this: any) {
|
||||
if ($window.isWindow(this)) {
|
||||
return window.focus
|
||||
}
|
||||
@@ -96,7 +96,7 @@ const _nativeFocus = function () {
|
||||
return window.HTMLElement.prototype.focus
|
||||
}
|
||||
|
||||
const _nativeBlur = function () {
|
||||
const _nativeBlur = function (this: any) {
|
||||
if ($window.isWindow(this)) {
|
||||
return window.blur
|
||||
}
|
||||
@@ -108,7 +108,7 @@ const _nativeBlur = function () {
|
||||
return window.HTMLElement.prototype.blur
|
||||
}
|
||||
|
||||
const _nativeSetSelectionRange = function () {
|
||||
const _nativeSetSelectionRange = function (this: any) {
|
||||
if (isInput(this)) {
|
||||
return window.HTMLInputElement.prototype.setSelectionRange
|
||||
}
|
||||
@@ -117,7 +117,7 @@ const _nativeSetSelectionRange = function () {
|
||||
return window.HTMLTextAreaElement.prototype.setSelectionRange
|
||||
}
|
||||
|
||||
const _nativeSelect = function () {
|
||||
const _nativeSelect = function (this: any) {
|
||||
if (isInput(this)) {
|
||||
return window.HTMLInputElement.prototype.select
|
||||
}
|
||||
@@ -126,7 +126,7 @@ const _nativeSelect = function () {
|
||||
return window.HTMLTextAreaElement.prototype.select
|
||||
}
|
||||
|
||||
const _isContentEditable = function () {
|
||||
const _isContentEditable = function (this: any) {
|
||||
if (isSvg(this)) {
|
||||
return false
|
||||
}
|
||||
@@ -134,7 +134,7 @@ const _isContentEditable = function () {
|
||||
return descriptor('HTMLElement', 'isContentEditable').get
|
||||
}
|
||||
|
||||
const _setType = function () {
|
||||
const _setType = function (this: any) {
|
||||
if (isInput(this)) {
|
||||
return descriptor('HTMLInputElement', 'type').set
|
||||
}
|
||||
@@ -146,7 +146,7 @@ const _setType = function () {
|
||||
throw new Error('this should never happen, cannot set type')
|
||||
}
|
||||
|
||||
const _getType = function () {
|
||||
const _getType = function (this: any) {
|
||||
if (isInput(this)) {
|
||||
return descriptor('HTMLInputElement', 'type').get
|
||||
}
|
||||
@@ -158,7 +158,7 @@ const _getType = function () {
|
||||
throw new Error('this should never happen, cannot get type')
|
||||
}
|
||||
|
||||
const _getMaxLength = function () {
|
||||
const _getMaxLength = function (this: any) {
|
||||
if (isInput(this)) {
|
||||
return descriptor('HTMLInputElement', 'maxLength').get
|
||||
}
|
||||
|
||||
@@ -645,7 +645,7 @@ const getCaretPosition = function (el) {
|
||||
return null
|
||||
}
|
||||
|
||||
const interceptSelect = function () {
|
||||
const interceptSelect = function (this: any) {
|
||||
if ($elements.isInput(this) && !$elements.canSetSelectionRangeElement(this)) {
|
||||
setSelectionRange(this, 0, $elements.getNativeProp(this, 'value').length)
|
||||
}
|
||||
|
||||
+5
@@ -16,6 +16,11 @@ declare namespace Cypress {
|
||||
queue: any
|
||||
retry: (fn: () => any, opts: any) => any
|
||||
state: State
|
||||
pauseTimers: <T>(shouldPause: boolean) => Cypress.Chainable<T>
|
||||
// TODO: this function refers to clearTimeout at cy/timeouts.ts, which doesn't have any argument.
|
||||
// But in many cases like cy/commands/screenshot.ts, it's called with a timeout id string.
|
||||
// We should decide whether calling with id is correct or not.
|
||||
clearTimeout: <T>(timeoutId?: string) => Cypress.Chainable<T>
|
||||
}
|
||||
|
||||
interface Cypress {
|
||||
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
/// <reference path="../../cli/types/jquery/index.d.ts" />
|
||||
|
||||
declare const lib: typeof import('./lib/extension')
|
||||
|
||||
export default lib
|
||||
@@ -18,7 +18,6 @@
|
||||
"throttle": "^1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "7.0.2",
|
||||
"bin-up": "1.2.0",
|
||||
"chai": "4.2.0",
|
||||
"mocha": "7.1.2"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import _ from 'lodash'
|
||||
import { action, computed, observable } from 'mobx'
|
||||
|
||||
import Err from '../errors/err-model'
|
||||
import Err, { ErrProps } from '../errors/err-model'
|
||||
import Instrument, { InstrumentProps } from '../instruments/instrument-model'
|
||||
import type { TimeoutID } from '../lib/types'
|
||||
|
||||
@@ -20,7 +20,7 @@ interface RenderProps {
|
||||
}
|
||||
|
||||
export interface CommandProps extends InstrumentProps {
|
||||
err?: Err
|
||||
err?: ErrProps
|
||||
event?: boolean
|
||||
number?: number
|
||||
numElements: number
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -3,7 +3,7 @@ import { action, computed, observable } from 'mobx'
|
||||
import { FileDetails } from '@packages/ui-components'
|
||||
|
||||
import Attempt from '../attempts/attempt-model'
|
||||
import Err from '../errors/err-model'
|
||||
import Err, { ErrProps } from '../errors/err-model'
|
||||
import { HookProps } from '../hooks/hook-model'
|
||||
import Runnable, { RunnableProps } from '../runnables/runnable-model'
|
||||
import { CommandProps } from '../commands/command-model'
|
||||
@@ -18,7 +18,7 @@ export type UpdateTestCallback = () => void
|
||||
|
||||
export interface TestProps extends RunnableProps {
|
||||
state: TestState | null
|
||||
err?: Err
|
||||
err?: ErrProps
|
||||
isOpen?: boolean
|
||||
agents?: Array<AgentProps>
|
||||
commands?: Array<CommandProps>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,8 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'ctReporterHeader': string;
|
||||
'display-none': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,27 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'app': string;
|
||||
'appWrapper': string;
|
||||
'appWrapperScreenshotting': string;
|
||||
'ctDevtoolsContainer': string;
|
||||
'ctPluginToggleButton': string;
|
||||
'ctPlugins': string;
|
||||
'ctPluginsHeader': string;
|
||||
'ctPluginsName': string;
|
||||
'ctTogglePluginsSectionButton': string;
|
||||
'ctTogglePluginsSectionButtonOpen': string;
|
||||
'display-none': string;
|
||||
'folder': string;
|
||||
'largerIcon': string;
|
||||
'leftNav': string;
|
||||
'noSpecAut': string;
|
||||
'noSpecsDescription': string;
|
||||
'reporter': string;
|
||||
'runner': string;
|
||||
'runnerCt': string;
|
||||
'screenshotting': string;
|
||||
'size-container': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -230,7 +230,7 @@ export class Header extends Component<HeaderProps> {
|
||||
}
|
||||
|
||||
this.props.state.updateWindowDimensions({
|
||||
headerHeight: $(this.headerRef.current).outerHeight(),
|
||||
headerHeight: $(this.headerRef.current).outerHeight() as number,
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@ export const logger = {
|
||||
_.each(formattedLog, (value, key) => {
|
||||
// don't log empty strings
|
||||
// _.trim([]) returns '' but we want to log empty arrays, so account for that
|
||||
if (_.trim(value) === '' && !_.isArray(value)) return
|
||||
// Skip trim if we know value is an object
|
||||
if (typeof value !== 'object' && _.trim(value) === '' && !_.isArray(value)) return
|
||||
|
||||
this.log(`%c${key}`, 'font-weight: bold', value)
|
||||
})
|
||||
|
||||
@@ -1,16 +1,43 @@
|
||||
const sinon = require('sinon')
|
||||
const { logger } = require('./logger')
|
||||
import _ from 'lodash'
|
||||
|
||||
describe('logger', () => {
|
||||
let spyLog = sinon.spy(logger, 'log')
|
||||
|
||||
afterEach(() => {
|
||||
// reset after each unit test
|
||||
spyLog.resetHistory()
|
||||
})
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/17542
|
||||
it('cy.log() shows all arguments in each line when there are multiple args', () => {
|
||||
const spy = sinon.spy(logger, 'log')
|
||||
|
||||
logger.logFormatted({ args: [1, 2, 3] })
|
||||
|
||||
expect(spy).to.have.been.calledWith(`%cArgs:`, 'font-weight: bold')
|
||||
expect(spy).to.have.been.calledWith(`%c [0]:`, 'font-weight: bold', 1)
|
||||
expect(spy).to.have.been.calledWith(`%c [1]:`, 'font-weight: bold', 2)
|
||||
expect(spy).to.have.been.calledWith(`%c [2]:`, 'font-weight: bold', 3)
|
||||
expect(spyLog).to.have.been.calledWith(`%cArgs:`, 'font-weight: bold')
|
||||
expect(spyLog).to.have.been.calledWith(`%c [0]:`, 'font-weight: bold', 1)
|
||||
expect(spyLog).to.have.been.calledWith(`%c [1]:`, 'font-weight: bold', 2)
|
||||
expect(spyLog).to.have.been.calledWith(`%c [2]:`, 'font-weight: bold', 3)
|
||||
})
|
||||
|
||||
describe('_logValues', () => {
|
||||
let spyTrim = sinon.spy(_, 'trim')
|
||||
|
||||
afterEach(() => {
|
||||
// reset after each unit test
|
||||
spyTrim.resetHistory()
|
||||
})
|
||||
|
||||
it('should not call trim', () => {
|
||||
logger._logValues({})
|
||||
logger._logValues({ test: {} })
|
||||
logger._logValues(null)
|
||||
logger._logValues(undefined)
|
||||
|
||||
expect(spyTrim.getCalls()).to.have.length(0)
|
||||
})
|
||||
|
||||
// The positive unit tests to capture if log has been called are already written in
|
||||
// the 'cy.log() shows all arguments in each line when there are multiple args' unit test.
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { observer } from 'mobx-react'
|
||||
import * as React from 'react'
|
||||
import type * as React from 'react'
|
||||
|
||||
/**
|
||||
* Wraps MobX `observer` to properly add a component `displayName` for debugging purposes
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,13 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'a': string;
|
||||
'isClosed': string;
|
||||
'isSelected': string;
|
||||
'li': string;
|
||||
'nav': string;
|
||||
'searchInput': string;
|
||||
'ul': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -1,6 +1,6 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import React, { useCallback, useMemo, useRef } from 'react'
|
||||
import React, { MutableRefObject, useCallback, useMemo, useRef } from 'react'
|
||||
import cs from 'classnames'
|
||||
import { throttle } from 'lodash'
|
||||
import { SearchInput, FileTree, SpecificTreeNode, TreeFile, FileBase, TreeFolder, VirtualizedTreeRef } from '@cypress/design-system'
|
||||
@@ -47,7 +47,7 @@ export const SpecList: React.FC<SpecListProps> = ({ searchRef, className, specs,
|
||||
}
|
||||
}, [searchRef])
|
||||
|
||||
const onEnter = useCallback(() => fileTreeRef.current.focus(), [])
|
||||
const onEnter = useCallback(() => fileTreeRef.current!.focus(), [])
|
||||
|
||||
const onVerticalArrowKey = useCallback((arrow: 'up' | 'down') => {
|
||||
if (arrow === 'down') {
|
||||
@@ -74,7 +74,7 @@ export const SpecList: React.FC<SpecListProps> = ({ searchRef, className, specs,
|
||||
<div>
|
||||
{/* TODO: Do we need any other rootDirectories? */}
|
||||
<FileTree
|
||||
innerRef={fileTreeRef}
|
||||
innerRef={fileTreeRef as MutableRefObject<VirtualizedTreeRef>}
|
||||
files={matches}
|
||||
rootDirectory="/"
|
||||
emptyPlaceholder="No specs found"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'specsList': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -6476,6 +6476,7 @@ exports['src/cypress/runner retries mochaEvents screenshots retry screenshot in
|
||||
"height": 660
|
||||
},
|
||||
"scaled": false,
|
||||
"overwrite": false,
|
||||
"blackout": [],
|
||||
"startTime": "match.string",
|
||||
"current": 1,
|
||||
@@ -6491,7 +6492,8 @@ exports['src/cypress/runner retries mochaEvents screenshots retry screenshot in
|
||||
"scale": false,
|
||||
"waitForCommandSynchronization": false,
|
||||
"disableTimersAndAnimations": true,
|
||||
"blackout": []
|
||||
"blackout": [],
|
||||
"overwrite": false
|
||||
}
|
||||
|
||||
exports['serialize state - retries'] = {
|
||||
|
||||
@@ -1939,6 +1939,7 @@ exports['src/cypress/runner other specs screenshots screenshot after failed test
|
||||
"height": 660
|
||||
},
|
||||
"scaled": true,
|
||||
"overwrite": false,
|
||||
"blackout": [],
|
||||
"startTime": "1970-01-01T00:00:00.000Z"
|
||||
}
|
||||
|
||||
Vendored
+3
@@ -5,3 +5,6 @@
|
||||
/// <reference path="../../cli/types/cypress.d.ts" />
|
||||
/// <reference path="../../cli/types/cypress-global-vars.d.ts" />
|
||||
/// <reference path="../../cli/types/cypress-type-helpers.d.ts" />
|
||||
|
||||
/// <reference path="../ts/index.d.ts" />
|
||||
/// <reference path="../driver/types/internal-types.d.ts" />
|
||||
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -73,12 +73,12 @@ yarn test-integration cli_spec ## shorthand, uses globbing to find spec
|
||||
yarn test <path/to/test>
|
||||
yarn test test/e2e/1_async_timeouts_spec.js
|
||||
## or
|
||||
yarn test-e2e 1_async ## shorthand, uses globbing to find spec
|
||||
yarn test-e2e async_timeouts ## shorthand, uses globbing to find spec
|
||||
```
|
||||
|
||||
To keep the browser open after a spec run (for easier debugging and iterating on specs), you can pass the `--no-exit` flag to the e2e test command. Live reloading due to spec changes should also work:
|
||||
```sh
|
||||
yarn test test/e2e/2_go_spec.js --browser chrome --no-exit
|
||||
yarn test test/e2e/go_spec.js --browser chrome --no-exit
|
||||
```
|
||||
|
||||
### Updating snaphots
|
||||
@@ -88,5 +88,5 @@ Prepend `SNAPSHOT_UPDATE=1` to any test command. See [`snap-shot-it` instruction
|
||||
```bash
|
||||
SNAPSHOT_UPDATE=1 yarn test test/unit/api_spec.js
|
||||
SNAPSHOT_UPDATE=1 yarn test test/integration/cli_spec.js
|
||||
SNAPSHOT_UPDATE=1 yarn test-e2e 1_async
|
||||
SNAPSHOT_UPDATE=1 yarn test-e2e async_timeout
|
||||
```
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user