When should element.all(locator).then(thenFunction) or element.all(locator) be used?

試著忘記壹切 提交于 2021-02-04 21:38:57

问题


In protractor, what's the difference between (source):

Example 1

const allOptions = element.all(by.options('fruit for fruit in fruits'));
expect(await allOptions.count()).toEqual(4);

and (source):

Example 2

const arr = await element.all(by.model('color'));
expect(arr.length).toEqual(3);

Why if I do...

Example 3

let allOptions = await element.all(by.css('.mat-option-text > span'));
let firstOption = allOptions.first();

...I get this static typescript error?

Property 'first' does not exist on type 'any[] | ElementFinder[]'. Property 'first' does not exist on type 'any[]'.ts(2339)


What is the correct usage of element.all(locator).then(thenFunction) and element.all(locator)?


回答1:


Essentially, element.all returns an ElementArrayFinder object but await element.all will return an array of ElementFinder objects.

An awaited ElementArrayFinder is simple an array of ElementFinder objects and therefore can call all existing array methods (such as length). An unawaited ElementArrayFinder is a special object defined withing protractor and has special methods available to it (such as count(), get() and first()).

The methods available to ElementArrayFinder are listed in the protractor api.

Example

For this example go to the page https://angular.io/. $([class="button hero-cta"]) only finds one element on this page

console.log(element.all('[class="button hero-cta"]')) will return the following ElementArrayFinder object

ElementArrayFinder {
  browser_: ProtractorBrowser {
    controlFlow: [Function],
    schedule: [Function],
    setFileDetector: [Function],
    getExecutor: [Function],
    getSession: [Function],
    getCapabilities: [Function],
    quit: [Function],
    actions: [Function],
    touchActions: [Function],
    executeScript: [Function],
    executeAsyncScript: [Function],
    call: [Function],
    wait: [Function],
    sleep: [Function],
    getWindowHandle: [Function],
    getAllWindowHandles: [Function],
    getPageSource: [Function],
    close: [Function],
    getCurrentUrl: [Function],
    getTitle: [Function],
    findElementInternal_: [Function],
    findElementsInternal_: [Function],
    takeScreenshot: [Function],
    manage: [Function],
    switchTo: [Function],
    driver: thenableWebDriverProxy {
      flow_: [ControlFlow],
      session_: [ManagedPromise],
      executor_: [Executor],
      fileDetector_: null,
      onQuit_: undefined,
      cancel: [Function],
      then: [Function: bound then],
      catch: [Function: bound then],
      getNetworkConnection: [Function],
      setNetworkConnection: [Function],
      toggleAirplaneMode: [Function],
      toggleWiFi: [Function],
      toggleData: [Function],
      toggleLocationServices: [Function],
      getGeolocation: [Function],
      setGeolocation: [Function],
      getCurrentDeviceActivity: [Function],
      startDeviceActivity: [Function],
      getAppiumSettings: [Function],
      setAppiumSettings: [Function],
      getCurrentContext: [Function],
      selectContext: [Function],
      getScreenOrientation: [Function],
      setScreenOrientation: [Function],
      isDeviceLocked: [Function],
      lockDevice: [Function],
      unlockDevice: [Function],
      installApp: [Function],
      isAppInstalled: [Function],
      removeApp: [Function],
      pullFileFromDevice: [Function],
      pullFolderFromDevice: [Function],
      pushFileToDevice: [Function],
      listContexts: [Function],
      uploadFile: [Function],
      switchToParentFrame: [Function],
      fullscreen: [Function],
      sendAppToBackground: [Function],
      closeApp: [Function],
      getAppStrings: [Function],
      launchSession: [Function],
      resetApp: [Function],
      hideSoftKeyboard: [Function],
      getDeviceTime: [Function],
      openDeviceNotifications: [Function],
      rotationGesture: [Function],
      shakeDevice: [Function],
      sendChromiumCommand: [Function],
      sendChromiumCommandAndGetResult: [Function]
    },
    element: [Function: element] { all: [Function] },
    '$': [Function],
    '$$': [Function],
    baseUrl: '',
    getPageTimeout: 10000,
    params: {},
    resetUrl: 'data:text/html,<html></html>',
    debugHelper: DebugHelper { browserUnderDebug_: [Circular] },
    ready: ManagedPromise {
      flow_: [ControlFlow],
      stack_: null,
      parent_: null,
      callbacks_: null,
      state_: 'fulfilled',
      handled_: true,
      value_: [Circular],
      queue_: null
    },
    trackOutstandingTimeouts_: true,
    mockModules_: [ [Object] ],
    ExpectedConditions: ProtractorExpectedConditions { browser: [Circular] },
    plugins_: Plugins {
      setup: [Function],
      onPrepare: [Function],
      teardown: [Function],
      postResults: [Function],
      postTest: [Function],
      onPageLoad: [Function],
      onPageStable: [Function],
      waitForPromise: [Function],
      waitForCondition: [Function],
      pluginObjs: [],
      assertions: {},
      resultsReported: false
    },
    allScriptsTimeout: 11000,
    getProcessedConfig: [Function],
    forkNewDriverInstance: [Function],
    restart: [Function],
    restartSync: [Function],
    internalRootEl: '',
    internalIgnoreSynchronization: true
  },
  getWebElements: [Function: getWebElements],
  locator_: name(name) {
    return By.css('*[name="' + escapeCss(name) + '"]');
  } {
    using: 'css selector',
    value: '[class="button hero-cta"]'
  },
  actionResults_: null,
  click: [Function],
  sendKeys: [Function],
  getTagName: [Function],
  getCssValue: [Function],
  getAttribute: [Function],
  getText: [Function],
  getSize: [Function],
  getLocation: [Function],
  isEnabled: [Function],
  isSelected: [Function],
  submit: [Function],
  clear: [Function],
  isDisplayed: [Function],
  getId: [Function],
  takeScreenshot: [Function]
}

console.log(await element.all('[class="button hero-cta"]')) will return an array of ElementFinder Objects

[
  ElementFinder {
    browser_: ProtractorBrowser {
      controlFlow: [Function],
      schedule: [Function],
      setFileDetector: [Function],
      getExecutor: [Function],
      getSession: [Function],
      getCapabilities: [Function],
      quit: [Function],
      actions: [Function],
      touchActions: [Function],
      executeScript: [Function],
      executeAsyncScript: [Function],
      call: [Function],
      wait: [Function],
      sleep: [Function],
      getWindowHandle: [Function],
      getAllWindowHandles: [Function],
      getPageSource: [Function],
      close: [Function],
      getCurrentUrl: [Function],
      getTitle: [Function],
      findElementInternal_: [Function],
      findElementsInternal_: [Function],
      takeScreenshot: [Function],
      manage: [Function],
      switchTo: [Function],
      driver: [thenableWebDriverProxy],
      element: [Function],
      '$': [Function],
      '$$': [Function],
      baseUrl: '',
      getPageTimeout: 10000,
      params: {},
      resetUrl: 'data:text/html,<html></html>',
      debugHelper: [DebugHelper],
      ready: [ManagedPromise],
      trackOutstandingTimeouts_: true,
      mockModules_: [Array],
      ExpectedConditions: [ProtractorExpectedConditions],
      plugins_: [Plugins],
      allScriptsTimeout: 11000,
      getProcessedConfig: [Function],
      forkNewDriverInstance: [Function],
      restart: [Function],
      restartSync: [Function],
      internalRootEl: '',
      internalIgnoreSynchronization: true
    },
    then: null,
    parentElementArrayFinder: ElementArrayFinder {
      browser_: [ProtractorBrowser],
      getWebElements: [Function: getWebElements],
      locator_: [name(name) {
    return By.css('*[name="' + escapeCss(name) + '"]');
  }],
      actionResults_: null,
      click: [Function],
      sendKeys: [Function],
      getTagName: [Function],
      getCssValue: [Function],
      getAttribute: [Function],
      getText: [Function],
      getSize: [Function],
      getLocation: [Function],
      isEnabled: [Function],
      isSelected: [Function],
      submit: [Function],
      clear: [Function],
      isDisplayed: [Function],
      getId: [Function],
      takeScreenshot: [Function]
    },
    elementArrayFinder_: ElementArrayFinder {
      browser_: [ProtractorBrowser],
      getWebElements: [Function: getWebElements],
      locator_: [name(name) {
    return By.css('*[name="' + escapeCss(name) + '"]');
  }],
      actionResults_: null,
      click: [Function],
      sendKeys: [Function],
      getTagName: [Function],
      getCssValue: [Function],
      getAttribute: [Function],
      getText: [Function],
      getSize: [Function],
      getLocation: [Function],
      isEnabled: [Function],
      isSelected: [Function],
      submit: [Function],
      clear: [Function],
      isDisplayed: [Function],
      getId: [Function],
      takeScreenshot: [Function]
    },
    click: [Function],
    sendKeys: [Function],
    getTagName: [Function],
    getCssValue: [Function],
    getAttribute: [Function],
    getText: [Function],
    getSize: [Function],
    getLocation: [Function],
    isEnabled: [Function],
    isSelected: [Function],
    submit: [Function],
    clear: [Function],
    isDisplayed: [Function],
    getId: [Function],
    takeScreenshot: [Function]
  }
]
.


1 spec, 0 failures
Finished in 3.881 seconds

[13:33:25] I/local - Shutting down selenium standalone server.
[13:33:25] I/launcher - 0 instance(s) of WebDriver still running
[13:33:25] I/launcher - chrome #01 passed

C:\ProtractorProjects\ddg>



回答2:


I think you don't have clear understanding what each one does...

element(...) - returns ElementFinder (one element)

element.all(...) - returns ElementArrayFinder (many elements)

both are used to point to the element. Then you'd like to interact with them - click, get count, get text etc... whatever you would want to do with them are Promises. So

element().count() or element().getText() - return a Promise

Promise essentially is nothing... because it may be resolved later, may be pending, may be rejected (it's not nothing in fact, but easier to think of it this way)

await keyword resolves a Promise and returns a value, which will be a number for .count() or a string for .getText()

so what you should be doing is this

// declare an element
let elem = element(by.css('some css'));

// then you declare a promise and resolve it
let value = await elem.getText()
// or
await elem.click()


来源:https://stackoverflow.com/questions/60165939/when-should-element-alllocator-thenthenfunction-or-element-alllocator-be-u

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!