mirror of
https://github.com/thoughtbot/capybara-webkit
synced 2023-03-27 23:22:28 -04:00
Working on frame handling. In terms of the QT code, the non-frame-related
specs pass with these changes (e.g. mainFrame() => currentFrame() and the new injectJavascriptHelpers() code in WebPage.cpp). It seems like the current JS+xpath implementation dives in to iframes already. Is this desired behavior? I wonder if that works with x-domain iframes? I doubt it... Also, this design assumes that we only step one frame down at a time... Lastly, I'm really not sure how QWebKit decides which frame is currentFrame(). For now, I'm hoping to be able to use the QWebFrame setFocus() method. This may be a dead end though. We may have to have WebPage manually keep track of the "current" frame.
This commit is contained in:
parent
9db603cbea
commit
182cb2e5b7
16 changed files with 141 additions and 15 deletions
|
@ -53,7 +53,9 @@ class Capybara::Driver::Webkit
|
||||||
end
|
end
|
||||||
|
|
||||||
def within_frame(frame_id)
|
def within_frame(frame_id)
|
||||||
raise Capybara::NotSupportedByDriverError
|
browser.frame_focus_id(frame_id)
|
||||||
|
yield
|
||||||
|
browser.frame_focus_parent
|
||||||
end
|
end
|
||||||
|
|
||||||
def within_window(handle)
|
def within_window(handle)
|
||||||
|
|
|
@ -30,6 +30,14 @@ class Capybara::Driver::Webkit
|
||||||
command("Url")
|
command("Url")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def frame_focus_id(frame_id)
|
||||||
|
command("FrameFocus", frame_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def frame_focus_parent
|
||||||
|
command("FrameFocus")
|
||||||
|
end
|
||||||
|
|
||||||
def command(name, *args)
|
def command(name, *args)
|
||||||
@socket.puts name
|
@socket.puts name
|
||||||
@socket.puts args.size
|
@socket.puts args.size
|
||||||
|
|
|
@ -6,6 +6,89 @@ describe Capybara::Driver::Webkit do
|
||||||
before { subject.visit("/hello/world?success=true") }
|
before { subject.visit("/hello/world?success=true") }
|
||||||
after { subject.reset! }
|
after { subject.reset! }
|
||||||
|
|
||||||
|
context "iframe app" do
|
||||||
|
before(:all) do
|
||||||
|
@app = lambda do |env|
|
||||||
|
params = ::Rack::Utils.parse_query(env['QUERY_STRING'])
|
||||||
|
iframe = unless params["iframe"]
|
||||||
|
"<iframe id=\"f\" src=\"/hello/world?iframe=true\"></iframe>"
|
||||||
|
end
|
||||||
|
if iframe
|
||||||
|
p_id = "farewell"
|
||||||
|
msg = "goodbye"
|
||||||
|
else
|
||||||
|
p_id = "greeting"
|
||||||
|
msg = "hello"
|
||||||
|
end
|
||||||
|
body = <<-HTML
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style type="text/css">
|
||||||
|
#display_none { display: none }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="display_none">
|
||||||
|
<div id="invisible">Can't see me</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.write("<p id='#{p_id}'>#{msg}</p>");
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
HTML
|
||||||
|
[200,
|
||||||
|
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
||||||
|
[body]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "finds content after loading a URL" do
|
||||||
|
subject.within_frame("f") do
|
||||||
|
subject.find("//*[contains(., 'goodbye')]").should_not be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an attribute's value" do
|
||||||
|
subject.within_frame("f") do
|
||||||
|
subject.find("//p").first["id"].should == "farewell"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a node's text" do
|
||||||
|
subject.within_frame("f") do
|
||||||
|
subject.find("//p").first.text.should == "goodbye"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the current URL" do
|
||||||
|
subject.within_frame("f") do
|
||||||
|
port = subject.instance_variable_get("@rack_server").port
|
||||||
|
subject.current_url.should == "http://127.0.0.1:#{port}/hello/world?iframe=true"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the source code for the page" do
|
||||||
|
subject.within_frame("f") do
|
||||||
|
subject.source.should =~ %r{<html>.*farewell.*}m
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "evaluates Javascript" do
|
||||||
|
subject.within_frame("f") do
|
||||||
|
result = subject.evaluate_script(%<document.getElementById('farewell').innerText>)
|
||||||
|
result.should == "hello"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "executes Javascript" do
|
||||||
|
subject.within_frame("f") do
|
||||||
|
subject.execute_script(%<document.getElementById('farewell').innerHTML = 'yo'>)
|
||||||
|
subject.find("//p[contains(., 'yo')]").should_not be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "hello app" do
|
context "hello app" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
@app = lambda do |env|
|
@app = lambda do |env|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "Source.h"
|
#include "Source.h"
|
||||||
#include "Evaluate.h"
|
#include "Evaluate.h"
|
||||||
#include "Execute.h"
|
#include "Execute.h"
|
||||||
|
#include "FrameFocus.h"
|
||||||
|
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
@ -7,7 +7,7 @@ Evaluate::Evaluate(WebPage *page, QObject *parent) : Command(page, parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Evaluate::start(QStringList &arguments) {
|
void Evaluate::start(QStringList &arguments) {
|
||||||
QVariant result = page()->mainFrame()->evaluateJavaScript(arguments[0]);
|
QVariant result = page()->currentFrame()->evaluateJavaScript(arguments[0]);
|
||||||
addVariant(result);
|
addVariant(result);
|
||||||
emit finished(true, m_buffer);
|
emit finished(true, m_buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ Execute::Execute(WebPage *page, QObject *parent) : Command(page, parent) {
|
||||||
|
|
||||||
void Execute::start(QStringList &arguments) {
|
void Execute::start(QStringList &arguments) {
|
||||||
QString script = arguments[0] + QString("; 'success'");
|
QString script = arguments[0] + QString("; 'success'");
|
||||||
QVariant result = page()->mainFrame()->evaluateJavaScript(script);
|
QVariant result = page()->currentFrame()->evaluateJavaScript(script);
|
||||||
QString response;
|
QString response;
|
||||||
if (result.isValid()) {
|
if (result.isValid()) {
|
||||||
emit finished(true, response);
|
emit finished(true, response);
|
||||||
|
|
12
src/FrameFocus.cpp
Normal file
12
src/FrameFocus.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "FrameFocus.h"
|
||||||
|
#include "Command.h"
|
||||||
|
#include "WebPage.h"
|
||||||
|
|
||||||
|
FrameFocus::FrameFocus(WebPage *page, QObject *parent) : Command(page, parent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameFocus::start(QStringList &arguments) {
|
||||||
|
QString response;
|
||||||
|
emit finished(true, response);
|
||||||
|
}
|
||||||
|
|
12
src/FrameFocus.h
Normal file
12
src/FrameFocus.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "Command.h"
|
||||||
|
|
||||||
|
class WebPage;
|
||||||
|
|
||||||
|
class FrameFocus : public Command {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrameFocus(WebPage *page, QObject *parent = 0);
|
||||||
|
virtual void start(QStringList &arguments);
|
||||||
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@ void Reset::start(QStringList &arguments) {
|
||||||
Q_UNUSED(arguments);
|
Q_UNUSED(arguments);
|
||||||
|
|
||||||
page()->triggerAction(QWebPage::Stop);
|
page()->triggerAction(QWebPage::Stop);
|
||||||
page()->mainFrame()->setHtml("<html><body></body></html>");
|
page()->currentFrame()->setHtml("<html><body></body></html>");
|
||||||
page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar());
|
page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar());
|
||||||
QString response = "";
|
QString response = "";
|
||||||
emit finished(true, response);
|
emit finished(true, response);
|
||||||
|
|
|
@ -7,7 +7,7 @@ Source::Source(WebPage *page, QObject *parent) : Command(page, parent) {
|
||||||
void Source::start(QStringList &arguments) {
|
void Source::start(QStringList &arguments) {
|
||||||
Q_UNUSED(arguments)
|
Q_UNUSED(arguments)
|
||||||
|
|
||||||
QString response = page()->mainFrame()->toHtml();
|
QString response = page()->currentFrame()->toHtml();
|
||||||
|
|
||||||
emit finished(true, response);
|
emit finished(true, response);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ Url::Url(WebPage *page, QObject *parent) : Command(page, parent) {
|
||||||
void Url::start(QStringList &argments) {
|
void Url::start(QStringList &argments) {
|
||||||
Q_UNUSED(argments);
|
Q_UNUSED(argments);
|
||||||
|
|
||||||
QUrl humanUrl = page()->mainFrame()->url();
|
QUrl humanUrl = page()->currentFrame()->url();
|
||||||
QByteArray encodedBytes = humanUrl.toEncoded();
|
QByteArray encodedBytes = humanUrl.toEncoded();
|
||||||
QString response = QString(encodedBytes);
|
QString response = QString(encodedBytes);
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ Visit::Visit(WebPage *page, QObject *parent) : Command(page, parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Visit::start(QStringList &arguments) {
|
void Visit::start(QStringList &arguments) {
|
||||||
page()->mainFrame()->setUrl(QUrl(arguments[0]));
|
page()->currentFrame()->setUrl(QUrl(arguments[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Visit::loadFinished(bool success) {
|
void Visit::loadFinished(bool success) {
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
WebPage::WebPage(QObject *parent) : QWebPage(parent) {
|
WebPage::WebPage(QObject *parent) : QWebPage(parent) {
|
||||||
connect(mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
|
|
||||||
this, SLOT(injectJavascriptHelpers()));
|
|
||||||
QResource javascript(":/capybara.js");
|
QResource javascript(":/capybara.js");
|
||||||
char * javascriptString = new char[javascript.size() + 1];
|
char * javascriptString = new char[javascript.size() + 1];
|
||||||
strcpy(javascriptString, (const char *)javascript.data());
|
strcpy(javascriptString, (const char *)javascript.data());
|
||||||
|
@ -14,10 +12,18 @@ WebPage::WebPage(QObject *parent) : QWebPage(parent) {
|
||||||
m_loading = false;
|
m_loading = false;
|
||||||
connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
|
connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
|
||||||
connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
|
connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
|
||||||
|
connect(this, SIGNAL(frameCreated(QWebFrame *)),
|
||||||
|
this, SLOT(frameCreated(QWebFrame *)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebPage::frameCreated(QWebFrame * frame) {
|
||||||
|
connect(frame, SIGNAL(javaScriptWindowObjectCleared()),
|
||||||
|
this, SLOT(injectJavascriptHelpers()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebPage::injectJavascriptHelpers() {
|
void WebPage::injectJavascriptHelpers() {
|
||||||
mainFrame()->evaluateJavaScript(m_capybaraJavascript);
|
QWebFrame* frame = qobject_cast<QWebFrame *>(QObject::sender());
|
||||||
|
frame->evaluateJavaScript(m_capybaraJavascript);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebPage::shouldInterruptJavaScript() {
|
bool WebPage::shouldInterruptJavaScript() {
|
||||||
|
@ -28,9 +34,9 @@ QVariant WebPage::invokeCapybaraFunction(const char *name, QStringList &argument
|
||||||
QString qname(name);
|
QString qname(name);
|
||||||
QString objectName("CapybaraInvocation");
|
QString objectName("CapybaraInvocation");
|
||||||
JavascriptInvocation invocation(qname, arguments);
|
JavascriptInvocation invocation(qname, arguments);
|
||||||
mainFrame()->addToJavaScriptWindowObject(objectName, &invocation);
|
currentFrame()->addToJavaScriptWindowObject(objectName, &invocation);
|
||||||
QString javascript = QString("Capybara.invoke()");
|
QString javascript = QString("Capybara.invoke()");
|
||||||
return mainFrame()->evaluateJavaScript(javascript);
|
return currentFrame()->evaluateJavaScript(javascript);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant WebPage::invokeCapybaraFunction(QString &name, QStringList &arguments) {
|
QVariant WebPage::invokeCapybaraFunction(QString &name, QStringList &arguments) {
|
||||||
|
@ -76,6 +82,6 @@ bool WebPage::isLoading() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WebPage::failureString() {
|
QString WebPage::failureString() {
|
||||||
return QString("Unable to load URL: ") + mainFrame()->url().toString();
|
return QString("Unable to load URL: ") + currentFrame()->url().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ class WebPage : public QWebPage {
|
||||||
void loadStarted();
|
void loadStarted();
|
||||||
void loadFinished(bool);
|
void loadFinished(bool);
|
||||||
bool isLoading() const;
|
bool isLoading() const;
|
||||||
|
void frameCreated(QWebFrame *);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
|
virtual void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
|
||||||
|
|
|
@ -11,3 +11,4 @@ CHECK_COMMAND(Url)
|
||||||
CHECK_COMMAND(Source)
|
CHECK_COMMAND(Source)
|
||||||
CHECK_COMMAND(Evaluate)
|
CHECK_COMMAND(Evaluate)
|
||||||
CHECK_COMMAND(Execute)
|
CHECK_COMMAND(Execute)
|
||||||
|
CHECK_COMMAND(FrameFocus)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
TARGET = webkit_server
|
TARGET = webkit_server
|
||||||
DESTDIR = .
|
DESTDIR = .
|
||||||
HEADERS = WebPage.h Server.h Connection.h Command.h Visit.h Find.h Reset.h Node.h JavascriptInvocation.h Url.h Source.h Evaluate.h Execute.h
|
HEADERS = WebPage.h Server.h Connection.h Command.h Visit.h Find.h Reset.h Node.h JavascriptInvocation.h Url.h Source.h Evaluate.h Execute.h FrameFocus.h
|
||||||
SOURCES = main.cpp WebPage.cpp Server.cpp Connection.cpp Command.cpp Visit.cpp Find.cpp Reset.cpp Node.cpp JavascriptInvocation.cpp Url.cpp Source.cpp Evaluate.cpp Execute.cpp
|
SOURCES = main.cpp WebPage.cpp Server.cpp Connection.cpp Command.cpp Visit.cpp Find.cpp Reset.cpp Node.cpp JavascriptInvocation.cpp Url.cpp Source.cpp Evaluate.cpp Execute.cpp FrameFocus.cpp
|
||||||
RESOURCES = webkit_server.qrc
|
RESOURCES = webkit_server.qrc
|
||||||
QT += network webkit
|
QT += network webkit
|
||||||
CONFIG += console
|
CONFIG += console
|
||||||
|
|
Loading…
Reference in a new issue