Skip to content

Commit e7ee8db

Browse files
committed
refactor and reformat
1 parent 3573535 commit e7ee8db

File tree

3 files changed

+266
-324
lines changed

3 files changed

+266
-324
lines changed

src/index.ts

+127-164
Original file line numberDiff line numberDiff line change
@@ -1,179 +1,142 @@
11
/// <reference types="cypress" />
22

3-
import type { WaitCmdOpts, WaitCmdReturn, GetValueOptions, RafOptions, Primitive } from './types';
3+
import type { WaitCmdOpts, WaitCmdReturn, GetValueOptions, RafOptions, Primitive } from './types'
44

5-
const ERR = '[cypress-wait-frames] - ';
5+
const ERR = '[cypress-wait-frames] - '
66

7-
const unique = Symbol('');
7+
const targetErr = `${ERR} Invalid subject. It must be either 'cy.window' or '() => cy.get('*')'.`
8+
const propsErr = `${ERR} Invalid properties. It must be a string or an array of strings.`
89

910
function waitFrames<T>({
10-
subject: getSubject,
11-
property,
12-
frames = 20,
13-
timeout = 30 * 1000,
11+
subject: cyGet,
12+
property,
13+
frames = 20,
14+
timeout = 30 * 1000,
1415
}: WaitCmdOpts<T>) {
15-
getSubject().then((subject) => {
16-
cy.window().then({ timeout }, (cyWin) => {
17-
const isWin = 'Cypress' in (subject as Cypress.AUTWindow);
18-
const isDoc = 'documentElement' in (subject as Document);
19-
const isEl = !isDoc && 'tagName' in (subject as HTMLElement);
20-
const isWrappedEl =
21-
!isEl &&
22-
isPlainObject(subject) &&
23-
(subject as JQuery<HTMLElement>).length === 1 &&
24-
'tagName' in (subject as JQuery<HTMLElement>)['0'];
25-
26-
if (!isWin && !isDoc && !isEl && !isWrappedEl) {
27-
throw new Error(
28-
`${ERR} Invalid subject. It must be either 'cy.window', 'cy.document' or '() => cy.get()'.`
29-
);
30-
}
31-
32-
if (!Array.isArray(property) && typeof property !== 'string') {
33-
throw new Error(
34-
`${ERR} Invalid properties. It must be a string or an array of strings.`
35-
);
36-
}
37-
38-
if (typeof property === 'string') {
39-
property = [property];
40-
}
41-
42-
return Cypress.Promise.all(
43-
property.map((prop) =>
44-
_waitFrames<T>({
45-
isWin,
46-
isDoc,
47-
cyWin,
48-
target: isWin
49-
? cyWin
50-
: isDoc
51-
? cyWin.document.documentElement
52-
: isEl
53-
? (subject as HTMLElement)
54-
: (subject as JQuery<HTMLElement>)['0'],
55-
prop,
56-
frames,
57-
})
58-
)
59-
)
60-
.then((results) => results)
61-
.catch((error) => {
62-
throw error;
63-
});
64-
});
65-
});
16+
cyGet().then((subject) => {
17+
cy.window().then({ timeout }, async (cyWin) => {
18+
let target = cyWin as Cypress.AUTWindow | HTMLElement | SVGElement
19+
20+
const isWin = Cypress.dom.isWindow(subject)
21+
22+
if (!isWin) {
23+
const isJquery = Cypress.dom.isJquery(subject)
24+
if (!isJquery) {throw new Error(targetErr)}
25+
26+
target = (subject as JQuery<HTMLElement | SVGElement>)['0']
27+
}
28+
29+
if (!target) {throw new Error(targetErr)}
30+
if (!Array.isArray(property) && typeof property !== 'string') {throw new Error(propsErr)}
31+
32+
if (typeof property === 'string') {property = [property]}
33+
34+
return await Cypress.Promise.all(
35+
property.map((prop) =>
36+
_waitFrames<T>({
37+
isWin,
38+
cyWin,
39+
target,
40+
prop,
41+
frames,
42+
})
43+
)
44+
)
45+
})
46+
})
6647
}
6748

68-
function isPlainObject(obj: unknown) {
69-
return !Array.isArray(obj) && typeof obj === 'object' && obj !== null;
70-
}
71-
72-
function isPrimitive(value: unknown) {
73-
return value === null || (typeof value !== 'object' && typeof value !== 'function');
74-
}
49+
const isPrimitive = (value: unknown) => value === null || typeof value !== 'object'
7550

7651
function getValue<T>({ isWin, cyWin, target, prop }: GetValueOptions<T>): Primitive {
77-
if ((prop as string).includes('.')) {
78-
let objValue: symbol | Primitive = unique;
79-
80-
const [objOrMethod, _prop] = (prop as string).split('.');
81-
82-
if (typeof target[objOrMethod as keyof typeof target] === 'function') {
83-
objValue = (
84-
(target as HTMLElement)[objOrMethod as keyof HTMLElement] as CallableFunction
85-
)?.()?.[_prop];
86-
}
87-
88-
if (typeof target[objOrMethod as keyof typeof target] === 'object') {
89-
objValue = (
90-
(target as HTMLElement)[objOrMethod as keyof HTMLElement] as Record<
91-
string,
92-
Primitive
93-
>
94-
)?.[_prop];
95-
}
96-
97-
if (objValue !== unique && isPrimitive(objValue)) {
98-
return objValue as Primitive;
99-
}
100-
101-
throw new Error(
102-
`${ERR} Invalid or unsupported ${isWin ? 'window' : ''} property: ${prop as string}`
103-
);
104-
}
105-
106-
if (prop in target && isPrimitive(target[prop as keyof typeof target])) {
107-
return target[prop as keyof typeof target] as Primitive;
108-
}
109-
110-
if (isWin) {
111-
throw new Error(`${ERR} Invalid window property: ${prop as string}`);
112-
}
113-
114-
function getCSS() {
115-
return cyWin.getComputedStyle(target as HTMLElement).getPropertyValue(prop as string);
116-
}
117-
118-
if ((prop as string).startsWith('--')) {
119-
return getCSS();
120-
}
121-
122-
if (!(prop in cyWin.getComputedStyle(target as HTMLElement))) {
123-
throw new Error(`${ERR} Invalid element DOM/CSS property: ${prop as string}`);
124-
}
125-
126-
return getCSS();
52+
const getCSS = () =>
53+
cyWin.getComputedStyle(target as HTMLElement).getPropertyValue(prop as string)
54+
55+
const emptyValue = Symbol('')
56+
57+
if (typeof prop === 'string' && prop.includes('.')) {
58+
let objValue: symbol | Primitive = emptyValue
59+
60+
const [objOrMethod, _prop] = prop.split('.')
61+
62+
if (typeof target[objOrMethod as keyof typeof target] === 'function') {
63+
objValue = (
64+
(target as HTMLElement)[objOrMethod as keyof HTMLElement] as CallableFunction
65+
)?.()?.[_prop]
66+
}
67+
68+
if (typeof target[objOrMethod as keyof typeof target] === 'object') {
69+
objValue = (
70+
(target as HTMLElement)[objOrMethod as keyof HTMLElement] as Record<string, Primitive>
71+
)?.[_prop]
72+
}
73+
74+
if (objValue !== emptyValue) {return objValue as Primitive}
75+
76+
throw new Error(
77+
`${ERR} Invalid or unsupported ${isWin ? 'window' : ''} property: ${prop as string}`
78+
)
79+
}
80+
81+
if (prop in target && isPrimitive(target[prop as keyof typeof target])) {
82+
return target[prop as keyof typeof target] as Primitive
83+
}
84+
85+
if (isWin) {throw new Error(`${ERR} Invalid window property: ${prop as string}`)}
86+
87+
if (typeof prop === 'string' && prop.startsWith('--')) {return getCSS()}
88+
89+
if (!(prop in cyWin.getComputedStyle(target as HTMLElement))) {
90+
throw new Error(`${ERR} Invalid element DOM/CSS property: ${prop as string}`)
91+
}
92+
93+
return getCSS()
12794
}
12895

129-
function _waitFrames<T>({ isWin, isDoc, cyWin, target, prop, frames }: RafOptions<T>) {
130-
return new Cypress.Promise<WaitCmdReturn<T>>((resolve, reject) => {
131-
const start = cyWin.performance.now();
132-
133-
let rafId: DOMHighResTimeStamp = 0;
134-
let prevValue: number | string | undefined | null = getValue<T>({
135-
isWin,
136-
cyWin,
137-
target,
138-
prop,
139-
});
140-
141-
let framesCount = 0;
142-
143-
function getNextValue() {
144-
try {
145-
framesCount++;
146-
147-
const nextValue = getValue<T>({ isWin, cyWin, target, prop });
148-
149-
if (prevValue !== nextValue) {
150-
framesCount = 0;
151-
prevValue = nextValue;
152-
return cyWin.requestAnimationFrame(getNextValue);
153-
}
154-
155-
if (framesCount === frames) {
156-
cyWin.cancelAnimationFrame(rafId as DOMHighResTimeStamp);
157-
resolve({
158-
subject: (isWin
159-
? cyWin
160-
: isDoc
161-
? cyWin.document
162-
: target) as WaitCmdReturn<T>['subject'],
163-
property: prop,
164-
value: nextValue,
165-
time: cyWin.performance.now() - start,
166-
});
167-
} else {
168-
cyWin.requestAnimationFrame(getNextValue);
169-
}
170-
} catch (error) {
171-
reject(error);
172-
}
173-
}
174-
175-
rafId = cyWin.requestAnimationFrame(getNextValue);
176-
});
96+
function _waitFrames<T>({ isWin, cyWin, target, prop, frames }: RafOptions<T>) {
97+
return new Cypress.Promise<WaitCmdReturn<T>>((resolve, reject) => {
98+
const start = cyWin.performance.now()
99+
100+
let rafId: DOMHighResTimeStamp = 0
101+
let prevValue: number | string | undefined | null = getValue<T>({
102+
isWin,
103+
cyWin,
104+
target,
105+
prop,
106+
})
107+
108+
let framesCount = 0
109+
110+
function getNextValue() {
111+
try {
112+
framesCount++
113+
114+
const nextValue = getValue<T>({ isWin, cyWin, target, prop })
115+
116+
if (prevValue !== nextValue) {
117+
framesCount = 0
118+
prevValue = nextValue
119+
return cyWin.requestAnimationFrame(getNextValue)
120+
}
121+
122+
if (framesCount === frames) {
123+
cyWin.cancelAnimationFrame(rafId as DOMHighResTimeStamp)
124+
resolve({
125+
subject: target as WaitCmdReturn<T>['subject'],
126+
property: prop,
127+
value: nextValue,
128+
time: cyWin.performance.now() - start,
129+
})
130+
} else {
131+
cyWin.requestAnimationFrame(getNextValue)
132+
}
133+
} catch (error) {
134+
reject(error)
135+
}
136+
}
137+
138+
rafId = cyWin.requestAnimationFrame(getNextValue)
139+
})
177140
}
178141

179-
Cypress.Commands.add('waitFrames', waitFrames);
142+
Cypress.Commands.add('waitFrames', waitFrames)

0 commit comments

Comments
 (0)