Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define types for plugin events #6322

Merged
merged 22 commits into from Feb 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b2fa8ab
define types for plugin events
chrisbreiding Feb 4, 2020
c34ca8e
add plugins file TS test
bahmutov Feb 4, 2020
2aeeeb5
fix plugins return type
chrisbreiding Feb 4, 2020
ce63ab2
add void returns where allowed
chrisbreiding Feb 4, 2020
107d6d5
config can be partial
chrisbreiding Feb 4, 2020
1ae6c53
add async test
bahmutov Feb 4, 2020
d6bbf1c
Merge branch 'issue-6321-plugin-types' of github.com:cypress-io/cypre…
bahmutov Feb 4, 2020
b197019
cannot return unknown keys in config
bahmutov Feb 4, 2020
ac2cb23
add more tests
chrisbreiding Feb 4, 2020
b3f252d
add Task types and tests
bahmutov Feb 4, 2020
68b3f1e
Merge branch 'issue-6321-plugin-types' of github.com:cypress-io/cypre…
bahmutov Feb 4, 2020
1eacea1
fix style issues
chrisbreiding Feb 4, 2020
e3f9b87
Merge branch 'issue-6321-plugin-types' of github.com:cypress-io/cypre…
chrisbreiding Feb 4, 2020
44738cc
update task type with compromise, remove redundant tests
chrisbreiding Feb 4, 2020
a853a96
fix type
chrisbreiding Feb 4, 2020
1894a9a
bump kitchensink dep
jennifer-shehane Feb 5, 2020
4503777
Merge branch 'v4.0-release' into issue-6321-plugin-types
chrisbreiding Feb 5, 2020
f3cd71c
add typescript reference and jsdoc to plugins scaffold file
chrisbreiding Feb 5, 2020
053364e
update scaffold snapshot
chrisbreiding Feb 5, 2020
a7f639d
Merge branch 'v4.0-release' into issue-6321-plugin-types
chrisbreiding Feb 5, 2020
c8ced45
add more tests for before:browser:launch
chrisbreiding Feb 5, 2020
3d44a39
fix return type
chrisbreiding Feb 5, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 30 additions & 24 deletions cli/types/index.d.ts
Expand Up @@ -50,7 +50,7 @@ declare namespace Cypress {
type RequestBody = string | object
type ViewportOrientation = "portrait" | "landscape"
type PrevSubject = "optional" | "element" | "document" | "window"
type PluginConfig = (on: PluginEvents, config: ConfigOptions) => void
type PluginConfig = (on: PluginEvents, config: ConfigOptions) => void | Partial<ConfigOptions> | Promise<Partial<ConfigOptions>>

interface CommandOptions {
prevSubject: boolean | PrevSubject | PrevSubject[]
Expand Down Expand Up @@ -4236,31 +4236,22 @@ declare namespace Cypress {
(fn: (currentSubject: Subject) => void): Chainable<Subject>
}

// for just a few events like "window:alert" it makes sense to allow passing cy.stub() or
// a user callback function. Others probably only need a callback function.

/**
* These events come from the application currently under test (your application).
* These are the most useful events for you to listen to.
* @see https://on.cypress.io/catalog-of-events#App-Events
*/

interface browserLaunchOptions {
interface BrowserLaunchOptions {
extensions: string[],
preferences: {[key: string]: any}
preferences: { [key: string]: any }
args: string[],
}

interface dimensions {
interface Dimensions {
width: number
height: number
}

interface screenshotDetails {
interface ScreenshotDetails {
size: number
takenAt: string
duration: number
dimensions: dimensions
dimensions: Dimensions
multipart: boolean
pixelRatio: number
name: string
Expand All @@ -4271,29 +4262,44 @@ declare namespace Cypress {
blackout: string[]
}

interface afterScreenshotReturnObject {
interface AfterScreenshotReturnObject {
path?: string
size?: number
dimensions?: dimensions
dimensions?: Dimensions
}

interface fileObject {
interface FileObject {
filePath: string
outputPath: string
shouldWatch: boolean
}

interface tasks {
[key: string]: (value: any) => any
/**
* Individual task callback. Receives a single argument and _should_ return
* anything but `undefined` or a promise that resolves anything but `undefined`
* TODO: find a way to express "anything but undefined" in TypeScript
*/
type Task = (value: any) => any

interface Tasks {
[key: string]: Task
}

interface PluginEvents {
(action: 'before:browser:launch', fn: (browser: Browser, browserLaunchOptions: browserLaunchOptions) => browserLaunchOptions): void
(action: 'after:screenshot', fn: (details: screenshotDetails) => afterScreenshotReturnObject | Promise<afterScreenshotReturnObject>): void
(action: 'file:preprocessor', fn: (file: fileObject) => string | Promise<string>): void
(action: 'task', tasks: tasks): void
(action: 'before:browser:launch', fn: (browser: Browser, browserLaunchOptions: BrowserLaunchOptions) => void | BrowserLaunchOptions | Promise<BrowserLaunchOptions>): void
(action: 'after:screenshot', fn: (details: ScreenshotDetails) => void | AfterScreenshotReturnObject | Promise<AfterScreenshotReturnObject>): void
(action: 'file:preprocessor', fn: (file: FileObject) => string | Promise<string>): void
(action: 'task', tasks: Tasks): void
}

// for just a few events like "window:alert" it makes sense to allow passing cy.stub() or
// a user callback function. Others probably only need a callback function.

/**
* These events come from the application currently under test (your application).
* These are the most useful events for you to listen to.
* @see https://on.cypress.io/catalog-of-events#App-Events
*/
interface Actions {
/**
* Fires when an uncaught exception occurs in your application.
Expand Down
108 changes: 108 additions & 0 deletions cli/types/tests/plugins-config.ts
@@ -0,0 +1,108 @@
// checking types passed to cypress/plugins/index.js file

// does nothing
const pluginConfig: Cypress.PluginConfig = (on, config) => {}

// allows synchronous returns
const pluginConfig2: Cypress.PluginConfig = (on, config) => {
config // $ExpectType ConfigOptions
config.baseUrl // $ExpectType: string

on('before:browser:launch', (browser, options) => {
browser.displayName // $ExpectType string
options.extensions // $ExpectType string[]
options.args // $ExpectType string[]

console.log('launching browser', browser.displayName)
return options
})

on('file:preprocessor', (file) => {
file.filePath // $ExpectType string
file.outputPath // $ExpectType string
file.shouldWatch // $ExpectType boolean

return file.outputPath
})

on('after:screenshot', (details) => {
details.size // $ExpectType number
details.takenAt // $ExpectType string
details.duration // $ExpectType number
details.dimensions // $ExpectType Dimensions
details.multipart // $ExpectType boolean
details.pixelRatio // $ExpectType number
details.name // $ExpectType string
details.specName // $ExpectType string
details.testFailure // $ExpectType boolean
details.path // $ExpectType string
details.scaled // $ExpectType boolean
details.blackout // $ExpectType string[]

return {
path: '/path/to/screenshot',
size: 1000,
// FIXME: why can't dimensions be included?
// dimensions: {
// width: 100,
// height: 100,
// }
}
})

on('task', {
foo() {
return true
}
})

return {
baseUrl: 'http://localhost:3000'
}
}

// allows/disallows void returns
const pluginConfig3: Cypress.PluginConfig = (on, config) => {
on('before:browser:launch', (browser, options) => {})

on('file:preprocessor', (file) => {}) // $ExpectError

on('after:screenshot', () => {})

// FIXME: this should error, but doesn't because the type isn't quite right
// on('task', { // $ExpectError
// foo() {}
// })
}

// allows async returns
const pluginConfig4: Cypress.PluginConfig = (on, config) => {
on('before:browser:launch', (browser, options) => {
return Promise.resolve(options)
})

on('file:preprocessor', (file) => {
return Promise.resolve(file.outputPath)
})

on('after:screenshot', () => {
return Promise.resolve({})
})

on('task', {
foo() {
return Promise.resolve([])
}
})

return Promise.resolve({
baseUrl: 'http://localhost:3000'
})
}

// does not allow returning unknown properties
const pluginConfig5: Cypress.PluginConfig = (on, config) => { // $ExpectError
return {
unknownKey: 42
}
}
2 changes: 1 addition & 1 deletion packages/example/package.json
Expand Up @@ -29,7 +29,7 @@
"bin-up": "1.2.2",
"chai": "3.5.0",
"cross-env": "6.0.3",
"cypress-example-kitchensink": "1.9.0",
"cypress-example-kitchensink": "1.9.1",
"gulp": "4.0.2",
"gulp-clean": "0.4.0",
"gulp-gh-pages": "0.6.0-6",
Expand Down
4 changes: 4 additions & 0 deletions packages/server/__snapshots__/scaffold_spec.js
Expand Up @@ -428,6 +428,7 @@ exports['lib/scaffold .fileTree leaves out plugins if configured to false 1'] =
]

exports['lib/scaffold .plugins creates pluginsFile when pluginsFolder does not exist 1'] = `
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
Expand All @@ -441,6 +442,9 @@ exports['lib/scaffold .plugins creates pluginsFile when pluginsFolder does not e
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {
// <backtick>on<backtick> is used to hook into various events Cypress emits
// <backtick>config<backtick> is the resolved Cypress config
Expand Down
4 changes: 4 additions & 0 deletions packages/server/lib/scaffold/plugins/index.js
@@ -1,3 +1,4 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
Expand All @@ -11,6 +12,9 @@
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
Expand Down