fypnlp
fypnlp

Reputation: 1547

Protractor> TypeError: item.element is not a function

I'm working on an ecommerce project on protractor and I can't honestly figure out what went wrong with the IT case. I got the following error

Failed: item.element is not a function[0m
  Stack:
    TypeError: item.element is not a function

I've been pulling my hair out for the last day but the console isn't clear about the specific problem. Cause I've checked and can't see the issue.

Question: what is this? How do I fix this?

The code from the course is as messy as hell, so I will tidy it up for you.

code

describe('Ecommerce Angular Project', function () {

it('Customer Shopping cart', function () {
    // write your code here!!!

  function selectItem(product) {
      //chain the locators so that you can pick a specific item regardless of where it is located

      element.all(by.tagName("app-card")).then(function (item) {

          item.element(by.css("h4 a")).getText().then(function (text) {

              if (text == "Samsung Note 8") {
                  // add to cart button if loop is correct. 
                  item.element(By.css("button[class*='btn-info']")).click();                           
              } //end of if Loop 


          })//END: this promise add to cart button for samsung

      })//end of command to find samsung 8

  }

  it('Customer registration', function () {
      // write your code here!!!

      //Scenario 3:  Go Shop page and add items to shopping cart

      //Given I am on the home page
      //when I select the shop link 
      //Then I am taken to the shop page
      //When I am in the shop page I select a mobile phone
      //Then the shopping cart  will show 1 item added
      //When I add another mobile phone to the shopping cart 
      //Then the shopping cart  will show 2 items added

      element(by.linkText("Shop")).click();

      //Select 2 items for shopping cart

      selectItem("Samsung Note 8");
      selectItem("iphone X");

      // I want to display the results and confirm there are only 2 items in the shopping cart
      element(by.partialLinkText("Checkout")).getText().then(function (text) {

          // I want to show both items in the console on a separate line confirm that it 2 items
          var res = text.split("(");
          expect(res[1].trim().charAt(0)).toBe("2");

      })//END: this function will display items in console from shopping bag

  })    //end of customer registration & shopping  it block 
})//end of describe block

Message from console

(note there were IT cases in this spec file and they passed but once, so ignore those message, but when came the IT scenario that's were things went very wrong)

(node:10145) [DEP0022] DeprecationWarning: os.tmpDir() is deprecated. Use os.tmpdir() instead.
[16:34:32] I/launcher - Running 1 instances of WebDriver
[16:34:32] I/hosted - Using the selenium server at http://localhost:4444/wd/hub
Started
[16:34:36] W/element - more than one element found for locator By(css selector, *[name="name"]) - the first result will be used
×
Success! The Form has been submitted successfully!.
[16:34:37] W/element - more than one element found for locator By(css selector, *[name="name"]) - the first result will be used
[16:34:37] W/element - more than one element found for locator By(css selector, *[name="name"]) - the first result will be used
Name should be at least 2 characters
[31mF[0m

Failures:
1) Ecommerce Angular Project Customer registration
  Message:
[31m    Failed: item.element is not a function[0m
  Stack:
    TypeError: item.element is not a function
        at /Users/xxx/Documents/JSworkspace/LocatorTraining/ecommerceAutomation.js:10:12
        at ManagedPromise.invokeCallback_ (/Users/xxx/Documents/JSworkspace/LocatorTraining/protractor/node_modules/selenium-webdriver/lib/promise.js:1376:14)
        at TaskQueue.execute_ (/Users/xxx/Documents/JSworkspace/LocatorTraining/protractor/node_modules/selenium-webdriver/lib/promise.js:3084:14)
        at TaskQueue.executeNext_ (/Users/xxx/Documents/JSworkspace/LocatorTraining/protractor/node_modules/selenium-webdriver/lib/promise.js:3067:27)
        at asyncRun (/Users/xxx/Documents/JSworkspace/LocatorTraining/protractor/node_modules/selenium-webdriver/lib/promise.js:2927:27)
        at /Users/xxx/Documents/JSworkspace/LocatorTraining/protractor/node_modules/selenium-webdriver/lib/promise.js:668:7
        at <anonymous>
        at process._tickCallback (internal/process/next_tick.js:188:7)
    From: Task: Run it("Customer registration") in control flow
        at UserContext.<anonymous> (/Users/xxx/Documents/JSworkspace/LocatorTraining/protractor/node_modules/jasminewd2/index.js:94:19)
    From asynchronous test: 
    Error
        at Suite.<anonymous> (/Users/xxx/Documents/JSworkspace/LocatorTraining/ecommerceAutomation.js:27:2)
        at Object.<anonymous> (/Users/xxx/Documents/JSworkspace/LocatorTraining/ecommerceAutomation.js:1:63)
        at Module._compile (module.js:652:30)
        at Object.Module._extensions..js (module.js:663:10)
        at Module.load (module.js:565:32)
        at tryModuleLoad (module.js:505:12)

1 spec, 1 failure
Finished in 3.801 seconds

[16:34:38] I/launcher - 0 instance(s) of WebDriver still running
[16:34:38] I/launcher - chrome #01 failed 1 test(s)
[16:34:38] I/launcher - overall: 1 failed spec(s)
[16:34:38] E/launcher - Process exited with error code 1

Upvotes: 0

Views: 2587

Answers (1)

yong
yong

Reputation: 13712

element.all() returns ElementArrayFinder, you can think it as an array of element. Therefore the item in the then() represents an array, rather than a single element.

element.all(by.tagName("app-card")).then(function (item) {
    item.element(...)
    ...
})

You can't call .element() on an array object. But you can call .element() on single element as following:

element.all(by.tagName("app-card")).then(function (items) {
    items[0].element(...) // items[0] is single element.
    ...
})

For your case, the function selectItem should change as following:

function selectItem(product) {
    //chain the locators so that you can pick a specific item regardless of where it is located

    element.all(by.tagName("app-card")).filter(function(item){
        return item.element(by.css("h4 a")).getText().then(function(txt){
            return txt === product;
        });
    }).then(function(items){
        if(items.length > 0) {
            items[0].element(by.css("button[class*='btn-info']")).click();
        }
        else {
            console.error('Not find product: ' + product);
        }
    }).catch(function(err){
       console.error(err);
    });
}

Upvotes: 2

Related Questions