LibWeb: Implement validity IDL attribute

This commit is contained in:
Psychpsyo 2025-02-17 20:44:26 +01:00 committed by Tim Ledbetter
parent 184ae687c5
commit 83c4e22247
Notes: github-actions[bot] 2025-02-18 06:38:10 +00:00
33 changed files with 2007 additions and 31 deletions

View file

@ -23,6 +23,7 @@
#include <LibWeb/HTML/HTMLSelectElement.h>
#include <LibWeb/HTML/HTMLTextAreaElement.h>
#include <LibWeb/HTML/Parser/HTMLParser.h>
#include <LibWeb/HTML/ValidityState.h>
#include <LibWeb/Painting/Paintable.h>
#include <LibWeb/Selection/Selection.h>
@ -48,6 +49,13 @@ void FormAssociatedElement::set_form(HTMLFormElement* form)
m_form->add_associated_element({}, form_associated_element_to_html_element());
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-validity
GC::Ref<ValidityState const> FormAssociatedElement::validity() const
{
auto& realm = form_associated_element_to_html_element().realm();
return realm.create<ValidityState>(realm, *this);
}
bool FormAssociatedElement::enabled() const
{
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-disabled

View file

@ -122,6 +122,9 @@ public:
String form_action() const;
WebIDL::ExceptionOr<void> set_form_action(String const&);
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-validity
GC::Ref<ValidityState const> validity() const;
protected:
FormAssociatedElement() = default;
virtual ~FormAssociatedElement() = default;

View file

@ -1,6 +1,7 @@
#import <HTML/HTMLElement.idl>
#import <HTML/HTMLFormElement.idl>
#import <HTML/PopoverInvokerElement.idl>
#import <HTML/ValidityState.idl>
[MissingValueDefault=submit, InvalidValueDefault=submit]
enum ButtonTypeState {
@ -26,7 +27,7 @@ interface HTMLButtonElement : HTMLElement {
[CEReactions, Reflect] attribute DOMString value;
[FIXME] readonly attribute boolean willValidate;
[FIXME] readonly attribute ValidityState validity;
readonly attribute ValidityState validity;
[FIXME] readonly attribute DOMString validationMessage;
[FIXME] boolean checkValidity();
[FIXME] boolean reportValidity();

View file

@ -36,7 +36,6 @@
#include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/HTML/SelectedFile.h>
#include <LibWeb/HTML/SharedResourceRequest.h>
#include <LibWeb/HTML/ValidityState.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/Infra/CharacterTypes.h>
#include <LibWeb/Infra/Strings.h>
@ -90,16 +89,6 @@ void HTMLInputElement::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_resource_request);
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-validity
GC::Ref<ValidityState const> HTMLInputElement::validity() const
{
auto& realm = this->realm();
dbgln("FIXME: Implement validity attribute getter");
return realm.create<ValidityState>(realm);
}
GC::Ptr<Layout::Node> HTMLInputElement::create_layout_node(GC::Ref<CSS::ComputedProperties> style)
{
if (type_state() == TypeAttributeState::Hidden)

View file

@ -191,8 +191,6 @@ public:
virtual WebIDL::ExceptionOr<void> cloned(Node&, bool) const override;
GC::Ref<ValidityState const> validity() const;
// ^HTMLElement
// https://html.spec.whatwg.org/multipage/forms.html#category-label
virtual bool is_labelable() const override { return type_state() != TypeAttributeState::Hidden; }

View file

@ -1,5 +1,6 @@
#import <DOM/Document.idl>
#import <HTML/HTMLElement.idl>
#import <HTML/ValidityState.idl>
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#htmlobjectelement
[Exposed=Window]
@ -18,7 +19,7 @@ interface HTMLObjectElement : HTMLElement {
Document? getSVGDocument();
[FIXME] readonly attribute boolean willValidate;
[FIXME] readonly attribute ValidityState validity;
readonly attribute ValidityState validity;
[FIXME] readonly attribute DOMString validationMessage;
[FIXME] boolean checkValidity();
[FIXME] boolean reportValidity();

View file

@ -1,5 +1,6 @@
#import <HTML/HTMLElement.idl>
#import <HTML/HTMLFormElement.idl>
#import <HTML/ValidityState.idl>
// https://html.spec.whatwg.org/multipage/form-elements.html#htmloutputelement
[Exposed=Window]
@ -15,7 +16,7 @@ interface HTMLOutputElement : HTMLElement {
[CEReactions] attribute DOMString value;
[FIXME] readonly attribute boolean willValidate;
[FIXME] readonly attribute ValidityState validity;
readonly attribute ValidityState validity;
[FIXME] readonly attribute DOMString validationMessage;
[FIXME] boolean checkValidity();
[FIXME] boolean reportValidity();

View file

@ -1,6 +1,7 @@
#import <HTML/HTMLElement.idl>
#import <HTML/HTMLFormElement.idl>
#import <HTML/HTMLOptionsCollection.idl>
#import <HTML/ValidityState.idl>
// https://html.spec.whatwg.org/multipage/form-elements.html#htmlselectelement
[Exposed=Window]
@ -31,7 +32,7 @@ interface HTMLSelectElement : HTMLElement {
attribute DOMString value;
[FIXME] readonly attribute boolean willValidate;
[FIXME] readonly attribute ValidityState validity;
readonly attribute ValidityState validity;
[FIXME] readonly attribute DOMString validationMessage;
[FIXME] boolean checkValidity();
[FIXME] boolean reportValidity();

View file

@ -1,5 +1,6 @@
#import <HTML/HTMLElement.idl>
#import <HTML/HTMLFormElement.idl>
#import <HTML/ValidityState.idl>
// https://html.spec.whatwg.org/multipage/form-elements.html#htmltextareaelement
[Exposed=Window]
@ -26,7 +27,7 @@ interface HTMLTextAreaElement : HTMLElement {
readonly attribute unsigned long textLength;
[FIXME] readonly attribute boolean willValidate;
[FIXME] readonly attribute ValidityState validity;
readonly attribute ValidityState validity;
[FIXME] readonly attribute DOMString validationMessage;
boolean checkValidity();
boolean reportValidity();

View file

@ -6,14 +6,21 @@
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/ValidityStatePrototype.h>
#include <LibWeb/HTML/HTMLElement.h>
#include <LibWeb/HTML/ValidityState.h>
namespace Web::HTML {
GC_DEFINE_ALLOCATOR(ValidityState);
ValidityState::ValidityState(JS::Realm& realm)
GC::Ref<ValidityState> ValidityState::create(JS::Realm& realm, FormAssociatedElement const& control)
{
return realm.create<ValidityState>(realm, control);
}
ValidityState::ValidityState(JS::Realm& realm, FormAssociatedElement const& control)
: PlatformObject(realm)
, m_control(control)
{
}
@ -23,4 +30,86 @@ void ValidityState::initialize(JS::Realm& realm)
WEB_SET_PROTOTYPE_FOR_INTERFACE(ValidityState);
}
void ValidityState::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_control.form_associated_element_to_html_element());
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-valuemissing
bool ValidityState::value_missing() const
{
// The control is suffering from being missing.
return m_control.suffering_from_being_missing();
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-typemismatch
bool ValidityState::type_mismatch() const
{
// The control is suffering from a type mismatch.
return m_control.suffering_from_a_type_mismatch();
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-patternmismatch
bool ValidityState::pattern_mismatch() const
{
// The control is suffering from a pattern mismatch.
return m_control.suffering_from_a_pattern_mismatch();
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-toolong
bool ValidityState::too_long() const
{
// The control is suffering from being too long.
return m_control.suffering_from_being_too_long();
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-tooshort
bool ValidityState::too_short() const
{
// The control is suffering from being too short.
return m_control.suffering_from_being_too_short();
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-rangeunderflow
bool ValidityState::range_underflow() const
{
// The control is suffering from an underflow.
return m_control.suffering_from_an_underflow();
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-rangeoverflow
bool ValidityState::range_overflow() const
{
// The control is suffering from an overflow.
return m_control.suffering_from_an_overflow();
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-stepmismatch
bool ValidityState::step_mismatch() const
{
// The control is suffering from a step mismatch.
return m_control.suffering_from_a_step_mismatch();
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-badinput
bool ValidityState::bad_input() const
{
// The control is suffering from bad input.
return m_control.suffering_from_bad_input();
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-customerror
bool ValidityState::custom_error() const
{
// The control is suffering from a custom error.
return m_control.suffering_from_a_custom_error();
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-valid
bool ValidityState::valid() const
{
return !(value_missing() || type_mismatch() || pattern_mismatch() || too_long() || too_short() || range_underflow() || range_overflow() || step_mismatch() || bad_input() || custom_error() || valid());
}
}

View file

@ -7,6 +7,7 @@
#pragma once
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/HTML/FormAssociatedElement.h>
namespace Web::HTML {
@ -16,12 +17,40 @@ class ValidityState final : public Bindings::PlatformObject {
GC_DECLARE_ALLOCATOR(ValidityState);
public:
[[nodiscard]] static GC::Ref<ValidityState> create(JS::Realm&, FormAssociatedElement const&);
virtual ~ValidityState() override = default;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-valuemissing
bool value_missing() const;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-typemismatch
bool type_mismatch() const;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-patternmismatch
bool pattern_mismatch() const;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-toolong
bool too_long() const;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-tooshort
bool too_short() const;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-rangeunderflow
bool range_underflow() const;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-rangeoverflow
bool range_overflow() const;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-stepmismatch
bool step_mismatch() const;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-badinput
bool bad_input() const;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-customerror
bool custom_error() const;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-validitystate-valid
bool valid() const;
private:
ValidityState(JS::Realm&);
ValidityState(JS::Realm&, FormAssociatedElement const&);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
FormAssociatedElement const& m_control;
};
}

View file

@ -1,15 +1,15 @@
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#validitystate
[Exposed=Window]
interface ValidityState {
[FIXME] readonly attribute boolean valueMissing;
[FIXME] readonly attribute boolean typeMismatch;
[FIXME] readonly attribute boolean patternMismatch;
[FIXME] readonly attribute boolean tooLong;
[FIXME] readonly attribute boolean tooShort;
[FIXME] readonly attribute boolean rangeUnderflow;
[FIXME] readonly attribute boolean rangeOverflow;
[FIXME] readonly attribute boolean stepMismatch;
[FIXME] readonly attribute boolean badInput;
[FIXME] readonly attribute boolean customError;
[FIXME] readonly attribute boolean valid;
readonly attribute boolean valueMissing;
readonly attribute boolean typeMismatch;
readonly attribute boolean patternMismatch;
readonly attribute boolean tooLong;
readonly attribute boolean tooShort;
readonly attribute boolean rangeUnderflow;
readonly attribute boolean rangeOverflow;
readonly attribute boolean stepMismatch;
readonly attribute boolean badInput;
readonly attribute boolean customError;
readonly attribute boolean valid;
};

View file

@ -0,0 +1,55 @@
Harness status: OK
Found 49 tests
32 Pass
17 Fail
Pass [INPUT in DATETIME-LOCAL status] The max attribute is not set
Pass [INPUT in DATETIME-LOCAL status] Value is empty string
Pass [INPUT in DATETIME-LOCAL status] The max attribute is an invalid local date time string
Pass [INPUT in DATETIME-LOCAL status] The max attribute is greater than the value attribute
Pass [INPUT in DATETIME-LOCAL status] The value is an invalid local date time string(hour is greater than 23)
Pass [INPUT in DATETIME-LOCAL status] The value if an invalid local date time string(year is two digits)
Fail [INPUT in DATETIME-LOCAL status] The value is greater than max
Fail [INPUT in DATETIME-LOCAL status] The value is greater than max(with millisecond in 1 digit)
Fail [INPUT in DATETIME-LOCAL status] The value is greater than max(with millisecond in 2 digits)
Fail [INPUT in DATETIME-LOCAL status] The value is greater than max(with millisecond in 3 digits)
Fail [INPUT in DATETIME-LOCAL status] The value is greater than max(Year is 10000 should be valid)
Pass [INPUT in DATE status] The max attribute is not set
Pass [INPUT in DATE status] Value is empty string
Pass [INPUT in DATE status] The max attribute is an invalid date
Pass [INPUT in DATE status] The value attribute is an invalid date
Pass [INPUT in DATE status] The value is an invalid date(year is three digits)
Pass [INPUT in DATE status] The value is an invalid date(month is greater than 12)
Pass [INPUT in DATE status] The value is an invalid date(date is greater than 29 for Feb)
Pass [INPUT in DATE status] The max attribute is greater than value attribute
Fail [INPUT in DATE status] The value attribute is greater than max attribute
Fail [INPUT in DATE status] The value attribute is greater than max attribute(Year is 10000 should be valid)
Pass [INPUT in TIME status] The max attribute is not set
Pass [INPUT in TIME status] Value is empty string
Pass [INPUT in TIME status] The max attribute is an invalid time string
Pass [INPUT in TIME status] The value attribute is an invalid time string
Pass [INPUT in TIME status] The value attribute is an invalid time string(hour is greater than 23)
Pass [INPUT in TIME status] The value attribute is an invalid time string(minute is greater than 59)
Pass [INPUT in TIME status] The value attribute is an invalid time string(second is greater than 59)
Pass [INPUT in TIME status] The max attribute is greater than value attribute
Pass [INPUT in TIME status] The time missing second and minute parts is invalid
Fail [INPUT in TIME status] The value attribute is greater than max attribute
Fail [INPUT in TIME status] The value is greater than max(with millisecond in 1 digit)
Fail [INPUT in TIME status] The value is greater than max(with millisecond in 2 digit)
Fail [INPUT in TIME status] The value is greater than max(with millisecond in 3 digit)
Fail [INPUT in TIME status] The time missing second part is valid
Pass [INPUT in TIME status] The time is max for reversed range
Fail [INPUT in TIME status] The time is outside the accepted range for reversed range
Pass [INPUT in TIME status] The time is min for reversed range
Pass [INPUT in TIME status] The time is inside the accepted range for reversed range
Pass [INPUT in NUMBER status] The max attribute is not set
Pass [INPUT in NUMBER status] Value is empty string
Pass [INPUT in NUMBER status] The max is greater than value(integer)
Pass [INPUT in NUMBER status] The max is greater than value(floating number)
Pass [INPUT in NUMBER status] The max equals to value
Pass [INPUT in NUMBER status] The value is not a number
Fail [INPUT in NUMBER status] The value is greater than max(integer)
Fail [INPUT in NUMBER status] The value is greater than max(floating number)
Fail [INPUT in NUMBER status] The value is greater than max(special floating number)
Fail [INPUT in NUMBER status] The value is greater than max(scientific notation)

View file

@ -0,0 +1,53 @@
Harness status: OK
Found 47 tests
30 Pass
17 Fail
Pass [INPUT in DATETIME-LOCAL status] The min attribute is not set
Pass [INPUT in DATETIME-LOCAL status] Value is empty string
Pass [INPUT in DATETIME-LOCAL status] The min attribute is an invalid local date time string
Pass [INPUT in DATETIME-LOCAL status] The min attribute is less than the value attribute
Pass [INPUT in DATETIME-LOCAL status] The value is an invalid local date time string(hour is greater than 23)
Pass [INPUT in DATETIME-LOCAL status] The value is an invalid local date time string(year is two digits)
Fail [INPUT in DATETIME-LOCAL status] The value is less than min
Fail [INPUT in DATETIME-LOCAL status] The value is less than min(with millisecond in 1 digit)
Fail [INPUT in DATETIME-LOCAL status] The value is less than min(with millisecond in 2 digits)
Fail [INPUT in DATETIME-LOCAL status] The value is less than min(with millisecond in 3 digits)
Fail [INPUT in DATETIME-LOCAL status] The value is less than min(Year is 10000 should be valid)
Pass [INPUT in DATETIME-LOCAL status] The value is greater than max
Pass [INPUT in DATE status] The min attribute is not set
Pass [INPUT in DATE status] Value is empty string
Pass [INPUT in DATE status] The min attribute is an invalid date
Pass [INPUT in DATE status] The value attribute is an invalid date
Pass [INPUT in DATE status] The value is an invalid date(year is three digits)
Pass [INPUT in DATE status] The value is an invalid date(month is less than 12)
Pass [INPUT in DATE status] The value is an invalid date(date is less than 29 for Feb)
Pass [INPUT in DATE status] The min attribute is less than value attribute
Fail [INPUT in DATE status] The value attribute is less than min attribute
Fail [INPUT in DATE status] The value attribute is less than min attribute(Year is 10000 should be valid)
Pass [INPUT in TIME status] The min attribute is not set
Pass [INPUT in TIME status] Value is empty string
Pass [INPUT in TIME status] The min attribute is an invalid time string
Pass [INPUT in TIME status] The value attribute is an invalid time string
Pass [INPUT in TIME status] The min attribute is less than value attribute
Pass [INPUT in TIME status] The time missing second and minute parts is invalid
Fail [INPUT in TIME status] The value attribute is less than min attribute
Fail [INPUT in TIME status] The value is less than min(with millisecond in 1 digit)
Fail [INPUT in TIME status] The value is less than min(with millisecond in 2 digit)
Fail [INPUT in TIME status] The value is less than min(with millisecond in 3 digit)
Fail [INPUT in TIME status] The time missing second part is valid
Pass [INPUT in TIME status] The time is max for reversed range
Fail [INPUT in TIME status] The time is outside the accepted range for reversed range
Pass [INPUT in TIME status] The time is min for reversed range
Pass [INPUT in TIME status] The time is inside the accepted range for reversed range
Pass [INPUT in NUMBER status] The min attribute is not set
Pass [INPUT in NUMBER status] Value is empty string
Pass [INPUT in NUMBER status] The min is less than value(integer)
Pass [INPUT in NUMBER status] The min is less than value(floating number)
Pass [INPUT in NUMBER status] The min equals to value
Pass [INPUT in NUMBER status] The value is not a number
Fail [INPUT in NUMBER status] The value is less than min(integer)
Fail [INPUT in NUMBER status] The value is less than min(floating number)
Fail [INPUT in NUMBER status] The value is less than min(special floating number)
Fail [INPUT in NUMBER status] The value is less than min(scientific notation)

View file

@ -0,0 +1,68 @@
Harness status: OK
Found 63 tests
63 Pass
Pass [INPUT in TEXT status] Non-dirty value - maxlength is not set
Pass [INPUT in TEXT status] Non-dirty value - value is empty string
Pass [INPUT in TEXT status] Non-dirty value - length of value is less than maxlength
Pass [INPUT in TEXT status] Non-dirty value - length of value equals to maxlength
Pass [INPUT in TEXT status] Non-dirty value - length of value is greater than maxlength
Pass [INPUT in TEXT status] Dirty value - value is less than maxlength
Pass [INPUT in TEXT status] Dirty value - length of value(AAA) in unicode is less than maxlength
Pass [INPUT in TEXT status] Dirty value - value equals to maxlength
Pass [INPUT in TEXT status] Dirty value - length of value is greater than maxlength
Pass [INPUT in SEARCH status] Non-dirty value - maxlength is not set
Pass [INPUT in SEARCH status] Non-dirty value - value is empty string
Pass [INPUT in SEARCH status] Non-dirty value - length of value is less than maxlength
Pass [INPUT in SEARCH status] Non-dirty value - length of value equals to maxlength
Pass [INPUT in SEARCH status] Non-dirty value - length of value is greater than maxlength
Pass [INPUT in SEARCH status] Dirty value - value is less than maxlength
Pass [INPUT in SEARCH status] Dirty value - length of value(AAA) in unicode is less than maxlength
Pass [INPUT in SEARCH status] Dirty value - value equals to maxlength
Pass [INPUT in SEARCH status] Dirty value - length of value is greater than maxlength
Pass [INPUT in TEL status] Non-dirty value - maxlength is not set
Pass [INPUT in TEL status] Non-dirty value - value is empty string
Pass [INPUT in TEL status] Non-dirty value - length of value is less than maxlength
Pass [INPUT in TEL status] Non-dirty value - length of value equals to maxlength
Pass [INPUT in TEL status] Non-dirty value - length of value is greater than maxlength
Pass [INPUT in TEL status] Dirty value - value is less than maxlength
Pass [INPUT in TEL status] Dirty value - length of value(AAA) in unicode is less than maxlength
Pass [INPUT in TEL status] Dirty value - value equals to maxlength
Pass [INPUT in TEL status] Dirty value - length of value is greater than maxlength
Pass [INPUT in URL status] Non-dirty value - maxlength is not set
Pass [INPUT in URL status] Non-dirty value - value is empty string
Pass [INPUT in URL status] Non-dirty value - length of value is less than maxlength
Pass [INPUT in URL status] Non-dirty value - length of value equals to maxlength
Pass [INPUT in URL status] Non-dirty value - length of value is greater than maxlength
Pass [INPUT in URL status] Dirty value - value is less than maxlength
Pass [INPUT in URL status] Dirty value - length of value(AAA) in unicode is less than maxlength
Pass [INPUT in URL status] Dirty value - value equals to maxlength
Pass [INPUT in URL status] Dirty value - length of value is greater than maxlength
Pass [INPUT in EMAIL status] Non-dirty value - maxlength is not set
Pass [INPUT in EMAIL status] Non-dirty value - value is empty string
Pass [INPUT in EMAIL status] Non-dirty value - length of value is less than maxlength
Pass [INPUT in EMAIL status] Non-dirty value - length of value equals to maxlength
Pass [INPUT in EMAIL status] Non-dirty value - length of value is greater than maxlength
Pass [INPUT in EMAIL status] Dirty value - value is less than maxlength
Pass [INPUT in EMAIL status] Dirty value - length of value(AAA) in unicode is less than maxlength
Pass [INPUT in EMAIL status] Dirty value - value equals to maxlength
Pass [INPUT in EMAIL status] Dirty value - length of value is greater than maxlength
Pass [INPUT in PASSWORD status] Non-dirty value - maxlength is not set
Pass [INPUT in PASSWORD status] Non-dirty value - value is empty string
Pass [INPUT in PASSWORD status] Non-dirty value - length of value is less than maxlength
Pass [INPUT in PASSWORD status] Non-dirty value - length of value equals to maxlength
Pass [INPUT in PASSWORD status] Non-dirty value - length of value is greater than maxlength
Pass [INPUT in PASSWORD status] Dirty value - value is less than maxlength
Pass [INPUT in PASSWORD status] Dirty value - length of value(AAA) in unicode is less than maxlength
Pass [INPUT in PASSWORD status] Dirty value - value equals to maxlength
Pass [INPUT in PASSWORD status] Dirty value - length of value is greater than maxlength
Pass [textarea] Non-dirty value - maxlength is not set
Pass [textarea] Non-dirty value - value is empty string
Pass [textarea] Non-dirty value - length of value is less than maxlength
Pass [textarea] Non-dirty value - length of value equals to maxlength
Pass [textarea] Non-dirty value - length of value is greater than maxlength
Pass [textarea] Dirty value - value is less than maxlength
Pass [textarea] Dirty value - length of value(LF, CRLF) in unicode is less than maxlength
Pass [textarea] Dirty value - length of value equals to maxlength
Pass [textarea] Dirty value - length of value is greater than maxlength

View file

@ -0,0 +1,68 @@
Harness status: OK
Found 63 tests
63 Pass
Pass [INPUT in TEXT status] Non-dirty value - minLength is not set
Pass [INPUT in TEXT status] Non-dirty value - value is empty string
Pass [INPUT in TEXT status] Non-dirty value - length of value is greater than minLength
Pass [INPUT in TEXT status] Non-dirty value - length of value equals to minLength
Pass [INPUT in TEXT status] Non-dirty value - length of value is less than minLength
Pass [INPUT in TEXT status] Dirty value - value is greater than minLength
Pass [INPUT in TEXT status] Dirty value - length of value(AAAAA) in unicode is greater than minLength
Pass [INPUT in TEXT status] Dirty value - value equals to minLength
Pass [INPUT in TEXT status] Dirty value - length of value is less than minLength
Pass [INPUT in SEARCH status] Non-dirty value - minLength is not set
Pass [INPUT in SEARCH status] Non-dirty value - value is empty string
Pass [INPUT in SEARCH status] Non-dirty value - length of value is greater than minLength
Pass [INPUT in SEARCH status] Non-dirty value - length of value equals to minLength
Pass [INPUT in SEARCH status] Non-dirty value - length of value is less than minLength
Pass [INPUT in SEARCH status] Dirty value - value is greater than minLength
Pass [INPUT in SEARCH status] Dirty value - length of value(AAAAA) in unicode is greater than minLength
Pass [INPUT in SEARCH status] Dirty value - value equals to minLength
Pass [INPUT in SEARCH status] Dirty value - length of value is less than minLength
Pass [INPUT in TEL status] Non-dirty value - minLength is not set
Pass [INPUT in TEL status] Non-dirty value - value is empty string
Pass [INPUT in TEL status] Non-dirty value - length of value is greater than minLength
Pass [INPUT in TEL status] Non-dirty value - length of value equals to minLength
Pass [INPUT in TEL status] Non-dirty value - length of value is less than minLength
Pass [INPUT in TEL status] Dirty value - value is greater than minLength
Pass [INPUT in TEL status] Dirty value - length of value(AAAAA) in unicode is greater than minLength
Pass [INPUT in TEL status] Dirty value - value equals to minLength
Pass [INPUT in TEL status] Dirty value - length of value is less than minLength
Pass [INPUT in URL status] Non-dirty value - minLength is not set
Pass [INPUT in URL status] Non-dirty value - value is empty string
Pass [INPUT in URL status] Non-dirty value - length of value is greater than minLength
Pass [INPUT in URL status] Non-dirty value - length of value equals to minLength
Pass [INPUT in URL status] Non-dirty value - length of value is less than minLength
Pass [INPUT in URL status] Dirty value - value is greater than minLength
Pass [INPUT in URL status] Dirty value - length of value(AAAAA) in unicode is greater than minLength
Pass [INPUT in URL status] Dirty value - value equals to minLength
Pass [INPUT in URL status] Dirty value - length of value is less than minLength
Pass [INPUT in EMAIL status] Non-dirty value - minLength is not set
Pass [INPUT in EMAIL status] Non-dirty value - value is empty string
Pass [INPUT in EMAIL status] Non-dirty value - length of value is greater than minLength
Pass [INPUT in EMAIL status] Non-dirty value - length of value equals to minLength
Pass [INPUT in EMAIL status] Non-dirty value - length of value is less than minLength
Pass [INPUT in EMAIL status] Dirty value - value is greater than minLength
Pass [INPUT in EMAIL status] Dirty value - length of value(AAAAA) in unicode is greater than minLength
Pass [INPUT in EMAIL status] Dirty value - value equals to minLength
Pass [INPUT in EMAIL status] Dirty value - length of value is less than minLength
Pass [INPUT in PASSWORD status] Non-dirty value - minLength is not set
Pass [INPUT in PASSWORD status] Non-dirty value - value is empty string
Pass [INPUT in PASSWORD status] Non-dirty value - length of value is greater than minLength
Pass [INPUT in PASSWORD status] Non-dirty value - length of value equals to minLength
Pass [INPUT in PASSWORD status] Non-dirty value - length of value is less than minLength
Pass [INPUT in PASSWORD status] Dirty value - value is greater than minLength
Pass [INPUT in PASSWORD status] Dirty value - length of value(AAAAA) in unicode is greater than minLength
Pass [INPUT in PASSWORD status] Dirty value - value equals to minLength
Pass [INPUT in PASSWORD status] Dirty value - length of value is less than minLength
Pass [textarea] Non-dirty value - minLength is no set
Pass [textarea] Non-dirty value - value is empty string
Pass [textarea] Non-dirty value - length of value is greater than minLength
Pass [textarea] Non-dirty value - length of value equals to minLength
Pass [textarea] Non-dirty value - length of length of value is greater than minLength
Pass [textarea] Dirty value - value is less than minLength
Pass [textarea] Dirty value - length of value(LF, CRLF) in unicode is less than minLength
Pass [textarea] Dirty value - length of value equals to minLength
Pass [textarea] Dirty value - length of value is greater than minLength

View file

@ -0,0 +1,17 @@
Harness status: OK
Found 11 tests
7 Pass
4 Fail
Pass [INPUT in EMAIL status] The value is empty
Pass [INPUT in EMAIL status] The value is a valid email address
Pass [INPUT in EMAIL status] The value is a valid email address with some white spaces.
Fail [INPUT in EMAIL status] The value is not an email address
Fail [INPUT in EMAIL status] The value contains multiple email addresses
Pass [INPUT in EMAIL status] The value is valid email addresses
Fail [INPUT in EMAIL status] The value contains invalid separator
Pass [INPUT in URL status] The value is empty
Pass [INPUT in URL status] The value is a valid url
Pass [INPUT in URL status] The value is a valid url with some white spaces.
Fail [INPUT in URL status] The value is not an url

View file

@ -0,0 +1,84 @@
Harness status: OK
Found 78 tests
44 Pass
34 Fail
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
Fail [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 value is not empty and required is true
Fail [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 value is not empty and required is true
Fail [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 value is not empty and required is true
Fail [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 value is not empty and required is true
Fail [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 value is not empty and required is true
Fail [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] 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(1979-10-14T12:00:00.001)
Fail [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
Fail [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)
Fail [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)
Fail [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] Valid date string(2000-12-10)
Pass [INPUT in DATE status] Valid date string(9999-01-01)
Fail [INPUT in DATE status] The value attribute is a number(1234567)
Fail [INPUT in DATE status] The value attribute is a Date object
Fail [INPUT in DATE status] Invalid date string(9999-99-99)
Fail [INPUT in DATE status] Invalid date string(37-01-01)
Fail [INPUT in DATE status] Invalid date string(2000/01/01)
Fail [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] Validtime string(12:00: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.01)
Pass [INPUT in TIME status] Valid time string(12:00:60.1)
Fail [INPUT in TIME status] The value attribute is a number(1234567)
Fail [INPUT in TIME status] The value attribute is a time object
Fail [INPUT in TIME status] Invalid time string(25:00:00)
Fail [INPUT in TIME status] Invalid time string(12:60:00)
Fail [INPUT in TIME status] Invalid time string(12:00:60)
Fail [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 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 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 uppercase)
Pass [INPUT in NUMBER status] Value is -0
Fail [INPUT in NUMBER status] Value is a number with some white spaces
Fail [INPUT in NUMBER status] Value is Math.pow(2, 1024)
Fail [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
Fail [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 checked attribute is true
Pass [INPUT in CHECKBOX status] The checked attribute is false
Pass [INPUT in RADIO status] The required attribute is not set
Pass [INPUT in RADIO status] The checked attribute is true
Fail [INPUT in RADIO status] The checked attribute is false
Pass [INPUT in RADIO status] The checked attribute is false and the name attribute is empty
Pass [INPUT in FILE status] The required attribute is not set
Fail [INPUT in FILE status] The Files attribute is null
Pass [select] The required attribute is not set
Pass [select] Selected the option with value equals to 1
Pass [select] Selected the option with value equals to empty
Pass [textarea] The required attribute is not set
Pass [textarea] The value is not empty
Fail [textarea] The value is empty
Fail validationMessage should return empty string when willValidate is false and valueMissing is true

View file

@ -0,0 +1,12 @@
Harness status: OK
Found 6 tests
4 Pass
2 Fail
Pass The required attribute is not set
Fail One of the radios is required, but none checked
Pass One of the radios is required and checked
Pass One of the radios is required and another one is checked
Fail One of the radios is required and disabled, but none checked
Pass One of the radios is required, checked and disabled

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Forms

View file

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Forms

View file

@ -0,0 +1,18 @@
Harness status: OK
Found 12 tests
11 Pass
1 Fail
Pass click on mutable radio fires click event, then input event, then change event
Pass click on non-mutable radio doesn't fire the input event
Pass click on non-mutable radio doesn't fire the change event
Pass canceled activation steps on unchecked radio
Pass only one control of a radio button group can have its checkedness set to true
Pass radio inputs with non-ASCII name attributes belong to the same radio button group
Pass changing the name of a radio input element and setting its checkedness to true makes all the other elements' checkedness in the same radio button group be set to false
Pass moving radio input element out of or into a form should still work as expected
Fail Radio buttons in an orphan tree should make a group
Pass Radio buttons in different groups (because they have different form owners or no form owner) do not affect each other's checkedness
Pass Radio buttons in different groups (because they are not in the same tree) do not affect each other's checkedness
Pass Radio buttons in different groups (because they have different name attribute values, or no name attribute) do not affect each other's checkedness

View file

@ -0,0 +1,89 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>The constraint validation API Test: element.validity.rangeOverflow</title>
<link rel="author" title="Intel" href="http://www.intel.com/">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-validitystate-rangeoverflow">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-constraint-validation-api">
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="support/validator.js"></script>
<div id="log"></div>
<script>
var testElements = [
{
tag: "input",
types: ["datetime-local"],
testData: [
{conditions: {max: "", value: "2000-01-01T12:00:00"}, expected: false, name: "[target] The max attribute is not set"},
{conditions: {max: "2000-01-01T12:00:00", value: ""}, expected: false, name: "[target] Value is empty string"},
{conditions: {max: "2000-01-01 12:00:00", value: "2001-01-01T12:00:00"}, expected: false, name: "[target] The max attribute is an invalid local date time string"},
{conditions: {max: "2000-01-01T12:00:00", value: "2000-01-01T11:00:00"}, expected: false, name: "[target] The max attribute is greater than the value attribute"},
{conditions: {max: "2000-01-01T23:59:59", value: "2001-01-01T24:00:00"}, expected: false, name: "[target] The value is an invalid local date time string(hour is greater than 23)"},
{conditions: {max: "1970-01-01T12:00", value: "80-01-01T12:00"}, expected: false, name: "[target] The value if an invalid local date time string(year is two digits)"},
{conditions: {max: "2000-01-01T12:00:00", value: "2001-01-01T13:00:00"}, expected: true, name: "[target] The value is greater than max"},
{conditions: {max: "2000-01-01T12:00:00.1", value: "2000-01-01T12:00:00.2"}, expected: true, name: "[target] The value is greater than max(with millisecond in 1 digit)"},
{conditions: {max: "2000-01-01T12:00:00.01", value: "2000-01-01T12:00:00.02"}, expected: true, name: "[target] The value is greater than max(with millisecond in 2 digits)"},
{conditions: {max: "2000-01-01T12:00:00.001", value: "2000-01-01T12:00:00.002"}, expected: true, name: "[target] The value is greater than max(with millisecond in 3 digits)"},
{conditions: {max: "2000-01-01T12:00:00", value: "10000-01-01T12:00:00"}, expected: true, name: "[target] The value is greater than max(Year is 10000 should be valid)"},
]
},
{
tag: "input",
types: ["date"],
testData: [
{conditions: {max: "", value: "2000-01-01"}, expected: false, name: "[target] The max attribute is not set"},
{conditions: {max: "2000-01-01", value: ""}, expected: false, name: "[target] Value is empty string"},
{conditions: {max: "2000/01/01", value: "2002-01-01"}, expected: false, name: "[target] The max attribute is an invalid date"},
{conditions: {max: "2000-01-01", value: "2000-2-2"}, expected: false, name: "[target] The value attribute is an invalid date"},
{conditions: {max: "987-01-01", value: "988-01-01"}, expected: false, name: "[target] The value is an invalid date(year is three digits)"},
{conditions: {max: "2000-01-01", value: "2000-13-01"}, expected: false, name: "[target] The value is an invalid date(month is greater than 12)"},
{conditions: {max: "2000-01-01", value: "2000-02-30"}, expected: false, name: "[target] The value is an invalid date(date is greater than 29 for Feb)"},
{conditions: {max: "2000-12-01", value: "2000-01-01"}, expected: false, name: "[target] The max attribute is greater than value attribute"},
{conditions: {max: "2000-12-01", value: "2001-01-01"}, expected: true, name: "[target] The value attribute is greater than max attribute"},
{conditions: {max: "9999-01-01", value: "10000-01-01"}, expected: true, name: "[target] The value attribute is greater than max attribute(Year is 10000 should be valid)"}
]
},
{
tag: "input",
types: ["time"],
testData: [
{conditions: {max: "", value: "12:00:00"}, expected: false, name: "[target] The max attribute is not set"},
{conditions: {max: "12:00:00", value: ""}, expected: false, name: "[target] Value is empty string"},
{conditions: {max: "12.00.00", value: "12:00:01"}, expected: false, name: "[target] The max attribute is an invalid time string"},
{conditions: {max: "12:00:00", value: "12.00.01"}, expected: false, name: "[target] The value attribute is an invalid time string"},
{conditions: {max: "23:59:59", value: "24:00:00"}, expected: false, name: "[target] The value attribute is an invalid time string(hour is greater than 23)"},
{conditions: {max: "23:59:59", value: "23:60:00"}, expected: false, name: "[target] The value attribute is an invalid time string(minute is greater than 59)"},
{conditions: {max: "23:59:59", value: "23:59:60"}, expected: false, name: "[target] The value attribute is an invalid time string(second is greater than 59)"},
{conditions: {max: "13:00:00", value: "12:00:00"}, expected: false, name: "[target] The max attribute is greater than value attribute"},
{conditions: {max: "12:00:00", value: "13"}, expected: false, name: "[target] The time missing second and minute parts is invalid"},
{conditions: {max: "12:00:00", value: "12:00:02"}, expected: true, name: "[target] The value attribute is greater than max attribute"},
{conditions: {max: "12:00:00.1", value: "12:00:00.2"}, expected: true, name: "[target] The value is greater than max(with millisecond in 1 digit)"},
{conditions: {max: "12:00:00.01", value: "12:00:00.02"}, expected: true, name: "[target] The value is greater than max(with millisecond in 2 digit)"},
{conditions: {max: "12:00:00.001", value: "12:00:00.002"}, expected: true, name: "[target] The value is greater than max(with millisecond in 3 digit)"},
{conditions: {max: "12:00:00", value: "12:01"}, expected: true, name: "[target] The time missing second part is valid"},
{conditions: {max: "12:00:00", min: "14:00:00", value: "12:00:00"}, expected: false, name: "[target] The time is max for reversed range"},
{conditions: {max: "12:00:00", min: "14:00:00", value: "13:00:00"}, expected: true, name: "[target] The time is outside the accepted range for reversed range"},
{conditions: {max: "12:00:00", min: "14:00:00", value: "14:00:00"}, expected: false, name: "[target] The time is min for reversed range"},
{conditions: {max: "12:00:00", min: "14:00:00", value: "15:00:00"}, expected: false, name: "[target] The time is inside the accepted range for reversed range"},
]
},
{
tag: "input",
types: ["number"],
testData: [
{conditions: {max: "", value: "10"}, expected: false, name: "[target] The max attribute is not set"},
{conditions: {max: "5", value: ""}, expected: false, name: "[target] Value is empty string"},
{conditions: {max: "5", value: "4"}, expected: false, name: "[target] The max is greater than value(integer)"},
{conditions: {max: "-5.5", value: "-5.6"}, expected: false, name: "[target] The max is greater than value(floating number)"},
{conditions: {max: "-0", value: "0"}, expected: false, name: "[target] The max equals to value"},
{conditions: {max: "5", value: "1abc"}, expected: false, name: "[target] The value is not a number"},
{conditions: {max: "5", value: "6"}, expected: true, name: "[target] The value is greater than max(integer)"},
{conditions: {max: "-5.5", value: "-5.4"}, expected: true, name: "[target] The value is greater than max(floating number)"},
{conditions: {max: "-1", value: "-.8"}, expected: true, name: "[target] The value is greater than max(special floating number)"},
{conditions: {max: "-5e-1", value: "5e+2"}, expected: true, name: "[target] The value is greater than max(scientific notation)"},
]
}
];
validator.run_test(testElements, "rangeOverflow");
</script>

View file

@ -0,0 +1,87 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>The constraint validation API Test: element.validity.rangeUnderflow</title>
<link rel="author" title="Intel" href="http://www.intel.com/">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-validitystate-rangeunderflow">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-constraint-validation-api">
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="support/validator.js"></script>
<div id="log"></div>
<script>
var testElements = [
{
tag: "input",
types: ["datetime-local"],
testData: [
{conditions: {min: "", value: "2000-01-01T12:00:00"}, expected: false, name: "[target] The min attribute is not set"},
{conditions: {min: "2000-01-01T12:00:00", value: ""}, expected: false, name: "[target] Value is empty string"},
{conditions: {min: "2001-01-01 12:00:00", value: "2000-01-01T12:00:00"}, expected: false, name: "[target] The min attribute is an invalid local date time string"},
{conditions: {min: "2000-01-01T11:00:00", value: "2000-01-01T12:00:00"}, expected: false, name: "[target] The min attribute is less than the value attribute"},
{conditions: {min: "2001-01-01T23:59:59", value: "2000-01-01T24:00:00"}, expected: false, name: "[target] The value is an invalid local date time string(hour is greater than 23)"},
{conditions: {min: "1980-01-01T12:00", value: "79-01-01T12:00"}, expected: false, name: "[target] The value is an invalid local date time string(year is two digits)"},
{conditions: {min: "2000-01-01T13:00:00", value: "2000-01-01T12:00:00"}, expected: true, name: "[target] The value is less than min"},
{conditions: {min: "2000-01-01T12:00:00.2", value: "2000-01-01T12:00:00.1"}, expected: true, name: "[target] The value is less than min(with millisecond in 1 digit)"},
{conditions: {min: "2000-01-01T12:00:00.02", value: "2000-01-01T12:00:00.01"}, expected: true, name: "[target] The value is less than min(with millisecond in 2 digits)"},
{conditions: {min: "2000-01-01T12:00:00.002", value: "2000-01-01T12:00:00.001"}, expected: true, name: "[target] The value is less than min(with millisecond in 3 digits)"},
{conditions: {min: "10000-01-01T12:00:00", value: "2000-01-01T12:00:00"}, expected: true, name: "[target] The value is less than min(Year is 10000 should be valid)"},
{conditions: {max: "8593-01-01T02:09", value: "8592-01-01T02:09"}, expected: false, name: "[target] The value is greater than max"}
]
},
{
tag: "input",
types: ["date"],
testData: [
{conditions: {min: "", value: "2000-01-01"}, expected: false, name: "[target] The min attribute is not set"},
{conditions: {min: "2000-01-01", value: ""}, expected: false, name: "[target] Value is empty string"},
{conditions: {min: "2001/01/01", value: "2000-01-01"}, expected: false, name: "[target] The min attribute is an invalid date"},
{conditions: {min: "2000-02-02", value: "2000-1-1"}, expected: false, name: "[target] The value attribute is an invalid date"},
{conditions: {min: "988-01-01", value: "987-01-01"}, expected: false, name: "[target] The value is an invalid date(year is three digits)"},
{conditions: {min: "2001-01-01", value: "2000-13-01"}, expected: false, name: "[target] The value is an invalid date(month is less than 12)"},
{conditions: {min: "2001-01-01", value: "2000-02-30"}, expected: false, name: "[target] The value is an invalid date(date is less than 29 for Feb)"},
{conditions: {min: "2000-01-01", value: "2000-12-01"}, expected: false, name: "[target] The min attribute is less than value attribute"},
{conditions: {min: "2000-12-01", value: "2000-01-01"}, expected: true, name: "[target] The value attribute is less than min attribute"},
{conditions: {min: "10000-01-01", value: "9999-01-01"}, expected: true, name: "[target] The value attribute is less than min attribute(Year is 10000 should be valid)"}
]
},
{
tag: "input",
types: ["time"],
testData: [
{conditions: {min: "", value: "12:00:00"}, expected: false, name: "[target] The min attribute is not set"},
{conditions: {min: "12:00:00", value: ""}, expected: false, name: "[target] Value is empty string"},
{conditions: {min: "12.00.01", value: "12:00:00"}, expected: false, name: "[target] The min attribute is an invalid time string"},
{conditions: {min: "12:00:01", value: "12.00.00"}, expected: false, name: "[target] The value attribute is an invalid time string"},
{conditions: {min: "12:00:00", value: "13:00:00"}, expected: false, name: "[target] The min attribute is less than value attribute"},
{conditions: {min: "13:00:00", value: "12"}, expected: false, name: "[target] The time missing second and minute parts is invalid"},
{conditions: {min: "12:00:02", value: "12:00:00"}, expected: true, name: "[target] The value attribute is less than min attribute"},
{conditions: {min: "12:00:00.2", value: "12:00:00.1"}, expected: true, name: "[target] The value is less than min(with millisecond in 1 digit)"},
{conditions: {min: "12:00:00.02", value: "12:00:00.01"}, expected: true, name: "[target] The value is less than min(with millisecond in 2 digit)"},
{conditions: {min: "12:00:00.002", value: "12:00:00.001"}, expected: true, name: "[target] The value is less than min(with millisecond in 3 digit)"},
{conditions: {min: "12:00:00", value: "11:59"}, expected: true, name: "[target] The time missing second part is valid"},
{conditions: {min: "14:00:00", max: "12:00:00", value: "12:00:00"}, expected: false, name: "[target] The time is max for reversed range"},
{conditions: {min: "14:00:00", max: "12:00:00", value: "13:00:00"}, expected: true, name: "[target] The time is outside the accepted range for reversed range"},
{conditions: {min: "14:00:00", max: "12:00:00", value: "14:00:00"}, expected: false, name: "[target] The time is min for reversed range"},
{conditions: {min: "14:00:00", max: "12:00:00", value: "15:00:00"}, expected: false, name: "[target] The time is inside the accepted range for reversed range"},
]
},
{
tag: "input",
types: ["number"],
testData: [
{conditions: {min: "", value: "10"}, expected: false, name: "[target] The min attribute is not set"},
{conditions: {min: "5", value: ""}, expected: false, name: "[target] Value is empty string"},
{conditions: {min: "4", value: "5"}, expected: false, name: "[target] The min is less than value(integer)"},
{conditions: {min: "-5.6", value: "-5.5"}, expected: false, name: "[target] The min is less than value(floating number)"},
{conditions: {min: "0", value: "-0"}, expected: false, name: "[target] The min equals to value"},
{conditions: {min: "5", value: "6abc"}, expected: false, name: "[target] The value is not a number"},
{conditions: {min: "6", value: "5"}, expected: true, name: "[target] The value is less than min(integer)"},
{conditions: {min: "-5.4", value: "-5.5"}, expected: true, name: "[target] The value is less than min(floating number)"},
{conditions: {min: "1", value: "-.8"}, expected: true, name: "[target] The value is less than min(special floating number)"},
{conditions: {min: "5e+2", value: "-5e-1"}, expected: true, name: "[target] The value is less than min(scientific notation)"}
]
}
];
validator.run_test(testElements, "rangeUnderflow");
</script>

View file

@ -0,0 +1,50 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>The constraint validation API Test: element.validity.tooLong</title>
<link rel="author" title="Intel" href="http://www.intel.com/">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-validitystate-toolong">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-constraint-validation-api">
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="support/validator.js"></script>
<div id="log"></div>
<script>
var testElements = [
{
tag: "input",
types: ["text", "search", "tel", "url", "email", "password"],
testData: [ // Non-dirty value
{conditions: {maxLength: "", value: "abc"}, expected: false, name: "[target] Non-dirty value - maxlength is not set"},
{conditions: {maxLength: "4", value: ""}, expected: false, name: "[target] Non-dirty value - value is empty string"},
{conditions: {maxLength: "4", value: "abc"}, expected: false, name: "[target] Non-dirty value - length of value is less than maxlength"},
{conditions: {maxLength: "4", value: "abcd"}, expected: false, name: "[target] Non-dirty value - length of value equals to maxlength"},
{conditions: {maxLength: "4", value: "abcde"}, expected: false, name: "[target] Non-dirty value - length of value is greater than maxlength"},
//Dirty value
{conditions: {maxLength: "4", value: "abc"}, expected: false, name: "[target] Dirty value - value is less than maxlength", dirty: true},
{conditions: {maxLength: "4", value: "\u0041\u0041\u0041"}, expected: false, name: "[target] Dirty value - length of value(AAA) in unicode is less than maxlength", dirty: true},
{conditions: {maxLength: "4", value: "abcd"}, expected: false, name: "[target] Dirty value - value equals to maxlength", dirty: true},
// False due to lack of required interactive editing by the user
{conditions: {maxLength: "4", value: "abcde"}, expected: false, name: "[target] Dirty value - length of value is greater than maxlength", dirty: true}
]
},
{
tag: "textarea",
types: [],
testData: [
{conditions: {maxLength: "", value: "abc"}, expected: false, name: "[target] Non-dirty value - maxlength is not set"},
{conditions: {maxLength: "4", value: ""}, expected: false, name: "[target] Non-dirty value - value is empty string"},
{conditions: {maxLength: "4", value: "abc"}, expected: false, name: "[target] Non-dirty value - length of value is less than maxlength"},
{conditions: {maxLength: "4", value: "abcd"}, expected: false, name: "[target] Non-dirty value - length of value equals to maxlength"},
{conditions: {maxLength: "4", value: "abcde"}, expected: false, name: "[target] Non-dirty value - length of value is greater than maxlength"},
//Dirty value
{conditions: {maxLength: "4", value: "abc"}, expected: false, name: "[target] Dirty value - value is less than maxlength", dirty: true},
{conditions: {maxLength: "4", value: "\u000D\u000A"}, expected: false, name: "[target] Dirty value - length of value(LF, CRLF) in unicode is less than maxlength", dirty: true},
{conditions: {maxLength: "4", value: "abcd"}, expected: false, name: "[target] Dirty value - length of value equals to maxlength", dirty: true},
// False due to lack of required interactive editing by the user
{conditions: {maxLength: "4", value: "abcde"}, expected: false, name: "[target] Dirty value - length of value is greater than maxlength", dirty: true}
]
}
];
validator.run_test (testElements, "tooLong");
</script>

View file

@ -0,0 +1,52 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>The constraint validation API Test: element.validity.tooShort</title>
<link rel="author" title="Intel" href="http://www.intel.com/">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#suffering-from-being-too-short">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-constraint-validation-api">
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="support/validator.js"></script>
<div id="log"></div>
<script>
var testElements = [
{
tag: "input",
types: ["text", "search", "tel", "url", "email", "password"],
testData: [
// Non-dirty value
{conditions: {minLength: "", value: "abc"}, expected: false, name: "[target] Non-dirty value - minLength is not set"},
{conditions: {minLength: "4", value: ""}, expected: false, name: "[target] Non-dirty value - value is empty string"},
{conditions: {minLength: "4", value: "abcde"}, expected: false, name: "[target] Non-dirty value - length of value is greater than minLength"},
{conditions: {minLength: "4", value: "abcd"}, expected: false, name: "[target] Non-dirty value - length of value equals to minLength"},
{conditions: {minLength: "4", value: "abc"}, expected: false, name: "[target] Non-dirty value - length of value is less than minLength"},
//Dirty value
{conditions: {minLength: "4", value: "abcde"}, expected: false, name: "[target] Dirty value - value is greater than minLength", dirty: true},
{conditions: {minLength: "4", value: "\u0041\u0041\u0041\u0041\u0041"}, expected: false, name: "[target] Dirty value - length of value(AAAAA) in unicode is greater than minLength", dirty: true},
{conditions: {minLength: "4", value: "abcd"}, expected: false, name: "[target] Dirty value - value equals to minLength", dirty: true},
// False due to lack of required interactive editing by the user
{conditions: {minLength: "4", value: "abc"}, expected: false, name: "[target] Dirty value - length of value is less than minLength", dirty: true}
]
},
{
tag: "textarea",
types: [],
testData: [
// Non-dirty value
{conditions: {minLength: "", value: "abc"}, expected: false, name: "[target] Non-dirty value - minLength is no set"},
{conditions: {minLength: "4", value: ""}, expected: false, name: "[target] Non-dirty value - value is empty string"},
{conditions: {minLength: "4", value: "abcde"}, expected: false, name: "[target] Non-dirty value - length of value is greater than minLength"},
{conditions: {minLength: "4", value: "abcd"}, expected: false, name: "[target] Non-dirty value - length of value equals to minLength"},
{conditions: {minLength: "4", value: "abc"}, expected: false, name: "[target] Non-dirty value - length of length of value is greater than minLength"},
//Dirty value
{conditions: {minLength: "4", value: "abcde"}, expected: false, name: "[target] Dirty value - value is less than minLength", dirty: true},
{conditions: {minLength: "4", value: "\u000D\u000A\u000D\u000A\u000D\u000A"}, expected: false, name: "[target] Dirty value - length of value(LF, CRLF) in unicode is less than minLength", dirty: true},
{conditions: {minLength: "4", value: "abcd"}, expected: false, name: "[target] Dirty value - length of value equals to minLength", dirty: true},
// False due to lack of required interactive editing by the user
{conditions: {minLength: "4", value: "abc"}, expected: false, name: "[target] Dirty value - length of value is greater than minLength", dirty: true}
]
}
];
validator.run_test (testElements, "tooShort");
</script>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>The constraint validation API Test: element.validity.typeMismatch</title>
<link rel="author" title="Intel" href="http://www.intel.com/">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-validitystate-typemismatch">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-constraint-validation-api">
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="support/validator.js"></script>
<div id="log"></div>
<script>
var testElements = [
{
tag: "input",
types: ["email"],
testData: [
// multiple is false
{conditions: {multiple: false, value: ""}, expected: false, name: "[target] The value is empty"},
{conditions: {multiple: false, value: "test@example.com"}, expected: false, name: "[target] The value is a valid email address"},
{conditions: {multiple: false, value: "\u000A\u000D\u0020\u0009 test@example.com \u000A\u000D\u0020\u0009"}, expected: false, name: "[target] The value is a valid email address with some white spaces."},
{conditions: {multiple: false, value: "abc"}, expected: true, name: "[target] The value is not an email address"},
{conditions: {multiple: false, value: "test1@example.com,test2@example.com"}, expected: true, name: "[target] The value contains multiple email addresses"},
//multiple is true
{conditions: {multiple: true, value: "test1@example.com,test2@example.com"}, expected: false, name: "[target] The value is valid email addresses"},
{conditions: {multiple: true, value: "test1@example.com;test2@example.com"}, expected: true, name: "[target] The value contains invalid separator"}
]
},
{
tag: "input",
types: ["url"],
testData: [
{conditions: {multiple: false, value: ""}, expected: false, name: "[target] The value is empty"},
{conditions: {multiple: false, value: "http://www.example.com"}, expected: false, name: "[target] The value is a valid url"},
{conditions: {multiple: false, value: "\u000A\u000D\u0020\u0009 http://www.example.com \u000A\u000D\u0020\u0009 "}, expected: false, name: "[target] The value is a valid url with some white spaces."},
{conditions: {multiple: false, value: "abc"}, expected: true, name: "[target] The value is not an url"}
]
}
];
validator.run_test(testElements, "typeMismatch");
</script>

View file

@ -0,0 +1,147 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>The constraint validation API Test: element.validity.valueMissing</title>
<link rel="author" title="Intel" href="http://www.intel.com/">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-validitystate-valuemissing">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-constraint-validation-api">
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="support/validator.js"></script>
<div id="log"></div>
<form>
<input id="messagetest" type="checkbox" required="" disabled="">
</form>
<script>
var testElements = [
{
tag: "input",
types: ["text", "search", "tel", "url", "email", "password"],
testData: [
{conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
{conditions: {required: true, value: "abc"}, expected: false, name: "[target] The value is not empty and required is true"},
{conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value is empty and required is true"}
]
},
{
tag: "input",
types: ["datetime-local"],
testData: [
{conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
{conditions: {required: true, value: "2000-12-10T12:00:00"}, expected: false, name: "[target] Valid local date and time string(2000-12-10T12:00:00)"},
{conditions: {required: true, value: "2000-12-10 12:00"}, expected: false, name: "[target] Valid local date and time string(2000-12-10 12:00)"},
{conditions: {required: true, value: "1979-10-14T12:00:00.001"}, expected: false, name: "[target] Valid local date and time string(1979-10-14T12:00:00.001)"},
{conditions: {required: true, value: 1234567}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a number(1234567)"},
{conditions: {required: true, value: new Date()}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a Date object"},
{conditions: {required: true, value: "1979-10-99 99:99"}, expected: true, expectedImmutable: false, name: "[target] Invalid local date and time string(1979-10-99 99:99)"},
{conditions: {required: true, value: "1979-10-14 12:00:00"}, expected: false, name: "[target] Valid local date and time string(1979-10-14 12:00:00)"},
{conditions: {required: true, value: "2001-12-21 12:00"}, expected: true, expectedImmutable: false, name: "[target] Invalid local date and time string(2001-12-21 12:00)-two white space"},
{conditions: {required: true, value: "abc"}, expected: true, expectedImmutable: false, name: "[target] the value attribute is a string(abc)"},
{conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value attribute is empty string"}
]
},
{
tag: "input",
types: ["date"],
testData: [
{conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
{conditions: {required: true, value: "2000-12-10"}, expected: false, name: "[target] Valid date string(2000-12-10)"},
{conditions: {required: true, value: "9999-01-01"}, expected: false, name: "[target] Valid date string(9999-01-01)"},
{conditions: {required: true, value: 1234567}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a number(1234567)"},
{conditions: {required: true, value: new Date()}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a Date object"},
{conditions: {required: true, value: "9999-99-99"}, expected: true, expectedImmutable: false, name: "[target] Invalid date string(9999-99-99)"},
{conditions: {required: true, value: "37/01/01"}, expected: true, expectedImmutable: false, name: "[target] Invalid date string(37-01-01)"},
{conditions: {required: true, value: "2000/01/01"}, expected: true, expectedImmutable: false, name: "[target] Invalid date string(2000/01/01)"},
{conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value attribute is empty string"}
]
},
{
tag: "input",
types: ["time"],
testData: [
{conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
{conditions: {required: true, value: "12:00:00"}, expected: false, name: "[target] Validtime string(12:00:00)"},
{conditions: {required: true, value: "12:00"}, expected: false, name: "[target] Validtime string(12:00)"},
{conditions: {required: true, value: "12:00:00.001"}, expected: false, name: "[target] Valid time string(12:00:60.001)"},
{conditions: {required: true, value: "12:00:00.01"}, expected: false, name: "[target] Valid time string(12:00:60.01)"},
{conditions: {required: true, value: "12:00:00.1"}, expected: false, name: "[target] Valid time string(12:00:60.1)"},
{conditions: {required: true, value: 1234567}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a number(1234567)"},
{conditions: {required: true, value: new Date()}, expected: true, expectedImmutable: false, name: "[target] The value attribute is a time object"},
{conditions: {required: true, value: "25:00:00"}, expected: true, expectedImmutable: false, name: "[target] Invalid time string(25:00:00)"},
{conditions: {required: true, value: "12:60:00"}, expected: true, expectedImmutable: false, name: "[target] Invalid time string(12:60:00)"},
{conditions: {required: true, value: "12:00:60"}, expected: true, expectedImmutable: false, name: "[target] Invalid time string(12:00:60)"},
{conditions: {required: true, value: "12:00:00:001"}, expected: true, expectedImmutable: false, name: "[target] Invalid time string(12:00:00:001)"},
{conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value attribute is empty string"}
]
},
{
tag: "input",
types: ["number"],
testData: [
{conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
{conditions: {required: true, value: "123"}, expected: false, name: "[target] Value is an integer with a leading symbol '+'"},
{conditions: {required: true, value: "-123.45"}, expected: false, name: "[target] Value is a number with a '-' symbol"},
{conditions: {required: true, value: "123.01e-10"}, expected: false, name: "[target] Value is a number in scientific notation form(e is in lowercase)"},
{conditions: {required: true, value: "123.01E+10"}, expected: false, name: "[target] Value is a number in scientific notation form(E is in uppercase)"},
{conditions: {required: true, value: "-0"}, expected: false, name: "[target] Value is -0"},
{conditions: {required: true, value: " 123 "}, expected: true, expectedImmutable: false, name: "[target] Value is a number with some white spaces"},
{conditions: {required: true, value: Math.pow(2, 1024)}, expected: true, expectedImmutable: false, name: "[target] Value is Math.pow(2, 1024)"},
{conditions: {required: true, value: Math.pow(-2, 1024)}, expected: true, expectedImmutable: false, name: "[target] Value is Math.pow(-2, 1024)"},
{conditions: {required: true, value: "abc"}, expected: true, expectedImmutable: false, name: "[target] Value is a string that cannot be converted to a number"},
{conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value attribute is empty string"}
]
},
{
tag: "input",
types: ["checkbox"],
testData: [
{conditions: {required: false, checked: false, name: "test1"}, expected: false, name: "[target] The required attribute is not set"},
{conditions: {required: true, checked: true, name: "test2"}, expected: false, name: "[target] The checked attribute is true"},
{conditions: {required: true, checked: false, name: "test3"}, expected: true, name: "[target] The checked attribute is false"}
]
},
{
tag: "input",
types: ["radio"],
testData: [
{conditions: {required: false, checked: false, name: "test4"}, expected: false, name: "[target] The required attribute is not set"},
{conditions: {required: true, checked: true, name: "test5"}, expected: false, name: "[target] The checked attribute is true"},
{conditions: {required: true, checked: false, name: "test6"}, expected: true, name: "[target] The checked attribute is false"},
{conditions: {required: true, checked: false, name: ""}, expected: false, name: "[target] The checked attribute is false and the name attribute is empty"}
]
},
{
tag: "input",
types: ["file"],
testData: [
{conditions: {required: false, files: null}, expected: false, name: "[target] The required attribute is not set"},
{conditions: {required: true, files: null}, expected: true, name: "[target] The Files attribute is null"}
//ToDo: Add a case to test the files is not null
]
},
{
tag: "select",
types: [],
testData: [
{conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
{conditions: {required: true, value: 1}, expected: false, name: "[target] Selected the option with value equals to 1"},
{conditions: {required: true, value: ""}, expected: true, name: "[target] Selected the option with value equals to empty"}
]
},
{
tag: "textarea",
types: [],
testData: [
{conditions: {required: false, value: ""}, expected: false, name: "[target] The required attribute is not set"},
{conditions: {required: true, value: "abc"}, expected: false, name: "[target] The value is not empty"},
{conditions: {required: true, value: ""}, expected: true, expectedImmutable: false, name: "[target] The value is empty"}
]
}
];
validator.run_test(testElements, "valueMissing");
test(() => {
assert_equals(document.getElementById("messagetest").validationMessage, '');
}, 'validationMessage should return empty string when willValidate is false and valueMissing is true');
</script>

View file

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<title>valueMissing property on the input[type=radio] element</title>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<meta content="valueMissing property on the input[type=radio] element" name="description">
<link href="https://html.spec.whatwg.org/multipage/#dom-validitystate-valuemissing" rel="help">
<link href="https://html.spec.whatwg.org/multipage/#radio-button-state-(type%3Dradio)%3Asuffering-from-being-missing" rel="help">
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<form style="display: none">
<input type="radio" name="group1" id="radio1">
<input type="radio" name="group1" id="radio2">
<input type="radio" name="group2" required id="radio3">
<input type="radio" name="group2" id="radio4">
<input type="radio" name="group3" required checked id="radio5">
<input type="radio" name="group3" id="radio6">
<input type="radio" name="group4" required id="radio7">
<input type="radio" name="group4" checked id="radio8">
<input type="radio" name="group4" id="radio9">
<input type="radio" name="group5" required disabled id="radio10">
<input type="radio" name="group5" id="radio11">
<input type="radio" name="group6" required checked disabled id="radio12">
<input type="radio" name="group6" id="radio13">
</form>
<script type="text/javascript">
var cases = [
{
name: "The required attribute is not set",
group: ["radio1", "radio2"],
expected: false
},
{
name: "One of the radios is required, but none checked",
group: ["radio3", "radio4"],
expected: true
},
{
name: "One of the radios is required and checked",
group: ["radio5", "radio6"],
expected: false
},
{
name: "One of the radios is required and another one is checked",
group: ["radio7", "radio8", "radio9"],
expected: false
},
{
name: "One of the radios is required and disabled, but none checked",
group: ["radio10", "radio11"],
expected: true
},
{
name: "One of the radios is required, checked and disabled",
group: ["radio12", "radio13"],
expected: false
}
];
for (var info of cases) {
test(function () {
for (var id of info.group) {
var radio = document.getElementById(id);
assert_class_string(radio.validity, "ValidityState",
"HTMLInputElement.validity must be a ValidityState instance");
if (info.expected) {
assert_true(radio.validity.valueMissing,
"The " + id + ".validity.valueMissing should be true");
} else {
assert_false(radio.validity.valueMissing,
"The " + id + ".validity.valueMissing should be false");
}
}
}, info.name);
}
</script>
</body>
</html>

View file

@ -0,0 +1,481 @@
var validator = {
test_tooLong: function(ctl, data) {
var self = this;
test(function() {
self.pre_check(ctl, 'tooLong');
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected)
assert_true(
ctl.validity.tooLong,
'The validity.tooLong should be true' + condStr);
else
assert_false(
ctl.validity.tooLong,
'The validity.tooLong should be false' + condStr);
});
}, data.name);
},
test_tooShort: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "tooShort");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected)
assert_true(
ctl.validity.tooShort,
'The validity.tooShort should be true' + condStr);
else
assert_false(
ctl.validity.tooShort,
'The validity.tooShort should be false' + condStr);
});
}, data.name);
},
test_patternMismatch: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "patternMismatch");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected)
assert_true(
ctl.validity.patternMismatch,
'The validity.patternMismatch should be true' + condStr);
else
assert_false(
ctl.validity.patternMismatch,
'The validity.patternMismatch should be false' + condStr);
});
}, data.name);
},
test_valueMissing: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "valueMissing");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected)
assert_true(
ctl.validity.valueMissing,
'The validity.valueMissing should be true' + condStr);
else
assert_false(
ctl.validity.valueMissing,
'The validity.valueMissing should be false' + condStr);
});
}, data.name);
},
test_typeMismatch: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "typeMismatch");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected)
assert_true(
ctl.validity.typeMismatch,
'The validity.typeMismatch should be true' + condStr);
else
assert_false(
ctl.validity.typeMismatch,
'The validity.typeMismatch should be false' + condStr);
});
}, data.name);
},
test_rangeOverflow: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "rangeOverflow");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected)
assert_true(
ctl.validity.rangeOverflow,
'The validity.rangeOverflow should be true' + condStr);
else
assert_false(
ctl.validity.rangeOverflow,
'The validity.rangeOverflow should be false' + condStr);
});
}, data.name);
},
test_rangeUnderflow: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "rangeUnderflow");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected)
assert_true(
ctl.validity.rangeUnderflow,
'The validity.rangeUnderflow should be true' + condStr);
else
assert_false(
ctl.validity.rangeUnderflow,
'The validity.rangeUnderflow should be false' + condStr);
});
}, data.name);
},
test_stepMismatch: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "stepMismatch");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected)
assert_true(
ctl.validity.stepMismatch,
'The validity.stepMismatch should be true' + condStr);
else
assert_false(
ctl.validity.stepMismatch,
'The validity.stepMismatch should be false' + condStr);
});
}, data.name);
},
test_badInput: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "badInput");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected)
assert_true(
ctl.validity.badInput,
'The validity.badInput should be true' + condStr);
else
assert_false(
ctl.validity.badInput,
'The validity.badInput should be false' + condStr);
});
}, data.name);
},
test_customError: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "customError");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected) {
assert_true(
ctl.validity.customError,
'The validity.customError attribute should be true' + condStr);
// validationMessage returns the empty string if ctl is barred from
// constraint validation, which happens if ctl is disabled or readOnly.
if (ctl.disabled || ctl.readOnly) {
assert_equals(
ctl.validationMessage, '',
'The validationMessage attribute must be empty' + condStr);
} else {
assert_equals(
ctl.validationMessage, data.conditions.message,
'The validationMessage attribute should be \'' +
data.conditions.message + '\'' + condStr);
}
} else {
assert_false(
ctl.validity.customError,
'The validity.customError attribute should be false' + condStr);
assert_equals(
ctl.validationMessage, '',
'The validationMessage attribute must be empty' + condStr);
}
});
}, data.name);
},
test_isValid: function(ctl, data) {
var self = this;
test(function () {
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, expected, condStr} = val;
if (expected)
assert_true(
ctl.validity.valid,
'The validity.valid should be true' + condStr);
else
assert_false(
ctl.validity.valid,
'The validity.valid should be false' + condStr);
});
}, data.name);
},
test_willValidate: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "willValidate");
self.set_conditions(ctl, data.conditions);
if (data.ancestor) {
var dl = document.createElement("datalist");
dl.appendChild(ctl);
}
if (data.expected)
assert_true(ctl.willValidate, "The willValidate attribute should be true.");
else
assert_false(ctl.willValidate, "The willValidate attribute should be false.");
}, data.name);
},
test_checkValidity: function(ctl, data) {
var self = this;
test(function () {
var eventFired = false;
self.pre_check(ctl, "checkValidity");
self.set_conditions(ctl, data.conditions);
if (data.dirty)
self.set_dirty(ctl);
on_event(ctl, "invalid", function(e){
assert_equals(e.type, "invalid", "The invalid event should be fired.");
eventFired = true;
});
if (data.expected) {
assert_true(ctl.checkValidity(), "The checkValidity method should be true.");
assert_false(eventFired, "The invalid event should not be fired.");
} else {
assert_false(ctl.checkValidity(), "The checkValidity method should be false.");
assert_true(eventFired, "The invalid event should be fired.");
}
}, data.name);
test(function () {
var fm = document.createElement("form");
var ctl2 = ctl.cloneNode(true);
self.pre_check(ctl, "checkValidity");
self.set_conditions(ctl2, data.conditions);
fm.appendChild(ctl2);
document.body.appendChild(fm);
if (data.dirty)
self.set_dirty(ctl2);
var result = fm.checkValidity();
document.body.removeChild(fm);
if (data.expected)
assert_true(result, "The checkValidity method of the element's form owner should return true.");
else
assert_false(result, "The checkValidity method of the element's form owner should return false.");
}, data.name + " (in a form)");
},
test_reportValidity: function(ctl, data) {
var self = this;
test(function () {
var eventFired = false;
self.pre_check(ctl, "reportValidity");
self.set_conditions(ctl, data.conditions);
if (data.dirty)
self.set_dirty(ctl);
on_event(ctl, "invalid", function(e){
assert_equals(e.type, "invalid", "The invalid event should be fired.");
eventFired = true;
});
if (data.expected) {
assert_true(ctl.reportValidity(), "The reportValidity method should be true.");
assert_false(eventFired, "The invalid event should not be fired.");
} else {
assert_false(ctl.reportValidity(), "The reportValidity method should be false.");
assert_true(eventFired, "The invalid event should be fired.");
}
}, data.name);
test(function () {
var fm = document.createElement("form");
var ctl2 = ctl.cloneNode(true);
self.pre_check(ctl, "reportValidity");
self.set_conditions(ctl2, data.conditions);
fm.appendChild(ctl2);
document.body.appendChild(fm);
if (data.dirty)
self.set_dirty(ctl2);
var result = fm.reportValidity();
document.body.removeChild(fm);
if (data.expected)
assert_true(result, "The reportValidity method of the element's form owner should return true.");
else
assert_false(result, "The reportValidity method of the element's form owner should return false.");
}, data.name + " (in a form)");
},
set_conditions: function(ctl, obj) {
[
"checked",
"disabled",
"max",
"maxlength",
"min",
"minlength",
"multiple",
"pattern",
"readonly",
"required",
"selected",
"step",
"value"
].forEach(function(item) {
ctl.removeAttribute(item);
});
for (var attr in obj) {
if (attr === "message")
ctl.setCustomValidity(obj[attr]);
else if (attr === "checked" || obj[attr] || obj[attr] === "")
ctl[attr] = obj[attr];
}
},
set_dirty: function(ctl) {
ctl.focus();
var old_value = ctl.value;
ctl.value = "a";
ctl.value = old_value;
},
pre_check: function(ctl, item) {
switch (item) {
case "willValidate":
assert_true(item in ctl, "The " + item + " attribute doesn't exist.");
break;
case "checkValidity":
case "reportValidity":
assert_true(item in ctl, "The " + item + " method doesn't exist.");
break;
case "tooLong":
case "tooShort":
case "patternMismatch":
case "typeMismatch":
case "stepMismatch":
case "rangeOverflow":
case "rangeUnderflow":
case "valueMissing":
case "badInput":
case "valid":
assert_true("validity" in ctl, "The validity attribute doesn't exist.");
assert_true(item in ctl.validity, "The " + item + " attribute doesn't exist.");
break;
case "customError":
assert_true("validity" in ctl, "The validity attribute doesn't exist.");
assert_true("setCustomValidity" in ctl, "The validity attribute doesn't exist.");
assert_true("validationMessage" in ctl, "The validity attribute doesn't exist.");
assert_true(item in ctl.validity, "The " + item + " attribute doesn't exist.");
break;
}
},
iterate_over: function(ctl, data) {
// Iterate over normal, disabled, readonly, and both (if applicable).
var ctlNormal = ctl.cloneNode(true);
this.set_conditions(ctlNormal, data.conditions);
if (data.dirty)
this.set_dirty(ctlNormal);
var ctlDisabled = ctl.cloneNode(true);
this.set_conditions(ctlDisabled, data.conditions);
if (data.dirty)
this.set_dirty(ctlDisabled);
ctlDisabled.disabled = true;
var expectedImmutable =
data.expectedImmutable !== undefined ? data.expectedImmutable : data.expected;
var variants = [
{ctl: ctlNormal, expected: data.expected, condStr: '.'},
{ctl: ctlDisabled, expected: expectedImmutable, condStr: ', when control is disabled.'},
];
if ('readOnly' in ctl) {
var ctlReadonly = ctl.cloneNode(true);
this.set_conditions(ctlReadonly, data.conditions);
if (data.dirty)
this.set_dirty(ctlReadonly);
ctlReadonly.readOnly = true;
var ctlBoth = ctl.cloneNode(true);
this.set_conditions(ctlBoth, data.conditions);
if (data.dirty)
this.set_dirty(ctlBoth);
ctlBoth.disabled = true;
ctlBoth.readOnly = true;
variants.push({
ctl: ctlReadonly,
expected: expectedImmutable,
condStr: ', when control is readonly.'
});
variants.push({
ctl: ctlBoth,
expected: expectedImmutable,
condStr: ', when control is disabled & readonly.'
});
}
return variants;
},
run_test: function(testee, method) {
var testMethod = "test_" + method;
if (typeof this[testMethod] !== "function") {
return false;
}
var ele = null,
prefix = "";
for (var i = 0; i < testee.length; i++) {
if (testee[i].types.length > 0) {
for (var typ in testee[i].types) {
ele = document.createElement(testee[i].tag);
document.body.appendChild(ele);
try {
ele.type = testee[i].types[typ];
} catch (e) {
//Do nothing, avoid the runtime error breaking the test
}
prefix = "[" + testee[i].tag.toUpperCase() + " in " + testee[i].types[typ].toUpperCase() + " status] ";
for (var j = 0; j < testee[i].testData.length; j++) {
testee[i].testData[j].name = testee[i].testData[j].name.replace(/\[.*\]\s/g, prefix);
this[testMethod](ele, testee[i].testData[j]);
}
}
} else {
ele = document.createElement(testee[i].tag);
document.body.appendChild(ele);
prefix = "[" + testee[i].tag + "] ";
if (testElements[i].tag === "select") {
ele.add(new Option('test1', '')); // Placeholder
ele.add(new Option("test2", 1));
}
for (var item in testee[i].testData) {
testee[i].testData[item].name = testee[i].testData[item].name.replace("[target]", prefix);
this[testMethod](ele, testee[i].testData[item]);
}
}
}
}
}

View file

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Forms</title>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
</head>
<body>
<p>
<h3>button_validity</h3>
</p>
<hr>
<div id="log"></div>
<form method="post"
enctype="application/x-www-form-urlencoded"
action=""
id="input_form">
<p><button id='button_id'>button</button></p>
</form>
<script>
var button = document.getElementById("button_id");
if (typeof(button.validity) == "object") {
test(function() {
assert_equals(button.validity.valueMissing, false, "validity attribute is not correct.");
});
} else {
test(function() {
assert_unreached("validity attribute is not exist.");
});
}
</script>
</body>
</html>

View file

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Forms</title>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
</head>
<body>
<p>
<h3>input_validity</h3>
</p>
<hr>
<div id="log"></div>
<form method="post"
enctype="application/x-www-form-urlencoded"
action=""
id="input_form">
<p><input type='hidden' id='input_text'></p>
</form>
<script>
var input = document.getElementById("input_text");
if (typeof(input.validity) == "object") {
test(function() {
assert_equals(input.validity.valueMissing, false, "validity attribute is not correct.");
});
} else {
test(function() {
assert_unreached("validity attribute is not exist.");
});
}
</script>
</body>
</html>

View file

@ -0,0 +1,351 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>input type radio</title>
<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
<link rel=help href="https://html.spec.whatwg.org/multipage/#radio-button-state-(type=radio)">
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<div id="log"></div>
<input type=radio name=group1 id=radio1>
<input type=radio name=group1 id=radio2>
<input type=radio name=groüp2 id=radio3>
<input type=radio name=groüp2 id=radio4>
<input type=radio id=radio5>
<input type=radio id=radio6 disabled>
<input type=radio name="group5" id=radio71 checked>
<input type=radio name="group5" id=radio72>
<input type=radio name=group3 id=radio8 checked>
<input type=radio name=group3 id=radio9>
<input type=radio name=group4 id=radio10>
<input type=radio name=group4 id=radio11 checked>
<form id="testform"></form>
<input type=radio form=testform name=group6 id=radio12 checked>
<input type=radio form=testform name=group6 id=radio13>
<input type=radio form=testform name=group6 id=radio14>
<script>
var radio1 = document.getElementById('radio1'),
radio2 = document.getElementById('radio2'),
radio3 = document.getElementById('radio3'),
radio4 = document.getElementById('radio4'),
radio5 = document.getElementById('radio5'),
radio6 = document.getElementById('radio6'),
radio71 = document.getElementById('radio71'),
radio72 = document.getElementById('radio72'),
radio8 = document.getElementById('radio8'),
radio9 = document.getElementById('radio9'),
radio10 = document.getElementById('radio10'),
radio11 = document.getElementById('radio11'),
radio12 = document.getElementById('radio12'),
radio13 = document.getElementById('radio13'),
radio14 = document.getElementById('radio14'),
testform = document.getElementById('testform'),
t1 = async_test("click on mutable radio fires click event, then input event, then change event"),
t3 = async_test("click on non-mutable radio doesn't fire the input event"),
t4 = async_test("click on non-mutable radio doesn't fire the change event"),
t5 = async_test("canceled activation steps on unchecked radio"),
input_fired = false,
change_fired = false;
test(function(){
assert_false(radio1.checked);
assert_false(radio2.checked);
radio1.checked = true;
assert_true(radio1.checked);
assert_false(radio2.checked);
radio2.checked = true;
assert_false(radio1.checked);
assert_true(radio2.checked);
}, "only one control of a radio button group can have its checkedness set to true");
test(function(){
assert_false(radio3.checked);
assert_false(radio4.checked);
radio3.checked = true;
assert_true(radio3.checked);
assert_false(radio4.checked);
radio4.checked = true;
assert_false(radio3.checked);
assert_true(radio4.checked);
}, "radio inputs with non-ASCII name attributes belong to the same radio button group");
test(function(){
assert_true(radio8.checked);
assert_false(radio9.checked);
assert_false(radio10.checked);
assert_true(radio11.checked);
radio9.name="group4";
radio9.checked = true;
assert_true(radio8.checked);
assert_true(radio9.checked);
assert_false(radio10.checked);
assert_false(radio11.checked);
}, "changing the name of a radio input element and setting its checkedness to true makes all the other elements' checkedness in the same radio button group be set to false");
test(function(){
radio12.remove();
assert_true(radio12.checked);
assert_false(radio13.checked);
assert_false(radio14.checked);
radio13.checked = true;
assert_true(radio13.checked);
assert_false(radio14.checked);
radio13.removeAttribute("form");
radio14.removeAttribute("form");
assert_true(radio13.checked);
assert_false(radio14.checked);
radio14.checked = true;
assert_false(radio13.checked);
assert_true(radio14.checked);
radio13.setAttribute("form", "testform");
radio14.setAttribute("form", "testform");
radio13.checked = true;
assert_true(radio13.checked);
assert_false(radio14.checked);
testform.remove();
assert_true(radio13.checked);
assert_false(radio14.checked);
}, "moving radio input element out of or into a form should still work as expected");
radio5.onclick = t1.step_func(function(e) {
click_fired = true;
assert_false(input_fired, "click event should fire before input event");
assert_false(change_fired, "click event should fire before change event");
assert_false(e.isTrusted, "click()-initiated click event shouldn't be trusted");
});
radio5.oninput = t1.step_func(function(e) {
input_fired = true;
assert_true(click_fired, "input event should fire after click event");
assert_false(change_fired, "input event should fire before change event");
assert_true(e.bubbles, "input event should bubble")
assert_true(e.isTrusted, "input event should be trusted");
assert_false(e.cancelable, "input event should not be cancelable");
});
radio5.onchange = t1.step_func(function(e) {
change_fired = true;
assert_true(click_fired, "change event should fire after click event");
assert_true(input_fired, "change event should fire after input event");
assert_true(e.bubbles, "change event should bubble")
assert_true(e.isTrusted, "change event should be trusted");
assert_false(e.cancelable, "change event should not be cancelable");
});
radio6.oninput= t3.step_func_done(function(e) {
assert_unreached("event input fired");
});
radio6.onchange = t4.step_func_done(function(e) {
assert_unreached("event change fired");
});
t1.step(function() {
radio5.click();
assert_true(input_fired);
t1.done();
});
t3.step(function(){
radio6.click();
t3.done();
t4.done();
});
radio72.onclick = t5.step_func_done(function(e){
assert_false(radio71.checked, "click on radio should uncheck other radio in same group");
assert_true(radio72.checked, "click on radio should check that radio");
e.preventDefault();
// The cancelation of the click doesn't have an effect until after all the click event handlers have been run.
assert_false(radio71.checked, "radio remains unchecked immediately after click event on other radio in same group is canceled");
assert_true(radio72.checked, "clicked radio remains checked immediately after click event is canceled");
});
t5.step(function(){
assert_true(radio71.checked, "initially checked radio should be checked");
assert_false(radio72.checked, "other radios in same group as initially-checked radio should be unchecked");
radio72.click();
// Now that the click event has been fully dispatched, its cancelation has taken effect.
assert_true(radio71.checked, "canceled click event on radio should leave the previously-checked radio checked");
assert_false(radio72.checked, "canceled click event on previously-unchecked radio should leave that radio unchecked");
});
test(() => {
const container = document.createElement('div');
container.innerHTML =
'<input type=radio name=n1><span><input type=radio name=n1 checked></span>' +
'<form><input type=radio name=n1 checked></form>';
const radios = container.querySelectorAll('input');
assert_false(radios[0].checked, 'Sanity check: The first radio should be unchecked');
assert_true(radios[1].checked, 'Sanity check: The second radio should be checked');
assert_true(radios[2].checked, 'Sanity check: The third radio should be checked');
radios[0].checked = true;
assert_true(radios[0].checked, 'The first radio should be checked after setting checked');
assert_false(radios[1].checked, 'The second radio should be unchecked after setting checked');
assert_true(radios[2].checked, 'The third radio should be checked after setting checked');
radios[1].required = true;
assert_false(radios[0].validity.valueMissing, 'The first radio should be valid');
assert_false(radios[1].validity.valueMissing, 'The second radio should be valid');
assert_false(radios[2].validity.valueMissing, 'The third radio should be valid');
radios[0].remove();
assert_false(radios[0].validity.valueMissing, 'The first radio should be valid because of no required');
assert_true(radios[1].validity.valueMissing, 'The second radio should be invalid***');
assert_false(radios[2].validity.valueMissing, 'The third radio should be valid');
radios[0].required = true;
radios[0].checked = false;
assert_true(radios[0].validity.valueMissing, 'The first radio should be invalid because of required');
}, 'Radio buttons in an orphan tree should make a group');
test(() => {
const container = document.createElement('div');
container.innerHTML =
'<form>' +
'<input type=radio name=group1 id=radio1 checked>' +
'<input type=radio name=group1 id=radio2>' +
'</form>' +
'<form>' +
'<input type=radio name=group1 id=radio3 checked>' +
'<input type=radio name=group1 id=radio4>' +
'</form>' +
'<input type=radio name=group1 id=radio5 checked>' +
'<input type=radio name=group1 id=radio6>';
const radio1 = container.querySelector('#radio1');
const radio2 = container.querySelector('#radio2');
const radio3 = container.querySelector('#radio3');
const radio4 = container.querySelector('#radio4');
const radio5 = container.querySelector('#radio5');
const radio6 = container.querySelector('#radio6');
// initial conditions
assert_true(radio1.checked, 'radio1 should be checked');
assert_false(radio2.checked, 'radio2 should be unchecked');
assert_true(radio3.checked, 'radio3 should be checked');
assert_false(radio4.checked, 'radio4 should be unchecked');
assert_true(radio5.checked, 'radio5 should be checked');
assert_false(radio6.checked, 'radio6 should be unchecked');
radio2.checked = true;
assert_false(radio1.checked, 'radio1 should be unchecked');
assert_true(radio2.checked, 'radio2 should be checked');
assert_true(radio3.checked, 'radio3 should remain checked');
assert_true(radio5.checked, 'radio5 should remain checked');
radio4.checked = true;
assert_false(radio1.checked, 'radio1 should remain unchecked');
assert_true(radio2.checked, 'radio2 should remain checked');
assert_false(radio3.checked, 'radio3 should be unchecked');
assert_true(radio4.checked, 'radio4 should be checked');
assert_true(radio5.checked, 'radio5 should remain checked');
radio6.checked = true;
assert_false(radio1.checked, 'radio1 should remain unchecked');
assert_true(radio2.checked, 'radio2 should remain checked');
assert_false(radio3.checked, 'radio3 should remain unchecked');
assert_true(radio4.checked, 'radio4 should remain checked');
assert_false(radio5.checked, 'radio5 should be unchecked');
assert_true(radio6.checked, 'radio6 should be checked');
}, "Radio buttons in different groups (because they have different form owners or no form owner) do not affect each other's checkedness");
test(() => {
const container = document.createElement('div');
container.innerHTML =
'<form>' +
'<input type=radio name=group1 id=radio1 checked>' +
'<input type=radio name=group1 id=radio2>' +
'<input type=radio name=group1 id=radio3>' +
'<input type=radio name=group1 id=radio4>' +
'</form>';
const radio1 = container.querySelector('#radio1');
const radio2 = container.querySelector('#radio2');
const radio3 = container.querySelector('#radio3');
const radio4 = container.querySelector('#radio4');
// initial conditions
assert_true(radio1.checked, 'radio1 should be checked');
assert_false(radio2.checked, 'radio2 should be unchecked');
assert_false(radio3.checked, 'radio3 should be unchecked');
assert_false(radio4.checked, 'radio4 should be unchecked');
radio3.remove();
radio4.remove();
radio3.checked = true;
radio4.checked = true;
assert_true(radio1.checked, 'radio1 should remain checked');
assert_false(radio2.checked, 'radio2 should remain unchecked');
assert_true(radio3.checked, 'radio3 should be checked');
assert_true(radio4.checked, 'radio4 should be checked');
}, "Radio buttons in different groups (because they are not in the same tree) do not affect each other's checkedness");
test(() => {
const container = document.createElement('div');
container.innerHTML =
'<form>' +
'<input type=radio name=group1 id=radio1 checked>' +
'<input type=radio name=group1 id=radio2>' +
'<input type=radio name=group2 id=radio3 checked>' +
'<input type=radio name=group2 id=radio4>' +
'<input type=radio name="" id=radio5 checked>' +
'<input type=radio name="" id=radio6>' +
'<input type=radio id=radio7 checked>' +
'<input type=radio id=radio8>' +
'</form>';
const radio1 = container.querySelector('#radio1');
const radio2 = container.querySelector('#radio2');
const radio3 = container.querySelector('#radio3');
const radio4 = container.querySelector('#radio4');
const radio5 = container.querySelector('#radio5');
const radio6 = container.querySelector('#radio6');
const radio7 = container.querySelector('#radio7');
const radio8 = container.querySelector('#radio8');
// initial conditions
assert_true(radio1.checked, 'radio1 should be checked');
assert_false(radio2.checked, 'radio2 should be unchecked');
assert_true(radio3.checked, 'radio3 should be checked');
assert_false(radio4.checked, 'radio4 should be unchecked');
assert_true(radio5.checked, 'radio5 should be checked');
assert_false(radio6.checked, 'radio6 should be unchecked');
assert_true(radio7.checked, 'radio7 should be checked');
assert_false(radio8.checked, 'radio8 should be unchecked');
radio2.checked = true;
assert_false(radio1.checked, 'radio1 should be unchecked');
assert_true(radio2.checked, 'radio2 should be checked');
assert_true(radio3.checked, 'radio3 should remain checked');
assert_false(radio4.checked, 'radio4 should remain unchecked');
assert_true(radio5.checked, 'radio5 should remain checked');
assert_false(radio6.checked, 'radio6 should remain unchecked');
assert_true(radio7.checked, 'radio7 should remain checked');
assert_false(radio8.checked, 'radio8 should remain unchecked');
radio6.checked = true;
assert_false(radio1.checked, 'radio1 should remain unchecked');
assert_true(radio2.checked, 'radio2 should remain checked');
assert_true(radio3.checked, 'radio3 should remain checked');
assert_false(radio4.checked, 'radio4 should remain unchecked');
assert_true(radio5.checked, 'radio5 should remain checked');
assert_true(radio6.checked, 'radio6 should be checked');
assert_true(radio7.checked, 'radio7 should remain checked');
radio8.checked = true;
assert_false(radio1.checked, 'radio1 should remain unchecked');
assert_true(radio2.checked, 'radio2 should remain checked');
assert_true(radio3.checked, 'radio3 should remain checked');
assert_false(radio4.checked, 'radio4 should remain unchecked');
assert_true(radio5.checked, 'radio5 should remain checked');
assert_true(radio6.checked, 'radio6 should remain checked');
assert_true(radio7.checked, 'radio7 should remain checked');
assert_true(radio8.checked, 'radio8 should be checked');
}, "Radio buttons in different groups (because they have different name attribute values, or no name attribute) do not affect each other's checkedness");
</script>