【问题标题】:When should element.all(locator).then(thenFunction) or element.all(locator) be used?什么时候应该使用 element.all(locator).then(thenFunction) 或 element.all(locator)?
【发布时间】:2020-02-11 22:12:18
【问题描述】:

在量角器中,(source)有什么区别:

示例 1

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

和(source):

示例 2

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

如果我这样做...

示例 3

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

...我收到这个静态打字错误?

类型“any[] 上不存在属性“first”|元素查找器 []'。类型“any[]”上不存在属性“first”。ts(2339)


element.all(locator).then(thenFunction)element.all(locator)的正确用法是什么?

【问题讨论】:

  • 我认为您不应该在element.all 部分之前使用await。除非这是一个需要解决的承诺(例如count)。
  • @JoaquinCasco 所以示例 2 中的 await 没用?我说的对吗?
  • 是的。 await 应该在 arr.length 之前 -> expect(await arr.length).toEqual(3);
  • @JoaquinCasco arr.length 没有返回承诺,你能解释一下为什么在这种情况下我们需要await 吗?非常感谢。

标签: typescript protractor angular-e2e


【解决方案1】:

基本上,element.all 返回一个ElementArrayFinder 对象,但await element.all 将返回一个ElementFinder 对象数组。

等待的 ElementArrayFinder 是一个简单的 ElementFinder 对象数组,因此可以调用所有现有的array methods(例如长度)。未等待的 ElementArrayFinder 是使用量角器定义的特殊对象,并且具有可用的特殊方法(例如 count()、get() 和 first())。

Protractor api 中列出了 ElementArrayFinder 可用的方法。

示例

对于此示例,请转到页面https://angular.io/$([class="button hero-cta"]) 在这个页面上只找到一个元素

console.log(element.all('[class="button hero-cta"]')) 将返回以下 ElementArrayFinder 对象

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"]')) 将返回一个 ElementFinder 对象数组

[
  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】:

    我认为您并没有清楚地了解每个人的作用......

    element(...) - 返回 ElementFinder(一个元素)

    element.all(...) - 返回 ElementArrayFinder(许多元素)

    两者都用于指向元素。然后你想和他们互动——点击、获取计数、获取文本等……你想对他们做的任何事情都是 Promise。所以

    element().count()element().getText() - 返回一个 Promise

    Promise 本质上什么都不是……因为它可能会在稍后解决,可能会等待处理,可能会被拒绝(实际上并不是什么都不是,但这样想起来更容易)

    await 关键字解析 Promise 并返回一个值,该值将是 .count() 的数字或 .getText() 的字符串

    所以你应该做的是这个

    // 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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-15
      • 1970-01-01
      • 1970-01-01
      • 2016-12-26
      • 2012-03-23
      • 1970-01-01
      • 2020-10-20
      • 2023-04-02
      相关资源
      最近更新 更多