mirror of
https://github.com/cypress-io/cypress.git
synced 2026-02-11 09:40:11 -06:00
Merge branch 'develop' into 8.0-release
This commit is contained in:
29
.github/ISSUE_TEMPLATE/1-bug-report.md
vendored
29
.github/ISSUE_TEMPLATE/1-bug-report.md
vendored
@@ -1,29 +0,0 @@
|
||||
---
|
||||
name: "🐛 Bug report"
|
||||
about: Report a bug found while using Cypress.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!-- 👋 Use the template below to report a bug. Fill in as much info as possible.
|
||||
|
||||
Have a question? Start a new discussion 👉 https://github.com/cypress-io/cypress/discussions
|
||||
|
||||
As an open source project with a small maintainer team, it may take some time for your issue to be addressed. Please be patient and we will respond as soon as we can. 🙏 -->
|
||||
|
||||
### Current behavior
|
||||
<!-- A description including screenshots, stack traces, DEBUG logs, etc. 👉 https://on.cypress.io/troubleshooting -->
|
||||
|
||||
### Desired behavior
|
||||
<!-- Remember, we are not familiar with the application you're testing, so please provide a clear description of what should happen.-->
|
||||
|
||||
### Test code to reproduce
|
||||
<!-- Provide test code that we can copy, paste, and run on our machine to see the issue. -->
|
||||
|
||||
<!-- You could also provide a repo that we can clone and run. You can fork 👉 https://github.com/cypress-io/cypress-test-tiny repo, set up a failing test, then link to your fork. -->
|
||||
|
||||
### Versions
|
||||
|
||||
<!-- Cypress version, last known working Cypress version (if applicable), Browser and version, Operating System, CI Provider, etc -->
|
||||
<!-- If possible, please update Cypress to latest version and check if the bug is still present. -->
|
||||
42
.github/ISSUE_TEMPLATE/1-bug-report.yml
vendored
Normal file
42
.github/ISSUE_TEMPLATE/1-bug-report.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: "🐛 Bug report"
|
||||
description: Report a bug found while using Cypress.
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Have a question? 👉 [Start a new discussion](https://github.com/cypress-io/cypress/discussions) or [ask in chat](https://on.cypress.io/discord).
|
||||
- type: textarea
|
||||
id: current-behavior
|
||||
attributes:
|
||||
label: Current behavior
|
||||
description: A description including screenshots, stack traces, DEBUG logs, etc. [Troubleshooting tips](https://on.cypress.io/troubleshooting).
|
||||
placeholder: Currently...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: desired-behavior
|
||||
attributes:
|
||||
label: Desired behavior
|
||||
description: Remember, we're not familiar with the app you're testing, so please provide a clear description of what should happen.
|
||||
placeholder: In this situation, Cypress should...
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Test code to reproduce
|
||||
description: Provide a failing test or repo we can run. You can fork [this repo](https://github.com/cypress-io/cypress-test-tiny), set up a failing test, then link to your fork.
|
||||
placeholder: Here is my failing test code and the app code to run the tests on...
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Cypress Version
|
||||
description: Run `cypress version` to see your current version. If possible, please update Cypress to the latest version first.
|
||||
placeholder: ex. 7.6.0
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: othter
|
||||
attributes:
|
||||
label: Other
|
||||
placeholder: Any other details?
|
||||
42
.github/ISSUE_TEMPLATE/2-install-issue.md
vendored
42
.github/ISSUE_TEMPLATE/2-install-issue.md
vendored
@@ -1,42 +0,0 @@
|
||||
---
|
||||
name: "⬇️ Issue during install"
|
||||
about: Report an issue while downloading Cypress.
|
||||
title: ''
|
||||
labels: 'topic: installation'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!-- 👋 Use the template below to report an issue with installing Cypress 👉 https://on.cypress.io/installing-cypress
|
||||
|
||||
Have a question? Start a new discussion 👉 https://github.com/cypress-io/cypress/discussions
|
||||
|
||||
Fill in as much info as possible. As an open source project with a small maintainer team, it may take some time for your issue to be addressed. Please be patient and we will respond as soon as we can. 🙏 -->
|
||||
|
||||
### Current behavior
|
||||
<!-- A description including screenshots, stack traces, etc. -->
|
||||
|
||||
### Debug logs
|
||||
<!-- Include DEBUG logs setting `DEBUG=cypress:*` 👉 https://on.cypress.io/troubleshooting#Print-DEBUG-logs -->
|
||||
|
||||
<!-- Include npm/yarn logs if applicable -->
|
||||
|
||||
### Download method
|
||||
<!-- Add version number if applicable -->
|
||||
|
||||
- [ ] npm
|
||||
- [ ] yarn
|
||||
- [ ] Direct download
|
||||
- [ ] other <!--Please specify-->
|
||||
|
||||
### Operating System
|
||||
<!-- Add version number if applicable -->
|
||||
|
||||
- [ ] Linux
|
||||
- [ ] Mac
|
||||
- [ ] Windows
|
||||
|
||||
### Other
|
||||
|
||||
- [ ] I'm installing latest Cypress version <!--Please update to latest first 👉 https://on.cypress.io/changelog -->
|
||||
- [ ] I'm behind a proxy <!--Configure your proxy first 👉 https://on.cypress.io/proxy-configuration -->
|
||||
- [ ] This only occurs in CI <!--specify CI provider -->
|
||||
60
.github/ISSUE_TEMPLATE/2-install-issue.yml
vendored
Normal file
60
.github/ISSUE_TEMPLATE/2-install-issue.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: "⬇️ Issue during install"
|
||||
description: Report an issue while downloading Cypress.
|
||||
labels: ['topic: installation']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Have a question? 👉 [Start a new discussion](https://github.com/cypress-io/cypress/discussions) or [ask in chat](https://on.cypress.io/discord).
|
||||
|
||||
If you're behind a corporate proxy, make sure to [configure it properly](https://on.cypress.io/proxy-configuration) before install.
|
||||
- type: textarea
|
||||
id: current-behavior
|
||||
attributes:
|
||||
label: Current behavior
|
||||
description: A description including screenshots, stack traces, DEBUG logs, etc. [Troubleshooting tips](https://on.cypress.io/troubleshooting).
|
||||
placeholder: When I try to download Cypress...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: debug-logs
|
||||
attributes:
|
||||
label: Debug logs
|
||||
description: Include DEBUG logs setting [`DEBUG=cypress:*`](https://on.cypress.io/troubleshooting#Print-DEBUG-logs/). Include npm/yarn logs if applicable.
|
||||
placeholder: Debug logs
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Cypress Version
|
||||
description: The version you're trying to install
|
||||
placeholder: ex. 7.6.0
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: package-manager
|
||||
attributes:
|
||||
label: Package Manager
|
||||
options:
|
||||
- npm
|
||||
- yarn
|
||||
- Direct download
|
||||
- pnpm
|
||||
- other
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: operating-system
|
||||
attributes:
|
||||
label: Operating system
|
||||
options:
|
||||
- Linux
|
||||
- Mac
|
||||
- Windows
|
||||
- other
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: othter
|
||||
attributes:
|
||||
label: Other
|
||||
placeholder: Any other details?
|
||||
19
.github/ISSUE_TEMPLATE/3-feature.md
vendored
19
.github/ISSUE_TEMPLATE/3-feature.md
vendored
@@ -1,19 +0,0 @@
|
||||
---
|
||||
name: "✨ Feature"
|
||||
about: Suggest a feature or enhancement to improve Cypress.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!-- 👋 Use the template below to request a feature.
|
||||
|
||||
Have a question? Start a new discussion 👉 https://github.com/cypress-io/cypress/discussions
|
||||
|
||||
Please be patient and we will respond as soon as we can. 🙏 -->
|
||||
|
||||
### What would you like?
|
||||
<!-- A clear description of the feature or enhancement wanted in Cypress -->
|
||||
|
||||
### Why is this needed?
|
||||
<!-- Remember, we are not familiar with the application you are testing, so please provide a clear description of why this would be useful to your project. -->
|
||||
21
.github/ISSUE_TEMPLATE/3-feature.yml
vendored
Normal file
21
.github/ISSUE_TEMPLATE/3-feature.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: "✨ Feature"
|
||||
description: Suggest a feature or enhancement to improve Cypress.
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Have a question? 👉 [Start a new discussion](https://github.com/cypress-io/cypress/discussions) or [ask in chat](https://on.cypress.io/discord).
|
||||
- type: textarea
|
||||
id: feature
|
||||
attributes:
|
||||
label: What would you like?
|
||||
description: A clear description of the feature or enhancement wanted in Cypress.
|
||||
placeholder: I'd like to be able to...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reason
|
||||
attributes:
|
||||
label: Why is this needed?
|
||||
description: Remember, we're not familiar with the app you're testing, so please provide a clear description of why this would be useful to your project.
|
||||
placeholder: I want this because...
|
||||
6
.github/ISSUE_TEMPLATE/config.yml
vendored
6
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -3,9 +3,9 @@ contact_links:
|
||||
- name: 🤔 Questions and Help
|
||||
url: https://github.com/cypress-io/cypress/discussions
|
||||
about: This issue tracker is not for support questions. Please refer to our Discussions.
|
||||
- name: 📊 Cypress Dashboard Feature
|
||||
url: https://portal.productboard.com/cypress-io/1-cypress-dashboard
|
||||
about: This issue tracker is not for requesting Cypress Dashboard features. Please express interest here.
|
||||
- name: 💬 Chat
|
||||
url: https://on.cypress.io/discord
|
||||
about: Want to discuss Cypress with others? Check out our chat.
|
||||
- name: 📃 Documentation Issue
|
||||
url: https://github.com/cypress-io/cypress-documentation/issues/new
|
||||
about: This issue tracker is not for documentation issues. Please open documentation issues here.
|
||||
|
||||
@@ -167,7 +167,7 @@ Search [all issues](https://github.com/cypress-io/cypress/issues) for keywords f
|
||||
If an issue already exists you should:
|
||||
|
||||
- Thank them for their contribution.
|
||||
- Explain that this issue if a duplicate of another issue, linking to the relevant issue (`#1234`).
|
||||
- Explain that this issue is a duplicate of another issue, linking to the relevant issue (`#1234`).
|
||||
- Add the `type: duplicate` label to the issue.
|
||||
- Close the issue.
|
||||
|
||||
|
||||
@@ -61,6 +61,11 @@ You can build the Cypress binary locally by running `yarn binary-build`. You can
|
||||
ZENHUB_API_TOKEN="..."
|
||||
```
|
||||
- The `cypress-bot` GitHub app credentials are also needed. Ask another team member who has done a deploy for those.
|
||||
- For purging the Cloudflare cache (part of the `move-binaries` step), you'll need `CF_ZONEID` and `CF_TOKEN` set. These can be found in 1Password. If you don't have access, ask a team member who has done a deploy.
|
||||
```text
|
||||
CF_ZONEID="..."
|
||||
CF_TOKEN="..."
|
||||
```
|
||||
- Tip: Use [as-a](https://github.com/bahmutov/as-a) to manage environment variables for different situations.
|
||||
|
||||
### Before Publishing a New Version
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
<p align="center">
|
||||
Fast, easy and reliable testing for anything that runs in a browser.
|
||||
</p>
|
||||
<p align="center">
|
||||
Join us, we're <a href="https://cypress.io/jobs">hiring</a>.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/package/cypress">
|
||||
|
||||
@@ -2,9 +2,8 @@ branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
- 7.0-release
|
||||
- windows-code-signing
|
||||
- /win*/
|
||||
- feature/cross-platform-wizard
|
||||
|
||||
# https://www.appveyor.com/docs/lang/nodejs-iojs/
|
||||
environment:
|
||||
@@ -32,6 +31,10 @@ environment:
|
||||
secure: tAoqu4zIgZUxOfW0u9YQgw==
|
||||
GH_PRIVATE_KEY:
|
||||
secure: msLmlIBnkNovqrqTeCqa7ZPjETyS8Xn4JLuiRMWYK7gZBTO66pNnFaoeqwPFwH+ooO0cDFhAOPTToLisgTLXCo4hnw38zuBuKq+ywCh5mtk5uZn4x4F8G2XyRLD/ViZm+VuD2yZzaTWF11upDqC4xbXDe32yD6OSLKhA5ms5F5ke83zEuWSLTqVVCIpVH12rVTJHl3QHaWPwZbBBE3SFN8D6uiclvI06y3pEg2bVShU8YqlwearYTRuErsYXNCUmT0SrDd2kHznlYf08edQDHpydnQvvTViZMgomvYp5wDCXFD+/FxtTMuTptJFpspirXL8w/xjYy1/JaTd/K01oUUD2Xwl/v0cS28OpdcraETyrQxQhEgTCXfg9ONbZ5mRvQlkaRROaTqDSGMmEPs4N91zarpA7RLxu7PPvxXQcbDW4GiJvH5BhVWu8lY/QBZsr8It1dhLYSzTPNIh9ey8xNaUbZ3oQhPBoreRi36B+FSPBsrZpB8Q8aa97gd+lCa8br2RfaEpzx8gA0pSK44odqcGuJe7T8MHOqYo0cUEUb2UypPPG7mWyjGip+x3Z9P/vSrZzDV+YFFvEzQAMoyRMp/456V+YL8iduryMRIadkJcB4ZVZz2hsxY5Gv6Eeh9NhwzyM64Rz5NP5fJ9Kw8E5Vm+ddEmft8Ec6dajcURoVN0i+s8t7h/e3Hzrr62UjWr0FpUx5fPBC/Tldn3+h4Rr9/HFI2RCZAI5wHOrx/aQ/HknA9UCEdqdod8ix5yAdSpTxp3aCGEoS97STXU43CjLEiQFyLaReoHOOwFp5EqaAiAqiORJaKuShWoir+OqSk7rucU7kFvIlU9GDfLuKUpxcQoDq/8fKT3lcG3Pr4MVV79BJ6EcjcsEf4ukQ3IfwMY+2RbwYWEowsQP18k4HztZpMEOuYPlSCiAPL7Cz4dcE5oybSURr9QQbSqVMoiCKZBn344KxpvH59KW90wt8CYyoeLSlPpM9s73g9My4fwbB3W9lcbw/AteRGer01VYEHY+1MyQwhqgHoXQ//op4gztFbpSLcli88v1IOopcr0Dw5NrylcjCTKuVWmQs0uIAfOr7zxqCZ8DCXG6spdipjF1jx+bxp318ZgH56pmmTOTMbj5Cmdpr3KlCFbYB4JI7lexnZmti1NcHtOglDSq+XT4092myAiarSzQLA6smB+gk68M50W492+QNuc+6LAOfev+Da4geLiErqMpuIqfA3jw4h5+9Ns6mf3JnOLZd1c/X/xvnV3JjBzSJ6f9xGMLBcMTQm/wVfkHM9tO1oZrHswDiBlE1AkQrj6kqT9Kznu/rbAUGRnWL65FoCwdMbYVEhQQvLbLvVCRGBJfB01oD2xs80jyZ2YYZFRZCl/d0lGrVVVZsq6XM7CsxR5WlpJy5JLxCQ4kliG8cjexh0GkVYJoRYneJifw8yThMlyAnMQ88iNS2p2MnYk0WZgTJOIHliIhPRFY4z6BtrxmL8SR1no1vhaQCdbE5RI/rYbk8NpOmQunkjcDwp7nTKn1d8bMTfKGUH+DzhvmqwxA5PW37P84FFSK+3ePY9+oKXcInkAaxiXUpzcZJ4KzUGEZaZCB6irU+sxs6QLDzsq05PprwVz2DGtEn1TcY8qQ6ezeMGxJMRgDvEGq2J0nEgOEZ98CJ7XiPJRlnvUjGUzBlcjnbfFH8zzl/0p189YtENhE6Fyr5bD9MAI6NpVHjLLlg3yjmQ6X95fUtiNCmSpCUveEqIQCRtHCY2E/RrulGqTWE+vCvbM6IJV3WnatPOtWZfXEntWHmS08j6aUkUDM9TodBuzG8TRhW2Kgv8b4pfoejuMa4WkvwRAUU7V+clTWG26dT9UHdk+QuOIQDUiCewWk3PmpIJI4WdcxpBWwDvIgojob7uaGzhkabFKi77RJRc5/Ulxm6yM2MX79jgJxrQprWxxkjlsQnJk186nQZQqpuwziH/ZxV82n1bmI9zCqMXgE1Yr86gvyZpk2UbWhlFdtXEPapge9Cfo/fWUBCIbVcd77Bk98E88Y5Y372YWW+D8oHZed8l+0tCeyZmoHQNCYykcf6w77C+8C+bVdJplPns96vyLgbWIr0cpqZBK4qmkAxHuKZoG0AKRw4U379lnXOsI+02TaTzGOMlFTg4ME5miCbxo/2pUnjrydyTE5evdImLzKAK50Fhy1XASaPxgLrkjhGZebwf1UD2kYg6A1NCHchQId25vSEwGRkMPWvY3a5KOmgsMmRoOUJ17uo/r57p7nLgZV9c1+YEdZxu+GmgwQDLNGpgW1cpEN6GSVpx8xhaGKeYSuqd4lh6H9U5/P8masNckrsz+EHv+w5plzx8nJ/Fx/H50OdOm1KUjo66m26aITX7EjJB/U1qtqNfiK6dt8EttJ5iRXlCbfOkj2biRYeKbXQ2Ezr+61/Mu/W/nhLqmLFDtM6K3xf2bSJnEXQFZOOXTRkKXnRDP7Y47ZgG3563fJQjSfoU4Hsw5xnegTOKlJsoEm95Rnq0esdMTA450Ki2wBOeIsOycljoApACBYLAlSe+ewxEaOjrLtnIR0LfzcKXlCRYbM31YWOCtMhMRehJbX9qWGNPTQHmjabYz7/IhLKtJuaMIpj3pfYgS/oQQ36g6ItCo7vLQAq+rgU99IUyQROOGXMUgK/8umL71oijA9dht0LmH9E7EGwih0WuLO2SndovTJODDfK9YrRTEocbo3B9S05O4fpGoQ32TK99mXjoQdlyxd/dn9Q9uDD27u/fGgUoYdt9VzAIigbRIQuRx430n33V0ZyXv90QuD4ESOLxVI1vnLj6JKAS4PGRz66rouYG6U+1syDWpf5Y6DzC/2KOfdLPwmuwjMQxuhf+6+tGeJbeotNX/eJF0LkRfyieRwEGKxIo0PaxdmVwsF7vKR6ZnOpr5BuLm/+44Rg3bQdJ4bcRW6i6dIhOyHWniLvsAPLu1NZDVN6jA13KTChhcrNnSGddjRFLekawl80E3KhG1p+KvItIZX3kzG4QjJ
|
||||
CSC_KEY_PASSWORD:
|
||||
secure: GiXelhGGKXKUNW6T7ptKUw==
|
||||
CSC_LINK:
|
||||
secure: 9uSZwUYwcdZejLTpGpySd6t9JSL1Hw3iTvb4T2HZrx6iKd5DSR7AN6A7lS5ThTZ6g1JNSypSHRwDeC1Z5xkP8QEIjDqKjyNrqC19gCiSMrpdjjIR8Y8upIISrDBWjOiI
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"chrome:beta": "92.0.4515.40",
|
||||
"chrome:stable": "91.0.4472.77"
|
||||
"chrome:beta": "92.0.4515.93",
|
||||
"chrome:stable": "91.0.4472.114"
|
||||
}
|
||||
|
||||
28
circle.yml
28
circle.yml
@@ -8,7 +8,7 @@ macBuildFilters: &macBuildFilters
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- optimize-ci-resource-classes
|
||||
- tgriesser/fix/mac-build
|
||||
|
||||
defaults: &defaults
|
||||
parallelism: 1
|
||||
@@ -42,7 +42,6 @@ onlyMainBranches: &onlyMainBranches
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- optimize-ci-resource-classes
|
||||
requires:
|
||||
- create-build-artifacts
|
||||
|
||||
@@ -91,6 +90,11 @@ commands:
|
||||
at: ~/
|
||||
- unpack-dependencies
|
||||
|
||||
restore_cached_binary:
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
|
||||
prepare-modules-cache:
|
||||
parameters:
|
||||
dont-move:
|
||||
@@ -464,7 +468,7 @@ commands:
|
||||
description: "Name of the github repo to clone like: cypress-example-kitchensink"
|
||||
type: string
|
||||
steps:
|
||||
- restore_cached_workspace
|
||||
- restore_cached_binary
|
||||
- run:
|
||||
name: "Cloning test project: <<parameters.repo>>"
|
||||
command: |
|
||||
@@ -977,14 +981,14 @@ jobs:
|
||||
- run: yarn test-mocha
|
||||
# test binary build code
|
||||
- run: yarn test-scripts
|
||||
# check for compile errors with the releaserc scripts
|
||||
- run: yarn test-npm-package-release-script
|
||||
# make sure our snapshots are compared correctly
|
||||
- run: yarn test-mocha-snapshot
|
||||
# make sure packages with TypeScript can be transpiled to JS
|
||||
- run: yarn lerna run build-prod --stream
|
||||
# run unit tests from each individual package
|
||||
- run: yarn test
|
||||
# check for compile errors with the releaserc scripts
|
||||
- run: yarn test-npm-package-release-script
|
||||
- verify-mocha-results:
|
||||
expectedResultCount: 9
|
||||
- store_test_results:
|
||||
@@ -1451,8 +1455,8 @@ jobs:
|
||||
command: yarn launch:test
|
||||
working_directory: npm/cypress-schematic
|
||||
- run:
|
||||
name: Test Schematics
|
||||
command: yarn test:schematics
|
||||
name: Run unit tests
|
||||
command: yarn test
|
||||
working_directory: npm/cypress-schematic
|
||||
- store-npm-logs
|
||||
|
||||
@@ -1476,7 +1480,7 @@ jobs:
|
||||
- run:
|
||||
name: Check current branch to persist artifacts
|
||||
command: |
|
||||
if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "optimize-ci-resource-classes" ]]; then
|
||||
if [[ "$CIRCLE_BRANCH" != "develop" ]]; then
|
||||
echo "Not uploading artifacts or posting install comment for this branch."
|
||||
circleci-agent step halt
|
||||
fi
|
||||
@@ -2111,7 +2115,6 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- optimize-ci-resource-classes
|
||||
requires:
|
||||
- build
|
||||
- test-kitchensink:
|
||||
@@ -2123,7 +2126,6 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- optimize-ci-resource-classes
|
||||
requires:
|
||||
- build
|
||||
- create-build-artifacts:
|
||||
@@ -2173,7 +2175,6 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- optimize-ci-resource-classes
|
||||
requires:
|
||||
- create-build-artifacts
|
||||
- test-npm-module-and-verify-binary:
|
||||
@@ -2181,7 +2182,6 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- optimize-ci-resource-classes
|
||||
requires:
|
||||
- create-build-artifacts
|
||||
- test-binary-against-staging:
|
||||
@@ -2190,7 +2190,6 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- optimize-ci-resource-classes
|
||||
requires:
|
||||
- create-build-artifacts
|
||||
|
||||
@@ -2215,7 +2214,6 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- optimize-ci-resource-classes
|
||||
requires:
|
||||
- create-build-artifacts
|
||||
|
||||
@@ -2287,7 +2285,6 @@ mac-workflow: &mac-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- optimize-ci-resource-classes
|
||||
requires:
|
||||
- darwin-create-build-artifacts
|
||||
|
||||
@@ -2299,7 +2296,6 @@ mac-workflow: &mac-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- optimize-ci-resource-classes
|
||||
requires:
|
||||
- darwin-create-build-artifacts
|
||||
|
||||
|
||||
@@ -62,13 +62,9 @@ current message
|
||||
|
||||
----------
|
||||
|
||||
This is usually caused by a missing library or dependency.
|
||||
This may be due to a missing library or dependency. [34mhttps://on.cypress.io/required-dependencies[39m
|
||||
|
||||
The error above should indicate which dependency is missing.
|
||||
|
||||
[34mhttps://on.cypress.io/required-dependencies[39m
|
||||
|
||||
If you are using Docker, we provide containers with all required dependencies installed.
|
||||
Please refer to the error above for more detail.
|
||||
|
||||
----------
|
||||
|
||||
|
||||
@@ -116,13 +116,9 @@ STRIPPED
|
||||
|
||||
Error: Cypress failed to start.
|
||||
|
||||
This is usually caused by a missing library or dependency.
|
||||
This may be due to a missing library or dependency. https://on.cypress.io/required-dependencies
|
||||
|
||||
The error below should indicate which dependency is missing.
|
||||
|
||||
https://on.cypress.io/required-dependencies
|
||||
|
||||
If you are using Docker, we provide containers with all required dependencies installed.
|
||||
Please refer to the error below for more details.
|
||||
|
||||
----------
|
||||
|
||||
@@ -138,13 +134,9 @@ Cypress Version: 1.2.3
|
||||
exports['fails with no stderr 1'] = `
|
||||
Error: Cypress failed to start.
|
||||
|
||||
This is usually caused by a missing library or dependency.
|
||||
This may be due to a missing library or dependency. https://on.cypress.io/required-dependencies
|
||||
|
||||
The error below should indicate which dependency is missing.
|
||||
|
||||
https://on.cypress.io/required-dependencies
|
||||
|
||||
If you are using Docker, we provide containers with all required dependencies installed.
|
||||
Please refer to the error below for more details.
|
||||
|
||||
----------
|
||||
|
||||
@@ -414,13 +406,9 @@ some weird indent
|
||||
|
||||
----------
|
||||
|
||||
This is usually caused by a missing library or dependency.
|
||||
This may be due to a missing library or dependency. [34mhttps://on.cypress.io/required-dependencies[39m
|
||||
|
||||
The error above should indicate which dependency is missing.
|
||||
|
||||
[34mhttps://on.cypress.io/required-dependencies[39m
|
||||
|
||||
If you are using Docker, we provide containers with all required dependencies installed.
|
||||
Please refer to the error above for more detail.
|
||||
|
||||
----------
|
||||
|
||||
|
||||
72
cli/lib/VerboseRenderer.js
Normal file
72
cli/lib/VerboseRenderer.js
Normal file
@@ -0,0 +1,72 @@
|
||||
// Vendored from @cypress/listr-verbose-renderer
|
||||
const figures = require('figures')
|
||||
const cliCursor = require('cli-cursor')
|
||||
const chalk = require('chalk')
|
||||
const dayjs = require('dayjs')
|
||||
|
||||
const formattedLog = (options, output) => {
|
||||
const timestamp = dayjs().format(options.dateFormat)
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`${chalk.dim(`[${timestamp}]`) } ${output}`)
|
||||
}
|
||||
|
||||
const renderHelper = (task, event, options) => {
|
||||
const log = formattedLog.bind(undefined, options)
|
||||
|
||||
if (event.type === 'STATE') {
|
||||
const message = task.isPending() ? 'started' : task.state
|
||||
|
||||
log(`${task.title} [${message}]`)
|
||||
|
||||
if (task.isSkipped() && task.output) {
|
||||
log(`${figures.arrowRight} ${task.output}`)
|
||||
}
|
||||
} else if (event.type === 'TITLE') {
|
||||
log(`${task.title} [title changed]`)
|
||||
}
|
||||
}
|
||||
|
||||
const render = (tasks, options) => {
|
||||
for (const task of tasks) {
|
||||
task.subscribe(
|
||||
(event) => {
|
||||
if (event.type === 'SUBTASKS') {
|
||||
render(task.subtasks, options)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
renderHelper(task, event, options)
|
||||
},
|
||||
(err) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(err)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class VerboseRenderer {
|
||||
constructor (tasks, options) {
|
||||
this._tasks = tasks
|
||||
this._options = Object.assign({
|
||||
dateFormat: 'HH:mm:ss',
|
||||
}, options)
|
||||
}
|
||||
|
||||
static get nonTTY () {
|
||||
return true
|
||||
}
|
||||
|
||||
render () {
|
||||
cliCursor.hide()
|
||||
render(this._tasks, this._options)
|
||||
}
|
||||
|
||||
end () {
|
||||
cliCursor.show()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VerboseRenderer
|
||||
@@ -149,13 +149,9 @@ const invalidSmokeTestDisplayError = {
|
||||
|
||||
${hr}
|
||||
|
||||
This is usually caused by a missing library or dependency.
|
||||
This may be due to a missing library or dependency. ${chalk.blue(requiredDependenciesUrl)}
|
||||
|
||||
The error above should indicate which dependency is missing.
|
||||
|
||||
${chalk.blue(requiredDependenciesUrl)}
|
||||
|
||||
If you are using Docker, we provide containers with all required dependencies installed.
|
||||
Please refer to the error above for more detail.
|
||||
`
|
||||
},
|
||||
}
|
||||
@@ -164,13 +160,9 @@ const missingDependency = {
|
||||
description: 'Cypress failed to start.',
|
||||
// this message is too Linux specific
|
||||
solution: stripIndent`
|
||||
This is usually caused by a missing library or dependency.
|
||||
This may be due to a missing library or dependency. ${chalk.blue(requiredDependenciesUrl)}
|
||||
|
||||
The error below should indicate which dependency is missing.
|
||||
|
||||
${chalk.blue(requiredDependenciesUrl)}
|
||||
|
||||
If you are using Docker, we provide containers with all required dependencies installed.
|
||||
Please refer to the error below for more details.
|
||||
`,
|
||||
}
|
||||
|
||||
|
||||
@@ -73,15 +73,15 @@ module.exports = {
|
||||
|
||||
debug('needs to start own Xvfb?', needsXvfb)
|
||||
|
||||
// 1. Start arguments with "--" so Electron knows these are OUR
|
||||
// arguments and does not try to sanitize them. Otherwise on Windows
|
||||
// an url in one of the arguments crashes it :(
|
||||
// https://github.com/cypress-io/cypress/issues/5466
|
||||
|
||||
// 2. Always push cwd into the args
|
||||
// Always push cwd into the args
|
||||
// which additionally acts as a signal to the
|
||||
// binary that it was invoked through the NPM module
|
||||
args = ['--'].concat(args, '--cwd', process.cwd())
|
||||
args = args || []
|
||||
if (typeof args === 'string') {
|
||||
args = [args]
|
||||
}
|
||||
|
||||
args = [...args, '--cwd', process.cwd()]
|
||||
|
||||
_.defaults(options, {
|
||||
dev: false,
|
||||
@@ -97,26 +97,24 @@ module.exports = {
|
||||
electronLogging: false,
|
||||
})
|
||||
|
||||
const { onStderrData, electronLogging } = overrides
|
||||
const envOverrides = util.getEnvOverrides(options)
|
||||
const electronArgs = []
|
||||
const node11WindowsFix = isPlatform('win32')
|
||||
|
||||
if (options.dev) {
|
||||
// if we're in dev then reset
|
||||
// the launch cmd to be 'npm run dev'
|
||||
executable = 'node'
|
||||
args.unshift(
|
||||
electronArgs.unshift(
|
||||
path.resolve(__dirname, '..', '..', '..', 'scripts', 'start.js'),
|
||||
)
|
||||
|
||||
debug('in dev mode the args became %o', args)
|
||||
}
|
||||
|
||||
const { onStderrData, electronLogging } = overrides
|
||||
const envOverrides = util.getEnvOverrides(options)
|
||||
const electronArgs = _.clone(args)
|
||||
const node11WindowsFix = isPlatform('win32')
|
||||
|
||||
if (!options.dev && verify.needsSandbox()) {
|
||||
// this is one of the Electron's command line switches
|
||||
// thus it needs to be before "--" separator
|
||||
electronArgs.unshift('--no-sandbox')
|
||||
electronArgs.push('--no-sandbox')
|
||||
}
|
||||
|
||||
// strip dev out of child process options
|
||||
@@ -141,10 +139,22 @@ module.exports = {
|
||||
stdioOptions.env.DISPLAY = process.env.DISPLAY
|
||||
}
|
||||
|
||||
debug('spawning Cypress with executable: %s', executable)
|
||||
debug('spawn args %o %o', electronArgs, _.omit(stdioOptions, 'env'))
|
||||
if (stdioOptions.env.ELECTRON_RUN_AS_NODE) {
|
||||
// Since we are running electron as node, we need to add an entry point file.
|
||||
const serverEntryPoint = path.join(state.getBinaryPkgPath(path.dirname(executable)), '..', 'index.js')
|
||||
|
||||
const child = cp.spawn(executable, electronArgs, stdioOptions)
|
||||
args = [serverEntryPoint, ...args]
|
||||
} else {
|
||||
// Start arguments with "--" so Electron knows these are OUR
|
||||
// arguments and does not try to sanitize them. Otherwise on Windows
|
||||
// an url in one of the arguments crashes it :(
|
||||
// https://github.com/cypress-io/cypress/issues/5466
|
||||
args = [...electronArgs, '--', ...args]
|
||||
}
|
||||
|
||||
debug('spawning Cypress with executable: %s', executable)
|
||||
debug('spawn args %o %o', args, _.omit(stdioOptions, 'env'))
|
||||
const child = cp.spawn(executable, args, stdioOptions)
|
||||
|
||||
function resolveOn (event) {
|
||||
return function (code, signal) {
|
||||
|
||||
@@ -58,6 +58,12 @@ module.exports = {
|
||||
},
|
||||
|
||||
isNeeded () {
|
||||
if (process.env.ELECTRON_RUN_AS_NODE) {
|
||||
debug('Environment variable ELECTRON_RUN_AS_NODE detected, xvfb is not needed')
|
||||
|
||||
return false // xvfb required for electron processes only.
|
||||
}
|
||||
|
||||
if (os.platform() !== 'linux') {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ const path = require('path')
|
||||
const chalk = require('chalk')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const { Listr } = require('listr2')
|
||||
const verbose = require('@cypress/listr-verbose-renderer')
|
||||
const Promise = require('bluebird')
|
||||
const logSymbols = require('log-symbols')
|
||||
const { stripIndent } = require('common-tags')
|
||||
@@ -16,6 +15,7 @@ const state = require('./state')
|
||||
const unzip = require('./unzip')
|
||||
const logger = require('../logger')
|
||||
const { throwFormErrorText, errors } = require('../errors')
|
||||
const verbose = require('../VerboseRenderer')
|
||||
|
||||
const getNpmArgv = () => {
|
||||
const json = process.env.npm_config_argv
|
||||
|
||||
@@ -2,13 +2,13 @@ const _ = require('lodash')
|
||||
const chalk = require('chalk')
|
||||
const { Listr } = require('listr2')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const verbose = require('@cypress/listr-verbose-renderer')
|
||||
const { stripIndent } = require('common-tags')
|
||||
const Promise = require('bluebird')
|
||||
const logSymbols = require('log-symbols')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
|
||||
const verbose = require('../VerboseRenderer')
|
||||
const { throwFormErrorText, errors } = require('../errors')
|
||||
const util = require('../util')
|
||||
const logger = require('../logger')
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"unit": "cross-env BLUEBIRD_DEBUG=1 NODE_ENV=test mocha --reporter mocha-multi-reporters --reporter-options configFile=../mocha-reporter-config.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cypress/listr-verbose-renderer": "^0.4.1",
|
||||
"@cypress/request": "^2.88.5",
|
||||
"@cypress/xvfb": "^1.2.4",
|
||||
"@types/node": "^14.14.31",
|
||||
@@ -32,15 +31,18 @@
|
||||
"cachedir": "^2.3.0",
|
||||
"chalk": "^4.1.0",
|
||||
"check-more-types": "^2.24.0",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"cli-table3": "~0.6.0",
|
||||
"commander": "^5.1.0",
|
||||
"common-tags": "^1.8.0",
|
||||
"dayjs": "^1.10.4",
|
||||
"debug": "4.3.2",
|
||||
"debug": "^4.3.2",
|
||||
"enquirer": "^2.3.6",
|
||||
"eventemitter2": "^6.4.3",
|
||||
"execa": "4.1.0",
|
||||
"executable": "^4.1.1",
|
||||
"extract-zip": "2.0.1",
|
||||
"figures": "^3.2.0",
|
||||
"fs-extra": "^9.1.0",
|
||||
"getos": "^3.2.1",
|
||||
"is-ci": "^3.0.0",
|
||||
|
||||
30
cli/types/cypress.d.ts
vendored
30
cli/types/cypress.d.ts
vendored
@@ -60,7 +60,7 @@ declare namespace Cypress {
|
||||
*/
|
||||
displayName: string
|
||||
version: string
|
||||
majorVersion: number
|
||||
majorVersion: number | string
|
||||
path: string
|
||||
isHeaded: boolean
|
||||
isHeadless: boolean
|
||||
@@ -490,6 +490,13 @@ declare namespace Cypress {
|
||||
getElementCoordinatesByPositionRelativeToXY(element: JQuery | HTMLElement, x: number, y: number): ElementPositioning
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://on.cypress.io/keyboard-api
|
||||
*/
|
||||
Keyboard: {
|
||||
defaults(options: Partial<KeyboardDefaultsOptions>): void
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://on.cypress.io/api/api-server
|
||||
*/
|
||||
@@ -841,7 +848,7 @@ declare namespace Cypress {
|
||||
* // tries to find the given text for up to 1 second
|
||||
* cy.contains('my text to find', {timeout: 1000})
|
||||
*/
|
||||
contains(content: string | number | RegExp, options?: Partial<Loggable & Timeoutable & CaseMatchable>): Chainable<Subject>
|
||||
contains(content: string | number | RegExp, options?: Partial<Loggable & Timeoutable & CaseMatchable & Shadow>): Chainable<Subject>
|
||||
/**
|
||||
* Get the child DOM element that contains given text.
|
||||
*
|
||||
@@ -859,7 +866,7 @@ declare namespace Cypress {
|
||||
* // yields <ul>...</ul>
|
||||
* cy.contains('ul', 'apples')
|
||||
*/
|
||||
contains<K extends keyof HTMLElementTagNameMap>(selector: K, text: string | number | RegExp, options?: Partial<Loggable & Timeoutable & CaseMatchable>): Chainable<JQuery<HTMLElementTagNameMap[K]>>
|
||||
contains<K extends keyof HTMLElementTagNameMap>(selector: K, text: string | number | RegExp, options?: Partial<Loggable & Timeoutable & CaseMatchable & Shadow>): Chainable<JQuery<HTMLElementTagNameMap[K]>>
|
||||
/**
|
||||
* Get the DOM element using CSS "selector" containing the text or regular expression.
|
||||
*
|
||||
@@ -868,7 +875,7 @@ declare namespace Cypress {
|
||||
* // yields <... class="foo">... apples ...</...>
|
||||
* cy.contains('.foo', 'apples')
|
||||
*/
|
||||
contains<E extends Node = HTMLElement>(selector: string, text: string | number | RegExp, options?: Partial<Loggable & Timeoutable & CaseMatchable>): Chainable<JQuery<E>>
|
||||
contains<E extends Node = HTMLElement>(selector: string, text: string | number | RegExp, options?: Partial<Loggable & Timeoutable & CaseMatchable & Shadow>): Chainable<JQuery<E>>
|
||||
|
||||
/**
|
||||
* Double-click a DOM element.
|
||||
@@ -2762,8 +2769,6 @@ declare namespace Cypress {
|
||||
clientRoute: string
|
||||
configFile: string
|
||||
cypressEnv: string
|
||||
integrationExampleName: string
|
||||
integrationExamplePath: string
|
||||
isNewProject: boolean
|
||||
isTextTerminal: boolean
|
||||
morgan: boolean
|
||||
@@ -2792,6 +2797,7 @@ declare namespace Cypress {
|
||||
|
||||
interface TestConfigOverrides extends Partial<Pick<ConfigOptions, 'animationDistanceThreshold' | 'baseUrl' | 'defaultCommandTimeout' | 'env' | 'execTimeout' | 'includeShadowDom' | 'requestTimeout' | 'responseTimeout' | 'retries' | 'scrollBehavior' | 'taskTimeout' | 'viewportHeight' | 'viewportWidth' | 'waitForAnimations'>> {
|
||||
browser?: IsBrowserMatcher | IsBrowserMatcher[]
|
||||
keystrokeDelay?: number
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2842,6 +2848,18 @@ declare namespace Cypress {
|
||||
env: object
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for Cypress.Keyboard.defaults()
|
||||
*/
|
||||
interface KeyboardDefaultsOptions {
|
||||
/**
|
||||
* Time, in milliseconds, between each keystroke when typing. (Pass 0 to disable)
|
||||
*
|
||||
* @default 10
|
||||
*/
|
||||
keystrokeDelay: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Full set of possible options for cy.request call
|
||||
*/
|
||||
|
||||
@@ -473,8 +473,8 @@ namespace CypressContainsTests {
|
||||
cy.contains('#app')
|
||||
cy.contains('my text to find')
|
||||
cy.contains('#app', 'my text to find')
|
||||
cy.contains('#app', 'my text to find', {log: false, timeout: 100})
|
||||
cy.contains('my text to find', {log: false, timeout: 100})
|
||||
cy.contains('#app', 'my text to find', { log: false, timeout: 100, matchCase: false, includeShadowDom: true })
|
||||
cy.contains('my text to find', { log: false, timeout: 100, matchCase: false, includeShadowDom: true })
|
||||
}
|
||||
|
||||
// https://github.com/cypress-io/cypress/pull/5574
|
||||
@@ -601,17 +601,19 @@ namespace CypressTestConfigOverridesTests {
|
||||
browser: [{name: 'firefox'}, {name: 'chrome'}]
|
||||
}, () => {})
|
||||
it('test', {
|
||||
browser: 'firefox'
|
||||
browser: 'firefox',
|
||||
keystrokeDelay: 0
|
||||
}, () => {})
|
||||
it('test', {
|
||||
browser: {foo: 'bar'} // $ExpectError
|
||||
browser: {foo: 'bar'}, // $ExpectError
|
||||
}, () => {})
|
||||
|
||||
it('test', {
|
||||
retries: null
|
||||
retries: null,
|
||||
keystrokeDelay: 0
|
||||
}, () => { })
|
||||
it('test', {
|
||||
retries: 3
|
||||
retries: 3,
|
||||
keystrokeDelay: false, // $ExpectError
|
||||
}, () => { })
|
||||
it('test', {
|
||||
retries: {
|
||||
@@ -640,14 +642,16 @@ namespace CypressTestConfigOverridesTests {
|
||||
// set config on a per-suite basis
|
||||
describe('suite', {
|
||||
browser: {family: 'firefox'},
|
||||
baseUrl: 'www.example.com'
|
||||
baseUrl: 'www.example.com',
|
||||
keystrokeDelay: 0
|
||||
}, () => {})
|
||||
|
||||
context('suite', {}, () => {})
|
||||
|
||||
describe('suite', {
|
||||
browser: {family: 'firefox'},
|
||||
baseUrl: 'www.example.com'
|
||||
baseUrl: 'www.example.com',
|
||||
keystrokeDelay: false // $ExpectError
|
||||
foo: 'foo' // $ExpectError
|
||||
}, () => {})
|
||||
|
||||
@@ -681,3 +685,18 @@ namespace CypressTaskTests {
|
||||
val // $ExpectType unknown
|
||||
})
|
||||
}
|
||||
|
||||
namespace CypressKeyboardTests {
|
||||
Cypress.Keyboard.defaults({
|
||||
keystrokeDelay: 0
|
||||
})
|
||||
Cypress.Keyboard.defaults({
|
||||
keystrokeDelay: 500
|
||||
})
|
||||
Cypress.Keyboard.defaults({
|
||||
keystrokeDelay: false // $ExpectError
|
||||
})
|
||||
Cypress.Keyboard.defaults({
|
||||
delay: 500 // $ExpectError
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
"entitlementsInherit": "./scripts/entitlements.mac.inherit.plist",
|
||||
"type": "distribution",
|
||||
"binaries": [
|
||||
"./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/babel-plugin-add-module-exports/node_modules/fsevents/build/Release/.node",
|
||||
"./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/babel-plugin-add-module-exports/node_modules/fsevents/build/Release/fse.node",
|
||||
"./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/@ffmpeg-installer/darwin-x64/ffmpeg",
|
||||
"./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/watchpack-chokidar2/node_modules/fsevents/build/Release/.node",
|
||||
"./build/mac/Cypress.app/Contents/Resources/app/packages/server/node_modules/watchpack-chokidar2/node_modules/fsevents/build/Release/fse.node",
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
# @cypress/angular
|
||||
|
||||
[](https://badge.fury.io/js/@cypress/angular) [![renovate-app badge][renovate-badge]][renovate-app]  [![ci status][ci image]][ci url] [](https://dashboard.cypress.io/projects/nf7zag/runs)
|
||||
|
||||
## Installation
|
||||
|
||||
NOTE: this is not published on npm yet. It's a work in progress. Consider [Cypress Angular
|
||||
](https://github.com/jscutlery/test-utils/tree/main/packages/cypress-angular) by [JS Cutlery](https://github.com/jscutlery) for a version that's currently working and available on npm.
|
||||
|
||||
```shell
|
||||
npm install -D cypress @cypress/angular @cypress/webpack-preprocessor
|
||||
npm install -D cypress @cypress/angular @cypress/webpack-dev-server
|
||||
```
|
||||
|
||||
Add to your support file
|
||||
Ensure you have a version of Cypress > 7.
|
||||
|
||||
Add the following to your support file:
|
||||
|
||||
```js
|
||||
// cypress/support/index.js
|
||||
@@ -19,12 +22,6 @@ require('core-js/es7/reflect');
|
||||
require('@cypress/angular/support');
|
||||
```
|
||||
|
||||
### Cypress >= v7
|
||||
|
||||
```shell
|
||||
npm install -D @cypress/webpack-dev-server
|
||||
```
|
||||
|
||||
Enable component testing in `cypress.json`.
|
||||
|
||||
```json
|
||||
@@ -53,59 +50,38 @@ module.exports = (on, config) => {
|
||||
};
|
||||
```
|
||||
|
||||
The `webpack.config.ts` file is [here](cypress/plugins/webpack.config.ts)
|
||||
|
||||
### Cypress < v7
|
||||
|
||||
Enable experimental component testing mode in `cypress.json` and point at the spec files. Usually they are alongside your application files in `src` folder.
|
||||
|
||||
```json
|
||||
{
|
||||
"experimentalComponentTesting": true,
|
||||
"componentFolder": "src",
|
||||
"testFiles": "**/*cy-spec.*"
|
||||
}
|
||||
```
|
||||
|
||||
Configure `cypress/plugins/index.js` to transpile Angular code.
|
||||
|
||||
```javascript
|
||||
const wp = require('@cypress/webpack-preprocessor');
|
||||
import * as webpackOptions from './webpack.config';
|
||||
module.exports = (on, config) => {
|
||||
const options = {
|
||||
webpackOptions,
|
||||
};
|
||||
on('file:preprocessor', wp(options));
|
||||
return config;
|
||||
};
|
||||
```
|
||||
|
||||
The `webpack.config.ts` file is [here](cypress/plugins/webpack.config.ts)
|
||||
The `webpack.config.ts` file is [here](cypress/plugins/webpack.config.ts).
|
||||
|
||||
## Use
|
||||
|
||||
```js
|
||||
import { mount } from '@cypress/angular';
|
||||
import { AppComponent } from './app.component';
|
||||
import { initEnv, mount } from '@cypress/angular'
|
||||
import { AppModule } from '../app.module'
|
||||
import { InputComponent } from './input.component'
|
||||
|
||||
describe('AppComponent', () => {
|
||||
it('shows the input', () => {
|
||||
// Init Angular stuff
|
||||
initEnv(AppComponent);
|
||||
// You can also :
|
||||
// initEnv({declarations: [AppComponent]});
|
||||
// initEnv({imports: [MyModule]});
|
||||
describe('InputComponent', () => {
|
||||
it('should show default value input', () => {
|
||||
initEnv(InputComponent)
|
||||
mount(InputComponent)
|
||||
cy.contains('My input value 4')
|
||||
})
|
||||
|
||||
it('should replace default value input', () => {
|
||||
initEnv({ declarations: [InputComponent] })
|
||||
mount(InputComponent, { myInput: 9 })
|
||||
cy.contains('My input value 9')
|
||||
})
|
||||
|
||||
it('should show default value input with AppModule', () => {
|
||||
initEnv({ imports: [AppModule] })
|
||||
mount(InputComponent)
|
||||
cy.contains('My input value 4')
|
||||
})
|
||||
})
|
||||
|
||||
// component + any inputs object
|
||||
mount(AppComponent, { title: 'World' });
|
||||
// use any Cypress command afterwards
|
||||
cy.contains('Welcome to World!');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
## Examples
|
||||
|
||||
@@ -219,41 +195,22 @@ rules: [
|
||||
|
||||
You can find the HTML report at `coverage/lcov-report/index.html`
|
||||
|
||||
## Working
|
||||
|
||||
I have successfully used this mounting approach to test components in other frameworks.
|
||||
|
||||
- [cypress-vue-unit-test](https://github.com/bahmutov/cypress-vue-unit-test)
|
||||
- [cypress-react-unit-test](https://github.com/bahmutov/cypress-react-unit-test)
|
||||
- [cypress-cycle-unit-test](https://github.com/bahmutov/cypress-cycle-unit-test)
|
||||
- [cypress-svelte-unit-test](https://github.com/bahmutov/cypress-svelte-unit-test)
|
||||
- [@cypress/angular](https://github.com/bahmutov/@cypress/angular)
|
||||
- [cypress-hyperapp-unit-test](https://github.com/bahmutov/cypress-hyperapp-unit-test)
|
||||
- [cypress-angularjs-unit-test](https://github.com/bahmutov/cypress-angularjs-unit-test)
|
||||
|
||||
## Debugging
|
||||
|
||||
You can turn on debugging log by setting environment variable :
|
||||
|
||||
```bash
|
||||
// Unix
|
||||
export DEBUG="@cypress/angular,cypress:webpack:stats"
|
||||
export DEBUG="@cypress/angular,cypress:webpack:dev-server"
|
||||
|
||||
// PowerShell
|
||||
$env:DEBUG="@cypress/angular,cypress:webpack:stats"
|
||||
$env:DEBUG="@cypress/angular,cypress:webpack:dev-server"
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
This project only transpiles the library, to see it in action:
|
||||
|
||||
- Install dependencies `npm i`
|
||||
- Compile the library `npm run build`
|
||||
- Open Cypress with `npx cypress open`
|
||||
|
||||
Pick any component test spec file to run
|
||||
|
||||
[renovate-badge]: https://img.shields.io/badge/renovate-app-blue.svg
|
||||
[renovate-app]: https://renovateapp.com/
|
||||
[ci image]: https://github.com/bahmutov/@cypress/angular/workflows/ci/badge.svg?branch=master
|
||||
[ci url]: https://github.com/bahmutov/@cypress/angular/actions
|
||||
- Install dependencies `yarn`
|
||||
- Compile the library `yarn build` or `yarn watch` for watch mode
|
||||
- Open Cypress with `yarn cy:open`
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 197 KiB |
BIN
npm/angular/images/demo.png
Normal file
BIN
npm/angular/images/demo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
@@ -59,7 +59,7 @@
|
||||
"to-string-loader": "1.1.6",
|
||||
"ts-loader": "8.1.0",
|
||||
"ts-node": "9.1.1",
|
||||
"tslib": "2.2.0",
|
||||
"tslib": "^2.2.0",
|
||||
"tslint": "5.20.1",
|
||||
"typescript": "4.2.4",
|
||||
"webpack-dev-server": "3.11.2",
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# [create-cypress-tests-v1.1.2](https://github.com/cypress-io/cypress/compare/create-cypress-tests-v1.1.1...create-cypress-tests-v1.1.2) (2021-06-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* case issue create cypress tests with `react/plugins/load-webpack` ([#16961](https://github.com/cypress-io/cypress/issues/16961)) ([c37ecea](https://github.com/cypress-io/cypress/commit/c37ecea3ca462015637515b331d1c9828ac1ed29)), closes [#16960](https://github.com/cypress-io/cypress/issues/16960)
|
||||
|
||||
# [create-cypress-tests-v1.1.1](https://github.com/cypress-io/cypress/compare/create-cypress-tests-v1.1.0...create-cypress-tests-v1.1.1) (2021-05-10)
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ module.exports = (on, config) => {
|
||||
if (config.testingType === "component") {
|
||||
injectDevServer(on, config, {
|
||||
// TODO replace with valid webpack config path
|
||||
webpackFileName: './webpack.config.js'
|
||||
webpackFilename: './webpack.config.js'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ const something = require("something");
|
||||
module.exports = (on, config) => {
|
||||
if (config.testingType === "component") {
|
||||
injectDevServer(on, config, {
|
||||
webpackFileName: 'config/webpack.config.js'
|
||||
webpackFilename: 'config/webpack.config.js'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export const WebpackTemplate: Template<{ webpackConfigPath: string }> = {
|
||||
includeWarnComment
|
||||
? ' // TODO replace with valid webpack config path'
|
||||
: '',
|
||||
` webpackFileName: '${webpackConfigPath}'`,
|
||||
` webpackFilename: '${webpackConfigPath}'`,
|
||||
'})',
|
||||
].join('\n'), { preserveComments: true }),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,5 @@ module.exports = {
|
||||
...require('../../.releaserc.base'),
|
||||
branches: [
|
||||
{ name: 'master', channel: 'latest' },
|
||||
{ name: 'next/npm/cypress-schematic', channel: 'next', prerelease: 'alpha' },
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,3 +1,32 @@
|
||||
# [@cypress/schematic-v1.4.2](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v1.4.1...@cypress/schematic-v1.4.2) (2021-06-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* plugin file referenced by cypress config in angular schematics ([#17143](https://github.com/cypress-io/cypress/issues/17143)) ([5c2efc7](https://github.com/cypress-io/cypress/commit/5c2efc750779b75792b579b3196c8cb8af1f72f9))
|
||||
|
||||
# [@cypress/schematic-v1.4.1](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v1.4.0...@cypress/schematic-v1.4.1) (2021-06-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* plugin file in angular schematics ([#17141](https://github.com/cypress-io/cypress/issues/17141)) ([7b4d694](https://github.com/cypress-io/cypress/commit/7b4d69430368e87108310aa5e592786a32104561))
|
||||
|
||||
# [@cypress/schematic-v1.4.0](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v1.3.1...@cypress/schematic-v1.4.0) (2021-06-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ng generate to @cypress/schematic to generate e2e spec files ([#16962](https://github.com/cypress-io/cypress/issues/16962)) ([96a9db4](https://github.com/cypress-io/cypress/commit/96a9db4204f50a7605a5e51d51584d27aa9df164))
|
||||
|
||||
# [@cypress/schematic-v1.3.1](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v1.3.0...@cypress/schematic-v1.3.1) (2021-06-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ensure schematic is installed as devDependency ([#16965](https://github.com/cypress-io/cypress/issues/16965)) ([b49fcaf](https://github.com/cypress-io/cypress/commit/b49fcaf9cfc929313ed681248f6ca9c0a0bdf8c5))
|
||||
* **angular:** set rxjs versions > 6.6.0 as dependency ([#16676](https://github.com/cypress-io/cypress/issues/16676)) ([46de81e](https://github.com/cypress-io/cypress/commit/46de81e75fd18bc37cb884e9a751106fff4d08ad))
|
||||
|
||||
# [@cypress/schematic-v1.3.0](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v1.2.0...@cypress/schematic-v1.3.0) (2021-05-26)
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
✅ Scaffold base Cypress files and directories
|
||||
|
||||
✅ Provide the ability to add new e2e files easily using `ng-generate`
|
||||
|
||||
✅ Optional: prompt you to add or update the default `ng e2e` command to use Cypress.
|
||||
|
||||
## Usage ⏯
|
||||
@@ -50,6 +52,12 @@ If you have chosen to add or update the `ng e2e` command, you can also run Cypre
|
||||
ng e2e
|
||||
```
|
||||
|
||||
To generate new e2e spec files:
|
||||
|
||||
```shell script
|
||||
ng generate @cypress/schematic:e2e
|
||||
```
|
||||
|
||||
## Builder Options 🛠
|
||||
|
||||
### Running the builder with a specific browser
|
||||
@@ -138,6 +146,36 @@ Read our docs to learn more about all the [configuration options](https://on.cyp
|
||||
|
||||
Read our docs to learn more about speeding up test execution in CI via [Cypress parallelization](https://on.cypress.io/parallelization)
|
||||
|
||||
## Generator Options
|
||||
|
||||
### Specify Filename (bypassing CLI prompt)
|
||||
|
||||
In order to bypass the prompt asking for your e2e spec name, simply add a `--name=` flag like this:
|
||||
|
||||
```shell script
|
||||
ng generate @cypress/schematic:e2e --name=login
|
||||
```
|
||||
|
||||
This will create a new spec file named `login.spec.ts` in the default Cypress folder location.
|
||||
|
||||
|
||||
### Specify Project
|
||||
|
||||
Add a `--project=` flag to specify the project:
|
||||
|
||||
```shell script
|
||||
ng generate @cypress/schematic:e2e --name=login --project=sandbox
|
||||
```
|
||||
### Specify Path
|
||||
|
||||
Add a `--path=` flag to specify the project:
|
||||
|
||||
```shell script
|
||||
ng generate @cypress/schematic:e2e --name=login --path=src/app/tests
|
||||
```
|
||||
|
||||
This will create the e2e spec file in your specific location, creating folders as needed.
|
||||
|
||||
## Migrating from Protractor to Cypress?
|
||||
|
||||
Read our [migration guide](https://on.cypress.io/protractor-to-cypress) to help you make the transition from Protractor to Cypress.
|
||||
|
||||
@@ -11,11 +11,9 @@
|
||||
"build:watch": "tsc -p tsconfig.json --watch",
|
||||
"clean": "git checkout HEAD -- sandbox && git clean -f -d sandbox",
|
||||
"launch": "yarn link:sandbox && cd sandbox && ng add @cypress/schematic && cd ..",
|
||||
"launch:test": "yarn link:sandbox && cd sandbox && ng add @cypress/schematic && cd ..",
|
||||
"launch:test": "yarn link:sandbox && cd sandbox && ng add @cypress/schematic --e2eUpdate=true && cd ..",
|
||||
"link:sandbox": "yarn link && cd sandbox && yarn link @cypress/schematic",
|
||||
"test:all": "yarn build:all && yarn test:schematics && yarn launch:test && yarn test:builders",
|
||||
"test:builders": "mocha -r @packages/ts/register --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json src/builders/cypress/index_spec.ts",
|
||||
"test:schematics": "mocha -r @packages/ts/register --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json src/schematics/cypress/index_spec.ts",
|
||||
"test": "mocha -r @packages/ts/register --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json src/**/*.spec.ts",
|
||||
"test:e2e:sandbox": "cd sandbox && ng run sandbox:cypress-run",
|
||||
"unlink:sandbox": "cd sandbox && yarn unlink @cypress/schematic && cd .. && yarn unlink"
|
||||
},
|
||||
@@ -56,5 +54,8 @@
|
||||
"registry": "http://registry.npmjs.org/"
|
||||
},
|
||||
"builders": "./src/builders/builders.json",
|
||||
"ng-add": {
|
||||
"save": "devDependencies"
|
||||
},
|
||||
"schematics": "./src/schematics/collection.json"
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { dirname, join } from 'path'
|
||||
import { open, run } from 'cypress'
|
||||
import { from, noop, Observable, of } from 'rxjs'
|
||||
import { catchError, concatMap, first, map, switchMap, tap } from 'rxjs/operators'
|
||||
import { CypressBuilderOptions } from './cypress-builder-options'
|
||||
import { CypressBuilderOptions } from './cypressBuilderOptions'
|
||||
|
||||
type CypressOptions = Partial<CypressCommandLine.CypressRunOptions> &
|
||||
Partial<CypressCommandLine.CypressOpenOptions>;
|
||||
|
||||
@@ -3,8 +3,16 @@
|
||||
"schematics": {
|
||||
"ng-add": {
|
||||
"description": "Adds Cypress to an Angular project.",
|
||||
"factory": "./cypress/index",
|
||||
"schema": "./cypress/schema.json"
|
||||
"factory": "./ng-add/index",
|
||||
"schema": "./ng-add/schema.json"
|
||||
},
|
||||
"e2e": {
|
||||
"description": "Create an e2e spec file",
|
||||
"factory": "./ng-generate/e2e/index",
|
||||
"schema": "./ng-generate/e2e/schema.json",
|
||||
"aliases": [
|
||||
"e2e-spec"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = (on, config) => {}
|
||||
@@ -3,7 +3,7 @@
|
||||
"supportFile": "<%= root%>cypress/support/index.ts",
|
||||
"videosFolder": "<%= root%>cypress/videos",
|
||||
"screenshotsFolder": "<%= root%>cypress/screenshots",
|
||||
"pluginsFile": "<%= root%>cypress/plugins/index.js",
|
||||
"pluginsFile": "<%= root%>cypress/plugins/index.ts",
|
||||
"fixturesFolder": "<%= root%>cypress/fixtures",
|
||||
"baseUrl": "<%= baseUrl%>"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// Plugins enable you to tap into, modify, or extend the internal behavior of Cypress
|
||||
// For more info, visit https://on.cypress.io/plugins-api
|
||||
module.exports = (on, config) => {}
|
||||
@@ -30,7 +30,7 @@ describe('@cypress/schematic: ng-add', () => {
|
||||
})
|
||||
|
||||
it('should create cypress files', async () => {
|
||||
const files = ['cypress/integration/spec.ts', 'cypress/plugins/index.js', 'cypress/support/commands.ts', 'cypress/support/index.ts', 'cypress/tsconfig.json', 'cypress.json']
|
||||
const files = ['cypress/integration/spec.ts', 'cypress/plugins/index.ts', 'cypress/support/commands.ts', 'cypress/support/index.ts', 'cypress/tsconfig.json', 'cypress.json']
|
||||
const homePath = '/projects/sandbox/'
|
||||
|
||||
return schematicRunner.runSchematicAsync('ng-add', {}, appTree).toPromise().then((tree) => {
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
NodePackage,
|
||||
} from '../utility'
|
||||
import { relative, resolve } from 'path'
|
||||
import { JSONFile, JSONPath } from '../utility/json-file'
|
||||
import { JSONFile, JSONPath } from '../utility/jsonFile'
|
||||
|
||||
export default function (_options: any): Rule {
|
||||
return (tree: Tree, _context: SchematicContext) => {
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "cypress-schematic",
|
||||
"title": "Cypress ng-add schematic",
|
||||
"title": "Cypress Install Schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"e2eUpdate": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "When true, `ng e2e` will be added or updated to use Cypress",
|
||||
"x-prompt": "Would you like the default `ng e2e` command to use Cypress? [ Protractor to Cypress Migration Guide: https://on.cypress.io/protractor-to-cypress ]"
|
||||
"x-prompt": "Would you like the default `ng e2e` command to use Cypress? [ Protractor to Cypress Migration Guide: https://on.cypress.io/protractor-to-cypress?cli=true ]"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
@@ -0,0 +1,43 @@
|
||||
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'
|
||||
import { join, resolve } from 'path'
|
||||
import { expect } from 'chai'
|
||||
|
||||
describe('@cypress/schematic:e2e ng-generate', () => {
|
||||
const schematicRunner = new SchematicTestRunner(
|
||||
'schematics',
|
||||
join(__dirname, '../../collection.json'),
|
||||
)
|
||||
let appTree: UnitTestTree
|
||||
|
||||
const workspaceOptions = {
|
||||
name: 'workspace',
|
||||
newProjectRoot: 'projects',
|
||||
version: '12.0.0',
|
||||
}
|
||||
|
||||
const appOptions = {
|
||||
name: 'sandbox',
|
||||
inlineTemplate: false,
|
||||
routing: false,
|
||||
skipTests: false,
|
||||
skipPackageJson: false,
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
appTree = await schematicRunner.runExternalSchematicAsync('@schematics/angular', 'workspace', workspaceOptions).toPromise()
|
||||
appTree = await schematicRunner.runExternalSchematicAsync('@schematics/angular', 'application', appOptions, appTree).toPromise()
|
||||
})
|
||||
|
||||
it('should create cypress files', async () => {
|
||||
const files = ['cypress/integration/foo.spec.ts']
|
||||
const homePath = '/projects/sandbox/'
|
||||
|
||||
return schematicRunner.runSchematicAsync('e2e', { name: 'foo' }, appTree).toPromise().then((tree) => {
|
||||
files.forEach((f) => {
|
||||
const pathToFile = resolve(homePath, f)
|
||||
|
||||
expect(tree.exists(pathToFile), pathToFile).equal(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,68 @@
|
||||
import {
|
||||
Rule, Tree, SchematicsException,
|
||||
apply, url, applyTemplates, move,
|
||||
chain, mergeWith,
|
||||
} from '@angular-devkit/schematics'
|
||||
|
||||
import { strings, normalize, virtualFs, workspaces } from '@angular-devkit/core'
|
||||
|
||||
import { Schema } from './schema'
|
||||
|
||||
function createSpec (tree: Tree): workspaces.WorkspaceHost {
|
||||
return {
|
||||
async readFile (path: string): Promise<string> {
|
||||
const data = tree.read(path)
|
||||
|
||||
if (!data) {
|
||||
throw new SchematicsException('File not found.')
|
||||
}
|
||||
|
||||
return virtualFs.fileBufferToString(data)
|
||||
},
|
||||
async writeFile (path: string, data: string): Promise<void> {
|
||||
return tree.overwrite(path, data)
|
||||
},
|
||||
async isDirectory (path: string): Promise<boolean> {
|
||||
return !tree.exists(path) && tree.getDir(path).subfiles.length > 0
|
||||
},
|
||||
async isFile (path: string): Promise<boolean> {
|
||||
return tree.exists(path)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default function (options: Schema): Rule {
|
||||
return async (tree: Tree) => {
|
||||
const host = createSpec(tree)
|
||||
const { workspace } = await workspaces.readWorkspace('/', host)
|
||||
|
||||
if (!options.project) {
|
||||
// @ts-ignore
|
||||
options.project = workspace.extensions.defaultProject
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
const project = workspace.projects.get(options.project)
|
||||
|
||||
if (!project) {
|
||||
throw new SchematicsException(`Invalid project name: ${options.project}`)
|
||||
}
|
||||
|
||||
if (options.path === undefined) {
|
||||
options.path = `${project.root}/cypress/integration`
|
||||
}
|
||||
|
||||
const templateSource = apply(url('../files/__path__'), [
|
||||
applyTemplates({
|
||||
classify: strings.classify,
|
||||
dasherize: strings.dasherize,
|
||||
name: options.name,
|
||||
}),
|
||||
move(normalize(options.path as string)),
|
||||
])
|
||||
|
||||
return chain([
|
||||
mergeWith(templateSource),
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "cypress-schematics-e2e-spec",
|
||||
"title": "Cypress E2E Spec Options Schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"format": "path",
|
||||
"description": "The path to create the component.",
|
||||
"visible": false
|
||||
},
|
||||
"project": {
|
||||
"type": "string",
|
||||
"description": "The name of the project.",
|
||||
"$default": {
|
||||
"$source": "projectName"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the e2e test.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
},
|
||||
"x-prompt": "What is the name of the e2e test?"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export interface Schema {
|
||||
// The name of the spec.
|
||||
name: string
|
||||
|
||||
// The path to create the spec.
|
||||
path?: string
|
||||
|
||||
// The name of the project.
|
||||
project?: string
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
describe('<%= classify(name) %>', () => {
|
||||
it('', () => {
|
||||
});
|
||||
});
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import { Tree } from '@angular-devkit/schematics'
|
||||
import { JSONFile } from './json-file'
|
||||
import { JSONFile } from './jsonFile'
|
||||
|
||||
const PKG_JSON_PATH = '/package.json'
|
||||
|
||||
|
||||
@@ -4,22 +4,9 @@ import { get } from 'http'
|
||||
import { getPackageJsonDependency } from './dependencies'
|
||||
|
||||
export interface NodePackage {
|
||||
name: string
|
||||
version: string
|
||||
}
|
||||
|
||||
export enum Paths {
|
||||
AngularJson = './angular.json',
|
||||
}
|
||||
|
||||
export enum Configs {
|
||||
JsonIndentLevel = 4,
|
||||
}
|
||||
|
||||
export interface CypressOptions {
|
||||
project?: string
|
||||
__version__: number
|
||||
}
|
||||
name: string
|
||||
version: string
|
||||
}
|
||||
|
||||
export function getAngularVersion (tree: Tree): number {
|
||||
const packageNode = getPackageJsonDependency(tree, '@angular/core')
|
||||
|
||||
@@ -27,5 +27,5 @@
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": ["src/**/files/**/*", "src/**/*_spec.ts"]
|
||||
"exclude": ["src/**/files/**/*", "src/**/*.spec.ts"]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*_spec.ts"
|
||||
"src/**/*.spec.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"src/**/files/**/*"
|
||||
|
||||
@@ -44,7 +44,12 @@ export const FileTreeFile = <T extends FileBase>({ item, indexes, style }: FileC
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cs(styles.node, styles.file, { [styles.active]: isSelected })} style={style} title={item.file.path}>
|
||||
<div
|
||||
className={cs(styles.node, styles.file, { [styles.active]: isSelected })}
|
||||
style={style}
|
||||
title={item.file.path}
|
||||
data-cy={isSelected ? 'selected-spec' : ''}
|
||||
>
|
||||
<InlineIcon {...inlineIconProps} />
|
||||
<NameWithHighlighting
|
||||
name={item.name}
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { mount } from './mount'
|
||||
|
||||
type MountHookResult<T> = {
|
||||
readonly current: T | null | undefined
|
||||
readonly error: Error | null
|
||||
}
|
||||
|
||||
type ResultContainer<T> = {
|
||||
result: MountHookResult<T>
|
||||
addResolver: (resolver: () => void) => void
|
||||
setValue: (val: T) => void
|
||||
setError: (err: Error) => void
|
||||
}
|
||||
|
||||
// mounting hooks inside a test component mostly copied from
|
||||
// https://github.com/testing-library/react-hooks-testing-library/blob/master/src/pure.js
|
||||
function resultContainer<T> () {
|
||||
function resultContainer<T> (): ResultContainer<T> {
|
||||
let value: T | undefined | null = null
|
||||
let error: Error | null = null
|
||||
const resolvers: any[] = []
|
||||
@@ -29,7 +42,7 @@ function resultContainer<T> () {
|
||||
|
||||
return {
|
||||
result,
|
||||
addResolver: (resolver: any) => {
|
||||
addResolver: (resolver: (() => void)) => {
|
||||
resolvers.push(resolver)
|
||||
},
|
||||
setValue: (val: T) => updateResult(val),
|
||||
@@ -46,36 +59,29 @@ type TestHookProps = {
|
||||
function TestHook ({ callback, onError, children }: TestHookProps) {
|
||||
try {
|
||||
children(callback())
|
||||
} catch (err) {
|
||||
if (err.then) {
|
||||
} catch (err: any) {
|
||||
if ('then' in err) {
|
||||
throw err
|
||||
} else {
|
||||
onError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO decide what the test hook component should show
|
||||
// maybe nothing, or maybe useful information about the hook?
|
||||
// maybe its current properties?
|
||||
// return <div>TestHook</div>
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounts a React hook function in a test component for testing.
|
||||
*
|
||||
* @see https://github.com/bahmutov/@cypress/react#advanced-examples
|
||||
*/
|
||||
export const mountHook = (hookFn: (...args: any[]) => any) => {
|
||||
const { result, setValue, setError } = resultContainer()
|
||||
export const mountHook = <T>(hookFn: (...args: any[]) => T) => {
|
||||
const { result, setValue, setError } = resultContainer<T>()
|
||||
|
||||
return mount(
|
||||
React.createElement(TestHook, {
|
||||
callback: hookFn,
|
||||
onError: setError,
|
||||
children: setValue,
|
||||
}),
|
||||
).then(() => {
|
||||
cy.wrap(result)
|
||||
const componentTest: React.ReactElement = React.createElement(TestHook, {
|
||||
callback: hookFn,
|
||||
onError: setError,
|
||||
children: setValue,
|
||||
})
|
||||
|
||||
return mount(componentTest).then(() => result)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# [@cypress/vite-dev-server-v2.0.1](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v2.0.0...@cypress/vite-dev-server-v2.0.1) (2021-06-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* vite startDevServer needs to return close() ([#16950](https://github.com/cypress-io/cypress/issues/16950)) ([67b2b3b](https://github.com/cypress-io/cypress/commit/67b2b3b9be13437e56384e377c7d32c6e433e064))
|
||||
|
||||
# [@cypress/vite-dev-server-v2.0.0](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v1.2.7...@cypress/vite-dev-server-v2.0.0) (2021-05-31)
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { debug as debugFn } from 'debug'
|
||||
import { Server } from 'http'
|
||||
import { start as createDevServer, StartDevServer } from './startServer'
|
||||
const debug = debugFn('cypress:vite-dev-server:vite')
|
||||
|
||||
export { StartDevServer }
|
||||
|
||||
type DoneCallback = () => unknown
|
||||
|
||||
export interface ResolvedDevServerConfig {
|
||||
port: number
|
||||
server: Server
|
||||
close: (done?: DoneCallback) => void
|
||||
}
|
||||
|
||||
export async function startDevServer (startDevServerArgs: StartDevServer): Promise<ResolvedDevServerConfig> {
|
||||
@@ -18,5 +19,5 @@ export async function startDevServer (startDevServerArgs: StartDevServer): Promi
|
||||
|
||||
debug('Component testing vite server started on port', port)
|
||||
|
||||
return { port, server: app.httpServer }
|
||||
return { port, close: app.httpServer.close }
|
||||
}
|
||||
|
||||
@@ -21,15 +21,28 @@ const INIT_FILEPATH = resolve(__dirname, '../client/initCypressTests.js')
|
||||
|
||||
const HMR_DEPENDENCY_LOOKUP_MAX_ITERATION = 50
|
||||
|
||||
function getSpecsSet (specs: Spec[]) {
|
||||
return new Set<string>(specs.map((spec) => spec.absolute))
|
||||
}
|
||||
|
||||
interface Spec{
|
||||
absolute: string
|
||||
relative: string
|
||||
}
|
||||
|
||||
export const makeCypressPlugin = (
|
||||
projectRoot: string,
|
||||
supportFilePath: string,
|
||||
devServerEvents: EventEmitter,
|
||||
specs: {absolute: string, relative: string}[],
|
||||
specs: Spec[],
|
||||
): Plugin => {
|
||||
let base = '/'
|
||||
|
||||
const specsPathsSet = new Set<string>(specs.map((spec) => spec.absolute))
|
||||
let specsPathsSet = getSpecsSet(specs)
|
||||
|
||||
devServerEvents.on('dev-server:specs:changed', (specs: Spec[]) => {
|
||||
specsPathsSet = getSpecsSet(specs)
|
||||
})
|
||||
|
||||
const posixSupportFilePath = supportFilePath ? convertPathToPosix(resolve(projectRoot, supportFilePath)) : undefined
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
module.exports = {
|
||||
...require('../../.releaserc.base'),
|
||||
branches: [
|
||||
{ name: 'npm/vue/v2', range: '2.x' },
|
||||
// we need to keep this branch in here even if no used because semantic-release demands
|
||||
// that we have at least one branch that has no config
|
||||
'next/npm/vue',
|
||||
// this line forces releasing 2.X releases on the latest channel
|
||||
{ name: 'npm/vue/v2', range: '2.X.X' },
|
||||
// this one releases v3 on master as beta on the next channel
|
||||
{ name: 'master', channel: 'next', prerelease: 'beta' },
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# [@cypress/vue-v3.0.0-beta.3](https://github.com/cypress-io/cypress/compare/@cypress/vue-v3.0.0-beta.2...@cypress/vue-v3.0.0-beta.3) (2021-06-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bumps deps for npm/vue ([#17096](https://github.com/cypress-io/cypress/issues/17096)) ([96af8bf](https://github.com/cypress-io/cypress/commit/96af8bf29d69537af0c10c69b33a0a889edcaa37))
|
||||
|
||||
# [@cypress/vue-v3.0.0-beta.2](https://github.com/cypress-io/cypress/compare/@cypress/vue-v3.0.0-beta.1...@cypress/vue-v3.0.0-beta.2) (2021-06-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add latest channel to properly release npm packages ([#16994](https://github.com/cypress-io/cypress/issues/16994)) ([ac16efc](https://github.com/cypress-io/cypress/commit/ac16efca80f33e12153b0c2bd0fc3f04983ed305))
|
||||
|
||||
# [@cypress/vue-v3.0.0-beta.1](https://github.com/cypress-io/cypress/compare/@cypress/vue-v2.2.3...@cypress/vue-v3.0.0-beta.1) (2021-05-31)
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@cypress/mount-utils": "0.0.0-development",
|
||||
"@vue/test-utils": "^2.0.0-rc.4"
|
||||
"@vue/test-utils": "^2.0.0-rc.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.9.0",
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# [@cypress/webpack-batteries-included-preprocessor-v2.2.2](https://github.com/cypress-io/cypress/compare/@cypress/webpack-batteries-included-preprocessor-v2.2.1...@cypress/webpack-batteries-included-preprocessor-v2.2.2) (2021-06-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **webpack-batteries-included-preprocessor:** Disable loading babel config files ([#16980](https://github.com/cypress-io/cypress/issues/16980)) ([e1d2256](https://github.com/cypress-io/cypress/commit/e1d22561b34a48ed668e4909dfeba5f102f46250))
|
||||
|
||||
# [@cypress/webpack-batteries-included-preprocessor-v2.2.1](https://github.com/cypress-io/cypress/compare/@cypress/webpack-batteries-included-preprocessor-v2.2.0...@cypress/webpack-batteries-included-preprocessor-v2.2.1) (2021-04-15)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"__description__": "This is here to prove that babel.config.json does not get used by babel-loader. It's not used for the compilation of this project.",
|
||||
"plugins": [
|
||||
"doesnt-exist"
|
||||
]
|
||||
}
|
||||
@@ -97,6 +97,8 @@ const getDefaultWebpackOptions = () => {
|
||||
[require.resolve('@babel/preset-env'), { modules: 'commonjs', targets: { 'chrome': '64' } }],
|
||||
require.resolve('@babel/preset-react'),
|
||||
],
|
||||
configFile: false,
|
||||
babelrc: false,
|
||||
},
|
||||
}],
|
||||
}, {
|
||||
|
||||
6
npm/webpack-batteries-included-preprocessor/test/fixtures/.babelrc
vendored
Normal file
6
npm/webpack-batteries-included-preprocessor/test/fixtures/.babelrc
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"__description__": "This is here to prove that .babelrc does not get used by babel-loader. It's not used for the compilation of this project.",
|
||||
"plugins": [
|
||||
"doesnt-exist"
|
||||
]
|
||||
}
|
||||
@@ -1,3 +1,10 @@
|
||||
# [@cypress/webpack-dev-server-v1.4.0](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v1.3.1...@cypress/webpack-dev-server-v1.4.0) (2021-06-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **npm/webpack-dev-server,runner-ct:** Normalize webpack errors + general React/TS improvements ([#16613](https://github.com/cypress-io/cypress/issues/16613)) ([c0fc23a](https://github.com/cypress-io/cypress/commit/c0fc23a052e53354a8300dd3f783cb161ae161e1))
|
||||
|
||||
# [@cypress/webpack-dev-server-v1.3.1](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v1.3.0...@cypress/webpack-dev-server-v1.3.1) (2021-05-26)
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# [@cypress/webpack-preprocessor-v5.9.1](https://github.com/cypress-io/cypress/compare/@cypress/webpack-preprocessor-v5.9.0...@cypress/webpack-preprocessor-v5.9.1) (2021-06-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **webpack-preprocessor:** hanging issues with webpack 5 ([#15611](https://github.com/cypress-io/cypress/issues/15611)) ([56bcbb6](https://github.com/cypress-io/cypress/commit/56bcbb61e61d823f80e80c46c943b01283da2942))
|
||||
|
||||
# [@cypress/webpack-preprocessor-v5.9.0](https://github.com/cypress-io/cypress/compare/@cypress/webpack-preprocessor-v5.8.0...@cypress/webpack-preprocessor-v5.9.0) (2021-05-26)
|
||||
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,6 +13,7 @@ const debugStats = require('debug')('cypress:webpack:stats')
|
||||
type FilePath = string
|
||||
interface BundleObject {
|
||||
promise: Promise<FilePath>
|
||||
deferreds: Array<{ resolve: (filePath: string) => void, reject: (error: Error) => void, promise: Promise<string> }>
|
||||
initial: boolean
|
||||
}
|
||||
|
||||
@@ -60,6 +61,11 @@ const cleanModuleNotFoundError = (err: Error) => {
|
||||
|
||||
if (!message.includes('Module not found')) return err
|
||||
|
||||
// Webpack 5 error messages are much less verbose. No need to clean.
|
||||
if ('NormalModule' in webpack) {
|
||||
return err
|
||||
}
|
||||
|
||||
const startIndex = message.lastIndexOf('resolve ')
|
||||
const endIndex = message.lastIndexOf(`doesn't exist`) + `doesn't exist`.length
|
||||
const partToReplace = message.substring(startIndex, endIndex)
|
||||
@@ -226,16 +232,14 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
|
||||
|
||||
const compiler = webpack(webpackOptions)
|
||||
|
||||
// we keep a reference to the latest bundle in this scope
|
||||
// it's a deferred object that will be resolved or rejected in
|
||||
// the `handle` function below and its promise is what is ultimately
|
||||
// returned from this function
|
||||
let latestBundle = createDeferred<string>()
|
||||
let firstBundle = createDeferred<string>()
|
||||
|
||||
// cache the bundle promise, so it can be returned if this function
|
||||
// is invoked again with the same filePath
|
||||
bundles[filePath] = {
|
||||
promise: latestBundle.promise,
|
||||
promise: firstBundle.promise,
|
||||
// we will resolve all reject everything in this array when a compile completes in the `handle` function
|
||||
deferreds: [firstBundle],
|
||||
initial: true,
|
||||
}
|
||||
|
||||
@@ -247,7 +251,10 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
|
||||
|
||||
debug(`errored bundling ${outputPath}`, err.message)
|
||||
|
||||
latestBundle.reject(err)
|
||||
const lastBundle = bundles[filePath].deferreds[bundles[filePath].deferreds.length - 1]
|
||||
|
||||
lastBundle.reject(err)
|
||||
bundles[filePath].deferreds.length = 0
|
||||
}
|
||||
|
||||
// this function is called when bundling is finished, once at the start
|
||||
@@ -294,7 +301,15 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
|
||||
// Seems to be a race condition where changing file before next tick
|
||||
// does not cause build to rerun
|
||||
Promise.delay(0).then(() => {
|
||||
latestBundle.resolve(outputPath)
|
||||
if (!bundles[filePath]) {
|
||||
return
|
||||
}
|
||||
|
||||
bundles[filePath].deferreds.forEach((deferred) => {
|
||||
deferred.resolve(outputPath)
|
||||
})
|
||||
|
||||
bundles[filePath].deferreds.length = 0
|
||||
})
|
||||
}
|
||||
|
||||
@@ -303,11 +318,10 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
|
||||
|
||||
const onCompile = () => {
|
||||
debug('compile', filePath)
|
||||
// we overwrite the latest bundle, so that a new call to this function
|
||||
// returns a promise that resolves when the bundling is finished
|
||||
latestBundle = createDeferred<string>()
|
||||
bundles[filePath].promise = latestBundle.promise
|
||||
const nextBundle = createDeferred<string>()
|
||||
|
||||
bundles[filePath].promise = nextBundle.promise
|
||||
bundles[filePath].deferreds.push(nextBundle)
|
||||
bundles[filePath].promise.finally(() => {
|
||||
debug('- compile finished for %s, initial? %s', filePath, bundles[filePath].initial)
|
||||
// when the bundling is finished, emit 'rerun' to let Cypress
|
||||
@@ -335,7 +349,8 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
|
||||
// so seems we just need to pass plugin.name
|
||||
// @ts-ignore
|
||||
compiler.hooks.compile.tap(plugin, onCompile)
|
||||
} else {
|
||||
} else if ('plugin' in compiler) {
|
||||
// @ts-ignore
|
||||
compiler.plugin('compile', onCompile)
|
||||
}
|
||||
}
|
||||
@@ -380,7 +395,15 @@ preprocessor.__reset = () => {
|
||||
bundles = {}
|
||||
}
|
||||
|
||||
function cleanseError (err: string | Error) {
|
||||
// for testing purposes, but do not add this to the typescript interface
|
||||
// @ts-ignore
|
||||
preprocessor.__bundles = () => {
|
||||
return bundles
|
||||
}
|
||||
|
||||
// @ts-ignore - webpack.StatsError is unique to webpack 5
|
||||
// TODO: Remove this when we update to webpack 5.
|
||||
function cleanseError (err: string | webpack.StatsError) {
|
||||
let msg = typeof err === 'string' ? err : err.message
|
||||
|
||||
return msg.replace(/\n\s*at.*/g, '').replace(/From previous event:\n?/g, '')
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"secure": "nsp check",
|
||||
"semantic-release": "semantic-release",
|
||||
"size": "npm pack --dry",
|
||||
"test": "yarn test-unit && yarn test-e2e",
|
||||
"test": "node ./test-webpack-4-5.js",
|
||||
"test-debug": "node --inspect --debug-brk ./node_modules/.bin/_mocha",
|
||||
"test-e2e": "mocha test/e2e/*.spec.*",
|
||||
"test-unit": "mocha test/unit/*.spec.*",
|
||||
@@ -29,7 +29,7 @@
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"@fellow/eslint-plugin-coffee": "0.4.13",
|
||||
"@types/webpack": "4.41.12",
|
||||
"@types/webpack": "^4.41.12",
|
||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||
"@typescript-eslint/parser": "^4.18.0",
|
||||
"babel-loader": "^8.0.2",
|
||||
@@ -58,13 +58,13 @@
|
||||
"sinon-chai": "^3.5.0",
|
||||
"snap-shot-it": "7.9.2",
|
||||
"ts-node": "8.10.1",
|
||||
"webpack": "^4.18.1"
|
||||
"webpack": "^4.41.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.1",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"babel-loader": "^8.0.2",
|
||||
"webpack": "^4.18.1"
|
||||
"webpack": "^4 || ^5"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
@@ -83,4 +83,4 @@
|
||||
"cypress-preprocessor",
|
||||
"webpack"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
57
npm/webpack-preprocessor/test-webpack-4-5.js
Normal file
57
npm/webpack-preprocessor/test-webpack-4-5.js
Normal file
@@ -0,0 +1,57 @@
|
||||
const execa = require('execa')
|
||||
const pkg = require('./package.json')
|
||||
const fs = require('fs')
|
||||
|
||||
/**
|
||||
* This file installs Webpack 5 and runs the unit and e2e tests for the preprocessor.
|
||||
* We read package.json, update the webpack version, then re-run yarn install.
|
||||
* After it finishes, pass or fail,
|
||||
* we revert the package.json back to the original state.
|
||||
*
|
||||
* The tests for the example projects (inside of examples) run with Webpack 4.
|
||||
* This ensures we have some coverage for both versions.
|
||||
*/
|
||||
const main = async () => {
|
||||
const originalPkg = JSON.stringify(pkg, null, 2)
|
||||
|
||||
const resetPkg = async () => {
|
||||
fs.writeFileSync('package.json', originalPkg, 'utf8')
|
||||
await execa('yarn', ['install'], { stdio: 'inherit' })
|
||||
}
|
||||
|
||||
const checkExit = async ({ exitCode, step }) => {
|
||||
if (typeof exitCode !== 'number') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`${step} finished with missing exit code from execa (received ${exitCode})`)
|
||||
}
|
||||
|
||||
if (step === 'e2e' || (step === 'unit' && exitCode !== 0)) {
|
||||
await resetPkg()
|
||||
process.exit(exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
pkg.dependencies['webpack'] = '^5.39.0'
|
||||
delete pkg.devDependencies['@types/webpack']
|
||||
delete pkg.devDependencies['webpack']
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[@cypress/webpack-preprocessor]: updating package.json...')
|
||||
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2))
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[@cypress/webpack-preprocessor]: install dependencies...')
|
||||
await execa('yarn', ['install'], { stdio: 'inherit' })
|
||||
|
||||
const unit = await execa('yarn', ['test-unit'], { stdio: 'inherit' })
|
||||
|
||||
await checkExit({ exitCode: unit.exitCode, step: 'unit' })
|
||||
|
||||
const e2e = await execa('yarn', ['test-e2e'], { stdio: 'inherit' })
|
||||
|
||||
await checkExit({ exitCode: e2e.exitCode, step: 'e2e' })
|
||||
}
|
||||
|
||||
// execute main function if called from command line
|
||||
if (require.main === module) {
|
||||
main()
|
||||
}
|
||||
@@ -91,7 +91,11 @@ describe('webpack preprocessor', function () {
|
||||
})
|
||||
|
||||
it('runs webpack', function () {
|
||||
expect(preprocessor.__bundles()[this.file.filePath]).to.be.undefined
|
||||
|
||||
return this.run().then(() => {
|
||||
expect(preprocessor.__bundles()[this.file.filePath].deferreds).to.be.empty
|
||||
expect(preprocessor.__bundles()[this.file.filePath].promise).to.be.instanceOf(Promise)
|
||||
expect(webpack).to.be.called
|
||||
})
|
||||
})
|
||||
@@ -264,7 +268,7 @@ describe('webpack preprocessor', function () {
|
||||
this.compilerApi.plugin.withArgs('compile').yield()
|
||||
this.compilerApi.watch.yield(null, this.statsApi)
|
||||
|
||||
return Promise.delay(10) // give assertion time till next tick
|
||||
return Promise.delay(11) // give assertion time till next tick
|
||||
})
|
||||
.then(() => {
|
||||
expect(this.file.emit).to.be.calledWith('rerun')
|
||||
@@ -331,8 +335,11 @@ describe('webpack preprocessor', function () {
|
||||
|
||||
it('it rejects with error when an err', function () {
|
||||
this.compilerApi.run.yields(this.err)
|
||||
expect(preprocessor.__bundles()[this.file.filePath]).to.be.undefined
|
||||
|
||||
return this.run().catch((err) => {
|
||||
expect(preprocessor.__bundles()[this.file.filePath].deferreds).to.be.empty
|
||||
expect(preprocessor.__bundles()[this.file.filePath].promise).to.be.instanceOf(Promise)
|
||||
expect(err.stack).to.equal(this.err.stack)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cypress",
|
||||
"version": "7.4.0",
|
||||
"version": "7.7.0",
|
||||
"description": "Cypress.io end to end testing tool",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -12,8 +12,8 @@
|
||||
"binary-release": "node ./scripts/binary.js release",
|
||||
"binary-upload": "node ./scripts/binary.js upload",
|
||||
"binary-zip": "node ./scripts/binary.js zip",
|
||||
"build": "lerna run build --stream",
|
||||
"build-prod": "lerna run build-prod --stream",
|
||||
"build": "lerna run build --stream --ignore create-cypress-tests && lerna run build --stream --scope create-cypress-tests",
|
||||
"build-prod": "lerna run build-prod --stream --ignore create-cypress-tests && lerna run build-prod --stream --scope create-cypress-tests",
|
||||
"bump": "node ./scripts/binary.js bump",
|
||||
"check-node-version": "node scripts/check-node-version.js",
|
||||
"check-terminal": "node scripts/check-terminal.js",
|
||||
@@ -46,7 +46,7 @@
|
||||
"stop-only": "npx stop-only --skip .cy,.publish,.projects,node_modules,dist,dist-test,fixtures,lib,bower_components,src,__snapshots__ --exclude e2e.ts,cypress-tests.ts,unwritten.spec.ts",
|
||||
"stop-only-all": "yarn stop-only --folder packages",
|
||||
"pretest": "yarn ensure-deps",
|
||||
"test": "yarn lerna exec yarn test --scope cypress --scope \"'@packages/{electron,extension,https-proxy,launcher,net-stubbing,network,proxy,rewriter,runner,socket}'\"",
|
||||
"test": "yarn lerna exec yarn test --scope cypress --scope \"'@packages/{electron,extension,https-proxy,launcher,net-stubbing,network,proxy,rewriter,runner,runner-shared,socket}'\"",
|
||||
"test-debug": "lerna exec yarn test-debug --ignore \"'@packages/{desktop-gui,driver,root,static,web-config}'\"",
|
||||
"pretest-e2e": "yarn ensure-deps",
|
||||
"test-e2e": "lerna exec yarn test-e2e --ignore \"'@packages/{desktop-gui,driver,root,static,web-config}'\"",
|
||||
|
||||
@@ -128,8 +128,6 @@
|
||||
"execTimeout": 60000,
|
||||
"fileServerFolder": "/Users/jennifer/Dev/Projects/cypress-example-kitchensink",
|
||||
"fixturesFolder": "/Users/jennifer/Dev/Projects/cypress-example-kitchensink/cypress/fixtures",
|
||||
"integrationExamplePath": "/Users/jennifer/Dev/Projects/cypress-example-kitchensink/cypress/integration/examples",
|
||||
"integrationExampleName": "examples",
|
||||
"integrationFolder": "/Users/jennifer/Dev/Projects/cypress-example-kitchensink/cypress/integration",
|
||||
"isHeadless": false,
|
||||
"isNewProject": false,
|
||||
|
||||
@@ -24,10 +24,11 @@ describe('Specs List', function () {
|
||||
cy.stub(this.ipc, 'openFinder')
|
||||
cy.stub(this.ipc, 'openFile')
|
||||
cy.stub(this.ipc, 'externalOpen')
|
||||
cy.stub(this.ipc, 'onboardingClosed')
|
||||
cy.stub(this.ipc, 'hasOpenedCypress').resolves(true)
|
||||
cy.stub(this.ipc, 'onSpecChanged')
|
||||
cy.stub(this.ipc, 'setUserEditor')
|
||||
cy.stub(this.ipc, 'showNewSpecDialog').resolves({ specs: null, path: null })
|
||||
cy.stub(this.ipc, 'removeScaffoldedFiles').resolves()
|
||||
|
||||
this.openProject = this.util.deferred()
|
||||
cy.stub(this.ipc, 'openProject').returns(this.openProject.promise)
|
||||
@@ -58,8 +59,10 @@ describe('Specs List', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('displays help link', () => {
|
||||
cy.contains('a', 'Need help?')
|
||||
it('launches system save dialog on click of new spec file', function () {
|
||||
cy.contains('New Spec File').click().then(function () {
|
||||
expect(this.ipc.showNewSpecDialog).to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('opens link to docs on click of help link', () => {
|
||||
@@ -96,98 +99,76 @@ describe('Specs List', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('first time onboarding specs', function () {
|
||||
describe('new project onboarding', function () {
|
||||
beforeEach(function () {
|
||||
this.config.isNewProject = true
|
||||
|
||||
this.openProject.resolve(this.config)
|
||||
})
|
||||
|
||||
context('modal', () => {
|
||||
it('displays', () => {
|
||||
cy.contains('.modal', 'To help you get started').should('be.visible')
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('displays the scaffolded files', () => {
|
||||
cy.get('.folder-preview-onboarding').within(function () {
|
||||
cy.contains('span', 'fixtures').siblings('ul').within(function () {
|
||||
})
|
||||
|
||||
cy.contains('example.json')
|
||||
cy.contains('span', 'integration').siblings('ul').within(() => {
|
||||
cy.contains('examples')
|
||||
})
|
||||
|
||||
cy.contains('span', 'support').siblings('ul').within(function () {
|
||||
cy.contains('commands.js')
|
||||
cy.contains('defaults.js')
|
||||
|
||||
cy.contains('index.js')
|
||||
})
|
||||
|
||||
cy.contains('span', 'plugins').siblings('ul').within(() => {
|
||||
cy.contains('index.js')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('lists folders and files alphabetically', () => {
|
||||
cy.get('.folder-preview-onboarding').within(() => {
|
||||
cy.contains('fixtures').parent().next()
|
||||
.contains('integration')
|
||||
})
|
||||
})
|
||||
|
||||
it('truncates file lists with more than 3 items', () => {
|
||||
cy.get('.folder-preview-onboarding').within(function () {
|
||||
cy.contains('examples').closest('.new-item').find('li')
|
||||
.should('have.length', 3)
|
||||
|
||||
cy.get('.is-more').should('have.text', ' ... 17 more files ...')
|
||||
})
|
||||
})
|
||||
|
||||
it('can dismiss the modal', function () {
|
||||
cy.contains('OK, got it!').click()
|
||||
|
||||
cy.get('.modal').should('not.be.visible')
|
||||
.then(function () {
|
||||
expect(this.ipc.onboardingClosed).to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('triggers open:finder on click of example folder', function () {
|
||||
cy.get('.modal').contains('examples').click().then(() => {
|
||||
expect(this.ipc.openFinder).to.be.calledWith(this.config.integrationExamplePath)
|
||||
})
|
||||
})
|
||||
|
||||
it('triggers open:finder on click of text folder', function () {
|
||||
cy.get('.modal').contains('cypress/integration').click().then(() => {
|
||||
expect(this.ipc.openFinder).to.be.calledWith(this.config.integrationFolder)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('banner', function () {
|
||||
beforeEach(function () {
|
||||
cy.get('.modal').find('.btn-success').click()
|
||||
})
|
||||
|
||||
it('displays', function () {
|
||||
cy.get('.first-test-banner')
|
||||
cy.get('.new-project-banner')
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('is dismissable', function () {
|
||||
cy.get('.first-test-banner').find('.close').click()
|
||||
cy.get('.first-test-banner').should('not.exist')
|
||||
cy.get('.new-project-banner').find('.close').click()
|
||||
cy.get('.new-project-banner').should('not.exist')
|
||||
})
|
||||
|
||||
it('does not display new user banner even when closed', function () {
|
||||
this.ipc.hasOpenedCypress.resolves(false)
|
||||
|
||||
cy.get('.new-user-banner').should('not.exist')
|
||||
cy.get('.new-project-banner').find('.close').click()
|
||||
cy.get('.new-project-banner').should('not.exist')
|
||||
cy.get('.new-user-banner').should('not.exist')
|
||||
})
|
||||
|
||||
it('opens link to docs on click of help link', function () {
|
||||
cy.contains('a', 'How to write tests').click().then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWith('https://on.cypress.io/writing-first-test')
|
||||
cy.contains('a', 'How to write your first test').click().then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWithMatch({ url: 'https://on.cypress.io/writing-first-test' })
|
||||
})
|
||||
})
|
||||
|
||||
it('removes scaffolded files on click and confirmation', function () {
|
||||
cy.contains('delete example files').click()
|
||||
cy.get('.confirm-remove-scaffolded-files').should('be.visible')
|
||||
cy.contains('Yes, delete files').click().then(function () {
|
||||
expect(this.ipc.removeScaffoldedFiles).to.be.called
|
||||
cy.get('.new-project-banner').should('not.exist')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('first time user in existing project', function () {
|
||||
beforeEach(function () {
|
||||
this.openProject.resolve(this.config)
|
||||
this.ipc.hasOpenedCypress.resolves(false)
|
||||
})
|
||||
|
||||
context('banner', function () {
|
||||
it('displays', function () {
|
||||
cy.get('.new-user-banner')
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('is dismissable', function () {
|
||||
cy.get('.new-user-banner').find('.close').click()
|
||||
cy.get('.new-user-banner').should('not.exist')
|
||||
})
|
||||
|
||||
it('opens link to docs on click of how to link', function () {
|
||||
cy.contains('a', 'How to write your first test').click().then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWithMatch({ url: 'https://on.cypress.io/writing-first-test' })
|
||||
})
|
||||
})
|
||||
|
||||
it('opens link to intro guide on click of intro link', function () {
|
||||
cy.contains('a', 'Introduction guide to Cypress').click().then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWithMatch({ url: 'https://on.cypress.io/intro-to-cypress' })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
const path = require('path')
|
||||
|
||||
function file (name) {
|
||||
return `file://${path.join(__dirname, '..', 'dist', name)}`
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getPathToIndex () {
|
||||
return file('index.html')
|
||||
},
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
"@cypress/react": "0.0.0-development",
|
||||
"@cypress/react-tooltip": "0.5.3",
|
||||
"@cypress/webpack-preprocessor": "0.0.0-development",
|
||||
"@fontsource/fira-sans": "4.3.0",
|
||||
"@fontsource/poppins": "4.3.0",
|
||||
"@fortawesome/fontawesome-free": "5.11.2",
|
||||
"@packages/web-config": "0.0.0-development",
|
||||
@@ -34,7 +35,6 @@
|
||||
"cypress-multi-reporters": "1.4.0",
|
||||
"cypress-real-events": "1.4.0",
|
||||
"dayjs": "^1.9.3",
|
||||
"fira": "cypress-io/fira#fb63362742eea8cdce0d90825ab9264d77719e3d",
|
||||
"gravatar": "1.8.0",
|
||||
"human-interval": "1.0.0",
|
||||
"lodash": "4.17.21",
|
||||
@@ -57,7 +57,6 @@
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"lib",
|
||||
"!lib/**/*_spec.jsx"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ class Default extends Component {
|
||||
onDrop={this._drop}
|
||||
>
|
||||
<span className="fa-stack fa-lg">
|
||||
<i className="fas fa-folder fa-stack-2x"></i>
|
||||
<i className="fas fa-plus fa-stack-1x"></i>
|
||||
<i className="fas fa-folder fa-stack-2x" />
|
||||
<i className="fas fa-plus fa-stack-1x" />
|
||||
</span>
|
||||
<p>Drag your project here or <a href="#" onClick={this._selectProject}>select manually</a>.</p>
|
||||
</div>
|
||||
@@ -51,7 +51,7 @@ class Default extends Component {
|
||||
return (
|
||||
<div className='local-install-notice alert alert-info alert-dismissible'>
|
||||
<p className='text-center'>
|
||||
<i className='fas fa-info-circle'></i>{' '}
|
||||
<i className='fas fa-info-circle' />{' '}
|
||||
We recommend versioning Cypress per project and{' '}
|
||||
<a onClick={this._openHelp} className='helper-docs-link'>
|
||||
installing it via <span className='mono'>npm</span>
|
||||
|
||||
@@ -71,7 +71,9 @@ register('updater:check', false)
|
||||
register('updater:run', false)
|
||||
register('window:open')
|
||||
register('window:close')
|
||||
register('onboarding:closed')
|
||||
register('new:project:banner:closed')
|
||||
register('has:opened:cypress')
|
||||
register('remove:scaffolded:files')
|
||||
register('set:clipboard:text')
|
||||
register('set:prompt:shown')
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ export default class Browsers extends Component {
|
||||
return (
|
||||
<li className='close-browser'>
|
||||
<button className='btn btn-xs btn-danger' onClick={this._closeBrowser.bind(this)}>
|
||||
<i className='fas fa-fw fa-times'></i>
|
||||
<i className='fas fa-fw fa-times' />
|
||||
Stop
|
||||
</button>
|
||||
</li>
|
||||
|
||||
@@ -12,19 +12,19 @@ export default class ProjectNav extends Component {
|
||||
<ul className='nav left-nav'>
|
||||
<li>
|
||||
<Link to={routes.specs(project)}>
|
||||
<i className='fas fa-code'></i>{' '}
|
||||
<i className='fas fa-code' />{' '}
|
||||
Tests
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={routes.runs(project)}>
|
||||
<i className='fas fa-database'></i>{' '}
|
||||
<i className='fas fa-database' />{' '}
|
||||
Runs
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={routes.settings(project)}>
|
||||
<i className='fas fa-cog'></i>{' '}
|
||||
<i className='fas fa-cog' />{' '}
|
||||
Settings
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
import cs from 'classnames'
|
||||
import _ from 'lodash'
|
||||
import React, { Component } from 'react'
|
||||
import { observer } from 'mobx-react'
|
||||
import BootstrapModal from 'react-bootstrap-modal'
|
||||
|
||||
import ipc from '../lib/ipc'
|
||||
|
||||
@observer
|
||||
class OnBoarding extends Component {
|
||||
componentDidMount () {
|
||||
this._maybeShowModal()
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this._maybeShowModal()
|
||||
}
|
||||
|
||||
_maybeShowModal () {
|
||||
if (!this.showedModal && this.props.project.isNew) {
|
||||
this.showedModal = true
|
||||
this.props.project.openModal()
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { project } = this.props
|
||||
|
||||
let closeModal = () => {
|
||||
project.closeModal()
|
||||
ipc.onboardingClosed()
|
||||
}
|
||||
|
||||
return (
|
||||
<BootstrapModal
|
||||
show={project.onBoardingModalOpen}
|
||||
onHide={closeModal}
|
||||
backdrop='static'
|
||||
>
|
||||
<div className='modal-body'>
|
||||
<div className='empty-onboarding'>
|
||||
<h1>To help you get started...</h1>
|
||||
<p>
|
||||
We've added some folders and example tests to your project. Try running the tests in the
|
||||
<strong onClick={this._openExampleSpec}>
|
||||
<i className='far fa-folder'></i>{' '}
|
||||
{project.integrationExampleName}{' '}
|
||||
</strong>
|
||||
folder or add your own test files to
|
||||
<strong onClick={this._openIntegrationFolder}>
|
||||
<i className='far fa-folder'></i>{' '}
|
||||
cypress/integration
|
||||
</strong>.
|
||||
</p>
|
||||
<div className='folder-preview-onboarding'>
|
||||
<ul>
|
||||
<li>
|
||||
<span>
|
||||
<i className='far fa-folder-open'></i>{' '}
|
||||
{project.name}
|
||||
</span>
|
||||
<ul>
|
||||
<li className='app-code'>
|
||||
<span >
|
||||
<i className='far fa-folder'></i>{' '}
|
||||
...
|
||||
</span>
|
||||
</li>
|
||||
{this._scaffoldedFiles(project.scaffoldedFiles, 'new-code')}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className='helper-line'>
|
||||
<BootstrapModal.Dismiss className='btn btn-success'>
|
||||
OK, got it!
|
||||
</BootstrapModal.Dismiss>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BootstrapModal>
|
||||
)
|
||||
}
|
||||
|
||||
_scaffoldedFiles (files, className) {
|
||||
files = _.sortBy(files, 'name')
|
||||
|
||||
const notFolders = _.every(files, (file) => !file.children)
|
||||
|
||||
if (notFolders && files.length > 3) {
|
||||
const numHidden = files.length - 2
|
||||
|
||||
files = files.slice(0, 2).concat({ name: `... ${numHidden} more files ...`, more: true })
|
||||
}
|
||||
|
||||
return _.map(files, (file) => {
|
||||
if (file.children) {
|
||||
return (
|
||||
<li className={cs(className, 'new-item')} key={file.name}>
|
||||
<span>
|
||||
<i className='far fa-folder-open'></i>{' '}
|
||||
{file.name}
|
||||
</span>
|
||||
<ul>
|
||||
{this._scaffoldedFiles(file.children)}
|
||||
</ul>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<li className={cs(className, 'new-item', { 'is-more': file.more })} key={file.name}>
|
||||
<span>
|
||||
<i className='far fa-file-code'></i>{' '}
|
||||
{file.name}
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
_openExampleSpec = () => {
|
||||
ipc.openFinder(this.props.project.integrationExamplePath)
|
||||
}
|
||||
|
||||
_openIntegrationFolder = () => {
|
||||
ipc.openFinder(this.props.project.integrationFolder)
|
||||
}
|
||||
}
|
||||
|
||||
export default OnBoarding
|
||||
@@ -1,137 +0,0 @@
|
||||
.empty-onboarding {
|
||||
margin: 0px auto 0;
|
||||
overflow: auto;
|
||||
|
||||
strong {
|
||||
margin-left: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
strong:hover {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px dotted #333;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: $pass;
|
||||
font-size: 18.5px;
|
||||
margin: 0px 0 10px;
|
||||
}
|
||||
|
||||
img {
|
||||
text-align: center;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
margin-bottom: 0;
|
||||
|
||||
a {
|
||||
border-bottom: 1px dotted lighten($brand-primary, 30%);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.helper-line {
|
||||
bottom: 0;
|
||||
position: inherit;
|
||||
}
|
||||
|
||||
h6 {
|
||||
margin-top: 30px;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
font-style: italic;
|
||||
color: #999;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.folder-preview-onboarding {
|
||||
background-color: #fcfcfc;
|
||||
padding: 0;
|
||||
border: 1px solid #e9e9e9;
|
||||
box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.04);
|
||||
margin: 0 auto 10px;
|
||||
color: #555;
|
||||
margin-top: 10px;
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin-left: 0;
|
||||
font-size: 13.5px;
|
||||
-webkit-padding-start: 0;
|
||||
|
||||
|
||||
&>li {
|
||||
position: relative;
|
||||
margin: 3px 0;
|
||||
|
||||
&.app-code {
|
||||
color: #aaa;
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
&.new-code {
|
||||
padding: 2px 0 0 31px;
|
||||
margin-left: -30px;
|
||||
margin-bottom: 0;
|
||||
border-top: 1px solid lighten($pass, 54%);
|
||||
background-color: lighten($pass, 58%);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&>ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&>ul {
|
||||
margin-bottom: 0;
|
||||
&>li {
|
||||
margin-bottom: 0;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.new-item:after {
|
||||
color: lighten($pass, 5%);
|
||||
content: "+";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.new-item .new-item:after {
|
||||
top: -2px;
|
||||
left: -40px;
|
||||
}
|
||||
|
||||
.new-item .new-item .new-item:after {
|
||||
top: -2px;
|
||||
left: -60px;
|
||||
}
|
||||
|
||||
.new-item .new-item .new-item .new-item:after {
|
||||
top: -2px;
|
||||
left: -80px;
|
||||
}
|
||||
|
||||
.is-more {
|
||||
i {
|
||||
display: none;
|
||||
}
|
||||
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,11 +23,11 @@ const validProps = cacheProps.concat([
|
||||
'isNew',
|
||||
'configFile',
|
||||
'browsers',
|
||||
'onBoardingModalOpen',
|
||||
'newProjectBannerOpen',
|
||||
'newUserBannerOpen',
|
||||
'browserState',
|
||||
'resolvedConfig',
|
||||
'parentTestsFolderDisplay',
|
||||
'integrationExampleName',
|
||||
'scaffoldedFiles',
|
||||
'resolvedNodePath',
|
||||
'resolvedNodeVersion',
|
||||
@@ -55,7 +55,8 @@ export default class Project {
|
||||
@observable isLoading = false
|
||||
@observable isNew = false
|
||||
@observable browsers = []
|
||||
@observable onBoardingModalOpen = false
|
||||
@observable newProjectBannerOpen = false
|
||||
@observable newUserBannerOpen = false
|
||||
@observable browserState = 'closed'
|
||||
@observable resolvedConfig
|
||||
@observable error
|
||||
@@ -63,7 +64,6 @@ export default class Project {
|
||||
@observable _warnings = {}
|
||||
@observable apiError
|
||||
@observable parentTestsFolderDisplay
|
||||
@observable integrationExampleName
|
||||
@observable scaffoldedFiles = []
|
||||
@observable resolvedNodePath
|
||||
@observable resolvedNodeVersion
|
||||
@@ -147,12 +147,9 @@ export default class Project {
|
||||
this.isLoading = isLoading
|
||||
}
|
||||
|
||||
@action openModal () {
|
||||
this.onBoardingModalOpen = true
|
||||
}
|
||||
|
||||
@action closeModal () {
|
||||
this.onBoardingModalOpen = false
|
||||
@action closeBanners () {
|
||||
this.newProjectBannerOpen = false
|
||||
this.newUserBannerOpen = false
|
||||
}
|
||||
|
||||
@action browserOpening () {
|
||||
@@ -206,11 +203,10 @@ export default class Project {
|
||||
|
||||
@action setOnBoardingConfig (config) {
|
||||
this.isNew = config.isNewProject
|
||||
this.newProjectBannerOpen = config.isNewProject
|
||||
this.integrationFolder = config.integrationFolder
|
||||
this.parentTestsFolderDisplay = config.parentTestsFolderDisplay
|
||||
this.fileServerFolder = config.fileServerFolder
|
||||
this.integrationExampleName = config.integrationExampleName
|
||||
this.integrationExamplePath = config.integrationExamplePath
|
||||
this.scaffoldedFiles = config.scaffoldedFiles
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import viewStore from '../lib/view-store'
|
||||
import ipc from '../lib/ipc'
|
||||
|
||||
import Settings from '../settings/settings'
|
||||
import OnBoarding from './onboarding'
|
||||
import ProjectNav from '../project-nav/project-nav'
|
||||
import RunsList from '../runs/runs-list'
|
||||
import SpecsList from '../specs/specs-list'
|
||||
@@ -53,7 +52,6 @@ class Project extends Component {
|
||||
{this._renderWarnings()}
|
||||
{this._currentView()}
|
||||
</div>
|
||||
<OnBoarding project={this.props.project}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class WarningMessage extends Component {
|
||||
return (
|
||||
<div className='alert alert-warning'>
|
||||
<p className='header'>
|
||||
<i className='fas fa-exclamation-triangle'></i>{' '}
|
||||
<i className='fas fa-exclamation-triangle' />{' '}
|
||||
<strong>Warning</strong>
|
||||
</p>
|
||||
<div>
|
||||
|
||||
@@ -46,7 +46,7 @@ class ProjectsList extends Component {
|
||||
return (
|
||||
<div className='alert alert-danger'>
|
||||
<p>
|
||||
<i className='fas fa-exclamation-triangle'></i>{' '}
|
||||
<i className='fas fa-exclamation-triangle' />{' '}
|
||||
<strong>Error</strong>
|
||||
</p>
|
||||
<p dangerouslySetInnerHTML={{
|
||||
|
||||
@@ -41,11 +41,11 @@ class RunsList extends Component {
|
||||
componentDidMount () {
|
||||
this._pingApiServer()
|
||||
this._handlePolling()
|
||||
this._getKey()
|
||||
this._getRecordKeys()
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this._getKey()
|
||||
this._getRecordKeys()
|
||||
this._handlePolling()
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ class RunsList extends Component {
|
||||
runsApi.stopPollingRuns()
|
||||
}
|
||||
|
||||
_getKey () {
|
||||
_getRecordKeys () {
|
||||
if (this._needsKey()) {
|
||||
projectsApi.getRecordKeys().then((keys = []) => {
|
||||
if (keys.length) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import _ from 'lodash'
|
||||
import React, { Component } from 'react'
|
||||
import { observer } from 'mobx-react'
|
||||
import Loader from 'react-loader'
|
||||
import BootstrapModal from 'react-bootstrap-modal'
|
||||
import Tooltip from '@cypress/react-tooltip'
|
||||
|
||||
import FileOpener from './file-opener'
|
||||
@@ -24,9 +25,7 @@ const formRunButtonLabel = (areTestsAlreadyRunning, specType, specsN) => {
|
||||
return `Running ${specType} tests`
|
||||
}
|
||||
|
||||
const label = specsN === 1 ? `Run 1 ${specType} spec` : `Run ${specsN} ${specType} specs`
|
||||
|
||||
return label
|
||||
return specsN === 1 ? `Run 1 ${specType} spec` : `Run ${specsN} ${specType} specs`
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,6 +59,7 @@ class SpecsList extends Component {
|
||||
super(props)
|
||||
this.state = {
|
||||
isFocused: false,
|
||||
confirmRemoveScaffoldedFiles: false,
|
||||
}
|
||||
|
||||
this.filterRef = React.createRef()
|
||||
@@ -75,10 +75,12 @@ class SpecsList extends Component {
|
||||
// @ts-ignore
|
||||
window.__project = this.props.project
|
||||
}
|
||||
}
|
||||
|
||||
this.state = {
|
||||
firstTestBannerDismissed: false,
|
||||
}
|
||||
componentDidMount () {
|
||||
ipc.hasOpenedCypress().then((opened) => {
|
||||
this.props.project.update({ newUserBannerOpen: !opened })
|
||||
})
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
@@ -98,7 +100,7 @@ class SpecsList extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
if (specsStore.isLoading) return <Loader color='#888' scale={0.5}/>
|
||||
if (specsStore.isLoading) return <Loader color='#888' scale={0.5} />
|
||||
|
||||
const filteredSpecs = specsStore.getFilteredSpecs()
|
||||
|
||||
@@ -121,7 +123,8 @@ class SpecsList extends Component {
|
||||
|
||||
return (
|
||||
<div className='specs'>
|
||||
{this._firstTestBanner()}
|
||||
{this._banners()}
|
||||
{this._confirmRemoveScaffoldedFilesDialog()}
|
||||
<header>
|
||||
<div className={cs('search', {
|
||||
'show-clear-filter': !!specsStore.filter,
|
||||
@@ -151,7 +154,7 @@ class SpecsList extends Component {
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className='new-file-button'>
|
||||
<button className='btn btn-link' onClick={this._createNewFile}><i className="fa fa-plus"></i> New Spec File</button>
|
||||
<button className='btn btn-link' onClick={this._createNewFile}><i className="fa fa-plus" /> New Spec File</button>
|
||||
</div>
|
||||
</header>
|
||||
{this._specsList()}
|
||||
@@ -415,24 +418,123 @@ class SpecsList extends Component {
|
||||
{this.props.project.integrationFolder}
|
||||
</code>
|
||||
</h5>
|
||||
<a className='helper-docs-link' onClick={this._openHelp}>
|
||||
<i className='fas fa-question-circle' />{' '}
|
||||
Need help?
|
||||
</a>
|
||||
<p>
|
||||
<a onClick={this._createNewFile}>
|
||||
<i className='fas fa-plus' /> New Spec File
|
||||
</a>
|
||||
|
|
||||
<a className='helper-docs-link' onClick={this._openHelp}>
|
||||
<i className='fas fa-question-circle' /> Need help?
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
_firstTestBanner () {
|
||||
if (!this.props.project.isNew || this.state.firstTestBannerDismissed) return
|
||||
_closeBanners = () => {
|
||||
this.props.project.closeBanners()
|
||||
ipc.newProjectBannerClosed()
|
||||
}
|
||||
|
||||
_removeScaffoldedFiles = () => {
|
||||
ipc.removeScaffoldedFiles().then(this._closeBanners)
|
||||
}
|
||||
|
||||
_openRemoveScaffoldedFilesDialog = () => {
|
||||
this.setState({ confirmRemoveScaffoldedFiles: true })
|
||||
}
|
||||
|
||||
_closeRemoveScaffoldedFilesDialog = () => {
|
||||
this.setState({ confirmRemoveScaffoldedFiles: false })
|
||||
}
|
||||
|
||||
_openHowToNewProjectBanner = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen({
|
||||
url: 'https://on.cypress.io/writing-first-test',
|
||||
params: {
|
||||
utm_medium: 'New Project Banner',
|
||||
utm_campaign: 'How To',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
_openHowToNewUserBanner = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen({
|
||||
url: 'https://on.cypress.io/writing-first-test',
|
||||
params: {
|
||||
utm_medium: 'New User Banner',
|
||||
utm_campaign: 'How To',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
_openIntroNewUserBanner = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen({
|
||||
url: 'https://on.cypress.io/intro-to-cypress',
|
||||
params: {
|
||||
utm_medium: 'New User Banner',
|
||||
utm_campaign: 'Intro Guide',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
_banners () {
|
||||
if (this.props.project.newProjectBannerOpen) {
|
||||
return (
|
||||
<div className="onboarding-banner new-project-banner info-box info-box-dismissible">
|
||||
<p className="header">
|
||||
<strong>Welcome to Cypress!</strong>
|
||||
</p>
|
||||
<p>We've created some sample test files that demonstrate key Cypress concepts to help you get started.</p>
|
||||
<p className="action-links">
|
||||
<a onClick={this._openHowToNewProjectBanner}>How to write your first test <i className="fa fa-sm fa-external-link-alt" /></a>
|
||||
|
|
||||
<a className="link-danger" onClick={this._openRemoveScaffoldedFilesDialog}>No thanks, delete example files</a>
|
||||
</p>
|
||||
<button className="close" onClick={this._closeBanners}><span>×</span></button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (this.props.project.newUserBannerOpen) {
|
||||
return (
|
||||
<div className="onboarding-banner new-user-banner info-box info-box-dismissible">
|
||||
<p className="header">
|
||||
<strong>New to Cypress?</strong>
|
||||
</p>
|
||||
<p>We've created some new user guides on key Cypress concepts to help you get started.</p>
|
||||
<p className="action-links">
|
||||
<a onClick={this._openHowToNewUserBanner}>How to write your first test <i className="fa fa-sm fa-external-link-alt" /></a>
|
||||
|
|
||||
<a onClick={this._openIntroNewUserBanner}>Introduction guide to Cypress <i className="fa fa-sm fa-external-link-alt" /></a>
|
||||
</p>
|
||||
<button className="close" onClick={this._closeBanners}><span>×</span></button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
_confirmRemoveScaffoldedFilesDialog = () => {
|
||||
if (!this.props.project.newProjectBannerOpen) return null
|
||||
|
||||
return (
|
||||
<div className="first-test-banner alert alert-info alert-dismissible">
|
||||
<p>We've created some sample tests around key Cypress concepts. Run the first one or create your own test file.</p>
|
||||
<p><a onClick={this._openHelp}>How to write tests</a></p>
|
||||
<button className="close" onClick={this._removeFirstTestBanner}><span>×</span></button>
|
||||
</div>
|
||||
<BootstrapModal show={this.state.confirmRemoveScaffoldedFiles} onHide={this._closeRemoveScaffoldedFilesDialog} backdrop='static'>
|
||||
<div className='modal-body confirm-remove-scaffolded-files'>
|
||||
<BootstrapModal.Dismiss className='btn btn-link close'>×</BootstrapModal.Dismiss>
|
||||
<h4>Are you sure that you want to delete all example spec files?</h4>
|
||||
<h4 className="note">Note: this will not delete any new or edited files.</h4>
|
||||
</div>
|
||||
<div className='modal-footer'>
|
||||
<BootstrapModal.Dismiss className='btn btn-link'>Cancel</BootstrapModal.Dismiss>
|
||||
<button className='btn btn-danger' onClick={this._removeScaffoldedFiles}>Yes, delete files</button>
|
||||
</div>
|
||||
</BootstrapModal>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -454,10 +556,6 @@ class SpecsList extends Component {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen('https://on.cypress.io/writing-first-test')
|
||||
}
|
||||
|
||||
_removeFirstTestBanner = () => {
|
||||
this.setState({ firstTestBannerDismissed: true })
|
||||
}
|
||||
}
|
||||
|
||||
export default SpecsList
|
||||
|
||||
@@ -7,10 +7,18 @@ $max-nesting-level: 14;
|
||||
width: 100%;
|
||||
min-height: 0;
|
||||
|
||||
.empty-well code {
|
||||
display: block;
|
||||
line-height: 1.8;
|
||||
margin-top: 5px;
|
||||
.empty-well {
|
||||
code {
|
||||
color: #666;
|
||||
background: $light-gray;
|
||||
display: block;
|
||||
line-height: 1.8;
|
||||
margin-top: 5px;
|
||||
|
||||
&:hover, &:focus {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header {
|
||||
@@ -77,8 +85,13 @@ $max-nesting-level: 14;
|
||||
padding-right: 15px;
|
||||
|
||||
button {
|
||||
color: #637eb9;
|
||||
font-size: 13px;
|
||||
padding: 6px 10px;
|
||||
|
||||
&:hover, &:focus {
|
||||
color: #38589c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,9 +295,41 @@ $max-nesting-level: 14;
|
||||
}
|
||||
}
|
||||
|
||||
.first-test-banner {
|
||||
.onboarding-banner {
|
||||
margin: 6px;
|
||||
padding-left: 20px;
|
||||
|
||||
p {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.action-links {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.link-danger {
|
||||
color: #666;
|
||||
|
||||
&:hover, &:focus {
|
||||
color: darken($brand-danger, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-remove-scaffolded-files {
|
||||
h4 {
|
||||
line-height: 24px;
|
||||
|
||||
&.note {
|
||||
font-style: italic;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #888;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,3 +122,17 @@
|
||||
right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.info-box {
|
||||
border-left: 4px solid #2a98b9;
|
||||
background-color: #f2fafd;
|
||||
padding: 10px 14px;
|
||||
position: relative;
|
||||
|
||||
&.info-box-dismissible .close {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
@import "~@fortawesome/fontawesome-free/scss/solid.scss";
|
||||
@import "~@fortawesome/fontawesome-free/scss/brands.scss";
|
||||
@import "~@fortawesome/fontawesome-free/scss/fontawesome.scss";
|
||||
@import "~fira/fira";
|
||||
@import "~@fontsource/fira-sans/latin.css";
|
||||
@import "~@fontsource/poppins/latin.css";
|
||||
|
||||
// Tooltip
|
||||
|
||||
@@ -7,9 +7,5 @@
|
||||
"reporter": "cypress-multi-reporters",
|
||||
"reporterOptions": {
|
||||
"configFile": "../../mocha-reporter-config.json"
|
||||
},
|
||||
"retries": {
|
||||
"runMode": 2,
|
||||
"openMode": 0
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user