Testing for Elixir web applications.
TucoTuco helps you test your web application by running a web browser and simulating user interaction with your application.
With a DSL approximating that of Capybara's, it should be easy for developers to write tests for a web application.
In your mix.exs add the following to the test environment deps:
{:tuco_tuco, "~>0.8.1", only: test}
Either specify tuco_tuco in your application block in mix.exs or do:
:application.start TucoTuco
Testing requires that you have Phantomjs, Firefox or ChromeDriver installed.
The WebDriver library will also prompt you to install the Firefox plugin with
mix webdriver.firefox.plugin
if it is not present.
You can also test against a remote WebDriver server such as a Selenium instance.
Here is a rough guide to using TucoTuco.
Import the DSL functionality with:
use TucoTuco.DSL
Start a session with:
TucoTuco.start_session :browser_name, :session_name, :browser_type
Where browser_name and session_name are atoms to reference the running browser and session with later and browser_type is one of
* :phantomjs
* :firefox
* :chromedriver
* :remote
Visit sends the browser to other pages.
visit "http:https://elixir-lang.org"
visit "/login"
Relative urls will be appended with the TucoTuco.app_root value.
You can go back and forward in the browser history:
go_forward
go_back
And query the current url:
current_url
current_path
current_query
current_port
You can click on a link or button with the click_link
and
click_button
commands.
click_link "Home"
click_link "i3"
click_button "Back"
click_button "Submit"
Yet to come: mouse movements.
Interacting with forms is easy with TucoTuco's functions for that:
fill_in "Login", "Stuart"
fill_in "Password", "secret_password"
click_button "Submit"
choose "A radio button"
select "Carrot"
select "Tomato", from: "Vegetables"
check "A Checkbox"
You can even attach files:
attach_file "Upload Picture", "path/to/my_photo.png"
Getting information about the page to use in assertions:
Page.has_css? "table thead tr.header"
Page.has_xpath? "//foo/bar[@name='baz']"
Page.has_text? "Some text from the page"
Page.has_link? "Back"
With 'has_css?and
has_xpath?` you can specify a count
of how many should be found.
# Check that there are 5 rows in the table.
Page.has_css? "table tbody tr", count: 5
There are many more. Check the documentation for them.
TucoTuco supplies two assertions that you can use directly in tests:
assert_selector :xpath, "//foo/bar"
refute_selector :xpath, "//baz[@class='bob']"
Finder return elements from the DOM.
Finder.find :id, "foo"
Finder.find :css, ".bar"
Finder.find :xpath, "//foo/bar"
Find returns an Element record.
The following functions for manipulating elements are imported from WebDriver, they all take a WebDriver.Element struct as the first argument. Luckily that is exactly what all the finders return:
Element.attribute reference, :a_html_attribute
Element.clear reference
Element.click reference
Element.css reference, "some-css-property-name"
Element.displayed? reference
Element.enabled? reference
Element.equals? reference, other_reference
Element.location? reference
Element.location_in_view? reference
Element.name reference
Element.selected? reference
Element.size reference
Element.submit reference
Element.text reference
Element.value reference, "value to set"
For more detailed docs on the Element functions see WebDriver.Element.
Javascript can be run using the execute_javascript
and execute_async_javascript
commands.
iex> execute_javascript "return argument[0] * 10", [3]
iex> 30
When you are testing applications that have Javascript modifying the page it is possible that elements will not be available when you want them because the browser script takes some time to run.
To alleviate this TucoTuco has retry settings. When retry is turned on all the Page.has_foo? and action functions will retry for a set number of times before failing.
You can also use the retry function yourself like this:
# Find elements
TucoTuco.Finder.find using, selector
# Any function
TucoTuco.Retry.retry fn -> my_function(args) end
Changing retry settings:
# Set retries on
TucoTuco.use_retries true
# Set the maximum retry time in milliseconds.
TucoTuco.max_retry_time 1000
# Set the delay between retries in milliseconds.
TucoTuco.retry_delay 20
You can run multiple sessions on different browser or on the same browser. To start a session use:
TucoTuco.start_session :browser_name, :session_name, browser_type
Where the browser type is one of :phantomjs, :firefox or :chrome. If the process :browser_name is already running the session will be started on that, otherwise a new browser will start running.
Once you have multiple sessions running you can swap sessions with:
TucoTuco.session :new_session
And to get a list of sessions that are running:
TucoTuco.sessions
When the driver supports it, you can take a screenshot and save it as a PNG file.
save_screenshot "path/to/file.png"
Example Session from console:
iex(1)> use TucoTuco.DSL
:ok
iex(2)> TucoTuco.start_session :test_browser, :tuco_test, :phantomjs
{:ok,
%TucoTuco.SessionPool.SessionPoolState{app_root: nil,
current_session: :tuco_test, max_retry_time: 2000, retry_delay: 50,
use_retry: false}}
iex(3)> visit "http:https://elixir-lang.org"
{:ok,
%WebDriver.Protocol.Response{request: %WebDriver.Protocol.Request{body: "{\"url\":\"http:https://elixir-lang.org\"}",
headers: ["Content-Type": "application/json;charset=UTF-8",
"Content-Length": 32], method: :POST,
url: "http:https://localhost:57491/wd/hub/session/4dc0b3b0-26b8-11e4-85b9-7b8e9f3c77e7/url"},
session_id: "4dc0b3b0-26b8-11e4-85b9-7b8e9f3c77e7", status: 0, value: %{}}}
iex(4)> click_link "getting started guide"
{:ok,
%WebDriver.Protocol.Response{request: %WebDriver.Protocol.Request{body: "{}",
headers: ["Content-Type": "application/json;charset=UTF-8",
"Content-Length": 2], method: :POST,
url: "http:https://localhost:57491/wd/hub/session/4dc0b3b0-26b8-11e4-85b9-7b8e9f3c77e7/element/:wdc:1408353394161/click"},
session_id: "4dc0b3b0-26b8-11e4-85b9-7b8e9f3c77e7", status: 0, value: %{}}}
iex(5)> current_url
"http:https://elixir-lang.org/getting_started/1.html"
iex(6)> Page.has_css? "article h1#toc_0"
false
iex(7)> Page.has_text? "Elixir also supports UTF-8 encoded strings:"
false
iex(8)> click_link "Next →"
{:ok,
%WebDriver.Protocol.Response{request: %WebDriver.Protocol.Request{body: "{}",
headers: ["Content-Type": "application/json;charset=UTF-8",
"Content-Length": 2], method: :POST,
url: "http:https://localhost:57491/wd/hub/session/4dc0b3b0-26b8-11e4-85b9-7b8e9f3c77e7/element/:wdc:1408353427808/click"},
session_id: "4dc0b3b0-26b8-11e4-85b9-7b8e9f3c77e7", status: 0, value: %{}}}
iex(9)> current_url
"http:https://elixir-lang.org/getting_started/2.html"
iex(10)> Page.has_xpath? "//h1[.='2 Diving in']"
false
iex(11)> go_back
{:ok,
%WebDriver.Protocol.Response{request: %WebDriver.Protocol.Request{body: "{}",
headers: ["Content-Type": "application/json;charset=UTF-8",
"Content-Length": 2], method: :POST,
url: "http:https://localhost:57491/wd/hub/session/4dc0b3b0-26b8-11e4-85b9-7b8e9f3c77e7/back"},
session_id: "4dc0b3b0-26b8-11e4-85b9-7b8e9f3c77e7", status: 0, value: %{}}}
iex(12)> current_path
"/getting_started/1.html"
Here are some preliminary instructions for using TucoTuco for testing Phoenix applications.
Edit mix.exs to include the tuco_tuco dependency and to start TucoTuco in test mode.
def application do
[
mod: { Photuco, [] },
applications: applications(Mix.env)
]
end
defp applications do
[:phoenix, :cowboy]
end
defp applications :test do
applications ++ [:tuco_tuco]
end
defp applications _ do
applications
end
defp deps do
[
{:phoenix, github: "phoenixframework/phoenix"},
{:cowboy, "~> 1.0.0"},
{:tuco_tuco, "~>0.8.1"}
]
end
Add the setup block for the tests in the foo_test.exe file
setup_all do
router = Phoenix.Project.module_root.Router
port = Phoenix.Config.get([router,:port])
router.start
{:ok, _} = TucoTuco.start_session :test_browser, :test_session, :firefox
TucoTuco.app_root "http:https://localhost:#{port}"
on_exit fn -> TucoTuco.stop end
:ok
end
2014-12-20
- 0.8.1
- Elixir 1.1.1 compatability
2014-10-30
- 0.7.1
- Made password inputs fillable
2014-10-23
- 0.7.0
- Add alert handling code
2014-10-21
- 0.6.1
- Bump Webdriver version to 0.6.1
2014-08-20
- 0.6.0
- Webdriver 0.6.0
2014-08-17
- 0.5.1
- Webdriver 0.5.2
- Use hex.pm for deps
2014-08-12
- 0.5.0
- Elixir-0.15.0
- Webdriver 0.5.0
2014-03-06
- 0.4.0
- Added save_screenshot
2014-03-04
- 0.3.0
- Added execute_javascript and execute_async_javascript
2014-03-02
- 0.2.1
- Element functions from WebDriver
- Retries