Can protractor be made to run slowly? - angularjs

Is there a way to run a Angular E2E test written using protractor slowly so that I can watch what is happening?

Below is my solution to do that. So basically I created a decorator for current control flow execute function, which now additionaly queues a delay of 100ms before each queued action.
This needs to be run before any tests are invoked (outside describe block)
var origFn = browser.driver.controlFlow().execute;
browser.driver.controlFlow().execute = function() {
var args = arguments;
// queue 100ms wait
origFn.call(browser.driver.controlFlow(), function() {
return protractor.promise.delayed(100);
});
return origFn.apply(browser.driver.controlFlow(), args);
};

Just like George Stocker said in the comment, I don't know why you would want to do this...but you can always add a sleep wherever you want in your test.
browser.sleep(6000);

Previous answers look more like workaround. Another way is to add param to Protractor config:
highlightDelay: 1000
And change to:
directConnect: false
It will delay Protractor actions like clicking or typing for 1 second and will highlight in light blue.

You can enter in 'debug mode' by placing in your code the command:
browser.pause();
In the debug mode, you would see the following output in your terminal:
------- WebDriver Debugger -------
ready
press c to continue to the next webdriver command
press d to continue to the next debugger statement
type "repl" to enter interactive mode
type "exit" to break out of interactive mode
press ^C to exit
You could then:
Run command by command by entering c
Continue to the next debugger statement (next browser.pause()) by entering d
Enter in interactive mode where you could interact with all the elements by entering repl

2 ways for doing this
1. First is very childish way, but I'll leave it here
you can highlight the elements you're interacting with!
highlightElement: async ($elementObject, time = 1000) => {
async function setStyle(element, style) {
const previous = await element.getAttribute('style');
await element.setAttribute('style', style);
await setTimeout(() => {
element.setAttribute('style', previous);
}, time);
}
await browser.sleep(time)
return await browser.executeScript(await setStyle, $elementObject.getWebElement(), 'color: red; background-color: yellow; z-index: 9999;');
},
This will highlight the element for a second
And then wrap your actions using this element
let click = async function ($elem) {
await highlightElement($elem);
await $elem.click();
}
let sendKeys = async function ($elem, text) {
await highlightElement($elem);
await $elem.sendKeys(text);
}
And then use it to try some scripts
await sendKeys($login, username);
await sendKeys($password, password);
await click($submit);
This shouldn't really be used in the real script, only when you're playing with it
2. Setup debugging configuration in your code editor
Example for vs code https://medium.com/#ganeshsirsi/how-to-debug-protractor-tests-in-visual-studio-code-e945fc971a74, but the same thing can be achieved in webstorm
This will allow you to execute the code line by line and interact with the variables in the real time. MUST HAVE for everyone who works with protractor. I'm serious

Related

Tampermonkey run script on specific tab

I'm on learning Tempermonkey and it's userscripts. And I have some questions.
I want to run one script for all firefox opened containers but this script must have different settings according the container's tab it ran on. Like some data and different conditions in some functions.
I tried to use GM_getTab for that but it sends me an empty object for some reasons.
// #grant GM_getTab
GM_getTab(function (e) {
console.log(e); // 'e is empty in console and in debug window either'
});
So basically how to use this function for my task?
P.S. Firefox: Portable 93.0 (64-bit)
Omg why always like this, just asked the question and found the solution in next 10 minutes :D
So the solution is:
(async () => {
const tabObj = await GM.getTab();
// You first have to define ID for all tabs you need, then just comment this part
tabObj.id = Math.random();
GM_saveTab(tabObj); // update the object
// get all stored objects
const tabsDatabase = await GM.getTabs();
const dbL = Object.keys(tabsDatabase).length;
console.log('Script-owned tab:', tabObj); // Current tab
console.log('Script-owned tabs count:', tabsDatabase); // All opened tabs
})();

Intermittently failing tests with Protractor - promise order execution?

I am facing intermittent protractor test failures across a range of test suites without any real pattern in the fail cases to indicate what could be going on, for example it's not the same tests that are failing. Sometimes I will get many failures and on other occasions just a single fail case.
I should point out that this tends to only happen when performing test runs on a Jenkins CI server we have configured (running under linux). Locally on Windows dev machines we may get a single fail case after 30-40 runs which I can live with!
The application we are testing is currently built with angular 1.5 and we are using angular material 1.1.3
Due to the animations used in angular material and the performance hit these can have, we have already tried disabling animations following this approach here which certainly make the tests quicker but dont help with the fail cases we are seeing/
I am at a point now where I am running one test suite over and over, after 5 successful runs it then failed on it's 6th attempt on our Jenkins CI environment\linux box, locally I have run this test many times now and no failures yet.
The test suite in question is detailed below along with a page object file snippet:
//test suite
describe('Operators View', function () {
var operatorPage = require('./operators.po.js'),
loginView = require('../login/login.po.js'),
page = new operatorPage();
describe('Large screen tests', function () {
beforeAll(function () {
loginView.login();
});
afterAll(function () {
loginView.logout();
});
it('should create an operator', function () {
page.settlementBtn.click();
page.operatorsBtn.click();
page.fabBtn.click();
page.createOperator();
expect(page.headline.getText()).toEqual('Operators');
});
});
});
// operators.po.js
var operatorsSection = function() {
this.helper = new Helpers();
this.headline = element(by.css('.md-headline'));
this.settlementBtn = element(by.css('[ui-sref="settlement"]'));
this.operatorsBtn = element(by.css('[ui-sref="operators"]'));
this.fabBtn = element(by.css('.md-fab'));
// Form Elements
this.licenceNumber = element(by.model('vm.transportOperator.licenceNumber'));
this.tradingName = element(by.model('vm.tradingName'));
this.name = element(by.model('vm.name'));
this.operatorAddressFirstLine = element(by.model('vm.transportOperator.address.line1'));
this.operatorAddressCityTown = element(by.model('vm.transportOperator.address.line5'));
this.operatorAddressPostCode = element(by.model('vm.transportOperator.address.postcode'));
this.payeeAddressFirstLine = element(by.model('vm.transportOperator.payee.address.line1'));
this.payeeAddressCityTown = element(by.model('vm.transportOperator.payee.address.line4'));
this.payeeAddressPostCode = element(by.model('vm.transportOperator.payee.address.postcode'));
this.opID = element(by.model('vm.transportOperator.fields.opID'));
this.spID = element(by.model('vm.transportOperator.fields.spID'));
this.schemeSelect = element(by.model('reference.scheme'));
this.schemeOptions = element(by.exactRepeater('scheme in vm.schemes').row('0'));
this.alias = element(by.model('reference.alias'));
this.reference = element(by.model('reference.reference'));
this.saveBtn = element(by.css('.md-raised'));
this.createOperator = function() {
this.licenceNumber.sendKeys(this.helper.getRandomId(10));
this.tradingName.sendKeys('Protractor Trade Name LTD');
this.name.sendKeys('Protractor Trade Name');
this.operatorAddressFirstLine.sendKeys('Protractor Town');
this.operatorAddressCityTown.sendKeys('Cardiff');
this.operatorAddressPostCode.sendKeys('PT4 4TP');
this.payeeAddressFirstLine.sendKeys('Protractor Town');
this.payeeAddressCityTown.sendKeys('Cardiff');
this.payeeAddressPostCode.sendKeys('PT4 4TP');
this.opID.sendKeys('177');
this.spID.sendKeys('Protractor Spid');
this.schemeSelect.click();
this.schemeOptions.click();
this.alias.sendKeys('PTAlias');
this.reference.sendKeys('Protractor');
this.saveBtn.click();
}
};
module.exports = operatorsSection;
In this test suite after the call to createOperator from the PO file is invoked and the savteBtn is clicked, the application will transition to a state that shows a table of created entries (after successful creation of course). We are using angular ui-router also, currently on version 0.2.18
The expectation fails with:
Expected 'Create An Operator' to equal 'Operators'.
Yet the accompanying screenshot that was captured shows the table view with an 'Operators' heading, it seems the call to page.headline.getText() inside the expectation call is being invoked too soon, so before the database operation to create the item and the page change has had a chance to complete?
I have started wondering if this could be down to the order of promises executed by protractor. I have come across articles talking about control flow in protractor and why there may be occasions when you should hook into the result of a protractor call's promise using .then() - I found this
It got me wondering if I should move the call to my saveBtn.click(), that's called at the end of my page object's createOperator function, into the test suite, so doing something like:
it('should create an operator', function () {
page.settlementBtn.click();
page.operatorsBtn.click();
page.fabBtn.click();
page.createOperator();
page.saveBtn.click().then(function(){
expect(page.headline.getText()).toEqual('Operators');
});
});
I'm starting to clutch at straws here to be honest, so any thoughts\advice from the community here would be much appreciated.
Thanks!
As requested, here is the function I use for waiting for URLs to be as they should.
public waitForUrlToBeLike (urlPart: string, timeout: number = 10000) {
return browser.wait(() => {
return browser.driver.getCurrentUrl().then((url) => {
let regex = new RegExp(urlPart);
return regex.test(url);
});
}, timeout);
}
I also use the following a lot to wait for elements to be present before making assertions on them:
public waitTillPresent (element: ElementFinder, timeout: number = 10000) {
return browser.wait(() => {
return element.isPresent();
}, timeout);
}

Long running script that polls external server with variable backoff timer?

I am writing a long running script based on Amphp library, that will poll a external server for a list of tasks to run and then execute those tasks.
In the response from the server would be the backoff timer that would control when the script makes it's next request.
Since I am very new to async programming what I am trying is not working.
I tried to create a \Amp\repeat() that had an \Amp\Pause(1000) so that each repeat would pause for 1 second.
Here's my test code:
function test() {
// http request goes here...
echo 'server request '.microtime(true).PHP_EOL;
// based on the server request, change the pause time
yield new \Amp\Pause(1000);
}
Amp\execute(function () {
\Amp\onSignal(SIGINT, function () {
\Amp\stop();
});
\Amp\repeat(100, function () {
yield from test();
});
});
What I expected to happen was that on each repeat, the test() function would pause for 1 second after the echo but instead the echo was run every 100ms (the repeat time).
In the past I would accomplish this with a while loop and usleep() but since usleep() is blocking this defeats the purpose.
I'm using PHP 7.0 and Amphp from github master branch.
\Amp\repeat calls the callback every 100 milliseconds, regardless of when the callback terminates.
\Amp\execute(function () {
/* onSignal handler here for example */
new \Amp\Coroutine(function () {
while (1) {
/* dispatch request */
echo 'server request '.microtime(true).PHP_EOL;
yield new \Amp\Pause(100);
}
});
});
This is using a normal loop which only continues 100 ms after the last action.
[If I misunderstood what exactly you want, please note in comments.]

Cortana ran into an issue

I have created a javascript application (aka UWA) in order to play with my Belkin wemo and then turn on or turn off the ligth with Cortana. The following function is well called but Cortana ends up with an issue. If I remove the call to the HTTP call, the program works fine. Who can tell me what's wrong with the following function because no more details are exposed unfortunately (of course in the real program is replaced with the right URL):
function setWemo(status) {
WinJS.xhr({ url: "<url>" }).then(function () {
var userMessage = new voiceCommands.VoiceCommandUserMessage();
userMessage.spokenMessage = "Light is now turned " + status;
var statusContentTiles = [];
var statusTile = new voiceCommands.VoiceCommandContentTile();
statusTile.contentTileType = voiceCommands.VoiceCommandContentTileType.titleOnly;
statusTile.title = "Light is set to: " + status;
statusContentTiles.push(statusTile);
var response = voiceCommands.VoiceCommandResponse.createResponse(userMessage, statusContentTiles);
return voiceServiceConnection.reportSuccessAsync(response);
}).done();
}
Make sure that your background task has access to the WinJS namespace. For background tasks, since there isn't any default.html, base.js won't be getting imported automatically unless you explicitly do it.
I had to update winjs to version 4.2 from here (or the source repository on git), then add that to my project to update from the released version that comes with VS 2015. WinJS 4.0 has a bug where it complains about gamepad controls if you try to import it this way (see this MSDN forum post)
Then I added a line like
importScripts("/Microsoft.WinJS.4.0/js/base.js");
to the top of your script's starting code to import WinJS. Without this, you're probably getting an error like "WinJS is undefined" popping up in your debug console, but for some reason, whenever I hit that, I wasn't getting a debug break in visual studio. This was causing the Cortana session to just hang doing nothing, never sending a final response.
I'd also add that you should be handling errors and handling progress, so that you can periodically send progress reports to Cortana to ensure that it does not time you out (which is why it gives you the error, probably after around 5 seconds):
WinJS.xhr({ url: "http://urlhere/", responseType: "text" }).done(function completed(webResponse) {
... handle response here
},
function error(errorResponse) {
... error handling
},
function progress(requestProgress) {
... <some kind of check to see if it's been longer than a second or two here since the last progress report>
var userProgressMessage = new voiceCommands.VoiceCommandUserMessage();
userProgressMessage.DisplayMessage = "Still working on it!";
userProgressMessage.SpokenMessage = "Still working on it";
var response = voiceCommands.VoiceCommandResponse.createResponse(userProgressMessage);
return voiceServiceConnection.reportProgressAsync(response);
});

Protractor Pause On Failure

I am new to protractor and I am trying to figure out how to make the test/runner pause on failure. Ideally I would love to transition to the nodejs debugger but am open to any suggestion.
My use case is basically, when a test fails I would like to see what state the UI is in to help understand why the test failed.
Nick.
You can also add to the jasmine config, to stop when spec fails:
(same as how protractor-screenshot-reporter works)
for jasmine 1:
onPrepare: function () {
exports.config = {
onPrepare: function () {
jasmine.getEnv().addReporter({
reportSpecResults: function (spec) {
if (!spec.results().passed()) {
spec.results().items_.forEach(function (v) {
console.log(v.trace.stack);
});
browser.pause();
}
}
});
}
}
}
for jasmine2:
onPrepare: function () {
jasmine.getEnv().addReporter({
specDone: function (spec) {
if (spec.status === 'failed') {
console.dir(spec.failedExpectations.length);
console.log(spec.failedExpectations[0].message);
console.log(spec.failedExpectations[0].stack);
browser.pause();
}
}
});
}
then by typing "repl" in the console you switch to interactive mode, so you can try out the protractor commands.
You can put browser to sleep after or before your expect line to see what's going on.
browser.sleep(20000); // sleep 20 seconds
Update:
protractor now supports .pause() method.
browser.pause()
Read the docs here: https://angular.github.io/protractor/#/api?view=Protractor.prototype.pause
You should put browser.debugger() where you want your test to stop.
You have to have selenium standalone server running. You can start it using webdriver-manager start from command prompt. In your configuration file for protractor you have to have entry for selenium server pointing to that server like
seleniumAddress: 'http://localhost:4444/wd/hub', and entry for chromeOnly should be set to false. Debugging only works for chrome browser. Once you run you application it will drop into nodejs debugger. You have to press 'c' to continue. Once you debug statement is hit, you can do F12 to open debugger, and under console, you can use window.clientSideScripts to see what you have. I myself am at this point, but documentation for clientSideScripts is non-existant, so you can type the name of the function and it will give you the function definition. Then, you can try to figure out parameters it expects.

Resources