How to use addCustomMethodsMethod method in Testcafe

Best JavaScript code snippet using testcafe

Run Testcafe automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

add-api.js

Source: add-api.js Github

copy
1import { assign } from 'lodash';
2import clientFunctionBuilderSymbol from '../builder-symbol';
3import { ELEMENT_SNAPSHOT_PROPERTIES, NODE_SNAPSHOT_PROPERTIES } from './snapshot-properties';
4import { CantObtainInfoForElementSpecifiedBySelectorError } from '../../errors/test-run';
5import { getCallsiteForMethod } from '../../errors/get-callsite';
6import ClientFunctionBuilder from '../client-function-builder';
7import ClientFunctionResultPromise from '../result-promise';
8import { assertType, is } from '../../errors/runtime/type-assertions';
9import makeRegExp from '../../utils/make-reg-exp';
10import selectorTextFilter from './selector-text-filter';
11import selectorAttributeFilter from './selector-attribute-filter';
12
13const SNAPSHOT_PROPERTIES = NODE_SNAPSHOT_PROPERTIES.concat(ELEMENT_SNAPSHOT_PROPERTIES);
14
15
16var filterNodes = (new ClientFunctionBuilder((nodes, filter, querySelectorRoot, originNode, ...filterArgs) => {
17    if (typeof filter === 'number') {
18        var matchingNode = filter < 0 ? nodes[nodes.length + filter] : nodes[filter];
19
20        return matchingNode ? [matchingNode] : [];
21    }
22
23    var result = [];
24
25    if (typeof filter === 'string') {
26        // NOTE: we can search for elements only in document or element.
27        if (querySelectorRoot.nodeType !== 1 && querySelectorRoot.nodeType !== 9)
28            return null;
29
30        var matching    = querySelectorRoot.querySelectorAll(filter);
31        var matchingArr = [];
32
33        for (var i = 0; i < matching.length; i++)
34            matchingArr.push(matching[i]);
35
36        filter = node => matchingArr.indexOf(node) > -1;
37    }
38
39    if (typeof filter === 'function') {
40        for (var j = 0; j < nodes.length; j++) {
41            if (filter(nodes[j], j, originNode, ...filterArgs))
42                result.push(nodes[j]);
43        }
44    }
45
46    return result;
47})).getFunction();
48
49var expandSelectorResults = (new ClientFunctionBuilder((selector, populateDerivativeNodes) => {
50    var nodes = selector();
51
52    if (!nodes.length)
53        return null;
54
55    var result = [];
56
57    for (var i = 0; i < nodes.length; i++) {
58        var derivativeNodes = populateDerivativeNodes(nodes[i]);
59
60        if (derivativeNodes) {
61            for (var j = 0; j < derivativeNodes.length; j++) {
62                if (result.indexOf(derivativeNodes[j]) < 0)
63                    result.push(derivativeNodes[j]);
64            }
65        }
66    }
67
68    return result;
69
70})).getFunction();
71
72async function getSnapshot (getSelector, callsite) {
73    var node     = null;
74    var selector = getSelector();
75
76    try {
77        node = await selector();
78    }
79
80    catch (err) {
81        err.callsite = callsite;
82        throw err;
83    }
84
85    if (!node)
86        throw new CantObtainInfoForElementSpecifiedBySelectorError(callsite);
87
88    return node;
89}
90
91function assertAddCustomDOMPropertiesOptions (properties) {
92    assertType(is.nonNullObject, 'addCustomDOMProperties', '"addCustomDOMProperties" option', properties);
93
94    Object.keys(properties).forEach(prop => {
95        assertType(is.function, 'addCustomDOMProperties', `Custom DOM properties method '${prop}'`, properties[prop]);
96    });
97}
98
99function assertAddCustomMethods (properties) {
100    assertType(is.nonNullObject, 'addCustomMethods', '"addCustomMethods" option', properties);
101
102    Object.keys(properties).forEach(prop => {
103        assertType(is.function, 'addCustomMethods', `Custom method '${prop}'`, properties[prop]);
104    });
105}
106
107function addSnapshotProperties (obj, getSelector, properties) {
108    properties.forEach(prop => {
109        Object.defineProperty(obj, prop, {
110            get: () => {
111                var callsite = getCallsiteForMethod('get');
112
113                return ClientFunctionResultPromise.fromFn(async () => {
114                    var snapshot = await getSnapshot(getSelector, callsite);
115
116                    return snapshot[prop];
117                });
118            }
119        });
120    });
121}
122
123export function addCustomMethods (obj, getSelector, customMethods) {
124    var customMethodProps = customMethods ? Object.keys(customMethods) : [];
125
126    customMethodProps.forEach(prop => {
127        var dependencies = {
128            customMethod: customMethods[prop],
129            selector:     getSelector()
130        };
131
132        var callsiteNames = { instantiation: prop };
133
134        obj[prop] = (new ClientFunctionBuilder((...args) => {
135            /* eslint-disable no-undef */
136            var node = selector();
137
138            return customMethod.apply(customMethod, [node].concat(args));
139            /* eslint-enable no-undef */
140        }, { dependencies }, callsiteNames)).getFunction();
141    });
142}
143
144function addSnapshotPropertyShorthands (obj, getSelector, customDOMProperties, customMethods) {
145    var properties = SNAPSHOT_PROPERTIES;
146
147    if (customDOMProperties)
148        properties = properties.concat(Object.keys(customDOMProperties));
149
150    addSnapshotProperties(obj, getSelector, properties);
151    addCustomMethods(obj, getSelector, customMethods);
152
153    obj.getStyleProperty = prop => {
154        var callsite = getCallsiteForMethod('getStyleProperty');
155
156        return ClientFunctionResultPromise.fromFn(async () => {
157            var snapshot = await getSnapshot(getSelector, callsite);
158
159            return snapshot.style ? snapshot.style[prop] : void 0;
160        });
161    };
162
163    obj.getAttribute = attrName => {
164        var callsite = getCallsiteForMethod('getAttribute');
165
166        return ClientFunctionResultPromise.fromFn(async () => {
167            var snapshot = await getSnapshot(getSelector, callsite);
168
169            return snapshot.attributes ? snapshot.attributes[attrName] : void 0;
170        });
171    };
172
173    obj.hasAttribute = attrName => {
174        var callsite = getCallsiteForMethod('hasAttribute');
175
176        return ClientFunctionResultPromise.fromFn(async () => {
177            var snapshot = await getSnapshot(getSelector, callsite);
178
179            return snapshot.attributes ? snapshot.attributes.hasOwnProperty(attrName) : false;
180        });
181    };
182
183    obj.getBoundingClientRectProperty = prop => {
184        var callsite = getCallsiteForMethod('getBoundingClientRectProperty');
185
186        return ClientFunctionResultPromise.fromFn(async () => {
187            var snapshot = await getSnapshot(getSelector, callsite);
188
189            return snapshot.boundingClientRect ? snapshot.boundingClientRect[prop] : void 0;
190        });
191    };
192
193    obj.hasClass = name => {
194        var callsite = getCallsiteForMethod('hasClass');
195
196        return ClientFunctionResultPromise.fromFn(async () => {
197            var snapshot = await getSnapshot(getSelector, callsite);
198
199            return snapshot.classNames ? snapshot.classNames.indexOf(name) > -1 : false;
200        });
201    };
202}
203
204function createCounter (getSelector, SelectorBuilder) {
205    var builder  = new SelectorBuilder(getSelector(), { counterMode: true }, { instantiation: 'Selector' });
206    var counter  = builder.getFunction();
207    var callsite = getCallsiteForMethod('get');
208
209    return async () => {
210        try {
211            return await counter();
212        }
213
214        catch (err) {
215            err.callsite = callsite;
216            throw err;
217        }
218    };
219}
220
221function addCounterProperties (obj, getSelector, SelectorBuilder) {
222    Object.defineProperty(obj, 'count', {
223        get: () => {
224            var counter = createCounter(getSelector, SelectorBuilder);
225
226            return ClientFunctionResultPromise.fromFn(() => counter());
227        }
228    });
229
230    Object.defineProperty(obj, 'exists', {
231        get: () => {
232            var counter = createCounter(getSelector, SelectorBuilder);
233
234            return ClientFunctionResultPromise.fromFn(async () => await counter() > 0);
235        }
236    });
237}
238
239function convertFilterToClientFunctionIfNecessary (callsiteName, filter, dependencies) {
240    if (typeof filter === 'function') {
241        var builder = filter[clientFunctionBuilderSymbol];
242        var fn      = builder ? builder.fn : filter;
243        var options = builder ? assign({}, builder.options, { dependencies }) : { dependencies };
244
245        return (new ClientFunctionBuilder(fn, options, { instantiation: callsiteName })).getFunction();
246    }
247
248    return filter;
249}
250
251function createDerivativeSelectorWithFilter (getSelector, SelectorBuilder, selectorFn, filter, additionalDependencies) {
252    var collectionModeSelectorBuilder = new SelectorBuilder(getSelector(), { collectionMode: true });
253    var customDOMProperties           = collectionModeSelectorBuilder.options.customDOMProperties;
254    var customMethods                 = collectionModeSelectorBuilder.options.customMethods;
255
256    var dependencies = {
257        selector:    collectionModeSelectorBuilder.getFunction(),
258        filter:      filter,
259        filterNodes: filterNodes
260    };
261
262    var { boundTestRun, timeout, visibilityCheck } = collectionModeSelectorBuilder.options;
263
264    dependencies = assign(dependencies, additionalDependencies);
265
266    var builder = new SelectorBuilder(selectorFn, {
267        dependencies,
268        customDOMProperties,
269        customMethods,
270        boundTestRun,
271        timeout,
272        visibilityCheck
273    }, { instantiation: 'Selector' });
274
275    return builder.getFunction();
276}
277
278var filterByText = convertFilterToClientFunctionIfNecessary('filter', selectorTextFilter);
279var filterByAttr = convertFilterToClientFunctionIfNecessary('filter', selectorAttributeFilter);
280
281function ensureRegExpContext (str) {
282    // NOTE: if a regexp is created in a separate context (via the 'vm' module) we
283    // should wrap it with new RegExp() to make the `instanceof RegExp` check successful.
284    if (typeof str !== 'string' && !(str instanceof RegExp))
285        return new RegExp(str);
286
287    return str;
288}
289
290function addFilterMethods (obj, getSelector, SelectorBuilder) {
291    obj.nth = index => {
292        assertType(is.number, 'nth', '"index" argument', index);
293
294        var builder = new SelectorBuilder(getSelector(), { index: index }, { instantiation: 'Selector' });
295
296        return builder.getFunction();
297    };
298
299    obj.withText = text => {
300        assertType([is.string, is.regExp], 'withText', '"text" argument', text);
301
302        text = ensureRegExpContext(text);
303
304        var selectorFn = () => {
305            /* eslint-disable no-undef */
306            var nodes = selector();
307
308            if (!nodes.length)
309                return null;
310
311            return filterNodes(nodes, filter, document, void 0, textRe);
312            /* eslint-enable no-undef */
313        };
314
315        return createDerivativeSelectorWithFilter(getSelector, SelectorBuilder, selectorFn, filterByText, {
316            textRe: makeRegExp(text)
317        });
318    };
319
320    obj.withExactText = text => {
321        assertType(is.string, 'withExactText', '"text" argument', text);
322
323        var selectorFn = () => {
324            /* eslint-disable no-undef */
325            var nodes = selector();
326
327            if (!nodes.length)
328                return null;
329
330            return filterNodes(nodes, filter, document, void 0, exactText);
331            /* eslint-enable no-undef */
332        };
333
334        return createDerivativeSelectorWithFilter(getSelector, SelectorBuilder, selectorFn, filterByText, {
335            exactText: text
336        });
337    };
338
339    obj.withAttribute = (attrName, attrValue) => {
340        assertType([is.string, is.regExp], 'withAttribute', '"attrName" argument', attrName);
341
342        attrName = ensureRegExpContext(attrName);
343
344        if (attrValue !== void 0) {
345            assertType([is.string, is.regExp], 'withAttribute', '"attrValue" argument', attrValue);
346            attrValue = ensureRegExpContext(attrValue);
347        }
348
349        var selectorFn = () => {
350            /* eslint-disable no-undef */
351            var nodes = selector();
352
353            if (!nodes.length)
354                return null;
355
356            return filterNodes(nodes, filter, document, void 0, attrName, attrValue);
357            /* eslint-enable no-undef */
358        };
359
360        return createDerivativeSelectorWithFilter(getSelector, SelectorBuilder, selectorFn, filterByAttr, {
361            attrName,
362            attrValue
363        });
364    };
365
366    obj.filter = (filter, dependencies) => {
367        assertType([is.string, is.function], 'filter', '"filter" argument', filter);
368
369        filter = convertFilterToClientFunctionIfNecessary('filter', filter, dependencies);
370
371        var selectorFn = () => {
372            /* eslint-disable no-undef */
373            var nodes = selector();
374
375            if (!nodes.length)
376                return null;
377
378            return filterNodes(nodes, filter, document, void 0);
379            /* eslint-enable no-undef */
380        };
381
382        return createDerivativeSelectorWithFilter(getSelector, SelectorBuilder, selectorFn, filter);
383    };
384
385    obj.filterVisible = () => {
386        const builder = new SelectorBuilder(getSelector(), { filterVisible: true }, { instantiation: 'Selector' });
387
388        return builder.getFunction();
389    };
390
391    obj.filterHidden = () => {
392        const builder = new SelectorBuilder(getSelector(), { filterHidden: true }, { instantiation: 'Selector' });
393
394        return builder.getFunction();
395    };
396}
397
398function addCustomDOMPropertiesMethod (obj, getSelector, SelectorBuilder) {
399    obj.addCustomDOMProperties = customDOMProperties => {
400        assertAddCustomDOMPropertiesOptions(customDOMProperties);
401
402        var builder = new SelectorBuilder(getSelector(), { customDOMProperties }, { instantiation: 'Selector' });
403
404        return builder.getFunction();
405    };
406}
407
408function addCustomMethodsMethod (obj, getSelector, SelectorBuilder) {
409    obj.addCustomMethods = customMethods => {
410        assertAddCustomMethods(customMethods);
411
412        var builder = new SelectorBuilder(getSelector(), { customMethods }, { instantiation: 'Selector' });
413
414        return builder.getFunction();
415    };
416}
417
418function addHierarchicalSelectors (obj, getSelector, SelectorBuilder) {
419    // Find
420    obj.find = (filter, dependencies) => {
421        assertType([is.string, is.function], 'find', '"filter" argument', filter);
422
423        filter = convertFilterToClientFunctionIfNecessary('find', filter, dependencies);
424
425        var selectorFn = () => {
426            /* eslint-disable no-undef */
427            return expandSelectorResults(selector, node => {
428                if (typeof filter === 'string') {
429                    return typeof node.querySelectorAll === 'function' ?
430                        node.querySelectorAll(filter) :
431                        null;
432                }
433
434                var results = [];
435
436                var visitNode = currentNode => {
437                    var cnLength = currentNode.childNodes.length;
438
439                    for (var i = 0; i < cnLength; i++) {
440                        var child = currentNode.childNodes[i];
441
442                        results.push(child);
443
444                        visitNode(child);
445                    }
446                };
447
448                visitNode(node);
449
450                return filterNodes(results, filter, null, node);
451            });
452            /* eslint-enable no-undef */
453        };
454
455        return createDerivativeSelectorWithFilter(getSelector, SelectorBuilder, selectorFn, filter, { expandSelectorResults });
456    };
457
458    // Parent
459    obj.parent = (filter, dependencies) => {
460        if (filter !== void 0)
461            assertType([is.string, is.function, is.number], 'parent', '"filter" argument', filter);
462
463        filter = convertFilterToClientFunctionIfNecessary('find', filter, dependencies);
464
465        var selectorFn = () => {
466            /* eslint-disable no-undef */
467            return expandSelectorResults(selector, node => {
468                var parents = [];
469
470                for (var parent = node.parentNode; parent; parent = parent.parentNode)
471                    parents.push(parent);
472
473                return filter !== void 0 ? filterNodes(parents, filter, document, node) : parents;
474            });
475            /* eslint-enable no-undef */
476        };
477
478        return createDerivativeSelectorWithFilter(getSelector, SelectorBuilder, selectorFn, filter, { expandSelectorResults });
479    };
480
481    // Child
482    obj.child = (filter, dependencies) => {
483        if (filter !== void 0)
484            assertType([is.string, is.function, is.number], 'child', '"filter" argument', filter);
485
486        filter = convertFilterToClientFunctionIfNecessary('find', filter, dependencies);
487
488        var selectorFn = () => {
489            /* eslint-disable no-undef */
490            return expandSelectorResults(selector, node => {
491                var childElements = [];
492                var cnLength      = node.childNodes.length;
493
494                for (var i = 0; i < cnLength; i++) {
495                    var child = node.childNodes[i];
496
497                    if (child.nodeType === 1)
498                        childElements.push(child);
499                }
500
501                return filter !== void 0 ? filterNodes(childElements, filter, node, node) : childElements;
502            });
503            /* eslint-enable no-undef */
504        };
505
506        return createDerivativeSelectorWithFilter(getSelector, SelectorBuilder, selectorFn, filter, { expandSelectorResults });
507    };
508
509    // Sibling
510    obj.sibling = (filter, dependencies) => {
511        if (filter !== void 0)
512            assertType([is.string, is.function, is.number], 'sibling', '"filter" argument', filter);
513
514        filter = convertFilterToClientFunctionIfNecessary('find', filter, dependencies);
515
516        var selectorFn = () => {
517            /* eslint-disable no-undef */
518            return expandSelectorResults(selector, node => {
519                var parent = node.parentNode;
520
521                if (!parent)
522                    return null;
523
524                var siblings = [];
525                var cnLength = parent.childNodes.length;
526
527                for (var i = 0; i < cnLength; i++) {
528                    var child = parent.childNodes[i];
529
530                    if (child.nodeType === 1 && child !== node)
531                        siblings.push(child);
532                }
533
534                return filter !== void 0 ? filterNodes(siblings, filter, parent, node) : siblings;
535            });
536            /* eslint-enable no-undef */
537        };
538
539        return createDerivativeSelectorWithFilter(getSelector, SelectorBuilder, selectorFn, filter, { expandSelectorResults });
540    };
541
542    // Next sibling
543    obj.nextSibling = (filter, dependencies) => {
544        if (filter !== void 0)
545            assertType([is.string, is.function, is.number], 'nextSibling', '"filter" argument', filter);
546
547        filter = convertFilterToClientFunctionIfNecessary('find', filter, dependencies);
548
549        var selectorFn = () => {
550            /* eslint-disable no-undef */
551            return expandSelectorResults(selector, node => {
552                var parent = node.parentNode;
553
554                if (!parent)
555                    return null;
556
557                var siblings  = [];
558                var cnLength  = parent.childNodes.length;
559                var afterNode = false;
560
561                for (var i = 0; i < cnLength; i++) {
562                    var child = parent.childNodes[i];
563
564                    if (child === node)
565                        afterNode = true;
566
567                    else if (afterNode && child.nodeType === 1)
568                        siblings.push(child);
569                }
570
571                return filter !== void 0 ? filterNodes(siblings, filter, parent, node) : siblings;
572            });
573            /* eslint-enable no-undef */
574        };
575
576        return createDerivativeSelectorWithFilter(getSelector, SelectorBuilder, selectorFn, filter, { expandSelectorResults });
577    };
578
579    // Prev sibling
580    obj.prevSibling = (filter, dependencies) => {
581        if (filter !== void 0)
582            assertType([is.string, is.function, is.number], 'prevSibling', '"filter" argument', filter);
583
584        filter = convertFilterToClientFunctionIfNecessary('find', filter, dependencies);
585
586        var selectorFn = () => {
587            /* eslint-disable no-undef */
588            return expandSelectorResults(selector, node => {
589                var parent = node.parentNode;
590
591                if (!parent)
592                    return null;
593
594                var siblings = [];
595                var cnLength = parent.childNodes.length;
596
597                for (var i = 0; i < cnLength; i++) {
598                    var child = parent.childNodes[i];
599
600                    if (child === node)
601                        break;
602
603                    if (child.nodeType === 1)
604                        siblings.push(child);
605                }
606
607                return filter !== void 0 ? filterNodes(siblings, filter, parent, node) : siblings;
608            });
609            /* eslint-enable no-undef */
610        };
611
612        return createDerivativeSelectorWithFilter(getSelector, SelectorBuilder, selectorFn, filter, { expandSelectorResults });
613    };
614
615}
616
617export function addAPI (obj, getSelector, SelectorBuilder, customDOMProperties, customMethods) {
618    addSnapshotPropertyShorthands(obj, getSelector, customDOMProperties, customMethods);
619    addCustomDOMPropertiesMethod(obj, getSelector, SelectorBuilder);
620    addCustomMethodsMethod(obj, getSelector, SelectorBuilder);
621    addFilterMethods(obj, getSelector, SelectorBuilder);
622    addHierarchicalSelectors(obj, getSelector, SelectorBuilder);
623    addCounterProperties(obj, getSelector, SelectorBuilder);
624}
625
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Testcafe on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)