mirror of https://github.com/vitalif/phantomjs
support for backtraces (part 2).
add a default error handler on all pages. people can override if they need. ensure error handler can be removed without errors. Hack ScriptSourceCode so we can pass in a raw string and not have it validated as a URL change source location hint for webpage.evaluate(). http://code.google.com/p/phantomjs/issues/detail?id=166 Please enter the commit message for your changes. Lines starting1.5
parent
afe570484f
commit
a48770cba3
|
@ -34,7 +34,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function require(name) {
|
function require(name) {
|
||||||
|
|
||||||
var code, func, exports;
|
var code, func, exports;
|
||||||
|
|
||||||
if (name === 'webpage' || name === 'fs' || name === 'webserver' || name === 'system') {
|
if (name === 'webpage' || name === 'fs' || name === 'webserver' || name === 'system') {
|
||||||
|
@ -55,5 +54,35 @@ function require(name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var handler;
|
||||||
|
var signal = phantom.page.javaScriptErrorSent;
|
||||||
|
|
||||||
|
phantom.__defineSetter__('onError', function(f) {
|
||||||
|
if (handler && typeof handler === 'function') {
|
||||||
|
try { signal.disconnect(handler) } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
handler = f;
|
||||||
|
|
||||||
|
if (typeof f === 'function') {
|
||||||
|
signal.connect(f);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})();
|
||||||
|
|
||||||
|
// TODO: Make this output to STDERR
|
||||||
|
phantom.defaultErrorHandler = function(error, backtrace) {
|
||||||
|
console.log(error + "\n");
|
||||||
|
|
||||||
|
backtrace.forEach(function(item) {
|
||||||
|
var message = item.file + ":" + item.line;
|
||||||
|
if (item.function) message += " in " + item.function
|
||||||
|
console.log(" " + message);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
phantom.onError = phantom.defaultErrorHandler;
|
||||||
|
|
||||||
// Legacy way to use WebPage
|
// Legacy way to use WebPage
|
||||||
window.WebPage = require('webpage').create;
|
window.WebPage = require('webpage').create;
|
||||||
|
|
|
@ -205,7 +205,7 @@ void Config::loadJsonFile(const QString &filePath)
|
||||||
// Add this object to the global scope
|
// Add this object to the global scope
|
||||||
webPage.mainFrame()->addToJavaScriptWindowObject("config", this);
|
webPage.mainFrame()->addToJavaScriptWindowObject("config", this);
|
||||||
// Apply the JSON config settings to this very object
|
// Apply the JSON config settings to this very object
|
||||||
webPage.mainFrame()->evaluateJavaScript(configurator.arg(jsonConfig));
|
webPage.mainFrame()->evaluateJavaScript(configurator.arg(jsonConfig), QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Config::autoLoadImages() const
|
bool Config::autoLoadImages() const
|
||||||
|
|
|
@ -48,17 +48,23 @@ CSConverter *CSConverter::instance()
|
||||||
CSConverter::CSConverter()
|
CSConverter::CSConverter()
|
||||||
: QObject(QCoreApplication::instance())
|
: QObject(QCoreApplication::instance())
|
||||||
{
|
{
|
||||||
m_webPage.mainFrame()->evaluateJavaScript(Utils::readResourceFileUtf8(":/coffee-script.js"));
|
m_webPage.mainFrame()->evaluateJavaScript(
|
||||||
|
Utils::readResourceFileUtf8(":/coffee-script.js"),
|
||||||
|
QString("phantomjs://coffee-script.js")
|
||||||
|
);
|
||||||
m_webPage.mainFrame()->addToJavaScriptWindowObject("converter", this);
|
m_webPage.mainFrame()->addToJavaScriptWindowObject("converter", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant CSConverter::convert(const QString &script)
|
QVariant CSConverter::convert(const QString &script)
|
||||||
{
|
{
|
||||||
setProperty("source", script);
|
setProperty("source", script);
|
||||||
QVariant result = m_webPage.mainFrame()->evaluateJavaScript("try {" \
|
QVariant result = m_webPage.mainFrame()->evaluateJavaScript(
|
||||||
" [true, this.CoffeeScript.compile(converter.source)];" \
|
"try {" \
|
||||||
"} catch (error) {" \
|
" [true, this.CoffeeScript.compile(converter.source)];" \
|
||||||
" [false, error.message];" \
|
"} catch (error) {" \
|
||||||
"}");
|
" [false, error.message];" \
|
||||||
|
"}",
|
||||||
|
QString()
|
||||||
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,8 +99,12 @@ exports.create = function (opts) {
|
||||||
this[signalName].disconnect(handlers[signalName]);
|
this[signalName].disconnect(handlers[signalName]);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlers[signalName] = f;
|
handlers[signalName] = f;
|
||||||
this[signalName].connect(handlers[signalName]);
|
|
||||||
|
if (typeof f === 'function') {
|
||||||
|
this[signalName].connect(f);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +125,10 @@ exports.create = function (opts) {
|
||||||
|
|
||||||
defineSetter("onConsoleMessage", "javaScriptConsoleMessageSent");
|
defineSetter("onConsoleMessage", "javaScriptConsoleMessageSent");
|
||||||
|
|
||||||
|
defineSetter("onError", "javaScriptErrorSent");
|
||||||
|
|
||||||
|
page.onError = phantom.defaultErrorHandler;
|
||||||
|
|
||||||
page.open = function (url, arg1, arg2, arg3, arg4) {
|
page.open = function (url, arg1, arg2, arg3, arg4) {
|
||||||
if (arguments.length === 1) {
|
if (arguments.length === 1) {
|
||||||
this.openUrl(url, 'get', this.settings);
|
this.openUrl(url, 'get', this.settings);
|
||||||
|
|
|
@ -122,8 +122,6 @@ Phantom::Phantom(QObject *parent)
|
||||||
m_page->applySettings(m_defaultPageSettings);
|
m_page->applySettings(m_defaultPageSettings);
|
||||||
|
|
||||||
setLibraryPath(QFileInfo(m_config.scriptFile()).dir().absolutePath());
|
setLibraryPath(QFileInfo(m_config.scriptFile()).dir().absolutePath());
|
||||||
|
|
||||||
onInitialized();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Phantom::~Phantom()
|
Phantom::~Phantom()
|
||||||
|
@ -208,6 +206,11 @@ QVariantMap Phantom::version() const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QObject *Phantom::page() const
|
||||||
|
{
|
||||||
|
return m_page;
|
||||||
|
}
|
||||||
|
|
||||||
// public slots:
|
// public slots:
|
||||||
QObject *Phantom::createWebPage()
|
QObject *Phantom::createWebPage()
|
||||||
{
|
{
|
||||||
|
@ -287,10 +290,7 @@ void Phantom::debugExit(int code)
|
||||||
// private slots:
|
// private slots:
|
||||||
void Phantom::printConsoleMessage(const QString &message, int lineNumber, const QString &source)
|
void Phantom::printConsoleMessage(const QString &message, int lineNumber, const QString &source)
|
||||||
{
|
{
|
||||||
QString msg = message;
|
Terminal::instance()->cout(message);
|
||||||
if (!source.isEmpty())
|
|
||||||
msg = source + ":" + QString::number(lineNumber) + " " + msg;
|
|
||||||
Terminal::instance()->cout(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Phantom::onInitialized()
|
void Phantom::onInitialized()
|
||||||
|
@ -299,7 +299,10 @@ void Phantom::onInitialized()
|
||||||
m_page->mainFrame()->addToJavaScriptWindowObject("phantom", this);
|
m_page->mainFrame()->addToJavaScriptWindowObject("phantom", this);
|
||||||
|
|
||||||
// Bootstrap the PhantomJS scope
|
// Bootstrap the PhantomJS scope
|
||||||
m_page->mainFrame()->evaluateJavaScript(Utils::readResourceFileUtf8(":/bootstrap.js"));
|
m_page->mainFrame()->evaluateJavaScript(
|
||||||
|
Utils::readResourceFileUtf8(":/bootstrap.js"),
|
||||||
|
QString("phantomjs://bootstrap.js")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private:
|
// private:
|
||||||
|
|
|
@ -52,6 +52,7 @@ class Phantom: public REPLCompletable
|
||||||
Q_PROPERTY(QString outputEncoding READ outputEncoding WRITE setOutputEncoding)
|
Q_PROPERTY(QString outputEncoding READ outputEncoding WRITE setOutputEncoding)
|
||||||
Q_PROPERTY(QString scriptName READ scriptName)
|
Q_PROPERTY(QString scriptName READ scriptName)
|
||||||
Q_PROPERTY(QVariantMap version READ version)
|
Q_PROPERTY(QVariantMap version READ version)
|
||||||
|
Q_PROPERTY(QObject *page READ page)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Phantom(QObject *parent = 0);
|
Phantom(QObject *parent = 0);
|
||||||
|
@ -74,6 +75,8 @@ public:
|
||||||
|
|
||||||
QVariantMap version() const;
|
QVariantMap version() const;
|
||||||
|
|
||||||
|
QObject* page() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QObject *createWebPage();
|
QObject *createWebPage();
|
||||||
QObject *createWebServer();
|
QObject *createWebServer();
|
||||||
|
|
|
@ -99,7 +99,7 @@ REPL::REPL(QWebFrame *webframe, Phantom *parent)
|
||||||
linenoiseSetCompletionCallback(REPL::offerCompletion);
|
linenoiseSetCompletionCallback(REPL::offerCompletion);
|
||||||
|
|
||||||
// Inject REPL utility functions
|
// Inject REPL utility functions
|
||||||
m_webframe->evaluateJavaScript(Utils::readResourceFileUtf8(":/repl.js"));
|
m_webframe->evaluateJavaScript(Utils::readResourceFileUtf8(":/repl.js"), QString("phantomjs://repl.js"));
|
||||||
|
|
||||||
// Start the REPL's loop
|
// Start the REPL's loop
|
||||||
QTimer::singleShot(0, this, SLOT(startLoop()));
|
QTimer::singleShot(0, this, SLOT(startLoop()));
|
||||||
|
@ -133,7 +133,8 @@ void REPL::offerCompletion(const char *buf, linenoiseCompletions *lc)
|
||||||
QStringList completions = REPL::getInstance()->m_webframe->evaluateJavaScript(
|
QStringList completions = REPL::getInstance()->m_webframe->evaluateJavaScript(
|
||||||
QString(JS_RETURN_POSSIBLE_COMPLETIONS).arg(
|
QString(JS_RETURN_POSSIBLE_COMPLETIONS).arg(
|
||||||
toInspect,
|
toInspect,
|
||||||
toComplete)
|
toComplete),
|
||||||
|
QString()
|
||||||
).toStringList();
|
).toStringList();
|
||||||
|
|
||||||
foreach (QString c, completions) {
|
foreach (QString c, completions) {
|
||||||
|
@ -158,7 +159,7 @@ void REPL::startLoop()
|
||||||
// Send the user input to the main Phantom frame for evaluation
|
// Send the user input to the main Phantom frame for evaluation
|
||||||
m_webframe->evaluateJavaScript(
|
m_webframe->evaluateJavaScript(
|
||||||
QString(JS_EVAL_USER_INPUT).arg(
|
QString(JS_EVAL_USER_INPUT).arg(
|
||||||
QString(userInput).replace('"', "\\\"")));
|
QString(userInput).replace('"', "\\\"")), QString("phantomjs://repl-input"));
|
||||||
|
|
||||||
// Save command in the REPL history
|
// Save command in the REPL history
|
||||||
linenoiseHistoryAdd(userInput);
|
linenoiseHistoryAdd(userInput);
|
||||||
|
|
|
@ -94,7 +94,7 @@ bool Utils::injectJsInFrame(const QString &jsFilePath, const Encoding &jsFileEnc
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Execute JS code in the context of the document
|
// Execute JS code in the context of the document
|
||||||
targetFrame->evaluateJavaScript(scriptBody);
|
targetFrame->evaluateJavaScript(scriptBody, jsFilePath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ bool Utils::loadJSForDebug(const QString& jsFilePath, const Encoding& jsFileEnc,
|
||||||
targetFrame->setHtml(remoteDebuggerHarnessSrc);
|
targetFrame->setHtml(remoteDebuggerHarnessSrc);
|
||||||
|
|
||||||
if (autorun) {
|
if (autorun) {
|
||||||
targetFrame->evaluateJavaScript("__run()");
|
targetFrame->evaluateJavaScript("__run()", QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -92,6 +92,10 @@ protected:
|
||||||
m_webPage->emitConsoleMessage(message, lineNumber, sourceID);
|
m_webPage->emitConsoleMessage(message, lineNumber, sourceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void javaScriptError(const QWebPage::JavaScriptError& error) {
|
||||||
|
m_webPage->emitError(error);
|
||||||
|
}
|
||||||
|
|
||||||
QString userAgentForUrl(const QUrl &url) const {
|
QString userAgentForUrl(const QUrl &url) const {
|
||||||
Q_UNUSED(url);
|
Q_UNUSED(url);
|
||||||
return m_userAgent;
|
return m_userAgent;
|
||||||
|
@ -287,7 +291,7 @@ QVariantMap WebPage::paperSize() const
|
||||||
QVariant WebPage::evaluate(const QString &code)
|
QVariant WebPage::evaluate(const QString &code)
|
||||||
{
|
{
|
||||||
QString function = "(" + code + ")()";
|
QString function = "(" + code + ")()";
|
||||||
return m_mainFrame->evaluateJavaScript(function);
|
return m_mainFrame->evaluateJavaScript(function, QString("phantomjs://webpage.evaluate()"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPage::emitAlert(const QString &msg)
|
void WebPage::emitAlert(const QString &msg)
|
||||||
|
@ -300,6 +304,25 @@ void WebPage::emitConsoleMessage(const QString &message, int lineNumber, const Q
|
||||||
emit javaScriptConsoleMessageSent(message, lineNumber, source);
|
emit javaScriptConsoleMessageSent(message, lineNumber, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebPage::emitError(const QWebPage::JavaScriptError& error)
|
||||||
|
{
|
||||||
|
QList<QWebPage::JavaScriptFrame> backtrace = error.backtrace();
|
||||||
|
QVariantList newBacktrace = QVariantList();
|
||||||
|
|
||||||
|
for (int i = 0; i < backtrace.size(); ++i) {
|
||||||
|
QWebPage::JavaScriptFrame frame = backtrace.at(i);
|
||||||
|
|
||||||
|
QVariantMap newFrame = QVariantMap();
|
||||||
|
newFrame["file"] = frame.file();
|
||||||
|
newFrame["line"] = frame.line();
|
||||||
|
newFrame["function"] = frame.function();
|
||||||
|
|
||||||
|
newBacktrace << newFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit javaScriptErrorSent(error.message(), newBacktrace);
|
||||||
|
}
|
||||||
|
|
||||||
void WebPage::finish(bool ok)
|
void WebPage::finish(bool ok)
|
||||||
{
|
{
|
||||||
QString status = ok ? "success" : "fail";
|
QString status = ok ? "success" : "fail";
|
||||||
|
@ -349,7 +372,7 @@ void WebPage::openUrl(const QString &address, const QVariant &op, const QVariant
|
||||||
networkOp = QNetworkAccessManager::DeleteOperation;
|
networkOp = QNetworkAccessManager::DeleteOperation;
|
||||||
|
|
||||||
if (networkOp == QNetworkAccessManager::UnknownOperation) {
|
if (networkOp == QNetworkAccessManager::UnknownOperation) {
|
||||||
m_mainFrame->evaluateJavaScript("console.error('Unknown network operation: " + operation + "');");
|
m_mainFrame->evaluateJavaScript("console.error('Unknown network operation: " + operation + "');", QString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,7 +621,7 @@ bool WebPage::injectJs(const QString &jsFilePath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPage::_appendScriptElement(const QString &scriptUrl) {
|
void WebPage::_appendScriptElement(const QString &scriptUrl) {
|
||||||
m_mainFrame->evaluateJavaScript( QString(JS_APPEND_SCRIPT_ELEMENT).arg(scriptUrl) );
|
m_mainFrame->evaluateJavaScript( QString(JS_APPEND_SCRIPT_ELEMENT).arg(scriptUrl), scriptUrl );
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPage::sendEvent(const QString &type, const QVariant &arg1, const QVariant &arg2)
|
void WebPage::sendEvent(const QString &type, const QVariant &arg1, const QVariant &arg2)
|
||||||
|
|
|
@ -102,6 +102,7 @@ signals:
|
||||||
void loadFinished(const QString &status);
|
void loadFinished(const QString &status);
|
||||||
void javaScriptAlertSent(const QString &msg);
|
void javaScriptAlertSent(const QString &msg);
|
||||||
void javaScriptConsoleMessageSent(const QString &message, int lineNumber, const QString &source);
|
void javaScriptConsoleMessageSent(const QString &message, int lineNumber, const QString &source);
|
||||||
|
void javaScriptErrorSent(const QString &message, const QVariantList &backtrace);
|
||||||
void resourceRequested(const QVariant &req);
|
void resourceRequested(const QVariant &req);
|
||||||
void resourceReceived(const QVariant &resource);
|
void resourceReceived(const QVariant &resource);
|
||||||
|
|
||||||
|
@ -116,6 +117,7 @@ private:
|
||||||
|
|
||||||
void emitAlert(const QString &msg);
|
void emitAlert(const QString &msg);
|
||||||
void emitConsoleMessage(const QString &msg, int lineNumber, const QString &source);
|
void emitConsoleMessage(const QString &msg, int lineNumber, const QString &source);
|
||||||
|
void emitError(const QWebPage::JavaScriptError& error);
|
||||||
|
|
||||||
virtual void initCompletions();
|
virtual void initCompletions();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue