Skip to content

Commit

Permalink
Merge branch 'develop' into issue-5654-fix-cy-req-options
Browse files Browse the repository at this point in the history
  • Loading branch information
flotwig authored Nov 14, 2019
2 parents a0ba801 + 5d2825c commit b0e1e5d
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 57 deletions.
65 changes: 32 additions & 33 deletions DEPLOY.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Deployment

Anyone can build the binary and NPM package, but you can only deploy the Cypress application
and publish the NPM module `cypress` if you are a member of `cypress` NPM organization.
and publish the NPM module `cypress` if you are a member of the `cypress` NPM organization.

> :information_source: See the [publishing](#publishing) section for how to build, test and publish a
new official version of the binary and `cypress` NPM package.
Expand All @@ -12,7 +12,11 @@ We build the NPM package and binary on all major platforms (Linux, Mac, Windows)
providers. In order to set the version while building we have to set the environment variable
with the new version on each CI provider *before starting the build*.

Use script command `npm run set-next-ci-version` to do this.
Use the script command below to to do this.

```shell
npm run set-next-ci-version
```

## Building

Expand All @@ -28,12 +32,12 @@ Building a new NPM package is very quick.
The steps above:

- Build the `cypress` NPM package
- Transpiles the code into ES5 version to be compatible with the common Node versions
- Puts the result into the `cli/build` folder.
- Transpile the code into ES5 to be compatible with the common Node versions
- Put the result into the [`cli/build`](./cli/build) folder.

You could publish from there, but first you need to build and upload the binary with the *same version*;
this guarantees that when users do `npm i cypress@<x.y.z>` they can download the binary
with the same version `x.y.z` from Cypress CDN service.
with the same version `x.y.z` from Cypress's CDN service.

### Building the binary

Expand All @@ -43,68 +47,64 @@ First, you need to build, zip and upload the application binary to the Cypress s

You can use a single command to do all tasks at once:

```
```shell
npm run binary-deploy
```

You can also specify each command separately:
Or you can specify each command separately:

```
```shell
npm run binary-build
npm run binary-zip
npm run binary-upload
```

You can pass options to each command to avoid answering questions, for example

```
```shell
npm run binary-deploy -- --platform darwin --version 0.20.0
npm run binary-upload -- --platform darwin --version 0.20.0 --zip cypress.zip
```

If something goes wrong, see the debug messages using the `DEBUG=cypress:binary ...` environment
variable.

Because we had many problems reliably zipping the built binary, for now we need
to build both the Mac and Linux binary from Mac (Linux binary is built using
a Docker container), then zip it **from Mac**, then upload it.
Because we had many problems reliably zipping the built binary, for now we need to build both the Mac and Linux binary from Mac (Linux binary is built using a Docker container), then zip it **from Mac**, then upload it.

### Building Linux binary in Docker

If you are using a Mac you can build the linux binary if you have docker installed.

```
```shell
npm run binary-build-linux
```

## Publishing

### Before Publishing a New Version

In order to publish a new `cypress` package to the NPM registry, we must build and test it across
multiple platforms and test projects. This makes publishing *directly* into the NPM registry
impossible. Instead, we have CI set up to do the following on every commit to `develop`:
In order to publish a new `cypress` package to the NPM registry, we must build and test it across multiple platforms and test projects. This makes publishing *directly* into the NPM registry impossible. Instead, we have CI set up to do the following on every commit to `develop`:

1. Build the NPM package with the new target version baked in.
2. Build the Linux/Mac binaries on CircleCI and build Windows on AppVeyor.
3. Upload the binaries and the new NPM package to the `cdn.cypress.io` under the "beta" folder.
3. Upload the binaries and the new NPM package to `cdn.cypress.io` under the "beta" folder.
4. Launch the test projects like [cypress-test-node-versions](https://github.com/cypress-io/cypress-test-node-versions) and [cypress-test-example-repos](https://github.com/cypress-io/cypress-test-example-repos) using the newly-uploaded package & binary instead of installing from the NPM registry. That installation looks like this:
```
```shell
export CYPRESS_INSTALL_BINARY=https://cdn.../binary/<new version>/<commit hash>/cypress.zip
npm i https://cdn.../npm/<new version>/<commit hash>/cypress.tgz
```

Multiple test projects are launched for each target operating system, and the results are reported
back to GitHub using status checks so that it is easy to see if a change has broken real-world usage
Multiple test projects are launched for each target operating system and the results are reported
back to GitHub using status checks so that you can see if a change has broken real-world usage
of Cypress. You can see the progress of the test projects by opening the status checks on GitHub:

![Screenshot of status checks](https://i.imgur.com/AsQwzgO.png)

Once all test projects are reliably working with new changes, publishing can proceed.
Once the `develop` branch for all test projects are reliably passing with the new changes, publishing can proceed.

### Steps to Publish a New Version

0. Make sure that if there is a new [`cypress-example-kitchensink`][https://github.com/cypress-io/cypress-example-kitchensink/releases] version, the corresponding dependency in `packages/example` has been updated to that new version.
0. Make sure that if there is a new [`cypress-example-kitchensink`][https://github.com/cypress-io/cypress-example-kitchensink/releases] version, the corresponding dependency in [`packages/example`](./packages/example) has been updated to that new version.
1. Make sure that you have the correct environment variables set up before proceeding.
- You'll need Cypress AWS access keys in `aws_credentials_json`, which looks like this:
```text
Expand All @@ -118,42 +118,41 @@ Once all test projects are reliably working with new changes, publishing can pro
- Tip: Use [as-a](https://github.com/bahmutov/as-a) to manage environment variables for different situations.
2. Use the `move-binaries` script to move the binaries for `<commit sha>` from `beta` to the `desktop` folder
for `<new target version>`
```
```shell
npm run move-binaries -- --sha <commit sha> --version <new target version>
```
3. Publish the new NPM package under the dev tag. The unique link to the package file `cypress.tgz`
is the one already tested above. You can publish to the NPM registry straight from the URL:
```
3. Publish the new NPM package under the `dev` tag. The unique link to the package file `cypress.tgz` is the one already tested above. You can publish to the NPM registry straight from the URL:
```shell
npm publish https://cdn.../npm/3.4.0/<long sha>/cypress.tgz --tag dev
```
4. Double-check that the new version has been published under the `dev` tag using `npm info cypress` or [available-versions](https://github.com/bahmutov/available-versions):
```
```shell
dist-tags:
dev: 3.4.0 latest: 3.3.2
```
5. Test `cypress@3.4.0` again to make sure everything is working. You can trigger test projects
from the command line (if you have the appropriate permissions)
5. Test `cypress@3.4.0` again to make sure everything is working. You can trigger test projects from the command line (if you have the appropriate permissions)
```
node scripts/test-other-projects.js --npm cypress@3.4.0 --binary 3.4.0
```
6. Update and publish the changelog and any release-specific documentation changes in [cypress-documentation](https://github.com/cypress-io/cypress-documentation).
7. Make the new NPM version the "latest" version by updating the dist-tag `latest` to point to the new version:
```
```shell
npm dist-tag add cypress@3.4.0
```
8. Run `binary-release` to update the download server's manifest, set the next CI version, and create an empty version commit:
```
8. Run `binary-release` to update the download the server's manifest, set the next CI version, and create an empty version commit:
```shell
npm run binary-release -- --version 3.4.0 --commit`
```
9. If needed, push out any updated changes to the links manifest to [`on.cypress.io`](https://github.com/cypress-io/cypress-services/tree/develop/packages/on).
10. If needed, deploy the updated [`cypress-example-kitchensink`][cypress-example-kitchensink] to `example.cypress.io` by following [these instructions under "Deployment"](./packages/example/README.md).
11. Close the release in [ZenHub](https://app.zenhub.com/workspaces/test-runner-5c3ea3baeb1e75374f7b0708/reports/release).
12. Bump `version` in `package.json` and commit it to `develop` using a commit message like `release 3.4.0 [skip ci]`
12. Bump `version` in [`package.json`](package.json) and commit it to `develop` using a commit message like `release 3.4.0 [skip ci]`
13. Tag this commit with `v3.4.0` and push that tag up.
14. Merge `develop` into `master` and push that branch up.
15. Using [cypress-io/release-automations][release-automations]:
- Publish GitHub release to [cypress-io/cypress/releases](https://github.com/cypress-io/cypress/releases) using package `set-releases` (see its README for details).
- Add a comment to each GH issue that has been resolved with the new published version using package `issues-in-release` (see its README for details)
16. Publish a new docker image in [`cypress-docker-images`](https://github.com/cypress-io/cypress-docker-images) under `included` for the new cypress version.
Take a break, you deserve it! :sunglasses:
Expand Down
1 change: 1 addition & 0 deletions PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Delete tasks if they are not applicable.
-->

- [ ] Have tests been added/updated?
- [ ] Has the original issue been tagged with a release in ZenHub? <!-- (internal team only)-->
- [ ] Has a PR for user-facing changes been opened in [`cypress-documentation`](https://github.com/cypress-io/cypress-documentation)? <!-- Link to PR here -->
- [ ] Have API changes been updated in the [`type definitions`](cli/types/index.d.ts)?
- [ ] Have new configuration options been added to the [`cypress.schema.json`](cli/schema/cypress.schema.json)?
2 changes: 1 addition & 1 deletion packages/driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@cypress/sinon-chai": "1.1.0",
"@cypress/underscore.inflection": "1.0.1",
"@cypress/unique-selector": "0.4.2",
"@cypress/webpack-preprocessor": "4.1.0",
"@cypress/webpack-preprocessor": "4.1.1",
"@cypress/what-is-circular": "1.0.1",
"angular": "1.7.7",
"backbone": "1.4.0",
Expand Down
42 changes: 30 additions & 12 deletions packages/driver/src/cy/chai.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,21 @@ const $dom = require('../dom')
const $utils = require('../cypress/utils')
const $chaiJquery = require('../cypress/chai_jquery')

// all words between single quotes which are at
// the end of the string
const allPropertyWordsBetweenSingleQuotes = /('.*?')$/g

// grab all words between single quotes except
// when the single quote word is the LAST word
const allButLastWordsBetweenSingleQuotes = /('.*?')(.+)/g
// all words between single quotes
const allPropertyWordsBetweenSingleQuotes = /('.*?')/g

const allBetweenFourStars = /\*\*.*\*\*/
const allNumberStrings = /'([0-9]+)'/g
const allEmptyStrings = /''/g
const allSingleQuotes = /'/g
const allEscapedSingleQuotes = /\\'/g
const allQuoteMarkers = /__quote__/g
const allWordsBetweenCurlyBraces = /(#{.+?})/g
const allQuadStars = /\*\*\*\*/g
const leadingWhitespaces = /\*\*'\s*/g
const trailingWhitespaces = /\s*'\*\*/g
const whitespace = /\s/g
const valueHasLeadingOrTrailingWhitespaces = /\*\*'\s+|\s+'\*\*/g

let assertProto = null
let matchProto = null
Expand Down Expand Up @@ -78,26 +79,43 @@ chai.use((chai, u) => {
existProto = Object.getOwnPropertyDescriptor(chai.Assertion.prototype, 'exist').get;
({ getMessage } = chaiUtils)

// remove any single quotes between our **, preserving escaped quotes
// and if an empty string, put the quotes back
// remove any single quotes between our **,
// except escaped quotes, empty strings and number strings.
const removeOrKeepSingleQuotesBetweenStars = (message) => {
return message.replace(allBetweenFourStars, (match) => {
if (valueHasLeadingOrTrailingWhitespaces.test(match)) {
// Above we used \s+, but below we use \s*.
// It's because of the strings like ' love' that have empty spaces on one side only.
match = match
.replace(leadingWhitespaces, (match) => {
return match.replace(`**'`, '**__quote__')
.replace(whitespace, '&nbsp;')
})
.replace(trailingWhitespaces, (match) => {
return match.replace(`'**`, '__quote__**')
.replace(whitespace, '&nbsp;')
})
}

return match
.replace(allEscapedSingleQuotes, '__quote__') // preserve escaped quotes
.replace(allNumberStrings, '__quote__$1__quote__') // preserve number strings (e.g. '42')
.replace(allEmptyStrings, '__quote____quote__') // preserve empty strings (e.g. '')
.replace(allSingleQuotes, '')
.replace(allQuoteMarkers, '\'') // put escaped quotes back
.replace(allQuadStars, '**\'\'**')
})
} // fix empty strings that end up as ****
}

const replaceArgMessages = (args, str) => {
return _.reduce(args, (memo, value, index) => {
if (_.isString(value)) {
value = value
.replace(allWordsBetweenCurlyBraces, '**$1**')
.replace(allEscapedSingleQuotes, '__quote__')
.replace(allButLastWordsBetweenSingleQuotes, '**$1**$2')
.replace(allPropertyWordsBetweenSingleQuotes, '**$1**')
// when a value has ** in it, **** are sometimes created after the process above.
// remove them with this.
.replace(allQuadStars, '**')

memo.push(value)
} else {
Expand Down
104 changes: 104 additions & 0 deletions packages/driver/test/cypress/integration/commands/assertions_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,110 @@ describe('src/cy/commands/assertions', () => {
})
})

context('format quotation marks', () => {
const expectMarkdown = (test, message, done) => {
cy.then(() => {
test()
})

cy.on('log:added', (attrs, log) => {
if (attrs.name === 'assert') {
cy.removeAllListeners('log:added')

expect(log.get('message')).to.eq(message)

done()
}
})
}

it('preserves quotation marks in number strings', (done) => {
expectMarkdown(() => {
try {
expect(25).to.eq('25')
} catch (error) {} /* eslint-disable-line no-empty */
},
`expected **25** to equal **'25'**`,
done)
})

it('preserves quotation marks in empty string', (done) => {
expectMarkdown(() => {
try {
expect(42).to.eq('')
} catch (error) {} /* eslint-disable-line no-empty */
},
`expected **42** to equal **''**`,
done)
})

it('preserves quotation marks if escaped', (done) => {
expectMarkdown(
() => expect(`\'cypress\'`).to.eq(`\'cypress\'`),
// ****'cypress'**** -> ** for emphasizing result string + ** for emphasizing the entire result.
`expected **'cypress'** to equal ****'cypress'****`,
done
)
})

it('removes quotation marks in DOM elements', (done) => {
expectMarkdown(
() => {
cy.get('body').then(($body) => {
expect($body).to.contain('div')
})
},
`expected **<body>** to contain **div**`,
done
)
})

it('removes quotation marks in strings', (done) => {
expectMarkdown(() => expect('cypress').to.eq('cypress'), `expected **cypress** to equal **cypress**`, done)
})

it('removes quotation marks in objects', (done) => {
expectMarkdown(
() => expect({ foo: 'bar' }).to.deep.eq({ foo: 'bar' }),
`expected **{ foo: bar }** to deeply equal **{ foo: bar }**`,
done
)
})

it('formats keys properly for "have.all.keys"', (done) => {
const person = {
name: 'Joe',
age: 20,
}

expectMarkdown(
() => expect(person).to.have.all.keys('name', 'age'),
`expected **{ name: Joe, age: 20 }** to have keys **name**, and **age**`,
done
)
})

describe('formats strings with spaces', (done) => {
const tester = (message, done) => {
const nbspedMsg = message
.replace(/^\s+/, (match) => {
return match.replace(/\s/g, '&nbsp;')
})
.replace(/\s+$/, (match) => {
return match.replace(/\s/g, '&nbsp;')
})

expectMarkdown(() => expect(message).to.eq(message), `expected **'${nbspedMsg}'** to equal **'${nbspedMsg}'**`, done)
}

[' 37:46 ', ' test ', ' love'].forEach((v) => {
it(v, (done) => {
tester(v, done)
})
})
})
})

context('chai overrides', () => {
beforeEach(function () {
this.$body = cy.$$('body')
Expand Down
Loading

0 comments on commit b0e1e5d

Please sign in to comment.