diff --git a/servo/components/compositing/Cargo.toml b/servo/components/compositing/Cargo.toml index 37035dec23f8..fcc129e2cccc 100644 --- a/servo/components/compositing/Cargo.toml +++ b/servo/components/compositing/Cargo.toml @@ -31,8 +31,8 @@ path = "../net_traits" [dependencies.util] path = "../util" -[dependencies.webdriver_server] -path = "../webdriver_server" +[dependencies.webdriver_traits] +path = "../webdriver_traits" [dependencies.devtools_traits] path = "../devtools_traits" diff --git a/servo/components/compositing/constellation.rs b/servo/components/compositing/constellation.rs index eb54339d159f..2e7a975b7319 100644 --- a/servo/components/compositing/constellation.rs +++ b/servo/components/compositing/constellation.rs @@ -39,6 +39,7 @@ use util::geometry::PagePx; use util::opts; use util::task::spawn_named; use clipboard::ClipboardContext; +use webdriver_traits::WebDriverScriptCommand; /// Maintains the pipelines and navigation context and grants permission to composite. pub struct Constellation { @@ -410,6 +411,12 @@ impl Constellation { }; sender.send(result).unwrap(); } + ConstellationMsg::WebDriverCommandMsg(pipeline_id, + command) => { + debug!("constellation got webdriver command message"); + self.handle_webdriver_command_msg(pipeline_id, + command); + } } true } @@ -753,6 +760,17 @@ impl Constellation { self.focus_parent_pipeline(pipeline_id); } + fn handle_webdriver_command_msg(&mut self, + pipeline_id: PipelineId, + msg: WebDriverScriptCommand) { + // Find the script channel for the given parent pipeline, + // and pass the event to that script task. + let pipeline = self.pipeline(pipeline_id); + let control_msg = ConstellationControlMsg::WebDriverCommandMsg(pipeline_id, msg); + let ScriptControlChan(ref script_channel) = pipeline.script_chan; + script_channel.send(control_msg).unwrap(); + } + fn add_or_replace_pipeline_in_frame_tree(&mut self, frame_change: FrameChange) { // If the currently focused pipeline is the one being changed (or a child diff --git a/servo/components/compositing/lib.rs b/servo/components/compositing/lib.rs index f3f54cad3889..7b8d49348c3a 100644 --- a/servo/components/compositing/lib.rs +++ b/servo/components/compositing/lib.rs @@ -27,7 +27,7 @@ extern crate net_traits; #[macro_use] extern crate util; extern crate gleam; -extern crate webdriver_server; +extern crate webdriver_traits; extern crate clipboard; extern crate libc; diff --git a/servo/components/msg/Cargo.toml b/servo/components/msg/Cargo.toml index 4eeb3a3b5249..b3a0ebfe5d15 100644 --- a/servo/components/msg/Cargo.toml +++ b/servo/components/msg/Cargo.toml @@ -14,6 +14,9 @@ path = "../style" [dependencies.util] path = "../util" +[dependencies.webdriver_traits] +path = "../webdriver_traits" + [dependencies.azure] git = "https://github.com/servo/rust-azure" diff --git a/servo/components/msg/constellation_msg.rs b/servo/components/msg/constellation_msg.rs index 6029541336fe..7b44a4b4c848 100644 --- a/servo/components/msg/constellation_msg.rs +++ b/servo/components/msg/constellation_msg.rs @@ -14,6 +14,7 @@ use layers::geometry::DevicePixel; use util::cursor::Cursor; use util::geometry::{PagePx, ViewportPx}; use std::sync::mpsc::{channel, Sender, Receiver}; +use webdriver_traits::WebDriverScriptCommand; use url::Url; #[derive(Clone)] @@ -231,6 +232,8 @@ pub enum Msg { FocusMsg(PipelineId), /// Requests that the constellation retrieve the current contents of the clipboard GetClipboardContents(Sender), + // Dispatch a webdriver command + WebDriverCommandMsg(PipelineId, WebDriverScriptCommand) } // https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API#Events diff --git a/servo/components/msg/lib.rs b/servo/components/msg/lib.rs index 7b52067c9277..fc125583e95d 100644 --- a/servo/components/msg/lib.rs +++ b/servo/components/msg/lib.rs @@ -9,6 +9,7 @@ extern crate hyper; extern crate layers; extern crate util; extern crate url; +extern crate webdriver_traits; #[cfg(target_os="macos")] extern crate core_foundation; diff --git a/servo/components/script/Cargo.toml b/servo/components/script/Cargo.toml index 63eaea80142e..50607cabefed 100644 --- a/servo/components/script/Cargo.toml +++ b/servo/components/script/Cargo.toml @@ -42,6 +42,9 @@ path = "../gfx" [dependencies.canvas] path = "../canvas" +[dependencies.webdriver_traits] +path = "../webdriver_traits" + [dependencies.cssparser] git = "https://github.com/servo/rust-cssparser" diff --git a/servo/components/script/lib.rs b/servo/components/script/lib.rs index b9f4b42f84dc..5c2e522f5d4b 100644 --- a/servo/components/script/lib.rs +++ b/servo/components/script/lib.rs @@ -52,6 +52,7 @@ extern crate style; extern crate url; extern crate uuid; extern crate string_cache; +extern crate webdriver_traits; pub mod cors; @@ -67,3 +68,4 @@ pub mod script_task; mod timers; pub mod textinput; mod devtools; +mod webdriver_handlers; diff --git a/servo/components/script/script_task.rs b/servo/components/script/script_task.rs index 6886137e48c1..6de727451635 100644 --- a/servo/components/script/script_task.rs +++ b/servo/components/script/script_task.rs @@ -45,6 +45,7 @@ use layout_interface; use page::{Page, IterablePage, Frame}; use timers::TimerId; use devtools; +use webdriver_handlers; use devtools_traits::{DevtoolsControlChan, DevtoolsControlPort, DevtoolsPageInfo}; use devtools_traits::{DevtoolsControlMsg, DevtoolScriptControlMsg}; @@ -56,6 +57,7 @@ use script_traits::CompositorEvent::{MouseMoveEvent, KeyEvent}; use script_traits::{NewLayoutInfo, OpaqueScriptLayoutChannel}; use script_traits::{ConstellationControlMsg, ScriptControlChan}; use script_traits::ScriptTaskFactory; +use webdriver_traits::WebDriverScriptCommand; use msg::compositor_msg::ReadyState::{FinishedLoading, Loading, PerformingLayout}; use msg::compositor_msg::{LayerId, ScriptListener}; use msg::constellation_msg::{ConstellationChan, FocusType}; @@ -727,6 +729,9 @@ impl ScriptTask { self.handle_update_subpage_id(containing_pipeline_id, old_subpage_id, new_subpage_id), ConstellationControlMsg::FocusIFrameMsg(containing_pipeline_id, subpage_id) => self.handle_focus_iframe_msg(containing_pipeline_id, subpage_id), + ConstellationControlMsg::WebDriverCommandMsg(pipeline_id, msg) => { + self.handle_webdriver_msg(pipeline_id, msg); + } } } @@ -783,6 +788,14 @@ impl ScriptTask { msg.responder.unwrap().respond(msg.image); } + fn handle_webdriver_msg(&self, pipeline_id: PipelineId, msg: WebDriverScriptCommand) { + let page = self.root_page(); + match msg { + WebDriverScriptCommand::EvaluateJS(script, reply) => + webdriver_handlers::handle_evaluate_js(&page, pipeline_id, script, reply) + } + } + fn handle_resize(&self, id: PipelineId, size: WindowSizeData) { let page = self.page.borrow(); if let Some(ref page) = page.as_ref() { diff --git a/servo/components/script/webdriver_handlers.rs b/servo/components/script/webdriver_handlers.rs new file mode 100644 index 000000000000..4d0aeca61ccd --- /dev/null +++ b/servo/components/script/webdriver_handlers.rs @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use webdriver_traits::{EvaluateJSReply}; +use dom::bindings::conversions::FromJSValConvertible; +use dom::bindings::conversions::StringificationBehavior; +use dom::bindings::js::OptionalRootable; +use dom::window::ScriptHelpers; +use dom::document::DocumentHelpers; +use page::Page; +use msg::constellation_msg::PipelineId; +use script_task::get_page; + +use std::rc::Rc; +use std::sync::mpsc::Sender; + +pub fn handle_evaluate_js(page: &Rc, pipeline: PipelineId, eval: String, reply: Sender>){ + let page = get_page(&*page, pipeline); + let window = page.window().root(); + let cx = window.r().get_cx(); + let rval = window.r().evaluate_js_on_global_with_result(&eval); + + reply.send(if rval.is_undefined() { + Ok(EvaluateJSReply::VoidValue) + } else if rval.is_boolean() { + Ok(EvaluateJSReply::BooleanValue(rval.to_boolean())) + } else if rval.is_double() { + Ok(EvaluateJSReply::NumberValue(FromJSValConvertible::from_jsval(cx, rval, ()).unwrap())) + } else if rval.is_string() { + //FIXME: use jsstring_to_str when jsval grows to_jsstring + Ok(EvaluateJSReply::StringValue(FromJSValConvertible::from_jsval(cx, rval, StringificationBehavior::Default).unwrap())) + } else if rval.is_null() { + Ok(EvaluateJSReply::NullValue) + } else { + Err(()) + }).unwrap(); +} diff --git a/servo/components/script_traits/Cargo.toml b/servo/components/script_traits/Cargo.toml index d33e0ff6b982..9b41ae54ec2d 100644 --- a/servo/components/script_traits/Cargo.toml +++ b/servo/components/script_traits/Cargo.toml @@ -19,6 +19,9 @@ path = "../util" [dependencies.devtools_traits] path = "../devtools_traits" +[dependencies.webdriver_traits] +path = "../webdriver_traits" + [dependencies.geom] git = "https://github.com/servo/rust-geom" diff --git a/servo/components/script_traits/lib.rs b/servo/components/script_traits/lib.rs index b5045d5a8323..82f917733dee 100644 --- a/servo/components/script_traits/lib.rs +++ b/servo/components/script_traits/lib.rs @@ -9,6 +9,7 @@ extern crate msg; extern crate net_traits; extern crate util; extern crate url; +extern crate webdriver_traits; // This module contains traits in script used generically // in the rest of Servo. @@ -26,6 +27,7 @@ use net_traits::image_cache_task::ImageCacheTask; use net_traits::storage_task::StorageTask; use std::any::Any; use std::sync::mpsc::{Sender, Receiver}; +use webdriver_traits::WebDriverScriptCommand; use geom::point::Point2D; use geom::rect::Rect; @@ -75,6 +77,8 @@ pub enum ConstellationControlMsg { UpdateSubpageId(PipelineId, SubpageId, SubpageId), /// Set an iframe to be focused. Used when an element in an iframe gains focus. FocusIFrameMsg(PipelineId, SubpageId), + // Passes a webdriver command to the script task for execution + WebDriverCommandMsg(PipelineId, WebDriverScriptCommand) } /// The mouse button involved in the event. diff --git a/servo/components/servo/Cargo.lock b/servo/components/servo/Cargo.lock index 46cf8773747f..b383fe6e733e 100644 --- a/servo/components/servo/Cargo.lock +++ b/servo/components/servo/Cargo.lock @@ -126,7 +126,7 @@ dependencies = [ "time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", - "webdriver_server 0.0.1", + "webdriver_traits 0.0.1", ] [[package]] @@ -660,6 +660,7 @@ dependencies = [ "style 0.0.1", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webdriver_traits 0.0.1", ] [[package]] @@ -856,6 +857,7 @@ dependencies = [ "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "uuid 0.1.11 (git+https://github.com/rust-lang/uuid)", + "webdriver_traits 0.0.1", ] [[package]] @@ -876,6 +878,7 @@ dependencies = [ "net_traits 0.0.1", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webdriver_traits 0.0.1", ] [[package]] @@ -1050,7 +1053,7 @@ dependencies = [ [[package]] name = "webdriver" version = "0.0.1" -source = "git+https://github.com/jgraham/webdriver-rust.git#4f543416a269b9d0d7ee5332db489768c2a769dd" +source = "git+https://github.com/jgraham/webdriver-rust.git#fa625e3cf8fdb39b503c1cc902506df3a1d1c9de" dependencies = [ "hyper 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1069,6 +1072,14 @@ dependencies = [ "util 0.0.1", "uuid 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "webdriver 0.0.1 (git+https://github.com/jgraham/webdriver-rust.git)", + "webdriver_traits 0.0.1", +] + +[[package]] +name = "webdriver_traits" +version = "0.0.1" +dependencies = [ + "rustc-serialize 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/servo/components/webdriver_server/Cargo.toml b/servo/components/webdriver_server/Cargo.toml index 337f8a6498a3..17fa3188e780 100644 --- a/servo/components/webdriver_server/Cargo.toml +++ b/servo/components/webdriver_server/Cargo.toml @@ -13,10 +13,13 @@ path = "../msg" [dependencies.util] path = "../util" +[dependencies.webdriver_traits] +path = "../webdriver_traits" + [dependencies.webdriver] git = "https://github.com/jgraham/webdriver-rust.git" [dependencies] -rustc-serialize="0.3.4" +rustc-serialize = "0.3.4" url = "0.2.16" uuid = "0.1.11" \ No newline at end of file diff --git a/servo/components/webdriver_server/lib.rs b/servo/components/webdriver_server/lib.rs index e8a1f4771b80..d1d57608f144 100644 --- a/servo/components/webdriver_server/lib.rs +++ b/servo/components/webdriver_server/lib.rs @@ -17,14 +17,16 @@ extern crate url; extern crate util; extern crate "rustc-serialize" as rustc_serialize; extern crate uuid; +extern crate webdriver_traits; -use msg::constellation_msg::{ConstellationChan, LoadData}; +use msg::constellation_msg::{ConstellationChan, LoadData, PipelineId}; use msg::constellation_msg::Msg as ConstellationMsg; use std::sync::mpsc::channel; +use webdriver_traits::WebDriverScriptCommand; use url::Url; use webdriver::command::{WebDriverMessage, WebDriverCommand}; -use webdriver::command::GetParameters; +use webdriver::command::{GetParameters, JavascriptCommandParameters}; use webdriver::response::{ WebDriverResponse, NewSessionResponse, ValueResponse}; use webdriver::server::{self, WebDriverHandler, Session}; @@ -51,7 +53,7 @@ struct WebdriverSession { struct Handler { session: Option, - constellation_chan: ConstellationChan + constellation_chan: ConstellationChan, } impl WebdriverSession { @@ -70,6 +72,14 @@ impl Handler { } } + fn get_root_pipeline(&self) -> PipelineId { + let (sender, reciever) = channel(); + let ConstellationChan(ref const_chan) = self.constellation_chan; + const_chan.send(ConstellationMsg::GetRootPipeline(sender)).unwrap(); + + reciever.recv().unwrap().unwrap() + } + fn handle_new_session(&mut self) -> WebDriverResult { if self.session.is_none() { let session = WebdriverSession::new(); @@ -92,13 +102,10 @@ impl Handler { "Invalid URL")) }; - let (sender, reciever) = channel(); - let ConstellationChan(ref const_chan) = self.constellation_chan; - const_chan.send(ConstellationMsg::GetRootPipeline(sender)).unwrap(); - - let pipeline_id = reciever.recv().unwrap().unwrap(); + let pipeline_id = self.get_root_pipeline(); let load_data = LoadData::new(url); + let ConstellationChan(ref const_chan) = self.constellation_chan; const_chan.send(ConstellationMsg::LoadUrl(pipeline_id, load_data)).unwrap(); //TODO: Now we ought to wait until we get a load event Ok(WebDriverResponse::Void) @@ -110,6 +117,32 @@ impl Handler { let handle = self.session.as_ref().unwrap().id.to_string(); Ok(WebDriverResponse::Generic(ValueResponse::new(handle.to_json()))) } + + fn handle_execute_script(&self, parameters: &JavascriptCommandParameters) -> WebDriverResult { + // TODO: This isn't really right because it always runs the script in the + // root window + let pipeline_id = self.get_root_pipeline(); + + let func_body = ¶meters.script; + let args = ¶meters.args; + let args_string = ""; + + // This is pretty ugly; we really want something that acts like + // new Function() and then takes the resulting function and executes + // it with a vec of arguments. + let script = format!("(function() {{ {} }})({})", func_body, args_string); + + let (sender, reciever) = channel(); + let ConstellationChan(ref const_chan) = self.constellation_chan; + const_chan.send(ConstellationMsg::WebDriverCommandMsg(pipeline_id, + WebDriverScriptCommand::EvaluateJS(script, sender))).unwrap(); + + match reciever.recv().unwrap() { + Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse::new(value.to_json()))), + Err(_) => Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, + "Unsupported return type")) + } + } } impl WebDriverHandler for Handler { @@ -119,6 +152,7 @@ impl WebDriverHandler for Handler { WebDriverCommand::NewSession => self.handle_new_session(), WebDriverCommand::Get(ref parameters) => self.handle_get(parameters), WebDriverCommand::GetWindowHandle => self.handle_get_window_handle(), + WebDriverCommand::ExecuteScript(ref x) => self.handle_execute_script(x), _ => Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, "Command not implemented")) } diff --git a/servo/components/webdriver_traits/Cargo.toml b/servo/components/webdriver_traits/Cargo.toml new file mode 100644 index 000000000000..c4575e73a538 --- /dev/null +++ b/servo/components/webdriver_traits/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "webdriver_traits" +version = "0.0.1" +authors = ["The Servo Project Developers"] + +[lib] +name = "webdriver_traits" +path = "lib.rs" + +[dependencies] +rustc-serialize="0.3.4" \ No newline at end of file diff --git a/servo/components/webdriver_traits/lib.rs b/servo/components/webdriver_traits/lib.rs new file mode 100644 index 000000000000..4e6a307f64a2 --- /dev/null +++ b/servo/components/webdriver_traits/lib.rs @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![crate_name = "webdriver_traits"] +#![crate_type = "rlib"] + +extern crate "rustc-serialize" as rustc_serialize; +use rustc_serialize::json::{Json, ToJson}; + +use std::sync::mpsc::Sender; + +pub enum WebDriverScriptCommand { + EvaluateJS(String, Sender>) +} + +pub enum EvaluateJSReply { + VoidValue, + NullValue, + BooleanValue(bool), + NumberValue(f64), + StringValue(String), + // TODO: ObjectValue and WebElementValue +} + +impl ToJson for EvaluateJSReply { + fn to_json(&self) -> Json { + match self { + &EvaluateJSReply::VoidValue => Json::Null, + &EvaluateJSReply::NullValue => Json::Null, + &EvaluateJSReply::BooleanValue(ref x) => x.to_json(), + &EvaluateJSReply::NumberValue(ref x) => x.to_json(), + &EvaluateJSReply::StringValue(ref x) => x.to_json() + } + } +} diff --git a/servo/ports/cef/Cargo.lock b/servo/ports/cef/Cargo.lock index 292f9c0e2afb..152b6359aeda 100644 --- a/servo/ports/cef/Cargo.lock +++ b/servo/ports/cef/Cargo.lock @@ -124,7 +124,7 @@ dependencies = [ "time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", - "webdriver_server 0.0.1", + "webdriver_traits 0.0.1", ] [[package]] @@ -651,6 +651,7 @@ dependencies = [ "style 0.0.1", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webdriver_traits 0.0.1", ] [[package]] @@ -834,6 +835,7 @@ dependencies = [ "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "uuid 0.1.11 (git+https://github.com/rust-lang/uuid)", + "webdriver_traits 0.0.1", ] [[package]] @@ -847,6 +849,7 @@ dependencies = [ "net_traits 0.0.1", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webdriver_traits 0.0.1", ] [[package]] @@ -1022,7 +1025,7 @@ dependencies = [ [[package]] name = "webdriver" version = "0.0.1" -source = "git+https://github.com/jgraham/webdriver-rust.git#4f543416a269b9d0d7ee5332db489768c2a769dd" +source = "git+https://github.com/jgraham/webdriver-rust.git#fa625e3cf8fdb39b503c1cc902506df3a1d1c9de" dependencies = [ "hyper 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1041,6 +1044,14 @@ dependencies = [ "util 0.0.1", "uuid 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "webdriver 0.0.1 (git+https://github.com/jgraham/webdriver-rust.git)", + "webdriver_traits 0.0.1", +] + +[[package]] +name = "webdriver_traits" +version = "0.0.1" +dependencies = [ + "rustc-serialize 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/servo/ports/gonk/Cargo.lock b/servo/ports/gonk/Cargo.lock index 0f29369ed46c..492a3b92ce69 100644 --- a/servo/ports/gonk/Cargo.lock +++ b/servo/ports/gonk/Cargo.lock @@ -119,7 +119,7 @@ dependencies = [ "time 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", - "webdriver_server 0.0.1", + "webdriver_traits 0.0.1", ] [[package]] @@ -634,6 +634,7 @@ dependencies = [ "style 0.0.1", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webdriver_traits 0.0.1", ] [[package]] @@ -826,6 +827,7 @@ dependencies = [ "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", "uuid 0.1.11 (git+https://github.com/rust-lang/uuid)", + "webdriver_traits 0.0.1", ] [[package]] @@ -839,6 +841,7 @@ dependencies = [ "net_traits 0.0.1", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "webdriver_traits 0.0.1", ] [[package]] @@ -1013,7 +1016,7 @@ dependencies = [ [[package]] name = "webdriver" version = "0.0.1" -source = "git+https://github.com/jgraham/webdriver-rust.git#4f543416a269b9d0d7ee5332db489768c2a769dd" +source = "git+https://github.com/jgraham/webdriver-rust.git#fa625e3cf8fdb39b503c1cc902506df3a1d1c9de" dependencies = [ "hyper 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1032,6 +1035,14 @@ dependencies = [ "util 0.0.1", "uuid 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "webdriver 0.0.1 (git+https://github.com/jgraham/webdriver-rust.git)", + "webdriver_traits 0.0.1", +] + +[[package]] +name = "webdriver_traits" +version = "0.0.1" +dependencies = [ + "rustc-serialize 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]]