How to use getObjectsDifference method in Jest

Best JavaScript code snippet using jest

profireader_angular.js

Source:profireader_angular.js Github

copy

Full Screen

...6 * @param {type} notstrict - compare by == if true (if false/ommted by ===)7 * @returns {Array/Object} with elements different in a and b. also if index is present only in one object (a or b)8 * if returened element is array same object are reffered by 'undefined'9 */10function getObjectsDifference(a, b, setval, notstrict) {11    'use strict';12    if ((typeof a !== 'object') || (typeof b !== 'object')) {13        console.log('getObjectsDifference expects both arguments to be array or object');14        return null;15    }16    var ret = $.isArray(b) ? [] : {};17    $.each(a, function (ind, aobj) {18        if ((typeof aobj === 'object') && (typeof b[ind] === 'object')) {19            if ((aobj === null) && (b[ind] === null)) {20                return;21            }22            var nl = getObjectsDifference(aobj, b[ind], setval, notstrict);23            if (!$.isEmptyObject(nl)) {24                ret[ind] = nl;25            }26        }27        else {28            if ((notstrict && (a[ind] == b[ind])) || (!notstrict && (a[ind] === b[ind]))) {29                return;30            }31            ret[ind] = (setval === undefined) ? aobj : setval;32        }33    });34    $.each(b, function (ind, bobj) {35        if ((typeof bobj === 'object') && (typeof a[ind] === 'object')) {36        }37        else {38            if ((notstrict && (a[ind] == b[ind])) || (!notstrict && (a[ind] === b[ind]))) {39                return;40            }41            ret[ind] = (setval === undefined) ? bobj : setval;42        }43    });44    return ret;45}46function quoteattr(s, preserveCR) {47    preserveCR = preserveCR ? '&#13;' : '\n';48    return ('' + s)/* Forces the conversion to string. */49        .replace(/&/g, '&amp;')/* This MUST be the 1st replacement. */50        .replace(/'/g, '&apos;')/* The 4 other predefined entities, required. */51        .replace(/"/g, '&quot;')52        .replace(/</g, '&lt;')53        .replace(/>/g, '&gt;')54        /*55         You may add other replacements here for HTML only56         (but it's not necessary).57         Or for XML, only if the named entities are defined in its DTD.58         */59        .replace(/\r\n/g, preserveCR)/* Must be before the next replacement. */60        .replace(/[\r\n]/g, preserveCR);61}62function resolveDictForAngularController(dict) {63    return _.object(_.map(dict, function (val, key) {64        return [key, function () {65            return val66        }]67    }))68}69angular.module('profireaderdirectives', ['ui.bootstrap', 'ui.bootstrap.tooltip'])70    .factory('$publish', ['$http', '$uibModal', function ($http, $uibModal) {71        return function (dict) {72            var modalInstance = $uibModal.open({73                templateUrl: 'submit_publish_dialog.html',74                controller: 'submit_publish_dialog',75                resolve: resolveDictForAngularController(dict)76            });77            return modalInstance;78        }79    }])80    .factory('$ok', ['$http', function ($http) {81        return function (url, data, ifok, iferror, translate, disableonsubmid) {82            //console.log($scope);83            function error(result, error_code) {84                if (iferror) {85                    iferror(result, error_code)86                }87                else {88                    // add_message(result, 'danger');89                }90            }91            //TODO MY by OZ: dim disableonsubmid element on submit (by cloning element with coordinates and classes)92            //pass here dialog DOM element from controller wherever $uibModalInstance is used93            return $http.post(url, $.extend({}, data, translate ? {__translate: translate} : {})).then(94                function (resp) {95                    if (!resp || !resp['data'] || typeof resp['data'] !== 'object' || resp === null) {96                        return error('wrong response', -1);97                    }98                    resp = resp ['data'];99                    if (!resp['ok']) {100                        return error(resp['data'], resp['error_code']);101                    }102                    if (ifok) {103                        return ifok(resp['data']);104                    }105                },106                function () {107                    return error('wrong response', -1);108                }109            );110        }111    }])112    .directive('prHelpTooltip', ['$compile', '$templateCache', '$controller', function ($compile, $templateCache, $controller) {113        return {114            restrict: 'E',115            link: function (scope, element, attrs) {116                element.html('<span uib-popover-html="\'' + quoteattr(scope.__('help tooltip ' + element.html())) + '\'" ' +117                    'popover-placement="' + (attrs['placement'] ? attrs['placement'] : 'bottom') + '" ' +118                    'popover-trigger="' + (attrs['trigger'] ? attrs['trigger'] : 'mouseenter') + '" ' +119                    'class="' + (attrs['classes'] ? attrs['classes'] : 'glyphicon glyphicon-question-sign') + '"></span>');120                $compile(element.contents())(scope);121            }122        }123    }])124    .directive('prCrop', ['$compile', '$templateCache', function ($compile, $templateCache) {125        return {126            restrict: 'A',127            require: 'ngModel',128            link: function (scope, element, attrs, model) {129                element.html($templateCache.get('cropper.html'));130                $compile(element.contents())(scope);131                var callback_name = 'pr_cropper_image_selected_in_filemanager_callback_' + scope.controllerName + '_' + randomHash();132                window[callback_name] = function (item) {133                    model.$modelValue.coordinates = {rotate: 0};134                    model.$modelValue.image_file_id = item.id;135                    closeFileManager();136                };137                scope.chooseImage = function (setImage) {138                    if (setImage) {139                        // TODO: OZ by OZ: prCompanyId -> company controller id (take company from company140                        // controller not from element attributes)141                        scope.chooseImageinFileManager("parent." + callback_name, 'choose', '', attrs['prCompanyId']);142                        model.$modelValue.uploaded = false;143                    }144                    else {145                        model.$modelValue.image_file_id = null;146                    }147                };148                var $image = $('img', element);149                var $inputImage = $('input', element);150                var URL = window.URL || window.webkitURL;151                var blobURL;152                var options = {153                    crop: function (e) {154                        if (model.$modelValue) {155                            //e['image_file_id'] = model.$modelValue.image_file_id;156                        }157                        model.$modelValue.coordinates = e;158                    }159                };160                var uploadCropper = function () {161                    var files = this.files;162                    var file;163                    var ff = $('input#inputImage').prop('files')[0];164                    if (files && files.length) {165                        file = files[0];166                        var fr = new FileReader();167                        fr.readAsDataURL(ff);168                        var content = '';169                        fr.onload = function (e) {170                            content = fr.result;171                            if (/^image\/\w+$/.test(file.type)) {172                                $inputImage.val('');173                                blobURL = URL.createObjectURL(file);174                                model.$modelValue.type = file.type;175                                model.$modelValue.name = file.name;176                                model.$modelValue.dataContent = content;177                                model.$modelValue.uploaded = true;178                                model.$modelValue.image_file_id = blobURL;179                            } else {180                                add_message('Please choose an image file.');181                            }182                        };183                    }184                };185                $inputImage.change(uploadCropper);186                var restartCropper = function () {187                    $image.cropper('destroy');188                    if (model.$modelValue.uploaded) {189                        $image.attr('src', model.$modelValue.image_file_id);190                        $image.cropper(options);191                        $image.cropper('replace', model.$modelValue.image_file_id);192                    }193                    else {194                        if (model.$modelValue.image_file_id) {195                            $image.attr('src', fileUrl(model.$modelValue.image_file_id));196                            $image.cropper(options);197                        }198                        else {199                            $image.attr('src', model.$modelValue.no_image_url);200                        }201                    }202                };203                //if (attrs['prCropper']) {204                //    scope[attrs['prCropper']] = function () {205                //        $image.cropper.apply($image, arguments);206                //    };207                //}208                scope['cropper'] = function () {209                    $image.cropper.apply($image, arguments);210                };211                //debugger;212                //213                scope.$watch(attrs['ngModel'] + '.image_file_id', function () {214                    if (model && model.$modelValue) {215                        //var file_url = fileUrl(model.$modelValue.image_file_id);216                        //$image.attr('src', );217                        //$image.cropper('replace', file_url);218                        if (model) {219                            if (model.$modelValue && model.$modelValue.ratio) options.aspectRatio = model.$modelValue.ratio;220                            if (model.$modelValue && model.$modelValue.coordinates) options.data = model.$modelValue.coordinates;221                        }222                        restartCropper();223                        //224                        //if (file_url) {225                        //226                        //}227                        //else {228                        //    console.log('no image');229                        //}230                    }231                });232                //233                //scope.$watch(attrs['ngModel'] + '.ratio', function () {234                //    if (model.$modelValue && model.$modelValue.ratio) {235                //        $image.cropper('setAspectRatio', model.$modelValue.ratio);236                //    }237                //});238                //239                //scope.$watch(attrs['ngModel'] + '.coordinates', function () {240                //    if (model.$modelValue) console.log(model.$modelValue.coordinates);241                //    if (model.$modelValue && model.$modelValue.coordinates) {242                //        options.data = model.$modelValue.coordinates;243                //        restartCropper();244                //        //$image.cropper('setData', model.$modelValue.coordinates);245                //    }246                //});247            }248        };249    }])250    .directive('dateTimestampFormat', function () {251        return {252            require: 'ngModel',253            link: function (scope, element, attr, ngModelCtrl) {254                ngModelCtrl.$formatters.unshift(function (timestamp) {255                    if (timestamp) {256                        var date = new Date(timestamp * 1000);257                        return date;258                    } else259                        return "";260                });261                ngModelCtrl.$parsers.push(function (date) {262                    if (date instanceof Date) {263                        var timestamp = Math.floor(date.getTime() / 1000)264                        return timestamp;265                    } else266                        return "";267                });268            }269        };270    })271    .directive('prDatepicker', function () {272        return {273            replace: false,274            require: 'ngModel',275            restrict: 'A',276            scope: {277                ngModel: '='278            },279            link: function (scope, element, attrs, model) {280                scope.$watch('ngModel', function (nv, ov) {281                    scope.setdate = scope['ngModel'];282                });283                scope.$watch('setdate', function (nv, ov) {284                    if (nv && nv.setHours) nv.setHours(12);285                    scope['ngModel'] = nv;286                });287            },288            template: function (ele, attrs) {289// TODO: MY BY OZ: please uncoment time (comented by ng-if=0 now), move date and time to one line290                return '<span><input style="width: 15em; display: inline" type="date" class="form-control" uib-datepicker-popup\291               ng-model="setdate" ng-required="true"\292               datepicker-options="dateOptions" close-text="Close"/><span class="input-group-btn"></span>\293               </span>';294            }295        }296    })297    .directive('highlighter', ['$timeout', function ($timeout) {298        return {299            restrict: 'A',300            link: function (scope, element, attrs) {301                scope.$watch(attrs.highlighter, function (nv, ov) {302                    if (nv !== ov) {303                        highlight($(element));304                    }305                });306            }307        };308    }])309    .directive('prImage', ['$timeout', function ($timeout) {310        return {311            restrict: 'A',312            scope: {313                prImage: '=',314                prNoImage: '@'315            },316            link: function (scope, element, attrs) {317                var image_reference = attrs['prImage'].split('.').pop();318                var no_image = attrs['prNoImage'] ? attrs['prNoImage'] : false;319                if (!no_image) {320                    no_image = noImageForImageName(image_reference);321                }322                scope.$watch('prImage', function (newval, oldval) {323                    element.css({324                        backgroundImage: "url('" + fileUrl(newval, false, no_image) + "')"325                    });326                });327                element.attr('src', '//static.profireader.com/static/images/0.gif');328                element.css({329                    backgroundPosition: 'center',330                    backgroundSize: 'contain',331                    backgroundRepeat: 'no-repeat'332                });333            }334        };335    }])336    //TODO: SS by OZ: better use actions (prUserCan) not rights. action can depend on many rights337    .directive('prUserRights', function ($timeout) {338        return {339            restrict: 'AE',340            link: function (scope, element, attrs) {341                var elementType = element.prop('nodeName');342                scope.$watch(attrs['prUserRights'], function (val) {343                    disable(val)344                })345                var disable = function (allow) {346                    if (allow === false) {347                        if (elementType === 'BUTTON' || elementType === 'INPUT') {348                            element.prop('disabled', true)349                        } else if (elementType === 'A') {350                            element.css({'pointer-events': 'none', 'cursor': 'default'})351                        } else {352                            element.hide()353                        }354                    }355                }356            }357        };358    })359    .directive('prUserCan', function ($timeout) {360        return {361            restrict: 'AE',362            link: function (scope, element, attrs) {363                var elementType = element.prop('nodeName');364                var enable = function (allow) {365                    if (allow === true) {366                        element.removeProp('disabled');367                        element.removeClass('disabled');368                        element.prop('title', '');369                    } else {370                        if (elementType === 'BUTTON' || elementType === 'INPUT') {371                            element.prop('disabled', true);372                            element.prop('title', allow === false ? '' : allow);373                        } else if (elementType === 'A') {374                            element.addClass('disabled');375                            element.prop('title', allow === false ? '' : allow);376                        } else {377                            element.hide()378                        }379                    }380                }381                scope.$watch(attrs['prUserCan'], function (val) {382                    enable(val)383                })384            }385        };386    })387    .service('objectTransformation', function () {388        var objectTransformation = {};389        objectTransformation.reverseKeyValue = function (objIn) {390            var objOut = {}, keys, i;391            keys = Object.keys($scope.data.PortalDivisionTags3);392            for (i = 0; i < objIn.length; i++) {393                objOut[objIn[keys[i]]] = keys[i];394            }395            return objOut;396        };397        objectTransformation.getValues1 = function (objList, key, unique) {398            var values = [], value;399            for (var i = 0; i < objList.length; i++) {400                value = objList[i][key];401                if (!unique || (values.indexOf(value) === -1)) {402                    values.push(value);403                }404            }405            return values;406        };407        objectTransformation.getValues2 = function (objList, key1, key2) {408            var resultObject = {}, key, value;409            for (var i = 0; i < objList.length; i++) {410                key = objList[i][key1];411                value = objList[i][key2];412                if (typeof resultObject[key] === 'undefined') {413                    resultObject[key] = [value]414                } else {415                    if (resultObject[key].indexOf(value) === -1) {416                        resultObject[key].push(value)417                    }418                }419            }420            return resultObject;421        };422        objectTransformation.getValues3 = function (objList, key1, key2, key2List) {423            var resultObject = {}, key, i, objFilledWithFalse = {};424            for (i = 0; i < key2List.length; i++) {425                objFilledWithFalse[key2List[i]] = false426            }427            for (i = 0; i < objList.length; i++) {428                key = objList[i][key1];429                if (typeof resultObject[key] === 'undefined') {430                    resultObject[key] = $.extend(true, {}, objFilledWithFalse);431                }432                resultObject[key][objList[i][key2]] = true;433            }434            return resultObject;435        };436        objectTransformation.getValues4 = function (objList, key1, key2, key2List) {437            var resultObject = {}, key, i, objFilledWithFalse = {}, lList, elem;438            lList = [];439            for (i = 0; i < objList.length; i++) {440                elem = objList[i][key1];441                if (lList.indexOf(elem) === -1) {442                    lList.push(elem);443                }444            }445            for (i = 0; i < lList.length; i++) {446                objFilledWithFalse[lList[i]] = false;447            }448            for (i = 0; i < key2List.length; i++) {449                resultObject[key2List[i]] = $.extend(true, {}, objFilledWithFalse);450            }451            for (i = 0; i < objList.length; i++) {452                key = objList[i];453                resultObject[key[key2]][key[key1]] = true;454            }455            return resultObject;456        };457        // substitution in keys is performed458        objectTransformation.subsInKey = function (objIn, objForSubstitution) {459            var keys, i, objOut;460            keys = Object.keys(objIn);461            objOut = {};462            for (i = 0; i < keys.length; i++) {463                objOut[objForSubstitution[keys[i]]] = objIn[keys[i]];464            }465            return objOut;466        };467        // substitution of list elements is performed468        objectTransformation.subsElemOfList = function (listIn, objForSubstitution) {469            var i, listOut;470            listOut = [];471            for (i = 0; i < listIn.length; i++) {472                listOut.push(objForSubstitution[listIn[i]])473            }474            return listOut;475        };476        return objectTransformation;477    })478//.directive('ngOk', ['$http', '$compile', '$ok', function ($http, $compile, $ok) {479//    return {480//        restrict: 'A',481//        scope: {482//            ngOnsubmit: '&',483//            ngOnsuccess: '&',484//            ngOnfail: '&',485//            ngAction: '=',486//            ngWatch: '@'487//        },488//        link: function (scope, iElement, iAttrs, ngModelCtrl) {489//490//491//            if (iAttrs['ngValidationResult']) {492//                scope[iAttrs['ngValidationResult']] = {};493//                var s = scope[iAttrs['ngValidationResult']];494//495//                s.checking = {};496//                s.checked = {};497//498//                s.errors = {};499//                s.warnings = {};500//                s.dirty = true;501//502//                s.submitting = false;503//                s.url = null;504//                s.on_success_url = null;505//            }506//507//            iAttrs.$observe('ngAjaxAction', function (value) {508//                s.url = value;509//            });510//511//            iAttrs.$observe('ngOnSuccess', function (value) {512//                s.on_success_url = value;513//            });514//515//516//            $.each($('[name]', $(iElement)), function (ind, el) {517//                $newel = $(el).clone();518//                scope.data[$(el).attr('name')] = $(el).val();519//                $newel.attr('ng-model', 'data.' + $newel.attr('name'));520//                $(el).replaceWith($compile($newel)(scope))521//            });522//523//524//            s.getSignificantClass = function (index, one, onw, onn) {525//526//                if (s.errors && !areAllEmpty(s.errors[index])) {527//                    return one;528//                }529//                if (s.warnings && !areAllEmpty(s.warnings[index])) {530//                    return onw;531//                }532//                if (s.notices && !areAllEmpty(s.notices[index])) {533//                    return onn;534//                }535//                return '';536//            };537//538//            s.getSignificantMessage = function (index) {539//540//                if (s.errors && !areAllEmpty(s.errors[index])) {541//                    return s.errors[index][0];542//                }543//                if (s.warnings && !areAllEmpty(s.warnings[index])) {544//                    return s.warnings[index][0];545//                }546//                if (s.notices && !areAllEmpty(s.notices[index])) {547//                    return s.notices[index][0]548//                }549//                return '';550//            };551//552//553//            s.refresh = function () {554//                s.changed = getObjectsDifference(s.checked, s['data']);555//                s.check();556//            };557//558//            s.check = _.debounce(function (d) {559//                if (areAllEmpty(s.checking)) {560//                    console.log('s.changed', s.changed);561//                    s.changed = getObjectsDifference(s.checked, scope['data']);562//                    if (!areAllEmpty(s.changed)) {563//                        s.checking = scope['data'];564//565//                        $http.post($(iElement).attr('njAjaxAction'), s.checking)566//                            .then(function (fromserver) {567//                                var resp = fromserver['data'];568//                                if (areAllEmpty(getObjectsDifference(s.checking, scope['data']))) {569//                                    s.errors = $.extend(true, {}, resp['errors']);570//                                    s.warnings = $.extend(true, {}, resp['warnings']);571//                                    s.checked = $.extend(true, {}, s.checking);572//                                    s.changed = {};573//                                    s.checking = {};574//                                }575//                                else {576//                                    s.checking = {};577//                                    s.refresh();578//                                }579//                            }, function () {580//                                s.checking = {};581//                                s.refresh();582//                            });...

Full Screen

Full Screen

index.js

Source:index.js Github

copy

Full Screen

...183  let difference;184  let hasThrown = false;185  try {186    const formatOptions = getFormatOptions(FORMAT_OPTIONS, options);187    difference = getObjectsDifference(a, b, formatOptions, options);188  } catch {189    hasThrown = true;190  }191  const noDiffMessage = getCommonMessage(_constants.NO_DIFF_MESSAGE, options); // If the comparison yields no results, compare again but this time192  // without calling `toJSON`. It's also possible that toJSON might throw.193  if (difference === undefined || difference === noDiffMessage) {194    const formatOptions = getFormatOptions(FALLBACK_FORMAT_OPTIONS, options);195    difference = getObjectsDifference(a, b, formatOptions, options);196    if (difference !== noDiffMessage && !hasThrown) {197      difference =198        getCommonMessage(_constants.SIMILAR_MESSAGE, options) +199        '\n\n' +200        difference;201    }202  }203  return difference;204}205function getFormatOptions(formatOptions, options) {206  const {compareKeys} = (0, _normalizeDiffOptions.normalizeDiffOptions)(207    options208  );209  return {...formatOptions, compareKeys};210}211function getObjectsDifference(a, b, formatOptions, options) {212  const formatOptionsZeroIndent = {...formatOptions, indent: 0};213  const aCompare = (0, _prettyFormat.format)(a, formatOptionsZeroIndent);214  const bCompare = (0, _prettyFormat.format)(b, formatOptionsZeroIndent);215  if (aCompare === bCompare) {216    return getCommonMessage(_constants.NO_DIFF_MESSAGE, options);217  } else {218    const aDisplay = (0, _prettyFormat.format)(a, formatOptions);219    const bDisplay = (0, _prettyFormat.format)(b, formatOptions);220    return (0, _diffLines.diffLinesUnified2)(221      aDisplay.split('\n'),222      bDisplay.split('\n'),223      aCompare.split('\n'),224      bCompare.split('\n'),225      options...

Full Screen

Full Screen

getEventData.mjs

Source:getEventData.mjs Github

copy

Full Screen

...28    }29  }),30  update: createProxyWithDefaultFallback({31    task(data, oldData) {32      const changesMap = getObjectsDifference(oldData, data);33      return Object.entries(changesMap).reduce((items, [key, value]) => {34        if (updateTaskMap[key]) {35          items.push( updateTaskMap[key](value, data))36        }37        return items;38      }, []);39    },40    project(data, oldData) {41    },42    default({ object }) {43      return { content: `updated ${object}`, type: 'update' }44    },45  }),46  delete: createProxyWithDefaultFallback({...

Full Screen

Full Screen

Jest Testing Tutorial

LambdaTest’s Jest Testing Tutorial covers step-by-step guides around Jest with code examples to help you be proficient with the Jest framework. The Jest tutorial has chapters to help you learn right from the basics of Jest framework to code-based tutorials around testing react apps with Jest, perform snapshot testing, import ES modules and more.

Chapters

  1. What is Jest Framework
  2. Advantages of Jest - Jest has 3,898,000 GitHub repositories, as mentioned on its official website. Learn what makes Jest special and why Jest has gained popularity among the testing and developer community.
  3. Jest Installation - All the prerequisites and set up steps needed to help you start Jest automation testing.
  4. Using Jest with NodeJS Project - Learn how to leverage Jest framework to automate testing using a NodeJS Project.
  5. Writing First Test for Jest Framework - Get started with code-based tutorial to help you write and execute your first Jest framework testing script.
  6. Jest Vocabulary - Learn the industry renowned and official jargons of the Jest framework by digging deep into the Jest vocabulary.
  7. Unit Testing with Jest - Step-by-step tutorial to help you execute unit testing with Jest framework.
  8. Jest Basics - Learn about the most pivotal and basic features which makes Jest special.
  9. Jest Parameterized Tests - Avoid code duplication and fasten automation testing with Jest using parameterized tests. Parameterization allows you to trigger the same test scenario over different test configurations by incorporating parameters.
  10. Jest Matchers - Enforce assertions better with the help of matchers. Matchers help you compare the actual output with the expected one. Here is an example to see if the object is acquired from the correct class or not. -

|<p>it('check_object_of_Car', () => {</p><p> expect(newCar()).toBeInstanceOf(Car);</p><p> });</p>| | :- |

  1. Jest Hooks: Setup and Teardown - Learn how to set up conditions which needs to be followed by the test execution and incorporate a tear down function to free resources after the execution is complete.
  2. Jest Code Coverage - Unsure there is no code left unchecked in your application. Jest gives a specific flag called --coverage to help you generate code coverage.
  3. HTML Report Generation - Learn how to create a comprehensive HTML report based on your Jest test execution.
  4. Testing React app using Jest Framework - Learn how to test your react web-application with Jest framework in this detailed Jest tutorial.
  5. Test using LambdaTest cloud Selenium Grid - Run your Jest testing script over LambdaTest cloud-based platform and leverage parallel testing to help trim down your test execution time.
  6. Snapshot Testing for React Front Ends - Capture screenshots of your react based web-application and compare them automatically for visual anomalies with the help of Jest tutorial.
  7. Bonus: Import ES modules with Jest - ES modules are also known as ECMAScript modules. Learn how to best use them by importing in your Jest testing scripts.
  8. Jest vs Mocha vs Jasmine - Learn the key differences between the most popular JavaScript-based testing frameworks i.e. Jest, Mocha, and Jasmine.
  9. Jest FAQs(Frequently Asked Questions) - Explore the most commonly asked questions around Jest framework, with their answers.

Run Jest automation tests on LambdaTest cloud grid

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

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful