mirror of https://github.com/vitalif/phantomjs
Embedding GhostDriver into PhantomJS(!!!)
Finally. After so much work, this is finally a reality. To launch PhantomJS in "Remote WebDriver mode": ```bash $ phantomjs --webdriver=OPTIONAL_IP:OPTIONAL_PORT ``` Also, GhostDriver brings along support for Selenium Grid: now PhantomJS can register itself to a Selenium Grid HUB. Just launch it in Webdriver Mode with the following extra options: ```bash $ phantomjs --webdriver=OPTIONAL_IP:OPTIONAL_PORT --webdriver-selenium-grid-hub=http://url.to.selenium.grid.hub:port ``` http://code.google.com/p/phantomjs/issues/detail?id=491.8
parent
2dcccc8968
commit
ffa9fab316
|
@ -193,7 +193,7 @@ phantom.onError = phantom.defaultErrorHandler;
|
||||||
var paths = [], dir;
|
var paths = [], dir;
|
||||||
|
|
||||||
if (request[0] === '.') {
|
if (request[0] === '.') {
|
||||||
paths.push(fs.absolute(joinPath(this.dirname, request)));
|
paths.push(fs.absolute(joinPath(phantom.webdriverMode ? ":/ghostdriver" : this.dirname, request)));
|
||||||
} else if (request[0] === '/') {
|
} else if (request[0] === '/') {
|
||||||
paths.push(fs.absolute(request));
|
paths.push(fs.absolute(request));
|
||||||
} else {
|
} else {
|
||||||
|
@ -284,8 +284,11 @@ phantom.onError = phantom.defaultErrorHandler;
|
||||||
cwd = fs.absolute(phantom.libraryPath);
|
cwd = fs.absolute(phantom.libraryPath);
|
||||||
mainFilename = joinPath(cwd, basename(require('system').args[0]) || 'repl');
|
mainFilename = joinPath(cwd, basename(require('system').args[0]) || 'repl');
|
||||||
mainModule._setFilename(mainFilename);
|
mainModule._setFilename(mainFilename);
|
||||||
// include CoffeeScript which takes care of adding .coffee extension
|
|
||||||
require('_coffee-script');
|
// include CoffeeScript which takes care of adding .coffee extension (only if not in Webdriver mode)
|
||||||
|
if (!phantom.webdriverMode) {
|
||||||
|
require('_coffee-script');
|
||||||
|
}
|
||||||
}());
|
}());
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,8 @@ static const struct QCommandLineConfigEntry flags[] =
|
||||||
{ QCommandLine::Option, '\0', "script-encoding", "Sets the encoding used for the starting script, default is 'utf8'", QCommandLine::Optional },
|
{ QCommandLine::Option, '\0', "script-encoding", "Sets the encoding used for the starting script, default is 'utf8'", QCommandLine::Optional },
|
||||||
{ QCommandLine::Option, '\0', "web-security", "Enables web security, 'yes' (default) or 'no'", QCommandLine::Optional },
|
{ QCommandLine::Option, '\0', "web-security", "Enables web security, 'yes' (default) or 'no'", QCommandLine::Optional },
|
||||||
{ QCommandLine::Option, '\0', "ssl-protocol", "Sets the SSL protocol (supported protocols: 'SSLv3' (default), 'SSLv2', 'TLSv1', 'any')", QCommandLine::Optional },
|
{ QCommandLine::Option, '\0', "ssl-protocol", "Sets the SSL protocol (supported protocols: 'SSLv3' (default), 'SSLv2', 'TLSv1', 'any')", QCommandLine::Optional },
|
||||||
|
{ QCommandLine::Option, '\0', "webdriver", "Starts in 'Remote WebDriver mode' (embedded GhostDriver): '[[<IP>:]<PORT>]' (default '127.0.0.1:8910') ", QCommandLine::Optional },
|
||||||
|
{ QCommandLine::Option, '\0', "webdriver-selenium-grid-hub", "URL to the Selenium Grid HUB: 'URL_TO_HUB' (default 'none') (NOTE: works only together with '--webdriver') ", QCommandLine::Optional },
|
||||||
{ QCommandLine::Param, '\0', "script", "Script", QCommandLine::Flags(QCommandLine::Optional|QCommandLine::ParameterFence)},
|
{ QCommandLine::Param, '\0', "script", "Script", QCommandLine::Flags(QCommandLine::Optional|QCommandLine::ParameterFence)},
|
||||||
{ QCommandLine::Param, '\0', "argument", "Script argument", QCommandLine::OptionalMultiple },
|
{ QCommandLine::Param, '\0', "argument", "Script argument", QCommandLine::OptionalMultiple },
|
||||||
{ QCommandLine::Switch, 'h', "help", "Shows this message and quits", QCommandLine::Optional },
|
{ QCommandLine::Switch, 'h', "help", "Shows this message and quits", QCommandLine::Optional },
|
||||||
|
@ -99,6 +101,20 @@ void Config::processArgs(const QStringList &args)
|
||||||
m_cmdLine->setArguments(args);
|
m_cmdLine->setArguments(args);
|
||||||
m_cmdLine->setConfig(flags);
|
m_cmdLine->setConfig(flags);
|
||||||
m_cmdLine->parse();
|
m_cmdLine->parse();
|
||||||
|
|
||||||
|
// Inject command line parameters to be picked up by GhostDriver
|
||||||
|
if (isWebdriverMode()) {
|
||||||
|
QStringList argsForGhostDriver;
|
||||||
|
|
||||||
|
m_scriptFile = "main.js"; //< launch script
|
||||||
|
argsForGhostDriver << m_webdriver; //< ip:port
|
||||||
|
if (!m_seleniumGridHub.isEmpty()) {
|
||||||
|
argsForGhostDriver << m_seleniumGridHub; //< selenium grid url
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear current args and override with those
|
||||||
|
setScriptArgs(argsForGhostDriver);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::loadJsonFile(const QString &filePath)
|
void Config::loadJsonFile(const QString &filePath)
|
||||||
|
@ -424,6 +440,48 @@ bool Config::javascriptCanCloseWindows() const
|
||||||
return m_javascriptCanCloseWindows;
|
return m_javascriptCanCloseWindows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Config::setWebdriver(const QString &webdriverConfig)
|
||||||
|
{
|
||||||
|
// This option can be provided empty: in that case we should use the default IP:PORT configuration
|
||||||
|
QString ip = "127.0.0.1";
|
||||||
|
QString port = "8910";
|
||||||
|
|
||||||
|
// Parse and validate the configuration
|
||||||
|
bool isValidPort;
|
||||||
|
QStringList wdCfg = webdriverConfig.split(':');
|
||||||
|
if (wdCfg.length() == 1 && wdCfg[0].toInt(&isValidPort) && isValidPort) {
|
||||||
|
// Only a PORT was provided
|
||||||
|
port = wdCfg[0];
|
||||||
|
} else if(wdCfg.length() == 2 && !wdCfg[0].isEmpty() && wdCfg[1].toInt(&isValidPort) && isValidPort) {
|
||||||
|
// Both IP and PORT provided
|
||||||
|
ip = wdCfg[0];
|
||||||
|
port = wdCfg[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting the "webdriver" configuration
|
||||||
|
m_webdriver = QString("%1:%2").arg(ip).arg(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Config::webdriver() const
|
||||||
|
{
|
||||||
|
return m_webdriver;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Config::isWebdriverMode() const
|
||||||
|
{
|
||||||
|
return !m_webdriver.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::setSeleniumGridHub(const QString &hubUrl)
|
||||||
|
{
|
||||||
|
m_seleniumGridHub = hubUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Config::seleniumGridHub() const
|
||||||
|
{
|
||||||
|
return m_seleniumGridHub;
|
||||||
|
}
|
||||||
|
|
||||||
// private:
|
// private:
|
||||||
void Config::resetToDefaults()
|
void Config::resetToDefaults()
|
||||||
{
|
{
|
||||||
|
@ -455,6 +513,8 @@ void Config::resetToDefaults()
|
||||||
m_helpFlag = false;
|
m_helpFlag = false;
|
||||||
m_printDebugMessages = false;
|
m_printDebugMessages = false;
|
||||||
m_sslProtocol = "sslv3";
|
m_sslProtocol = "sslv3";
|
||||||
|
m_webdriver = QString();
|
||||||
|
m_seleniumGridHub = QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::setProxyAuthPass(const QString &value)
|
void Config::setProxyAuthPass(const QString &value)
|
||||||
|
@ -598,6 +658,12 @@ void Config::handleOption(const QString &option, const QVariant &value)
|
||||||
if (option == "ssl-protocol") {
|
if (option == "ssl-protocol") {
|
||||||
setSslProtocol(value.toString());
|
setSslProtocol(value.toString());
|
||||||
}
|
}
|
||||||
|
if (option == "webdriver") {
|
||||||
|
setWebdriver(value.toString());
|
||||||
|
}
|
||||||
|
if (option == "selenium-grid-hub") {
|
||||||
|
setSeleniumGridHub(value.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::handleParam(const QString& param, const QVariant &value)
|
void Config::handleParam(const QString& param, const QVariant &value)
|
||||||
|
@ -623,4 +689,4 @@ QString Config::sslProtocol() const
|
||||||
void Config::setSslProtocol(const QString& sslProtocolName)
|
void Config::setSslProtocol(const QString& sslProtocolName)
|
||||||
{
|
{
|
||||||
m_sslProtocol = sslProtocolName.toLower();
|
m_sslProtocol = sslProtocolName.toLower();
|
||||||
}
|
}
|
||||||
|
|
13
src/config.h
13
src/config.h
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
class QCommandLine;
|
class QCommandLine;
|
||||||
|
|
||||||
class Config: QObject
|
class Config: public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QString cookiesFile READ cookiesFile WRITE setCookiesFile)
|
Q_PROPERTY(QString cookiesFile READ cookiesFile WRITE setCookiesFile)
|
||||||
|
@ -58,6 +58,8 @@ class Config: QObject
|
||||||
Q_PROPERTY(bool javascriptCanOpenWindows READ javascriptCanOpenWindows WRITE setJavascriptCanOpenWindows)
|
Q_PROPERTY(bool javascriptCanOpenWindows READ javascriptCanOpenWindows WRITE setJavascriptCanOpenWindows)
|
||||||
Q_PROPERTY(bool javascriptCanCloseWindows READ javascriptCanCloseWindows WRITE setJavascriptCanCloseWindows)
|
Q_PROPERTY(bool javascriptCanCloseWindows READ javascriptCanCloseWindows WRITE setJavascriptCanCloseWindows)
|
||||||
Q_PROPERTY(QString sslProtocol READ sslProtocol WRITE setSslProtocol)
|
Q_PROPERTY(QString sslProtocol READ sslProtocol WRITE setSslProtocol)
|
||||||
|
Q_PROPERTY(QString webdriver READ webdriver WRITE setWebdriver)
|
||||||
|
Q_PROPERTY(QString seleniumGridHub READ seleniumGridHub WRITE setSeleniumGridHub)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Config(QObject *parent = 0);
|
Config(QObject *parent = 0);
|
||||||
|
@ -152,6 +154,13 @@ public:
|
||||||
void setSslProtocol(const QString& sslProtocolName);
|
void setSslProtocol(const QString& sslProtocolName);
|
||||||
QString sslProtocol() const;
|
QString sslProtocol() const;
|
||||||
|
|
||||||
|
void setWebdriver(const QString& webdriverConfig);
|
||||||
|
QString webdriver() const;
|
||||||
|
bool isWebdriverMode() const;
|
||||||
|
|
||||||
|
void setSeleniumGridHub(const QString& hubUrl);
|
||||||
|
QString seleniumGridHub() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void handleSwitch(const QString &sw);
|
void handleSwitch(const QString &sw);
|
||||||
void handleOption(const QString &option, const QVariant &value);
|
void handleOption(const QString &option, const QVariant &value);
|
||||||
|
@ -196,6 +205,8 @@ private:
|
||||||
bool m_javascriptCanOpenWindows;
|
bool m_javascriptCanOpenWindows;
|
||||||
bool m_javascriptCanCloseWindows;
|
bool m_javascriptCanCloseWindows;
|
||||||
QString m_sslProtocol;
|
QString m_sslProtocol;
|
||||||
|
QString m_webdriver;
|
||||||
|
QString m_seleniumGridHub;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONFIG_H
|
#endif // CONFIG_H
|
||||||
|
|
|
@ -354,7 +354,7 @@ bool FileSystem::changeWorkingDirectory(const QString &path) const
|
||||||
|
|
||||||
QString FileSystem::absolute(const QString &relativePath) const
|
QString FileSystem::absolute(const QString &relativePath) const
|
||||||
{
|
{
|
||||||
return QFileInfo(relativePath).absoluteFilePath();
|
return QFileInfo(relativePath).absoluteFilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QWebPage>
|
#include <QWebPage>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QMetaObject>
|
||||||
|
#include <QMetaProperty>
|
||||||
|
|
||||||
#include "consts.h"
|
#include "consts.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
@ -179,12 +182,37 @@ bool Phantom::execute()
|
||||||
if (m_terminated)
|
if (m_terminated)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (m_config.scriptFile().isEmpty()) {
|
#ifndef QT_NO_DEBUG_OUTPUT
|
||||||
// REPL mode requested
|
qDebug() << "Phantom - execute: Configuration";
|
||||||
|
const QMetaObject* configMetaObj = m_config.metaObject();
|
||||||
|
for (int i = 0, ilen = configMetaObj->propertyCount(); i < ilen; ++i) {
|
||||||
|
qDebug() << " " << i << configMetaObj->property(i).name() << ":" << m_config.property(configMetaObj->property(i).name()).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Phantom - execute: Script & Arguments";
|
||||||
|
qDebug() << " " << "script:" << m_config.scriptFile();
|
||||||
|
QStringList args = m_config.scriptArgs();
|
||||||
|
for (int i = 0, ilen = args.length(); i < ilen; ++i) {
|
||||||
|
qDebug() << " " << i << "arg:" << args.at(i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m_config.isWebdriverMode()) { // Remote WebDriver mode requested
|
||||||
|
qDebug() << "Phantom - execute: Starting Remote WebDriver mode";
|
||||||
|
|
||||||
|
Terminal::instance()->cout("PhantomJS is launching GhostDriver...");
|
||||||
|
if (!Utils::injectJsInFrame(":/ghostdriver/main.js", m_scriptFileEnc, QDir::currentPath(), m_page->mainFrame(), true)) {
|
||||||
|
m_returnValue = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (m_config.scriptFile().isEmpty()) { // REPL mode requested
|
||||||
|
qDebug() << "Phantom - execute: Starting REPL mode";
|
||||||
|
|
||||||
// Create the REPL: it will launch itself, no need to store this variable.
|
// Create the REPL: it will launch itself, no need to store this variable.
|
||||||
REPL::getInstance(m_page->mainFrame(), this);
|
REPL::getInstance(m_page->mainFrame(), this);
|
||||||
} else {
|
} else { // Load the User Script
|
||||||
// Load the User Script
|
qDebug() << "Phantom - execute: Starting normal mode";
|
||||||
|
|
||||||
if (m_config.debug()) {
|
if (m_config.debug()) {
|
||||||
// Debug enabled
|
// Debug enabled
|
||||||
if (!Utils::loadJSForDebug(m_config.scriptFile(), m_scriptFileEnc, QDir::currentPath(), m_page->mainFrame(), m_config.remoteDebugAutorun())) {
|
if (!Utils::loadJSForDebug(m_config.scriptFile(), m_scriptFileEnc, QDir::currentPath(), m_page->mainFrame(), m_config.remoteDebugAutorun())) {
|
||||||
|
@ -261,6 +289,11 @@ void Phantom::setCookiesEnabled(const bool value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Phantom::webdriverMode() const
|
||||||
|
{
|
||||||
|
return m_config.isWebdriverMode();
|
||||||
|
}
|
||||||
|
|
||||||
// public slots:
|
// public slots:
|
||||||
QObject *Phantom::createWebPage()
|
QObject *Phantom::createWebPage()
|
||||||
{
|
{
|
||||||
|
@ -331,12 +364,19 @@ void Phantom::loadModule(const QString &moduleSource, const QString &filename)
|
||||||
|
|
||||||
bool Phantom::injectJs(const QString &jsFilePath)
|
bool Phantom::injectJs(const QString &jsFilePath)
|
||||||
{
|
{
|
||||||
|
QString pre = "";
|
||||||
qDebug() << "Phantom - injectJs:" << jsFilePath;
|
qDebug() << "Phantom - injectJs:" << jsFilePath;
|
||||||
|
|
||||||
|
// If in Remote Webdriver Mode, we need to manipulate the PATH, to point it to a resource in `ghostdriver.qrc`
|
||||||
|
if (webdriverMode()) {
|
||||||
|
pre = ":/ghostdriver/";
|
||||||
|
qDebug() << "Phantom - injectJs: prepending" << pre;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_terminated)
|
if (m_terminated)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return Utils::injectJsInFrame(jsFilePath, libraryPath(), m_page->mainFrame());
|
return Utils::injectJsInFrame(pre + jsFilePath, libraryPath(), m_page->mainFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Phantom::exit(int code)
|
void Phantom::exit(int code)
|
||||||
|
|
|
@ -56,6 +56,7 @@ class Phantom: public REPLCompletable
|
||||||
Q_PROPERTY(QObject *page READ page)
|
Q_PROPERTY(QObject *page READ page)
|
||||||
Q_PROPERTY(bool cookiesEnabled READ areCookiesEnabled WRITE setCookiesEnabled)
|
Q_PROPERTY(bool cookiesEnabled READ areCookiesEnabled WRITE setCookiesEnabled)
|
||||||
Q_PROPERTY(QVariantList cookies READ cookies WRITE setCookies)
|
Q_PROPERTY(QVariantList cookies READ cookies WRITE setCookies)
|
||||||
|
Q_PROPERTY(bool webdriverMode READ webdriverMode)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Private constructor: the Phantom class is a singleton
|
// Private constructor: the Phantom class is a singleton
|
||||||
|
@ -99,6 +100,8 @@ public:
|
||||||
bool areCookiesEnabled() const;
|
bool areCookiesEnabled() const;
|
||||||
void setCookiesEnabled(const bool value);
|
void setCookiesEnabled(const bool value);
|
||||||
|
|
||||||
|
bool webdriverMode() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QObject *createWebPage();
|
QObject *createWebPage();
|
||||||
QObject *createWebServer();
|
QObject *createWebServer();
|
||||||
|
|
|
@ -85,7 +85,7 @@ public:
|
||||||
Multiple = 0x04, /**< argument can be used multiple time and will produce multiple signals. */
|
Multiple = 0x04, /**< argument can be used multiple time and will produce multiple signals. */
|
||||||
ParameterFence = 0x08, //**< all arguments after this point are considered parameters, not options. */
|
ParameterFence = 0x08, //**< all arguments after this point are considered parameters, not options. */
|
||||||
MandatoryMultiple = Mandatory|Multiple,
|
MandatoryMultiple = Mandatory|Multiple,
|
||||||
OptionalMultiple = Optional|Multiple,
|
OptionalMultiple = Optional|Multiple
|
||||||
} Flags;
|
} Flags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue