Access window object / browser scope from protractor - selenium

I'm running tests with protractor, but it seems impossible to access the JS 'window' object. I even tried adding a tag in my html file that would contain something like
var a = window.location;
and then try expect(a) but I couldn't make it work, I always get undefined references...
How should I process to access variables that are in the browser scope ?

Assuming you are using a recent version of Protractor, let's say >= 1.1.0, hopefully >= 1.3.1
Attempting to access Browser side JS code directly from Protractor won't work because Protractor runs in NodeJS and every Browser side code is executed through Selenium JsonWireProtocol.
Without further detail, a working example:
browser.get('https://angularjs.org/');
One-liner promise that, as of today, resolves to '1.3.0-rc.3'
browser.executeScript('return window.angular.version.full;');
You can use it directly in an expect statement given Protractor's expect resolves promises for you:
expect(browser.executeScript('return window.angular.version.full;')).
toEqual('1.3.0-rc.3');
Longer example passing a function instead of a string plus without expect resolving the promise for you. i.e. for more control and for doing some fancy thing with the result.
browser.driver.executeScript(function() {
return window.angular.version.full;
}).then(function(result) {
console.log('NodeJS-side console log result: ' + result);
//=> NodeJS-side console log result: 1.3.0-rc.3
});

Related

TypeError: userAgent.toLowerCase is not a function

While running Angular-unit test, using chrome browser, ended up with the error as
TypeError: userAgent.toLowerCase is not a function
at _isAndroid (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/forms/fesm2015/forms.mjs:176:43)
at new DefaultValueAccessor (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/forms/fesm2015/forms.mjs:227:38)
at NodeInjectorFactory.factory (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/forms/fesm2015/forms.mjs:254:1)
at getNodeInjectable (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/core/fesm2015/core.mjs:3565:44)
at instantiateAllDirectives (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/core/fesm2015/core.mjs:10318:27)
at createDirectivesInstances (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/core/fesm2015/core.mjs:9647:5)
at ɵɵelementStart (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/core/fesm2015/core.mjs:14561:9)
at templateFn (ng:///TodaysMarketMoversComponent.js:397:66)
at executeTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/core/fesm2015/core.mjs:9618:9)
at renderView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/#angular/core/fesm2015/core.mjs:9421:13)
Most wondering/confusing part to me- toLowerCase function has never been used through out the component/spec file.
It looks like the userAgent is being checked by the #angular/forms lib and has been deleted or not provided at all for some reason.
If it's not your code that's changing the userAgent then it's probably some third-party script.
If I were you I'd start with the latest additions in terms of libraries and dependencies and peel them back until I get a unit test running. That will give the clue.

Selenium request returns error 400 - Bad request

I'm trying to get pull data from http://43.248.49.97/indexEn
Normally on the browser there is a first request to the url above returns error 412, the second one is to a JS file and the third one is also to the url above and returns ok (200).
When using selenium the third request returns error 400 - Bad request instead.
I'm using Python. Any ideas on why this is happening?]
Thanks
I had the same problem with you but I found a solution which perfectly solves my problem.
Maybe your program fails because you are detected as a robot using selenium.
So here is the method to solve it or hide your identity(window.navigator.webdriver) by using JavaScript:
With CDP(Chrome Devtools-Protocol), you run the code before the frame is loaded by the JS file(detector). Therefore, use these codes to remove the "webdriver True" property:
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
key codes:
from selenium.webdriver import Chrome
driver = Chrome('D://chromedriver.exe')
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
})
"""
})
driver.get('http://pythonlearner.com')
However, if you upgrade your Chrome to 88 right now. The method mentioned above will be useless. Fortunately, we still have a solution (add this code)
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
These codes should help you pass the JS file so that you can obtain the data. At least I successfully run my program.
I am using ChromeDriver 104.0.5112.79.0 and the solution with chrome_options.add_argument("--disable-blink-features=AutomationControlled") works for me!

Protractor get console variable value

In Firefox browser developer tool console, I type var a = libraryform.firstname
It returns the firstname value entered by user for that form.
I am new to protractor and selenium. How can I call library.firstname in protractor to get the value of fistname?
Use Javascript Executor to execute the javascript which you able to get them working in developer console against your application.
For e.g.,
this returns web-element which retrieved through javascript executed in browser.
var element = browser.executeScript("document.getElementById('identifier1')");
Refer this page for more examples
If this single line returns required value in browser console, then the protractor code should be some thing like this,
var name = browser.executeScript('return libraryform.firstname')
If you need too many lines of js, you can specify with semicolon separated,
var name = browser.executeScript("var element=$('.dropdown-toggle').eq(0); return element.text();")

running javascript functions using wallaby's execute_script does not work

System
OSX v10.13.4 / Elixir v1.6.5 / OTP 19 / Phoenix 1.3.2 / Wallaby 0.19.2 / PhantomJS 2.1
Issue
The following code works in testing
execute_script(session, "localStorage.setItem('test', 'foo'); return localStorage.getItem('test');")
However, if I call the exact same methods which are in a function called get_test() inside app.js of my Phoenix App
function get_test() {
localStorage.setItem('test', 'foo');
return localStorage.getItem('test');
}
window.get_test = get_test
And run the following in my test suite
execute_script(session, "return get_test();")
I get {:error, :obscured}
I have tried with selenium on the same code and it works. However, for some reason, with PhantomJS it does not seem to find functions that have been created by ourselves.
Am I missing something? I did notice in the tests for execute_script in wallaby there are no tests that call specifically created functions.
https://github.com/keathley/wallaby/blob/master/integration_test/cases/browser/execute_script_test.exs
A similar test
https://github.com/keathley/wallaby/blob/master/integration_test/cases/browser/local_storage_test.exs
of which I added the following to the local_storage_test to verify I was not going nuts
#function_script """
function get_tester() {
localStorage.setItem('tester', 'foo');
return localStorage.getItem('tester');
}
return get_tester();
"""
session
|> visit("index.html")
|> execute_script(#function_script, fn(value) -> send self(), {:callback, value} end)
assert_received {:callback, "foo"}
and it passed. This is clearly something wrong with my app. Or Phantom config perhaps.
UPDATE:
Although not mentioned directly - I have narrowed this down to libsodim not loading properly with phantomjs. Back to basics on the debugging. Nothing wrong with the JS written. On a positive note, I now have a whole library of tests which is cool and some cool tools for testing.

Selenium IDE: this.browserbot.getUserWindow().typeList.filter returns error on IE8

I have faced with following trouble during working with Selenium.
I need to verify that some value exists in list and I use the following code:
assertEval
this.browserbot.getUserWindow().typeList.filter(function(v) { return v[0] === 'Type_${r_suffix}'; })[0][0];
Type_${r_suffix}
This works file on Firefox, but on IE 8 returns error: Object doesn't support this property or method.
Could someone have an idea where is a problem?
As the MDN docs say, the filter() method is available only for IE9 and above.
Your're just using a too new technology. Filter it manually using a for loop or insert the code for Array.prototype.filter (from the MDN) to have access to it.