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

Add Cypress.dom.* to TS type declarations #5298

Merged
merged 13 commits into from
Mar 2, 2020
108 changes: 108 additions & 0 deletions cli/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,36 @@ declare namespace Cypress {
clear: (keys?: string[]) => void
}

interface ViewportPosition extends WindowPosition {
right: number
bottom: number
}

interface WindowPosition {
top: number
left: number
topCenter: number
leftCenter: number
}

interface ElementPositioning {
scrollTop: number
scrollLeft: number
width: number
height: number
fromElViewport: ViewportPosition
fromElWindow: WindowPosition
fromAutWindow: WindowPosition
}

interface ElementCoordinates {
width: number
height: number
fromElViewport: ViewportPosition & { x: number, y: number }
fromElWindow: WindowPosition & { x: number, y: number }
fromAutWindow: WindowPosition & { x: number, y: number }
}

/**
* Several libraries are bundled with Cypress by default.
*
Expand Down Expand Up @@ -371,7 +401,85 @@ declare namespace Cypress {
* @see https://on.cypress.io/dom
*/
dom: {
/**
* Returns a jQuery object obtained by wrapping an object in jQuery.
*/
wrap(wrappingElement_function: JQuery.Selector | JQuery.htmlString | Element | JQuery | ((index: number) => string | JQuery)): JQuery
query(selector: JQuery.Selector, context?: Element | JQuery): JQuery
/**
* Returns an array of raw elements pulled out from a jQuery object.
*/
unwrap(obj: any): any
/**
* Returns a boolean indicating whether an object is a DOM object.
*/
isDom(obj: any): boolean
isType(element: JQuery | HTMLElement , type: string): boolean
/**
* Returns a boolean indicating whether an element is visible.
*/
isVisible(element: JQuery | HTMLElement): boolean
/**
* Returns a boolean indicating whether an element is hidden.
*/
isHidden(element: JQuery | HTMLElement): boolean
/**
* Returns a boolean indicating whether an element can receive focus.
*/
isFocusable(element: JQuery | HTMLElement): boolean
isTextLike(element: JQuery | HTMLElement): boolean
/**
* Returns a boolean indicating whether an element is scrollable.
*/
isScrollable(element: Window | JQuery | HTMLElement): boolean
/**
* Returns a boolean indicating whether an element currently has focus.
*/
isFocused(element: JQuery | HTMLElement): boolean
/**
* Returns a boolean indicating whether an element is detached from the DOM.
*/
isDetached(element: JQuery | HTMLElement): boolean
/**
* Returns a boolean indicating whether an element is attached to the DOM.
*/
isAttached(element: JQuery | HTMLElement | Window | Document): boolean
isSelector(element: JQuery | HTMLElement, selector: JQuery.Selector): boolean
/**
* Returns a boolean indicating whether an element is a descendent of another element.
*/
isDescendent(element1: JQuery | HTMLElement, element2: JQuery | HTMLElement): boolean
/**
* Returns a boolean indicating whether an object is a DOM element.
*/
isElement(obj: any): boolean
/**
* Returns a boolean indicating whether a node is of document type.
*/
isDocument(obj: any): boolean
/**
* Returns a boolean indicating whether an object is a window object.
*/
isWindow(obj: any): boolean
/**
* Returns a boolean indicating whether an object is a jQuery object.
*/
isJquery(obj: any): boolean
isInputType(element: JQuery | HTMLElement, type: string | string[]): boolean
stringify(element: JQuery | HTMLElement, form: string): string
getElements(element: JQuery): JQuery | HTMLElement[]
getContainsSelector(text: string, filter?: string): JQuery.Selector
getFirstDeepestElement(elements: HTMLElement[], index?: number): HTMLElement
getWindowByElement(element: JQuery | HTMLElement): JQuery | HTMLElement
getReasonIsHidden(element: JQuery | HTMLElement): string
getFirstScrollableParent(element: JQuery | HTMLElement): JQuery | HTMLElement
getFirstFixedOrStickyPositionParent(element: JQuery | HTMLElement): JQuery | HTMLElement
getFirstStickyPositionParent(element: JQuery | HTMLElement): JQuery | HTMLElement
getCoordsByPosition(left: number, top: number, xPosition?: string, yPosition?: string): number
getElementPositioning(element: JQuery | HTMLElement): ElementPositioning
getElementAtPointFromViewport(doc: Document, x: number, y: number): Element | null
getElementCoordinatesByPosition(element: JQuery | HTMLElement, position: string): ElementCoordinates
getElementCoordinatesByPositionRelativeToXY(element: JQuery | HTMLElement, x: number, y: number): ElementPositioning
}

/**
Expand Down
77 changes: 77 additions & 0 deletions cli/types/tests/cypress-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,3 +355,80 @@ namespace CypressBrowserTests {
Cypress.isBrowser({family: 'foo'}) // $ExpectError
Cypress.isBrowser() // $ExpectError
}

namespace CypressDomTests {
const obj: any = {}
const el = {} as any as HTMLElement
const jel = {} as any as JQuery
const doc = {} as any as Document

Cypress.dom.wrap((x: number) => 'a') // $ExpectType JQuery<HTMLElement>
Cypress.dom.query('foo', el) // $ExpectType JQuery<HTMLElement>
Cypress.dom.unwrap(obj) // $ExpectType any
Cypress.dom.isDom(obj) // $ExpectType boolean
Cypress.dom.isType(el, 'foo') // $ExpectType boolean
Cypress.dom.isVisible(el) // $ExpectType boolean
Cypress.dom.isHidden(el) // $ExpectType boolean
Cypress.dom.isFocusable(el) // $ExpectType boolean
Cypress.dom.isTextLike(el) // $ExpectType boolean
Cypress.dom.isScrollable(el) // $ExpectType boolean
Cypress.dom.isFocused(el) // $ExpectType boolean
Cypress.dom.isDetached(el) // $ExpectType boolean
Cypress.dom.isAttached(el) // $ExpectType boolean
Cypress.dom.isSelector(el, 'foo') // $ExpectType boolean
Cypress.dom.isDescendent(el, el) // $ExpectType boolean
Cypress.dom.isElement(obj) // $ExpectType boolean
Cypress.dom.isDocument(obj) // $ExpectType boolean
Cypress.dom.isWindow(obj) // $ExpectType boolean
Cypress.dom.isJquery(obj) // $ExpectType boolean
Cypress.dom.isInputType(el, 'number') // $ExpectType boolean
Cypress.dom.stringify(el, 'foo') // $ExpectType string
Cypress.dom.getElements(jel) // $ExpectType JQuery<HTMLElement> | HTMLElement[]
Cypress.dom.getContainsSelector('foo', 'bar') // $ExpectType string
Cypress.dom.getFirstDeepestElement([el], 1) // $ExpectType HTMLElement
Cypress.dom.getWindowByElement(el) // $ExpectType HTMLElement | JQuery<HTMLElement>
Cypress.dom.getReasonIsHidden(el) // $ExpectType string
Cypress.dom.getFirstScrollableParent(el) // $ExpectType HTMLElement | JQuery<HTMLElement>
Cypress.dom.getFirstFixedOrStickyPositionParent(el) // $ExpectType HTMLElement | JQuery<HTMLElement>
Cypress.dom.getFirstStickyPositionParent(el) // $ExpectType HTMLElement | JQuery<HTMLElement>
Cypress.dom.getCoordsByPosition(1, 2) // $ExpectType number
Cypress.dom.getElementPositioning(el) // $ExpectType ElementPositioning
Cypress.dom.getElementAtPointFromViewport(doc, 1, 2) // $ExpectType Element | null
Cypress.dom.getElementCoordinatesByPosition(el, 'top') // $ExpectType ElementCoordinates
Cypress.dom.getElementCoordinatesByPositionRelativeToXY(el, 1, 2) // $ExpectType ElementPositioning

Cypress.dom.wrap() // $ExpectError
Cypress.dom.query(el, 'foo') // $ExpectError
Cypress.dom.unwrap() // $ExpectError
Cypress.dom.isDom() // $ExpectError
Cypress.dom.isType(el) // $ExpectError
Cypress.dom.isVisible('') // $ExpectError
Cypress.dom.isHidden('') // $ExpectError
Cypress.dom.isFocusable('') // $ExpectError
Cypress.dom.isTextLike('') // $ExpectError
Cypress.dom.isScrollable('') // $ExpectError
Cypress.dom.isFocused('') // $ExpectError
Cypress.dom.isDetached('') // $ExpectError
Cypress.dom.isAttached('') // $ExpectError
Cypress.dom.isSelector('', 'foo') // $ExpectError
Cypress.dom.isDescendent('', '') // $ExpectError
Cypress.dom.isElement() // $ExpectError
Cypress.dom.isDocument() // $ExpectError
Cypress.dom.isWindow() // $ExpectError
Cypress.dom.isJquery() // $ExpectError
Cypress.dom.isInputType('', 'number') // $ExpectError
Cypress.dom.stringify('', 'foo') // $ExpectError
Cypress.dom.getElements(el) // $ExpectError
Cypress.dom.getContainsSelector(el, 'bar') // $ExpectError
Cypress.dom.getFirstDeepestElement(el, 1) // $ExpectError
Cypress.dom.getWindowByElement('') // $ExpectError
Cypress.dom.getReasonIsHidden('') // $ExpectError
Cypress.dom.getFirstScrollableParent('') // $ExpectError
Cypress.dom.getFirstFixedOrStickyPositionParent('') // $ExpectError
Cypress.dom.getFirstStickyPositionParent('') // $ExpectError
Cypress.dom.getCoordsByPosition(1) // $ExpectError
Cypress.dom.getElementPositioning('') // $ExpectError
Cypress.dom.getElementAtPointFromViewport(el, 1, 2) // $ExpectError
Cypress.dom.getElementCoordinatesByPosition(doc, 'top') // $ExpectError
Cypress.dom.getElementCoordinatesByPositionRelativeToXY(doc, 1, 2) // $ExpectError
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
const $ = Cypress.$.bind(Cypress)
declare namespace Cypress {
interface cy {
state(key: 'document'): Document
}
}

describe('src/dom/coordinates', () => {
const $ = Cypress.$.bind(Cypress)
let doc: Document

before(() => {
return cy
.visit('/fixtures/generic.html')
Expand All @@ -10,9 +17,9 @@ describe('src/dom/coordinates', () => {
})

beforeEach(function () {
this.doc = cy.state('document')
doc = cy.state('document')

$(this.doc.body).empty().html(this.body)
$(doc.body).empty().html(this.body)

this.$button = $('<button style=\'position: absolute; top: 25px; left: 50px; width: 100px; line-height: 50px; padding: 10px; margin: 10px; border: 10px solid black\'>foo</button>')
.appendTo(cy.$$('body'))
Expand All @@ -24,8 +31,8 @@ describe('src/dom/coordinates', () => {
it('returns the leftCenter and topCenter normalized', function () {
const win = Cypress.dom.getWindowByElement(this.$button.get(0))

const scrollY = Object.getOwnPropertyDescriptor(win, 'scrollY')
const scrollX = Object.getOwnPropertyDescriptor(win, 'scrollX')
const scrollY = Object.getOwnPropertyDescriptor(win, 'scrollY')!
const scrollX = Object.getOwnPropertyDescriptor(win, 'scrollX')!

Object.defineProperty(win, 'scrollY', {
value: 10,
Expand Down Expand Up @@ -63,17 +70,17 @@ describe('src/dom/coordinates', () => {

context('.getElementAtPointFromViewport', () => {
it('returns same element based on x/y coords', function () {
expect(Cypress.dom.getElementAtPointFromViewport(this.doc, 100, 60)).to.eq(this.$button.get(0))
expect(Cypress.dom.getElementAtPointFromViewport(doc, 100, 60)).to.eq(this.$button.get(0))
})

it('does not return if element is hidden', function () {
this.$button.hide()

expect(Cypress.dom.getElementAtPointFromViewport(this.doc, 100, 60)).not.to.eq(this.$button.get(0))
expect(Cypress.dom.getElementAtPointFromViewport(doc, 100, 60)).not.to.eq(this.$button.get(0))
})

it('returns null if no element was found', function () {
expect(Cypress.dom.getElementAtPointFromViewport(this.doc, 1e9, 1e9)).to.be.null
expect(Cypress.dom.getElementAtPointFromViewport(doc, 1e9, 1e9)).to.be.null
})
})

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
const $ = Cypress.$.bind(Cypress)
declare namespace Cypress {
interface cy {
state(key: 'window'): Window
}
}

describe('src/dom/elements', () => {
const $ = Cypress.$.bind(Cypress)

context('.isAttached', () => {
beforeEach(() => {
cy.visit('/fixtures/iframe-outer.html')
})

it('no elements', () => {
const $el = $(null)
const $el = $(null!)

expect(Cypress.dom.isAttached($el)).to.be.false
})
Expand Down Expand Up @@ -68,9 +74,9 @@ describe('src/dom/elements', () => {

it('element in iframe', (done) => {
cy.get('iframe').then(($iframe) => {
const $doc = $iframe.contents()
const $doc = $iframe.contents() as JQuery<Document>

const $btn = $doc.find('button')
const $btn = $doc.find('button') as unknown as JQuery<HTMLButtonElement>

expect($btn.length).to.eq(1)

Expand All @@ -84,7 +90,7 @@ describe('src/dom/elements', () => {
done()
})

const win = $doc.get(0).defaultView
const win = $doc.get(0).defaultView!

win.location.reload()
})
Expand All @@ -93,7 +99,7 @@ describe('src/dom/elements', () => {

context('.isDetached', () => {
it('opposite of attached', () => {
const $el = $(null)
const $el = $(null!)

expect(Cypress.dom.isDetached($el)).to.be.true
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const { $ } = Cypress
declare interface Window {
jquery: Function
}

describe('src/dom/jquery', () => {
context('.isJquery', () => {
Expand All @@ -9,7 +11,7 @@ describe('src/dom/jquery', () => {
})

it('is true for actual jquery instances', () => {
expect(Cypress.dom.isJquery($(':first'))).to.be.true
expect(Cypress.dom.isJquery(Cypress.$(':first'))).to.be.true
})
})
})
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const $dom = Cypress.dom
const $ = Cypress.$.bind(Cypress)

describe('src/cypress/dom/visibility', () => {
const $ = Cypress.$.bind(Cypress)

beforeEach(() => {
cy.visit('/fixtures/generic.html')
})
Expand All @@ -13,7 +14,7 @@ describe('src/cypress/dom/visibility', () => {

it('throws when not passed a DOM element', () => {
const fn = () => {
$dom.isHidden(null)
$dom.isHidden(null!)
}

expect(fn).to.throw('Cypress.dom.isHidden() failed because it requires a DOM element. The subject received was: \'null\'')
Expand All @@ -27,6 +28,7 @@ describe('src/cypress/dom/visibility', () => {

it('throws when not passed a DOM element', () => {
const fn = () => {
// @ts-ignore
$dom.isVisible('form')
}

Expand Down