Skip to content
This repository has been archived by the owner on Dec 18, 2019. It is now read-only.

webdriverio getAttribute crashes when attribute is not set #43

Open
NiGhTTraX opened this issue Jan 13, 2017 · 13 comments
Open

webdriverio getAttribute crashes when attribute is not set #43

NiGhTTraX opened this issue Jan 13, 2017 · 13 comments
Labels

Comments

@NiGhTTraX
Copy link

NiGhTTraX commented Jan 13, 2017

Reproduction steps

<input type="checkbox">
<input type="checkbox">
$$('input[type=checkbox]').getAttribute('checked');

crashes with

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1):
TypeError: Cannot read property 'ELEMENT' of null

Debugging

By catching unhandled rejections in my code with

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
});

I got a stack trace of

Unhandled Rejection at: Promise Promise {
  <rejected> TypeError: Cannot read property 'ELEMENT' of null
    at is$$Result (/usr/src/app/node_modules/wdio-sync/build/index.js:506:63)
    at Object.applyPrototype (/usr/src/app/node_modules/wdio-sync/build/index.js:535:105)
    at Object.<anonymous> (/usr/src/app/node_modules/wdio-sync/build/index.js:452:58)
    at Object.exec (/usr/src/app/node_modules/webdriverio/build/lib/helpers/safeExecute.js:28:24)
    at Object.resolve (/usr/src/app/node_modules/webdriverio/build/lib/webdriverio.js:193:29)
    at /usr/src/app/node_modules/webdriverio/build/lib/webdriverio.js:503:32
    at _fulfilled (/usr/src/app/node_modules/q/q.js:834:54)
    at self.promiseDispatch.done (/usr/src/app/node_modules/q/q.js:863:30)
    at Promise.promise.promiseDispatch (/usr/src/app/node_modules/q/q.js:796:13)
    at /usr/src/app/node_modules/q/q.js:604:44 }

That leads us to is$$Result which checks if the result is an array of objects that have an .ELEMENT property. The problem is that getAttribute will return null when the attribute is not set, hence the Cannot read property 'ELEMENT' of null error.

@NiGhTTraX
Copy link
Author

My solution is to check result[0] before trying to access .ELEMENT on it. Here's a PR with the fix.

@NiGhTTraX
Copy link
Author

In the mean time, you can use

$$('input[type=checkbox]').map(c => c.getAttribute('checked'))

@christian-bromann
Copy link
Contributor

@NiGhTTraX thanks for filing the issue. Using the $$ command like this ($$('input[type=checkbox]').getAttribute('checked');) is not correct. The $$ command returns an array of elements. You can't call commands on the array type (I would need to modify the array prototype which I don't want do). So to get all attributes you can either do:

$$('input[type=checkbox]').map(c => c.getAttribute('checked'))

or

browser.getAttribute('input[type=checkbox]', 'checked')

@NiGhTTraX
Copy link
Author

@christian-bromann $$('...').getAttribute('...') works when every selected element has the attribute set. It just doesn't work when the elements (or at least the first one) doesn't have it. Even the docs show that it can be used in that way.

@christian-bromann
Copy link
Contributor

Even the docs show that it can be used in that way.

This is a bug in the docs then. I don't like $$('...').getAttribute as it overwrites the Array prototype here

@NiGhTTraX
Copy link
Author

I don't like $$('...').getAttribute as it overwrites the Array prototype here

Ok. Just letting you know that it's currently happening anyway:

[17:23:50]  DEBUG	Queue has stopped!
[17:23:50]  DEBUG	You can now go into the browser or use the command line as REPL
[17:23:50]  DEBUG	(To exit, press ^C again or type .exit)

> browser.elements('.toggle')
{ state: 'success',
  sessionId: 'dd9d44b1-91a4-412e-b611-79adbb8fcb64',
  hCode: 79051361,
  value: 
   [ { ELEMENT: '2', selector: '.toggle', value: [Object], index: 0 },
     { ELEMENT: '3', selector: '.toggle', value: [Object], index: 1 },
     { ELEMENT: '4', selector: '.toggle', value: [Object], index: 2 } ],
  class: 'org.openqa.selenium.remote.Response',
  selector: '.toggle',
  _status: 0 }

> browser.elements('.toggle').getAttribute
[Function: bound ]

@christian-bromann
Copy link
Contributor

This command

browser.elements('.toggle')

returns an object though whereas

> $$(".runyourtests a")
[ { ELEMENT: '21',
    selector: '.runyourtests a',
    value: { ELEMENT: '21' },
    index: 0 },
  { ELEMENT: '22',
    selector: '.runyourtests a',
    value: { ELEMENT: '22' },
    index: 1 },
  { ELEMENT: '23',
    selector: '.runyourtests a',
    value: { ELEMENT: '23' },
    index: 2 } ]

doesn't

@NiGhTTraX
Copy link
Author

Ah, you're right. I think I wrote $$ out of reflex, but the problem is actually with browser.elements:

> browser.elements('input[type=checkbox]').getAttribute('checked')
(node:22) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'ELEMENT' of null
(node:22) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

So to get all attributes you can either do:
browser.getAttribute('input[type=checkbox]', 'checked')

> browser.getAttribute('input[type=checkbox]', 'checked')
(node:22) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'ELEMENT' of null
(node:22) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

@NiGhTTraX
Copy link
Author

@christian-bromann so is the fix in #44 not good?

@christian-bromann
Copy link
Contributor

Not sure what this error is about but I was not able to reproduce this with wdio (latest):

describe('Mocha Spec Sync example', function() {
    it("follows link to new page", function() {
        browser.url('http://webdriverjs.christian-bromann.com/');

        var selector = 'input[type=checkbox]';
        console.log($$(selector).length, 'elements found');
        console.log(browser.getAttribute(selector, 'checked'));
	console.log(browser.elements(selector).getAttribute('checked'));
    });
});

returns:

$ ./bin/wdio wdio.conf.js

2 'elements found'
[ 'true', null ]
[ 'true', null ]
․

1 passing (4.60s)

@NiGhTTraX
Copy link
Author

@christian-bromann the problem only occurs when the first matched element doesn't have the attribute you're trying to get. In your example the first checkbox is checked. I can still reproduce the issue with

    "wdio": "~0.3.3",
    "wdio-mocha-framework": "~0.5.8",
    "webdriverio": "~4.6.2",

@christian-bromann
Copy link
Contributor

Reopening. If the input is actually

<input type="checkbox">

The execution gets stuck somewhere (probably due to an supressed error in WebdriverIO. Maybe because of TypeError: Cannot read property 'ELEMENT' of null

@NiGhTTraX
Copy link
Author

@christian-bromann please see #44 for a fix.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants