How to use proxy.command method in Appium Base Driver

Best JavaScript code snippet using appium-base-driver

proficonf.spec.js

Source:proficonf.spec.js Github

copy

Full Screen

1import { DependencyContainer } from '../src/dependency-container';2import { factoryMockHelper } from './setup';3import { Proficonf } from '../src/proficonf';4describe('Proficonf', () => {5    let proficonf;6    let eventEmitterFactory;7    let eventEmitter;8    let iframeLoaderFactory;9    let iframeLoader;10    let iframeMessengerFactory;11    let iframeMessenger;12    let window;13    let nanoid;14    let eventForwarderFactory;15    let eventForwarder;16    let document;17    let iframeElement;18    let rootElement;19    let interfaceConfigSerializer;20    const messageHandlers = new Map();21    function emitMessage(command, payload) {22        return messageHandlers.get(command)(payload);23    }24    beforeEach(() => {25        eventEmitter = jasmine.createSpyObj('eventEmitter', ['on', 'removeListener', 'once']);26        eventEmitterFactory = factoryMockHelper.create(eventEmitter);27        iframeLoader = jasmine.createSpyObj('iframeLoader', ['loadUrl']);28        iframeLoaderFactory = factoryMockHelper.create(iframeLoader);29        iframeMessenger = jasmine.createSpyObj('iframeMessenger', [30            'initialize',31            'addMessageHandlerOnce',32            'sendMessage',33            'sendRequest',34        ]);35        iframeMessenger.addMessageHandlerOnce.and.callFake((command, handler) => {36            messageHandlers.set(command, handler);37        });38        iframeMessengerFactory = factoryMockHelper.create(iframeMessenger);39        window = { stub: true };40        nanoid = jasmine.createSpy('nanoid').and.returnValue('Fake-Id');41        eventForwarder = jasmine.createSpyObj('eventForwarder', [42            'initialize'43        ]);44        eventForwarderFactory = factoryMockHelper.create(eventForwarder);45        iframeElement = {46            setAttribute: jasmine.createSpy('setAttribute'),47            contentWindow: { contentWindowStub: true },48            style: {}49        };50        document = jasmine.createSpyObj('document', {51            createElement: iframeElement52        });53        rootElement = jasmine.createSpyObj('root', ['appendChild']);54        interfaceConfigSerializer = jasmine.createSpyObj('interfaceConfigSerializer', ['serializeToString', 'serializeToObject']);55        interfaceConfigSerializer.serializeToString.and.returnValue('fake-serialized-ui-config');56        interfaceConfigSerializer.serializeToObject.withArgs({57            removeElements: ['fake-element'],58            customPrimaryColor: 'fake-color',59            customLogoSrc: 'fake-logo-src',60            displayMode: 'fake-display-mode'61        }).and.returnValue('fake-serialized-object');62        DependencyContainer63            .set('eventEmitterFactory', eventEmitterFactory)64            .set('iframeLoaderFactory', iframeLoaderFactory)65            .set('iframeMessengerFactory', iframeMessengerFactory)66            .set('nanoid', nanoid)67            .set('window', window)68            .set('document', document)69            .set('interfaceConfigSerializer', interfaceConfigSerializer)70            .set('eventForwarderFactory', eventForwarderFactory)71            .set('location', {72                protocol: 'http:',73                stub: true74            });75        proficonf = new Proficonf({76            rootElement,77            meetingUrl: 'https://fake.com/j/meeting-alias',78            user: {79                name: 'fake-user-name',80                locale: 'fake-locale'81            },82            iframe: {83                width: 'fake-width',84                height: 'fake-height',85                style: {86                    'fake-style-prop': 'fake-style-prop-value',87                }88            },89            ui: {90                disableElements: ['element-1']91            },92        });93    });94    describe('constructor()', () => {95        it('should create new EventEmitter', () => {96            expect(eventEmitterFactory.create).toHaveBeenCalledOnceWith();97        });98        describe('[iframe initialization]', () => {99            it('should create iframe element', () => {100                expect(document.createElement).toHaveBeenCalledOnceWith('iframe');101            });102            it('should initialize default iframe properties', () => {103                expect(iframeElement.allow).toBe('camera; microphone; display-capture; autoplay; clipboard-write; clipboard-read; fullscreen');104                expect(iframeElement.name).toBe('ProficonfEmbeddedRoom-meeting-alias');105                expect(iframeElement.id).toBe('ProficonfEmbeddedRoom-meeting-alias');106            });107            it('should initialize iframe styles', () => {108                expect(iframeElement.style['border']).toBe('0');109                expect(iframeElement.style['fake-style-prop']).toBe('fake-style-prop-value');110                expect(iframeElement.style['width']).toBe('fake-width');111                expect(iframeElement.style['height']).toBe('fake-height');112            });113            it('should set default values for height and width', () => {114                new Proficonf({115                    rootElement,116                    meetingUrl: 'https://fake.com/j/meeting-alias',117                    user: {118                        name: 'fake-user-name',119                        locale: 'fake-locale'120                    },121                    iframe: {122                        style: {123                            'fake-style-prop': 'fake-style-prop-value',124                        }125                    },126                    ui: {127                        disableLeftBar: 'fake-disable-left-bar'128                    },129                });130                expect(iframeElement.style['width']).toBe('640px');131                expect(iframeElement.style['height']).toBe('450px');132            });133        });134    });135    it('has iframeElement getter', () => {136        expect(proficonf.getIframeElement()).toBe(iframeElement);137    });138    it('has rootElement getter', () => {139        expect(proficonf.getRootElement()).toBe(rootElement);140    });141    it('should allow to subscribe for events', () => {142        proficonf.on('x', 'y');143        expect(eventEmitter.on).toHaveBeenCalledOnceWith('x', 'y');144    });145    it('should allow to subscribe for events once', () => {146        proficonf.once('x', 'y');147        expect(eventEmitter.once).toHaveBeenCalledOnceWith('x', 'y');148    });149    it('should allow to unsubscribe from events', () => {150        proficonf.removeListener('x', 'y');151        expect(eventEmitter.removeListener).toHaveBeenCalledOnceWith('x', 'y');152    });153    describe('join()', () => {154        beforeAll(() => {155            jasmine.clock().install().mockDate(new Date());156        });157        afterAll(() => {158            jasmine.clock().uninstall();159        });160        beforeEach(() => {161            iframeMessenger.sendMessage162                .withArgs('initialize', {})163                .and.callFake(() => emitMessage('app:ready', {}));164        });165        it('should make iframe visible', async () => {166            await proficonf.join();167            expect(rootElement.appendChild).toHaveBeenCalledOnceWith(iframeElement);168        });169        it('should initialize iframeLoader', async () => {170            await proficonf.join();171            expect(iframeLoaderFactory.create).toHaveBeenCalledOnceWith(iframeElement);172        });173        it('should load iframe url', async () => {174            await proficonf.join();175            expect(iframeLoader.loadUrl).toHaveBeenCalledOnceWith(176                'https://fake.com/j/meeting-alias?embedded=1&locale=fake-locale&un=fake-user-name&ui=fake-serialized-ui-config'177            );178        });179        it('should use user token when provided for url', async () => {180            proficonf = new Proficonf({181                rootElement,182                meetingUrl: 'https://fake.com/j/meeting-alias',183                user: {184                    token: 'fake-token'185                },186                iframe: {187                    width: 'fake-width',188                    height: 'fake-height',189                    style: {190                        'fake-style-prop': 'fake-style-prop-value',191                    }192                },193                ui: {194                    disableLeftBar: 'fake-disable-left-bar'195                },196            });197            await proficonf.join();198            expect(iframeLoader.loadUrl).toHaveBeenCalledOnceWith(199                'https://fake.com/j/meeting-alias?embedded=1&t=fake-token&ui=fake-serialized-ui-config'200            );201        });202        it('Should createe iframe messenger', async () => {203            await proficonf.join();204            expect(iframeMessengerFactory.create).toHaveBeenCalledOnceWith({205                targetOrigin: 'https://fake.com',206                targetWindow: iframeElement.contentWindow,207                window,208                nanoid,209                correlationId: 'meeting-alias'210            });211        });212        it('Should create eventForwarder', async () => {213            await proficonf.join();214            expect(eventForwarderFactory.create).toHaveBeenCalledOnceWith({215                iframeMessenger,216                eventEmitter217            });218        });219        it('Should initialize eventForwarder', async () => {220            await proficonf.join();221            expect(eventForwarder.initialize).toHaveBeenCalledOnceWith();222        });223        it('Should initialize iframeMessenger', async () => {224            await proficonf.join();225            expect(iframeMessenger.initialize).toHaveBeenCalledOnceWith();226        });227        it('Should send initialize command', async () => {228            await proficonf.join();229            expect(iframeMessenger.sendMessage).toHaveBeenCalledOnceWith('initialize', {});230        });231        it('Should throw on initialization timeout', async () => {232            iframeMessenger.sendMessage233                .withArgs('initialize', {})234                .and.callFake(() => {235                    jasmine.clock().tick(300001);236                });237            await expectAsync(238                proficonf.join()239            ).toBeRejectedWith(new Error('App initialization timeout'));240        });241    });242    describe('[joined]', () => {243        beforeEach(() => {244            iframeMessenger.sendMessage245                .withArgs('initialize', {})246                .and.callFake(() => emitMessage('app:ready', {}));247            return proficonf.join();248        });249        async function testCommandProxy({250            command,251            functionName,252            expectedRequestPayload,253            functionArguments = []254        }) {255            it(`should proxy command: ${command}`, async () => {256                const commandArguments = expectedRequestPayload257                    ? [command, expectedRequestPayload]258                    : [command];259                iframeMessenger.sendRequest.withArgs(...commandArguments).and.resolveTo('fake-result');260                await expectAsync(proficonf[functionName || command](...functionArguments)).toBeResolvedTo('fake-result');261            });262        }263        describe('getParticipants()', () => {264            testCommandProxy({ command: 'getParticipants' });265        });266        describe('getParticipantById()', () => {267            testCommandProxy({268                command: 'getParticipantById',269                functionArguments: ['fake-id'],270                expectedRequestPayload: { id: 'fake-id' }271            });272        });273        describe('blockParticipant()', () => {274            testCommandProxy({275                command: 'blockParticipant',276                functionArguments: ['fake-id'],277                expectedRequestPayload: { id: 'fake-id' }278            });279        });280        describe('unblockParticipant()', () => {281            testCommandProxy({282                command: 'unblockParticipant',283                functionArguments: ['fake-id'],284                expectedRequestPayload: { id: 'fake-id' }285            });286        });287        describe('banParticipant()', () => {288            testCommandProxy({289                command: 'banParticipant',290                functionArguments: ['fake-id'],291                expectedRequestPayload: { id: 'fake-id' }292            });293        });294        describe('setUserName()', () => {295            testCommandProxy({296                command: 'setUserName',297                functionArguments: ['fake-name'],298                expectedRequestPayload: { name: 'fake-name' }299            });300        });301        describe('setUserLocale()', () => {302            testCommandProxy({303                command: 'setUserLocale',304                functionArguments: ['fake-locale'],305                expectedRequestPayload: { locale: 'fake-locale' }306            });307        });308        describe('enableChatForParticipant()', () => {309            testCommandProxy({310                command: 'setChatState',311                functionName: 'enableChatForParticipant',312                functionArguments: ['fake-id'],313                expectedRequestPayload: { participantId: 'fake-id', isChatAllowed: true }314            });315        });316        describe('disableChatForParticipant()', () => {317            testCommandProxy({318                command: 'setChatState',319                functionName: 'disableChatForParticipant',320                functionArguments: ['fake-id'],321                expectedRequestPayload: { participantId: 'fake-id', isChatAllowed: false }322            });323        });324        describe('disableParticipantMicrophone()', () => {325            testCommandProxy({326                command: 'disableParticipantMicrophone',327                functionArguments: ['fake-id'],328                expectedRequestPayload: { id: 'fake-id' }329            });330        });331        describe('askToEnableParticipantMicrophone()', () => {332            testCommandProxy({333                command: 'askToEnableParticipantMicrophone',334                functionArguments: ['fake-id'],335                expectedRequestPayload: { id: 'fake-id' }336            });337        });338        describe('blockParticipantMicrophone()', () => {339            testCommandProxy({340                command: 'blockParticipantMicrophone',341                functionArguments: ['fake-id'],342                expectedRequestPayload: { id: 'fake-id' }343            });344        });345        describe('unblockParticipantMicrophone()', () => {346            testCommandProxy({347                command: 'unblockParticipantMicrophone',348                functionArguments: ['fake-id'],349                expectedRequestPayload: { id: 'fake-id' }350            });351        });352        describe('askToEnableParticipantCamera()', () => {353            testCommandProxy({354                command: 'askToEnableParticipantCamera',355                functionArguments: ['fake-id'],356                expectedRequestPayload: { id: 'fake-id' }357            });358        });359        describe('blockParticipantCamera()', () => {360            testCommandProxy({361                command: 'blockParticipantCamera',362                functionArguments: ['fake-id'],363                expectedRequestPayload: { id: 'fake-id' }364            });365        });366        describe('unblockParticipantCamera()', () => {367            testCommandProxy({368                command: 'unblockParticipantCamera',369                functionArguments: ['fake-id'],370                expectedRequestPayload: { id: 'fake-id' }371            });372        });373        describe('enableCamera()', () => {374            testCommandProxy({375                command: 'enableCamera',376                functionArguments: [{ stub: true }],377                expectedRequestPayload: { constraints: { stub: true } }378            });379        });380        describe('disableCamera()', () => {381            testCommandProxy({382                command: 'disableCamera'383            });384        });385        describe('setCameraDevice()', () => {386            testCommandProxy({387                command: 'setCameraDevice',388                functionArguments: ['fake-device-id'],389                expectedRequestPayload: { deviceId: 'fake-device-id' }390            });391        });392        describe('getCameraState()', () => {393            testCommandProxy({394                command: 'getCameraState',395            });396        });397        describe('enableMicrophone()', () => {398            testCommandProxy({399                command: 'enableMicrophone',400                functionArguments: [{ stub: true }],401                expectedRequestPayload: { constraints: { stub: true } }402            });403        });404        describe('setMicrophoneDevice()', () => {405            testCommandProxy({406                command: 'setMicrophoneDevice',407                functionArguments: ['fake-device'],408                expectedRequestPayload: { deviceId: 'fake-device' }409            });410        });411        describe('disableMicrophone()', () => {412            testCommandProxy({413                command: 'disableMicrophone'414            });415        });416        describe('getDeviceList()', () => {417            testCommandProxy({418                command: 'getDeviceList'419            });420        });421        describe('switchCamera()', () => {422            testCommandProxy({423                command: 'switchCamera'424            });425        });426        describe('switchMicrophone()', () => {427            testCommandProxy({428                command: 'switchMicrophone'429            });430        });431        describe('getMicrophoneState()', () => {432            testCommandProxy({433                command: 'getMicrophoneState'434            });435        });436        describe('startScreenSharing()', () => {437            testCommandProxy({438                command: 'startScreenSharing',439                functionArguments: [{ stub: true }],440                expectedRequestPayload: { constraints: { stub: true } }441            });442        });443        describe('getScreenSharingState()', () => {444            testCommandProxy({445                command: 'getScreenSharingState',446            });447        });448        describe('stopScreenSharing()', () => {449            testCommandProxy({450                command: 'stopScreenSharing',451            });452        });453        describe('disableParticipantMicrophone()', () => {454            testCommandProxy({455                command: 'disableParticipantMicrophone',456                functionArguments: ['fake-id'],457                expectedRequestPayload: { id: 'fake-id' }458            });459        });460        describe('disableParticipantCamera()', () => {461            testCommandProxy({462                command: 'disableParticipantCamera',463                functionArguments: ['fake-id'],464                expectedRequestPayload: { id: 'fake-id' }465            });466        });467        describe('blockParticipantMicrophone()', () => {468            testCommandProxy({469                command: 'blockParticipantMicrophone',470                functionArguments: ['fake-id'],471                expectedRequestPayload: { id: 'fake-id' }472            });473        });474        describe('blockParticipantCamera()', () => {475            testCommandProxy({476                command: 'blockParticipantCamera',477                functionArguments: ['fake-id'],478                expectedRequestPayload: { id: 'fake-id' }479            });480        });481        describe('unblockParticipantCamera()', () => {482            testCommandProxy({483                command: 'unblockParticipantCamera',484                functionArguments: ['fake-id'],485                expectedRequestPayload: { id: 'fake-id' }486            });487        });488        describe('unblockParticipantMicrophone()', () => {489            testCommandProxy({490                command: 'unblockParticipantMicrophone',491                functionArguments: ['fake-id'],492                expectedRequestPayload: { id: 'fake-id' }493            });494        });495        describe('setParticipantRole()', () => {496            testCommandProxy({497                command: 'setParticipantRole',498                functionArguments: ['fake-id', 'fake-role' ],499                expectedRequestPayload: { id: 'fake-id', role: 'fake-role' }500            });501        });502        describe('setScreenLayout()', () => {503            testCommandProxy({504                command: 'setScreenLayout',505                functionArguments: ['fake-mode'],506                expectedRequestPayload: { layout: 'fake-mode' }507            });508        });509        describe('startMeeting()', () => {510            testCommandProxy({511                command: 'startMeeting',512            });513        });514        describe('endMeeting()', () => {515            testCommandProxy({516                command: 'endMeeting',517            });518        });519        describe('startRecording()', () => {520            testCommandProxy({521                command: 'startRecording',522                functionArguments: ['fake-ui-state'],523                expectedRequestPayload: { uiState: 'fake-ui-state' },524            });525        });526        describe('setRecordingConfig()', () => {527            testCommandProxy({528                command: 'setRecordingConfig',529                functionArguments: ['fake-ui-state'],530                expectedRequestPayload: { uiState: 'fake-ui-state' },531            });532        });533        describe('stopRecording()', () => {534            testCommandProxy({535                command: 'stopRecording',536            });537        });538        describe('getRecordingState()', () => {539            testCommandProxy({540                command: 'getRecordingState',541            });542        });543        describe('sendChatMessage()', () => {544            testCommandProxy({545                command: 'sendChatMessage',546                functionArguments: ['fake-message'],547                expectedRequestPayload: { message: 'fake-message' },548            });549        });550        describe('updateUIConfig()', () => {551            testCommandProxy({552                command: 'updateUIConfig',553                functionArguments: [{554                    removeElements: ['fake-element'],555                    customPrimaryColor: 'fake-color',556                    customLogoSrc: 'fake-logo-src',557                    displayMode: 'fake-display-mode'558                }],559                expectedRequestPayload: 'fake-serialized-object'560            });561        });562        describe('startStream()', () => {563            testCommandProxy({564                command: 'startStream',565                functionArguments: [{ serverUrl: 'fake-server-url', streamKey: 'fake-stream-key' }],566                expectedRequestPayload: { serverUrl: 'fake-server-url', streamKey: 'fake-stream-key' },567            });568        });569        describe('stopStream()', () => {570            testCommandProxy({571                command: 'stopStream',572                functionArguments: [{ serverUrl: 'fake-server-url', streamKey: 'fake-stream-key' }],573                expectedRequestPayload: { serverUrl: 'fake-server-url', streamKey: 'fake-stream-key' },574            });575        });576        describe('stopAllStreams()', () => {577            testCommandProxy({578                command: 'stopAllStreams',579            });580        });581    });...

Full Screen

Full Screen

gesture.js

Source:gesture.js Github

copy

Full Screen

1import { errors } from 'appium-base-driver';2import { util } from 'appium-support';3import { iosCommands } from 'appium-ios-driver';4import _ from 'lodash';5import log from '../logger';6let helpers = {}, extensions = {}, commands = {};7commands.moveTo = iosCommands.gesture.moveTo;8commands.mobileShake = async function mobileShake () {9  if (!this.isSimulator()) {10    throw new errors.UnknownError('Shake is not supported on real devices');11  }12  await this.opts.device.shake();13};14commands.click = async function click (el) {15  if (!this.isWebContext()) {16    // there are multiple commands that map here, so manually proxy17    return await this.nativeClick(el);18  }19  el = util.unwrapElement(el);20  if ((await this.settings.getSettings()).nativeWebTap) {21    // atoms-based clicks don't always work in safari 722    log.debug('Using native web tap');23    await this.nativeWebTap(el);24  } else {25    let atomsElement = this.useAtomsElement(el);26    return await this.executeAtom('click', [atomsElement]);27  }28};29function gesturesChainToString (gestures, keysToInclude = ['options']) {30  return gestures.map((item) => {31    let otherKeys = _.difference(_.keys(item), ['action']);32    otherKeys = _.isArray(keysToInclude) ? _.intersection(otherKeys, keysToInclude) : otherKeys;33    if (otherKeys.length) {34      return `${item.action}` +35        `(${_.map(otherKeys, (x) => x + '=' + (_.isPlainObject(item[x]) ? JSON.stringify(item[x]) : item[x])).join(', ')})`;36    }37    return item.action;38  }).join('-');39}40commands.performActions = async function performActions (actions) {41  log.debug(`Received the following W3C actions: ${JSON.stringify(actions, null, '  ')}`);42  // This is mandatory, since WDA only supports TOUCH pointer type43  // and Selenium API uses MOUSE as the default one44  const preprocessedActions = actions45    .map((action) => Object.assign({}, action, action.type === 'pointer' ? {46      parameters: {47        pointerType: 'touch'48      }49    } : {}))50    .map((action) => {51      const modifiedAction = _.clone(action) || {};52      // Selenium API unexpectedly inserts zero pauses, which are not supported by WDA53      modifiedAction.actions = (action.actions || [])54        .filter((innerAction) => !(innerAction.type === 'pause' && innerAction.duration === 0));55      return modifiedAction;56    });57  log.debug(`Preprocessed actions: ${JSON.stringify(preprocessedActions, null, '  ')}`);58  return await this.proxyCommand('/actions', 'POST', {actions: preprocessedActions});59};60commands.performTouch = async function performTouch (gestures) {61  log.debug(`Received the following touch action: ${gesturesChainToString(gestures)}`);62  try {63    return await this.proxyCommand('/wda/touch/perform', 'POST', {actions: gestures});64  } catch (e) {65    if (!this.isWebContext()) {66      throw e;67    }68    log.errorAndThrow('The Touch API is aimed for usage in NATIVE context. ' +69      'Consider using "execute" API with custom events trigger script ' +70      `to emulate touch events being in WEBVIEW context. Original error: ${e.message}`);71  }72};73commands.performMultiAction = async function performMultiAction (actions) {74  log.debug(`Received the following multi touch action:`);75  for (let i in actions) {76    log.debug(`    ${parseInt(i, 10) + 1}: ${_.map(actions[i], 'action').join('-')}`);77  }78  try {79    return await this.proxyCommand('/wda/touch/multi/perform', 'POST', {actions});80  } catch (e) {81    if (!this.isWebContext()) {82      throw e;83    }84    log.errorAndThrow('The MultiTouch API is aimed for usage in NATIVE context. ' +85      'Consider using "execute" API with custom events trigger script ' +86      `to emulate multitouch events being in WEBVIEW context. Original error: ${e.message}`);87  }88};89commands.nativeClick = async function nativeClick (el) {90  el = util.unwrapElement(el);91  let endpoint = `/element/${el}/click`;92  return await this.proxyCommand(endpoint, 'POST', {});93};94/*95 * See https://github.com/facebook/WebDriverAgent/blob/master/WebDriverAgentLib/Commands/FBElementCommands.m96 * to get the info about available WDA gestures API97 *98 * See https://developer.apple.com/reference/xctest/xcuielement and99 * https://developer.apple.com/reference/xctest/xcuicoordinate to get the detailed description of100 * all XCTest gestures101*/102helpers.mobileScroll = async function mobileScroll (opts = {}, swipe = false) {103  if (!opts.element) {104    opts.element = await this.findNativeElementOrElements(`class name`, `XCUIElementTypeApplication`, false);105  }106  // WDA supports four scrolling strategies: predication based on name, direction,107  // predicateString, and toVisible, in that order. Swiping requires direction.108  let params = {};109  if (opts.name && !swipe) {110    params.name = opts.name;111  } else if (opts.direction) {112    if (!['up', 'down', 'left', 'right'].includes(opts.direction.toLowerCase())) {113      let msg = 'Direction must be up, down, left or right';114      log.errorAndThrow(msg);115    }116    params.direction = opts.direction;117  } else if (opts.predicateString && !swipe) {118    params.predicateString = opts.predicateString;119  } else if (opts.toVisible && !swipe) {120    params.toVisible = opts.toVisible;121  } else {122    let msg = swipe123      ? 'Mobile swipe requires direction'124      : 'Mobile scroll supports the following strategies: name, direction, predicateString, and toVisible. Specify one of these';125    log.errorAndThrow(msg);126  }127  // we can also optionally pass a distance which appears to be a ratio of128  // screen height, so 1.0 means a full screen's worth of scrolling129  if (!swipe && opts.distance) {130    params.distance = opts.distance;131  }132  let element = util.unwrapElement(opts.element);133  let endpoint = `/wda/element/${element}/${swipe ? 'swipe' : 'scroll'}`;134  return await this.proxyCommand(endpoint, 'POST', params);135};136helpers.mobileSwipe = async function mobileSwipe (opts = {}) {137  return await this.mobileScroll(opts, true);138};139function parseFloatParameter (paramName, paramValue, methodName) {140  if (_.isUndefined(paramValue)) {141    log.errorAndThrow(`"${paramName}" parameter is mandatory for "${methodName}" call`);142  }143  const result = parseFloat(paramValue);144  if (isNaN(result)) {145    log.errorAndThrow(`"${paramName}" parameter should be a valid number. "${paramValue}" is given instead`);146  }147  return result;148}149helpers.mobilePinch = async function mobilePinch (opts = {}) {150  if (!opts.element) {151    opts.element = await this.findNativeElementOrElements(`class name`, `XCUIElementTypeApplication`, false);152  }153  const params = {154    scale: parseFloatParameter('scale', opts.scale, 'pinch'),155    velocity: parseFloatParameter('velocity', opts.velocity, 'pinch')156  };157  const el = util.unwrapElement(opts.element);158  return await this.proxyCommand(`/wda/element/${el}/pinch`, 'POST', params);159};160helpers.mobileDoubleTap = async function mobileDoubleTap (opts = {}) {161  if (opts.element) {162    // Double tap element163    const el = util.unwrapElement(opts.element);164    return await this.proxyCommand(`/wda/element/${el}/doubleTap`, 'POST');165  }166  // Double tap coordinates167  const params = {168    x: parseFloatParameter('x', opts.x, 'doubleTap'),169    y: parseFloatParameter('y', opts.y, 'doubleTap')170  };171  return await this.proxyCommand('/wda/doubleTap', 'POST', params);172};173helpers.mobileTwoFingerTap = async function mobileTwoFingerTap (opts = {}) {174  if (!opts.element) {175    opts.element = await this.findNativeElementOrElements(`class name`, `XCUIElementTypeApplication`, false);176  }177  const el = util.unwrapElement(opts.element);178  return await this.proxyCommand(`/wda/element/${el}/twoFingerTap`, 'POST');179};180helpers.mobileTouchAndHold = async function mobileTouchAndHold (opts = {}) {181  let params = {182    duration: parseFloatParameter('duration', opts.duration, 'touchAndHold')183  };184  if (opts.element) {185    // Long tap element186    const el = util.unwrapElement(opts.element);187    return await this.proxyCommand(`/wda/element/${el}/touchAndHold`, 'POST', params);188  }189  // Long tap coordinates190  params.x = parseFloatParameter('x', opts.x, 'touchAndHold');191  params.y = parseFloatParameter('y', opts.y, 'touchAndHold');192  return await this.proxyCommand('/wda/touchAndHold', 'POST', params);193};194helpers.mobileTap = async function mobileTap (opts = {}) {195  const params = {196    x: parseFloatParameter('x', opts.x, 'tap'),197    y: parseFloatParameter('y', opts.y, 'tap')198  };199  const el = opts.element ? (util.unwrapElement(opts.element)) : '0';200  return await this.proxyCommand(`/wda/tap/${el}`, 'POST', params);201};202helpers.mobileDragFromToForDuration = async function mobileDragFromToForDuration (opts = {}) {203  const params = {204    duration: parseFloatParameter('duration', opts.duration, 'dragFromToForDuration'),205    fromX: parseFloatParameter('fromX', opts.fromX, 'dragFromToForDuration'),206    fromY: parseFloatParameter('fromY', opts.fromY, 'dragFromToForDuration'),207    toX: parseFloatParameter('toX', opts.toX, 'dragFromToForDuration'),208    toY: parseFloatParameter('toY', opts.toY, 'dragFromToForDuration')209  };210  if (opts.element) {211    // Drag element212    const el = util.unwrapElement(opts.element);213    return await this.proxyCommand(`/wda/element/${el}/dragfromtoforduration`, 'POST', params);214  }215  // Drag coordinates216  return await this.proxyCommand('/wda/dragfromtoforduration', 'POST', params);217};218helpers.mobileSelectPickerWheelValue = async function mobileSelectPickerWheelValue (opts = {}) {219  if (!opts.element) {220    log.errorAndThrow('Element id is expected to be set for selectPickerWheelValue method');221  }222  if (!_.isString(opts.order) || !['next', 'previous'].includes(opts.order.toLowerCase())) {223    log.errorAndThrow(`The mandatory 'order' parameter is expected to be equal either to 'next' or 'previous'. ` +224                      `'${opts.order}' is given instead`);225  }226  const el = util.unwrapElement(opts.element);227  const params = {order: opts.order};228  if (opts.offset) {229    params.offset = parseFloatParameter('offset', opts.offset, 'selectPickerWheelValue');230  }231  return await this.proxyCommand(`/wda/pickerwheel/${el}/select`, 'POST', params);232};233helpers.getCoordinates = async function getCoordinates (gesture) {234  let el = gesture.options.element;235  // defaults236  let coordinates = {x: 0, y: 0, areOffsets: false};237  let optionX = null;238  if (gesture.options.x) {239    optionX = parseFloatParameter('x', gesture.options.x, 'getCoordinates');240  }241  let optionY = null;242  if (gesture.options.y) {243    optionY = parseFloatParameter('y', gesture.options.y, 'getCoordinates');244  }245  // figure out the element coordinates.246  if (el) {247    let rect = await this.getElementRect(el);248    let pos = {x: rect.x, y: rect.y};249    let size = {w: rect.width, h: rect.height};250    // defaults251    let offsetX = 0;252    let offsetY = 0;253    // get the real offsets254    if (optionX || optionY) {255      offsetX = (optionX || 0);256      offsetY = (optionY || 0);257    } else {258      offsetX = (size.w / 2);259      offsetY = (size.h / 2);260    }261    // apply the offsets262    coordinates.x = pos.x + offsetX;263    coordinates.y = pos.y + offsetY;264  } else {265    // moveTo coordinates are passed in as offsets266    coordinates.areOffsets = (gesture.action === 'moveTo');267    coordinates.x = (optionX || 0);268    coordinates.y = (optionY || 0);269  }270  return coordinates;271};272helpers.applyMoveToOffset = function applyMoveToOffset (firstCoordinates, secondCoordinates) {273  if (secondCoordinates.areOffsets) {274    return {275      x: firstCoordinates.x + secondCoordinates.x,276      y: firstCoordinates.y + secondCoordinates.y,277    };278  } else {279    return secondCoordinates;280  }281};282Object.assign(extensions, helpers, commands);283export { extensions, helpers, commands, gesturesChainToString };...

Full Screen

Full Screen

alert.js

Source:alert.js Github

copy

Full Screen

1import { errors, isErrorType } from 'appium-base-driver';2let commands = {}, helpers = {}, extensions = {};3commands.getAlertText = async function () {4  if (this.isWebContext()) {5    let alert = await this.getAlert();6    let text = await alert.getText();7    return text;8  }9  let method = 'GET';10  let endpoint = `/alert/text`;11  return await this.proxyCommand(endpoint, method);12};13// TODO: WDA does not currently support this natively14commands.setAlertText = async function (text) {15  if (!Array.isArray(text)) {16    text = text.split('');17  }18  if (this.isWebContext()) {19    let alert = await this.getAlert();20    await alert.setText(text);21    return;22  }23  let method = 'POST';24  let endpoint = `/alert/text`;25  return await this.proxyCommand(endpoint, method, text);26};27commands.postAcceptAlert = async function () {28  if (this.isWebContext()) {29    let alert = await this.getAlert();30    if (alert.close) {31      await alert.close();32    } else {33      await alert.ok();34    }35    return;36  }37  let method = 'POST';38  let endpoint = `/alert/accept`;39  return await this.proxyCommand(endpoint, method);40};41commands.postDismissAlert = async function () {42  if (this.isWebContext()) {43    let alert = await this.getAlert();44    if (alert.close) {45      await alert.close();46    } else {47      await alert.cancel();48    }49    return;50  }51  let method = 'POST';52  let endpoint = `/alert/dismiss`;53  return await this.proxyCommand(endpoint, method);54};55helpers.getAlert = async function () {56  let possibleAlert = await this.findNativeElementOrElements('class name', 'XCUIElementTypeScrollView', true);57  if (possibleAlert.length !== 1) throw new errors.NoAlertOpenError();58  let possibleAlertButtons = await this.findNativeElementOrElements('class name', 'XCUIElementTypeButton', true, possibleAlert[0].ELEMENT);59  if (possibleAlertButtons.length  < 1 || possibleAlertButtons.length > 2) throw new errors.NoAlertOpenError();60  let assertButtonName = async (button, expectedName) => {61    button = button.ELEMENT ? button.ELEMENT : button;62    let name = await this.proxyCommand(`/element/${button}/attribute/name`, 'GET');63    if (name.toLowerCase() !== expectedName) throw new errors.NoAlertOpenError();64  };65  let alert = possibleAlert[0];66  if (possibleAlertButtons.length === 1) {67    // make sure the button is 'Close'68    let closeButton = possibleAlertButtons[0];69    await assertButtonName(closeButton, 'close');70    alert.close = async () => {71      await this.proxyCommand(`/element/${closeButton.ELEMENT}/click`, 'POST');72    };73  } else {74    // ensure the buttons are 'Cancel' and 'OK'75    let cancelButton = possibleAlertButtons[0];76    await assertButtonName(cancelButton, 'cancel');77    let okButton = possibleAlertButtons[1];78    await assertButtonName(okButton, 'ok');79    alert.cancel = async () => {80      await this.proxyCommand(`/element/${cancelButton.ELEMENT}/click`, 'POST');81    };82    alert.ok = async () => {83      await this.proxyCommand(`/element/${okButton.ELEMENT}/click`, 'POST');84    };85  }86  alert.getText = async () => {87    let textView = await this.findNativeElementOrElements('class name', 'XCUIElementTypeTextView', false, alert.ELEMENT);88    return await this.proxyCommand(`/element/${textView.ELEMENT}/attribute/value`, 'GET');89  };90  alert.setText = async (value) => {91    try {92      let textView = await this.findNativeElementOrElements('class name', 'XCUIElementTypeTextField', false, alert.ELEMENT);93      await this.proxyCommand(`/element/${textView.ELEMENT}/value `, 'POST', {value});94    } catch (err) {95      if (isErrorType(err, errors.NoSuchElementError)) {96        throw new Error('Tried to set text of an alert that was not a prompt');97      }98      throw err;99    }100  };101  return alert;102};103Object.assign(extensions, commands, helpers);104export { commands, helpers };...

Full Screen

Full Screen

proxy-test.js

Source:proxy-test.js Github

copy

Full Screen

1const td            = require('testdouble');2const Promise       = require('rsvp').Promise;3const path          = require('path');4const expect        = require('../../helpers/expect');5const contains      = td.matchers.contains;6const cordovaPath   = path.join('appPath', 'corber', 'cordova');7describe('Proxy Command', () => {8  let proxyCommand;9  let logger;10  let spawn;11  let VerifyInstall;12  beforeEach(() => {13    let project = {14      root: 'appPath',15      isEmberCLIProject: td.function()16    };17    logger = td.object(['warn', 'error', 'success']);18    td.replace('../../../lib/utils/logger', logger);19    let getCordovaPath = td.replace('../../../lib/targets/cordova/utils/get-path');20    td.when(getCordovaPath(project)).thenReturn(cordovaPath);21    VerifyInstall = td.replace('../../../lib/targets/cordova/validators/is-installed');22    td.when(VerifyInstall.prototype.run()).thenReturn(Promise.resolve());23    spawn = td.replace('../../../lib/utils/spawn');24    td.when(spawn('cordova build', [], { shell: true }, contains({ cwd: cordovaPath })))25      .thenReturn(Promise.resolve());26    let ProxyCommand = require('../../../lib/commands/proxy');27    proxyCommand = new ProxyCommand({28      project,29      analytics: td.object(['track', 'trackTiming', 'trackError'])30    });31  });32  afterEach(() => {33    td.reset();34  });35  it('resolves when proxy spawn exits successfully', () => {36    let promise = proxyCommand.validateAndRun(['build']);37    return expect(promise).to.eventually.be.fulfilled;38  });39  it('rejects if install not verified', () => {40    td.when(VerifyInstall.prototype.run())41      .thenReturn(Promise.reject('install not verified'));42    return proxyCommand.validateAndRun(['build']).then(() => {43      td.verify(logger.error(contains('install not verified')));44    });45  });46  it('rejects with error code msg when proxy spawn exits in failure', () => {47    td.when(spawn('cordova build', [], { shell: true }, contains({ cwd: cordovaPath })))48      .thenReturn(Promise.resolve({ code: -1 }));49    return proxyCommand.validateAndRun(['build']).then(() => {50      td.verify(logger.error(contains('\'cordova build\' failed with error code -1')));51    });52  });53  it('warns if a supported corber command is used', () => {54    return proxyCommand.validateAndRun(['build']).then(() => {55      td.verify(logger.warn(contains('bypassed corber command')));56    });57  });58  it('warns if cordova command is unknown', () => {59    td.when(spawn('cordova foo', [], { shell: true }, contains({ cwd: cordovaPath })))60      .thenReturn(Promise.resolve());61    return proxyCommand.validateAndRun(['foo']).then(() => {62      td.verify(logger.warn(contains('unknown Cordova command')));63    });64  });65  it('does not warn if known non-supported corber command is used', () => {66    td.when(spawn('cordova emulate', [], { shell: true }, contains({ cwd: cordovaPath })))67      .thenReturn(Promise.resolve())68    return proxyCommand.validateAndRun(['emulate']).then(() => {69      td.verify(logger.warn(contains('bypassed corber command')), { times: 0 });70      td.verify(logger.warn(contains('unknown Cordova command')), { times: 0 });71    });72  });...

Full Screen

Full Screen

20211005131430-config-without-proxy-command-permission-for-renaming.js

Source:20211005131430-config-without-proxy-command-permission-for-renaming.js Github

copy

Full Screen

1import mongoose from 'mongoose';2import { getModelSafely, getMongoUri, mongoOptions } from '@growi/core';3import loggerFactory from '~/utils/logger';4import Config from '~/server/models/config';5const logger = loggerFactory('growi:migrate:slack-app-integration-rename-keys');6module.exports = {7  async up(db) {8    mongoose.connect(getMongoUri(), mongoOptions);9    const isExist = (await Config.count({ key: 'slackbot:withoutProxy:commandPermission' })) > 0;10    if (!isExist) return;11    const commandPermissionValue = await Config.findOne({ key: 'slackbot:withoutProxy:commandPermission' });12    // do nothing if data is 'null' or null13    if (commandPermissionValue._doc.value === 'null' || commandPermissionValue._doc.value == null) return;14    const commandPermission = JSON.parse(commandPermissionValue._doc.value);15    const newCommandPermission = {16      note: false,17      keep: false,18    };19    Object.entries(commandPermission).forEach((entry) => {20      const [key, value] = entry;21      switch (key) {22        case 'create':23          newCommandPermission.note = value;24          break;25        case 'togetter':26          newCommandPermission.keep = value;27          break;28        default:29          newCommandPermission[key] = value;30          break;31      }32    });33    await Config.findOneAndUpdate(34      { key: 'slackbot:withoutProxy:commandPermission' },35      {36        $set: {37          value: JSON.stringify(newCommandPermission),38        },39      },40    );41    logger.info('Migration has successfully applied');42  },43  async down(db, next) {44    mongoose.connect(getMongoUri(), mongoOptions);45    const isExist = (await Config.count({ key: 'slackbot:withoutProxy:commandPermission' })) > 0;46    if (!isExist) return next();47    const commandPermissionValue = await Config.findOne({ key: 'slackbot:withoutProxy:commandPermission' });48    // do nothing if data is 'null' or null49    if (commandPermissionValue._doc.value === 'null' || commandPermissionValue._doc.value == null) return next();50    const commandPermission = JSON.parse(commandPermissionValue._doc.value);51    const newCommandPermission = {52      create: false,53      togetter: false,54    };55    Object.entries(commandPermission).forEach((entry) => {56      const [key, value] = entry;57      switch (key) {58        case 'note':59          newCommandPermission.create = value;60          break;61        case 'keep':62          newCommandPermission.togetter = value;63          break;64        default:65          newCommandPermission[key] = value;66          break;67      }68    });69    await Config.findOneAndUpdate(70      { key: 'slackbot:withoutProxy:commandPermission' },71      {72        $set: {73          value: JSON.stringify(newCommandPermission),74        },75      },76    );77    next();78    logger.info('Migration rollback has successfully applied');79  },...

Full Screen

Full Screen

proxy-helper-specs.js

Source:proxy-helper-specs.js Github

copy

Full Screen

1import { errors } from 'appium-base-driver';2import sinon from 'sinon';3import chai from 'chai';4import chaiAsPromised from 'chai-as-promised';5import XCUITestDriver from '../../..';6chai.should();7chai.use(chaiAsPromised);8describe('proxy commands', () => {9  let driver = new XCUITestDriver();10  // give the driver a spy-able proxy object11  driver.wda = {jwproxy: {command: () => {}}};12  let proxyStub = sinon.stub(driver.wda.jwproxy, 'command');13  afterEach(() => {14    if (proxyStub) {15      proxyStub.reset();16    }17  });18  describe('proxyCommand', () => {19    it('should send command through WDA', async () => {20      proxyStub.returns({status: 0});21      await driver.proxyCommand('/some/endpoint', 'POST', {some: 'stuff'});22      proxyStub.calledOnce.should.be.true;23      proxyStub.firstCall.args[0].should.eql('/some/endpoint');24      proxyStub.firstCall.args[1].should.eql('POST');25      proxyStub.firstCall.args[2].some.should.eql('stuff');26    });27    it('should throw an error if no endpoint is given', async () => {28      await driver.proxyCommand(null, 'POST', {some: 'stuff'}).should.eventually.be.rejectedWith(/endpoint/);29      proxyStub.callCount.should.eql(0);30    });31    it('should throw an error if no endpoint is given', async () => {32      await driver.proxyCommand('/some/endpoint', null, {some: 'stuff'}).should.eventually.be.rejectedWith(/GET, POST/);33      proxyStub.callCount.should.eql(0);34    });35    it('should throw an error if wda returns an error (even if http status is 200)', async () => {36      proxyStub.returns({status: 13, value: 'WDA error occurred'});37      try {38        await driver.proxyCommand('/some/endpoint', 'POST', {some: 'stuff'});39      } catch (err) {40        err.jsonwpCode.should.eql(13);41        err.message.should.include('WDA error occurred');42        err.should.be.an.instanceof(errors.UnknownError);43      }44      proxyStub.calledOnce.should.be.true;45    });46    it('should not throw an error if no status is returned', async () => {47      proxyStub.returns({value: 'WDA error occurred'});48      await driver.proxyCommand('/some/endpoint', 'POST', {some: 'stuff'});49      proxyStub.calledOnce.should.be.true;50    });51  });...

Full Screen

Full Screen

ProxyManager.js

Source:ProxyManager.js Github

copy

Full Screen

1const execSync = require('child_process').execSync;2let window_proxy_command = function (command) {3    let ret = execSync(__dirname + "/../system/window/WindowProxyManager.exe "+ command);4};5let darwin_proxy_command = function (command) {6    command = command.replace(/\:/, " ");7    let ret = execSync(__dirname + "/../system/darwin/DarwinProxyManager.sh "+ command);8}9let linux_proxy_command = function (command) {10    // TODO: help me , please11    let arr = command.split(" ");12    if (arr[0] == 'start') {13    } else if (arr[0] == 'stop') {14    }15}16function setProxyOn (proxy_address) {17    console.log('attach proxy');18    if (process.platform == 'darwin') {19        darwin_proxy_command("start " + proxy_address);20    } else if (process.platform == 'win32') {21        window_proxy_command("start " + proxy_address);22    } else if (process.platform == 'linux') {23        linux_proxy_command("start " + proxy_address);24    }25}26function setProxyOff () {27    console.log('detach proxy');28    if (process.platform == 'darwin') {29        darwin_proxy_command("stop");30    } else if (process.platform == 'win32') {31        window_proxy_command("stop");32    } else if (process.platform == 'linux') {33        linux_proxy_command("stop");34    }35}36module.exports = {37    on : setProxyOn,38    off : setProxyOff...

Full Screen

Full Screen

lock.js

Source:lock.js Github

copy

Full Screen

1import B from 'bluebird';2let commands = {};3commands.lock = async function lock (seconds) {4  await this.proxyCommand('/wda/lock', 'POST');5  if (isNaN(seconds)) {6    return;7  }8  const floatSeconds = parseFloat(seconds);9  if (floatSeconds <= 0) {10    return;11  }12  await B.delay(floatSeconds * 1000);13  await this.proxyCommand('/wda/unlock', 'POST');14};15commands.unlock = async function unlock () {16  await this.proxyCommand('/wda/unlock', 'POST');17};18commands.isLocked = async function isLocked () {19  return await this.proxyCommand('/wda/locked', 'GET');20};21export { commands };...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var wd = require('wd');2var assert = require('assert');3var async = require('async');4var path = require('path');5var fs = require('fs');6var desired = {7  chromeOptions: {8  }9};10var driver = wd.promiseChainRemote('localhost', 4723);11  .init(desired)12  .then(function() {13  })14  .then(function() {15    return driver.execute("mobile: proxyCommand", {16      proxy: {17      },18    });19  })20  .then(function() {21    console.log('done');22  })23  .fin(function() {24    return driver.quit();25  })26  .done();

Full Screen

Using AI Code Generation

copy

Full Screen

1var webdriver = require('selenium-webdriver');2var proxy = require('selenium-webdriver/proxy');3var driver = new webdriver.Builder()4  .forBrowser('chrome')5  .setProxy(proxy.manual({http: 'localhost:8001'}))6  .build();

Full Screen

Using AI Code Generation

copy

Full Screen

1var wd = require('wd');2var assert = require('assert');3var desired = {4};5var driver = wd.remote('localhost', 4723);6driver.init(desired, function() {7    driver.title(function(err, title) {8      console.log("title is: " + title);9      driver.quit();10    });11  });12});13var wd = require('wd');14var assert = require('assert');15var desired = {16};17var driver = wd.remote('localhost', 4723);18driver.init(desired, function() {19    driver.title(function(err, title) {20      console.log("title is: " + title);21      driver.quit();22    });23  });24});25var wd = require('wd');26var assert = require('assert');27var desired = {28};29var driver = wd.remote('localhost', 4723);30driver.init(desired, function() {31    driver.title(function(err, title) {32      console.log("title is: " + title);33      driver.quit();34    });35  });36});37var wd = require('wd');38var assert = require('assert');39var desired = {40};41var driver = wd.remote('localhost', 4723);42driver.init(desired, function() {43    driver.title(function(err, title) {44      console.log("title is: " + title);45      driver.quit();46    });47  });48});49var wd = require('wd');50var assert = require('assert');51var desired = {52};53var driver = wd.remote('localhost', 4723);54driver.init(desired, function() {55    driver.title(function(err, title) {

Full Screen

Using AI Code Generation

copy

Full Screen

1import { AppiumDriver, createDriver, SearchOptions } from "nativescript-dev-appium";2describe("sample scenario", () => {3    let driver: AppiumDriver;4    before(async () => {5        driver = await createDriver();6    });7    after(async () => {8        await driver.quit();9    });10    it("should find an element", async () => {11        const searchOptions: SearchOptions = {12        };13        const helloLabel = await driver.findElementByText("hello", searchOptions);14        await helloLabel.click();15        const textField = await driver.findElementByText("TextField", SearchOptions.exact);16        await textField.sendKeys("hello world");17    });18});19import { AppiumDriver, createDriver, SearchOptions } from "nativescript-dev-appium";20describe("sample scenario", () => {21    let driver: AppiumDriver;22    before(async () => {23        driver = await createDriver();24    });25    after(async () => {26        await driver.quit();27    });28    it("should find an element", async () => {29        const searchOptions: SearchOptions = {30        };31        const helloLabel = await driver.findElementByText("hello", searchOptions);32        await helloLabel.click();33        const textField = await driver.findElementByText("TextField", SearchOptions.exact);34        await textField.sendKeys("hello world");35        const deviceTime = await driver.proxy.command("GET", "/session/:sessionId/appium/device/system_time", []);36        console.log(deviceTime);37    });38});

Full Screen

Using AI Code Generation

copy

Full Screen

1var wd = require('wd');2var assert = require('assert');3var path = require('path');4var desired = {5    "app": path.resolve('path/to/android/app'),6};

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Appium Base Driver 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