diff --git a/cli/package.json b/cli/package.json index 577cb3ea371b..046ed8d3e6e8 100644 --- a/cli/package.json +++ b/cli/package.json @@ -16,6 +16,7 @@ "check-deps-pre": "npm run check-deps -- --prescript", "dtslint": "dtslint types", "postinstall": "node ./scripts/post-install.js", + "lint": "bin-up eslint --fix *.js scripts/*.js bin/* lib/*.js lib/**/*.js test/*.js test/**/*.js", "prerelease": "npm run build", "release": "cd build && releaser --no-node --no-changelog", "size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";", @@ -27,6 +28,7 @@ "test-unit": "npm run unit", "pretest-watch": "npm run check-deps-pre", "test-watch": "npm run unit -- --watch", + "types": "npm run dtslint", "unit": "BLUEBIRD_DEBUG=1 NODE_ENV=test bin-up mocha --reporter mocha-multi-reporters --reporter-options configFile=../mocha-reporter-config.json" }, "dependencies": { diff --git a/cli/types/index.d.ts b/cli/types/index.d.ts index 1a08f23bf673..fb2abae383f0 100644 --- a/cli/types/index.d.ts +++ b/cli/types/index.d.ts @@ -4304,22 +4304,44 @@ declare namespace Cypress { // Diff taken from https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-311923766 type Diff = ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T] type Omit = Pick> + + /** + * Public interface for the global "cy" object. If you want to add + * a custom property to this object, you should extend this interface. + * @see https://on.cypress.io/typescript#Types-for-custom-commands + * + ``` + // in your TS file + declare namespace Cypress { + interface cy { + // declare additional properties on "cy" object, like + // label: string + } + interface Chainable { + // declare additional custom commands as methods, like + // login(username: string, password: string) + } + } + ``` + */ + interface cy extends Chainable {} } /** * Global variables `cy` added by Cypress with all API commands. * @see https://on.cypress.io/api - * @example + * ``` cy.get('button').click() cy.get('.result').contains('Expected text') ``` */ -declare const cy: Cypress.Chainable +declare const cy: Cypress.cy + /** * Global variable `Cypress` holds common utilities and constants. * @see https://on.cypress.io/api - * @example + * ``` Cypress.config("pageLoadTimeout") // => 60000 Cypress.version // => "1.4.0" diff --git a/cli/types/tests/plugins-test.ts b/cli/types/tests/plugins-test.ts new file mode 100644 index 000000000000..b2b06a2db80c --- /dev/null +++ b/cli/types/tests/plugins-test.ts @@ -0,0 +1,58 @@ +// +// Test that plugin authors can write .d.ts files to extend Cypress types +// with new "cy" properties and new methods. +// +// Unfortunately we cannot test that vendor types located in node_modules are working +// since those are copied as part of the deploy process +// + +/** + * If you want to add additional properties to the "cy" object, + * or additional methods to "cy" or "cy.()" chained value, + * declare them and TypeScript will merge new definitions with existing ones. + * @see https://on.cypress.io/typescript#Types-for-custom-commands +*/ +declare namespace Cypress { + interface cy { + /** + * We have added a label property to "cy" object. + * @example console.log(cy.myLabel) + */ + myLabel: string, + /** + * Definition for a custom command "login" that was added separately + * using `Cypress.Commands.add('login', (username, password) => {...})`. + */ + login(username: string, password: string): Chainable + } + interface Chainable { + /** + * Additional property added to the chained object, + * returned by Cypress commands. This property will NOT + * be part of "cy" object, but a property of an object + * returned by Cypress commands. + ``` + cy.get('.element').chainerProp + ``` + */ + chainerProp: number + } +} + +// $ExpectType string +cy.myLabel + +// new custom command "cy.login" +// $ExpectType Chainable +cy.login(Cypress.env('username'), Cypress.env('password')) + +// "myLabel" property has been added to "interface cy" +// thus it is NOT of the command chain. +// $ExpectError +cy.get('.element').myLabel + +// $ExpectType number +cy.chainerProp + +// $ExpectType number +cy.get('.element').chainerProp