Skip to content

Commit 3ddf5a6

Browse files
committed
Workaround non-conformant chrome element ref
Originally meant to add some tests for frame switching. But ran into an issue with chrome/chromedriver. The switch frame command failed to execute in chrome, the error message is pretty explicit it requires the payload of the method to carry the `ELEMENT` attribute instead of the attribute from the w3c spec (element-6066-11e4-a52e-4f735466cecf). I think the upstream issue is https://bugs.chromium.org/p/chromedriver/issues/detail?id=1992 The proposed workaround for this is to also serialize the ElementReference with an ELEMENT attribute. There is the risk of clashing with other implementations but so have I have encoutered no issues.
1 parent 2dcb34b commit 3ddf5a6

File tree

5 files changed

+60
-16
lines changed

5 files changed

+60
-16
lines changed

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,11 @@ impl DriverSession {
326326
let _: Empty = try!(self.client.post(&format!("/session/{}/frame", self.session_id), &SwitchFrameCmd::from(handle)));
327327
Ok(())
328328
}
329+
330+
pub fn switch_to_parent_frame(&self) -> Result<(), Error> {
331+
let _: Empty = try!(self.client.post(&format!("/session/{}/frame/parent", self.session_id), &Empty {}));
332+
Ok(())
333+
}
329334
}
330335

331336
impl Drop for DriverSession {

src/messages.rs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ impl Serialize for ElementReference {
127127
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
128128
let mut ss = s.serialize_struct("ElementReference", 1)?;
129129
ss.serialize_field("element-6066-11e4-a52e-4f735466cecf", &self.reference)?;
130+
// even in w3c compliance mode chromedriver only accepts a reference name ELEMENT
131+
ss.serialize_field("ELEMENT", &self.reference)?;
130132
ss.end()
131133
}
132134
}
@@ -207,17 +209,3 @@ pub struct ExecuteCmd {
207209
pub script: String,
208210
pub args: Vec<JsonValue>,
209211
}
210-
211-
#[cfg(test)]
212-
mod tests {
213-
use serde_json::{from_str, to_string};
214-
use super::*;
215-
216-
#[test]
217-
fn element_ref_serialize() {
218-
let r: ElementReference = from_str("{\"element-6066-11e4-a52e-4f735466cecf\": \"ZZZZ\"}").unwrap();
219-
assert_eq!(r.reference, "ZZZZ");
220-
let r2 = from_str(&to_string(&r).unwrap()).unwrap();
221-
assert_eq!(r, r2);
222-
}
223-
}

tests/inner_frame.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<iframe>
2+
</iframe>
3+
4+
<iframe>
5+
</iframe>

tests/integration_test.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
<head>
44
<title>Test page title</title>
55
</head>
6-
<body></body>
6+
<body>
7+
<iframe src="inner_frame.html"></iframe>
8+
</body>
79
</html>

tests/webdriver_client_integration.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::time::Duration;
1414
use webdriver_client::{Driver, HttpDriverBuilder, DriverSession};
1515
use webdriver_client::firefox::GeckoDriver;
1616
use webdriver_client::chrome::ChromeDriver;
17-
use webdriver_client::messages::ExecuteCmd;
17+
use webdriver_client::messages::{ExecuteCmd, LocationStrategy};
1818

1919
#[test]
2020
fn test_file_geckodriver() {
@@ -81,6 +81,50 @@ fn test_file(sess: DriverSession) {
8181
// sess.close_window().unwrap();
8282
}
8383

84+
#[test]
85+
fn test_frame_switch_chromedriver() {
86+
ensure_logging_init();
87+
let chrome = ChromeDriver::build()
88+
.spawn().unwrap();
89+
let sess = chrome.session().unwrap();
90+
test_frame_switch(sess);
91+
}
92+
93+
#[test]
94+
fn test_frame_switch_geckodriver() {
95+
ensure_logging_init();
96+
let gecko = GeckoDriver::build()
97+
.spawn().unwrap();
98+
let sess = gecko.session().unwrap();
99+
test_frame_switch(sess);
100+
}
101+
102+
fn test_frame_switch(sess: DriverSession) {
103+
let test_url = get_integration_test_url();
104+
sess.go(&test_url).unwrap();
105+
106+
// switching to parent from parent is harmless
107+
sess.switch_to_parent_frame().unwrap();
108+
109+
let frames = sess.find_elements("iframe", LocationStrategy::Css).unwrap();
110+
assert_eq!(frames.len(), 1);
111+
112+
sess.switch_to_frame(frames[0].reference().unwrap()).unwrap();
113+
let frames = sess.find_elements("iframe", LocationStrategy::Css).unwrap();
114+
assert_eq!(frames.len(), 2);
115+
116+
for f in &frames {
117+
sess.switch_to_frame(f.reference().unwrap()).unwrap();
118+
let childframes = sess.find_elements("iframe", LocationStrategy::Css).unwrap();
119+
assert_eq!(childframes.len(), 0);
120+
sess.switch_to_parent_frame().unwrap();
121+
}
122+
123+
sess.switch_to_parent_frame().unwrap();
124+
let frames = sess.find_elements("iframe", LocationStrategy::Css).unwrap();
125+
assert_eq!(frames.len(), 1);
126+
}
127+
84128
#[test]
85129
fn test_exception_handling_geckodriver() {
86130
ensure_logging_init();

0 commit comments

Comments
 (0)