diff --git a/.gitignore b/.gitignore index 4390a05bd436..ce917dd756c5 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,17 @@ packages/server/support packages/server/test/support/fixtures/server/libs # CLI tool +cli/types/blob-util +cli/types/bluebird +cli/types/chai +cli/types/chai-jquery +cli/types/jquery +cli/types/lodash +cli/types/mocha +cli/types/minimatch +cli/types/sinon +cli/types/sinon-chai +# ignore CLI output build folder cli/build # Building app binary diff --git a/circle.yml b/circle.yml index c16b702f5d75..1295b640baed 100644 --- a/circle.yml +++ b/circle.yml @@ -65,7 +65,7 @@ jobs: # need to restore a separate cache for each package.json - restore_cache: - key: v6-{{ arch }}-{{ .Branch }}-cli-deps + key: v7-{{ arch }}-{{ .Branch }}-cli-deps - restore_cache: key: v5-{{ arch }}-{{ .Branch }}-root-deps - restore_cache: @@ -117,7 +117,7 @@ jobs: # save each node_modules folder per package - save_cache: - key: v6-{{ arch }}-{{ .Branch }}-cli-deps-{{ checksum "cli/package.json" }} + key: v7-{{ arch }}-{{ .Branch }}-cli-deps-{{ checksum "cli/package.json" }} paths: - cli/node_modules - save_cache: @@ -234,6 +234,12 @@ jobs: steps: - attach_workspace: at: ~/ + - run: + command: ls -la types + working_directory: cli + - run: + command: ls -la chai + working_directory: cli/types - run: command: npm run dtslint working_directory: cli @@ -529,6 +535,9 @@ jobs: name: build NPM package working_directory: cli command: npm run build + - run: + command: ls -la types + working_directory: cli/build - run: name: list NPM package contents working_directory: cli/build @@ -754,6 +763,7 @@ linux-workflow: &linux-workflow branches: only: - develop + - move-ts-types-to-dev-dependencies-3371 requires: - build - build-binary: diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 000000000000..a59482844f06 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,26 @@ +# Cypress CLI source + +This folder is used to build Cypress NPM module. + +## Building + +See `scripts/build.js`. Note that the built NPM package will include [NPM_README.md](NPM_README.md) as its public README file. + +## Testing + +To build and test an NPM package: + +- `npm install` +- `npm run build` + +This creates `build` folder. + +- `cd build; npm pack` + +This creates an archive, usually named `cypress-.tgz`. You can install this archive from other projects, but because there is no corresponding binary yet (probably), skip binary download. For example from inside `cypress-example-kitchensink` folder + +```shell +npm i ~/git/cypress/cli/build/cypress-3.1.5.tgz --ignore-scripts +``` + +Which installs the `tgz` file we have just built from folder `~/git/cypress/cli/build`. diff --git a/cli/package.json b/cli/package.json index 5cc9677da6b1..5f30c3103fd0 100644 --- a/cli/package.json +++ b/cli/package.json @@ -10,6 +10,7 @@ "node": ">=4.0.0" }, "scripts": { + "postinstall": "node ./scripts/post-install.js", "pretest": "npm run check-deps-pre", "test": "npm run test-unit", "pretest-unit": "npm run check-deps-pre", @@ -40,16 +41,6 @@ "dependencies": { "@cypress/listr-verbose-renderer": "0.4.1", "@cypress/xvfb": "1.2.4", - "@types/blob-util": "1.3.3", - "@types/bluebird": "3.5.18", - "@types/chai": "4.0.8", - "@types/chai-jquery": "1.1.38", - "@types/jquery": "3.3.6", - "@types/lodash": "4.14.121", - "@types/minimatch": "3.0.3", - "@types/mocha": "2.2.44", - "@types/sinon": "7.0.0", - "@types/sinon-chai": "3.2.2", "bluebird": "3.5.0", "cachedir": "1.3.0", "chalk": "2.4.2", @@ -81,6 +72,16 @@ }, "devDependencies": { "@cypress/sinon-chai": "1.0.0", + "@types/blob-util": "1.3.3", + "@types/bluebird": "3.5.18", + "@types/chai": "4.0.8", + "@types/chai-jquery": "1.1.38", + "@types/jquery": "3.3.6", + "@types/lodash": "4.14.120", + "@types/minimatch": "3.0.3", + "@types/mocha": "2.2.44", + "@types/sinon": "7.0.0", + "@types/sinon-chai": "3.2.2", "babel-cli": "6.26.0", "babel-preset-es2015": "6.24.1", "bin-up": "1.1.0", @@ -102,6 +103,6 @@ "bin", "lib", "index.js", - "types/*.d.ts" + "types/**/*.d.ts" ] } diff --git a/cli/scripts/build.js b/cli/scripts/build.js index 7f593faf36a0..11c1bf0c0a48 100644 --- a/cli/scripts/build.js +++ b/cli/scripts/build.js @@ -25,6 +25,8 @@ function preparePackageForNpmRelease (json) { // to prepare it for releasing to npm delete json.devDependencies delete json['private'] + // no need to include "nyc" code coverage settings + delete json.nyc _.extend(json, { version, diff --git a/cli/scripts/post-install.js b/cli/scripts/post-install.js new file mode 100644 index 000000000000..e1d1dd137f64 --- /dev/null +++ b/cli/scripts/post-install.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node + +const { includeTypes } = require('./utils') +const shell = require('shelljs') +const { join } = require('path') + +shell.set('-v') // verbose +shell.set('-e') // any error is fatal + +// we include the TypeScript definitions for the bundled 3rd party tools +// thus we need to copy them from "dev" dependencies into our types folder +includeTypes.forEach((folder) => { + const source = join('node_modules', '@types', folder) + + shell.cp('-R', source, 'types') +}) + +// fix paths to Chai, jQuery and other types to be relative +shell.sed( + '-i', + '', + '', + join('types', 'chai-jquery', 'index.d.ts') +) +shell.sed( + '-i', + '', + '', + join('types', 'chai-jquery', 'index.d.ts') +) +shell.sed( + '-i', + '', + '', + join('types', 'sinon-chai', 'index.d.ts') +) +shell.sed( + '-i', + '', + '', + join('types', 'sinon-chai', 'index.d.ts') +) +// also use relative import for sinon-chai +shell.sed( + '-i', + 'from \'sinon\';', + 'from \'../sinon\';', + join('types', 'sinon-chai', 'index.d.ts') +) diff --git a/cli/scripts/start-build.js b/cli/scripts/start-build.js index 505e069b8e91..b9263973e5f0 100755 --- a/cli/scripts/start-build.js +++ b/cli/scripts/start-build.js @@ -1,5 +1,7 @@ #!/usr/bin/env node +const { includeTypes } = require('./utils') +const { join } = require('path') const shell = require('shelljs') shell.set('-v') // verbose @@ -11,7 +13,14 @@ shell.mkdir('-p', 'build/types') shell.cp('bin/cypress', 'build/bin/cypress') shell.cp('NPM_README.md', 'build/README.md') shell.cp('.release.json', 'build/.release.json') +// copies our typescript definitions shell.cp('-R', 'types/*.ts', 'build/types/') +// copies 3rd party typescript definitions +includeTypes.forEach((folder) => { + const source = join('types', folder) + + shell.cp('-R', source, 'build/types') +}) shell.exec('babel lib -d build/lib') shell.exec('babel index.js -o build/index.js') diff --git a/cli/scripts/utils.js b/cli/scripts/utils.js new file mode 100644 index 000000000000..8c215081d438 --- /dev/null +++ b/cli/scripts/utils.js @@ -0,0 +1,19 @@ +/** + * Folder names in "node_modules/@types" that we should include + * when we bundle Cypress NPM package. These folder have ".d.ts" + * definition files that we will need to include with our NPM package. + */ +const includeTypes = [ + 'blob-util', + 'bluebird', + 'lodash', + 'mocha', + 'minimatch', + 'sinon', + 'sinon-chai', + 'chai', + 'chai-jquery', + 'jquery', +] + +module.exports = { includeTypes } diff --git a/cli/types/blob-util.d.ts b/cli/types/cy-blob-util.d.ts similarity index 90% rename from cli/types/blob-util.d.ts rename to cli/types/cy-blob-util.d.ts index e8fc61702f86..a70481fa30fc 100644 --- a/cli/types/blob-util.d.ts +++ b/cli/types/cy-blob-util.d.ts @@ -3,7 +3,7 @@ // so that Cypress can get and use the Blob type // tslint:disable-next-line:no-implicit-dependencies -import * as blobUtil from 'blob-util' +import * as blobUtil from './blob-util' export = BlobUtil export as namespace BlobUtil diff --git a/cli/types/bluebird.d.ts b/cli/types/cy-bluebird.d.ts similarity index 88% rename from cli/types/bluebird.d.ts rename to cli/types/cy-bluebird.d.ts index 21b11c221c23..37b1dc07af3a 100644 --- a/cli/types/bluebird.d.ts +++ b/cli/types/cy-bluebird.d.ts @@ -1,7 +1,7 @@ // Shim definition to export a namespace. Cypress is actually a global module // so import/export isn't allowed there. We import here and define a global module // so that Cypress can get and use the Blob type -import * as BluebirdStatic from 'bluebird' +import * as BluebirdStatic from './bluebird' export = Bluebird export as namespace Bluebird diff --git a/cli/types/chai.d.ts b/cli/types/cy-chai.d.ts similarity index 80% rename from cli/types/chai.d.ts rename to cli/types/cy-chai.d.ts index 1b14cd5f2fab..419154fa7786 100644 --- a/cli/types/chai.d.ts +++ b/cli/types/cy-chai.d.ts @@ -1,7 +1,6 @@ // Shim definition to export a namespace. Cypress is actually a global module // so import/export isn't allowed there. We import here and define a global module -// tslint:disable-next-line:no-implicit-dependencies -import * as chai from 'chai' +/// export = Chai export as namespace Chai diff --git a/cli/types/cy-minimatch.d.ts b/cli/types/cy-minimatch.d.ts new file mode 100644 index 000000000000..f94e54e3d92b --- /dev/null +++ b/cli/types/cy-minimatch.d.ts @@ -0,0 +1,96 @@ +// I was trying to avoid relying on "import" of actual module from "minimatch" +// because it would not work in test project, and the only reliable way +// to get around type errors finally was to copy the minimal minimatch function +// definition from "minimatch/index.d.ts" here and just keep it in our code + +export = Minimatch +export as namespace Minimatch + +interface MinimatchOptions { + /** + * Dump a ton of stuff to stderr. + * + * @default false + */ + debug?: boolean + + /** + * Do not expand {a,b} and {1..3} brace sets. + * + * @default false + */ + nobrace?: boolean + + /** + * Disable ** matching against multiple folder names. + * + * @default false + */ + noglobstar?: boolean + + /** + * Allow patterns to match filenames starting with a period, + * even if the pattern does not explicitly have a period in that spot. + * + * @default false + */ + dot?: boolean + + /** + * Disable "extglob" style patterns like +(a|b). + * + * @default false + */ + noext?: boolean + + /** + * Perform a case-insensitive match. + * + * @default false + */ + nocase?: boolean + + /** + * When a match is not found by minimatch.match, + * return a list containing the pattern itself if this option is set. + * Otherwise, an empty list is returned if there are no matches. + * + * @default false + */ + nonull?: boolean + + /** + * If set, then patterns without slashes will be matched against + * the basename of the path if it contains slashes. + * + * @default false + */ + matchBase?: boolean + + /** + * Suppress the behavior of treating # + * at the start of a pattern as a comment. + * + * @default false + */ + nocomment?: boolean + + /** + * Suppress the behavior of treating a leading ! character as negation. + * + * @default false + */ + nonegate?: boolean + + /** + * Returns from negate expressions the same as if they were not negated. + * (Ie, true on a hit, false on a miss.) + * + * @default false + */ + flipNegate?: boolean +} + +declare namespace Minimatch { + function minimatch(target: string, pattern: string, options?: MinimatchOptions): boolean +} diff --git a/cli/types/moment.d.ts b/cli/types/cy-moment.d.ts similarity index 100% rename from cli/types/moment.d.ts rename to cli/types/cy-moment.d.ts diff --git a/cli/types/index.d.ts b/cli/types/index.d.ts index 7a7a2220cfa6..900694b42a96 100644 --- a/cli/types/index.d.ts +++ b/cli/types/index.d.ts @@ -7,19 +7,20 @@ // TypeScript Version: 2.8 // Updated by the Cypress team: https://www.cypress.io/about/ -/// -/// -/// -/// - -/// -/// -/// -/// -/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// + +// "moment" types are with "node_modules/moment" /// -/// -/// // Cypress adds chai expect and assert to global declare const expect: Chai.ExpectStatic @@ -93,7 +94,7 @@ declare namespace Cypress { * * @see https://on.cypress.io/minimatch */ - minimatch: Mimimatch.MimimatchStatic + minimatch: typeof Minimatch.minimatch /** * Cypress automatically includes moment.js and exposes it as Cypress.moment. * diff --git a/cli/types/minimatch.d.ts b/cli/types/minimatch.d.ts deleted file mode 100644 index f39961193e90..000000000000 --- a/cli/types/minimatch.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Shim definition to export a namespace. Cypress is actually a global module -// so import/export isn't allowed there. We import here and define a global module -// so that Cypress can get and use the Blob type -// tslint:disable-next-line:no-implicit-dependencies -import * as mimimatch from 'minimatch' -export = Mimimatch -export as namespace Mimimatch - -declare namespace Mimimatch { - type MimimatchStatic = mimimatch.IMinimatchStatic & typeof mimimatch -} diff --git a/cli/types/tests/kitchen-sink.ts b/cli/types/tests/kitchen-sink.ts index ac1522da26b3..23856750a39d 100644 --- a/cli/types/tests/kitchen-sink.ts +++ b/cli/types/tests/kitchen-sink.ts @@ -11,9 +11,12 @@ cy.wrap('foo').then(subject => { subject // $ExpectType string }) -Cypress.minimatch('/users/1/comments', '/users/*/comments', { +const result = Cypress.minimatch('/users/1/comments', '/users/*/comments', { matchBase: true, }) +result // $ExpectType boolean + +Cypress.minimatch('/users/1/comments', '/users/*/comments') // $ExpectType boolean // check if cy.server() yields default server options cy.server().should((server) => { diff --git a/cli/types/tslint.json b/cli/types/tslint.json index ed2c8cb35996..710bb8385ab6 100644 --- a/cli/types/tslint.json +++ b/cli/types/tslint.json @@ -22,5 +22,20 @@ "export-just-namespace": false, "file-name-casing": false, "jsdoc-format": false + }, + "linterOptions": { + "exclude": [ + // Lodash types and other external types are 3rd party and don't follow our rules + "./blob-util/*", + "./bluebird/*", + "./chai/*", + "./chai-jquery/*", + "./jquery/*", + "./lodash/**/*", + "./mocha/*", + "./minimatch/*", + "./sinon/**/*", + "./sinon-chai/*" + ] } }