LibWeb/HTML: Correctly compute whether element is mutable

This adapts the implementation of `is_mutable` to align more closely
with the spec. Specifically, it is now also taken into account whether
the element is enabled.
This commit is contained in:
Glenn Skrzypczak 2025-08-10 00:29:35 +02:00 committed by Tim Flynn
parent 1228063a85
commit cac2ee41b9
10 changed files with 171 additions and 63 deletions

View File

@ -145,6 +145,9 @@ public:
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-setcustomvalidity // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-setcustomvalidity
void set_custom_validity(String& error); void set_custom_validity(String& error);
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#mutability
virtual bool is_mutable() const { return true; }
protected: protected:
FormAssociatedElement() = default; FormAssociatedElement() = default;
virtual ~FormAssociatedElement() = default; virtual ~FormAssociatedElement() = default;
@ -220,9 +223,6 @@ public:
bool has_scheduled_selectionchange_event() const { return m_has_scheduled_selectionchange_event; } bool has_scheduled_selectionchange_event() const { return m_has_scheduled_selectionchange_event; }
void set_scheduled_selectionchange_event(bool value) { m_has_scheduled_selectionchange_event = value; } void set_scheduled_selectionchange_event(bool value) { m_has_scheduled_selectionchange_event = value; }
bool is_mutable() const { return m_is_mutable; }
void set_is_mutable(bool is_mutable) { m_is_mutable = is_mutable; }
virtual void did_edit_text_node() = 0; virtual void did_edit_text_node() = 0;
virtual GC::Ptr<DOM::Text> form_associated_element_to_text_node() = 0; virtual GC::Ptr<DOM::Text> form_associated_element_to_text_node() = 0;
@ -260,9 +260,6 @@ private:
// https://w3c.github.io/selection-api/#dfn-has-scheduled-selectionchange-event // https://w3c.github.io/selection-api/#dfn-has-scheduled-selectionchange-event
bool m_has_scheduled_selectionchange_event { false }; bool m_has_scheduled_selectionchange_event { false };
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#mutability
bool m_is_mutable { true };
}; };
} }

View File

@ -893,13 +893,6 @@ void HTMLInputElement::handle_maxlength_attribute()
} }
} }
// https://html.spec.whatwg.org/multipage/input.html#attr-input-readonly
void HTMLInputElement::handle_readonly_attribute(Optional<String> const& maybe_value)
{
// The readonly attribute is a boolean attribute that controls whether or not the user can edit the form control. When specified, the element is not mutable.
set_is_mutable(!maybe_value.has_value() || !is_allowed_to_be_readonly(m_type));
}
// https://html.spec.whatwg.org/multipage/input.html#the-input-element:attr-input-placeholder-3 // https://html.spec.whatwg.org/multipage/input.html#the-input-element:attr-input-placeholder-3
static bool is_allowed_to_have_placeholder(HTML::HTMLInputElement::TypeAttributeState state) static bool is_allowed_to_have_placeholder(HTML::HTMLInputElement::TypeAttributeState state)
{ {
@ -1066,7 +1059,6 @@ void HTMLInputElement::create_text_input_shadow_tree()
MUST(element->append_child(*m_inner_text_element)); MUST(element->append_child(*m_inner_text_element));
m_text_node = realm().create<DOM::Text>(document(), move(initial_value)); m_text_node = realm().create<DOM::Text>(document(), move(initial_value));
handle_readonly_attribute(attribute(HTML::AttributeNames::readonly));
if (type_state() == TypeAttributeState::Password) if (type_state() == TypeAttributeState::Password)
m_text_node->set_is_password_input({}, true); m_text_node->set_is_password_input({}, true);
handle_maxlength_attribute(); handle_maxlength_attribute();
@ -1414,8 +1406,6 @@ void HTMLInputElement::form_associated_element_attribute_changed(FlyString const
m_placeholder_text_node->set_data(Utf16String::from_utf8(placeholder())); m_placeholder_text_node->set_data(Utf16String::from_utf8(placeholder()));
update_placeholder_visibility(); update_placeholder_visibility();
} }
} else if (name == HTML::AttributeNames::readonly) {
handle_readonly_attribute(value);
} else if (name == HTML::AttributeNames::src) { } else if (name == HTML::AttributeNames::src) {
handle_src_attribute(value.value_or({})).release_value_but_fixme_should_propagate_errors(); handle_src_attribute(value.value_or({})).release_value_but_fixme_should_propagate_errors();
} else if (name == HTML::AttributeNames::alt) { } else if (name == HTML::AttributeNames::alt) {
@ -3563,4 +3553,16 @@ void HTMLInputElement::set_is_open(bool is_open)
invalidate_style(DOM::StyleInvalidationReason::HTMLInputElementSetIsOpen); invalidate_style(DOM::StyleInvalidationReason::HTMLInputElementSetIsOpen);
} }
bool HTMLInputElement::is_mutable() const
{
return
// https://html.spec.whatwg.org/multipage/input.html#the-input-element:concept-fe-mutable-3
// A select element that is not disabled is mutable.
enabled()
// https://html.spec.whatwg.org/multipage/input.html#the-readonly-attribute:concept-fe-mutable
// The readonly attribute is a boolean attribute that controls whether or not the user can edit the form control. When specified, the element is not mutable.
&& !(has_attribute(AttributeNames::readonly) && is_allowed_to_be_readonly(m_type));
}
} }

View File

@ -252,6 +252,8 @@ public:
virtual bool suffering_from_a_step_mismatch() const override; virtual bool suffering_from_a_step_mismatch() const override;
virtual bool suffering_from_bad_input() const override; virtual bool suffering_from_bad_input() const override;
virtual bool is_mutable() const override;
private: private:
HTMLInputElement(DOM::Document&, DOM::QualifiedName); HTMLInputElement(DOM::Document&, DOM::QualifiedName);
@ -320,7 +322,6 @@ private:
void set_checked_within_group(); void set_checked_within_group();
void handle_maxlength_attribute(); void handle_maxlength_attribute();
void handle_readonly_attribute(Optional<String> const& value);
WebIDL::ExceptionOr<void> handle_src_attribute(String const& value); WebIDL::ExceptionOr<void> handle_src_attribute(String const& value);
void user_interaction_did_change_input_value(); void user_interaction_did_change_input_value();

View File

@ -429,7 +429,7 @@ void HTMLSelectElement::show_the_picker_if_applicable()
return; return;
// 2. If element is not mutable, then return. // 2. If element is not mutable, then return.
if (!enabled()) if (!is_mutable())
return; return;
// 3. Consume user activation given element's relevant global object. // 3. Consume user activation given element's relevant global object.
@ -494,7 +494,7 @@ WebIDL::ExceptionOr<void> HTMLSelectElement::show_picker()
// The showPicker() method steps are: // The showPicker() method steps are:
// 1. If this is not mutable, then throw an "InvalidStateError" DOMException. // 1. If this is not mutable, then throw an "InvalidStateError" DOMException.
if (!enabled()) if (!is_mutable())
return WebIDL::InvalidStateError::create(realm(), "Element is not mutable"_utf16); return WebIDL::InvalidStateError::create(realm(), "Element is not mutable"_utf16);
// 2. If this's relevant settings object's origin is not same origin with this's relevant settings object's top-level origin, // 2. If this's relevant settings object's origin is not same origin with this's relevant settings object's top-level origin,
@ -740,4 +740,11 @@ bool HTMLSelectElement::suffering_from_being_missing() const
return has_attribute(HTML::AttributeNames::required) && (selected_options->length() == 0 || (selected_options->length() == 1 && selected_options->item(0) == placeholder_label_option())); return has_attribute(HTML::AttributeNames::required) && (selected_options->length() == 0 || (selected_options->length() == 1 && selected_options->item(0) == placeholder_label_option()));
} }
// https://html.spec.whatwg.org/multipage/form-elements.html#the-select-element:concept-fe-mutable
bool HTMLSelectElement::is_mutable() const
{
// A select element that is not disabled is mutable.
return enabled();
}
} }

View File

@ -117,6 +117,8 @@ public:
// https://html.spec.whatwg.org/multipage/form-elements.html#the-select-element%3Asuffering-from-being-missing // https://html.spec.whatwg.org/multipage/form-elements.html#the-select-element%3Asuffering-from-being-missing
virtual bool suffering_from_being_missing() const override; virtual bool suffering_from_being_missing() const override;
virtual bool is_mutable() const override;
private: private:
HTMLSelectElement(DOM::Document&, DOM::QualifiedName); HTMLSelectElement(DOM::Document&, DOM::QualifiedName);

View File

@ -376,7 +376,6 @@ void HTMLTextAreaElement::create_shadow_tree_if_needed()
MUST(element->append_child(*m_inner_text_element)); MUST(element->append_child(*m_inner_text_element));
m_text_node = realm().create<DOM::Text>(document(), Utf16String {}); m_text_node = realm().create<DOM::Text>(document(), Utf16String {});
handle_readonly_attribute(attribute(HTML::AttributeNames::readonly));
// NOTE: If `children_changed()` was called before now, `m_raw_value` will hold the text content. // NOTE: If `children_changed()` was called before now, `m_raw_value` will hold the text content.
// Otherwise, it will get filled in whenever that does get called. // Otherwise, it will get filled in whenever that does get called.
m_text_node->set_text_content(m_raw_value); m_text_node->set_text_content(m_raw_value);
@ -386,13 +385,6 @@ void HTMLTextAreaElement::create_shadow_tree_if_needed()
update_placeholder_visibility(); update_placeholder_visibility();
} }
// https://html.spec.whatwg.org/multipage/input.html#attr-input-readonly
void HTMLTextAreaElement::handle_readonly_attribute(Optional<String> const& maybe_value)
{
// The readonly attribute is a boolean attribute that controls whether or not the user can edit the form control. When specified, the element is not mutable.
set_is_mutable(!maybe_value.has_value());
}
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-maxlength // https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-maxlength
void HTMLTextAreaElement::handle_maxlength_attribute() void HTMLTextAreaElement::handle_maxlength_attribute()
{ {
@ -442,8 +434,6 @@ void HTMLTextAreaElement::form_associated_element_attribute_changed(FlyString co
if (name == HTML::AttributeNames::placeholder) { if (name == HTML::AttributeNames::placeholder) {
if (m_placeholder_text_node) if (m_placeholder_text_node)
m_placeholder_text_node->set_data(Utf16String::from_utf8(value.value_or(String {}))); m_placeholder_text_node->set_data(Utf16String::from_utf8(value.value_or(String {})));
} else if (name == HTML::AttributeNames::readonly) {
handle_readonly_attribute(value);
} else if (name == HTML::AttributeNames::maxlength) { } else if (name == HTML::AttributeNames::maxlength) {
handle_maxlength_attribute(); handle_maxlength_attribute();
} }
@ -489,4 +479,11 @@ bool HTMLTextAreaElement::suffering_from_being_missing() const
return has_attribute(HTML::AttributeNames::required) && is_mutable() && value().is_empty(); return has_attribute(HTML::AttributeNames::required) && is_mutable() && value().is_empty();
} }
// https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element:concept-fe-mutable
bool HTMLTextAreaElement::is_mutable() const
{
// A textarea element is mutable if it is neither disabled nor has a readonly attribute specified.
return enabled() && !has_attribute(AttributeNames::readonly);
}
} }

View File

@ -134,6 +134,9 @@ public:
// https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element%3Asuffering-from-being-missing // https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element%3Asuffering-from-being-missing
virtual bool suffering_from_being_missing() const override; virtual bool suffering_from_being_missing() const override;
// https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element:concept-fe-mutable
virtual bool is_mutable() const override;
private: private:
HTMLTextAreaElement(DOM::Document&, DOM::QualifiedName); HTMLTextAreaElement(DOM::Document&, DOM::QualifiedName);
@ -147,7 +150,6 @@ private:
void create_shadow_tree_if_needed(); void create_shadow_tree_if_needed();
void handle_readonly_attribute(Optional<String> const& value);
void handle_maxlength_attribute(); void handle_maxlength_attribute();
void queue_firing_input_event(); void queue_firing_input_event();

View File

@ -2,70 +2,70 @@ Harness status: OK
Found 78 tests Found 78 tests
46 Pass 77 Pass
32 Fail 1 Fail
Pass [INPUT in TEXT status] The required attribute is not set Pass [INPUT in TEXT status] The required attribute is not set
Pass [INPUT in TEXT status] The value is not empty and required is true Pass [INPUT in TEXT status] The value is not empty and required is true
Fail [INPUT in TEXT status] The value is empty and required is true Pass [INPUT in TEXT status] The value is empty and required is true
Pass [INPUT in SEARCH status] The required attribute is not set Pass [INPUT in SEARCH status] The required attribute is not set
Pass [INPUT in SEARCH status] The value is not empty and required is true Pass [INPUT in SEARCH status] The value is not empty and required is true
Fail [INPUT in SEARCH status] The value is empty and required is true Pass [INPUT in SEARCH status] The value is empty and required is true
Pass [INPUT in TEL status] The required attribute is not set Pass [INPUT in TEL status] The required attribute is not set
Pass [INPUT in TEL status] The value is not empty and required is true Pass [INPUT in TEL status] The value is not empty and required is true
Fail [INPUT in TEL status] The value is empty and required is true Pass [INPUT in TEL status] The value is empty and required is true
Pass [INPUT in URL status] The required attribute is not set Pass [INPUT in URL status] The required attribute is not set
Pass [INPUT in URL status] The value is not empty and required is true Pass [INPUT in URL status] The value is not empty and required is true
Fail [INPUT in URL status] The value is empty and required is true Pass [INPUT in URL status] The value is empty and required is true
Pass [INPUT in EMAIL status] The required attribute is not set Pass [INPUT in EMAIL status] The required attribute is not set
Pass [INPUT in EMAIL status] The value is not empty and required is true Pass [INPUT in EMAIL status] The value is not empty and required is true
Fail [INPUT in EMAIL status] The value is empty and required is true Pass [INPUT in EMAIL status] The value is empty and required is true
Pass [INPUT in PASSWORD status] The required attribute is not set Pass [INPUT in PASSWORD status] The required attribute is not set
Pass [INPUT in PASSWORD status] The value is not empty and required is true Pass [INPUT in PASSWORD status] The value is not empty and required is true
Fail [INPUT in PASSWORD status] The value is empty and required is true Pass [INPUT in PASSWORD status] The value is empty and required is true
Pass [INPUT in DATETIME-LOCAL status] The required attribute is not set Pass [INPUT in DATETIME-LOCAL status] The required attribute is not set
Pass [INPUT in DATETIME-LOCAL status] Valid local date and time string(2000-12-10T12:00:00) Pass [INPUT in DATETIME-LOCAL status] Valid local date and time string(2000-12-10T12:00:00)
Pass [INPUT in DATETIME-LOCAL status] Valid local date and time string(2000-12-10 12:00) Pass [INPUT in DATETIME-LOCAL status] Valid local date and time string(2000-12-10 12:00)
Pass [INPUT in DATETIME-LOCAL status] Valid local date and time string(1979-10-14T12:00:00.001) Pass [INPUT in DATETIME-LOCAL status] Valid local date and time string(1979-10-14T12:00:00.001)
Fail [INPUT in DATETIME-LOCAL status] The value attribute is a number(1234567) Pass [INPUT in DATETIME-LOCAL status] The value attribute is a number(1234567)
Fail [INPUT in DATETIME-LOCAL status] The value attribute is a Date object Pass [INPUT in DATETIME-LOCAL status] The value attribute is a Date object
Fail [INPUT in DATETIME-LOCAL status] Invalid local date and time string(1979-10-99 99:99) Pass [INPUT in DATETIME-LOCAL status] Invalid local date and time string(1979-10-99 99:99)
Pass [INPUT in DATETIME-LOCAL status] Valid local date and time string(1979-10-14 12:00:00) Pass [INPUT in DATETIME-LOCAL status] Valid local date and time string(1979-10-14 12:00:00)
Fail [INPUT in DATETIME-LOCAL status] Invalid local date and time string(2001-12-21 12:00)-two white space Pass [INPUT in DATETIME-LOCAL status] Invalid local date and time string(2001-12-21 12:00)-two white space
Fail [INPUT in DATETIME-LOCAL status] the value attribute is a string(abc) Pass [INPUT in DATETIME-LOCAL status] the value attribute is a string(abc)
Fail [INPUT in DATETIME-LOCAL status] The value attribute is empty string Pass [INPUT in DATETIME-LOCAL status] The value attribute is empty string
Pass [INPUT in DATE status] The required attribute is not set Pass [INPUT in DATE status] The required attribute is not set
Pass [INPUT in DATE status] Valid date string(2000-12-10) Pass [INPUT in DATE status] Valid date string(2000-12-10)
Pass [INPUT in DATE status] Valid date string(9999-01-01) Pass [INPUT in DATE status] Valid date string(9999-01-01)
Fail [INPUT in DATE status] The value attribute is a number(1234567) Pass [INPUT in DATE status] The value attribute is a number(1234567)
Fail [INPUT in DATE status] The value attribute is a Date object Pass [INPUT in DATE status] The value attribute is a Date object
Fail [INPUT in DATE status] Invalid date string(9999-99-99) Pass [INPUT in DATE status] Invalid date string(9999-99-99)
Fail [INPUT in DATE status] Invalid date string(37-01-01) Pass [INPUT in DATE status] Invalid date string(37-01-01)
Fail [INPUT in DATE status] Invalid date string(2000/01/01) Pass [INPUT in DATE status] Invalid date string(2000/01/01)
Fail [INPUT in DATE status] The value attribute is empty string Pass [INPUT in DATE status] The value attribute is empty string
Pass [INPUT in TIME status] The required attribute is not set Pass [INPUT in TIME status] The required attribute is not set
Pass [INPUT in TIME status] Validtime string(12:00:00) Pass [INPUT in TIME status] Validtime string(12:00:00)
Pass [INPUT in TIME status] Validtime string(12:00) Pass [INPUT in TIME status] Validtime string(12:00)
Pass [INPUT in TIME status] Valid time string(12:00:60.001) Pass [INPUT in TIME status] Valid time string(12:00:60.001)
Pass [INPUT in TIME status] Valid time string(12:00:60.01) Pass [INPUT in TIME status] Valid time string(12:00:60.01)
Pass [INPUT in TIME status] Valid time string(12:00:60.1) Pass [INPUT in TIME status] Valid time string(12:00:60.1)
Fail [INPUT in TIME status] The value attribute is a number(1234567) Pass [INPUT in TIME status] The value attribute is a number(1234567)
Fail [INPUT in TIME status] The value attribute is a time object Pass [INPUT in TIME status] The value attribute is a time object
Fail [INPUT in TIME status] Invalid time string(25:00:00) Pass [INPUT in TIME status] Invalid time string(25:00:00)
Fail [INPUT in TIME status] Invalid time string(12:60:00) Pass [INPUT in TIME status] Invalid time string(12:60:00)
Fail [INPUT in TIME status] Invalid time string(12:00:60) Pass [INPUT in TIME status] Invalid time string(12:00:60)
Fail [INPUT in TIME status] Invalid time string(12:00:00:001) Pass [INPUT in TIME status] Invalid time string(12:00:00:001)
Fail [INPUT in TIME status] The value attribute is empty string Pass [INPUT in TIME status] The value attribute is empty string
Pass [INPUT in NUMBER status] The required attribute is not set Pass [INPUT in NUMBER status] The required attribute is not set
Pass [INPUT in NUMBER status] Value is an integer with a leading symbol '+' Pass [INPUT in NUMBER status] Value is an integer with a leading symbol '+'
Pass [INPUT in NUMBER status] Value is a number with a '-' symbol Pass [INPUT in NUMBER status] Value is a number with a '-' symbol
Pass [INPUT in NUMBER status] Value is a number in scientific notation form(e is in lowercase) Pass [INPUT in NUMBER status] Value is a number in scientific notation form(e is in lowercase)
Pass [INPUT in NUMBER status] Value is a number in scientific notation form(E is in uppercase) Pass [INPUT in NUMBER status] Value is a number in scientific notation form(E is in uppercase)
Pass [INPUT in NUMBER status] Value is -0 Pass [INPUT in NUMBER status] Value is -0
Fail [INPUT in NUMBER status] Value is a number with some white spaces Pass [INPUT in NUMBER status] Value is a number with some white spaces
Fail [INPUT in NUMBER status] Value is Math.pow(2, 1024) Pass [INPUT in NUMBER status] Value is Math.pow(2, 1024)
Fail [INPUT in NUMBER status] Value is Math.pow(-2, 1024) Pass [INPUT in NUMBER status] Value is Math.pow(-2, 1024)
Fail [INPUT in NUMBER status] Value is a string that cannot be converted to a number Pass [INPUT in NUMBER status] Value is a string that cannot be converted to a number
Fail [INPUT in NUMBER status] The value attribute is empty string Pass [INPUT in NUMBER status] The value attribute is empty string
Pass [INPUT in CHECKBOX status] The required attribute is not set Pass [INPUT in CHECKBOX status] The required attribute is not set
Pass [INPUT in CHECKBOX status] The checked attribute is true Pass [INPUT in CHECKBOX status] The checked attribute is true
Pass [INPUT in CHECKBOX status] The checked attribute is false Pass [INPUT in CHECKBOX status] The checked attribute is false
@ -80,5 +80,5 @@ Pass [select] Selected the option with value equals to 1
Pass [select] Selected the option with value equals to empty Pass [select] Selected the option with value equals to empty
Pass [textarea] The required attribute is not set Pass [textarea] The required attribute is not set
Pass [textarea] The value is not empty Pass [textarea] The value is not empty
Fail [textarea] The value is empty Pass [textarea] The value is empty
Fail validationMessage should return empty string when willValidate is false and valueMissing is true Fail validationMessage should return empty string when willValidate is false and valueMissing is true

View File

@ -0,0 +1,49 @@
Harness status: OK
Found 44 tests
44 Pass
Pass input[type=button] showPicker() throws when disabled
Pass input[type=checkbox] showPicker() throws when disabled
Pass input[type=color] showPicker() throws when disabled
Pass input[type=date] showPicker() throws when disabled
Pass input[type=datetime-local] showPicker() throws when disabled
Pass input[type=email] showPicker() throws when disabled
Pass input[type=file] showPicker() throws when disabled
Pass input[type=hidden] showPicker() throws when disabled
Pass input[type=image] showPicker() throws when disabled
Pass input[type=month] showPicker() throws when disabled
Pass input[type=number] showPicker() throws when disabled
Pass input[type=password] showPicker() throws when disabled
Pass input[type=radio] showPicker() throws when disabled
Pass input[type=range] showPicker() throws when disabled
Pass input[type=reset] showPicker() throws when disabled
Pass input[type=search] showPicker() throws when disabled
Pass input[type=submit] showPicker() throws when disabled
Pass input[type=tel] showPicker() throws when disabled
Pass input[type=text] showPicker() throws when disabled
Pass input[type=time] showPicker() throws when disabled
Pass input[type=url] showPicker() throws when disabled
Pass input[type=week] showPicker() throws when disabled
Pass input[type=button] showPicker() doesn't throw when readonly
Pass input[type=checkbox] showPicker() doesn't throw when readonly
Pass input[type=color] showPicker() doesn't throw when readonly
Pass input[type=date] showPicker() throws when readonly
Pass input[type=datetime-local] showPicker() throws when readonly
Pass input[type=email] showPicker() throws when readonly
Pass input[type=file] showPicker() doesn't throw when readonly
Pass input[type=hidden] showPicker() doesn't throw when readonly
Pass input[type=image] showPicker() doesn't throw when readonly
Pass input[type=month] showPicker() throws when readonly
Pass input[type=number] showPicker() throws when readonly
Pass input[type=password] showPicker() throws when readonly
Pass input[type=radio] showPicker() doesn't throw when readonly
Pass input[type=range] showPicker() doesn't throw when readonly
Pass input[type=reset] showPicker() doesn't throw when readonly
Pass input[type=search] showPicker() throws when readonly
Pass input[type=submit] showPicker() doesn't throw when readonly
Pass input[type=tel] showPicker() throws when readonly
Pass input[type=text] showPicker() throws when readonly
Pass input[type=time] showPicker() throws when readonly
Pass input[type=url] showPicker() throws when readonly
Pass input[type=week] showPicker() throws when readonly

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<title>Test showPicker() disabled/readonly requirement</title>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="../../../../resources/testdriver.js"></script>
<script src="../../../../resources/testdriver-vendor.js"></script>
<body></body>
<script type=module>
import inputTypes from "./input-types.js";
for (const inputType of inputTypes) {
test(() => {
const input = document.createElement("input");
input.setAttribute("type", inputType);
input.setAttribute("disabled", "");
assert_throws_dom('InvalidStateError', () => { input.showPicker(); });
}, `input[type=${inputType}] showPicker() throws when disabled`);
}
const noReadonlySupport = ['button', 'checkbox', 'color', 'file',
'hidden', 'image', 'radio', 'range', 'reset', 'submit'];
for (const inputType of inputTypes) {
if (!noReadonlySupport.includes(inputType)) {
promise_test(async () => {
const input = document.createElement("input");
input.setAttribute("type", inputType);
input.setAttribute("readonly", "");
await test_driver.bless('show picker');
assert_throws_dom('InvalidStateError', () => { input.showPicker(); });
assert_true(navigator.userActivation.isActive, 'User activation is not consumed for readonly showPicker() call');
}, `input[type=${inputType}] showPicker() throws when readonly`);
} else {
promise_test(async () => {
const input = document.createElement("input");
input.setAttribute("type", inputType);
input.setAttribute("readonly", "");
document.body.appendChild(input);
await test_driver.bless('show picker');
input.showPicker();
input.blur();
input.remove();
assert_false(navigator.userActivation.isActive, 'User activation is consumed for non-readonly showPicker() call');
}, `input[type=${inputType}] showPicker() doesn't throw when readonly`);
}
}
</script>