Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.

Commit 7b08083

Browse files
andyjackqiyigg
authored andcommitted
feat(driverProvider): Add useExistingWebDriver driver provider (#4756)
1 parent 249e657 commit 7b08083

File tree

7 files changed

+147
-0
lines changed

7 files changed

+147
-0
lines changed

docs/server-setup.md

+34
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,37 @@ Protractor can test directly against Chrome and Firefox without using a Selenium
108108
- `directConnect: true` - Your test script communicates directly Chrome Driver or Firefox Driver, bypassing any Selenium Server. If this is true, settings for `seleniumAddress` and `seleniumServerJar` will be ignored. If you attempt to use a browser other than Chrome or Firefox an error will be thrown.
109109

110110
The advantage of directly connecting to browser drivers is that your test scripts may start up and run faster.
111+
112+
Re-using an Existing WebDriver
113+
------------------------------
114+
115+
The use case for re-using an existing WebDriver is when you have existing
116+
`selenium-webdriver` code and are already in control of how the WebDriver is
117+
created, but would also like Protractor to use the same browser, so you can
118+
use protractor's element locators and the rest of its API. This could be
119+
done with the `attachSession` driver provider, but the `attachSession` API is
120+
being removed in `selenium-webdriver` 4.0.0.
121+
122+
Instead of a protractor config file, you create a config object in your test
123+
setup code, and add your already-created WebDriver object and base URL.
124+
125+
```javascript
126+
const ProtractorConfigParser = require('protractor/built/configParser').ConfigParser;
127+
const ProtractorRunner = require('protractor/built/runner').Runner;
128+
129+
const ptorConfig = new ProtractorConfigParser().config_;
130+
ptorConfig.baseUrl = myExistingBaseUrl;
131+
ptorConfig.seleniumWebDriver = myExistingWebDriver;
132+
ptorConfig.noGlobals = true; // local preference
133+
134+
// looks similar to protractor/built/runner.js run()
135+
const ptorRunner = new ProtractorRunner(ptorConfig);
136+
ptorRunner.driverProvider_.setupEnv();
137+
const browser = ptorRunner.createBrowser();
138+
ptorRunner.setupGlobals_(browser); // now you can access protractor.$, etc.
139+
```
140+
141+
Note that this driver provider leaves you in control of quitting the driver,
142+
but that also means Protractor API calls that expect the driver to properly
143+
quit and/or restart the browser, e.g. `restart`, `restartSync`, and
144+
`forkNewDriverInstance`, will not behave as documented.

lib/config.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {WebDriver} from 'selenium-webdriver';
2+
13
import {PluginConfig} from './plugins';
24

35
export interface Config {
@@ -228,6 +230,12 @@ export interface Config {
228230
*/
229231
firefoxPath?: string;
230232

233+
// ---- 8. To re-use an existing WebDriver object ---------------------------
234+
235+
// This would not appear in a configuration file. Instead a configuration
236+
// object would be created that includes an existing webdriver.
237+
seleniumWebDriver?: WebDriver;
238+
231239
// ---------------------------------------------------------------------------
232240
// ----- What tests to run ---------------------------------------------------
233241
// ---------------------------------------------------------------------------

lib/driverProviders/index.ts

+8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export * from './mock';
88
export * from './sauce';
99
export * from './testObject';
1010
export * from './kobiton';
11+
export * from './useExistingWebDriver';
1112

1213

1314
import {AttachSession} from './attachSession';
@@ -20,6 +21,7 @@ import {Mock} from './mock';
2021
import {Sauce} from './sauce';
2122
import {TestObject} from './testObject';
2223
import {Kobiton} from './kobiton';
24+
import {UseExistingWebDriver} from './useExistingWebDriver';
2325

2426
import {Config} from '../config';
2527
import {Logger} from '../logger';
@@ -32,6 +34,9 @@ export let buildDriverProvider = (config: Config): DriverProvider => {
3234
if (config.directConnect) {
3335
driverProvider = new Direct(config);
3436
logWarnings('directConnect', config);
37+
} else if (config.seleniumWebDriver) {
38+
driverProvider = new UseExistingWebDriver(config);
39+
logWarnings('useExistingWebDriver', config);
3540
} else if (config.seleniumAddress) {
3641
if (config.seleniumSessionId) {
3742
driverProvider = new AttachSession(config);
@@ -109,6 +114,9 @@ export let logWarnings = (providerType: string, config: Config): void => {
109114
if ('mock' !== providerType && config.mockSelenium) {
110115
warnList.push('mockSelenium');
111116
}
117+
if ('useExistingWebDriver' !== providerType && config.seleniumWebDriver) {
118+
warnList.push('seleniumWebDriver');
119+
}
112120
if (warnList.length !== 0) {
113121
logger.warn(warnInto + warnList.join(', '));
114122
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* This is an implementation of the Use Existing WebDriver Driver Provider.
3+
* It is responsible for setting up the account object, tearing it down, and
4+
* setting up the driver correctly.
5+
*/
6+
import * as q from 'q';
7+
import {promise as wdpromise, WebDriver} from 'selenium-webdriver';
8+
9+
import {Config} from '../config';
10+
import {Logger} from '../logger';
11+
12+
import {DriverProvider} from './driverProvider';
13+
14+
const http = require('selenium-webdriver/http');
15+
16+
let logger = new Logger('useExistingWebDriver');
17+
18+
export class UseExistingWebDriver extends DriverProvider {
19+
constructor(config: Config) {
20+
super(config);
21+
}
22+
23+
/**
24+
* Configure and launch (if applicable) the object's environment.
25+
* @return {q.promise} A promise which will resolve when the environment is
26+
* ready to test.
27+
*/
28+
protected setupDriverEnv(): q.Promise<any> {
29+
const defer = q.defer();
30+
this.config_.seleniumWebDriver.getSession().then((session) => {
31+
logger.info('Using session id - ' + session.getId());
32+
return defer.resolve();
33+
});
34+
return q(undefined);
35+
}
36+
37+
/**
38+
* Getting a new driver by attaching an existing session.
39+
*
40+
* @public
41+
* @return {WebDriver} webdriver instance
42+
*/
43+
getNewDriver(): WebDriver {
44+
const newDriver = this.config_.seleniumWebDriver;
45+
this.drivers_.push(newDriver);
46+
return newDriver;
47+
}
48+
49+
/**
50+
* Maintains the existing session and does not quit the driver.
51+
*
52+
* @public
53+
*/
54+
quitDriver(): wdpromise.Promise<void> {
55+
return wdpromise.when(undefined);
56+
}
57+
}

scripts/test.js

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ var passingTests = [
4343
'node built/cli.js spec/built/noCFBasicConf.js --useBlockingProxy',
4444
'node built/cli.js spec/built/noCFPluginConf.js',
4545
//'node scripts/driverProviderAttachSession.js',
46+
'node built/cli.js spec/driverProviderUseExistingWebDriver.js',
47+
'node built/cli.js spec/driverProviderUseExistingWebDriver.js --useBlockingProxy',
4648
'node scripts/errorTest.js',
4749
// Interactive Element Explorer tasks
4850
'node scripts/interactive_tests/interactive_test.js',
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
var env = require('./environment');
2+
var webdriver = require('selenium-webdriver');
3+
4+
var existingDriver = new webdriver.Builder()
5+
.usingServer(env.seleniumAddress)
6+
.withCapabilities(env.capabilities)
7+
.build();
8+
9+
exports.config = {
10+
11+
framework: 'jasmine',
12+
13+
specs: [
14+
'driverProviders/useExistingWebDriver/*_spec.js'
15+
],
16+
17+
capabilities: env.capabilities,
18+
19+
baseUrl: env.baseUrl,
20+
21+
seleniumWebDriver: existingDriver,
22+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
describe('uses existing webdriver', function() {
2+
var URL = '/ng2/#/async';
3+
4+
beforeEach(function() {
5+
browser.get(URL);
6+
});
7+
it('should be able to use an existing session', function() {
8+
var increment = $('#increment');
9+
expect(increment).toBeDefined();
10+
});
11+
// the driverProvider is set up to ignore the quitDriver() call;
12+
// so we call quit() ourselves to tidy up when testing is done.
13+
afterEach(function() {
14+
browser.quit();
15+
});
16+
});

0 commit comments

Comments
 (0)