Skip to content

Commit a2c0bc3

Browse files
authored
include CLI TS types in a way to avoid clashing with Jest (#7352)
1 parent 5a4e339 commit a2c0bc3

23 files changed

+327
-61
lines changed

circle.yml

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,10 @@ jobs:
364364
command: ls -la types
365365
working_directory: cli
366366
- run:
367-
command: yarn lerna exec --scope cypress "yarn dtslint"
367+
command: ls -la chai
368+
working_directory: cli/types
368369
- run:
369-
command: yarn type-check --ignore-progress
370+
command: yarn lerna exec --scope cypress "yarn dtslint"
370371
- store-npm-logs
371372

372373
build-system-unit-tests:
@@ -1032,6 +1033,47 @@ jobs:
10321033
working_directory: test-binary
10331034
command: $(npm bin)/cypress info
10341035

1036+
test-types-cypress-and-jest:
1037+
parameters:
1038+
executor:
1039+
description: Executor name to use
1040+
type: executor
1041+
default: cy-doc
1042+
wd:
1043+
description: Working directory, should be OUTSIDE cypress monorepo folder
1044+
type: string
1045+
default: /root/test-cypress-and-jest
1046+
<<: *defaults
1047+
steps:
1048+
- attach_workspace:
1049+
at: ~/
1050+
# make sure we have cypress.zip received
1051+
- run: ls -l
1052+
- run: ls -l cypress.zip cypress.tgz
1053+
- run: mkdir << parameters.wd >>
1054+
- run: node --version
1055+
- run: npm --version
1056+
- run:
1057+
name: Create new NPM package ⚗️
1058+
working_directory: << parameters.wd >>
1059+
command: npm init -y
1060+
- run:
1061+
name: Install dependencies 📦
1062+
working_directory: << parameters.wd >>
1063+
environment:
1064+
CYPRESS_INSTALL_BINARY: /root/cypress/cypress.zip
1065+
# let's install Cypress, Jest and any other package that might conflict
1066+
# https://github.com/cypress-io/cypress/issues/6690
1067+
command: |
1068+
npm install /root/cypress/cypress.tgz \
1069+
typescript jest @types/jest enzyme @types/enzyme
1070+
- run:
1071+
name: Test types clash ⚔️
1072+
working_directory: << parameters.wd >>
1073+
command: |
1074+
echo "console.log('hello world')" > hello.ts
1075+
npx tsc hello.ts --noEmit
1076+
10351077
# install NPM + binary zip and run against staging API
10361078
"test-binary-against-staging":
10371079
<<: *defaults
@@ -1354,6 +1396,10 @@ linux-workflow: &linux-workflow
13541396
requires:
13551397
- build-binary
13561398
- build-npm-package
1399+
- test-types-cypress-and-jest:
1400+
requires:
1401+
- build-binary
1402+
- build-npm-package
13571403
- post-pre-release-install-comment:
13581404
context: test-runner:commit-status-checks
13591405
filters:

cli/package.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,6 @@
2323
"@cypress/listr-verbose-renderer": "0.4.1",
2424
"@cypress/request": "2.88.5",
2525
"@cypress/xvfb": "1.2.4",
26-
"@types/blob-util": "1.3.3",
27-
"@types/bluebird": "3.5.29",
28-
"@types/chai": "4.2.7",
29-
"@types/chai-jquery": "1.1.40",
30-
"@types/jquery": "3.3.31",
31-
"@types/lodash": "4.14.149",
32-
"@types/minimatch": "3.0.3",
33-
"@types/mocha": "5.2.7",
34-
"@types/sinon": "7.5.1",
35-
"@types/sinon-chai": "3.2.3",
3626
"@types/sizzle": "2.3.2",
3727
"arch": "2.1.1",
3828
"bluebird": "3.7.2",
@@ -72,6 +62,16 @@
7262
"@babel/preset-env": "7.9.5",
7363
"@cypress/sinon-chai": "1.1.0",
7464
"@packages/root": "*",
65+
"@types/blob-util": "1.3.3",
66+
"@types/bluebird": "3.5.29",
67+
"@types/chai": "4.2.7",
68+
"@types/chai-jquery": "1.1.40",
69+
"@types/jquery": "3.3.31",
70+
"@types/lodash": "4.14.149",
71+
"@types/minimatch": "3.0.3",
72+
"@types/mocha": "5.2.7",
73+
"@types/sinon": "7.5.1",
74+
"@types/sinon-chai": "3.2.3",
7575
"chai": "3.5.0",
7676
"chai-as-promised": "7.1.1",
7777
"chai-string": "1.5.0",

cli/scripts/post-install.js

Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,70 @@
1-
const fs = require('../lib/fs')
2-
const path = require('path')
1+
#!/usr/bin/env node
2+
3+
// @ts-check
4+
/* eslint-disable no-console */
5+
6+
const { includeTypes } = require('./utils')
7+
const shell = require('shelljs')
8+
const { join } = require('path')
9+
const resolvePkg = require('resolve-pkg')
10+
11+
shell.set('-v') // verbose
12+
shell.set('-e') // any error is fatal
13+
14+
// We include the TypeScript definitions for the bundled 3rd party tools
15+
// thus we need to copy them from "dev" dependencies into our types folder
16+
// and we need to sometimes tweak these types files to use relative paths
17+
// This ensures that globals like Cypress.$, Cypress._ etc are property typed
18+
// yet we do not install "@types/.." packages with "npm install cypress"
19+
// because they can conflict with user's own libraries
20+
21+
includeTypes.forEach((folder) => {
22+
const source = resolvePkg(`@types/${folder}`, { cwd: join(__dirname, '..', '..') })
23+
24+
shell.cp('-R', source, 'types')
25+
})
26+
27+
// jQuery v3.3.x includes "dist" folder that just references back to itself
28+
// causing dtslint to think there are double definitions. Remove that folder.
29+
const typesJqueryDistFolder = join('types', 'jquery', 'dist')
30+
31+
shell.rm('-rf', typesJqueryDistFolder)
332

433
/**
5-
* https://github.com/cypress-io/cypress/pull/5780
6-
* Folder names in "node_modules/@types" that were copied to cli/types to generate index.d.ts.
7-
* They cause type errors in type checker. So, they should be removed.
34+
* Replaces "reference types=<name>" comment with "reference path=..." line.
35+
* @param {string} typeName - like "chai" or "jquery"
36+
* @param {string} relativeTypesFilePath - relative path to .d.ts file like "../chai/index.d.ts"
37+
* @param {string} filename - the source file to change
838
*/
9-
const includeTypes = [
10-
'blob-util',
11-
'bluebird',
12-
'lodash',
13-
'mocha',
14-
'minimatch',
15-
'sinon',
16-
'sinon-chai',
17-
'chai',
18-
'chai-jquery',
19-
'jquery',
20-
]
21-
22-
includeTypes.forEach((t) => {
23-
const dir = path.join(__dirname, '../types', t)
24-
25-
if (fs.existsSync(dir)) {
26-
fs.removeSync(dir)
27-
}
28-
})
39+
function makeReferenceTypesCommentRelative (typeName, relativeTypesFilePath, filename) {
40+
console.log('in file %s changing reference for types %s to relative path %s',
41+
filename, typeName, relativeTypesFilePath)
42+
43+
const referenceTypes = `<reference types="${typeName}" />`
44+
const relativeTypes = `<reference path="${relativeTypesFilePath}" />`
45+
46+
shell.sed(
47+
'-i',
48+
referenceTypes,
49+
relativeTypes,
50+
filename,
51+
)
52+
}
53+
54+
// fix paths to Chai, jQuery and other types to be relative
55+
makeReferenceTypesCommentRelative('chai', '../chai/index.d.ts',
56+
join('types', 'chai-jquery', 'index.d.ts'))
57+
58+
makeReferenceTypesCommentRelative('jquery', '../jquery/index.d.ts',
59+
join('types', 'chai-jquery', 'index.d.ts'))
60+
61+
const sinonChaiFilename = join('types', 'sinon-chai', 'index.d.ts')
62+
63+
makeReferenceTypesCommentRelative('chai', '../chai/index.d.ts', sinonChaiFilename)
64+
65+
// also use relative import via path for sinon-chai
66+
// there is reference comment line we need to fix to be relative
67+
makeReferenceTypesCommentRelative('sinon', '../sinon/index.d.ts', sinonChaiFilename)
68+
69+
// and an import sinon line to be changed to relative path
70+
shell.sed('-i', 'from \'sinon\';', 'from \'../sinon\';', sinonChaiFilename)

cli/scripts/start-build.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#!/usr/bin/env node
22

3+
const { includeTypes } = require('./utils')
4+
const { join } = require('path')
35
const shell = require('shelljs')
46

57
shell.set('-v') // verbose
@@ -13,6 +15,12 @@ shell.cp('NPM_README.md', 'build/README.md')
1315
shell.cp('.release.json', 'build/.release.json')
1416
// copies our typescript definitions
1517
shell.cp('-R', 'types/*.ts', 'build/types/')
18+
// copies 3rd party typescript definitions
19+
includeTypes.forEach((folder) => {
20+
const source = join('types', folder)
21+
22+
shell.cp('-R', source, 'build/types')
23+
})
1624

1725
shell.exec('babel lib -d build/lib')
1826
shell.exec('babel index.js -o build/index.js')

cli/scripts/utils.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Folder names in "node_modules/@types" that we should include
3+
* when we bundle Cypress NPM package. These folder have ".d.ts"
4+
* definition files that we will need to include with our NPM package.
5+
*/
6+
const includeTypes = [
7+
'blob-util',
8+
'bluebird',
9+
'lodash',
10+
'mocha',
11+
'minimatch',
12+
'sinon',
13+
'sinon-chai',
14+
'chai',
15+
'chai-jquery',
16+
'jquery',
17+
]
18+
19+
module.exports = { includeTypes }

cli/types/cy-blob-util.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Shim definition to export a namespace. Cypress is actually a global module
2+
// so import/export isn't allowed there. We import here and define a global module
3+
// so that Cypress can get and use the Blob type
4+
5+
// tslint:disable-next-line:no-implicit-dependencies
6+
import * as blobUtil from './blob-util'
7+
8+
export = BlobUtil
9+
export as namespace BlobUtil
10+
11+
declare namespace BlobUtil {
12+
type BlobUtilStatic = typeof blobUtil
13+
}

cli/types/cy-bluebird.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Shim definition to export a namespace. Cypress is actually a global module
2+
// so import/export isn't allowed there. We import here and define a global module
3+
// so that Cypress can get and use the Blob type
4+
import BluebirdStatic = require('./bluebird')
5+
6+
export = Bluebird
7+
export as namespace Bluebird
8+
9+
declare namespace Bluebird {
10+
type BluebirdStatic = typeof BluebirdStatic
11+
}

cli/types/cy-chai.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Shim definition to export a namespace. Cypress is actually a global module
2+
// so import/export isn't allowed there. We import here and define a global module
3+
/// <reference path="./chai/index.d.ts" />
4+
declare namespace Chai {
5+
interface Include {
6+
html(html: string): Assertion
7+
text(text: string): Assertion
8+
value(text: string): Assertion
9+
}
10+
}

cli/types/cy-minimatch.d.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// I was trying to avoid relying on "import" of actual module from "minimatch"
2+
// because it would not work in test project, and the only reliable way
3+
// to get around type errors finally was to copy the minimal minimatch function
4+
// definition from "minimatch/index.d.ts" here and just keep it in our code
5+
6+
export = Minimatch
7+
export as namespace Minimatch
8+
9+
interface MinimatchOptions {
10+
/**
11+
* Dump a ton of stuff to stderr.
12+
*
13+
* @default false
14+
*/
15+
debug?: boolean
16+
17+
/**
18+
* Do not expand {a,b} and {1..3} brace sets.
19+
*
20+
* @default false
21+
*/
22+
nobrace?: boolean
23+
24+
/**
25+
* Disable ** matching against multiple folder names.
26+
*
27+
* @default false
28+
*/
29+
noglobstar?: boolean
30+
31+
/**
32+
* Allow patterns to match filenames starting with a period,
33+
* even if the pattern does not explicitly have a period in that spot.
34+
*
35+
* @default false
36+
*/
37+
dot?: boolean
38+
39+
/**
40+
* Disable "extglob" style patterns like +(a|b).
41+
*
42+
* @default false
43+
*/
44+
noext?: boolean
45+
46+
/**
47+
* Perform a case-insensitive match.
48+
*
49+
* @default false
50+
*/
51+
nocase?: boolean
52+
53+
/**
54+
* When a match is not found by minimatch.match,
55+
* return a list containing the pattern itself if this option is set.
56+
* Otherwise, an empty list is returned if there are no matches.
57+
*
58+
* @default false
59+
*/
60+
nonull?: boolean
61+
62+
/**
63+
* If set, then patterns without slashes will be matched against
64+
* the basename of the path if it contains slashes.
65+
*
66+
* @default false
67+
*/
68+
matchBase?: boolean
69+
70+
/**
71+
* Suppress the behavior of treating #
72+
* at the start of a pattern as a comment.
73+
*
74+
* @default false
75+
*/
76+
nocomment?: boolean
77+
78+
/**
79+
* Suppress the behavior of treating a leading ! character as negation.
80+
*
81+
* @default false
82+
*/
83+
nonegate?: boolean
84+
85+
/**
86+
* Returns from negate expressions the same as if they were not negated.
87+
* (Ie, true on a hit, false on a miss.)
88+
*
89+
* @default false
90+
*/
91+
flipNegate?: boolean
92+
}
93+
94+
declare namespace Minimatch {
95+
function minimatch(target: string, pattern: string, options?: MinimatchOptions): boolean
96+
}

cli/types/cy-moment.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import moment = require('moment')
2+
export = Moment
3+
export as namespace Moment
4+
5+
declare namespace Moment {
6+
type MomentStatic = typeof moment
7+
}

0 commit comments

Comments
 (0)