2011-02-18 22:53:06 -05:00
|
|
|
require 'spec_helper'
|
|
|
|
require 'capybara/driver/webkit'
|
|
|
|
|
|
|
|
describe Capybara::Driver::Webkit do
|
2011-02-25 23:47:55 -05:00
|
|
|
before(:all) { @@browser = Capybara::Driver::Webkit::Browser.new }
|
2011-02-26 16:35:21 -05:00
|
|
|
subject { Capybara::Driver::Webkit.new(app, :browser => @@browser) }
|
2011-02-25 17:53:36 -05:00
|
|
|
before { subject.visit("/hello/world?success=true") }
|
2011-02-18 22:53:06 -05:00
|
|
|
after { subject.reset! }
|
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
context "hello app" do
|
|
|
|
let(:app) do
|
|
|
|
lambda do |env|
|
|
|
|
body = <<-HTML
|
|
|
|
<html><body>
|
|
|
|
<div style="display: none">
|
|
|
|
<div id="invisible">Can't see me</div>
|
|
|
|
</div>
|
|
|
|
<script type="text/javascript">
|
|
|
|
document.write("<p id='greeting'>he" + "llo</p>");
|
|
|
|
</script>
|
|
|
|
</body></html>
|
|
|
|
HTML
|
|
|
|
[200,
|
|
|
|
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
|
|
|
[body]]
|
|
|
|
end
|
|
|
|
end
|
2011-02-18 22:53:06 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "finds content after loading a URL" do
|
|
|
|
subject.find("//*[contains(., 'hello')]").should_not be_empty
|
|
|
|
end
|
2011-02-24 23:22:56 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "has an empty page after reseting" do
|
|
|
|
subject.reset!
|
|
|
|
subject.find("//*[contains(., 'hello')]").should be_empty
|
|
|
|
end
|
2011-02-25 00:15:08 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "raises an error for an invalid xpath query" do
|
|
|
|
expect { subject.find("totally invalid salad") }.
|
|
|
|
to raise_error(Capybara::Driver::Webkit::WebkitError, /xpath/i)
|
|
|
|
end
|
2011-02-25 22:57:55 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "returns an attribute's value" do
|
|
|
|
subject.find("//p").first["id"].should == "greeting"
|
|
|
|
end
|
2011-02-25 23:39:29 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "parses xpath with quotes" do
|
|
|
|
subject.find('//*[contains(., "hello")]').should_not be_empty
|
|
|
|
end
|
2011-02-26 10:06:11 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "returns a node's text" do
|
|
|
|
subject.find("//p").first.text.should == "hello"
|
|
|
|
end
|
2011-02-25 18:04:23 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "returns the current URL" do
|
|
|
|
port = subject.instance_variable_get("@rack_server").port
|
|
|
|
subject.current_url.should == "http://127.0.0.1:#{port}/hello/world?success=true"
|
|
|
|
end
|
2011-02-26 10:19:24 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "returns the source code for the page" do
|
|
|
|
subject.source.should =~ %r{<html>.*greeting.*}m
|
|
|
|
end
|
2011-02-26 13:02:43 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "aliases body as source" do
|
|
|
|
subject.body.should == subject.source
|
|
|
|
end
|
2011-02-26 13:02:43 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "evaluates Javascript and returns a string" do
|
|
|
|
result = subject.evaluate_script(%<document.getElementById('greeting').innerText>)
|
|
|
|
result.should == "hello"
|
|
|
|
end
|
2011-02-26 13:02:43 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "evaluates Javascript and returns an array" do
|
|
|
|
result = subject.evaluate_script(%<["hello", "world"]>)
|
|
|
|
result.should == %w(hello world)
|
|
|
|
end
|
2011-02-26 13:02:43 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "evaluates Javascript and returns an int" do
|
|
|
|
result = subject.evaluate_script(%<123>)
|
|
|
|
result.should == 123
|
|
|
|
end
|
2011-02-26 13:02:43 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "evaluates Javascript and returns a float" do
|
|
|
|
result = subject.evaluate_script(%<1.5>)
|
|
|
|
result.should == 1.5
|
|
|
|
end
|
2011-02-26 13:02:43 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "evaluates Javascript and returns null" do
|
|
|
|
result = subject.evaluate_script(%<(function () {})()>)
|
|
|
|
result.should == nil
|
|
|
|
end
|
2011-02-26 13:02:43 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "evaluates Javascript and returns an object" do
|
|
|
|
result = subject.evaluate_script(%<({ 'one' : 1 })>)
|
|
|
|
result.should == { 'one' => 1 }
|
|
|
|
end
|
2011-02-26 13:02:43 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "evaluates Javascript and returns true" do
|
|
|
|
result = subject.evaluate_script(%<true>)
|
|
|
|
result.should === true
|
|
|
|
end
|
2011-02-26 13:02:43 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "evaluates Javascript and returns false" do
|
|
|
|
result = subject.evaluate_script(%<false>)
|
|
|
|
result.should === false
|
|
|
|
end
|
2011-02-26 13:38:10 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "evaluates Javascript and returns an escaped string" do
|
|
|
|
result = subject.evaluate_script(%<'"'>)
|
|
|
|
result.should === "\""
|
|
|
|
end
|
2011-02-26 14:03:30 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "evaluates Javascript with multiple lines" do
|
|
|
|
result = subject.evaluate_script("[1,\n2]")
|
|
|
|
result.should == [1, 2]
|
|
|
|
end
|
2011-02-26 14:03:30 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "executes Javascript" do
|
|
|
|
subject.execute_script(%<document.getElementById('greeting').innerHTML = 'yo'>)
|
|
|
|
subject.find("//p[contains(., 'yo')]").should_not be_empty
|
|
|
|
end
|
2011-02-18 22:53:06 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "raises an error for failing Javascript" do
|
|
|
|
expect { subject.execute_script(%<invalid salad>) }.
|
|
|
|
to raise_error(Capybara::Driver::Webkit::WebkitError)
|
|
|
|
end
|
2011-02-26 15:18:11 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "returns a node's tag name" do
|
|
|
|
subject.find("//p").first.tag_name.should == "p"
|
|
|
|
end
|
2011-02-26 15:50:45 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "finds visible elements" do
|
|
|
|
subject.find("//p").first.should be_visible
|
|
|
|
subject.find("//*[@id='invisible']").first.should_not be_visible
|
|
|
|
end
|
2011-02-26 15:50:45 -05:00
|
|
|
end
|
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
context "form app" do
|
|
|
|
let(:app) do
|
|
|
|
lambda do |env|
|
|
|
|
body = <<-HTML
|
|
|
|
<html><body>
|
|
|
|
<form action="/" method="GET">
|
|
|
|
<input type="text" name="foo" value="bar"/>
|
|
|
|
<select name="animal">
|
2011-02-26 17:51:47 -05:00
|
|
|
<option id="select-option-monkey">Monkey</option>
|
|
|
|
<option id="select-option-capybara" selected="selected">Capybara</option>
|
|
|
|
</select>
|
|
|
|
<select name="toppings" multiple="multiple">
|
2011-02-26 17:52:28 -05:00
|
|
|
<optgroup label="Mediocre Toppings">
|
|
|
|
<option selected="selected" id="topping-apple">Apple</option>
|
|
|
|
<option selected="selected" id="topping-banana">Banana</option>
|
|
|
|
</optgroup>
|
|
|
|
<optgroup label="Best Toppings">
|
|
|
|
<option selected="selected" id="topping-cherry">Cherry</option>
|
|
|
|
</optgroup>
|
2011-02-26 16:35:21 -05:00
|
|
|
</select>
|
|
|
|
<textarea id="only-textarea">what a wonderful area for text</textarea>
|
|
|
|
</form>
|
2011-03-09 19:04:41 -05:00
|
|
|
<ul id="events"></ul>
|
|
|
|
<script type="text/javascript">
|
|
|
|
var events = document.getElementById("events");
|
|
|
|
var textarea = document.getElementById("only-textarea");
|
|
|
|
var recordEvent = function (event) {
|
|
|
|
var element = document.createElement("li");
|
|
|
|
element.innerHTML = event.type;
|
|
|
|
events.appendChild(element);
|
|
|
|
};
|
|
|
|
textarea.addEventListener("focus", recordEvent);
|
|
|
|
textarea.addEventListener("keydown", recordEvent);
|
|
|
|
textarea.addEventListener("keyup", recordEvent);
|
|
|
|
textarea.addEventListener("change", recordEvent);
|
|
|
|
textarea.addEventListener("blur", recordEvent);
|
|
|
|
</script>
|
2011-02-26 16:35:21 -05:00
|
|
|
</body></html>
|
|
|
|
HTML
|
|
|
|
[200,
|
|
|
|
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
|
|
|
[body]]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns a textarea's value" do
|
|
|
|
subject.find("//textarea").first.value.should == "what a wonderful area for text"
|
|
|
|
end
|
2011-02-26 16:08:14 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "returns a text input's value" do
|
|
|
|
subject.find("//input").first.value.should == "bar"
|
|
|
|
end
|
2011-02-26 16:08:14 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "returns a select's value" do
|
|
|
|
subject.find("//select").first.value.should == "Capybara"
|
|
|
|
end
|
2011-02-26 16:08:14 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "sets an input's value" do
|
|
|
|
input = subject.find("//input").first
|
|
|
|
input.set("newvalue")
|
|
|
|
input.value.should == "newvalue"
|
|
|
|
end
|
2011-02-26 16:20:05 -05:00
|
|
|
|
2011-03-09 19:04:41 -05:00
|
|
|
it "triggers input events" do
|
|
|
|
subject.find("//textarea").first.set("newvalue")
|
|
|
|
subject.find("//li").map(&:text).should == %w(focus keydown keyup change blur)
|
|
|
|
end
|
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "sets a select's value" do
|
|
|
|
select = subject.find("//select").first
|
|
|
|
select.set("Monkey")
|
|
|
|
select.value.should == "Monkey"
|
|
|
|
end
|
2011-02-26 15:48:44 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "sets a textarea's value" do
|
|
|
|
textarea = subject.find("//textarea").first
|
|
|
|
textarea.set("newvalue")
|
|
|
|
textarea.value.should == "newvalue"
|
|
|
|
end
|
2011-02-26 17:51:47 -05:00
|
|
|
|
|
|
|
let(:monkey_option) { subject.find("//option[@id='select-option-monkey']").first }
|
|
|
|
let(:capybara_option) { subject.find("//option[@id='select-option-capybara']").first }
|
|
|
|
let(:animal_select) { subject.find("//select[@name='animal']").first }
|
|
|
|
let(:apple_option) { subject.find("//option[@id='topping-apple']").first }
|
|
|
|
let(:banana_option) { subject.find("//option[@id='topping-banana']").first }
|
|
|
|
let(:cherry_option) { subject.find("//option[@id='topping-cherry']").first }
|
|
|
|
let(:toppings_select) { subject.find("//select[@name='toppings']").first }
|
|
|
|
|
|
|
|
it "selects an option" do
|
|
|
|
animal_select.value.should == "Capybara"
|
|
|
|
monkey_option.select_option
|
|
|
|
animal_select.value.should == "Monkey"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "unselects an option in a multi-select" do
|
|
|
|
toppings_select.value.should include("Apple", "Banana", "Cherry")
|
|
|
|
|
|
|
|
apple_option.unselect_option
|
|
|
|
toppings_select.value.should_not include("Apple")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "reselects an option in a multi-select" do
|
|
|
|
apple_option.unselect_option
|
|
|
|
banana_option.unselect_option
|
|
|
|
cherry_option.unselect_option
|
|
|
|
|
|
|
|
toppings_select.value.should == []
|
|
|
|
|
|
|
|
apple_option.select_option
|
|
|
|
banana_option.select_option
|
|
|
|
cherry_option.select_option
|
|
|
|
|
|
|
|
toppings_select.value.should include("Apple", "Banana", "Cherry")
|
|
|
|
end
|
2011-02-26 15:48:44 -05:00
|
|
|
end
|
2011-02-26 16:16:30 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
context "mouse app" do
|
|
|
|
let(:app) do
|
|
|
|
lambda do |env|
|
|
|
|
body = <<-HTML
|
|
|
|
<html><body>
|
|
|
|
<div id="change">Change me</div>
|
|
|
|
<div id="mouseup">Push me</div>
|
|
|
|
<div id="mousedown">Release me</div>
|
|
|
|
<script type="text/javascript">
|
|
|
|
document.getElementById("change").
|
|
|
|
addEventListener("change", function () {
|
|
|
|
this.className = "triggered";
|
|
|
|
});
|
|
|
|
document.getElementById("mouseup").
|
|
|
|
addEventListener("mouseup", function () {
|
|
|
|
this.className = "triggered";
|
|
|
|
});
|
|
|
|
document.getElementById("mousedown").
|
|
|
|
addEventListener("mousedown", function () {
|
|
|
|
this.className = "triggered";
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
<a href="/next">Next</a>
|
|
|
|
</body></html>
|
|
|
|
HTML
|
|
|
|
[200,
|
|
|
|
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
|
|
|
[body]]
|
|
|
|
end
|
|
|
|
end
|
2011-02-26 16:16:30 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "clicks an element" do
|
|
|
|
subject.find("//a").first.click
|
|
|
|
subject.current_url =~ %r{/next$}
|
|
|
|
end
|
2011-02-26 16:26:22 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "fires a mouse event" do
|
|
|
|
subject.find("//*[@id='mouseup']").first.trigger("mouseup")
|
|
|
|
subject.find("//*[@class='triggered']").should_not be_empty
|
|
|
|
end
|
2011-02-26 16:26:22 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
it "fires a non-mouse event" do
|
|
|
|
subject.find("//*[@id='change']").first.trigger("change")
|
|
|
|
subject.find("//*[@class='triggered']").should_not be_empty
|
|
|
|
end
|
|
|
|
|
|
|
|
it "fires drag events" do
|
|
|
|
draggable = subject.find("//*[@id='mousedown']").first
|
|
|
|
container = subject.find("//*[@id='mouseup']").first
|
2011-02-26 16:26:22 -05:00
|
|
|
|
2011-02-26 16:35:21 -05:00
|
|
|
draggable.drag_to(container)
|
|
|
|
|
|
|
|
subject.find("//*[@class='triggered']").size.should == 2
|
|
|
|
end
|
2011-02-26 16:26:22 -05:00
|
|
|
end
|
2011-02-26 16:46:59 -05:00
|
|
|
|
|
|
|
context "nesting app" do
|
|
|
|
let(:app) do
|
|
|
|
lambda do |env|
|
|
|
|
body = <<-HTML
|
|
|
|
<html><body>
|
|
|
|
<div id="parent">
|
|
|
|
<div class="find">Expected</div>
|
|
|
|
</div>
|
|
|
|
<div class="find">Unexpected</div>
|
|
|
|
</body></html>
|
|
|
|
HTML
|
|
|
|
[200,
|
|
|
|
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
|
|
|
[body]]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "evaluates nested xpath expressions" do
|
|
|
|
parent = subject.find("//*[@id='parent']").first
|
|
|
|
parent.find("./*[@class='find']").map(&:text).should == %w(Expected)
|
|
|
|
end
|
|
|
|
end
|
2011-03-09 00:08:30 -05:00
|
|
|
|
|
|
|
context "slow app" do
|
|
|
|
let(:app) do
|
|
|
|
lambda do |env|
|
|
|
|
body = <<-HTML
|
|
|
|
<html><body>
|
|
|
|
<form action="/next"><input type="submit"/></form>
|
|
|
|
<p>#{env['PATH_INFO']}</p>
|
|
|
|
</body></html>
|
|
|
|
HTML
|
|
|
|
sleep(0.5)
|
|
|
|
[200,
|
|
|
|
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
|
|
|
[body]]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "waits for a request to load" do
|
|
|
|
subject.find("//input").first.click
|
|
|
|
subject.find("//p").first.text.should == "/next"
|
|
|
|
end
|
|
|
|
end
|
2011-02-26 14:55:40 -05:00
|
|
|
end
|