Path: blob/trunk/javascript/selenium-webdriver/test/lib/input_test.js
2885 views
// Licensed to the Software Freedom Conservancy (SFC) under one1// or more contributor license agreements. See the NOTICE file2// distributed with this work for additional information3// regarding copyright ownership. The SFC licenses this file4// to you under the Apache License, Version 2.0 (the5// "License"); you may not use this file except in compliance6// with the License. You may obtain a copy of the License at7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing,11// software distributed under the License is distributed on an12// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13// KIND, either express or implied. See the License for the14// specific language governing permissions and limitations15// under the License.1617'use strict'1819const assert = require('node:assert')20const command = require('selenium-webdriver/lib/command')21const error = require('selenium-webdriver/lib/error')22const input = require('selenium-webdriver/lib/input')23const { WebElement } = require('selenium-webdriver/lib/webdriver')2425describe('input.Actions', function () {26class StubExecutor {27constructor(...responses) {28this.responses = responses29this.commands = []30}3132execute(command) {33const name = command.getName()34const parameters = command.getParameters()35this.commands.push({ name, parameters })36return this.responses.shift() || Promise.reject(new Error('unexpected command: ' + command.getName()))37}38}3940describe('perform()', function () {41it('omits idle devices', async function () {42let executor = new StubExecutor(Promise.resolve(), Promise.resolve(), Promise.resolve(), Promise.resolve())4344await new input.Actions(executor).perform()45assert.deepStrictEqual(executor.commands, [])4647await new input.Actions(executor).pause().perform()48assert.deepStrictEqual(executor.commands, [])4950await new input.Actions(executor).pause(1).perform()51assert.deepStrictEqual(executor.commands, [52{53name: command.Name.ACTIONS,54parameters: {55actions: [56{57id: 'default keyboard',58type: 'key',59actions: [{ type: 'pause', duration: 1 }],60},61{62id: 'default mouse',63type: 'pointer',64parameters: { pointerType: 'mouse' },65actions: [{ type: 'pause', duration: 1 }],66},67{68id: 'default wheel',69type: 'wheel',70actions: [{ type: 'pause', duration: 1 }],71},72],73},74},75])7677executor.commands.length = 078let actions = new input.Actions(executor)79await actions.pause(1, actions.keyboard()).perform()80assert.deepStrictEqual(executor.commands, [81{82name: command.Name.ACTIONS,83parameters: {84actions: [85{86id: 'default keyboard',87type: 'key',88actions: [{ type: 'pause', duration: 1 }],89},90],91},92},93])94})9596it('can be called multiple times', async function () {97const executor = new StubExecutor(Promise.resolve(), Promise.resolve())98const actions = new input.Actions(executor).keyDown(input.Key.SHIFT)99100const expected = {101name: command.Name.ACTIONS,102parameters: {103actions: [104{105id: 'default keyboard',106type: 'key',107actions: [{ type: 'keyDown', value: input.Key.SHIFT }],108},109],110},111}112113await actions.perform()114assert.deepStrictEqual(executor.commands, [expected])115116await actions.perform()117assert.deepStrictEqual(executor.commands, [expected, expected])118})119})120121describe('pause()', function () {122it('defaults to all devices', async function () {123const executor = new StubExecutor(Promise.resolve())124125await new input.Actions(executor).pause(3).perform()126127assert.deepStrictEqual(executor.commands, [128{129name: command.Name.ACTIONS,130parameters: {131actions: [132{133id: 'default keyboard',134type: 'key',135actions: [{ type: 'pause', duration: 3 }],136},137{138id: 'default mouse',139type: 'pointer',140parameters: { pointerType: 'mouse' },141actions: [{ type: 'pause', duration: 3 }],142},143{144id: 'default wheel',145type: 'wheel',146actions: [147{148duration: 3,149type: 'pause',150},151],152},153],154},155},156])157})158159it('duration defaults to 0', async function () {160const executor = new StubExecutor(Promise.resolve())161162await new input.Actions(executor).pause().pause(3).perform()163164assert.deepStrictEqual(executor.commands, [165{166name: command.Name.ACTIONS,167parameters: {168actions: [169{170id: 'default keyboard',171type: 'key',172actions: [173{ type: 'pause', duration: 0 },174{ type: 'pause', duration: 3 },175],176},177{178id: 'default mouse',179type: 'pointer',180parameters: { pointerType: 'mouse' },181actions: [182{ type: 'pause', duration: 0 },183{ type: 'pause', duration: 3 },184],185},186{187id: 'default wheel',188type: 'wheel',189actions: [190{ type: 'pause', duration: 0 },191{ type: 'pause', duration: 3 },192],193},194],195},196},197])198})199200it('single device w/ synchronization', async function () {201const executor = new StubExecutor(Promise.resolve())202const actions = new input.Actions(executor)203204await actions.pause(100, actions.keyboard()).pause(100, actions.mouse()).perform()205206assert.deepStrictEqual(executor.commands, [207{208name: command.Name.ACTIONS,209parameters: {210actions: [211{212id: 'default keyboard',213type: 'key',214actions: [215{ type: 'pause', duration: 100 },216{ type: 'pause', duration: 0 },217],218},219{220id: 'default mouse',221type: 'pointer',222parameters: { pointerType: 'mouse' },223actions: [224{ type: 'pause', duration: 0 },225{ type: 'pause', duration: 100 },226],227},228],229},230},231])232})233234it('single device w/o synchronization', async function () {235const executor = new StubExecutor(Promise.resolve())236const actions = new input.Actions(executor, { async: true })237238await actions.pause(100, actions.keyboard()).pause(100, actions.mouse()).perform()239240assert.deepStrictEqual(executor.commands, [241{242name: command.Name.ACTIONS,243parameters: {244actions: [245{246id: 'default keyboard',247type: 'key',248actions: [{ type: 'pause', duration: 100 }],249},250{251id: 'default mouse',252type: 'pointer',253parameters: { pointerType: 'mouse' },254actions: [{ type: 'pause', duration: 100 }],255},256],257},258},259])260})261262it('pause a single device multiple times by specifying it multiple times', async function () {263const executor = new StubExecutor(Promise.resolve())264const actions = new input.Actions(executor)265266await actions.pause(100, actions.keyboard(), actions.keyboard()).perform()267268assert.deepStrictEqual(executor.commands, [269{270name: command.Name.ACTIONS,271parameters: {272actions: [273{274id: 'default keyboard',275type: 'key',276actions: [277{ type: 'pause', duration: 100 },278{ type: 'pause', duration: 100 },279],280},281],282},283},284])285})286})287288describe('keyDown()', function () {289it('sends normalized code point', async function () {290let executor = new StubExecutor(Promise.resolve())291292await new input.Actions(executor).keyDown('\u0041\u030a').perform()293assert.deepStrictEqual(executor.commands, [294{295name: command.Name.ACTIONS,296parameters: {297actions: [298{299id: 'default keyboard',300type: 'key',301actions: [{ type: 'keyDown', value: '\u00c5' }],302},303],304},305},306])307})308309it('rejects keys that are not a single code point', function () {310const executor = new StubExecutor(Promise.resolve())311const actions = new input.Actions(executor)312assert.throws(() => actions.keyDown('\u1E9B\u0323'), error.InvalidArgumentError)313})314})315316describe('keyUp()', function () {317it('sends normalized code point', async function () {318let executor = new StubExecutor(Promise.resolve())319320await new input.Actions(executor).keyUp('\u0041\u030a').perform()321assert.deepStrictEqual(executor.commands, [322{323name: command.Name.ACTIONS,324parameters: {325actions: [326{327id: 'default keyboard',328type: 'key',329actions: [{ type: 'keyUp', value: '\u00c5' }],330},331],332},333},334])335})336337it('rejects keys that are not a single code point', function () {338const executor = new StubExecutor(Promise.resolve())339const actions = new input.Actions(executor)340assert.throws(() => actions.keyUp('\u1E9B\u0323'), error.InvalidArgumentError)341})342})343344describe('sendKeys()', function () {345it('sends down/up for single key', async function () {346const executor = new StubExecutor(Promise.resolve())347const actions = new input.Actions(executor)348349await actions.sendKeys('a').perform()350assert.deepStrictEqual(executor.commands, [351{352name: command.Name.ACTIONS,353parameters: {354actions: [355{356id: 'default keyboard',357type: 'key',358actions: [359{ type: 'keyDown', value: 'a' },360{ type: 'keyUp', value: 'a' },361],362},363],364},365},366])367})368369it('sends down/up for vararg keys', async function () {370const executor = new StubExecutor(Promise.resolve())371const actions = new input.Actions(executor)372373await actions.sendKeys('a', 'b').perform()374assert.deepStrictEqual(executor.commands, [375{376name: command.Name.ACTIONS,377parameters: {378actions: [379{380id: 'default keyboard',381type: 'key',382actions: [383{ type: 'keyDown', value: 'a' },384{ type: 'keyUp', value: 'a' },385{ type: 'keyDown', value: 'b' },386{ type: 'keyUp', value: 'b' },387],388},389],390},391},392])393})394395it('sends down/up for multichar strings in varargs', async function () {396const executor = new StubExecutor(Promise.resolve())397const actions = new input.Actions(executor)398399await actions.sendKeys('a', 'bc', 'd').perform()400assert.deepStrictEqual(executor.commands, [401{402name: command.Name.ACTIONS,403parameters: {404actions: [405{406id: 'default keyboard',407type: 'key',408actions: [409{ type: 'keyDown', value: 'a' },410{ type: 'keyUp', value: 'a' },411{ type: 'keyDown', value: 'b' },412{ type: 'keyUp', value: 'b' },413{ type: 'keyDown', value: 'c' },414{ type: 'keyUp', value: 'c' },415{ type: 'keyDown', value: 'd' },416{ type: 'keyUp', value: 'd' },417],418},419],420},421},422])423})424425it('synchronizes with other devices', async function () {426const executor = new StubExecutor(Promise.resolve())427const actions = new input.Actions(executor)428429await actions.sendKeys('ab').pause(100, actions.mouse()).perform()430assert.deepStrictEqual(executor.commands, [431{432name: command.Name.ACTIONS,433parameters: {434actions: [435{436id: 'default keyboard',437type: 'key',438actions: [439{ type: 'keyDown', value: 'a' },440{ type: 'keyUp', value: 'a' },441{ type: 'keyDown', value: 'b' },442{ type: 'keyUp', value: 'b' },443{ type: 'pause', duration: 0 },444],445},446{447id: 'default mouse',448type: 'pointer',449parameters: { pointerType: 'mouse' },450actions: [451{ type: 'pause', duration: 0 },452{ type: 'pause', duration: 0 },453{ type: 'pause', duration: 0 },454{ type: 'pause', duration: 0 },455{ type: 'pause', duration: 100 },456],457},458],459},460},461])462})463464it('without device synchronization', async function () {465const executor = new StubExecutor(Promise.resolve())466const actions = new input.Actions(executor, { async: true })467468await actions.sendKeys('ab').pause(100, actions.mouse()).perform()469assert.deepStrictEqual(executor.commands, [470{471name: command.Name.ACTIONS,472parameters: {473actions: [474{475id: 'default keyboard',476type: 'key',477actions: [478{ type: 'keyDown', value: 'a' },479{ type: 'keyUp', value: 'a' },480{ type: 'keyDown', value: 'b' },481{ type: 'keyUp', value: 'b' },482],483},484{485id: 'default mouse',486type: 'pointer',487parameters: { pointerType: 'mouse' },488actions: [{ type: 'pause', duration: 100 }],489},490],491},492},493])494})495496it('string length > 500', async function () {497const executor = new StubExecutor(Promise.resolve())498const actions = new input.Actions(executor, { async: true })499let str = ''500for (let i = 0; i < 501; i++) {501str += i502}503const executionResult = await actions504.sendKeys(str)505.perform()506.then(() => true)507.catch(() => false)508assert.strictEqual(executionResult, true)509})510})511512describe('click()', function () {513it('clicks immediately if no element provided', async function () {514const executor = new StubExecutor(Promise.resolve())515const actions = new input.Actions(executor)516517await actions.click().perform()518assert.deepStrictEqual(executor.commands, [519{520name: command.Name.ACTIONS,521parameters: {522actions: [523{524id: 'default mouse',525type: 'pointer',526parameters: { pointerType: 'mouse' },527actions: [528{529type: 'pointerDown',530button: input.Button.LEFT,531altitudeAngle: 0,532azimuthAngle: 0,533width: 0,534height: 0,535pressure: 0,536tangentialPressure: 0,537tiltX: 0,538tiltY: 0,539twist: 0,540},541{ type: 'pointerUp', button: input.Button.LEFT },542],543},544],545},546},547])548})549550it('moves to target element before clicking', async function () {551const executor = new StubExecutor(Promise.resolve())552const actions = new input.Actions(executor)553554const fakeElement = {}555556await actions.click(fakeElement).perform()557assert.deepStrictEqual(executor.commands, [558{559name: command.Name.ACTIONS,560parameters: {561actions: [562{563id: 'default mouse',564type: 'pointer',565parameters: { pointerType: 'mouse' },566actions: [567{568type: 'pointerMove',569origin: fakeElement,570duration: 100,571x: 0,572y: 0,573altitudeAngle: 0,574azimuthAngle: 0,575width: 0,576height: 0,577pressure: 0,578tangentialPressure: 0,579tiltX: 0,580tiltY: 0,581twist: 0,582},583{584type: 'pointerDown',585button: input.Button.LEFT,586altitudeAngle: 0,587azimuthAngle: 0,588width: 0,589height: 0,590pressure: 0,591tangentialPressure: 0,592tiltX: 0,593tiltY: 0,594twist: 0,595},596{ type: 'pointerUp', button: input.Button.LEFT },597],598},599],600},601},602])603})604605it('synchronizes with other devices', async function () {606const executor = new StubExecutor(Promise.resolve())607const actions = new input.Actions(executor)608609const fakeElement = {}610611await actions.click(fakeElement).sendKeys('a').perform()612assert.deepStrictEqual(executor.commands, [613{614name: command.Name.ACTIONS,615parameters: {616actions: [617{618id: 'default keyboard',619type: 'key',620actions: [621{ type: 'pause', duration: 0 },622{ type: 'pause', duration: 0 },623{ type: 'pause', duration: 0 },624{ type: 'keyDown', value: 'a' },625{ type: 'keyUp', value: 'a' },626],627},628{629id: 'default mouse',630type: 'pointer',631parameters: { pointerType: 'mouse' },632actions: [633{634type: 'pointerMove',635origin: fakeElement,636duration: 100,637x: 0,638y: 0,639altitudeAngle: 0,640azimuthAngle: 0,641width: 0,642height: 0,643pressure: 0,644tangentialPressure: 0,645tiltX: 0,646tiltY: 0,647twist: 0,648},649{650type: 'pointerDown',651button: input.Button.LEFT,652altitudeAngle: 0,653azimuthAngle: 0,654width: 0,655height: 0,656pressure: 0,657tangentialPressure: 0,658tiltX: 0,659tiltY: 0,660twist: 0,661},662{ type: 'pointerUp', button: input.Button.LEFT },663{ type: 'pause', duration: 0 },664{ type: 'pause', duration: 0 },665],666},667],668},669},670])671})672})673674describe('dragAndDrop', function () {675it('dragAndDrop(fromEl, toEl)', async function () {676const executor = new StubExecutor(Promise.resolve())677const actions = new input.Actions(executor)678const e1 = new WebElement(null, 'abc123')679const e2 = new WebElement(null, 'def456')680681await actions.dragAndDrop(e1, e2).perform()682683assert.deepStrictEqual(executor.commands, [684{685name: command.Name.ACTIONS,686parameters: {687actions: [688{689id: 'default mouse',690type: 'pointer',691parameters: { pointerType: 'mouse' },692actions: [693{694type: 'pointerMove',695duration: 100,696origin: e1,697x: 0,698y: 0,699altitudeAngle: 0,700azimuthAngle: 0,701width: 0,702height: 0,703pressure: 0,704tangentialPressure: 0,705tiltX: 0,706tiltY: 0,707twist: 0,708},709{710type: 'pointerDown',711button: input.Button.LEFT,712altitudeAngle: 0,713azimuthAngle: 0,714width: 0,715height: 0,716pressure: 0,717tangentialPressure: 0,718tiltX: 0,719tiltY: 0,720twist: 0,721},722{723type: 'pointerMove',724duration: 100,725origin: e2,726x: 0,727y: 0,728altitudeAngle: 0,729azimuthAngle: 0,730width: 0,731height: 0,732pressure: 0,733tangentialPressure: 0,734tiltX: 0,735tiltY: 0,736twist: 0,737},738{ type: 'pointerUp', button: input.Button.LEFT },739],740},741],742},743},744])745})746747it('dragAndDrop(el, offset)', async function () {748const executor = new StubExecutor(Promise.resolve())749const actions = new input.Actions(executor)750const e1 = new WebElement(null, 'abc123')751752await actions.dragAndDrop(e1, { x: 30, y: 40 }).perform()753754assert.deepStrictEqual(executor.commands, [755{756name: command.Name.ACTIONS,757parameters: {758actions: [759{760id: 'default mouse',761type: 'pointer',762parameters: { pointerType: 'mouse' },763actions: [764{765type: 'pointerMove',766duration: 100,767origin: e1,768x: 0,769y: 0,770altitudeAngle: 0,771azimuthAngle: 0,772width: 0,773height: 0,774pressure: 0,775tangentialPressure: 0,776tiltX: 0,777tiltY: 0,778twist: 0,779},780{781type: 'pointerDown',782button: input.Button.LEFT,783altitudeAngle: 0,784azimuthAngle: 0,785width: 0,786height: 0,787pressure: 0,788tangentialPressure: 0,789tiltX: 0,790tiltY: 0,791twist: 0,792},793{794type: 'pointerMove',795duration: 100,796origin: input.Origin.POINTER,797x: 30,798y: 40,799altitudeAngle: 0,800azimuthAngle: 0,801width: 0,802height: 0,803pressure: 0,804tangentialPressure: 0,805tiltX: 0,806tiltY: 0,807twist: 0,808},809{ type: 'pointerUp', button: input.Button.LEFT },810],811},812],813},814},815])816})817818it('throws if target is invalid', async function () {819const executor = new StubExecutor(Promise.resolve())820const actions = new input.Actions(executor)821const e = new WebElement(null, 'abc123')822823assert.throws(() => actions.dragAndDrop(e), error.InvalidArgumentError)824assert.throws(() => actions.dragAndDrop(e, null), error.InvalidArgumentError)825assert.throws(() => actions.dragAndDrop(e, {}), error.InvalidArgumentError)826assert.throws(() => actions.dragAndDrop(e, { x: 0 }), error.InvalidArgumentError)827assert.throws(() => actions.dragAndDrop(e, { y: 0 }), error.InvalidArgumentError)828assert.throws(() => actions.dragAndDrop(e, { x: 0, y: 'a' }), error.InvalidArgumentError)829assert.throws(() => actions.dragAndDrop(e, { x: 'a', y: 0 }), error.InvalidArgumentError)830})831})832})833834835