mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-31 03:29:43 -06:00
use typescript in driver (#5383)
* upgrade eslint-plugin-dev to 5.0.0 * more [lint fixes] * use typescript in driver * cleanup minor * remove unneeded file * mild refactor webpack configs * fix elements.ts * fix isTextLike signature change * fix isType check, fix type_spec * actually use webpack-preprocessor * fix isType domUtil * fix connectors_spec * cleanup connectors_spec * address feedback- cleanup, add comments, refac * answer: no, need index.js
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
"@cypress/sinon-chai": "1.1.0",
|
||||
"@cypress/underscore.inflection": "1.0.1",
|
||||
"@cypress/unique-selector": "0.4.2",
|
||||
"@cypress/webpack-preprocessor": "4.1.0",
|
||||
"@cypress/what-is-circular": "1.0.1",
|
||||
"angular": "1.7.7",
|
||||
"backbone": "1.4.0",
|
||||
@@ -60,6 +61,7 @@
|
||||
"url-parse": "1.4.7",
|
||||
"vanilla-text-mask": "5.1.1",
|
||||
"wait-on": "3.3.0",
|
||||
"webpack": "4.41.0",
|
||||
"zone.js": "0.9.0"
|
||||
},
|
||||
"files": [
|
||||
|
||||
43
packages/driver/src/config/lodash.d.ts
vendored
Normal file
43
packages/driver/src/config/lodash.d.ts
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// const _ = require('lodash')
|
||||
import _ from 'lodash'
|
||||
import underscoreInflection from '@cypress/underscore.inflection'
|
||||
|
||||
import clean from 'underscore.string/clean'
|
||||
import count from 'underscore.string/count'
|
||||
import isBlank from 'underscore.string/isBlank'
|
||||
import toBoolean from 'underscore.string/toBoolean'
|
||||
import capitalize from 'underscore.string/capitalize'
|
||||
|
||||
const inflection = underscoreInflection(_)
|
||||
|
||||
// only export exactly what we need, nothing more!
|
||||
_.mixin({
|
||||
clean,
|
||||
count,
|
||||
isBlank,
|
||||
toBoolean,
|
||||
capitalize, // its mo' better the lodash version
|
||||
ordinalize: inflection.ordinalize,
|
||||
})
|
||||
|
||||
declare module 'lodash' {
|
||||
export interface LoDashExplicitWrapper<TValue> {
|
||||
clean(...args): LoDashExplicitWrapper<TValue>
|
||||
count(...args): LoDashExplicitWrapper<TValue>
|
||||
isBlank(...args): LoDashExplicitWrapper<TValue>
|
||||
toBoolean(...args): LoDashExplicitWrapper<TValue>
|
||||
capitalize(...args): LoDashExplicitWrapper<TValue>
|
||||
ordinalize(...args): LoDashExplicitWrapper<TValue>
|
||||
}
|
||||
|
||||
export interface LodashStatic<TValue> {
|
||||
clean(...args): LoDashExplicitWrapper<TValue>
|
||||
count(...args): LoDashExplicitWrapper<TValue>
|
||||
isBlank(...args): LoDashExplicitWrapper<TValue>
|
||||
toBoolean(...args): LoDashExplicitWrapper<TValue>
|
||||
capitalize(...args): LoDashExplicitWrapper<TValue>
|
||||
ordinalize(...args): LoDashExplicitWrapper<TValue>
|
||||
}
|
||||
}
|
||||
|
||||
export default _
|
||||
@@ -11,3 +11,5 @@ _.mixin({
|
||||
capitalize: require('underscore.string/capitalize'), // its mo' better the lodash version
|
||||
ordinalize: inflection.ordinalize,
|
||||
})
|
||||
|
||||
export default _
|
||||
|
||||
@@ -111,7 +111,7 @@ module.exports = function (Commands, Cypress, cy, state, config) {
|
||||
}
|
||||
|
||||
const isBody = options.$el.is('body')
|
||||
const isTextLike = $dom.isTextLike(options.$el)
|
||||
const isTextLike = $dom.isTextLike(options.$el.get(0))
|
||||
const isDate = $dom.isType(options.$el, 'date')
|
||||
const isTime = $dom.isType(options.$el, 'time')
|
||||
const isMonth = $dom.isType(options.$el, 'month')
|
||||
@@ -537,7 +537,7 @@ module.exports = function (Commands, Cypress, cy, state, config) {
|
||||
|
||||
const node = $dom.stringify($el)
|
||||
|
||||
if (!$dom.isTextLike($el)) {
|
||||
if (!$dom.isTextLike($el.get(0))) {
|
||||
const word = $utils.plural(subject, 'contains', 'is')
|
||||
|
||||
$utils.throwErrByPath('clear.invalid_element', {
|
||||
|
||||
@@ -117,7 +117,7 @@ create = (state, expect) ->
|
||||
|
||||
# readonly can only be applied to input/textarea
|
||||
# not on checkboxes, radios, etc..
|
||||
if $dom.isTextLike(subject) and subject.prop("readonly")
|
||||
if $dom.isTextLike(subject.get(0)) and subject.prop("readonly")
|
||||
node = $dom.stringify(subject)
|
||||
|
||||
$utils.throwErrByPath("dom.readonly", {
|
||||
|
||||
@@ -359,8 +359,8 @@ const create = (state) => {
|
||||
'{shift}': 'shift',
|
||||
},
|
||||
|
||||
type (options = {}) {
|
||||
_.defaults(options, {
|
||||
type (opts = {}) {
|
||||
const options = _.defaults(opts, {
|
||||
delay: 10,
|
||||
parseSpecialCharSequences: true,
|
||||
onEvent () {},
|
||||
@@ -599,7 +599,7 @@ const create = (state) => {
|
||||
})
|
||||
},
|
||||
|
||||
ensureKey (el, key, options, fn) {
|
||||
ensureKey (el, key, options, fn?: Function) {
|
||||
_.defaults(options, {
|
||||
prevText: null,
|
||||
})
|
||||
@@ -697,7 +697,7 @@ const create = (state) => {
|
||||
|
||||
resetModifiers (doc) {
|
||||
const activeEl = $elements.getActiveElByDocument(doc)
|
||||
const activeModifiers = kb.getActiveModifiers(state)
|
||||
const activeModifiers = kb.getActiveModifiers()
|
||||
|
||||
for (let modifier in activeModifiers) {
|
||||
const isActivated = activeModifiers[modifier]
|
||||
@@ -718,7 +718,7 @@ const create = (state) => {
|
||||
return kb
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export {
|
||||
create,
|
||||
toModifiersEventOptions,
|
||||
modifiersToString,
|
||||
@@ -1,17 +1,18 @@
|
||||
const _ = require('lodash')
|
||||
const $ = require('jquery')
|
||||
const $jquery = require('./jquery')
|
||||
const $window = require('./window')
|
||||
const $document = require('./document')
|
||||
const $utils = require('../cypress/utils')
|
||||
const $selection = require('./selection')
|
||||
const { parentHasDisplayNone } = require('./visibility')
|
||||
// NOT patched jquery
|
||||
import $ from 'jquery'
|
||||
import * as $jquery from './jquery'
|
||||
import * as $window from './window'
|
||||
import * as $document from './document'
|
||||
import $utils from '../cypress/utils.coffee'
|
||||
import * as $selection from './selection'
|
||||
import _ from '../config/lodash'
|
||||
import { parentHasDisplayNone } from './visibility'
|
||||
|
||||
const { wrap } = $jquery
|
||||
|
||||
const fixedOrStickyRe = /(fixed|sticky)/
|
||||
|
||||
const focusable = [
|
||||
const focusableSelectors = [
|
||||
'a[href]',
|
||||
'area[href]',
|
||||
'input:not([disabled])',
|
||||
@@ -20,17 +21,43 @@ const focusable = [
|
||||
'button:not([disabled])',
|
||||
'iframe',
|
||||
'[tabindex]',
|
||||
'[contentEditable]',
|
||||
'[contenteditable]',
|
||||
]
|
||||
const inputTypeNeedSingleValueChangeRe = /^(date|time|month|week)$/
|
||||
const canSetSelectionRangeElementRe = /^(text|search|URL|tel|password)$/
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
Element: typeof Element
|
||||
HTMLElement: typeof HTMLElement
|
||||
HTMLInputElement: typeof HTMLInputElement
|
||||
HTMLSelectElement: typeof HTMLSelectElement
|
||||
HTMLButtonElement: typeof HTMLButtonElement
|
||||
HTMLOptionElement: typeof HTMLOptionElement
|
||||
HTMLTextAreaElement: typeof HTMLTextAreaElement
|
||||
Selection: typeof Selection
|
||||
SVGElement: typeof SVGElement
|
||||
EventTarget: typeof EventTarget
|
||||
Document: typeof Document
|
||||
}
|
||||
|
||||
interface Selection {
|
||||
modify: Function
|
||||
}
|
||||
}
|
||||
|
||||
// rules for native methods and props
|
||||
// if a setter or getter or function then add a native method
|
||||
// if a traversal, don't
|
||||
|
||||
const descriptor = (klass, prop) => {
|
||||
return Object.getOwnPropertyDescriptor(window[klass].prototype, prop)
|
||||
const descriptor = <T extends keyof Window, K extends keyof Window[T]['prototype']>(klass: T, prop: K) => {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(window[klass].prototype, prop)
|
||||
|
||||
if (descriptor === undefined) {
|
||||
throw new Error(`Error, could not get property descriptor for ${klass} ${prop}. This should never happen`)
|
||||
}
|
||||
|
||||
return descriptor
|
||||
}
|
||||
|
||||
const _getValue = function () {
|
||||
@@ -83,6 +110,8 @@ const _getSelectionStart = function () {
|
||||
if (isTextarea(this)) {
|
||||
return descriptor('HTMLTextAreaElement', 'selectionStart').get
|
||||
}
|
||||
|
||||
throw new Error('this should never happen, cannot get selectionStart')
|
||||
}
|
||||
|
||||
const _getSelectionEnd = function () {
|
||||
@@ -93,6 +122,8 @@ const _getSelectionEnd = function () {
|
||||
if (isTextarea(this)) {
|
||||
return descriptor('HTMLTextAreaElement', 'selectionEnd').get
|
||||
}
|
||||
|
||||
throw new Error('this should never happen, cannot get selectionEnd')
|
||||
}
|
||||
|
||||
const _nativeFocus = function () {
|
||||
@@ -153,6 +184,8 @@ const _setType = function () {
|
||||
if (isButton(this)) {
|
||||
return descriptor('HTMLButtonElement', 'type').set
|
||||
}
|
||||
|
||||
throw new Error('this should never happen, cannot set type')
|
||||
}
|
||||
|
||||
const _getType = function () {
|
||||
@@ -163,6 +196,8 @@ const _getType = function () {
|
||||
if (isButton(this)) {
|
||||
return descriptor('HTMLButtonElement', 'type').get
|
||||
}
|
||||
|
||||
throw new Error('this should never happen, cannot get type')
|
||||
}
|
||||
|
||||
const nativeGetters = {
|
||||
@@ -174,7 +209,7 @@ const nativeGetters = {
|
||||
type: _getType,
|
||||
activeElement: descriptor('Document', 'activeElement').get,
|
||||
body: descriptor('Document', 'body').get,
|
||||
frameElement: Object.getOwnPropertyDescriptor(window, 'frameElement').get,
|
||||
frameElement: Object.getOwnPropertyDescriptor(window, 'frameElement')!.get,
|
||||
}
|
||||
|
||||
const nativeSetters = {
|
||||
@@ -199,9 +234,9 @@ const nativeMethods = {
|
||||
select: _nativeSelect,
|
||||
}
|
||||
|
||||
const tryCallNativeMethod = (...args) => {
|
||||
const tryCallNativeMethod = (obj, fn, ...args) => {
|
||||
try {
|
||||
return callNativeMethod(...args)
|
||||
return callNativeMethod(obj, fn, ...args)
|
||||
} catch (err) {
|
||||
return
|
||||
}
|
||||
@@ -224,9 +259,8 @@ const callNativeMethod = function (obj, fn, ...args) {
|
||||
|
||||
return retFn
|
||||
}
|
||||
|
||||
const getNativeProp = function (obj, prop) {
|
||||
const nativeProp = nativeGetters[prop]
|
||||
const getNativeProp = function<T, K extends keyof T> (obj: T, prop: K): T[K] {
|
||||
const nativeProp = nativeGetters[prop as string]
|
||||
|
||||
if (!nativeProp) {
|
||||
const props = _.keys(nativeGetters).join(', ')
|
||||
@@ -245,8 +279,8 @@ const getNativeProp = function (obj, prop) {
|
||||
return retProp
|
||||
}
|
||||
|
||||
const setNativeProp = function (obj, prop, val) {
|
||||
const nativeProp = nativeSetters[prop]
|
||||
const setNativeProp = function<T, K extends keyof T> (obj: T, prop: K, val) {
|
||||
const nativeProp = nativeSetters[prop as string]
|
||||
|
||||
if (!nativeProp) {
|
||||
const fns = _.keys(nativeSetters).join(', ')
|
||||
@@ -263,7 +297,11 @@ const setNativeProp = function (obj, prop, val) {
|
||||
return retProp
|
||||
}
|
||||
|
||||
const isNeedSingleValueChangeInputElement = (el) => {
|
||||
export interface HTMLSingleValueChangeInputElement extends HTMLInputElement {
|
||||
type: 'date' | 'time' | 'week' | 'month'
|
||||
}
|
||||
|
||||
const isNeedSingleValueChangeInputElement = (el: HTMLElement): el is HTMLSingleValueChangeInputElement => {
|
||||
if (!isInput(el)) {
|
||||
return false
|
||||
}
|
||||
@@ -271,7 +309,8 @@ const isNeedSingleValueChangeInputElement = (el) => {
|
||||
return inputTypeNeedSingleValueChangeRe.test(el.type)
|
||||
}
|
||||
|
||||
const canSetSelectionRangeElement = (el) => {
|
||||
const canSetSelectionRangeElement = (el): el is HTMLElementCanSetSelectionRange => {
|
||||
//TODO: If IE, all inputs can set selection range
|
||||
return isTextarea(el) || (isInput(el) && canSetSelectionRangeElementRe.test(getNativeProp(el, 'type')))
|
||||
}
|
||||
|
||||
@@ -285,23 +324,23 @@ const getTagName = (el) => {
|
||||
// should be true for elements:
|
||||
// - with [contenteditable]
|
||||
// - with document.designMode = 'on'
|
||||
const isContentEditable = (el) => {
|
||||
const isContentEditable = (el: any): el is HTMLContentEditableElement => {
|
||||
return getNativeProp(el, 'isContentEditable')
|
||||
}
|
||||
|
||||
const isTextarea = (el) => {
|
||||
const isTextarea = (el): el is HTMLTextAreaElement => {
|
||||
return getTagName(el) === 'textarea'
|
||||
}
|
||||
|
||||
const isInput = (el) => {
|
||||
const isInput = (el): el is HTMLInputElement => {
|
||||
return getTagName(el) === 'input'
|
||||
}
|
||||
|
||||
const isButton = (el) => {
|
||||
const isButton = (el): el is HTMLButtonElement => {
|
||||
return getTagName(el) === 'button'
|
||||
}
|
||||
|
||||
const isSelect = (el) => {
|
||||
const isSelect = (el): el is HTMLSelectElement => {
|
||||
return getTagName(el) === 'select'
|
||||
}
|
||||
|
||||
@@ -313,7 +352,7 @@ const isOptgroup = (el) => {
|
||||
return getTagName(el) === 'optgroup'
|
||||
}
|
||||
|
||||
const isBody = (el) => {
|
||||
const isBody = (el): el is HTMLBodyElement => {
|
||||
return getTagName(el) === 'body'
|
||||
}
|
||||
|
||||
@@ -325,7 +364,7 @@ const isHTML = (el) => {
|
||||
return getTagName(el) === 'html'
|
||||
}
|
||||
|
||||
const isSvg = function (el) {
|
||||
const isSvg = function (el): el is SVGElement {
|
||||
try {
|
||||
return 'ownerSVGElement' in el
|
||||
} catch (error) {
|
||||
@@ -336,7 +375,7 @@ const isSvg = function (el) {
|
||||
// active element is the default if its null
|
||||
// or its equal to document.body
|
||||
const activeElementIsDefault = (activeElement, body) => {
|
||||
return (!activeElement) || (activeElement === body)
|
||||
return !activeElement || activeElement === body
|
||||
}
|
||||
|
||||
const isFocused = (el) => {
|
||||
@@ -375,9 +414,11 @@ const isFocusedOrInFocused = (el) => {
|
||||
if (elToCheckCurrentlyFocused && elToCheckCurrentlyFocused === activeElement) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const isElement = function (obj) {
|
||||
const isElement = function (obj): obj is HTMLElement | JQuery<HTMLElement> {
|
||||
try {
|
||||
if ($jquery.isJquery(obj)) {
|
||||
obj = obj[0]
|
||||
@@ -389,10 +430,24 @@ const isElement = function (obj) {
|
||||
}
|
||||
}
|
||||
|
||||
const isFocusable = ($el) => {
|
||||
return _.some(focusable, (sel) => {
|
||||
return $el.is(sel)
|
||||
})
|
||||
/**
|
||||
* The element can be activeElement, receive focus events, and also receive keyboard events
|
||||
*/
|
||||
const isFocusable = ($el: JQuery<Element>) => {
|
||||
// matches a focusable selector
|
||||
if (_.some(focusableSelectors, (sel) => $el.is(sel))) {
|
||||
return true
|
||||
}
|
||||
|
||||
// when document.designMode === 'on' (indicated by truthy isContentEditable)
|
||||
// the documentElement will be focusable
|
||||
if (
|
||||
(isElement($el[0]) && getTagName($el[0]) === 'html' && isContentEditable($el[0]))
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const isW3CRendered = (el) => {
|
||||
@@ -405,8 +460,15 @@ const isW3CFocusable = (el) => {
|
||||
return isFocusable(wrap(el)) && isW3CRendered(el)
|
||||
}
|
||||
|
||||
const isType = function ($el, type) {
|
||||
const el = [].concat($jquery.unwrap($el))[0]
|
||||
type JQueryOrEl<T extends HTMLElement> = JQuery<T> | T
|
||||
|
||||
const isType = function (el: JQueryOrEl<HTMLElement>, type) {
|
||||
el = ([] as HTMLElement[]).concat($jquery.unwrap(el))[0]
|
||||
|
||||
if (!isInput(el) && !isButton(el)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// NOTE: use DOMElement.type instead of getAttribute('type') since
|
||||
// <input type="asdf"> will have type="text", and behaves like text type
|
||||
const elType = (getNativeProp(el, 'type') || '').toLowerCase()
|
||||
@@ -419,7 +481,7 @@ const isType = function ($el, type) {
|
||||
}
|
||||
|
||||
const isScrollOrAuto = (prop) => {
|
||||
return (prop === 'scroll') || (prop === 'auto')
|
||||
return prop === 'scroll' || prop === 'auto'
|
||||
}
|
||||
|
||||
const isAncestor = ($el, $maybeAncestor) => {
|
||||
@@ -443,7 +505,7 @@ const getFirstCommonAncestor = (el1, el2) => {
|
||||
|
||||
const getAllParents = (el) => {
|
||||
let curEl = el.parentNode
|
||||
const allParents = []
|
||||
const allParents: any[] = []
|
||||
|
||||
while (curEl) {
|
||||
allParents.push(curEl)
|
||||
@@ -457,7 +519,7 @@ const isChild = ($el, $maybeChild) => {
|
||||
return $el.children().index($maybeChild) >= 0
|
||||
}
|
||||
|
||||
const isSelector = ($el, selector) => {
|
||||
const isSelector = ($el: JQuery<HTMLElement>, selector) => {
|
||||
return $el.is(selector)
|
||||
}
|
||||
|
||||
@@ -498,7 +560,7 @@ const isAttached = function ($el) {
|
||||
// is technically bound to a differnet document
|
||||
// but c'mon
|
||||
const isIn = (el) => {
|
||||
return $.contains(doc, el)
|
||||
return $.contains((doc as unknown) as Element, el)
|
||||
}
|
||||
|
||||
// make sure the document is currently
|
||||
@@ -529,15 +591,53 @@ const isSame = function ($el1, $el2) {
|
||||
return el1 && el2 && _.isEqual(el1, el2)
|
||||
}
|
||||
|
||||
const isTextLike = function ($el) {
|
||||
export interface HTMLContentEditableElement extends HTMLElement {
|
||||
isContenteditable: true
|
||||
}
|
||||
|
||||
export interface HTMLTextLikeInputElement extends HTMLInputElement {
|
||||
type:
|
||||
| 'text'
|
||||
| 'password'
|
||||
| 'email'
|
||||
| 'number'
|
||||
| 'date'
|
||||
| 'week'
|
||||
| 'month'
|
||||
| 'time'
|
||||
| 'datetime'
|
||||
| 'datetime-local'
|
||||
| 'search'
|
||||
| 'url'
|
||||
| 'tel'
|
||||
setSelectionRange: HTMLInputElement['setSelectionRange']
|
||||
}
|
||||
|
||||
export interface HTMLElementCanSetSelectionRange extends HTMLElement {
|
||||
setSelectionRange: HTMLInputElement['setSelectionRange']
|
||||
value: HTMLInputElement['value']
|
||||
selectionStart: number
|
||||
selectionEnd: number
|
||||
}
|
||||
|
||||
export type HTMLTextLikeElement = HTMLTextAreaElement | HTMLTextLikeInputElement | HTMLContentEditableElement
|
||||
|
||||
const isTextLike = function (el: HTMLElement): el is HTMLTextLikeElement {
|
||||
const $el = $jquery.wrap(el)
|
||||
const sel = (selector) => {
|
||||
return isSelector($el, selector)
|
||||
}
|
||||
const type = (type) => {
|
||||
return isType($el, type)
|
||||
if (isInput(el)) {
|
||||
return isType(el, type)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const isContentEditableElement = isContentEditable($el.get(0))
|
||||
const isContentEditableElement = isContentEditable(el)
|
||||
|
||||
if (isContentEditableElement) return true
|
||||
|
||||
return _.some([
|
||||
isContentEditableElement,
|
||||
@@ -636,7 +736,7 @@ const isDescendent = ($el1, $el2) => {
|
||||
return false
|
||||
}
|
||||
|
||||
return !!(($el1.get(0) === $el2.get(0)) || $el1.has($el2).length)
|
||||
return !!($el1.get(0) === $el2.get(0) || $el1.has($el2).length)
|
||||
}
|
||||
|
||||
const findParent = (el, fn) => {
|
||||
@@ -664,7 +764,7 @@ const findParent = (el, fn) => {
|
||||
// 2. check to figure out the element listed at those coordinates
|
||||
// 3. if this element is ourself or our descendants, click whatever was returned
|
||||
// 4. else throw an error because something is covering us up
|
||||
const getFirstFocusableEl = ($el) => {
|
||||
const getFirstFocusableEl = ($el: JQuery<HTMLElement>) => {
|
||||
if (isFocusable($el)) {
|
||||
return $el
|
||||
}
|
||||
@@ -856,8 +956,15 @@ const stringify = (el, form = 'long') => {
|
||||
const $el = $jquery.wrap(el)
|
||||
|
||||
const long = () => {
|
||||
const str = $el.clone().empty().prop('outerHTML')
|
||||
const text = _.chain($el.text()).clean().truncate({ length: 10 }).value()
|
||||
const str = $el
|
||||
.clone()
|
||||
.empty()
|
||||
.prop('outerHTML')
|
||||
|
||||
const text = (_.chain($el.text()) as any)
|
||||
.clean()
|
||||
.truncate({ length: 10 })
|
||||
.value()
|
||||
const children = $el.children().length
|
||||
|
||||
if (children) {
|
||||
@@ -903,96 +1010,50 @@ const stringify = (el, form = 'long') => {
|
||||
})
|
||||
}
|
||||
|
||||
// We extend `module.exports` to allow circular dependencies using `require`
|
||||
// Otherwise we would not be able to `require` this util from `./selection`, for example.
|
||||
_.extend(module.exports, {
|
||||
export {
|
||||
isElement,
|
||||
|
||||
isSelector,
|
||||
|
||||
isScrollOrAuto,
|
||||
|
||||
isFocusable,
|
||||
|
||||
isW3CFocusable,
|
||||
|
||||
isAttached,
|
||||
|
||||
isDetached,
|
||||
|
||||
isAttachedEl,
|
||||
|
||||
isDetachedEl,
|
||||
|
||||
isAncestor,
|
||||
|
||||
isChild,
|
||||
|
||||
isScrollable,
|
||||
|
||||
isTextLike,
|
||||
|
||||
isDescendent,
|
||||
|
||||
isContentEditable,
|
||||
|
||||
isSame,
|
||||
|
||||
isOption,
|
||||
|
||||
isOptgroup,
|
||||
|
||||
isBody,
|
||||
|
||||
isHTML,
|
||||
|
||||
isInput,
|
||||
|
||||
isIframe,
|
||||
|
||||
isTextarea,
|
||||
|
||||
isType,
|
||||
|
||||
isFocused,
|
||||
|
||||
isFocusedOrInFocused,
|
||||
|
||||
isInputAllowingImplicitFormSubmission,
|
||||
|
||||
isNeedSingleValueChangeInputElement,
|
||||
|
||||
canSetSelectionRangeElement,
|
||||
|
||||
stringify,
|
||||
|
||||
getNativeProp,
|
||||
|
||||
setNativeProp,
|
||||
|
||||
callNativeMethod,
|
||||
|
||||
tryCallNativeMethod,
|
||||
|
||||
findParent,
|
||||
|
||||
getElements,
|
||||
|
||||
getFirstFocusableEl,
|
||||
|
||||
getActiveElByDocument,
|
||||
|
||||
getContainsSelector,
|
||||
|
||||
getFirstDeepestElement,
|
||||
|
||||
getFirstCommonAncestor,
|
||||
|
||||
getFirstParentWithTagName,
|
||||
|
||||
getFirstFixedOrStickyPositionParent,
|
||||
|
||||
getFirstStickyPositionParent,
|
||||
|
||||
getFirstScrollableParent,
|
||||
})
|
||||
}
|
||||
@@ -11,7 +11,7 @@ const { wrap, unwrap, isJquery, query } = $jquery
|
||||
const { isVisible, isHidden, getReasonIsHidden } = $visibility
|
||||
const { isType, isFocusable, isElement, isScrollable, isFocused, stringify, getElements, getContainsSelector, getFirstDeepestElement, isDetached, isAttached, isTextLike, isSelector, isDescendent, getFirstFixedOrStickyPositionParent, getFirstStickyPositionParent, getFirstScrollableParent } = $elements
|
||||
const { getCoordsByPosition, getElementPositioning, getElementCoordinatesByPosition, getElementAtPointFromViewport, getElementCoordinatesByPositionRelativeToXY } = $coordinates
|
||||
|
||||
const { getHostContenteditable, getSelectionBounds } = require('./selection')
|
||||
const isDom = (obj) => {
|
||||
return isElement(obj) || isWindow(obj) || isDocument(obj)
|
||||
}
|
||||
@@ -23,69 +23,38 @@ const isDom = (obj) => {
|
||||
// can be tucked away behind these interfaces.
|
||||
module.exports = {
|
||||
wrap,
|
||||
|
||||
query,
|
||||
|
||||
unwrap,
|
||||
|
||||
isDom,
|
||||
|
||||
isType,
|
||||
|
||||
isVisible,
|
||||
|
||||
isHidden,
|
||||
|
||||
isFocusable,
|
||||
|
||||
isTextLike,
|
||||
|
||||
isScrollable,
|
||||
|
||||
isFocused,
|
||||
|
||||
isDetached,
|
||||
|
||||
isAttached,
|
||||
|
||||
isSelector,
|
||||
|
||||
isDescendent,
|
||||
|
||||
isElement,
|
||||
|
||||
isDocument,
|
||||
|
||||
isWindow,
|
||||
|
||||
isJquery,
|
||||
|
||||
stringify,
|
||||
|
||||
getElements,
|
||||
|
||||
getContainsSelector,
|
||||
|
||||
getFirstDeepestElement,
|
||||
|
||||
getWindowByElement,
|
||||
|
||||
getReasonIsHidden,
|
||||
|
||||
getFirstScrollableParent,
|
||||
|
||||
getFirstFixedOrStickyPositionParent,
|
||||
|
||||
getFirstStickyPositionParent,
|
||||
|
||||
getCoordsByPosition,
|
||||
|
||||
getElementPositioning,
|
||||
|
||||
getElementAtPointFromViewport,
|
||||
|
||||
getElementCoordinatesByPosition,
|
||||
|
||||
getElementCoordinatesByPositionRelativeToXY,
|
||||
|
||||
getHostContenteditable,
|
||||
getSelectionBounds,
|
||||
}
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const $document = require('./document')
|
||||
const $elements = require('./elements')
|
||||
import * as $document from './document'
|
||||
import * as $elements from './elements'
|
||||
|
||||
const INTERNAL_STATE = '__Cypress_state__'
|
||||
|
||||
@@ -222,6 +214,8 @@ const deleteRightOfCursor = function (el) {
|
||||
//# successful delete
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const deleteLeftOfCursor = function (el) {
|
||||
@@ -257,6 +251,8 @@ const deleteLeftOfCursor = function (el) {
|
||||
//# successful delete
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const _collapseInputOrTextArea = (el, toIndex) => {
|
||||
@@ -587,7 +583,7 @@ const interceptSelect = function () {
|
||||
// el = el.firstChild
|
||||
// return el
|
||||
|
||||
module.exports = {
|
||||
export {
|
||||
getSelectionBounds,
|
||||
deleteRightOfCursor,
|
||||
deleteLeftOfCursor,
|
||||
@@ -1,7 +1,6 @@
|
||||
const $ = Cypress.$.bind(Cypress)
|
||||
const { _ } = Cypress
|
||||
const { Promise } = Cypress
|
||||
const $selection = require('../../../../../src/dom/selection')
|
||||
const { getCommandLogWithText, findReactInstance, withMutableReporterState } = require('../../../support/utils')
|
||||
|
||||
// trim new lines at the end of innerText
|
||||
@@ -3209,7 +3208,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
const hostEl = cy.$$('<div contenteditable><div id="ce-inner1">foo</div></div>').appendTo(cy.$$('body'))
|
||||
|
||||
cy.get('#ce-inner1').then(($el) => {
|
||||
expect($selection.getHostContenteditable($el[0])).to.eq(hostEl[0])
|
||||
expect(Cypress.dom.getHostContenteditable($el[0])).to.eq(hostEl[0])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3217,7 +3216,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
const hostEl = cy.$$('<div contenteditable="true"><div id="ce-inner1">foo</div></div>').appendTo(cy.$$('body'))
|
||||
|
||||
cy.get('#ce-inner1').then(($el) => {
|
||||
expect($selection.getHostContenteditable($el[0])).to.eq(hostEl[0])
|
||||
expect(Cypress.dom.getHostContenteditable($el[0])).to.eq(hostEl[0])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3225,7 +3224,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
const hostEl = cy.$$('<div contenteditable=""><div id="ce-inner1">foo</div></div>').appendTo(cy.$$('body'))
|
||||
|
||||
cy.get('#ce-inner1').then(($el) => {
|
||||
expect($selection.getHostContenteditable($el[0])).to.eq(hostEl[0])
|
||||
expect(Cypress.dom.getHostContenteditable($el[0])).to.eq(hostEl[0])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3233,7 +3232,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
const hostEl = cy.$$('<div contenteditable="foo"><div id="ce-inner1">foo</div></div>').appendTo(cy.$$('body'))
|
||||
|
||||
cy.get('#ce-inner1').then(($el) => {
|
||||
expect($selection.getHostContenteditable($el[0])).to.eq(hostEl[0])
|
||||
expect(Cypress.dom.getHostContenteditable($el[0])).to.eq(hostEl[0])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3241,7 +3240,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
cy.$$('<div contenteditable="false"><div id="ce-inner1">foo</div></div>').appendTo(cy.$$('body'))
|
||||
|
||||
cy.get('#ce-inner1').then(($el) => {
|
||||
expect($selection.getHostContenteditable($el[0])).to.eq($el[0])
|
||||
expect(Cypress.dom.getHostContenteditable($el[0])).to.eq($el[0])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3300,7 +3299,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
cy.get('input:first').invoke('attr', 'maxlength', '5').type('foobar{leftarrow}')
|
||||
|
||||
cy.window().then((win) => {
|
||||
expect($selection.getSelectionBounds(Cypress.$('input:first').get(0)))
|
||||
expect(Cypress.dom.getSelectionBounds(Cypress.$('input:first').get(0)))
|
||||
.to.deep.eq({ start: 4, end: 4 })
|
||||
})
|
||||
})
|
||||
@@ -3309,7 +3308,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
cy.get('input:first').type('foo{rightarrow}{rightarrow}{rightarrow}bar{rightarrow}')
|
||||
|
||||
cy.window().then((win) => {
|
||||
expect($selection.getSelectionBounds(Cypress.$('input:first').get(0)))
|
||||
expect(Cypress.dom.getSelectionBounds(Cypress.$('input:first').get(0)))
|
||||
.to.deep.eq({ start: 6, end: 6 })
|
||||
})
|
||||
})
|
||||
@@ -3318,7 +3317,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
cy.get('input:first').type(`oo{leftarrow}{leftarrow}{leftarrow}f${'{leftarrow}'.repeat(5)}`)
|
||||
|
||||
cy.window().then((win) => {
|
||||
expect($selection.getSelectionBounds(Cypress.$('input:first').get(0)))
|
||||
expect(Cypress.dom.getSelectionBounds(Cypress.$('input:first').get(0)))
|
||||
.to.deep.eq({ start: 0, end: 0 })
|
||||
})
|
||||
})
|
||||
@@ -3327,7 +3326,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
cy.get('[contenteditable]:first').type('foobar')
|
||||
|
||||
cy.window().then((win) => {
|
||||
expect($selection.getSelectionBounds(Cypress.$('[contenteditable]:first').get(0)))
|
||||
expect(Cypress.dom.getSelectionBounds(Cypress.$('[contenteditable]:first').get(0)))
|
||||
.to.deep.eq({ start: 6, end: 6 })
|
||||
})
|
||||
})
|
||||
@@ -3340,7 +3339,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
cy.get('[contenteditable]:first').type('bar')
|
||||
|
||||
cy.window().then((win) => {
|
||||
expect($selection.getSelectionBounds(Cypress.$('[contenteditable]:first').get(0)))
|
||||
expect(Cypress.dom.getSelectionBounds(Cypress.$('[contenteditable]:first').get(0)))
|
||||
.to.deep.eq({ start: 6, end: 6 })
|
||||
})
|
||||
})
|
||||
@@ -3349,7 +3348,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
cy.get('[contenteditable]:first').type('foo{leftarrow}{leftarrow}')
|
||||
|
||||
cy.window().then((win) => {
|
||||
expect($selection.getSelectionBounds(Cypress.$('[contenteditable]:first').get(0)))
|
||||
expect(Cypress.dom.getSelectionBounds(Cypress.$('[contenteditable]:first').get(0)))
|
||||
.to.deep.eq({ start: 1, end: 1 })
|
||||
})
|
||||
})
|
||||
@@ -3364,7 +3363,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
cy.get(':text:first').type('foobar')
|
||||
|
||||
cy.window().then((win) => {
|
||||
expect($selection.getSelectionBounds(Cypress.$(':text:first').get(0)))
|
||||
expect(Cypress.dom.getSelectionBounds(Cypress.$(':text:first').get(0)))
|
||||
.to.deep.eq({ start: 6, end: 6 })
|
||||
})
|
||||
})
|
||||
@@ -3373,7 +3372,7 @@ describe('src/cy/commands/actions/type', () => {
|
||||
cy.get('#comments').type('foobar')
|
||||
|
||||
cy.window().then((win) => {
|
||||
expect($selection.getSelectionBounds(Cypress.$('#comments').get(0)))
|
||||
expect(Cypress.dom.getSelectionBounds(Cypress.$('#comments').get(0)))
|
||||
.to.deep.eq({ start: 6, end: 6 })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -24,9 +24,9 @@ describe "src/cy/commands/connectors", ->
|
||||
|
||||
it "spreads a jQuery wrapper into individual arguments", ->
|
||||
cy.noop($("div")).spread (first, second) ->
|
||||
expect(first.tagName).to.eq('DIV');
|
||||
expect(first.tagName).to.eq('DIV')
|
||||
expect(first.innerText).to.eq("div")
|
||||
expect(second.tagName).to.eq('DIV');
|
||||
expect(second.tagName).to.eq('DIV')
|
||||
expect(second.innerText).to.contain("Nested Find")
|
||||
|
||||
it "passes timeout option to spread", ->
|
||||
@@ -480,8 +480,8 @@ describe "src/cy/commands/connectors", ->
|
||||
memo + num
|
||||
, 0
|
||||
math: {
|
||||
sum: =>
|
||||
@obj.sum.apply(@obj, arguments)
|
||||
sum: (args...) =>
|
||||
@obj.sum.apply(@obj, args)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1222,7 +1222,7 @@ describe "src/cy/commands/connectors", ->
|
||||
it "awaits promises returned", ->
|
||||
count = 0
|
||||
|
||||
start = new Date
|
||||
start = new Date()
|
||||
|
||||
cy.get("#list li").each ($li, i, arr) ->
|
||||
new Promise (resolve, reject) ->
|
||||
@@ -1232,7 +1232,7 @@ describe "src/cy/commands/connectors", ->
|
||||
, 20
|
||||
.then ($lis) ->
|
||||
expect(count).to.eq(3)
|
||||
expect(new Date - start).to.be.gt(60)
|
||||
expect(new Date() - start).to.be.gt(60)
|
||||
|
||||
it "supports array like structures", ->
|
||||
count = 0
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
// only required to read in webpack config, since it is .ts
|
||||
require('@packages/ts/register')
|
||||
|
||||
const _ = require('lodash')
|
||||
const path = require('path')
|
||||
const fs = require('fs-extra')
|
||||
const Promise = require('bluebird')
|
||||
const webpack = require('@cypress/webpack-preprocessor')
|
||||
|
||||
const webpackOptions = require('@packages/runner/webpack.config.ts').default
|
||||
|
||||
module.exports = (on) => {
|
||||
on('file:preprocessor', webpack({ webpackOptions }))
|
||||
|
||||
on('task', {
|
||||
'return:arg' (arg) {
|
||||
return arg
|
||||
|
||||
5
packages/driver/ts/import-coffee.d.ts
vendored
Normal file
5
packages/driver/ts/import-coffee.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// allows Typescript to import .coffee files
|
||||
declare module '*.coffee' {
|
||||
const content: any
|
||||
export default content
|
||||
}
|
||||
23
packages/driver/tsconfig.json
Normal file
23
packages/driver/tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": false,
|
||||
"noImplicitThis": false,
|
||||
"strictFunctionTypes": true,
|
||||
"preserveWatchOutput": true,
|
||||
"sourceMap": true,
|
||||
"importHelpers": true,
|
||||
"strictNullChecks": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"noImplicitReturns": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"outDir": "dist",
|
||||
"esModuleInterop": true,
|
||||
"noErrorTruncation": true
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ describe('browser detection', () => {
|
||||
// using DEBUG=... flag
|
||||
const checkBrowsers = (browsers) => {
|
||||
log('detected browsers %j', browsers)
|
||||
expect(browsers).to.be.an.array
|
||||
expect(browsers).to.be.an('array')
|
||||
|
||||
const mainProps = project(['name', 'version'], browsers)
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ const api = require('../..')
|
||||
|
||||
describe('launcher', function () {
|
||||
it('has all needed methods', function () {
|
||||
expect(api.launch).to.be.a.function
|
||||
expect(api.detect).to.be.a.function
|
||||
expect(api.detectByPath).to.be.a.function
|
||||
expect(api.launch).to.be.a('function')
|
||||
expect(api.detect).to.be.a('function')
|
||||
expect(api.detectByPath).to.be.a('function')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "tslint-config-standard",
|
||||
"rules": {
|
||||
"space-before-function-paren": false
|
||||
}
|
||||
}
|
||||
10
packages/network/index.ts
Normal file
10
packages/network/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
if (process.env.CYPRESS_ENV !== 'production') {
|
||||
require('@packages/ts/register')
|
||||
}
|
||||
|
||||
import agent from './lib/agent'
|
||||
import * as connect from './lib/connect'
|
||||
|
||||
export { agent }
|
||||
|
||||
export { connect }
|
||||
@@ -1,4 +1,4 @@
|
||||
import { $, dom } from '@packages/driver'
|
||||
import { dom } from '@packages/driver'
|
||||
import events from './events'
|
||||
|
||||
class Shortcuts {
|
||||
@@ -12,7 +12,7 @@ class Shortcuts {
|
||||
|
||||
_handleKeyDownEvent (event) {
|
||||
// if typing into an input, textarea, etc, don't trigger any shortcuts
|
||||
if (dom.isTextLike($(event.target))) return
|
||||
if (dom.isTextLike(event.target)) return
|
||||
|
||||
switch (event.key) {
|
||||
case 'r': events.emit('restart')
|
||||
|
||||
@@ -60,7 +60,7 @@ export default class Header extends Component {
|
||||
<p>The <strong>viewport</strong> determines the width and height of your application. By default the viewport will be <strong>{state.defaults.width}px</strong> by <strong>{state.defaults.height}px</strong> unless specified by a <code>cy.viewport</code> command.</p>
|
||||
<p>Additionally you can override the default viewport dimensions by specifying these values in your {configFileFormatted(config.configFile)}.</p>
|
||||
<pre>{/* eslint-disable indent */}
|
||||
{`{
|
||||
{`{
|
||||
"viewportWidth": ${state.defaults.width},
|
||||
"viewportHeight": ${state.defaults.height}
|
||||
}`}
|
||||
|
||||
5
packages/runner/ts/import-coffee.d.ts
vendored
Normal file
5
packages/runner/ts/import-coffee.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// allows Typescript to import .coffee files
|
||||
declare module '*.coffee' {
|
||||
const content: any
|
||||
export default content
|
||||
}
|
||||
@@ -22,7 +22,7 @@ if (liveReloadEnabled && watchModeEnabled) console.log(chalk.gray(`\nLive Reload
|
||||
|
||||
process.env.NODE_ENV = env
|
||||
|
||||
const config: webpack.Configuration = {
|
||||
const commonConfig: webpack.Configuration = {
|
||||
mode: 'none',
|
||||
node: {
|
||||
fs: 'empty',
|
||||
@@ -191,9 +191,8 @@ const config: webpack.Configuration = {
|
||||
],
|
||||
|
||||
cache: true,
|
||||
|
||||
}
|
||||
|
||||
export default config
|
||||
export default commonConfig
|
||||
|
||||
export { HtmlWebpackPlugin }
|
||||
|
||||
Reference in New Issue
Block a user