Closed bobthekingofegypt closed 9 years ago
I'm so happy you brought this up, because a while ago we'd had a discussion and decided that no one would ever actually use that functionality!
So, you could do this now by basically rewriting runner.js (which is what you've started). I don't think there's any way to generalize your use case enough that it would be worth it to make it reusable, so I'd encourage you to just go ahead and write your own runner.js.
If anyone else would use this though, I'd love for them to chime in here!
We would definitely use this. We are writing a web app that allows insurance policy holders to communicate with construction contractors who are supposed to do repairs on the policy holders' homes.
Currently, we have to write e2e tests for each side of the app separately. We have to write one test that signs in as a policy holder, does some setup and then sends off a communication to the contractor. And then we have to log out as a policy holder, log in as a contractor, and then make sure that the communication arrived in the contractor's inbox as expected.
However, if the functionality described above were possible, then we could run two parallel versions of the browser at the same time where one is signed in as a policy holder and the other is signed in as a contractor and we could instantly verify that the communications can go back and forth as expected.
That would be a huge benefit to us. I can imagine there are many other such websites out there that could use this type of functionality.
I'd like to use this as well. I'd like to test a game that needs multiple instances to exercise all scenarios
Would definitely use this as well! Been logging out and logging in as different users as well, with this support we would no longer have to do that =)
@juliemr Curious why this couldn't be generalized?
I was thinking it might make more sense if the concept of a "primary driver" remained, with a config option to specify n number of "helper drivers" that could be kept in an array similar to the example from @bobthekingofegypt. Would this approach make it any less intrusive to the mainline use case while allowing the multi-driver flexibility?
Granted I don't understand how saucelab compatibility comes into play here. However, if two two concepts simply aren't compatible, that could be accounted for in the config logic.
I wouldn't mind attempting a PR.
I need this to test instant messaging and notifications between two logged in users.
My suggestion is similar to @bobthekingofegypt but using blocks instead of elementOne
, elementTwo
And having browser1, browser2, ... kind of globals:
By default browser
would point to browser1
and all expectations would run by default on browser1 unless browser2 is specified with some DSL like browser2.run(..{...}...);
making the feature backward compatible.
Sample usage of browser2
it('works with 2 logged in users', function() {
browser1.get('page1');
browser2.get('page2');
expect($('.div').getText()).toContain('hi'); // always defaults to browser1
browser2.run(function() {
$('button#send').click();
expect($('.div').getText()).toContain('hello you');
});
});
+1 need for this.
+1. Would be able to use this as well. Saves having to log out and log in as different users. On Mar 12, 2014 10:22 AM, "adamduffy" notifications@github.com wrote:
+1 need for thtis.
Reply to this email directly or view it on GitHubhttps://github.com/angular/protractor/issues/381#issuecomment-37437150 .
/sub
Will leave a reminder here that this feature won't work on IE: https://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_Can_I_run_multiple_instances_of_the_WebDriver_sub-classes?
Not sure about Safari, probably won't support this either.
It was a while ago that I did this, and I haven't been working with Angular/protractor since so it is a bit hazy.
But looking at my diff I don't think I did anything beyond what was required to make a proof of concept work. All the promise work is because you need to block till all sessions are ready, and then make sure all sessions terminate at the end of the test. I also left in some code so single browser tests would work as normal. The fork does work, I used it for two projects; it does have flaws though.
I haven't tracked the changes in protractor but if what you want to do is simple you can try checking out my fork and npm link it, I changed the name from protractor to protractor-multi so I could run them both at the same time.
+1 for this. I would like to test asynchronous pub/sub with 2 browsers.
You can generalize this with implementing the ability of parallelization tests with scaling that is not limited to 2.
Sometimes we implement tests that are not affecting each other and can be run in parallel. We would like to have ability of specifying different sets of specs. I guess this should be possible both with Selenium Standalone server and direct usage of drivers. I tried to run 2 different instances of protractor on single local machine (but in different bash windows, hehe) at a time using one instance of Selenium Standalone server and they worked in parallel well.
So, the POC is to implement running parallel tests within single protractor instance (with single output and ability to collect results to single report). Maybe there can be way to use something like Async.JS to run different specs in threads.
Maybe there is a way to do that with some Grunt package, but it is not convenient to have many Protractor config files, we would like to have all configs in one file.
Thanks in advance for your reply.
+1 for this (writing a websockets app that could benefit from this)
+1 still needing some support... @juliemr Could you give me some directions?
From issue #569...
I need 2 instances of browser running within a single test and must be able to manipulate them individually. I haven't found any info on how to perform it. Would be glad if you could enlighten me. This is a definite roadblock for my test suite. Thanks.
Thanks @hankduan. The problem I see is. If I use multiCapabilities, I can't manipulate both instances as I want to. The action of a user in one browser must reflect in the other browser. Like in google docs, when a user writes in a shared document, the other can see what is happening. This is basically what I must test. And if the second user deletes what had been written beforehand, the first must see it.
@rafaelbattesti wrote: "Thanks @hankduan. The problem I see is. If I use multiCapabilities, I can't manipulate both instances as I want to. The action of a user in one browser must reflect in the other browser. Like in google docs, when a user writes in a shared document, the other can see what is happening. This is basically what I must test. And if the second user deletes what had been written beforehand, the first must see it."
What about using "wait" functions. For about, you can implement something like "waitForElement" and in one spec file (1) start to wait with your timeout (e.g. 30s), in other spec file (2) run test that should reflect the first browser. spec file (2) makes actions and after them new element appears. spec file (1) sees that his element appears and continues his actions. Does this make sense?
@rafaelbattesti If your backend is not mocked out, you can give @Mikrovolnovka's method a try. It might be a little flakey some times, but that is the best solution for the use case at the moment as we do not have any "official" way of doing this right now.
+1 . I would like to test client 2 client web app (#949). does anyone knows how can i do it? thanks
+1 as this would be very very useful
+1
+1
Hi, we would use this too! http://simulations.wharton.upenn.edu/
+1
This might be a work around. Please let me know if this a a good way of doing it or not.
conf.js
multiCapabilities: [
{ browserName: 'chrome', },
{ browserName: 'firefox', }],
test.js
it('open login page', function () {
var browserType = null;
console.log("browser base URL =<< "+ browser.baseUrl);
browser.getCapabilities().then(function (cap) {
console.log(cap.caps_.browserName);
browserType = cap.caps_.browserName;
});
});
it('test something with two browser open up simultaneously', function (){
if(browserType == 'firefox') { login as user1 and send message "hello" }
if(browserType == 'chrome') {login as user2 and wait for message "hello" and response "hi"}
});
I'm essentially opening two different browser and in the same test script, defining what each browser should act as different user.
+1
I am not sure if I solved the exact same problem already a year ago.
We also had an interacting socket.io app. We wrote the protractor e2e tests one year ago, so the code is right now only compatible with a very early version of protractor (0.12 if I remember it right).
The following code is just a small demo code for a blog post I wrote a year ago about our first steps with protractor in an interacting dual browser setup (Source in german http://blog.cnc.io/allgemein/e2e-tests-in-angularjs-with-protractor/)
Maybe we can translate this code to work with version 1.3.1 and have this feature out of the box?
/*###############################################
Start the selenium server:
java -jar selenium/selenium-server-standalone-2.35.0.jar \
-Dwebdriver.chrome.driver=node_modules/chromedriver/bin/chromedriver
Start the tests:
jasmine-node --verbose path/to/my/e2e/tests/example-spec.js
//###############################################*/
//It is important to use the protractor selenium-webdriver
var webdriver = require('protractor/node_modules/selenium-webdriver');
var protractor = require('protractor');
require('protractor/jasminewd');
describe('yeoman angularjs generator app', function() {
//create a driver which starts a chrome browser
var driver1 = new webdriver.Builder()
.usingServer('http://localhost:4444/wd/hub')
.withCapabilities(webdriver.Capabilities.chrome()).build();
//create another driver which starts a firefox browser
var driver2 = new webdriver.Builder()
.usingServer('http://localhost:4444/wd/hub')
.withCapabilities(webdriver.Capabilities.firefox()).build();
//set timeout and wrap the webdriver instance in a protractor instance
driver1.manage().timeouts().setScriptTimeout(15000);
var ptor1 = protractor.wrapDriver(driver1);
driver2.manage().timeouts().setScriptTimeout(15000);
var ptor2 = protractor.wrapDriver(driver2);
//the test scenario
it('should have a list of awesome things', function() {
//load web application in both browser
ptor1.get('http://localhost:9000/?myspecialparam=forbrowserone');
ptor2.get('http://localhost:9000/?myspecialparam=forbrowsertwo');
//run test in first browser (chrome)
var thingslistone = ptor.findElements(
protractor.By.repeater('thing in awesomeThings'));
thingslistone.then(function(arr) {
expect(arr.length).toEqual(3);
expect(arr[0].getText()).toEqual('HTML5 Boilerplate');
expect(arr[1].getText()).toEqual('AngularJS');
expect(arr[2].getText()).toEqual('Karma');
});
//run test in second browser (firefox)
var thingslisttwo = ptor2.findElements(
protractor.By.repeater('thing in awesomeThings'));
thingslisttwo.then(function(arr) {
expect(arr.length).toEqual(3);
expect(arr[0].getText()).toEqual('HTML5 Boilerplate');
expect(arr[1].getText()).toEqual('AngularJS');
expect(arr[2].getText()).toEqual('Karma');
});
}, 20000);
//needed to quit the browser after all tests are executed
it('afterAll', function() {
driver1.quit();
driver2.quit();
})
});
This is my thought:
Since I am using multiCapabilities to start multiple threads, the global browserInstanceCount variable in protractor.conf may not be shared by all threads.
I am trying a new way of identifying browsers so that it no longer rely on the browser type. The new approach is to assign ticket number to new browser. The ticket number is saved in a text file and will accumulate every time it is read by a new browser. So now browser is identified by ticket number instead of browser type. I tried with 4 same or mixed browser types and it works so far. The file, however, has to be removed by Jenkins or manually each time before script starts.
The ticket management is written in the conf.js : var location = "ticket";
if(fs.existsSync(location)){ //when file exists, add 1 for the new thread var number = null; number - fs.readFileSync(location).toString(); number = parseInt(number) + 1; fs.writeFileSync(location, number); browser.params.ticketNumber = number; } else{ // when file does not exists, assign 1 for the first thread browser.params.ticketNumber = "1"; fs.writeFileSync(location, browser.params.ticketNumber); }
In your spec: if(browser.params.userTicket == "1") { // do steps for browser #1 } else if(browser.params.userTicket == "2"){ // do steps for browser #2 }....
If the global variable in protractor.conf works then your solution is better since no file management required. Please try it out and let us know.
On Thu, Oct 16, 2014 at 8:51 AM, carlhopf notifications@github.com wrote:
Quickly hacked something together on top of angular 1.3.1, to start and get a second global browser object. Works fine so far! Be warned: the code is extremely ugly and only works for 'chromeOnly: true' configs.
Just wanted to share the code, in case anyone needs a starting point in getting a second browser instance running.
What about a protractor.conf option like 'browserInstanceCount', then simply launch this many instances of drivers for each running test suite and make them available as a global browsers[] array?
carlhopf@e92e62e https://github.com/carlhopf/protractor/commit/e92e62eff80ebfb4f8e2ebb1e39b4699170d55fc
To test:
git clone https://github.com/carlhopf/protractor.git cd protractor npm install npm link webdriver-manager update
— Reply to this email directly or view it on GitHub https://github.com/angular/protractor/issues/381#issuecomment-59384113.
Sorry, I've had to delete my old comment due to a bug. Here is my new take on the problem to allow multiple browsers windows/instances for protractor 1.3.1: https://github.com/carlhopf/protractor/commit/dd76f72bcc2e6fc338b95e3465a19034b4591241
This allows to call
it('should create, test, and close a new browser window', function() {
var browser2 = newBrowser();
browser2.get('http://localhost:8000');
expect(browser2.element(by.css('my-missing-element')).isPresent()).toBe(false);
quitBrowser(browser2);
});
and you'll get a new browser window to work with (supports as many as you'd like to use). All new windows will also automatically close when protractor quits.
NOTE: you must add "chromeOnly: true;" to protractor.conf.js, I've just made lib/driverProviders/chome.js compatible so far!
Test it out yourself:
git clone https://github.com/carlhopf/protractor
cd protractor
npm install
npm link
webdriver-manager update
Here is another workaround i'd like to propose for multiple windows/instances for protractor 1.3.1: https://github.com/carlhopf/protractor/commit/9aa1a7e4b10ca3becd699ea7f3ae63158dfd8b9e
This gives you newBrowser(), quitBrowser(index) and switchBrowser(index) and assigns the currently selected browser to the global protractor objects (browser, element, protractor.getInstance(), ...). So there is no need to change test syntax, simply switchBrowser() and continue as before.
describe('should open 2 browsers', function() {
beforeEach(function() {
newBrowser();
});
it('should open two windows', function() {
browser.get('http://localhost:8001');
switchBrowser(1);
browser.get('http://127.0.0.1:8001');
browser.executeAsyncScript(function(callback) {
callback(window.location.href.indexOf('127.0.0.1') !== -1);
}).then(function(res) {
expect(res).toBe(true);
});
switchBrowser(0);
browser.executeAsyncScript(function(callback) {
callback(window.location.href.indexOf('127.0.0.1') === -1);
}).then(function(res) {
expect(res).toBe(true);
});
});
afterEach(function() {
quitBrowser(1);
expect(browsers.length).toBe(1);
});
});
NOTE: you must add "chromeOnly: true;" to protractor.conf.js, I've just made lib/driverProviders/chome.js compatible so far!
Test it out yourself:
npm install -g git://github.com/carlhopf/protractor.git#switchbrowser
webdriver-manager update
"I'm so happy you brought this up, because a while ago we'd had a discussion and decided that no one would ever actually use that functionality!"
I think at least every "real-time" app need this testing functionality. At least for chrome there is no problem to open new window through: var win = prt.driver.executeScript('window.open("http://localhost/", "windowName", "width=1024,height=768");'); (see http://stackoverflow.com/a/726803/926620 ). But the problem then is shared session. To overcome this limitation I use different hostname (for two windows 127.0.0.1 and localhost), like described in http://stackoverflow.com/a/23551878/926620 .
This feature is very important for me too.
Got my multi-browser test to run again with the "vanilla" protractor package. Perfect for chat or any other multi-window live interaction web project testing.
Just had to change the following includes:
var webdriver = require('selenium-webdriver');
var protractor = require('protractor');
require('jasminewd');
The full example code is:
/*###############################################
Start the selenium server:
java -jar selenium/selenium-server-standalone-2.35.0.jar \
-Dwebdriver.chrome.driver=node_modules/chromedriver/bin/chromedriver
Start the tests:
jasmine-node --verbose path/to/my/e2e/tests/example-spec.js
//###############################################*/
var webdriver = require('selenium-webdriver');
var protractor = require('protractor');
require('jasminewd');
describe('yeoman angularjs generator app', function() {
//create a driver which starts a chrome browser
var driver1 = new webdriver.Builder()
.usingServer('http://localhost:4444/wd/hub')
.withCapabilities(webdriver.Capabilities.chrome()).build();
//create another driver which starts a firefox browser
var driver2 = new webdriver.Builder()
.usingServer('http://localhost:4444/wd/hub')
.withCapabilities(webdriver.Capabilities.firefox()).build();
//set timeout and wrap the webdriver instance in a protractor instance
driver1.manage().timeouts().setScriptTimeout(15000);
var ptor1 = protractor.wrapDriver(driver1);
driver2.manage().timeouts().setScriptTimeout(15000);
var ptor2 = protractor.wrapDriver(driver2);
//the test scenario
it('should have a list of awesome things', function() {
//load web application in both browser
ptor1.get('http://localhost:9000/?myspecialparam=forbrowserone');
ptor2.get('http://localhost:9000/?myspecialparam=forbrowsertwo');
//run test in first browser (chrome)
var thingslistone = ptor.findElements(
protractor.By.repeater('thing in awesomeThings'));
thingslistone.then(function(arr) {
expect(arr.length).toEqual(3);
expect(arr[0].getText()).toEqual('HTML5 Boilerplate');
expect(arr[1].getText()).toEqual('AngularJS');
expect(arr[2].getText()).toEqual('Karma');
});
//run test in second browser (firefox)
var thingslisttwo = ptor2.findElements(
protractor.By.repeater('thing in awesomeThings'));
thingslisttwo.then(function(arr) {
expect(arr.length).toEqual(3);
expect(arr[0].getText()).toEqual('HTML5 Boilerplate');
expect(arr[1].getText()).toEqual('AngularJS');
expect(arr[2].getText()).toEqual('Karma');
});
}, 20000);
//needed to quit the browser after all tests are executed
it('afterAll', function() {
driver1.quit();
driver2.quit();
})
});
I have not tested it a lot, i just had the time to get it running again. Any suggestions are welcome if there are some bugs or misconceptions in the code.
Implemented with https://github.com/angular/protractor/commit/0bbfd2b6d38392938781d846ad37b5a0fd964004. This will be released in protractor 1.5.0
@hankduan Can I get a documentation link for how to control multiple browsers for instant messaging kind of applications. I have tried searching for this and I am unable to find some code except multiCapabilities.
note to self: I should work on the docs.
For now, read the api annotation: https://github.com/angular/protractor/blob/master/lib/runner.js#L190 There are also a lot of examples here: https://github.com/angular/protractor/blob/master/spec/interaction/interaction_spec.js
Please make sure to install
npm install protractor
Update web driver manager
webdriver-manager update
Run this command from your root
node node_modules\protractor\bin\webdriver-manager update
Now start up a server with:
webdriver-manager start
Also make sure that your protractor.conf.js file has below line
// baseUrl: 'http://localhost:4200/',
seleniumAddress: 'http://localhost:4444/wd/hub/',
Now run your e2e tests on different browesers
ng e2e
Currently I am working on some socket based multi-player games using angular. In order to perform an e2e test I need to have two browsers talk to each other as the games wont start till 2 people join.
I was wondering if this could be something that is added on top of protractor. I kinda hacked up a proof of concept to allow me to test users joining and chatting on the game. https://github.com/bobthekingofegypt/protractor/commit/8ac849a5225698efc260d6e26307bccfe9801693
As a concept it appears to work ok, it allows you to write tests like
This change breaks certain things like saucelabs support and it's not very complete but it is meant as a conversation starter.
It is quite a niche use case but is this something you would consider supporting in protractor?