diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 5b4d244e746..82f55589686 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -4702,25 +4702,38 @@ where WebDriverCommandMsg::CloseWebView(webview_id) => { self.handle_close_top_level_browsing_context(webview_id); }, - WebDriverCommandMsg::NewWebView(webview_id, sender, load_sender) => { - let (chan, port) = match ipc::channel() { + WebDriverCommandMsg::NewWebView( + originating_webview_id, + response_sender, + load_status_sender, + ) => { + let (embedder_sender, receiver) = match ipc::channel() { Ok(result) => result, Err(error) => return warn!("Failed to create channel: {error:?}"), }; - self.embedder_proxy - .send(EmbedderMsg::AllowOpeningWebView(webview_id, chan)); - let (webview_id, viewport_details) = match port.recv() { - Ok(Some((webview_id, viewport_details))) => (webview_id, viewport_details), + self.embedder_proxy.send(EmbedderMsg::AllowOpeningWebView( + originating_webview_id, + embedder_sender, + )); + let (new_webview_id, viewport_details) = match receiver.recv() { + Ok(Some((new_webview_id, viewport_details))) => { + (new_webview_id, viewport_details) + }, Ok(None) => return warn!("Embedder refused to allow opening webview"), Err(error) => return warn!("Failed to receive webview id: {error:?}"), }; self.handle_new_top_level_browsing_context( ServoUrl::parse_with_base(None, "about:blank").expect("Infallible parse"), - webview_id, + new_webview_id, viewport_details, - Some(load_sender), + Some(load_status_sender), ); - let _ = sender.send(webview_id); + if let Err(error) = response_sender.send(new_webview_id) { + error!( + "WebDriverCommandMsg::NewWebView: IPC error when sending new_webview_id \ + to webdriver server: {error}" + ); + } }, WebDriverCommandMsg::FocusWebView(webview_id) => { self.handle_focus_web_view(webview_id); diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index a8decee24ed..648146ac2e9 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -466,26 +466,40 @@ impl WindowProxy { features: DOMString, can_gc: CanGc, ) -> Fallible>> { - // Step 4. + // Step 5. If target is the empty string, then set target to "_blank". let non_empty_target = match target.as_ref() { "" => DOMString::from("_blank"), _ => target, }; - // Step 5 + // Step 6. Let tokenizedFeatures be the result of tokenizing features. let tokenized_features = tokenize_open_features(features); - // Step 7-9 + // Step 7 - 8. + // If tokenizedFeatures["noreferrer"] exists, then set noreferrer to + // the result of parsing tokenizedFeatures["noreferrer"] as a boolean feature. let noreferrer = parse_open_feature_boolean(&tokenized_features, "noreferrer"); + + // Step 9. Let noopener be the result of getting noopener for window + // open with sourceDocument, tokenizedFeatures, and urlRecord. let noopener = if noreferrer { true } else { parse_open_feature_boolean(&tokenized_features, "noopener") }; - // Step 10, 11 + // (TODO) Step 10. Remove tokenizedFeatures["noopener"] and tokenizedFeatures["noreferrer"]. + + // (TODO) Step 11. Let referrerPolicy be the empty string. + // (TODO) Step 12. If noreferrer is true, then set referrerPolicy to "no-referrer". + + // Step 13 - 14 + // Let targetNavigable and windowType be the result of applying the rules for + // choosing a navigable given target, sourceDocument's node navigable, and noopener. + // If targetNavigable is null, then return null. let (chosen, new) = match self.choose_browsing_context(non_empty_target, noopener) { (Some(chosen), new) => (chosen, new), (None, _) => return Ok(None), }; - // TODO Step 12, set up browsing context features. + // TODO Step 15.2, Set up browsing context features for targetNavigable's + // active browsing context given tokenizedFeatures. let target_document = match chosen.document() { Some(target_document) => target_document, None => return Ok(None), @@ -496,7 +510,7 @@ impl WindowProxy { false }; let target_window = target_document.window(); - // Step 13, and 14.4, will have happened elsewhere, + // Step 15.3 and 15.4 will have happened elsewhere, // since we've created a new browsing context and loaded it with about:blank. if !url.is_empty() { let existing_document = self @@ -504,18 +518,18 @@ impl WindowProxy { .get() .and_then(ScriptThread::find_document) .unwrap(); - // Step 14.1 let url = match existing_document.url().join(&url) { Ok(url) => url, Err(_) => return Err(Error::Syntax), }; - // Step 14.3 let referrer = if noreferrer { Referrer::NoReferrer } else { target_window.as_global_scope().get_referrer() }; - // Step 14.5 + // Step 15.5 Otherwise, navigate targetNavigable to urlRecord using sourceDocument, + // with referrerPolicy set to referrerPolicy and exceptionsEnabled set to true. + // FIXME: referrerPolicy may not be used properly here. exceptionsEnabled not used. let referrer_policy = target_document.get_referrer_policy(); let pipeline_id = target_window.pipeline_id(); let secure = target_window.as_global_scope().is_secure_context(); @@ -534,14 +548,13 @@ impl WindowProxy { } else { NavigationHistoryBehavior::Push }; - target_window.load_url(history_handling, false, load_data, can_gc); } + // Step 17 (Dis-owning has been done in create_auxiliary_browsing_context). if noopener { - // Step 15 (Dis-owning has been done in create_auxiliary_browsing_context). return Ok(None); } - // Step 17. + // Step 18 Ok(target_document.browsing_context()) } diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index 9c647ab5b8b..1bde6f314f2 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -79,6 +79,8 @@ fn find_node_by_unique_id( match documents.find_document(pipeline) { Some(doc) => find_node_by_unique_id_in_document(&doc, node_id), None => { + // FIXME: This is unreacheable!! Because we already early return in Constellation + // To be Fixed soon if ScriptThread::has_node_id(pipeline, &node_id) { Err(ErrorStatus::StaleElementReference) } else { diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index 0d92be01a3f..f2638764df6 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -949,6 +949,7 @@ impl Handler { ))) } + /// fn handle_new_window( &mut self, _parameters: &NewWindowParameters, @@ -956,11 +957,16 @@ impl Handler { let (sender, receiver) = ipc::channel().unwrap(); let session = self.session().unwrap(); + // Step 2. (TODO) If session's current top-level browsing context is no longer open, + // return error with error code no such window. + let cmd_msg = WebDriverCommandMsg::NewWebView( session.webview_id, sender, self.load_status_sender.clone(), ); + // Step 5. Create a new top-level browsing context by running the window open steps. + // This MUST be done without invoking the focusing steps. self.constellation_chan .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) .unwrap(); @@ -968,8 +974,6 @@ impl Handler { let mut handle = self.session.as_ref().unwrap().id.to_string(); if let Ok(new_webview_id) = receiver.recv() { let session = self.session_mut().unwrap(); - session.webview_id = new_webview_id; - session.browsing_context_id = BrowsingContextId::from(new_webview_id); let new_handle = Uuid::new_v4().to_string(); handle = new_handle.clone(); session.window_handles.insert(new_webview_id, new_handle); diff --git a/ports/servoshell/desktop/app_state.rs b/ports/servoshell/desktop/app_state.rs index 464e344424a..4740cfc35ca 100644 --- a/ports/servoshell/desktop/app_state.rs +++ b/ports/servoshell/desktop/app_state.rs @@ -12,7 +12,7 @@ use image::{DynamicImage, ImageFormat}; use keyboard_types::{Key, KeyboardEvent, Modifiers, ShortcutMatcher}; use log::{error, info}; use servo::base::id::WebViewId; -use servo::config::pref; +use servo::config::{opts, pref}; use servo::ipc_channel::ipc::IpcSender; use servo::webrender_api::ScrollLocation; use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; @@ -477,9 +477,13 @@ impl WebViewDelegate for RunningAppState { .build(); webview.notify_theme_change(self.inner().window.theme()); - webview.focus(); - webview.raise_to_top(true); - + // When WebDriver is enabled, do not focus and raise the WebView to the top, + // as that is what the specification expects. Otherwise, we would like `window.open()` + // to create a new foreground tab + if opts::get().webdriver_port.is_some() { + webview.focus(); + webview.raise_to_top(true); + } self.add(webview.clone()); Some(webview) } diff --git a/tests/wpt/meta/webdriver/tests/classic/element_click/click.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_click/click.py.ini index 7405df1cdfb..2ed5e00cc3f 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_click/click.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_click/click.py.ini @@ -4,6 +4,3 @@ [test_no_such_element_with_shadow_root] expected: FAIL - - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_click/shadow_dom.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_click/shadow_dom.py.ini deleted file mode 100644 index 32fd2854998..00000000000 --- a/tests/wpt/meta/webdriver/tests/classic/element_click/shadow_dom.py.ini +++ /dev/null @@ -1,9 +0,0 @@ -[shadow_dom.py] - [test_shadow_element_click[host_element\]] - expected: FAIL - - [test_nested_shadow_element_click[outer_element\]] - expected: FAIL - - [test_nested_shadow_element_click[inner_element\]] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/interactability.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/interactability.py.ini index 9510b686ea1..921b8c5cb5d 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/interactability.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/interactability.py.ini @@ -5,9 +5,6 @@ [test_iframe_is_interactable] expected: FAIL - [test_readonly_element] - expected: FAIL - [test_not_a_focusable_element] expected: FAIL @@ -22,3 +19,9 @@ [test_disabled] expected: FAIL + + [test_transparent_element] + expected: FAIL + + [test_readonly_element] + expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/send_keys.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/send_keys.py.ini index 9dca7adc465..85afe070906 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/send_keys.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/send_keys.py.ini @@ -5,5 +5,5 @@ [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[closed\]] + [test_surrogates] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/find_element_from_element/find.py.ini b/tests/wpt/meta/webdriver/tests/classic/find_element_from_element/find.py.ini index 64a0652b75b..85a7daf2244 100644 --- a/tests/wpt/meta/webdriver/tests/classic/find_element_from_element/find.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/find_element_from_element/find.py.ini @@ -1,7 +1,6 @@ [find.py] - expected: TIMEOUT [test_no_browsing_context] - expected: ERROR + expected: FAIL [test_no_such_element_with_shadow_root] expected: FAIL @@ -15,33 +14,12 @@ [test_no_such_element_with_unknown_selector[existent-inside-shadow-root\]] expected: FAIL - [test_no_such_element_with_startnode_from_other_window_handle] - expected: FAIL - [test_no_such_element_with_startnode_from_other_frame] expected: FAIL - [test_stale_element_reference[top_context\]] - expected: FAIL - - [test_stale_element_reference[child_context\]] - expected: FAIL - [test_find_element[xpath-//a\]] expected: FAIL - [test_xhtml_namespace[css selector-#linkText\]] - expected: FAIL - - [test_xhtml_namespace[link text-full link text\]] - expected: FAIL - - [test_xhtml_namespace[partial link text-link text\]] - expected: FAIL - - [test_xhtml_namespace[tag name-a\]] - expected: FAIL - [test_xhtml_namespace[xpath-//*[name()='a'\]\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/get_computed_role/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_computed_role/get.py.ini index 44749396246..c023dd2d5c5 100644 --- a/tests/wpt/meta/webdriver/tests/classic/get_computed_role/get.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/get_computed_role/get.py.ini @@ -5,8 +5,5 @@ [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL - [test_computed_roles[
foo
-article-article\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_attribute/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_attribute/get.py.ini index c5bc0a36f6d..c7642bd8ee1 100644 --- a/tests/wpt/meta/webdriver/tests/classic/get_element_attribute/get.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/get_element_attribute/get.py.ini @@ -5,9 +5,6 @@ [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL - [test_boolean_attribute[audio-attrs0\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_css_value/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_css_value/get.py.ini index 0af7750e50e..c1af0175608 100644 --- a/tests/wpt/meta/webdriver/tests/classic/get_element_css_value/get.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/get_element_css_value/get.py.ini @@ -4,6 +4,3 @@ [test_no_such_element_with_shadow_root] expected: FAIL - - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini index 991123b881c..3a1948de96e 100644 --- a/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/get_element_property/get.py.ini @@ -5,8 +5,5 @@ [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL - [test_web_reference[shadowRoot-ShadowRoot\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_rect/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_rect/get.py.ini index 10339e7291b..3a58f29d7bd 100644 --- a/tests/wpt/meta/webdriver/tests/classic/get_element_rect/get.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/get_element_rect/get.py.ini @@ -5,8 +5,5 @@ [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL - [test_basic] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_shadow_root/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_shadow_root/get.py.ini index 1b3957f08c8..bb9de0071f4 100644 --- a/tests/wpt/meta/webdriver/tests/classic/get_element_shadow_root/get.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/get_element_shadow_root/get.py.ini @@ -1,33 +1,3 @@ [get.py] - [test_no_top_browsing_context] - expected: FAIL - [test_no_browsing_context] expected: FAIL - - [test_no_such_element_with_invalid_value] - expected: FAIL - - [test_no_such_element_from_other_window_handle[open\]] - expected: FAIL - - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL - - [test_no_such_element_from_other_frame[open\]] - expected: FAIL - - [test_no_such_element_from_other_frame[closed\]] - expected: FAIL - - [test_stale_element_reference[top_context\]] - expected: FAIL - - [test_stale_element_reference[child_context\]] - expected: FAIL - - [test_get_shadow_root] - expected: FAIL - - [test_no_shadow_root] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_tag_name/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_tag_name/get.py.ini index 879854dfc56..8fb651289ad 100644 --- a/tests/wpt/meta/webdriver/tests/classic/get_element_tag_name/get.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/get_element_tag_name/get.py.ini @@ -5,8 +5,5 @@ [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL - [test_get_element_tag_name] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/get_element_text/get.py.ini b/tests/wpt/meta/webdriver/tests/classic/get_element_text/get.py.ini index 66e31b2d5a7..b4016ed5298 100644 --- a/tests/wpt/meta/webdriver/tests/classic/get_element_text/get.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/get_element_text/get.py.ini @@ -5,9 +5,6 @@ [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL - [test_transform_capitalize[space\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini b/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini index 9f75dbb4f9e..a287655de66 100644 --- a/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/is_element_enabled/enabled.py.ini @@ -5,9 +5,6 @@ [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL - [test_stale_element_reference[child_context\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/is_element_selected/selected.py.ini b/tests/wpt/meta/webdriver/tests/classic/is_element_selected/selected.py.ini index 2c5777abee2..07512c40b00 100644 --- a/tests/wpt/meta/webdriver/tests/classic/is_element_selected/selected.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/is_element_selected/selected.py.ini @@ -5,8 +5,5 @@ [test_no_such_element_with_shadow_root] expected: FAIL - [test_no_such_element_from_other_window_handle[closed\]] - expected: FAIL - [test_stale_element_reference[child_context\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/new_window/new.py.ini b/tests/wpt/meta/webdriver/tests/classic/new_window/new.py.ini index 7288018eebf..374e04d8c54 100644 --- a/tests/wpt/meta/webdriver/tests/classic/new_window/new.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/new_window/new.py.ini @@ -1,6 +1,3 @@ [new.py] [test_no_top_browsing_context] expected: FAIL - - [test_no_browsing_context] - expected: ERROR diff --git a/tests/wpt/meta/webdriver/tests/classic/new_window/new_tab.py.ini b/tests/wpt/meta/webdriver/tests/classic/new_window/new_tab.py.ini index db51a3496ae..935bc48d1e9 100644 --- a/tests/wpt/meta/webdriver/tests/classic/new_window/new_tab.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/new_window/new_tab.py.ini @@ -1,9 +1,3 @@ [new_tab.py] - [test_keeps_current_window_handle] - expected: FAIL - - [test_opens_about_blank_in_new_tab] - expected: FAIL - [test_initial_selection_for_contenteditable] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/new_window/new_window.py.ini b/tests/wpt/meta/webdriver/tests/classic/new_window/new_window.py.ini index 5ea6fe581f7..c29bde84dc1 100644 --- a/tests/wpt/meta/webdriver/tests/classic/new_window/new_window.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/new_window/new_window.py.ini @@ -2,11 +2,5 @@ [test_payload] expected: FAIL - [test_keeps_current_window_handle] - expected: FAIL - - [test_opens_about_blank_in_new_window] - expected: FAIL - [test_initial_selection_for_contenteditable] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key.py.ini index 42ceab66336..0a9efbca289 100644 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/key.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/key.py.ini @@ -9,19 +9,16 @@ expected: FAIL [test_backspace_erases_keys] - expected: ERROR + expected: FAIL [test_element_in_shadow_tree[outer-open\]] - expected: ERROR + expected: FAIL [test_element_in_shadow_tree[outer-closed\]] - expected: ERROR + expected: FAIL [test_element_in_shadow_tree[inner-open\]] - expected: ERROR + expected: FAIL [test_element_in_shadow_tree[inner-closed\]] - expected: ERROR - - [test_element_not_focused] - expected: ERROR + expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_origin.py.ini b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_origin.py.ini index 8102334d66b..4018e8e3e5b 100644 --- a/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_origin.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/perform_actions/pointer_origin.py.ini @@ -1,10 +1,4 @@ [pointer_origin.py] - [test_viewport_inside] - expected: FAIL - - [test_pointer_inside] - expected: FAIL - [test_element_center_point] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch.py.ini b/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch.py.ini index 66625728565..b26241b424d 100644 --- a/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/switch_to_frame/switch.py.ini @@ -13,6 +13,3 @@ [test_no_browsing_context_when_already_top_level] expected: FAIL - - [test_frame_id_shadow_root] - expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/take_screenshot/screenshot.py.ini b/tests/wpt/meta/webdriver/tests/classic/take_screenshot/screenshot.py.ini index aef7c9d5ddc..f2fac7a7fa1 100644 --- a/tests/wpt/meta/webdriver/tests/classic/take_screenshot/screenshot.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/take_screenshot/screenshot.py.ini @@ -4,6 +4,3 @@ [test_no_browsing_context] expected: FAIL - - [test_format_and_dimensions] - expected: FAIL