diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index d21980b01ba..e510720a9d8 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -68,6 +68,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 + uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: sarif_file: results.sarif diff --git a/README.md b/README.md index 6312700b47d..2c1096ff1c3 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # ![HtmlUnit Logo](https://github.com/HtmlUnit/htmlunit/blob/master/src/site/resources/images/htmlunit.png) -Version 5.3.0 / July 15, 2026 +Version 5.4.0 / August 07, 2026 :heart: [Sponsor](https://github.com/sponsors/rbri) [![Maven Central Version](https://img.shields.io/maven-central/v/org.htmlunit/htmlunit)](https://central.sonatype.com/artifact/org.htmlunit/htmlunit) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/HtmlUnit/htmlunit/badge)](https://securityscorecards.dev/viewer/?uri=github.com/HtmlUnit/htmlunit) +![Commercial Users](https://api.scarf.sh/v2/packages/HTML-Unit/e4454d4c-c1a0-44d6-8af9-ab9ee18b428c/commercial-users-badge) +![Scarf: Downloads](https://api.scarf.sh/v2/packages/HTML-Unit/e4454d4c-c1a0-44d6-8af9-ab9ee18b428c/downloads-badge) ### Homepage @@ -68,7 +70,7 @@ Add to your `pom.xml`: org.htmlunit htmlunit - 5.3.0 + 5.4.0 ``` @@ -77,7 +79,7 @@ Add to your `pom.xml`: Add to your `build.gradle`: ```groovy -implementation group: 'org.htmlunit', name: 'htmlunit', version: '5.3.0' +implementation group: 'org.htmlunit', name: 'htmlunit', version: '5.4.0' ``` ## Getting Started @@ -242,7 +244,7 @@ Add the snapshot repository and dependency to your `pom.xml`: org.htmlunit htmlunit - 5.3.0-SNAPSHOT + 5.5.0-SNAPSHOT @@ -261,7 +263,7 @@ repositories { } // ... dependencies { - implementation group: 'org.htmlunit', name: 'htmlunit', version: '5.4.0-SNAPSHOT' + implementation group: 'org.htmlunit', name: 'htmlunit', version: '5.5.0-SNAPSHOT' // ... } ``` diff --git a/checkstyle.xml b/checkstyle.xml index f6546283797..33239593744 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -114,6 +114,12 @@ + + + + + + diff --git a/pom.xml b/pom.xml index f22f3f47f4f..d3cce78e1bb 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.htmlunit htmlunit - 5.3.0 + 5.4.0 jar HtmlUnit @@ -40,12 +40,12 @@ --add-opens org.htmlunit/org.htmlunit.util.quercus.servlet=ALL-UNNAMED - 5.3.0 - 5.3.0 - 5.3.0 - 5.3.0 - 5.3.0 - 5.3.0 + 5.4.0 + 5.4.0 + 5.4.0 + 5.4.0 + 5.4.0 + 5.4.0 4.5.14 3.20.0 @@ -59,11 +59,11 @@ selenium-devtools-v150 - 6.1.2 + 6.1.3 2.3.0 - 12.1.11 + 12.1.12 4.0.66 - 1.5.38 + 1.6.1 1.15.0 2.0.0-M1 4.4.0 @@ -74,9 +74,9 @@ 12.3.1 - 4.10.2 - 7.25.0 - 1.4.2 + 4.10.3 + 7.26.0 + 1.5.0 10.0.4 @@ -84,21 +84,21 @@ 3.6.1 3.6.0 3.28.0 - 4.10.2.0 + 4.10.3.0 3.2.8 3.6.3 2.12.1 3.15.0 - 3.5.0 + 3.5.1 3.8.0 3.4.0 3.12.0 3.5.6 3.12.1 - 6.0.2 + 6.1.0 0.8.15 2.2.0 - 2.9.1 + 2.9.3 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 801410c507d..3694bdaa631 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -7,6 +7,227 @@ + + + docu: Detailed description about input html elements usage. + + + core-js: ES2021 WeakRef and FinalizationRegistry with full standard compliance added. + + + websocket-client: jetty updated to 12.1.12. + + + HtmlSelect methods removeOption() and replaceOption() support for optgroups fixed. + + + HTMLNumberInput the different validation methods using a relaxed version of the number parser. + + + HTMLNumberInput value property getter still does some cleanup on the raw value (e.g. removes a trailing dot). + + + HTMLNumberInput value property getter no longer uses a format that matches the browser locale. + + + HTMLNumberInput now sanitizes the value in the setter, not in the getter as before. + + + Add a new Html spec conform number parser - HtmlNumberParser and use it from HtmlNumberInput. + + + Implemented the validationMessage property for HtmlButton, HtmlTextArea, HtmlInput, HtmlObject, HtmlOutput, and HtmlSelect. + + + Fixed HTMLFormElement.checkValidity()/reportValidity(): the aggregate check over a form's controls + now correctly fires on every failing control. + + + Fixed checkValidity()/reportValidity(): a failing control now correctly fires a cancelable 'invalid' + event (and reportValidity() additionally focuses the first invalid control). + + + INCOMPATIBLE CHANGE: org.htmlunit.html.ValidatableElement renamed to ValidatableHtmlElement. + + + neko: section no longer closes select. + + + Added HTMLFieldSetElement.type property. + + + Property HTMLFieldSetElement.elements added. + + + Fixed DisabledElement.isDisabled(): a disabled fieldset no longer disables descendants of its + first legend element, matching the spec's exemption for controls placed inside a fieldset's legend. + + + Fixed checkValidity()/reportValidity() and the CSS :valid/:invalid pseudo-classes + for HtmlButton, HtmlTextarea, HtmlInput, HtmlObject, HtmlOutput, and HtmlSelect. + + + HtmlFileInput.reset(): a form reset no longer tries to reconstruct a fake File from the + 'value' attribute; it now simply clears the selected files, without firing a change event. + + + HtmlFileInput.isValid(): a disabled file input is no longer incorrectly reported as invalid + by checkValidity() when 'required' is set and no file is selected. + + + Method reportValidity() support to various form controls added. + + + Various fixes to HtmlButton validation processing. + + + Document HtmlButton's no-op implementations for reset and default value handling, and remove extraneous debug logging. + + + Method isReadonly() removed from HtmlButton because there is no readonly support for this control. + + + DisabledElement now implements Element and provides a default implementation of isDisabled(). + + + Fixed HtmlTextArea.reset(): the text entry cursor/selection is now only moved to the end of the restored + value when that value actually differs from the current one, instead of always being forced to the end. + + + Fixed HtmlInput/HtmlSelectableTextInput: setting the value to the value it already holds no longer moves + the text entry cursor/selection to the end, mirroring the same fix applied to HtmlTextArea. + + + Fixed HtmlSelectableTextInput.reset(): removed a leftover selection reset that left selectionStart and + selectionEnd in an inconsistent state after a form reset. + + + Major refactoring of the value handling for textarea; setting the value no longer manipulates the DOM, + instead a separate value and dirty flag are maintained (this is now in sync with the spec and the input element). + + + Method isReadonly() removed from HtmlSelect; because there is no readonly support for this control. + + + HtmlSelect should not drop invalid size attributes on page attachment. + + + Fixed reset of the isValueDirty flag for HtmlInput. + + + Corrected and improved value caching in ComputedCssStyleDeclaration. + + + Fixed line count determination. + + + neko: HTMLElement hashCode and equals fixed. + + + neko: Remove the <SOUND>, <ILAYER>, <LAYER>, <NOLAYER>, <NEXTID>, <MULTICOL>, + <BLINK>, <SPACER>, and <XML> tag suport. + + + neko: HTMLWriterFilter now serializes <textarea> and <title> element content with entity encoding + (https://github.com/HtmlUnit/htmlunit-neko/issues/173). + + + neko: Remove the <comment> tag suport (https://github.com/HtmlUnit/htmlunit-neko/issues/173). + + + neko: A new <nobr> start tag closes an <nobr> that is still open, even across intervening block elements. + + + neko: A new <a> start tag closes an <a> that is still open, even across intervening block elements. + + + csp: Multi-policy AND query APIs added. + + + neko: Some performance optimizations and code cleanup. + + + Fix a possible resource leak by making sure ImageIOImageData closes the base stream. + + + DownloadedContent.OnFile and ImageIOImageData now use Cleaner instead of finalize(). + + + Improved headers for XHR preflight requests. + + + The innerText() method for select elements now generates the same output as real browsers. + + + The java.net.http module is now required. + + + neko: Major update - the select element now allows arbitrary tags. + https://github.com/whatwg/html/pull/10557 + (https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/select) + + + neko: The input element closes select elements. + + + Navigator.sendBeacon() method added. + + + The area element supports the 'type' property in Firefox 153. + + + Error.stackTraceLimit is available in Firefox 153. + + + (I)frame requests now also send the Accept header. + + + Area link handling is now in sync with anchor handling (implementation shared via the new + HyperlinkElementSupport class and the new HyperlinkElement interface). This adds support + for the 'ping' and 'download' attributes, among others. + + + Script web requests now respect the 'crossorigin' attribute. + + + Anchor ping requests now also send the Accept-Encoding and Cache-Control headers. + + + Anchor web requests now respect the 'crossorigin' attribute. + + + Major update to WebRequest to improve support for the Sec-Fetch-* HTTP headers. + + + The URL/anchor hostname setter received several fixes. + + + core-js: Added support for a common workaround for subclassing built-in objects (such as Set) + without using ES6 class/extends syntax, by using Reflect.construct() with a newTarget argument. + + + core-js: Improved strict mode handling for direct eval() calls. + + + Range.getClientRects() and Range.getBoundingClientRect() now ignore whitespace-only text nodes + and block-level siblings when calculating the horizontal offset of a text node. + + + Range.getClientRects() and Range.getBoundingClientRect() now handle DomText nodes correctly. + + + Range.getBoundingClientRect() now uses shrink-wrap width calculation for block elements, + returning a tight bounding box around the actual content rather than the full + containing block width. + + + Range.getTextNodeRect() now correctly determines character offsets when the range + boundaries are set on a parent element rather than directly on the text node, + returning the full text width instead of a single-character width. + + + + Make XMLHttpRequest check blob url's origin properly instead of @@ -2011,5 +2232,14599 @@ core-js: Some improvements for the interpreter by generating smaller interpreter bytecode. + + + + + core-js: String.prototype.matchAll, Symbol.matchAll, and RegExp.prototype[Symbol.matchAll] added. + + + neko: BOM header detection fixed + + + neko: bunch of micro optimizations + + + Property navigator pdfViewerEnabled added. + + + Implementation of Plugin/PluginArray/MimeType/MimeTypeArray rewritten. The navigator properties + plugins and mimeTypes returning static results in all browsers. + + + Class PluginConfiguration removed, the config is static for all browsers. + + + A bit more code cleanup - flash is finally gone. + + + Upgrade Apache commons-io to 2.18.0. + + + DOMTokenList add()/remove() are able to handle an arbitrary amount of tokens. + + + Element.getInnerHTML() is gone in Chrome/Edge. + + + WebRequest custom serialization misses the handling of defaultResponseContentCharset. + + + Class SilentIncorrectnessListener added. + + + Javadoc fixed for Document.elementFromPoint(). + + + Bunch of fixes for Document.createElement() when calling with invalid tag names. + + + StyleSheetList.item() should return null if the provided index is not available. + + + HTMLOptionsCollection.item() should return null if the provided index is not available. + + + CssRuleList.item() should return null if the provided index is not available. + + + FrameContentHandler sample added. + + + document.all == undefined and document.all == null now returns true. + + + core-js: make sure, equivalentValues() is used if available. + + + + + + INCOMPATIBLE CHANGE: HtmlPage.getBody() no longer returns an HtmlFrameSet. + + + disable early cdata closing for xhtml pages + + + neko: feature 'http://cyberneko.org/html/features/scanner/cdata-early-closing' to disable early + closing of cdata sections added + + + neko: interface HTMLEventInfo merged into Augmentations + + + neko: feature 'http://cyberneko.org/html/features/scanner/allow-selfclosing-script' to allow + parsing of self closing script tags added + + + neko: wrong default for NamespaceBinder 'http://cyberneko.org/html/properties/names/elems' property + + + neko: code improvements for string handling + + + Bunch of minor changes to reduce object creation and improve performance during DOM creation. + + + The DOMTree might include cycles in some border cases; fixed. + + + No longer use getElementsByTagName() in cases we do not need the live update capabilities of the result. + This reduces the internal workload and should make some cases faster. + + + DomElement.click() now returns the correct page if the page contains a JS-based form auto submit. + This was a regression from version 4.4.0. + + + Nullish assignment operator '??=' implemented. + + + Like real browsers work a bit more optimized as long as no CharacterDataChangeListener/DomChangeListener + is registered. In this case we can avoid some dom tree traversal. + + + core-js: Support optional chaining for function calls, as well as the "eval" case like 'f?.()'. + + + Simple implementation of Node.lookupPrefix(String) added. + + + core-js: many fixes for default values in destructuring assignments + + + core-js: many fixes for optional chain and nullish coalesce + + + NPE in AttachmentHandler.isAttachment(WebResponse) fixed. + + + + + + + INCOMPATIBLE CHANGE: Return type of AbstractCssStyleDeclaration.item(int) has changed from Object to String. + + + INCOMPATIBLE CHANGE: Classes HtmlBlink, HtmlCommand, HtmlIsIndex, HtmlMenuItem, HtmlMultiColumn, and HtmlNextId removed. + + + Next round to remove the 'keygen' tag support. + + + Bunch of fixes for the various ruby supprt tags. + + + Cleanup of the ElementFactory/DefaultElementFactory to simplify the code and improve the performance. + + + Small performance and memory optimization for the creation of our DOM tree. + + + AbstractDomNodeList access might throw a NPE due to a race condition in the DomHtmlAttributeChangeListenerImpl + clearing of cachedElements processing. + + + Special handling of the bgsound tag in FF removed. BGSound is now handled as unknown tag in all browsers. + Looks like this was a leftover from the IE days. + + + Function initHashChangeEvent() is no longer available in FF_ESR. + + + Location.query property always returns an empty string if the location has the about protocol and + the browser is FF/FF_ESR. + + + Property window.clientInformation is settable in FF too. + + + The WebSocket ctor in FF_ESR now accepts also undefined/null. + + + FF_ESR right clicking for the context menu triggers a mouse event with a detail of 1 instead of 2. + + + HtmlDetailElement 'name' property added for FF. + + + JS class DomRequest removed (was only used by FF_ESR). + + + PointerEvent properties altitudeAngle and azimuthAngle supported in FF. + + + Javascript return type of some methods changed from Object to String. + + + Javascript Cssstyledeclaration#item() now returns a String. + + + core-js: code cleanup; remove the unused javascript/optimizer package. + + + core-js: bunch of code optimizations. + + + core-js: remove '__exception__' property from global context. + + + core-js: improve ScriptRuntime.toPrimitive() and use it at many places. + + + core-js: optimize initializion of error objects. + + + core-js: Support the standard "toStringTag" symbol when converting objects to strings. + + + core-js: optional chaining operator '?.' support added. + + + core-js: Some byte code generation fixes for Android. + + + core-js: Symbol.prototype.description support added. + + + core-js: some minor fixes for the Reflect/Proxy support. + + + New (transient) configuration option SSLContext added. + + + Class org.htmlunit.javascript.preprocessor.HtmxOneNineTenScriptPreProcessor removed. + This class is no longer required because default parameter support was added to core-js. + + + core-js: Support for default parameters added. + + + core-js: String.isWellFormed() and String.toWellFormed() added. + + + core-js: Support surrogate chars in JSON.stringify(). + + + Upgrade Apache commons-io to 2.17.0. + + + core-js: Support for Promise.any added. + + + core-js: Support for nullish coalescing operator '??' added. + + + core-js: Support for logical assigment operators '||=' and '&&=' added. + + + core-js: Stacktrace line number fixed. + + + websocket-client: jetty updated to 9.4.56.v20240826. + + + Upgrade Apache commons-lang3 to 3.17.0. + + + core-js: Map groupBy added. + + + TextDecoder.decode() decodes now only the TypedArray view's range. + + + CaretPosition is now available in all supported browsers. + + + core-js: 'cause' property added to NativeError and some toString() improvements. + + + core-js: New methods toReversed, toSorted, toSpliced, and with added to Array and TypedArray. + + + core-js: Make sure to use only the RegExpProxy interface instead of some hardcoded instanceof + call. This opens the door to integrate a much more standard complient regexp suppor. + + + core-js: When doing math, try to do integer arithmetic when the arguments passed + are Integer objects, rather than always falling back to floating-point math. + This speeds up some benchmarks that rely heavily on integer arithmetic. + + + Upgrade commons-logging to 1.3.4 + + + Click action now uses the PointerEvent instead of the MouseEvent in Firefox. + + + TextEvent is available Firefox also. + + + core-js: Ensure that generator functions always pass parameters properly. + + + Some missing index verification added in FileList. + + + Initial incomplete implementation of file handling for DataTransfer. + + + Complete implementation of DataTransferItem, and DataTransferItemList. + + + Package org.htmlunit.javascript.host.draganddrop added. DataTransfer, DataTransferItem, + and DataTransferItemList moved into this package. + + + FileList is now iterable. + + + core-js: Obsolete classes ObjToIntMap and UintMap removed; depending on context, classes replaced + with either HashMap or sometimes HashSet. + + + core-js: Support for Array/TypedArray findLast() and findLastIndex() added. + + + Fix FileReader handling of in memory File's. + + + Fix FormData.append()/set() handling of in memory File's. + + + Fix FormData.append()/set() handling of Blob's. + + + MutationObserver now fires also when attributes added/removed. + + + core-js: Obsolete class ObjArray removed; depending on context, class replaced + with either ArrayList or ArrayDeque. + + + core-js: Symbol.unscopables for arrays implemented. + + + DOMTokenList toggle() method got some fixes. + + + DOMTokenList value property added. + + + DOMTokenList simplify impl and fix removal of duplicate entries. + + + DOMTokenList is now iterable, keys(), entries(), and replace() method implemented. + + + Implementation of DOMTokenList.forEach() added. + + + Deprecated method CssStyleSheet.parseMedia(CSSErrorHandler, String) removed. + Deprecated method CSSStyleSheet.validateSelectors(SelectorList, int, DomNode) removed. + Deprecated method HtmlFileInput.setValueAttribute(String) removed. + Deprecated ctor HtmlUnitUsernamePasswordCredentials.HtmlUnitUsernamePasswordCredentials(String, String) removed. + + + Deprecated methods compile(HtmlPage, String, String, int), execute(HtmlPage, SCRIPT), and + execute(HtmlPage, String, String, int) removed from AbstractJavaScriptEngine. + + + Deprecated methods setSSLClientCertificate(URL, String, String), and + setSSLClientCertificate(InputStream, String, String) removed from WebClientOptions. + + + Deprecated methods addCredentials(String, String), .addCredentials(String, String, String, int, String), + addNTLMCredentials(String, String, String, int, String, String), and + addSocksCredentials(String, String, String, int) removed from DefaultCredentialsProvider. + + + Method CSSStyleSheet.validateSelectors(SelectorList, int, DomNode) is deprecated; please use method + CSSStyleSheet.validateSelectors(SelectorList, DomNode) instead. + + + core-js: Error with yield in ComputedPropertyName fixed. + + + core-js: Support ctor for regex that takes an existing regex and a different set of flags. + + + FF implements a special handling for the return value of the compareFn function + used to custom sort arrays. If the result is a boolean the value false will not + be converted to 0 - it will be converted to -1. + + + Upgrade Apache commons-lang3 to 3.16.0. + + + One no loger required thread local variable removed. + + + Method WebRequest.setRefererlHeader(URL) is deprecated; please use Method WebRequest.setRefererHeader(URL) instead. + + + core-js: exception when calling apply with emptyArgs. + + + Window.performance is setable. + + + AbortController and AbortSignal stubs implemented. + + + Worker ctor no longer failes when called with undefined as options. + + + HTMLFormControlsCollection is now iterable. + + + RadioNodeList is now iterable. + + + HTMLFormControlsCollection namedItem() implemented. + + + RadioNodeList getter and setter for value attribute implemented. + + + WebRequest.getParameters() updated again to be more compatible with Spring. + + + WebRequest.getParameters() updated to deliver the same results as the servlet API + will report if this request reaches a servlet. This implies several changes: For url-encoded and + plain text encoded post requests, the query parameters are part of the result. + For multipart requests only the query parameters forming the result. Please check also the + javadoc of the method for more details. + + + WorkerNavigator and WorkerLocation implemented. + + + WebWorker context setup fixed, all API's now available. + + + + + + + core-js: Various missing methods in TypedArray added. + + + XMLHttprequest 'responseXML' and 'response' (responseType document) results are identical. + + + XMLHttprequest 'responseXML' bom headers are overruling the content encoding. + + + XMLHttprequest 'responseXML' reads the plain response without converting to a string internally. + + + XMLHttprequest 'responseXML' some fixes for handling of empty content. + + + XMLHttprequest 'responseXML' - if the responseType is set to 'document' and the request + was made asynchronously then support 'text/html' content type. + + + XMLHttprequest 'response'' property now handles the XMLDocument generation the same way + as the property 'responseXML'. + + + The response encoding determination for XMLHttprequest fixed. If the content type header does not contain + a content type (but a charset) then the charset info is ignored. + + + DomNode.compareDocumentPosition now returns correct results if both nodes do not share the + same root (eg. different document fragments). + + + Small sample for changing the browsers user agent addet to the docs. + + + Upgrade Apache commons-lang3 to 3.15.0. + + + core-js: Array.prototype.sort is now stable. + + + core-js: Function.prototype.toString/toSource now uses the source. This superceeds a fix + we made in version 3.0.0. + + + Logging of a notifications about calling js functionality while the WebClient and the JS Engine + are already going down is removed. + + + core-js: Improved position reporting in case of syntax errors. + + + core-js: Improved support for continuations. + + + core-js: Computed properties support added. + + + Upgrade commons-codec to 1.17.1. + + + Fix wrong impl of polyfill cache. + + + When an element is clicked, the postponed actions are executed too early - only + the processing of the downloaded pages may take place at this time. + + + A FormData object constructed from a form only enumerates not disabled elements + by taking care of elements inside disabled fieldsets. + + + DisabledElement.isDisabled() now checks also for the parent elements. + This fixes problems with elements inside a disabled fieldset. + + + Function Element.getHTML() added for FF. + + + Changed accept header for images and documents to be in sync with FF 128. + + + DedicatedWorkerGlobalScope 'name' property added. + + + DedicatedWorkerGlobalScope 'constructor' property was missing. + + + Option 'fileProtocolForXMLHttpRequestsAllowed' to allow XMLHttpRequest for local files + from the same directory and subdirectories. + + + FieldSets and Outputs are also accessible by there old names. + + + Upgrade commons-logging to 1.3.3 + + + websocket-client: jetty updated to 9.4.55.v20240627. + + + Method HtmlForm.getElements() is now deprecated; please use HtmlForm.getElements(Predicate<HtmlElement>) + or HtmlForm.getFromElements() instead. Please read the jdoc of the new methods, they return + slightly different results. + + + FieldSets are part of the Form.elements collection. + + + Inputs of type image are not part of the Form.elements collection. + + + Window length/self/parent/frames are defined as [Replaceable]. HtmlUnit now mimics the browsers regarding this. + + + ComputedCSSStyleDeclaration.display takes care of the hidden attribute. + + + Move the 'cookie' property from HTMLDocument to Document. + + + + + + + Improved implementation of the hidden attribute setter. + + + core-js: another hack on the const handling (in most cases const no treated like let - this is not correct + but avoids the 'constant redefinition' parser error). + + + Sarissa 0.9.9.7 tests added. + + + DateTimeFormat.format now takes care of the current browser timezone and locale. + + + Fix some NPE in HtmlSerializer's. + + + Improved innerHTML content parsing for special tags like title, textarea, style, and script. + + + DocumentFragment append()/prepend()/replaceChildren() added. + + + URL.origin should include the port (if it is not the default one). + + + Calling new DocumentFragment() now creates a properly initialized object. + + + XPathEvaluator.createExpression() and XPathExpression.evaluate() added. + + + Various exceptions fixed when XPathEvaluator.evaluate() is called without some optional parameters. + + + Documentation for changing the browser timezone/language added. + + + File.lastModifiedDate formatting fixed. + + + Document.lastModified now takes care of the browser timezone. + + + Intl.DateTimeFormat().resolvedOptions().locale support added. + + + core-js: Date/Time format functions are now taking care of the browser locale. + + + core-js: Date.prototype.toLocaleString takes care of locales argument. + + + core-js: Object.defineProperty() has to take care of ConsString. + + + Upgrade Apache commons-net to 3.11.1. + + + Fix NPE during click processing when JavaScript engine disabled. + + + + + + + INCOMPATIBLE CHANGE: The signature of two methods from org.htmlunit.attachment.AttachmentHandler was changed. + Please implement handleAttachment(Page, String) instead of handleAttachment(Page) + and handleAttachment(WebResponse, String) instead of handleAttachment(WebResponse). + + + INCOMPATIBLE CHANGE: Ctor XMLHttpRequest(boolean caseSensitiveProperties) removed. This was only introduced + for the XMLHttpRequest ActiveX object that is no longer there. + + + + core-js: NetworkError introduced. + + + neko: fix Html element creation when parsing XHTML files. + + + Upgrade Apache commons-net to 3.11.0. + + + GWT 2.11.0 tests. + + + neko: fix the setup of the fragment parser; this fixes some problems with range.createContextualFragment(). + + + neko: code cleanup, more tests, some unused stuff removed; javadoc fixes. + + + neko: AttributeMap.cloneMap() fixed. + + + neko: fix fragment parsing without providing a context takes care of html tags in the fragment. + + + HashChangeEvent.initHashChangeEvent() no longer supported by Firefox 126. + + + Firefox 126 sends the Priority header. + + + Function Element.getHTML() added for Chrome/Edge. + + + WebSocket ctor resolves the url relative to the page for the latest Chrome/Edge/FF. + + + Handling of Attachments is improved. Now we treat responses only haven and Content-Type header of application/octetstream + in the same way as if the Content-Disposition header was set to attachment. This is was real browsers also do. + + + Upgrade commons-logging to 1.3.2 + + + ComputedCssStyleDeclaration.isScrollable(boolean, boolean) now checks also for the overflow-x/overflow-y styles. + + + Make HtmlElement.type() allow full-width space (\u3000), six-per-em space (\u2006) and tab (\t) characters. + + + Prevent iframes from loading local resource for security reason (reading local file resources is still allowed + if the enclosing document itself was loaded from file). + + + Prevent XMLHttpRequest from loading local resource for security reason. + + + Improve Attachment.getSuggestedFilename() by making it prioritize the value of Anchor.download if exist. + + + Improve Attachment.getSuggestedFilename() by making it return the value of File.name + if the attachment was downloaded through a blob-url created from a File. + + + Options support added for window.scroll()/scrollBy()/scrollTo(). + + + Initial simple implementation of element.scroll()/scrollBy()/scrollTo(). + + + Fixes for hash processing in Location.reload(). + + + + + + HttpClientConverter.parseUrlQuery(String, Charset) and toQueryFormFields(List<NameValuePair>, Charset) are deprecated. + Please use HttpUtils instead. + + + HttpClientConverter.formatDate(Date) and HttpClientConverter.parseDate(String) are deprecated. + Please use HttpUtils instead. + + + Class HttpStatus defining a complete list of Http status codes added. + + + Http status code constants in HttpClientConverter are deprecated. + Please use the constants from HttpStatus. + + + Deprecated http status code constants removed from WebResponse. + + + + core-js: Fixed handling of unicode characters in the lexer. + + + core-js: slightly improved Context.close() impl and try-with-resources usage. + + + Upgrade commons-codec to 1.17.0. + + + Internal class WebClientInternals removed. + + + First simple version of HtmlElement innerText setter implemented. + + + XMLHttpRequest now supports the 'x-user-defined' trick to transfer binary data. + + + Support for URL.createObjectURL() and URL.revokeObjectURL() added. + + + neko: x-user-defined encoding is now supported; like in real browsers x-user-defined is mapped to windows-1252. + + + neko: Another bunch of fixes for encodings. + + + TextDecoder - fix handling of various charsets (incl. replacement and x-user-defined) + + + Upgrade Apache commons-text to 1.12.0. + + + Upgrade Apache commons-io to 2.16.1. + + + core-js: set-callTrap should be called with the value, not the descriptor of value. + + + Wrong script encoding was uses in some cases (regression in 4.0.0). + + + keyboard-howto updated and enhanced. Some documentation about clipboard handling added. + + + Missing unit test for the ClipboardHandler added. + + + + + + IE is no longer supported. This implies the largest change of the code base during the last > 10 years. + More than 200 flags removed from the code and about 6.000 test case expectations adjusted. + And also many IE specifc classes are gone. + + + The removal of the IE support also implies that the ActiveX support is also gone. + + + Applets are no longer supported. This implies the AppletConfirmHandler and the applet related configuration + settings are also removed. + + + New subproject htmlunit-websocket-client. For the start this is a shaded version of the latest + Jetty 9 websocket-client. + + + + Chrome/Edge 123. + + + Firefox 124. + + + Upgrade Apache commons-io to 2.16.0. + + + Refactor pac file support and add missing convert_addr() function support. + + + The EncodingSniffer now uses the StandardEncodingTranslator from neko. + + + neko: Introduce property http://cyberneko.org/html/properties/encoding-translator to set the translator from + parsers. + + + neko: Introduce EncodingTranslator interface and switch the default encoding translator to the StandardEncodingTranslator. + + + Upgrade commons-logging to 1.3.1 + + + Fix <iframe> so that the parent charset is used when no charset could otherwise be found. + + + The number of prescan bytes of an HTML document is changed from 4096 to 1024 bytes to be in line with specs. + + + CSS @charset definition support added. + + + Treat 'x-user-defined'' in meta tag as windows-1252. + + + Fix the priority of BOM by moving it to the highest priority charset to be in line with html/xml/js/css etc. specifications. + + + Huge refactoring of the encoding handling. some methods of the EncodingSniffer are now deprecates; please have a look at the + javadoc for hints about possible replacements. + + + Fix for a ClassCastException in HtmlUnitNekoDOMBuilder (oss-fuzz). + + + Execution of script tags included in template tags parsed from js is different in chrome. + + + Template.content always returns the same object. + + + Ensure that reading more characters at the end of the buffer is not stopped due to the buffer appearing + being at the end with reading, rather we read till we get a -1. + Streams can deliver less than requested size and hence the buffer looks like it it almost finished, but it is technically not. + + + neko: XMLDocumentSource chaining is back. + + + neko: new feature http://cyberneko.org/html/features/scanner/plain-attr-values added. + + + neko: HTMLWriterFilter methods getPrintWriter(), hasSeenRootElement(), getElementDepth(), + and getNormalize() added. + + + core-js: fix return value when assigning to Symbol.__proto__. + + + core-js: [Symbol.species] support added to typed arrays + + + Update EncodingSniffer.ENCODING_FROM_LABEL with the latest at https://encoding.spec.whatwg.org/#names-and-labels + + + Fix the encoding detection for xslt transformations. + + + Image.onload() must be processed as postponed action. + + + core-js: [Symbol.species] for Promise fixed'. + + + core-js: [Symbol.species] support improved. + + + Stubs for element.scroll()/scrollBy()/scrollTo() added. + + + Invalid numbers are processed correct now when using the rowSpan/colSpan properties. + + + Whitespace gets removed from rowspan/colspan attributes when using rowSpan/colSpan properties. + + + Restore the ability to specify null as password value (regression in 3.4.0). + + + neko: infinity loop problem fixed while processing <plaintext> using document.write(). + + + Form elements available also when the form is detached from DOM (regression in 3.6.0). + + + Geoloction implementation changed, the location is now part of the WebClientOptions, means you can set the + location to an arbitrary position. + + + Upgrade Apache log4j-api to 2.23.0. + + + Fix a NPE when closing a top level window after the js engine was already stopped. + + + neko: Html elements inside and svg titles element do not close this title element. + + + neko: Parsing of self closing title tags inside a svg tag fixed. + + + websocket-client: jetty updated to 9.4.54.v20240208. + + + Spotbugs annotations removed - there was no real benefit from having them in the code. + + + + + + Fix NPE when defining a javascript constructor alias for a non existing constructor. + + + Method org.htmlunit.javascript.host.css.CSSStyleSheet.validateSelectors(SelectorList, int, DomNode) does not + forward the SelectorList to the implementation (regression from version 3.7.0). + + + Upgrade commons-codec to 1.16.1. + + + OrderedFastHashMap is now serializable. + + + neko: FastHashMap is now serializable. + + + neko: Fix the parsing of special tags (eg. title) - they consume all content until the matching + end tag is reached. + + + neko: Optimize the attribute handling a bit for faster processing. + + + neko: Deprecated feature "http://cyberneko.org/html/features/document-fragment" removed. + Please use "http://cyberneko.org/html/features/balance-tags/document-fragment" instead. + + + Avoid a NPE if an XmlHttpRequest response arrives while the client already shouts down. + + + Firefox 122: The MouseEvent provided to the oncontextmenu handler has an detail of 1. + + + Firefox 122: HtmlButton no longer ignores disabled state set at the beginning of the action. + + + Firefox 122: anchor pathname property adjusted. + + + Firefox 122: 'offsetPosition'/'offset-position' and 'textWrap'/'text-wrap' are supported. + + + Firefox 122: 'offset' default value is 'normal'. + + + neko: fix a regression in neko 3.11.0 regarding the handling of self closing unknown tags. + + + Fix potential NPE in HtmlPage.getElementById(String), HtmlPage.getElementsById(String), + HtmlPage.getElementByName(String), HtmlPage.getElementsByName(String), and HtmlPage.getElementsByIdAndOrName(String). + + + Chrome/Edge 121: The properties 'width' and 'offsetWith' returning correct results for the 'rt' tag. + + + Chrome/Edge 121: Default display style for the 'rt' tag is 'ruby-text'. + + + Chrome/Edge 121: Default display style for the 'ruby' tag is 'ruby'. + + + Edge 121: html/image accept-header mentions 'image/avif'. + + + Chrome/Edge 121: SpeechSynthesis/SpeechSynthesisVoice are available as globals. + + + Chrome/Edge 121: CSSMediaRule.insertRule() the second argument 'position' is optional. + + + Chrome/Edge 121: scrollbarColor/ scrollbarWidth style property added. + + + Bunch of dom performance updates. + + + Changing the input type when Javascript engine is disabled should not throw. + + + core-js: Correct implementation of Math.atanh. + + + core-js: BigIntLiteral.toSource includes suffix. + + + core-js: Limit the length of the string to be used for source code indentation to avoid + protect memory from overflow. + + + core-js: When an Array object's prototype is changed, disable the "dense only" optimization + to ensure that prototype properties are considered by standard operations. + + " + Detection and reporting of obsolete mime types for javascript files has changed to be in + sync with the spec and the current practice. + "text/javascript" is the correct; "application/javascript" is reported as obsolete. + + + neko: AbstractDOMParser fix an old bug in the (optimized) handling of text nodes + during dom construction - in some cases parts of the text got lost. + + + neko: HTMLScanner make sure endDocument() is called even if the <plaintext> node + is at the end of the document - otherwise the endElement calls for the parents are missing. + + + neko: DOMMessageFormatter possible NPE fixed. + + + neko: more performance updates. + + + neko: tag name scanner updated to match the real browsers. + + + HtmxOneNineTenScriptPreprozessor renamed to HtmxOneNineTenScriptPreProcessor. + + + + + + + Htmx 1.9.10 support when using the org.htmlunit.javascript.preprocessor.HtmxOneNineTenScriptPreprozessor. + + + core-js: arguments[Symbol.iterator] points to Array Array.prototype[Symbol.iterator]. + + + core-js: Array.prototype[Symbol.iterator] points to the 'values' functions. + + + neko: many test cases added to the parser. + + + neko: rewritten script tag content parsing to be in sync with the spec. + + + Make the output file handling of XmlSerializer.save(SgmlPage, File) more robust. + + + Suspicious code in WebResponseDate fixed. + + + BrowserVersionFeatures JS_OBJECT_ASSIGN and JS_WEAK_SET added. + + + Some BrowserVersionFeatures renamed: + STRING_INCLUDES -> JS_STRING_INCLUDES, STRING_REPEAT -> JS_STRING_REPEAT, + STRING_STARTS_ENDS_WITH -> JS_STRING_STARTS_ENDS_WITH, and STRING_TRIM_LEFT_RIGHT -> JS_STRING_TRIM_LEFT_RIGHT. + + + String.includes/startsWith/endsWith no longer throws a TypeError when the first argument is a regex + and Symbol.match of that regex has been set to false. + + + String.prototype.replaceAll implemented. + + + RegExp.dotAll flag implemented. + + + No longer throw an TypeError when RegExp.prototype.toString is called on a NativeObject. + + + Symbol.iterator property is now available on CSSStyleDeclaration/ComputedCSSStyleDeclaration. + + + SymbolConstants are readonly. + + + neko: frameset tags ignored in some more cases, handling of text before the frameset also fixed. + + + neko: frameset tags closing the head. + + + WebClientOptions.setMaxInMemory(int) should not create temp files if the limit is set to something <= 0. + + + core-js: Fix Math.clz23() rounding errors. + + + core-js: Reflect.construct() uses the wrong set of arguments if newTarget is set. + + + core-js: Receiver argument support added for Reflect.set(). + + + core-js: Reflect.construct() uses the wrong set of arguments if newTarget is set. + + + Improve content type detection for '.php' content. + + + neko: frames tags without a frameset parent are ignored. + + + neko: hr tag is allowed inside select's. + + + neko: unknown elements are always moved to the body. + + + Upgrade Apache log4j-api to 2.22.1. + + + Node.isEqualNode() implemented. + + + WebKitCSSMatrix aliases to DOMMatrix. + + + neko: RTC is an inline element. + + + neko: support early closing of cdata sections by >. + + + neko: support bang comments (--!> as closing sequence). + + + csp: Address deprecation of 'referrer'. + + + csp: Address deprecation of 'plugin-types' and 'prefetch-src'. + + + ScriptPreProcessor documentation added to the FAQ. + + + Bunch of refactorings to reduce the overall source code dependencies from core-js. + + + Make closing of windows more robust by making sure the deregistration is done also in case of errors. + This should fix some more memory leaks. + + + The return value of the (internal) method DomNode.getScriptableObject() was changed from + <T> to <T extends HtmlUnitScriptable>. This should remove some casts and + makes the code a bit more clean. + + + URL and anchor tag 'protocol' setter accepts also complete urls as parameter. + + + URL 'protocol' setter validates (FF, Chrome, Edge). + + + Details 'name' property support added (Chrome/Edge). + + + Because the naming of the method and parametes is misleading, the method + WebClientOptions.setSSLClientCertificate(InputStream, String, String) is deprecated. Please use + WebClientOptions.setSSLClientCertificateKeyStore(InputStream, String, String) instead. + + + Because the naming of the method and parametes is misleading, the method + WebClientOptions.setSSLClientCertificate(URL, String, String) is deprecated. Please use + WebClientOptions.setSSLClientCertificateKeyStore(URL, String, String) instead. + + + + + + + Upgrade commons-logging to 1.3.0 + + + Upgrade Apache commons-io to 2.15.1. + + + New subproject htmlunit-csp. This replaces shapesecurity/salvation. + + + Enable FEATURE_SECURE_PROCESSING for the MSXML XSLProcessor (CVE-2023-49093). + + + neko: fix wrong error processing for some unicode entities. + + + Resolve only link tags having a 'stylesheet' rel attribute when searching + for all styles of a page. + + + Upgrade Apache commons-lang3 to 3.14.0. + + + The new CSS3Parser pool implementation throws sometimes an illegal state exception + under load (regression from 3.8.0). + + + neko: incorrect handling of &#x and &#x; fixed. + + + neko: some incorrect HTML named entity definitions fixed. + + + neko: new HTML named entities parser that is up to 20x faster for common entities. + + + Upgrade Apache log4j-api to 2.22.0. + + + Some cleanup/simplification done for the way java objects are mapped to js objects. + + + + + + + core-js: support trailing commas in function parameters. + + + Content attribute value of a pseudo-attribute is no longer changed to lower case. + + + Updated CSS3Parser pool implementation with a different concept to allow more pooling, + lighter synchronization, and avoid leaks when not auto-closed. It also uses AutoCloseable + instead of Closeable (this is for IO, not for try-with-resource in general). + + + core-js: hashbang support added. + + + core-js: handling of object indices more in line with the spec. This repaces the fix + we had since 3.4. + + + core-js: allow updating of 'name' of a function, as required by the standard. + + + core-js: javascript 'Set' cannot handle wrapped java objects properly. + + " + Improved detection onf XML/XHtml content when not content type header is set. + + " + Internal method HtmlInput.setType(String, boolean) renamed to changeType(String, boolean) and + a return value added. Please check the javadoc if you use this. + + + + + + + INCOMPATIBLE CHANGE: For this version, the processing of WebWindowListener events got many changes/fixes/improvements. + The main point was to let this work as stable as possible even if many WebWindowListener are registred. Also the state + of the various WebClient properties should be clear in every case. This results in some minor changes the might have + some impact for the backward compatibility. + + + cssparser: Switched from JavaCC to ParserGeneratorCC (https://github.com/tulipcc/ParserGeneratorCC). + Based on this we have to chance to update the ParserGeneratorCC to fix some of our problems with + the generated code. See https://github.com/tulipcc/ParserGeneratorCC/pulls for more. + + + Properties ownerNode and href moved from CSSStyleSheet to StyleSheet. + + + Upgrade Apache commons-io to 2.15.0. + + + core-js: a no longer used switch removed + + + core-js: build system switched to maven + + + WebWindowListener javadoc updated to reflect the latest changes and include some words about common pitfalls. + + + Make sure the webClient is in a consistent state when the WebWindowListener events are fired. + + + Trigger WebWindowEvent for the initial WebClient window also if js is disabled. + + + Implementation of CSS pseudo classes :invalid and :valid improved. + + + Form.isValid() checks all form elements. + + + WebClient documentation enhanced. + + + Documentation about proxy setup integrated into the WebClient documentation. + + + Support ComputedCSSStyleDeclaration when JS engine is disabled. + + + test-javadoc removed from the website. + + + HtmlForm.getElements() is now part of the public api. + + + A bit more documentation about the two ways to disable the JavaScript engine added. + + + Remove proxy polyfill from the documentation because it is no longer available + (Proxy/Reflect support was added to core-js). + + + Upgrade Jetty to 9.4.53.v20231009. + + + Sending the correct content type of "application/pdf" for PDF files for form-multipart posts. + + + Fixed a major memory leak - frame windows (incl. iframes) are still referenced by the web client + window list after the parent was closed. In the end they are not garbage collected. + + + Upgrade Apache commons-net to 3.10.0. + + + 'rel' attribute may contain multiple values, we have to split before checking the value. + + + + + + INCOMPATIBLE CHANGE: WebClient.close() now really closes all windows and also + stops the js engine. This means you can't use the the webClient afterwards for browsing. + If you only like to cleanup all the window resources use WebClient.reset(). + + + New method WebClient.reset() added, this is like close() but restarting the js engine + and open a new empty window afterwards. + + + MochiKit 1.4.2 test suite added. + + + Upgrade Apache commons-io to 2.14.0. + + + Accessing form elements by id (e.g. myForm.elementId) searches only form elements and not + arbitrary descendants. + + + Form elements are all elements that belong to a form; not only the child elements. We now + take care of elements that use the form attribute to specify the associated form in many more places. + This means that the method HtmlForm.getLostChildren() is removed. You should always use the mehtod + HtmlForm.getElements() to get an list of all form-elements associated to that form (descendants or + using the 'form' attribute). This implies also that all the HtmlForm methods for searching elements + now working based on the getElements() method (also searching for elements associated to the form + based on the 'form' attribute. + + + The URLSearchParams ctor now supports also a sequence of name-value string pairs, + or any object with an iterator that produces a sequence of string pairs, + or a record of string keys and string values. + + + Implementation of FormData.forEach(), FormData.keys(), and FormData.values() added. + + + Symbol.iterator property is now available on FormData. + + + cssparser: 'only' is a valid class selector name. + + + core-js: Reflect.apply() now works also with primitive thisArgument (String, Number, Boolean). + + + Introduce Platform-FontUtil to encapsulate awt.font stuff for android support. + + + Several fixes for window.postMessage(). + + + core-js: some minor improvements for the Reflect support. + + + core-js: bunch of improvements for the Proxy support. + + + core-js: Array.of has to use defineOwnProperty instead of set. + + + core-js: Improved unicode support for the js source parser. + + + Upgrade Jetty to 9.4.52.v20230823. + + + Update batik-transcoder version to 1.17. + + + Try to make the WebClient.close() procedure more robust. + + + FF 116 now supports css page rules. + + + Method WebClientOptions.setSSLClientCertificateKeyStore(KeyStore, char[]) added. + + + + + + + INCOMPATIBLE CHANGE: Class org.htmlunit.html.DomTreeWalker removed; + use org.htmlunit.platform.dom.traversal.DomTreeWalker instead. + + + INCOMPATIBLE CHANGE: Method org.htmlunit.SgmlPage.createTreeWalker(Node, int, NodeFilter, boolean) removed; + use use org.htmlunit.platform.dom.traversal.DomTreeWalker.DomTreeWalker(DomNode, int, NodeFilter, boolean) instead. + + + INCOMPATIBLE CHANGE: Class org.htmlunit.SgmlPage no longer implements the + org.w3c.dom.traversal.DocumentTraversal interface; the method org.htmlunit.SgmlPage.createNodeIterator(Node, int, NodeFilter, boolean) + is therefore also removed. + + + INCOMPATIBLE CHANGE: Method org.htmlunit.html.HtmlImage.getImageReader() removed; + use org.htmlunit.html.HtmlImage.getImageData() instead. + + + INCOMPATIBLE CHANGE: Support for proxy polyfill removed. + + + + core-js: Support for Array.prototype.flatMap added. + + + core-js: Proxy implementation added. + + + core-js: format issues in Messages.properties fixed. + + + core-js: missing array limit check added + + + cssparser: 'inherit' is a valid class selector name. + + + core-js: Improved handling for NativeError instances when generating the console output. + Before this, when outputing NativeError instances the json serializer was used ending up in something like this '{"fileName":"source.js","lineNumber":426}'; + means the whole message was missing. This fix brings the output closer to the output of real browsers by writing the message and the stack trace. + + + htmx version 1.9.4 testsuite added. + + + neko: self closing textarea tag are now handled correctly. + + + neko: bunch of test cases added. + + + neko: XMLString now internally uses a StringBuilder instead of maintaining an char[] buffer. + + + neko: Code cleanup and more unused code removed. + + + neko: Use the same code style rules as HtmlUnit. + + + Always restore interrupted status when catching and ignoring InterruptedExceptions. + + + Adjust HtmlDialog handling for the changes done in Chrome/Edge/FF 115. + + + Upgrade Apache commons-lang3 to 3.13.0. + + + Fix batik version in images-howto. + + + + + + + Testsuite cleanup and consistency checks. + + + Support for rb and rtc tag added. + + + Document.releaseCapture() and Element.releaseCapture() having no return value. + + + htmx version 1.9.3 testsuite added. + + + NamedNodeMap methods getNamedItemNS(), setNamedItemNS(), and removeNamedItemNS() added. + + + NamedNodeMap, HTMLSelectElement/HTMLOptionsCollection and HTMLFormElement + are now iterable (for..of support). + + + Support for the toStringTag symbol added to all dom classes. + + + core-js: Two more fixes for symbol handling. + + + Fix parameter processing for document.evaluate(). + + + core-js: Negative integer index values must be handles as strings and not as integer. + + + Ctor HtmlUnitUsernamePasswordCredentials(String, String) is deprecated, please use + HtmlUnitUsernamePasswordCredentials(String, char[]) instead. + + + Several methods of DefaultCredentialsProvider are deprecated, please use + there counterparts expecting the password as char[] instead. + + + New methods StorageHolder.getLocalStorage(URL) and StorageHolder.getSessionStorage(WebWindow) to better + support testing the Web Storage API. + + + Documentation for working with the StorageHolder added (https://www.htmlunit.org/details.html#Local.2FSession_Storage). + + + Some code for the no longer available global storage removed from the StorageHolder implentation. + + + HttpWebConnection.downloadResponse(HttpUriRequest, WebRequest, HttpResponse, long) and + WebResponse.markAsBlocked(String) introduced to make some content blocking iml possible. + + + HttpWebConnection.downloadResponse(HttpUriRequest, WebRequest, HttpResponse, long) introduced + to make some content blocking iml possible. + + + Documentation for content blocking added (https://www.htmlunit.org/details.html#Content_blocking). + + + WebClientOptions.getHomePage() now points to https://www.htmlunit.org/. + + + WebClientOptions.setActiveXNative() is deprecated (like the whole IE). + + + HtmlElement autofocus property added. + + + Input elements value attribute handling fixed. + + + Input elements are now using a separate isValueDirty flag. + + + Various documentation fixes and migration guide updates. + + + New WebClientOption setTempFileDirectory() to specify a separate directory for + the temp file. + + + Upgrade Apache commons-io to 2.13.0. + + + core-js: Reflect.construct() support added. + + + + + + + core-js: Reflect implementation added (only construct() support is missing). + + " + Dialog tag method and properties added. + + + core-js: optimization - replace some language version checks with constant values + + + core-js: the PropertyDescriptor has an setter slot even if no setter function is available + + + core-js: the order of slots in the PropertyDescriptor is no in sync with the spec/browsers + + + Use Objects.equals() instead of StringUtils.equals(). + + + HtmlForm.getInputByValue and HtmlForm.getInputsByValue have to use + the value instead of the value attribute (regression in 3.0.0). + + + core-js: Support for Array.at added. + + + core-js: Support for Array.flat added. + + + nodeList[Symbol.iterator] === nodeList.values has to be true. + + + Symbol.iterator property is now available on URLSearchParams. + + + Putting both the @JsxSymbol and @JsxFunction annotations on the same method works properly. + + + Reflect's properties having an incorrect scope. + + + Some fixes for TextEvent and more tests. + + + Remove the no longer available properties ondevicelight, + ondeviceproximity, and onuserproximity from window (FF). + + + KeyboardEvent which property is IE only. + + + Body onmessageerror property has to be writeable in FF too. + + + Introduce AbstractRange and move the properties collapsed, startContainer, + endContainer, startOffset, and endOffset. + + + Meta media property has to be writeable in FF. + + + Marquee properties height, width, and bgColor are avilable in FF also. + + + Event type property is read-only. + + + ScreenOrientation onchange property has to be writeable. + + + Support of form property relList added. + + + Setter for form property rel added. + + + Nearly all screen properties are read-only. + + + Link relList property is setable. + + + Anchor relList property is setable. + + + Remove the superfluous origin setter for anchors. + + + The which property is moved up to the UIEvent for Chrome/Edge and FF. + + + MouseEvent which property is only available in IE. + + + The head property is defined on Document and not on HtmlDocuent. + + + Frameset onmessageerror property is setable in FF also. + + + neko: minor optimization of avoid object creation and some not required method calls. + + + Upgrade Apache commons-io to 2.12.0. + + + SOCKS proxy setup fixed. + + + + + + + Fix for the dom construction in some edge cases (oss-fuzz). + + + RTCSctpTransport stub added. + + + URLSearchParams.size property added. + + + SubmitEvent support added. + + + Avoid usage of org.w3c.dom.ranges.Range - this is not available on android. + + + Support unicode property escapes in regular expressions. + + + cssparser: Custom properties without values are valid. + + + + + + + INCOMPATIBLE CHANGE: CookieManager.getPort(URL) removed. Looks like + <a href="http://code.google.com/p/googleappengine/issues/detail?id=4784"> is solved. + + + core-js: Handling of java primitive types in EqualObjectGraphs are fixed. + + + neko: mention CVE-2023-26119 on the github page. + + + neko: HtmlTagBalancer.reset() now resets the whole state. + + + neko: fix search for message bundles (regression in 3.0.0). + + + Calls to hasOwnProperty() and getOwnPropertyDescriptor now taking care of form elements accessible from + the form object. + + + Document.getSelection() is defined for Firefox and IE also. + + + Document.getElementsByName() is defined for Firefox also. + + + Document.getElementsByName() returns a NodeList instead of a HTMLCollection. + + + HTMLCollections are iterable now - you can use them in for..of loops. + + + Regexp "[^]" and "[^]" break translation of later char ranges in the regex. + + + window.isSecureContext added. + + + neko: Template tags are valid inside the head. + + + neko: Script tags are valid inside select's. + + + neko: The dialog tag closes a p tag. + + + NPE fix for CSSStyleDeclaration.getPropertyPriority(). + + + Incorrect placement of character data outside the form if there is no closing form tag + (regression in 3.0.0). + + + Regexp "[^]" should match any character, including new line. + + + XMLHttpRequest post request for the same origin must include the cookies (regression in 3.0.0). + + + Use 'keep-alive' instead of 'Keep-Alive' for the connection header. + + + + + + + INCOMPATIBLE CHANGE: Value processing for input controls changed; typing now ONLY changes the value + but not the value attribute. As consequence all calls to setValueAttribute(..) have to be replaced by setValue() or type(). + + + INCOMPATIBLE CHANGE: HtmlButton.getAttribute() now returns the plain attribute value also for 'type' attribute + instead of returning 'submit' in case the attribute is not set. + + + INCOMPATIBLE CHANGE: xpath: All packages renamed from net.sourceforge.htmlunit.xpath to org.htmlunit.xpath. + + + INCOMPATIBLE CHANGE: neko: All packages renamed from net.sourceforge.htmlunit.cyberneko to org.htmlunit.cyberneko + and net.sourceforge.htmlunit.xerces to org.htmlunit.xerces. + + + INCOMPATIBLE CHANGE: cssparser: All packages renamed from net.sourceforge.htmlunit.cssparser to org.htmlunit.cssparser. + + + INCOMPATIBLE CHANGE: core-js: All packages renamed from net.sourceforge.htmlunit.corejs to org.htmlunit.corejs. + + + INTERNET_EXPLORER is deprecated. + + + core-js: Function.toString() now returns the source of the function without any reformating. + + + DocumentFragment methods childElementCount(), firstElementChild(), and lastElementChild() + are ignoring non element nodes. + + + Document readystatechange event was not triggered on page loading. + + + Style.item() function fixed. + + + Prevent sending cookies with preflight and cross-origin requests. + + + Remove well known ports from the WebRequest url. + + + Fix incorrect splitting of URLSeachParams when parameters contain url-encoded required characters like "&". + + + Implementation of URLSeachParams.forEach() added. + + + Implementation of Blob.stream() stub added; just throws UnsupportedOperationException. + + + Implementation of Blob.arrayBuffer() added. + + + xpath: again some unused code removed. + + + Always throw an UnsupportedEncodingException from all DataUrlDecoder methods to not bypass the general exeption handling. + + + StringIndexOutOfBoundsException when parsing invalid data url's (oss-fuzz). + + + Style and template tags are valid table childs. + + + Implement handling of the Cache-Control: no-cache directive. + + + Upgrade Jetty to 9.4.51.v20230217. + + + CSS selectors filtering the type attribute like button[type='submit'] fixed. + + + Fix NullPointerException when parsing using html with ignored head tags (oss-fuzz). + + + core-js: Setter function from property descriptor has to convert the args. + + + core-js: Preserving cause, when a JavaException is rethrown in JavaScript. + + + core-js: Fix name property for bound functions. + + + Document.evaluate() and XPathEvaluator.evaluate() now failing with a js exception + if something is wrong with the xpath. + + + Remove support for xpath function lower-case as this is not available in real browsers. + + + Take all Access-Control-Allow-Headers into account during XMLHttpRequest preflight auth. + + + neko: source/param/track are body tags. + + + neko: noscript can be part of the header also. + + + neko: Add audio/bdi/canvas/data/datalist/dialog/mark/meter/picture/progress/slot/time/output/video tag support. + + + neko: Select tags can only contain option/optgroup/template tags and text. + + + neko: Content inside the noembed tag is handled as text. + + + Fix ClassCastExceptions while parsing wrong html tags inside svg elements (e.g. <form>) (oss-fuzz). + + + Class com.gargoylesoftware.htmlunit.html.XmlSerializer is now public. + + + Bunch of fixes to attach input controls to the correct form during dom creation. + + + Many corrections for the dom generation for misplaced form or form controls inside tables. + + + neko: Close forms directly if they are at the wrong place inside a table. + + + neko: Augmentations converted into a tagging interface. + + + neko: code cleanup and unused features removed. + + + Enable FEATURE_SECURE_PROCESSING for the XSLT processor. + + + Document disabling of website certificate check in the FAQ. + + + + + + neko: Refactor XMLAttributes/XMLAttributesImpl to use a simple ArrayList<Attribute> as backend. + + + neko: Fix ArrayOutOfBoundsException when parsing using JDK 17 (oss-fuzz). + + + DocumentType properties entities and notations are only available in IE. + + + Methods append/prepend/replaceChildren added to Element. + + + Element.replaceWith() fixed for the case this was called without any new elements. + + + Another Xerces detection fix for JDK 17. + + + Missing properties addedNodes, removedNodes, previousSibling, and nextSibling added to MutationRecord. + + + Anchors are now taking care of the rel="noreferrer" attribute. + + + Form ref attribute implemented (Chrome and Edge) + + + Method com.gargoylesoftware.htmlunit.html.HtmlImage.getImageReader() is depracated (Android compatibility). + + + Package package com.gargoylesoftware.htmlunit.javascript.host.canvas.rendering renamed + to package com.gargoylesoftware.htmlunit.platform.canvas.rendering. + + + Package package com.gargoylesoftware.htmlunit.javascript.host.canvas.rendering renamed + to package com.gargoylesoftware.htmlunit.platform.canvas.rendering. + + + Methods com.gargoylesoftware.htmlunit.css.CssStyleSheet.parseSelectors(String) and + com.gargoylesoftware.htmlunit.javascript.host.css.CSSStyleSheet.parseSelectors(String) removed. + + + Reports generated by ElementOwnPropertiesTest and ElementPropertiesTest fixed. + + + Methods createGain() and decodeAudioData() moved from AudioContext to BaseAudioContext. + + + cssparser: many, many updates for parsing the :not() pseudo selector done - they are now + first class citicens for the parser and also for handling the selectors. + + + Fixed url parameter processing in history.replaceState() / history.pushState(). + + + Deprecated constants ABOUT_SCHEME, ABOUT_BLANK, and URL_ABOUT_BLANK removed from WebClient. + + + Class com.gargoylesoftware.htmlunit.html.DomTreeWalker is deprecated (Android compatibility). + + + Method com.gargoylesoftware.htmlunit.SgmlPage.createTreeWalker(Node, int, NodeFilter, boolean) + is deprecated (Android compatibility). + + + New class com.gargoylesoftware.htmlunit.platform.dom.traversal.DomTreeWalker; this class can only + be used with standard jdk - not on Android. + + + Fixed definition of the Location properties (they are defined on the object + itself instead on the prototype). + + + WebClient#loadHtmlCodeIntoCurrentWindow() now uses the + html parser instead of the xhtml parser. + + + neko: Fix Exception when parsing a template tag as first node (oss-fuzz). + + + Fix Exception when parsing documents with ignored head tags (oss-fuzz). + + + + + + Xerces detection fixed. + + + HtmlUnit is now regulary tested by Google OSS-Fuzz. + + + neko: Fix ArrayIndexOutOfBoundsException when parsing a incomplete + entity reference at the end (oss-fuzz). + + + Fix ClassCastException when parsing svg body tag (oss-fuzz). + + + Fix ClassCastException when parsing base element with namespace (oss-fuzz). + + + core-js: fix scope for bound functions called inside Promise.then(). + + + Cached location.hash was not updated by history.replaceState() / history.pushState(). + + + The url was not encoded by history.replaceState() / history.pushState(). + + + Inconsistent use of UrlUtils.encodeAnchor() / UrlUtils.encodeHash(). + + + neko: more unused code removed. + + + xpath: again some unused code removed. + + + + + + cssparser: typo when skipping a rule containing em values. + + + core-js: Many fixes for Object.assign(). + + + Replace \n in console output with real line break. + + + core-js: Make sure the placeholder replacements of console.log() is also done for ConsStrings. + + + core-js: console.log() ignores %c styling but updates the param count to not disturb further replacements. + + + Support for unicode point escapes added when converting regex from js to java. + + + Minor fixes for unicode handling when converting regex from js to java. + + + RequestParameter normalization should not replace KeyDataPair by NameValuePair. + + + Minor fixes for radio button validation to fit Chrome/Edge/FF instead of IE. + + + cssparser: support case-insensitively syntax for attribute values (https://www.w3.org/TR/selectors-4/#attribute-case). + + + Fix prototype for Intl.Collator, Intl.DateTimeFormat, Intl.NumberFormat, + and Intl.v8BreakIterator (regression from 2.64.0). + + + Browsers using windows-1252 if the content type header is charset=ascii. + + + Crypto.randomUUID() added. + + + neko: Fix handling of parser inserted tbody tags inside templates. + + + Upgrade Jetty to 9.4.50.v20221201. + + + Process cookies with negative max-age values to make sure the cookie store gets updated (in fact + this deletes an existing cookie). + + + Upgrade Apache HttpComponents to 4.5.14. + + + core-js: Constructor properties fixes. + + + Upgrade Apache commons-net to 3.9.0. + + + core-js: Descriptor of Function.length should be configurable. + + + neko: Use our own fork of xerces to get rid of some classpath problems because of the xml-api dependency. + + + + + + Support sameSite attribute when constructing a cookie. + + + Cookie toString() includes sameSite attribute if set. + + + Treat localhost as secure origin when processing cookies. + + + Take care of the fixed position style attribute at some places. + + + Remove some not required string operations from the DOMTokenList code. + + + Fixing change notification for the DOMTokenList in some situations. + + + DOMTokenList no longer adds an attribute to the dom node if remove is called an there + was no attribute so far. + + + AnimationEvent construction fixed. + + + core-js: classCastException in hasOwnProperty on NativeJavaObject fixed. + + + XPathResult determination of the resultType fixed. + + + numberValue() and stringValue() for an empty XPathResult fixed. + + + XPathResult.booleanValue() fixed. + + + xpath: correct return value when substring() is used with a negative length + + + xpath: fix error handling for invalid function arg count + + + + + + core-js: RegEx - fix the error message in case the quantifier maximum (second value) is smaller than the minimum (first value) + + + core-js: Remove usage of putIfAbsent() in the Hashmap class. This method does not exist on + many old Android releases and there's no real downside to removing it. + + + core-js: parent relationship in TaggedTemplateLiteral fixed. + + + StaticDomNodeList has to be serializable. + + + Lambda functions used by Element have to be serializable. + + + FunctionWrapper has to be serializable. + + + Avoid usage of ThreadLocal#withInitial for Android 7. + + + NamedNodeMap moved from com.gargoylesoftware.htmlunit.javascript to com.gargoylesoftware.htmlunit.javascript.host. + + + HTMLMediaElement.load() implemented as NoOp. + + + Support for HTMLMediaElement.src and HTMLMediaElement.currentSrc properties added. + + + nodeType and nodeName moved to HTMLMediaElement. + + + Simple mock for Performance getEntries()/getEntriesByName()/getEntriesByType() added. + + + htmx version 1.8.2 testsuite added. + + + HTMLMediaElement.canPlayType() now returns more realistic results. This might + help for some pages where the player src attribut is set from js only if the + media type is supported. + + + Method DomElement.setInnerHtml(String) added. + + + Fix generation of test-javadoc. + + + First simple implementation of NumberFormat.format() and NumberFormat.resolvedOptions() added. + + + Fix one more xsl transform issue when running without Xalan. + + + + + + Wrong dependency to htmlunit-xpath snapshot + + + There was still a dependency to Xalan. + + + + + + FF_ESR updatade from version 91 to 102. + + + com.gargoylesoftware.htmlunit.util.TextUtils removed. + + + Switch from xalan to htmlunit-xpath. + + + Upgrade Jetty to 9.4.49.v20220914. + + + Introducing a PrintHandler configurable at the WebClient. You can provide your + own Window.print() implementations if required. + + + A bug in one faq sample code that might result in wrong encoding is fixed. + + + Bunch of code cleanup for CSS handling. + + + + + + CSS pseudo selector :invalid improvements. + + + Number control processing of whitespace fixed. + + + Url/Email control processing of whitespace fixed. + + + Email control takes care of the min/max length property during validation. + + + Improved implementation of the ValidityState.isTooShort property. + + + Fix maxlength validation if the initial value is longer. + + + Upgrade salvation lib to salvation2 3.0.1. + + + Screen/ScreenOrientation property onchange added. + + + Screen property isExtended (Chrome/Edge) added. + + + Screen property orientation (and mozOrientation for FF) added. + + + ScreenOrientation properties angle and type added. + + + Various minor optimizations and some code cleanup. + + + Deprecated class SimpleScriptable removed. + + + Deprecated constant BrowserVersion.FIREFOX_78 removed. + + + Deprecated methods CSSStyleSheet.selects(BrowserVersion, Selector, DomElement, String, boolean) + and CSSStyleSheet.selects(BrowserVersion, Condition, DomElement, boolean) removed. + + + Various NullPointerExceptions fixed when calculation style properties for the html node itself. + + + + + + + window.event is a replaceable property + + + window.event should return undefined if called outside an event handler + + + Replace all XPath usages from our code because this might be called during dom tree + consturction and XPath sometimes fails if the tree got changed during xpath evaluation. + + + A bunch of code refactorings to avoid making inconsistent dom nodes visible in the dom tree. + + + Spotbugs annotations used in the code to supress some warnings. + + + Upgrade Apache log4j-api to 2.18.0. + + + + + + + Introduce HtmlInput.getValue() and HtmlInput.setValue(String). + + + core-js: Fix Object.getOwnPropertyDescriptors by fixing missing scope definitions. + + + core-js: Fix ClassCastException when using StringBuilder/Buffer. + + + core-js: Fix typeof for native classes with shared global scope. + + + Introduce new abstract class HtmlSelectableTextInput to to share text selection and typing support. + + + Correct the length of the resulting ArrayBuffer for XMLHttpRequest having a response type of 'arraybuffer' + if the response is gzip compressed. This also fixes an ArrayIndexOutOfBounds exception. + + + WebRequest.getParameters() normalizes null values to empty strings. + + + WebRequest.getParameters() now takes care of explicit set parameters for get requests also. + + + Ignore invalid css selectors (inside pseudo not) instead of throwing an exception. + + + core-js: Code cleanup and minor optimizations. + + + core-js: Better handling of Callables in NativeConsole. + + + Node.getRootNode() fixed for DocumentFragment itself and fragment children. + + + Window is no longer a callable. + + + Window.postMessage now supports arbitary js objects as message + instead of converting them into strings. + + + + + + String.toLocaleLowerCase() takes care of provided locale. + + + Button/Input formNoValidate propery added. + + + ValidityState.patternMismatch fixed. + + + Dispatching custom events now works for all DomNode's. This fixes also a NPE when running + the htmx 1.7.0 test suite. + + + Node.getRootNode() added. + + + Support for :focus-within and :focus-visible pseudo selectors added. + + + core-js: Did another hack in the code to tread const in for-of loop's like let. + + + neko: Some missing end-of-file checks added (this fixes possible IndexOutOfBounds exceptions). + + + neko: Possilbe OOM exception with broken input fixed. + + + core-js: JSON.stringify() fixes. + + + HTMLCollection IE only methods nextNode() and reset() removed. + + + Bunch of fixes for HTMLCollection and NodeList properties. + + + Use NativeConsole from core-js instead of our own implementation. As a side effect, + WebConsole.Formatter is no longer supported. + + + core-js: Using subarray() on a subarray produces incorrect results. + + + Add missing delegate methods to WebResponseWrapper. + + + Improved method and vaiable naming at some places. + + + INCOMPATIBLE CHANGE: Class MediaList was moved from package + com.gargoylesoftware.htmlunit.javascript.host.dom + into package com.gargoylesoftware.htmlunit.javascript.host.css. + + + New method WebRequest.getParameters() returning all parameters + (from the url and the body if available). + This change was required to fix some issues with Spring MockMVC. + + + Implementation of CSSPageRule selectorText setter added. + + + cssparser: Support page rule setSelectorText(). + + + docu: various fixes regarding using the sonatype snapshot repository. + + + Running the test suite fails on some newer maschines because Jetty is not happy + with tread pool limits setups in use. + + + 'Origin' header added to same-origin non-GET requests. + + + + + + core-js: ES2017 Object.getOwnPropertyDescriptors() implemented. + + + core-js: Fix Object.assign when undefined value and inextensible. + + + Worker.terminate() stub added. + + + CanvasRenderingContext2D ignores unknown colors. + + + HtmlFileInput.setValueAttribute(String) now handles an empty input as no file. + + + Make sure template content is not added to the dom during parsing; + only to the content document fragment. + + + Image.prototype setup fixed. + + + + + + Polyfill support documented. + + + Dedicated documentation of the WebClient/WebClientOptions and some more documentation updates. + + + Make sure to read sufficient byte for the encoding sniffer when the response is gzip encoded. + + + Handle bom header also for gzip'ed responses. + + + New web client option setProxyPolyfillEnabled() to automatically load a polyfill for the + proxy api into the client. + + + core-js: regex sticky support împlemented. + + + core-js: improved error msg about unsupported regex flags. + + + Jobs sheduled with the same targetExecutionTime are now processed in sheduling order. + + + New web client option setFetchPolyfillEnabled() to automatically load a polyfill for the + fetch api into the client. + + + FileReader readAsArrayBuffer() and readAsText() are working for blobs also. + + + Upgrade commons-codec to 1.15. + + + Introducing a ClipboardHandler configurable at the WebClient. If you need clipboard support + for entry fields set this to an AwtClipboardHandler. + + + Element.toggleAttribute() added. + + + Upgrade Jetty to 9.4.45.v20220203. + + + Document.body setter accepts Framesets. + + + + + + + neko: Switch to xerces 2.12.2. + + + asNormalizedText() uses the default style to determine blocks if css is disabled. + + + HtmlUnitScriptable code cleanup. + + + SimpleScriptable is deprecated, please use HtmlUnitScriptable instead. + + + Various fixes for the handling of select options when the select property changes. + + + checkValidity returns correct value for radiobuttons checked by js or the user. + + + checkValidity returns correct value if the checkbox was checked by js or the user. + + + core-js: Object.hasOwn added. + + + core-js: Support optional variable binding in catch. + + + core-js: RegEx handles {0} quantifier with max of zero correctly. + + + core-js: Date ctor now respects the timezone. + + + core-js: Promise.allSettled() added. + + + + + + + Quota simulation added to localStorage. + + + innerText ignores title content in most cases. + + + NPE when using the console in a special scenario fixed. + + + Formaction, formmethod, formtarget and formenctype no longer ignored on button without type attribute. + + + Fix duplicate classes inside our javadoc. + + + The caching algorithm now observe the max-age headers. + + + HTMLOutputElement form property added. + + + htmx testsuite changed to version 1.6.1 added. + + + Flash is no longer available in IE. + + + innerText ignores script children. + + + Script tags in DOMParser-created documents are not executed when adding to pages. + + + setCustomValidity() added. + + + Button of type submit/reset button does not submit if the onclick handler disables the button + for Chrome/Edge. + + + Submit/Reset button does not submit if the onclick handler disables the button. + + + Form noValidate property added. + + + Fix validation of decimal min/max/step values in number input. + + + Element.closest() function added. + + + Some text added to the web page to clarify js disable option. + + + willValidate property added. + + + htmx testsuite version 1.5.0 added. + + + Adjust selection if the selected option gets removed. + + + Fix validation for email input fields. + + + The browser locale (language) is now forwarded to the JS engine; this fixes + String.toLocaleLowerCase() if the locale is different from en. + + + File.lastModifiedDate uses the browser locale (language); + same for Date.toLocalDateString and toLocalTimeString. + + + Upgrade Apache log4j-api to 2.17.1. + + + + + + Fix charCode/keyCode for KeyPressEvent's when simulating Firefox. + + + core-js: Fix Array.from when called with a sparse array. + + + core-js: Improved BitInt support. + + + core-js: Fix return value of __lookupSetter__ with prototypes. + + + core-js: Fix regression when setting __proto__. + + + core-js: Fix some potential NPEs in Parser.java. + + + core-js: Fix invalid single quotes in French messages. + + + Some fixes for the code samples on the getting started page. + + + cssparser: Support for dimensions turn and quater added. + + + cssparser: hsl/hsla support added. + + + cssparser: Improved color parsing for rgb/rgba. + + + Fix request url encoding for script src. + + + FIREFOX_78 is now deprecated, use FIREFOX_ESR instead. + + + FIREFOX_ESR updated to Firefox 91. + + + core-js: Fix for compilation or try statements. + + + Links to issues and pulls on htmlunit webpage changes-report.html corrected. + + + + + + core-js: Fix problems with null "this" parameters in Function.prototype.call, + Function.prototype.apply, Function.prototype.toString, and Object.prototype.toLocaleString. + + + core-js: Messages now fall back to en in every case. + + + core-js: Fix support for BigInt in Hashtable + + + core-js: Improved JDK 17 support. + + + core-js: Replace 'new Integer/Double/Long' by Integer/Double/Long.valueOf. + + + neko: Switch to xerces 2.12.1. + + + Text content based width calculations in ComputedCSSStyleDeclaration now using the getVisibleText() + method to come closer to real browsers (e.g. whitespace is now removed). + + + neko: Switch to jUnit 5. + + + SimpleScriptable#setHtmlElement removed. + + + Deprecated method DomNode.asText() removed. + + + HTMLElement enterKeyHint property added. + + + HtmlSerializerVisibleText is now a bit more customizable. + + + Plus sign was replaced by a blank when found inside a data url. + + + HtmlSerializerVisibleText handling of different white-space style definitions improved. + + + Separate documentation page for proxy setup and authentication. + + + Support socks proxy authentication. + + + + + + core-js: Improve compile speed in some cases. + + + core-js: Avoid unnecessary arrayCopy in Kit.readStream, when initialBufferCapacity matches stream length. + + + core-js: Classcache must honor current security context. + + + core-js: Optimized XmlProcessor toXmlNewlines. + + + Fix innerText when the element has svg children. + + + HTMLElement.outerText added. + + + Fix innerHTML and outerHTML if one child node is a template. + + + neko: Fix some problems when parsing template content. + + + Navigator.languages added. + + + A short section about 'Multithreading/Threads Pooling' added to the web page. + + + WebClient.setExecutor(ExecutorService) added to make threading more flexible. + + + Use a CachedThreadPool instead of a FixedThreadPool for our executor service because the number + of WebSocket threads might block the whole execution otherwise. + + + Add missing support for XmlHttpRequest responseType and response properties. + + + Add missing request browser headers when setting location from js. + + + Xpath case sensitive processing was broken if an string inside the xpath contains []() or @. + + + Setting the value of an file input to an empty string should not trigger the on change. + + + core-js: Fix processing of SCRIPTABLE_UNDEFINED when used in string concatenation. + + + + + + XMLHttpRequest.send() has to serialize the body value if it is Document. + + + Finally support getting and setting style properties via elem.style['property-name'] notation. + + + Style property vertical-align now accepts also "baseline", "sub", "super", "text-top", "text-bottom", + "middle", "top", "bottom", "inherit", "initial", "revert"and "unset". + + + NativeMap's Map.entries() emulation no longer returns NativeMap.NULL_VALUE instead of actual null instance. + + + Use the CssErrorHandler configured at the WebClient for parsing inline styles also. + + + Assigning URL.search has to encode the given string. + + + If an URLSearchParams object is constructed from an URL all the changes have to update the url also. + + + URLSearchParams js object misses initialization of parent and prototype. + + + Fix detail value for PointerEvents. + + + Dependency HttpClient test-jar no longer required for the test suite. + + + + + + More detailed tests and some fixes for HtmlArea processing. + + + core-js: Two minor code optimizations regarding ConsString handling. + + + core-js: Delegator handling required for HtmlUnit is now part of Rhino. + + + core-js: Remove some no longer required changes from our Rhino fork. + + + Use our own simple Shape2D classes to reduce the java.awt dependencies. + + + Use our own simple color class to reduce the java.awt dependencies. + + + Element behaviors and HTML components (HTCs) have been removed from the code base. + It was removed more than 5 years ago from IE10. + (https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/hh801216(v=vs.85)?redirectedfrom=MSDN) + + + The new Apache commons-io to 2.11.0 is available but we are still at 2.20.0 because the new version seems + to have an regression (https://issues.apache.org/jira/browse/IO-744). + + + SVGMatrix no longer requires java.awt.geom.AffineTransform. Hope that helps + a bit on android. + + + CSSImportRule.styleSheet now returns the imported style sheet instead of the importing one. + + + CSS.supports() added - returns always true for now. + + + Inline styles are now parsed by the htmlunit-cssparser. + + + Upgrade Jetty to 9.4.43.v20210629. + + + CSSStyleDeclaration.item property added. + + + CSSStyleDeclaration.length is now correct for stylesheets. + + + CSSGroupingRule.insert() now sets the parent rule for the inserted rule. + + + PageRule style and selectorText property added. + + + Improved PageRule support. + + + CSSStyleDeclaration.parentRule property added. + + + Various CSS formatting fixes. + + + XMLHttpRequest-abort() triggers an error in Chrome/Edge if the send is aborted. + + + + + + XMLHttpRequest-abort() sets the state back to 0 and the webResponse to a network error. + + + core-js: Various fixes for undefined. + + + core-js: Support ES2019 JSON superset. + + + core-js: globalThis implemented. + + + core-js: Fix bug when calling function on custom global object. + + + CSSConditionRule.conditionText added (for CSSMediaRule). + + + CSSGroupingRule.cssRules, .insertRule() and .deleteRule() added (for CSSMediaRule). + + + CssParser: bring formatting closer to the browser. + + + MediaList default toString() now prints the media text. + + + Assigning a value to CSSRule.cssText is a no op. + + + HtmlImage.getSrc() added. + + + HtmlInput.getSrc() and HtmlImageInput.getSrc() added. + + + INCOMPATIBLE CHANGE: HtmlImageInput.getSrcAttribute() returns the plain value of the source attribute. + Use HtmlImageInput.getSrc() if you need the full qualified url. + If your code uses HtmlImageInput.getSrcAttribute() you have to + replace this with HtmlImageInput.getSrc(). + + + XMLHttpRequest preserves the content type header if sending a file an the header was set from the javascript. + + + Improved ComputedCSSStyleDeclaration regarding height and width for empty span's. + + + Improved ComputedCSSStyleDeclaration regarding image height and width. + + + Improved ComputedCSSStyleDeclaration regarding image height and width. + + + HtmlImage.getWidthOrDefault() and HtmlImage.getHeightOrDefault() added. + + + Frameset/HTMLTableSectionElement/HTMLTableCaptionElement outerHTML property is setable. + + + Translate response charset GB2312 to GBK like browsers do. + + + Setting window.clientInformation now works correct for Chrome/Edge and IE. + + + Setting window.innerHeight was broken because of an typo for a long time. + + + Properties without a setter defined are no longer setable - this was a hack introduced for IE6 + and is no longer valid. + + + Document.body is setable. + + + AudioParam value property is writable. + + + core-js: All "new Error" instances have a "stack" even if they are not thrown. + + + core-js: A number of small spec compliance issues with all the Error classes are fixed. + + + core-js: Make sure that the "name" and "length" properties of BaseFunction can have + their attributes be modified and be deleted if so configured. + + + core-js: Template support added. + + + core-js: Object.seal/freeze/isSealed/isFrozen logic got a few fixes. + + + core-js: Support indexed accessor properties. + + + core-js: Object.values / Object.entries / Object.fromEntries added. + + + core-js: Refactoring of the slot implementation. + + + Upgrade Apache commons-io to 2.10.0. + + + Page type detection was wrong if no content type header was set and some unicode + chars are present in the first bytes of an document. + + + ComputedCSSStyleDeclaration height property now returns "auto" for + invisible elements. + + + A simple version of getInnerHTML added for Chrome/Edge. + + + Console.trace() now prints the call stack. + + + Upgrade Jetty to 9.4.41.v20210516. + + + Fix a possible resource leak if ThreadDeath is thrown when closing the script executor. + + + + + + HTMLElement.innerText implementation is now closer to the spec. + + + core-js: Optimization of the + operator. + + + core-js: Small optimization for the increment/decrement operator. + + + core-js: Small optimization for the increment/decrement operator. + + + Document.contains(node) fixed. + + + Node.contains(node) returns false for null and undefined parameter values. + + + Error.stack lines are separated by LF only. + + + Some links to the 'The Java Web Scraping Handbook' added. + + + No longer throw an exception when DOM event name is used as function name. + + + core-js: fix duplicate entries of source files in htmlunit-core-js-2.x.0-sources.jar. + + + core-js: toNumeric speed improved. + + + core-js: Number.parseInt and Number.parseFloat are the same as the global functions. + + + core-js: Number.EPSILON implemented. + + + core-js: String.raw implemented. + + + core-js: Improve LengthOfArrayLike to operate on XMLObject. + + + core-js: BigInt support. + + + Anchor.protocol, Anchor.hostname fixes for various border cases. + + + URL properties hash, host, hostname, href, password, pathname, port, protocol, search, + username and function toJSON added. + + + core-js: Support numeric separator '_'. + + + URL.toString() now returns the same value as implicit converting. + + + URLSearchParams.toString() now returns the same value as implicit converting. + + + Upgrade Jetty to 9.4.40.v20210413. + + + Selection.toString() now returns the same value as implicit converting. + + + core-js: Improved JSON.stringify() implementation. + + + core-js: NPE fixed for code like for ({};;); + + + core-js: Improved shorthand assignment support + + + MediaDevices.getUserMedia() added - but other than in real browsers this always throws an error + because MediaStream's are not supported at the moment. + + + Navigator.mediaDevices property added. + + + Support for https proxies - the Webclient constructors are supporting a proxyScheme now. + + + Synchronize access to the WebSocketClient from the JettyWebSocketAdapter to avoid NPE. + + + + + + Clicking an anchor was always calling the attachment handler (if set). This was a regression from anchor + download attribute support. + + + + + + Fix :required and :optional pseudo classes to work with all html elements supporting the 'required' attribute. + + + HtmlDetails.asNormalizedText() and HtmlDetails.asVisibleText() fixed. + + + Support for the CSS3 ':invalid' pseudo class added. + + + HTMLDetailsElement supports setting the open property. + + + Method HtmlFileInput.setDirectory(File) added to support input elements with + type file and webkitdirectory attribute. + + + Cookies generated from client code now sent to subdomains also. + + + Anchors having the download attribute set are now passing the response into the AttachmentHandler + if there is one defined. + + + core-js: Make variable which has been defined null available in script. + + + core-js: Speed of bitwiseNOT improved. + + + core-js: Copying nodes in an XML tree no longer removes the source node. + + + core-js: Object.assign fixed. + + + Documentation for the animation frame support added. + + + Upgrade Jetty to 9.4.39.v20210325. + + + Execution of deferred scripts might fail if one script removes another. + + + + + + HtmlNumberInput checkValidity() fixes. + + + Upgrade Apache log4j-api to 2.14.1. + + + CI build for pull requests is available at https://jenkins.wetator.org/job/htmlunit/view/change-requests/. + + + Upgrade Apache commons-lang3 to 3.12.0. + + + Upgrade Jetty to 9.4.38.v20210224. + + + core-js: Array length limit check fixed. + + + core-js: Exponentiation operator support added. + + + FAQ updates. + + + Documentation for image file format support added. + + + A bunch of improvements for the CanvasRenderingContext2D.drawImage() implementations. + + + Improved handling of floats in CSSStyleDeclaration during value conversion. + + + core-js: Addition with string literal is now closer to the ECMAScript spec. + + + Upgrade Apache commons-net to 3.8.0. + + + DomNode#asNormalizedText() added to provide a more meaningful and stable normalization. + DomNode#asText() is now deprecated. + + + HtmlSerializerVisibleText moved into separate package 'com.gargoylesoftware.htmlunit.html.serializer'. + + + Image comparison integrated into our test environment based on https://github.com/romankh3/image-comparison. + We are able now to run the CanvasRenderingcontext2D test now as part of our CI build (and found already some issues) + + + Fix the font size used by the AwtRenderingBackend implementation. + + + Fix the AwtRenderingBackend implementation of clearRect to make it transparent instead of white. + + + Two convenience methods added: WebClient.loadHtmlCodeIntoCurrentWindow(String) and WebClient.loadXHtmlCodeIntoCurrentWindow(String). + + + Handle the anchor download property like Shift/Ctrl click - open a new window containing the downloaded content as UnknownPage. + + + HTMLInputElement.src is now setable also. + + + HTMLInputElement.src now returns the value in the context of the page. + + + + + + neko: Fix a regression from the improved table parsing done in 2.44.0. + + + + + + Defer attribute of scripts was ignored. + + + Window.scroll()/scrollTo()/scrollBy() now triggers a scroll event. + + + core-js: Reject old octal's in property names. + + + Location.reload() reloads to the wrong address when invoked across frames. + + + Return a rejected Promise rather than throw errors for all the methods in SubtleCrypto. + + + InputEvent constructor fixed. + + + core-js: Make property __proto__ writable for functions also. + + + core-js: Make property only having a getter readonly. + + + core-js: Make message handling variadic. + + + KeyboardEvent constructor fixed. + + + Fixes for (re) attaching iframes. + + + Fix handling of removal of the src attribute from frames. + + + Referer header url is without ref part. + + + Improved content sniffing for html pages. + + + The invocation order of events added to XMLHttpRequest, through both addEventListener() and on-handlers + is fixed, to be more consistent with major browser such as Chrome / FF / IE, as well as other events already + implemented in HtmlUnit that use EventTarget's framework. + + + Properties oncopy, oncut, onpaste, classList and hasAttribute, onselectionchange, + ontransitioncancel,ontransitionend,ontransitionrun and ontransitionstart fixed for many elements. + + + Various fixes for body element properties. + + + Setting onload attribute on body forwards to window. + + + Deprecated method HtmlLabel.getReferencedElement() removed. + + + + + + core-js: Fix bug with node position in labeled loops. + + + core-js: JSON.stringify with no arguments should return undefined. + + + core-js: JSON.stringify with more than 3 arguments should respect the first 3 arguments. + + + Fix detection of supported javascript types. + + + OWASP dependency-check added to the build process. + + + Document.cookies setter called with with blank does not reset the cookies in CHROME/EDGE. + + + core-js: Fix handling of MemberBox functions in getOwnPropertyDescriptor. + + + core-js: Fix Error.captureStackTrace(myError). + + + core-js: Fix __lookupGetter__/__lookupSetter__ implementation. + + + Support individual timeout settings for XMLHttpRequest. + + + Processing of href changes is synchronous if only the hash was changed. + + + Improved performance due to avoiding Script conversion into String only for naming the action. + + + core-js: Fix comment parsing in try and catch statements. + + + core-js: Make type checking and casting a bit more generic to provide better error messages. + + + Various fixes for handling of xml nodes by css selectors. + + + Element.getElementsByTagName is case sensitive for xml nodes. + + + CSS tag name selector is case sensitive for xml nodes. + + + CSS selector for hyphen separated attribute values '|=' now works as specified. + + + core-js: Fix parameter handling for Object.assign. + + + core-js: Fix the (confusing) exception msg if Object.prototype.setPrototypeOf is called with less than two parameters. + + + core-js: Fix JSON.stringify on a RegExp object; RegExp object is no longer callable. + + + core-js: Math.max/min - each element coerced. + + + Support setting the USER_AGENT header per WebRequset. + + + Constructor improved for StorageEvent, TimeEvent, TouchEvent, TrackEvent, TransitionEvent and WheelEvent. + + + + + + INCOMPATIBLE CHANGE: Method signature for AbstractJavaScriptEngine.initialize(WebWindow, Page) changed, + the method requires now the page as second parameter. + + + Property composed added to Event. + + + Properties linkColor, aLinkColor, vLinkColor, bgColor, and fgColor moved from HtmlDocument to Document. + + + CssParser: Generate correct type for rem dimensions. + + + CssParser: Support for the dimensions 'ch', 'vw', 'vh', 'vmin' and 'vmax' added. + + + CssParser: Back to JavaCC 7.0.4. + + + DeviceMotionEvent is available in IE also. + + + Upgrade Jetty to 9.4.34.v20201102. + + + Thenable prototypes support added. + + + MouseEvent.buttons property added. + + + UIEvent handling of view property improved. + + + Event, UIEvent and MouseEvent construction via new now handles the details dictionary more correct. + + + MouseEvent properties clientX. clientY and button are readonly. + + + AudioBufferSourceNode.start(), AudioNode.connect(). + + + AudioContext.createBufferSource() moved up to BaseAudioContext. + + + BaseAudioContext.createBuffer() added. + + + GainNode gain property added. + + + AudioParam value, defaultValue, maxValue and minValued added. + + + Promise.then() now supports also Thenables. + + + Validation pattern has to be ignored for empty values. + + + New configuration option AcceptLanguageHeader for the BrowserVersion. + + + Document.open() does not change the location of about:blank pages in FF. + + + Function clear() moved from HtmlDocument to Document. + + + Property all moved from HtmlDocument to Document. + + + Functions captureEvents() and releaseEvents() moved from HtmlDocument to Document for Chrome/Edge/FF/FF78. + + + Properties body, designMode, domain, forms, embeds, links, images, plugins, scripts, anchors and applets moved + from HtmlDocument to Document for FF/FF78. + + + Functions execCommand(), queryCommandEnabled() and queryCommandSupported() moved + from HtmlDocument to Document for FF/FF78. + + + Property parentWindow moved from HtmlDocument to Document for IE. + + + Property onreadystatechange and readyState removed from HtmlScript for IE. + + + Upgrade Apache commons-net to 3.7.2. + + + Property onshow is not available in Chrome/Edge. + + + Make sure the js initialization of the new page is finished before the page is + visible as enclosed page to the outside. + + + PointerEvent supports altitudeAngle and azimuthAngle property for Chrome/Edge. + + + Upgrade Apache HttpComponents to 4.5.13. + + + Method getPage(WebWindow, WebRequest, boolean) has to handle NoHttpResponseException + because this internal call is used by the WebDriver (regression from 2.44.0). + + + Upgrade Apache log4j-api to 2.14.0. + + + + + + Upgrade Apache commons-net to 3.7.1. + + + Upgrade Jetty to 9.4.32.v20200930. + + + Fix Rhino setup to avoid placing lazy load references to 'XML', 'XMLList', + 'Namespace', and 'QName' in the window scope. + + + Improved page cleanup when closing the WebClient; there was a leak if the enclosed page has + an onbeforeunload handler in place that avoids page unloading). + + + Fix some possible NPE when calling toString from js for Range or Location objects. + + + The console.log() output of Promise objects is now similar to Chrome. + + + core-js: Add missing attribute escaping for String.prototype.big and similar calls. + + + core-js: Make sure the this object is coercible for String.prototype.big and similar calls. + + + core-js: Object() constructor fix for non extensible functions. + + + core-js: TypedArray.prototype.subarray() should not throw an exception if called without parameters. + + + CssParser: JavaCC 7.0.9. + + + CssParser: JDK 1.8 is now required. + + + CssParser: var() support added. + + + CssParser: calc() support added. + + + Take care of the body if a post request is redirected based on a 307/308 response. + + + Setup of the js engine for the DedicatedWorkerGlobalScope improved/fixes. Some strange js errors + for scripts running inside the workers are now hopefully gone. + + + Scripts nodes are not moved out of tables. + + + neko: Fixes for tables inside tables and forms inside tables. + + + Added validation based on minlength/maxlength for input types password, search, tel, text, url. + + + Added validation based on min/max for input types date, datetime-local, month, number, range, time, week. + + + Added validation based on pattern for input types date, email, password, search, tel, text, url. + + + Event processing for XMLHttpRequest is rewritten. + Events defined using addEventListener are now supported and the triggered events are more correct. + + + Fix NPE during checkbox/radiobutton event handlers without JS engine. + + + Parameter encoding for string representation of URLSearchParams fixed. + + + core-js: Make __proto__ more closely match the spec. + + + core-js: NativeArrayBuffer slice() length is 2. + + + Possible NPE in HtmlPage.setFocusedEvent() fixed. + + + DOMParser.parseFromString no longer tries to execute script tags + contained in the given input. + + + Support for placeholder-shown / -ms-input-placeholder added. + + + Bunch of updates to be back in sync with the IE11 DateTimeFormat handling. + + + Improved height calculation; for elements having a fixed width + we will do word wrapping to generate a better height values. + + + Upgrade salvation lib to salvation2 3.0.0. + + + Support to send blobs via XMLHttpRequest.send() added. + + + FileReader.readAsDataURL() now works for Blob's also. + + + Blob.slice() supported. + + + Initial support for new Blob(bits[, options]);. + + + FormData.entries() support added. + + + neko: Setting innerHtml produces sometimes a stack overflow. + + + + + + Initial support for new File(bits, name[, options]);. + + + File.lastModifiedDate is no longer available in FF. + + + Using a node list directly inside a for..of operation is now supported like 'for (var entry of nodeList) {...}'. + + + URLSearchParams migrated to Rhino iterators also. Our own iterator implementation is now history. + + + Major rework for our NodeList implementation. The methods entries(), keys(), and values() returning + a better iterator implementation (now uses ES6Iterator from Rhino). Outside of some minor fixes this + implements for..of support. + + + Minor changes of AbstractJavaScriptConfiguration better encapsulate the used maps; + internal maps are now concurrent maps and no longer encapsulated as unmodifiable + to make access faster. + + + ClassConfiguration is changed a bit, the fields propertyMap_, functionMap_, + staticPropertyMap_, staticFunctionMap_ and constants_ are now lazy initialized + to save some memory. + + + Simulated screen resolution is now 1920x1080. + + + Fix prototype of parentElement property for IE. + + + core-js: Throw if the lastIndex prop of an regex is readonly. + + + core-js: Support RegEx[Symbol.match]() and RegEx[Symbol.search](). + + + core-js: Object.setPrototypeOf() arg[0] has to be coercible. + + + core-js: Reduce auto boxing, make some more methods static and general code cleanup. + + + core-js: String.prototype[Symbol.iterator].call(undefined) has to throw because undefined is not coercible. + + + core-js: Fix String.indexOf and String.includes when searching for an empty string. + + + DOMParser.parseFromString now supports the creation of HTMLDocuments also. + + + HtmlLink no longer stores the web response. + + + Improved encoding and BOM handling when loading a stylesheet. + + + FF60 support removed. + + + + + + core-js: Fix wrong start object for getter in Object.assign(). + + + core-js: No longer inherit strict mode when parsing a function body. + + + Fix NPE in XMLSerializer.serializeToString(). + + + Make sure XMLSerializer.serializeToString() serializes all elements + of a given document fragment. + + + Respect button 'formnovalidate' attribute. + + + core-js: Did a dirty hack in the code to disable parts of Rhino's const handling. + Hopefully a futher Rhino version will make some progress here and we get real + up to date const support. + + + core-js: Improved regex range handling. + + + core-js: String.trimStart String.strimEnd added. + + + core-js: String.fromCodePoint() added. + + + core-js: Bunch of fixes for JDK 11. + + + core-js: Regular expressions are not functions in the context of string replace. + + + core-js: Class 'BodyCodegen' moved into a file. + + + core-js: TypedArray constructors are only callable via new. + + + core-js: Improved handling of negative ArrayBuffer size. + + + core-js: code cleanup; use the RangeError construction helper, avoid autoboxing and new Double() calls. + + + Fix ClassCastException in Document.firstElementChild and Document.lastElementChild for + documents with doctype. + + + Document.readyState should be interactive in DOMContentLoaded event handler. + + + The method Crypto.getRandomValues misses a ArrayBufferView byte length check. + + + The method Crypto.getRandomValues has to return the modified array. + + + Upgrade Jetty to 9.4.30.v20200611. + + + core-js: Support for ES6 generators was added to Rhino. + + + + + + core-js: It should be not possible to change the prototype of a non-extensible object. + + + core-js: Fix handling of undefined parameter value in String.normalize(). + + + core-js: Improved regexp parser. + + + core-js: Function.__proto__ property ignores write access. + + + core-js: Fix Object.getOwnPropertyDescriptor for index properties on native strings. + + + Invoking getImageData with coordinates outside the drawing area no longer produces exceptions. + + + Support for setTimeout and setInterval added to DedicatedWorkerGlobalScope. + + + Maven Fluido Skin used for the web page updated to version 1.9. + + + core-js: Fix for a side effect between different regular expressions. + + + core-js: Many fixes for array calls using this pattern Array.prototype.foo.call(null, ....);. + + + core-js: Do not save/share an instance of NativeArrayBuffer in a static variable because this + creates side effects. + + + core-js: An error should be thrown when defining a property for a read-only variable in strict mode. + + + core-js: The values of present properties of a sealed object can be changed as long as they are writable. + + + core-js: Symbol.length should be 0. + + + core-js: Calling String.substr with undefined as length fixed. + + + core-js: Using a regex like a function should throw a TypeError. + + + core-js: Calling String.split with zero as limit fixed. + + + Upgrade Apache commons-io to 2.7. + + + Upgrade Jetty to 9.4.29.v20200521. + + + WebResponse.getContentAsString() fails for compressed responses because of the + BOM header detection. + + + Possible ArrayIndexOutOfBoundsException fixed. + + + HTMLTemplateElement.outerHTML() fixed. + + + Properly print HtmlTemplate's children via asXml. + + + Document getElementById(..) now returns null for elements inside a template tag. + + + Fix NPE getting event handlers without JS engine. + + + + + + New WebClientConfiguration option ConnectionTimeToLive added. + + + Fix for removing event listener from body. + + + Improve focus and blur handling. + + + HtmlLabel.getReferencedElement() is now deprecated. Use HtmlLabel.getLabeledElement() + instead. + + + Label form property has to work based in it's own form in IE11. + + + Label control property has to look for a nested labelable control as fallback if no for + attribute is given. Additionally it is not available in IE11. + + + Better handling of recursive iframes content. + + + Fix exception when handling invalid body element with no JS engine. + + + Fix frameset exception with no JS engine. + + + Label form property has to work based on the element labeled by the label. + + + Fix possible ConcurrentModificationException when cloning an HtmlPage / HtmlElement. + + + Respect Content-Security-Policy: frame-ancestors when loading frame content. + + + Respect X-Frame-Options: DENY when loading frame content. + + + Fix SvgScript NPE when script engine not available. + + + Upgrade Jetty to 9.4.28.v20200408. + + + Fix NPE in image onload handler processing. + + + HTMLFormElement.requestSubmit() for FF and CHROME added. + + + New method AttachmentHandler.handleAttachment(WebResponse) added. By implementing your + own AttachmentHandler you now can process the attachment response by your code without + opening a new WebClinet window. + + + + + + Neko: fix encoding of blanks in file uri's. + + + DedicatedWorkerGlobalScope now extends EventTarget. + + + Upgrade Apache commons-lang3 to 3.10. + + + Functions atob() and btoa() added to the worker scope. + + + FrameContentHandler added to support stop loading of frame content. + + + Make the shutdown processing of the JavaScriptEngine more robust to avoid exceptions + when accessing the engine while the shutdown was already triggered. + + + CanvasRenderingContext2D transformation handling fixed. + + + AwtRenderingBackend log improved, every backend is now identified by an unique number. + + + Detailed debug log added to the AwtRenderingBackend. + + + Text positioning in CanvasRenderingContext2D.fillText() fixed. + + + CanvasRenderingContext2D.save() does not set the saved values to defaults. + + + CanvasRenderingContext2D.save() / restore() takes care of the clip region. + + + Enum com.gargoylesoftware.htmlunit.javascript.configuration.BrowserName removed. + + + FIREFOX (latest) support added. Like we already do for CHROME we will support + the recent version of Firefox in addition to at least one ESR version. + + + HtmlLabel.getReferencedElement() now also supports HtmlButton, HtmlMeter, + HtmlOutput, HtmlProgress, HtmlSelect and HtmlTextArea in nested variant + and ignores not labelable elements in both variants. + + + WorkerGlobalScope.importScripts() now checks the content type of the + script to import. + + + First simple implementation for the anchor download and shape property added. + + + BrowserVersion FIREFOX_60 is now deprecated. + + + Deprecated constructor WebRequest.WebRequest(URL, String) removed. + + + + + + Upgrade Apache HttpComponents to 4.5.12. + + + Improved color parsing to support hsl colors also for + CanvasRenderingContext2D strokeStyle and fillStyle property. + + + Make the type() processing more robust if the value of the control was + changed directly without updating the selection. + + + Major parts of CanvasRenderingContext2D.clip implemented. + + + Use the correct color table for CanvasRenderingContext2D.fillStyle and + CanvasRenderingContext2D.strokeStyle. + + + Fix StringIndexOutOfBoundsException when calculation text for dom nodes. + + + Support linking of submittable elements to a form via the form attribute. + + + Methods firstElementChild() and lastElementChild() are no longer + failing because of a ClassCastException when calling for an xml document. + + + CanvasRenderingContext2D.putImageData() implemented. + + + ImageData constructor implemented. + + + CanvasRenderingContext2D.createImageData(ImageData) implemented. + + + CanvasRenderingContext2D.createImageData(width, height) implemented. + + + CanvasRenderingContext2D.getImageData() takes a snapshot of the current context. + + + Support for link property 'relList' implemented. + + + Support for area property 'relList' implemented. + + + Support for area property 'rel' added. + + + Support for anchor property 'relList' implemented. + + + Support for anchor property 'username' and 'password' added. + + + HtmlNumberInput accepts decimals. + + + New switch WebClientOptions.isWebSocketEnabled() added. This removes the WebSocket slot + from the Window object. If you disable WebSocket support for your client, the + jetty libraries are no longer requires. + + + AttachmentHandler.isAttachment(WebResponse) has to check case insensitive. + + + Neko: Make sure rewind is working in all cases. + + + + + + Security: prevent Rhinos access to Java resources; e.g. call java methods. + + + Upgrade Apache HttpComponents to 4.5.11. + + + XSLTProcessor now respects the xsl:output indent='yes' setting when simulating chrome. + + + Upgrade Jetty to 9.4.26.v20200117. + + + DocumentFragment.getElementById() added. + + + DocumentFragment methods childElementCount(), firstElementChild(), and lastElementChild() are no longer + failing because of a ClassCastException. + + + Resync core-js with rhino trunk (2019-11-25). This includes some improvements to iterable processing. + + + The entity processing was broken if an '&' was in front of a tag like </div>&X</div>. + + + Promise.all() and Promise.race() are now able to work with iterables instead of only supporting + arrays. + + + Upgrade Jetty to 9.4.25.v20191220. + + + Try to make stopping of the WebSockets more robust. + + + Some documentation added for file upload. + + + Upgrade Apache log4j-api to 2.13.0. + + + CanvasRenderingContext2D.globalAlpha implemented. + + + Angle handling for CanvasRenderingContext2D ellipse and arc fixed. + + + No longer use annotations for the implementation of isReadOnlySettable to + make the code simpler and faster. + + + CanvasRenderingContext2D.ellipse(..) implemented. + + + DOMRectList is visible. + + + Resync core-js with rhino trunk (2019-11-25). This fixes a bug regarding isExtensible handling. + + + Browser specific vAling handling fixed. + + + Do not create js peers during html parsing if js is disabled. + + + Some neko updates and some caching to use less objects and memory during html parsing. + + + Firefox 68 ESR simulation now available. + + + More robust color parsing. + + + CanvasRenderingContext2D.closePath() implemented. + + + Upgrade Jetty to 9.4.24.v20191120. + + + MockWebConnection.getRequestedUrls() added. + + + Respect form 'novalidate' attribute. + + + Resync core-js with rhino trunk (2019-10-19). + + + Img elements in forms are accessible directly using the name also when nested. + + + WebClient#openWindow no longer throws a ClassCastException when called from a non html page. + + + Wrong encoding used in window.atob(). + + + File input with required attribute now validates correctly. + + + Upgrade Apache HttpComponents to 4.5.10. + + + + + + INCOMPATIBLE CHANGE: WebConnection.close() and WebConnectionWrapper.close() are throwing an + IOException instead of an Exception now. + + + Method isAttachment(WebResponse) moved from Attachment to the AttachmentHandler interface + as default method. Based on this you can now overwrite the isAttachment(WebResponse) + implementation with your own. + + + FIREFOX_52 is deprecated. + + + Correct handling of media properties without values. + + + Console.assert(..) added. + + + Do not start the (Default)JavascriptExecutor if javascript is disabled for the client. + + + New method com.gargoylesoftware.htmlunit.Cache.clearOutdated() to remove outdated entries. + + + Make responses cachable in case the Cache-Control header with max-age or s-maxage overrules the Expires header. + + + Javascript Proxy stub removed. The class is only a stub an might confuse feature detections code + that only checks for existence. + + + Brotli support added. + + + Class XPathUtils renamed to XPathHelper. + + + Class XmlUtil renamed to XmlUtils and moved to com.gargoylesoftware.htmlunit.util. + + + Class TextUtil renamed to TextUtils and moved to com.gargoylesoftware.htmlunit.util. + + + ArchUnit added. + + + Log no longer a warning for not supported link types. Instead log more detailed debug messages + for this case. + + + Fix NPE for some unsupported css hacks. + + + Add a save() method in TextPage, which knows to save in the same charset as was received in the response. + + + Upgrade Apache commons-text to 1.7. + + + HtmlPage.save(File) no longer fails if some linked resources are not available. + + + Link to sourceforge mailing lists fixed. + + + MessageEvent.initMessageEvent() port parameter checking fixed. + + + Improved offsetTop calculation. + + + Trigger the correct event listener if a script tag points to an url that returns 204 (no content). + + + WebSocket onOpen event handler is called with the event as parameter. + + + WebSocket events are initialized with correct srcElement and origin. + + + Cleanup our logging setup; slf4j dependencies removed, log4j2 is now used for all the tests + of log output. + + + Fix the referrer and origin header when the request was created from window.location.reload(). + + + AudioContext.createBufferSource and a simple AudioContext.decodeAudioData added. + + + Revert a minor change to ensure backward compatibility with older jetty versions. + + + neko: Handle the (invalid) comment close tag '--!>' like the valid one regarding to the + spec (https://html.spec.whatwg.org/multipage/parsing.html#comment-end-bang-state) + + + XMLHttpRequestEventTarget has no ctor. + + + Properties onError and onLoad moved from XMLHttpRequest up to XMLHttpRequestEventTarget. + + + Clicking a label with a valid for attribute does not forward the click to the target + if the target is disabled. + + + Code cleanup and some resource handling fixes for HttpWebConnection. + + + + + + Upgrade Apache commons-lang3 to 3.9. + + + Upgrade Apache HttpClient to 4.5.8. + + + StackOverflowError during javascript processing are now handled like other javascript errors. + Only the JavaScriptErrorListener gets informed. + + + Make the processing of request headers more correct and document the general idea. + + + Log a warning, if click() is a no-op because the target element is disabled or not displayed. + + + Fix an error in the url circle detection when loading frame content. + + + Avoid scientific notation when converting float back to strings (CSSParser) + + + Logging documentation updated. + + + INCOMPATIBLE CHANGE: JavaScriptErrorListener interface defines one new method + warn(String, String, int, String, int). + Please add an implementation to your own implementations of this interface. + + + INCOMPATIBLE CHANGE: DefaultJavaScriptErrorListener now logs all messages. + + + Class SilentJavaScriptErrorListener added. + + + JavaScriptErrorListener is no longer saved from the HtmlUnitContextFactory to be sure + to use always the currently configured one. + + + Class com.gargoylesoftware.htmlunit.javascript.StrictErrorHandler removed. + + + Class com.gargoylesoftware.htmlunit.javascript.StrictErrorReporter removed. + + + core-js: some array length border cases fixed + + + core-js: array length null/undefined fixed + + + core-js: array includes added + + + core-js: array padStart and padEnd added + + + Image handler are processed (again) if an image is imported into a new document. + + + Page of the imported node fixed when importing. + + + There is no need for a window if constructing a new event handler. + + + Fix NPE when getting the baseUrl from a page created using DOMImplementation.createHTMLDocument(). + + + Invalid urls with the about protocol (e.g. about:htmlunit) are now throwing a MalformedURLException + to be handled like any other IOException. + + + HtmlRangeInput improvements. + + + Input element with type date now stores the value typed in. + + + + + + Fix insert position for elements with contenteditable='true'. + + + Send 'image/png' as mime type when uploading a png file. + + + + + + CSS declarations in CDATA sections are not processed for XHtml and Xml pages. + + + Script code in CDATA sections are not processed for XHtml and Xml pages. + + + Neko-HtmlUnit parser: entity reference handling rewritten according to the spec. + All specified character references are now supported and a bunch of fixes where + also made for numeric references. + + + ClassList.toggle/add/remove should take care of the HtmlAttributeChangeListener. + + + Audio node created from js now supports nodeType and nodeName property. + + + Upgrade Apache HttpClient to 4.5.7. + + + Avoid the try to add a response to cache if the response is already from cache or an redirect. + + + Fix caching for redirected calls. + + + Some fixes for broken attribute processing done in neko-htmlunit. + + + JavaScriptExecutor is no longer serializable. + + + FileReader.readAsText() added. + + + Major cleanup of the htmlunit-cssparser; all the references to the w3c classes are removed. + This avoid a lot of instanceof/cast processing and will make it simpler to enhance the parser + in the future. + + + New method Window.animateAnimationsFrames(). Use this to force one animation cycle. + + + Huge improvement for CanvasRenderingContext2D; we have working path handling and transformations now. + + + Another Rhino update; Array.fill, Array.keys, Array.entries, and Array.values is now supported. + + + HtmlPage.save(File) and XmlSerializer.save(SgmlPage, File) are using the correct file encoding. + + + No longer fail if the generated bytecode for method exceeds 64K limit; + we (Rhino) will fall back to the interpreter mode. + + + We are using the Map/Set/WeakMap/WeakMap implementation from Rhino now, our own impl is gone. + + + Improved support for insecure socket connections; InsecureTrustManager now + extends X509ExtendedTrustManager instead of implementing only X509TrustManager. + + + Fix Promise.resolve() called with an object having no 'then' slot. + + + Fix handling of invalid values in media queries. + + + Browsers are supporting GMT time format for cookie expires parsing. + + + Fix calculation of absolute url from relative one if dots present. + + + Setting the innerHtml has to clear the computed styles to force recalculation + based on the new content. + + + Map and Set forEach() are using undefined as this context in strict mode. + + + Stub impl of DateTimeFormat.resolvedOptions() added. + + + Correct handling of content type 'no-gzip' and 'gzip-only-text/html'. + + + Reworked JS event listeners implementation; many incompatibilities with + all supported browsers are fixed. + + + Maven Fluido Skin used for the web page updated to version 1.7 + + + + + + INCOMPATIBLE CHANGE: ScriptResult.getNewPage() is no longer available. You can use something like + webClient.getCurrentWindow().getEnclosedPage() instead. + + + Source repository is on GitHub now. + + + Input tel/search/number now fires the oninput event. + + + Reworked JS event listeners implementation; many incompatibilities with + all supported browsers are fixed. + + + Maven Fluido Skin used for the web page updated to version 1.7 + + + Improved calculation of the left offset. + + + We are using the typed array implementation from Rhino now, our own impl is gone. + + + Method Date.toUTCString() is available in Rhino; remove our own impl. + + + Fix the order of the windows returned by WebClient.getTopLevelWindows() + to be again the same as WebClient.getWebWindows(). + + + Improved support for javascript named function expressions (core-js). + + + DomNodeIterator no longer traverses uncles of root node. + + + Add missing default delegating methods getContentLength(), cleanUp(), and defaultCharsetUtf8() + to WebResponseWrapper. + + + Major cleanup for neko and switch to xerces 2.12.0 + + + + + + Event listeners had to be functions, other types are ignored. + + + Setting window.clientInformation is ignored in IE. + + + HTMLxxxInput.reset() results in a wrong state of the selection delegate. + + + FF60 ESR support. + + + FF45 support removed. + + + Many fixes for document.createEvent('xxx') to support the various UI events. + + + Correct handling of additional parameters provided in functions setTimeout/setInterval. + + + NPE in HtmlTextArea.removeFocus(). + + + WebClient default request header should not overwrite request-specific ones. + + + Various fixes for the selector specificity calculation (CssParser). + + + + + + core-js is now in sync with the latest Rhino codebase. + + + Use Rhino/core-js now es2 mode (instead of using rhinos outdated default mode). + + + Use Rhino/core-js Symbol implementation instead of our own one. + + + Various updates/fixes for the typed array support. + + + Set constructor now supports parameters of type iterator also. + + + document.fonts added. + + + BrowserVersion: deprecate FIREFOX_45. + + + Navigator.doNotTrack fixed, property is available in Chrome too, Window.doNotTrack added for is available for IE. + + + Special handling of the GAE environment is no longer required, the JDK8 at GAE has no longer + any restrictions. + + + + + + Improved clone implementation to take care of references. + + + Setting the Map size property is now ignored (or throws a Type error in strict mode). + + + Setting the CSSStyleDeclaration length property is now ignored (or throws a Type error in strict mode). + + + Setters for window.innerWidth/Height and window.outerWidth/Height added. + + + Redirect of head requests should be head requests also. + + + Use the correct content type when guessing from the '.js' file extension. + + + Major refactoring of the css handling (selector processing). Every style sheet now has + a selector index to speed up style processing. + + + We have now our own cssparser (a cleaned up version of the cssparser we have used so far) + to be able to change the model classes to better support our use cases. + + + getArttibute is optimized for speed in some special cases. + + + Local files are now cached using the same rules as server requests + (cacheable if date-modified is more than ten minutes in the past) + + + Our page cache now takes care of Cache Control headers. + + + Fix incorrect encoding of consecutive '%' characters in url's + + + RegExp: fix processing of /[]/ and /[^]/. + + + Handling of invalid processing instructions fixed in neko. + + + Fix some problem to be able to run our test suite with edge. + + + JavaScript: WeakSet and WeakMap constructor now supports user defined iterators also. + + + Doing Ctrl+Click on an anchor now opens a new window also if the href is javascript based. + + + JavaScript: Setter for history.scrollRestoration added. + + + Fix the broken initialization of the canvas context that empties the canvas every time canvas.getContext("2d") was called. + + + JavaScript: Set and Map constructor now supports user defined iterators also. + + + JavaScript: Array.from() now supports user defined iterators also. + + + Samples on page Get Started updated. + + + NPE in com.gargoylesoftware.htmlunit.html.HtmlPage.cleanUp(). + + + JavaScript: URLSearchParams implementation finished (entries(), keys(), values()). + + + JavaScript: URLSearchParams parser fixed (handling of '=' as first char of a part). + + + JavaScript: Invalid 'Origin' header was sent as part of XMLHttpRequest + if the request url was absolute and the page contains a base tag + + + JavaScript: CSSStyleSheet#addRule fixed error handling + + + JavaScript: CSSStyleSheet#addRule fixed return value when simulating ie + + + JavaScript: CSSStyleSheet#insertRule improved error handling + + + JavaScript: CSSStyleDeclaration#cssText throws an NPE when in stylesheet mode + + + JavaScript: CSSStyleDeclaration#cssText usually return a ';' after the last rule + + + + + + JavaScript: TextEncoder/TextDecoder impl added. + + + JavaScript: MutationObserver fires callbacks asynchronously + + + JavaScript: Promise has to provide the same context setup as the rest + and call processPostponedActions afterwards + + + If the coords of an image map entry are not valid ignore this entry. + + + JavaScript: calling click() from js should always work even if the control is not visible. + + + JavaScript: Crypto.subtle added + + + WebClient.setWebStartHandler() and the interface WebStartHandler added. Create your implementation + of this interface to support WebStart links. + + + JavaScript: CanvasGradient.addColorStop() added + + + JavaScript: CanvasRenderingContext2D.createRadialGradient() now returns an CanvasGradient + + + JavaScript: CanvasRenderingContext2D.createLinearGradient() now returns an CanvasGradient + + + Check option cssEnabled before downloading a css file (regression from 1927). + + + JavaScript: Error.captureStackTrace is not available in FF and IE. + + + JavaScript: location.reload uses the same request method like the original request. + + + JavaScript: WebSocket constructor call failed with a NPE when called during page construction. + + + JavaScript: fix Number.toLocaleString() to be able to support locale strings like 'en-US'. + + + JavaScript: performance.navigation.toJSON() added. + + + JavaScript: URL.searchParams added. + + + New configuration settings webSocketMaxTextMessageSize, webSocketMaxTextMessageBufferSize, + webSocketMaxBinaryMessageSize, and webSocketMaxBinaryMessageBufferSize. + + + JavaScript: URL constructor and origin property added. + + + + + + The link tag now supports the onLoad and the onError handler. + + + The link tags are now loaded at page initialization. + + + Link tags added to the page from javascript are now resolved directly. + + + CSS: cssparser updated to 0.9.24. + + + JavaScript: document.currentScript added. + + + Selector specificity calculation fixed for selectors using the general sibling combinator (~). + + + JavaScript: window.onerror provides now a valid error object. + + + JavaScript: throw a type error if the url property is requested from the WebSocket prototype. + + + JavaScript: simple impl for CanvasRenderingContext.fillText added. + + + JavaScript: various fixes for the Promise implementation. + + + JavaScript: writing to an iFrame triggers the onload event now for chrome also + + + JavaScript: navigator.productSub now returns the same value as simulated browsers + + + JavaScript: fix for a strange side effect in Range.getClientRects() and Range.getBoundingClientRect(). + Both calls have removed all nodes inside the range from the document. + + + JavaScript: fix handling of negative buffer sizes for the ArrayBuffer ctor. + + + JavaScript: getComputedTextLength() support added for svg text elements. + + + JavaScript: document.createElementNS is now able to create svg elements also. + + + JavaScript: support NetworkInformation (Chrome only at the moment). + + + JavaScript: support FileReader.readAsArrayBuffer(). + + + JavaScript: support FileReader.readAsDataURL(). + + + ProxyAutoConfig: fix isInNet(). + + + There is an option for IE that enables/disables the sending of the + complete file path when uploading a file. Starting with this version + we simulate this in disabled state like the default setting for the + internet zone. + + + BrowserVersion.clone now copies the system-timezone attribute. + + + INCOMPATIBLE CHANGE: BrowserVersion is final now and all constructors are removed. + The only way to create new customized Browser versions is by using the BrowserVersionBuilder. + + + BrowserVersion setter methods are fluent now. + + + DomElement: Fix .getChildElements(). + + + Remove deprecated HtmlFileInput.setValueAttribute(String[]), HtmlInput.click(int,int), + SgmlPage.getPageEncoding(), WebRequest.setCharset(String) and WebResponse.getContentAsString(String). + + + Fix Location header if it has non-ASCII characters. + + + JavaScript: fix ClassCastException in Array.from. + + + Support for form attributes formaction, formmethod, formtarget and formenctype added. + + + JavaScript: fix ClassCastException when calculating offsetHeight. + + + Take care of label elements during event bubbling; they have to trigger a click event for the associated element. + + + JavaScript: fix window.getComputedStyle() pseudo handling if pseudo param starts with double colon. + + + We are simulating the 64 bit version of Firefox 52 ESR and CHROME now. + + + More appropriate browser appVersion. + + + JavaScript: fix Number.toLocaleString(). + + + JavaScript: SVGMatrix operations (flipX, flipY, inverse, multiply, rotate, rotateFromVector, + scale, scaleNonUniform, skewX, skewY, translate) implemented. + + + + + + JavaScript: fix Array out of bounds Exception in insertBefore implementation when calling without any parameters. + + + JavaScript: implement Array.from(). + + + CSS: cssparser updated to 0.9.23. + + + JavaScript: implement Element.matches(). + + + JavaScript: implement .before(), .after() and .replaceWith(). + + + Simulated system time zone is now configurable (BrowserVersion.setSystemTimezone()). + + + JavaScript: fix Set/Map with undefined value. + + + Stack property was not set when new Error() was called from js. + + + Fixed wrong dom tree because of duplicated head element. + + + Avoid CCE in innerText when the element contains a SvgElement. + + + Various fixes for javascript encoding detection. + + + NPE in StyleSheetList.equivalentValues(). + + + HtmlImageInput: add .saveAs(). + + + JavaScript: MouseEvent to support .pageX and .pageY for all browsers. + + + JavaScript: fix Object.assign(). + + + JavaScript: fix .set() of Typed Arrays. + + + JavaScript: fix Typed Arrays construction with null. + + + WebClientOptions: deprecate .getPrintContentOnFailingStatusCode(). + + + JavaScript: implement Audio. + + + JavaScript: Selection.type implementation fixed for Chrome. + + + JavaScript: document.baseURI calculation fixed for relative href. + + + JavaScript: fix setting .innerHTML. + + + JavaScript: implement NodeList.entries(), keys(), values() and forEach(). + + + Neko: fix handling of strange comment syntax supported by browsers + + + JavaScript: fix AbstractList iteration. + + + Neko: fix handling of invalid numeric entity references inside attributes. + + + JavaScript: add basic support for Range.getClientRects(). + + + JavaScript: fix Map and Set iterator prototype. + + + RegExp: fix translation of \0 at the end. + + + Method HtmlPage.getElementsById(String) added to make simple to detect duplicate id's. + + + JavaScript: fix parameter checking for MutationObserver.observe(). + + + HtmlScript: charset attribute should not be considered. + + + JavaScript: CSSRuleList.item() is supported in all browsers. + + + Remove HtmlKeygen. + + + JavaScript: support Object.getOwnPropertySymbols(). + + + HtmlOption: fix .setSelected(). + + + + + + Handle infinite meta refresh. + + + HtmlOption: fix clicking. + + + HttpWebConnection: fix User-Agent header of CONNECT request. + + + Applet: initial javascript interaction support added; it is now possible to use + the JSObject from the applet to call javascript functions or set attributes. + + + JavaScript: fix __proto__ of the top level object. + + + JavaScript: fix Object.getPrototypeOf(). + + + WebClient: add .getInternals() to listener to WebSockets. + + + JavaScript: Set and Map to support .forEach(). + + + Object tag now has some applet support. + + + CSS: fix handling :target pseudo class. + + + Deprecate HtmlImage.getComplete(). + + + Deprecate HtmlKeygen. + + + JavaScript: WebSocket onError processing was missing. + + + Fix detection of HtmlInput types (IE). + + + Correct file type detection for files with css suffix. + + + JavaScript: simple implementation for MediaSource.isTypeSupported added (returns always false). + + + WebClientOptions: add option for screen width/height. + + + Reduce the number of temp files created when asking images for width/height. + + + + + + Deprecate SgmlPage.getPageEncoding() and WebResponse.getContentAsString(String) variants. + + + INCOMPATIBLE CHANGE: change return type of WebRequest.getCharset, + WebResponse.getContentCharset() and getContentCharsetOrNull(). + + + JavaScript: correct handling of window.onbeforeunload. + + + Encoding support for DataURl added. + + + INCOMPATIBLE CHANGE: PromptHandler.handlePrompt() has a third parameter. + + + WebClientOptions: add option to automatically download images. + + + Browsers are storing cookies with a dot at the start of the domain. + + + HtmlAnchor: handle clicking page with shift or ctrl keys. + + + INCOMPATIBLE CHANGE: change the return type of DomNode.getByXPath. + + + Add HtmlSlot. + + + DomElement: .click() should does nothing when the element is not displayed. + + + Table elements now supporting the summary and rules attribute. + + + Remove deprecated HtmlElement.getHtmlElementsByTagName(), .getHtmlElementsByTagNames() + and CSSStyleSheet.modifyIfNecessary(). + + + BrowserVersion: remove deprecated INTERNET_EXPLORER_11. + + + HtmlFileInput: deprecate .setValueAttribute(), use .setFiles() instead. + + + JavaScript: nowrap property support added for div, dd, and dt elements (IE only). + + + FormData now also respects configured mime type for uploading a file. + + + Reintroduce ScriptPreProcessor. + + + JavaScript: fix Symbol creation. + + + HtmlOption: clicking should unselect other options, even if the parent select is 'multiple'. + + + JavaScript: WebSocket constructor should report an js error if the provided url is empty/null or invalid. + + + HtmlInput: deprecate .click(int, int). + + + JavaScript: EventHander set at window-level only on setting it by attribute. + + + Elements with 'tabindex' are focusable. + + + JavaScript: implement HTMLInputElement.checkValidity(). + + + HtmlInput: .setValueAttribute() no longer executes onchange event handler. + + + JavaScript: HTMLInputElement: fix .value for file types. + + + Minor java code issue from our get started page fixed; sample for using getElementsByTagName added. + + + Add HtmlEmailInput, HtmlTelInput and HtmlUrlInput + + + INCOMPATIBLE CHANGE: remove SvgPage and InteractivePage, use HtmlPage instead. + + + SgmlPage to implement DocumentTraversal. + + + SgmlPage: fix getElementsByTagName() and add .getElementsByTagNameNS(). + + + BrowserVersion: remove deprecated FIREFOX_38. + + + JavaScript: fix NullPointerException in MutationObserver. + + + DomNode: implement .getUserData() and .setUserData(). + + + Mandate Java 8 as a minimum requirement. + + + + + + XmlPage: to ignore ByteOrderMark at the beginning of file. + + + CSS: cssparser updated to 0.9.21. + + + Do not trigger mouse events for the associated element when clicking a label. + + + JavaScript: the Map constructor accepts maps. + + + JavaScript: the set constructor accepts array buffers, string, sets and maps. + + + Class JavasScriptPage removed. Real browsers are handling this page as simple HtmlPage + containing only a script tag in the header. + + + If there is no content type, the browser will look inside the content for a script tag. + + + Conversion of ordered list to text has to take care of all children not only list items. + + + JavaScript: FF45 triggers mouse events also for disabled buttons and input elements. + + + DL tag should close containing tags. + + + JavaScript: Missing clear property added for headline, paragraph, and pre tags (IE only). + + + Ignore the charset when checking the content type header for CORS requests. + + + WebClientOptions: add 'HistoryPageCacheLimit' to allow specifying the number + of page references stored in history. If this value is smaller than the + configured HistorySizeLimit than HtmlUnit will only use soft references + for the first historyPageCacheLimit entries in the history. For older + entries only the url is saved; the page will be (re)retrieved on demand. + + + JavaScript: HTMLElement.getClientRects() returns an empty list for "display: none". + + + HtmlImage.saveAs(File) no longer parses the image. + + + JavaScript: throw JS runtime exception instead of Java IllegalArgumentException when method is called on incorrect objects. + + + JavaScript: referrerPolicy property now supported for anchors (Chrome only). + + + Many minor js class hierarchy fixes and missing constants added for IE. + + + Upgrade Apache log4j-api to 2.7. + + + Upgrade Apache commons-lang to 3.5. + + + JavaScript: missing property content added for template elements. + + + CSS: Support for css pseudo classes 'required' and 'optional' added. + + + NPE in native arrays if typed array has a null value. + + + asText() now includes the content of iframe elements. + + + JavaScript: CanvasRenderingContext2D simple implementation for clearRect, fillRect, strokeRect. + + + JavaScript: CanvasRenderingContext2D support for transparency added. + + + JavaScript: CanvasRenderingContext2D background color fixed. + + + JavaScript: simple implementation of CanvasRenderingContext2D.measureText() added + + + Value of the Script#readyState property (IE only) fixed for nodes created from js. + + + Page#toXML() no longer produces self closing form tags for empty forms. + + + JavaScript: console.timeStamp() added + + + Parameter processing fixed for our FloatXX/IntXX Array slice. + + + Value processing fixed for our FloatXX/IntXX Array constructor. The conversion for + the values of the provided array works now; there is no longer a NPE. + + + XPath attribute query has to take care of case for xml files. + + + Simple impl for SVGMatrix flipX/flipY/scale added. + + + JavaScript: CSSStyleDeclaration fix handling of null and NaN for length properties. + + + JavaScript: fix element.removeChild() when it is inside XMLDocument. + + + Browsers are accepting arbitrary url's when the scheme is 'about'. + + + WebClientOptions: add 'localAddress' to allow specifying a network interface. + + + XMLHttpRequest.getAllResponseHeaders() now uses the correct delimiter and more minor fixes. + + + Implementation of event.stopImmediatePropagation() added. + + + Authentication used for a first site was unnecessary sent to a second web site. + + + JavaScript: Reflect.has() implemented. + + + Support the special replacement patterns for the replacement string if replace was called for a string like 'abcd'.replace('cd', 'x$&'). + + + + + + ClientWidth is not correctly calculated for div with 'position: absolute'. + + + Use soft references for storing the page as part of the history to avoid OOMExceptions. + + + Do not save any history entries if HistorySizeLimit is less than 1. + + + CSS: cssparser updated to 0.9.20. + + + HtmlPage: .save() to handle relevant HtmlLink protocols. + + + Fix handling return statements in URL starting with "javascript:". + + + Take care of the font size when calculating the offsetWidth for text. + + + ReferenceError after calling Object(FrameWindow). + + + IllegalStateException adding an option to a select. + + + New class DefaultJavaScriptErrorListener added. This listener will be always used of no specific listener is defined. + The logging of js errors was moved to this class. If you like to have the logging and your own JavaScriptErrorListener + than subclass or decorate this. + + + Computing of the current css styles now takes mouseOver into account. + + + IndexOutofRangeException fixed in com.gargoylesoftware.htmlunit.attachment.Attachment.getSuggestedFilename(). + + + JavaScript: scrollHeight, scrollWidth implementation improved. + + + JavaScript: Window to throw Exception during construction by JavaScript. + + + JavaScript: string.repeat() is not available in IE. + + + JavaScript: string.includes() is not available in IE and FF38. + + + JavaScript: implement Object.assign(). + + + JavaScript: string.startsWith(), and .endsWith() are not available in IE. + + + BrowserVersion: deprecate FIREFOX_38. + + + NPE in CSSStyleSheet.fixIndex(). + + + + + + JavaScript: Implementation for DOMImplementation.createHTMLDocument() added. + + + Use our own implementation of URL.sameFile to avoid excessive number of DNS lookups and + and support path normalization before doing the comparison. + + + Keyboard: to have a parameter which allows typing to start at the text end. + + + CSS: cssparser updated to 0.9.19. + + + HtmlElement: do not trigger keypress if keydown.preventDefault() is true. + + + Remove deprecated DomNode.getScriptObject(), WebWindow.getScriptObject(), + HtmlElement.type() methods and HtmlPage constructor with 'originatingUrl'. + + + WebClient: supports a registry of known file extensions used to determine + the content type when uploading files. + + + WebClientOptions: .setSSLClientCertificate() supports InputStream. + + + DataUrlDecoder.decodeUrl() no longer replaces '+' with a space character. + + + Dependency to gsbase library removed. + + + JavaScript: Simple implementation of URL.createObjectURL and URL.revokeObjectURL added. + + + JavaScript: 'in' operator now works for FileList. + + + JavaScript: DOMTokenList as an array. + + + INCOMPATIBLE CHANGE: modify BrowserVersion.browserVersionNumeric from float to int. + + + JavaScript: clear cached Symbols on closing the page. + + + WebClientOptions: add setHistorySizeLimit(). + + + CSS: fix value verification for length property setters (e.g. width, height,...). + + + HtmlForm: to include Accept and Accept-Encoding headers on submission. + + + JavaScript: window.getComputedStyle() should use sheets of the element.document. + + + JavaScript: fix HTMLElement.style setter. + + + JavaScript: fix HTMLElement.offsetLeft. + + + CSS: fontSize influences the calculated height. + + + HttpWebConnection no longer removes 'Content-Length', 'Content-Encoding' and 'Content-MD5' HTTP headers. + + + BrowserVersion: Chrome is the BEST_SUPPORTED. + + + JavaScript: support Document.adoptNode. + + + DomNode: .asText() to handle CSS styles. + + + JavaScript: add primitive support for SVGElement.getBBox(). + + + JavaScript: Promise supports .reject() and .catch(). + + + JavaScript: IE supports the data URIs. + + + JavaScript: fix caching of computed styles. + + + DomNode: fix .asText() for some special spaces. + + + Fix CSS selector regression introduced during handling pseudo element in window.getComputedStyle(). + + + + + + Use Neko-HtmlUnit fork. + + + JavaScript: window.getComputedStyle() to handle pseudo element. + + + Malformed HTML: handle unterminated attribute value. + + + JavaScript: fix .offsetWidth, .offsetHeight, .clientWidth and .clientHeight of unconnected elements. + + + WebSocket support for binary data added. + + + JavaScript: datetime property added for time elements. + + + JavaScript: do not execute iframe onload handle if set while the element is attached to page (Chrome). + + + JavaScript: CSSStyleDeclaration to return lower-case values (Chrome and IE). + + + WebSocket event handling fixed, open event now fired, tests added. + + + Improved MessageEvent implementation. + + + JavaScript: Event.eventPhase is supported by Chrome. + + + HtmlElement: deprecate .getHtmlElementsByTagName() and .getHtmlElementsByTagNames(). + + + JavaScript: add .labels property for HTMLButtonElement, HTMLInputElement, HTMLKeygenElement, + HTMLMeterElement, HTMLOutputElement, HTMLProgressElement, HTMLSelectElement and HTMLTextAreaElement. + + + DomElement: fix .getElementsByTagName(). + + + Improved CloseEvent implementation; properties reason, code and wasClean are available now. + + + JavaScript: fix document.all when called with invalid index (Chrome). + + + JavaScript: fix table.innerText. + + + Fix XML attributes order. + + + JavaScript: StaticNodeList removed. + + + JavaScript: HTMLCollection and HTMLAllCollection function like access implementation improved (Chrome). + + + JavaScript: wordSpacing property support percent values for FF45. + + + JavaScript: HTMLLabelElement.control property added (FF and Chrome). + + + JavaScript: FormData delete, get, getAll, set and has functions added. + + + History processing changed; now HtmlUnit remembers pages instead of requests. + + + Pages are not loaded after History.pushState call. + + + JavaScript: fix XMLHttpRequest CORS handling (Chrome). + + + JavaScript: fix setting .innerText to null (Chrome). + + + Fix handling of empty Cookies (Chrome). + + + BrowserVersion: remove deprecated FIREFOX_31. + + + JavaScript: limited support for css @keyframes rules added. + + + JavaScript: CSSRuleList ignores unsupported rules. + + + JavaScript: Element.baseURI. + + + JavaScript: XMLHttpRequest.overrideMimeType(). + + + JavaScript: fix XMLDocument.getElementsByTagName(). + + + JavaScript: support window.performace.timing. + + + JavaScript: support HTMLAnchorElement.ping. + + + Firefox 45 ESR support added. + + + HtmlPage: add setElementFromPointHandler() for manually handling JavaScript document.elementFromPoint(). + + + JavaScript: add value property support for HTMLDataElement (FF only). + + + JavaScript: add initial support for HTMLStyleElement.scoped. + + + JavaScript: add support for HTMLStyleElement.disabled. + + + JavaScript: add support for Node.remove(). + + + INCOMPATIBLE CHANGE: change BrowserVersion.INTERNET_EXPLORER nickname to "IE". + + + JavaScript: update Date.toLocaleDateString() and .toLocaleTimeString() to use en_US locale. + + + JavaScript: simple implementation of SVGPathElement.getTotalLength() added. + + + JavaScript: ClassCastException in DOMTokenList#updateAttribute(). + + + JavaScript: HTMLCollection to enumerate children names (Chrome). + + + XPath: fix attribute case sensitivity (Chrome). + + + JavaScript: fix PopStateEvent.state to be clone (Chrome and IE). + + + JavaScript: fix Selection.rangeCount for Chrome. + + + CSS: Chrome doesn't support 'target' selector or computed 'zIndex' property. + + + JavaScript: fix location.hash. + + + JavaScript: HTMLTableElement.innerText should not be read-only (Chrome). + + + Remove deprecated WebClient.closeAllWindows(), HttpWebConnection.shutdown(), + SgmlPage.createDomDocumentFragment(), XmlPage.getContent(), + XmlPage.createXmlElement(), XmlPage.createXmlElementNS() and XmlPage.getXmlElementDescendants(). + + + SubmittableElement: rename getSubmitKeyValuePairs() to getSubmitNameValuePairs(). + + + + + + JavaScript: correct calculation of clientWidth and .clientHeight styles. + + + WebSocket: fix duplicate cookies sent with requests. + + + JavaScript: Doctype properties prefix, localName and namespaceURI returning undefined for Chrome. + + + JavaScript: Location should change immediately when calling history.pushState. + + + HtmlPage.asXml(): expand empty I, BUTTON and unknown nodes to make generated XML readable as HTML on browsers. + + + JavaScript: FormData.append now supports the optional filename parameter. + + + BrowserVersion: deprecate INTERNET_EXPLORER_11, use INTERNET_EXPLORER instead. + + + JavaScript: FormData constructor should support form parameter. + + + JavaScript: XMLHttpRequest.upload is available in IE also. + + + HtmlImage: to be serializable. + + + JavaScript: HTMLElement.getBoundClientRect throws an error for IE if the element is not connected to a page. + + + JavaScript: implement ClientRectList methods. + + + JavaScript: implement Symbol.for. + + + JavaScript: set prototype for objects constructed without 'new' keyword. + + + Do not explicitly send the port 443 for HTTPS connections. + + + Use the right keyCode when simulating enter. + + + Setting the text property of an option creates a label attribute if there is no label defined so far. + + + Origin attribute for anchors now works (FF, Chrome). + + + SVGElements are supporting querySelector() and querySelectorAll(). + + + id property was missing for SVGElements. + + + Element.className no longer trims whitespace for Chrome. + + + HashChangeEvent.initHashChangeEvent() not supported by Chrome. + + + Applet is no longer supported by Chrome. + + + Implementation of option.text is now in sync with latest Chrome. + + + Properties clientLeft and clientTop are available in Chrome also. + + + Add properties name, value, type, valuetype support to HTMLParamElement. + + + Fix really weird IE behavior when applying a CSS3 pseudo selector to an detached node. + This fixes the 'Invalid selector' output for the :enabled and :checked selector for pages + using jQuery. + + + Paragraph with style visibility:collapse is invisible in IE11 also. + + + Document baseURI property is not available for IE. + + + Improved asynchronously loading of scripts with async attribute. + + + Improved simulation of double click. + + + Improving null handling when setting the value of text areas and input elements. + + + Setting the width of a table column to null now works correct for FF/Chrome also. + + + Fix our simulation of setting table caption/tHead/tFoot for Chrome. + + + For Chrome className returns an empty string if the value of the class attribute is blank. + + + Fixed document.all.namedItem for Chrome when parameter is a form name. + + + Chrome ignores the target attribute if the href starts with 'javascript:'. + + + Fix form processing for urls containing anchors when simulating chrome. + + + Result of innerText fixed for Chrome. + + + Fix return value of getAttributeNS when attribute is not defined. + + + Option.text returns always the label if defined in Chrome. + + + CSS :lang selector now works correct if the lang was defined at the parent. + + + Empty form actions are not expanded by FF. + + + Type attribute is case sensitive for input elements. + + + Implementation of Performance.now() added. + + + Improved clientHeight calculation when height is set to auto. + + + Updates on event handling, mouse-over for option and select elements are more correct now. + + + IE never triggers a mouseover event for select options. + + + FF triggers a mouseover event for select options even if the option is disabled. + + + GAE support is back. + + + Function document.open(..) returns the opened document. + + + Browsers do not escape double quote and backslash in cookie values. + + + Fix for possible StringIndexOutOfBoundsException in HtmlUnitBrowserCompatCookieSpec. + + + Fix NPE in FormData#append when calling with null or undefined as value. + + + Fix redirect handling for status code 301, 302 and 307 (POST); add support for status code 308. + + + Bring the implementation of special key support (e.g. VK_DELETE) for password input and textarea control + in sync with the input text control. + + + BrowserVersion BEST_SUPPORTED added. This is (for now) a shortcut for FIREFOX_38. + + + Area elements are not focusable if no href attribute defined. + + + Anchors are not focusable if no href attribute defined. + + + Basic authentication credentials in the URL could get lost. + + + DefaultCredentialsProvider: to have .removeCredentials(). + + + Dependency to Commons Collections removed. + + + HtmlPage: fix base URL with leading whitespace. + + + + + + JavaScript: support document.hasFocus(). + + + INCOMPATIBLE CHANGE: Cache.cacheIfPossible() to return boolean + and rename .isDynamicContent() to isCacheableContent(). + + + CSSStyleSheet: response is cleaned up when it is not cached. + + + JavaScript: Support for History.pushState() and History.replaceState(). + + + SgmlPage: fix .getElementsByTagName(). + + + JavaScript: Empty dummy implementations for MediaQueryList#addListener and + MediaQueryList#removeListener added. + + + HttpWebConnection: deprecate .shutdown(). + + + INCOMPATIBLE CHANGE: WebConnection to extend AutoCloseable. + + + JavaScript: Removing the active element from the DOM tree should reset the + activeElement property. + + + JavaScript: fix HTMLFormElement.action when the attribute is not defined. + + + JavaScript: When an element inside an iframe becomes the active one, + the iframe element also becomes the active one of his enclosing document. + + + JavaScript: Improved simulation of onfocusin/out events. + + + HtmlPage: fix synchronization for .addAutoCloseable(). + + + Enhance performance of DomNode.asText(). + + + WebSocket: to be closed once the window is closed. + + + JavaScript: Missing property HTMLElement.oninput added. + + + Correctly handle redirection with broken gzip content. + + + CSS: support for Media Query feature 'max-resolution', 'min-resolution', and 'resolution' added. + + + CSS: support for Media Query feature 'max-device-width', 'min-device-width', 'max-height', + 'min-height', 'max-device-height' and 'min-device-height' added. + + + CSS: support for Media Query 'not' operator added. + + + CSS: support for Media Query feature 'orientation'. + + + CSS: initial support for Media Query features 'max-width' and 'min-width'. + + + JavaScript: fix Promise.resolve() with empty parameters. + + + JavaScript: XMLHttpRequest.onerror is available in CHROME too. + + + JavaScript: XMLHttpRequest.onerror handler will be called with a ProgressEvent as parameter. + + + JavaScript: support for ProgressEvent properties lengthComputable, loaded, and total added. + + + JavaScript: add minimal WebWorker support. + + + DomNode and WebWindow: deprecate .getScriptObject(). + + + JavaScript: collections to be iterated using the default Symbol.iterator. + + + ComputedCSSStyleDeclaration: fix StackOverflowError on calculating 'top' value. + + + JavaScript: XMLHttpRequest.overrideMimeType() is available in IE11 too. + + + JavaScript: XMLHttpRequest.overrideMimeType() does some state checking for IE11 and CHROME. + + + Upgrade Apache HttpComponents to 4.5.1. + + + JavaScript: Event.stopPropagation() is available in Chrome too. + + + Load asynchronously scripts with async attribute. + + + JavaScript: WebSocket to handle insecure SSL. + + + Various fixes for our checkbox and radiobutton simulation. This also fixes + css selectors working with the checked attribute. + + + Do not click surrounding anchor for 'checkbox' and 'radio' input (Chrome). + + + JavaScript: fix document.forms.form_name with prefixed forms. + + + JavaScript: fix result value for title.text property for empty title tags (IE8). + + + JavaScript: delays execution of Promise.then arguments. + + + JavaScript: fix CSSStyleRule.selectorText. + + + CSS: only FF supports CSSCharsetRule. + + + JavaScript: fix MediaList.item() and MediaList.mediaText results for media queries. + + + CSS: cssparser updated to 0.9.18. + + + JavaScript: Property style.boxSizing is available in Chrome and FF too. + + + CSS: fix @font-face for Chrome. + + + Fix base tag for relative URI. + + + JavaScript: TextArea now works correct if the children are manipulated from js. + + + JavaScript: Window.top property is only writable in IE. + + + JavaScript: window.onsubmit support added. + + + Correctly handle script when src attribute is only "://". + + + JavaScript: process scripts with 'application/javascript' type (add IE11). + + + JavaScript: Iterating through the .attributes property modifies outerHTML result. + + + Cookies: fix handling of two digits expiry date in Chrome. + + + JavaScript: add .placeholder property (HTMLInputElement and HTMLTextAreaElement). + + + JavaScript: textContent property is writable for table elements in Chrome also. + + + JavaScript: HTMLScriptElement.src should return complete URL if src was defined. + + + Correct simulation of type handling for input tags without type attribute being set. + + + Handle typing in inputs of type search like in inputs of type text. + + + RegExp: fix translation of \0 when translating a js regexp into a java one. + + + JavaScript: label property implemented for menu element. + + + JavaScript: type property implemented for menu element. + + + JavaScript: fix FormData to correctly handle File. + + + JavaScript: add window.location.origin. + + + JavaScript: OptionsCollection length setter fix (Chrome). + + + JavaScript: mouse events fixed when clicking an option (Chrome). + + + JavaScript: added support for Window.crypto.getRandomValues. + + + JavaScript: added dummy implementations of Window.requestAnimationFrame and Window.cancelAnimationFrame. + + + Reflect fix done in latest Chrome for Node.compareDocumentPosition. + + + Node.removeChild now throws a javascript exception if the node to be removed is not + a descendant of the receiver. + + + Node.insertBefore now throws a javascript exception instead of an DOMException. + + + Improved width calculation if the style defines the width using a percent value. + + + Index property for HTMLOptionElement added. + + + Consider base tag even when misplaced within body. + + + Added HtmlPage.getBaseURL and HTMLDocument.baseURI. + + + INCOMPATIBLE CHANGE: The usual isXxxxEnabled() methods are added to the Interface WebConsole.Logger + for better performance. + + + String substitution in window.console.log fixed (handing of special chars like $, + escaped percent sign, handling of missing replacement parameters). + + + Window.dump() is available in FF only. + + + XMLHttpRequest: call onload handler with a ProgressEvent parameter. + + + Support for text property removed from HTMLTimeElement. + + + Fix ClassCastException when triggering a click event for SVG elements. + + + Correct handling of file URL's containing encoded character. + + + Simulated Shockwave Flash plugin info updated to current version. + + + Version property added to plugin. + + + RegExp: there was a mutable 'singleton' shared between different regex results; this introduces + strange side effects. + + + Return value of CSSStyleDeclaration.removeStyleAttribute() fixed when simulating Chrome. + + + Dummy implementation for History.state together with some more tests added. + + + Latest FF versions are no longer defining these methods: History.next, History.current, History.previous. + + + Cookies: quote only if the cookie was sent with quotes. + + + Stylesheet list contains only active style sheets when simulating Chrome. + + + File.lastModifiedDate now produces the correct output in all browsers. + + + File.lastModified is not available in FF31. + + + + + + Introduce AbstractPage. + + + HtmlPage: change return type of .getFocusedElement() to DomElement. + + + Cache: clean up cached WebResponse only when it moves out of cache. + + + XmlPage: deprecate .getContent(), .createXmlElement(), .createXmlElementNS() + and .getXmlElementDescendants(). + + + Add SvgPage. + + + JavaScript: primitive implementation of XMLHttpRequestUpload. + + + JavaScript: implement FormData. + + + Fix detection of standards mode for DocType with empty name (IE8). + + + JavaScript: DocumentFragment: add .URL property and fix its default value (IE8). + + + SgmlPage: deprecate createDomDocumentFragment(). + + + HtmlPage: deprecate getFocusedElement() as its return type will change to DomElement. + + + JavaScript: do not trigger events if the element is detached from page. + + + JavaScript: Node.cloneNode() should return a node with a parent (IE8). + + + DomElement: now handle events (e.g. .click(), .focus()) to support SVG interaction. + + + SVG: fix SVG element creation. + + + JavaScript: support HTMLInputElement.files. + + + JavaScript: WebClient.getPage should trigger hashchange event when called for with the same URL but different hash than the current page. + + + DomNode: .setTextContent() should add child only if the text is not empty. + + + JavaScript: XMLHttpRequest CORS handling for PUT and POST. + + + JavaScript: fix Map, Set, WeakMap and WeakSet with empty constructor. + + + XmlPage: implement getElementsByTagName(). + + + Support PATCH Method for HTTP. + + + JavaScript: properly handle event handlers as a property of document body. + + + Typing: support clipboard copy, cut and paste. + + + ImageData: reuse data property, to preserve setting the values. + + + Rename SelectionDelegate to SelectableTextSelectionDelegate, and add SimpleSelectionDelegate. + + + JavaScript: initial implementation of performance.navigation. + + + Regex: back references to optional groups are corrected (e.g. /(a)?xyz\1/). + + + HtmlElement: Deprecated type() with shift, control and alt parameters. + + + Properly handle cookies for unqualified hostname. + + + HtmlElement: add type(Keyboard). + + + Mocked ActiveX objects have to be able to deal with unknown/unsupported properties. + + + Regex: back references to enclosing groups are ignored by js regex (e.g. /(a)(b\2)/). + + + Regex: minor improvements for the octal detection when converting a js regex into java regex. + + + Fix an IllegalStateException when parsing ajax response containing an object tag. + + + JavaScript: Limited support for CSSStyleRule.readonly added (property is available in IE only). + + + JavaScript: fix KeyboardEvent constants. + + + JavaScript: trigger SHIFT keydown/keyup events when "upper" characters are typed. + + + JavaScript: implement HTMLElement.contentEditable and isContentEditable. + + + JavaScript: implement TextRange.compareEndPoints() and .move(). + + + HtmlTextInput: handle typing arrow keys. + + + JavaScript: initial support for MutationObserver. + + + DomNode: add/remove CharacterDataChangeListener. + + + Upgrade Apache HttpComponents to 4.5. + + + HtmlElement: mark .fireEvent() as internal API. + + + Remove deprecated BrowserVersion.FIREFOX_24, ProxyAutoConfig, HttpWebConnection.downloadContent(), + Event, KeyboardEvent and MouseEvent. + + + + + + CSS: cssparser updated to 0.9.16. + + + Update htmlunit-core-js to Rhino head of 03.06.2015 + custom patches. + + + JavaScript: fix WebSocket.readyState. + + + Firefox 38 ESR support added. + + + BrowserVersion: deprecate FIREFOX_31. + + + Button tag submits a form if type is unknown. + + + Initial support for HTML5 Input Types. + + + JavaScript: add HTMLInputElement.min and .max. + + + Add HtmlTemplate element. + + + CSS: fix default attribute values. + + + JavaScript: Typed Arrays to tolerate out of range. + + + JavaScript: implement style.setProperty(). + + + JavaScript: implement style.getPropertyPriority(). + + + JavaScript: implement CanvasRenderingContext2D.getImageData(). + + + JavaScript: support image.naturalWidth and .naturalHeight. + + + JavaScript: support CustomEvent. + + + JavaScript: Element lookup by CSS class name does not always work. + + + History: support POST requests. + + + JavaScript: fix setting HTMLOptionElement.label. + + + JavaScript: arbitrary elements are defined as JavaScript properties (only in IE8). + + + JavaScript: HTMLInputElement: support minLength (Chrome). + + + JavaScript: implement window.matchMedia() and .styleMedia. + + + JavaScript: implement Map, Set, WeakMap and WeakSet. + + + JavaScript: handle events with functions bound to null. + + + JavaScript: execute onload handlers for dynamically created iframe as well when src is set to about:blank. + + + JavaScript: implement MessageChannel. + + + Support for 'hidden' HTML5 attribute added (method HtmlElement.isDisplayed() takes care of this). + + + Remove deprecated JavaScriptEngine.shutdownJavaScriptExecutor() and CookieManager.getCookies(). + + + JavaScript: implement NodeIterator. + + + Upgrade Xalan to 2.7.2. + + + + + + CSS selectors checking for an empty attribute (e.g. [data-section='']) are checking now the existence + of the attribute also. + + + Upgrade NekoHtml to 1.9.22. + + + HTMLTextAreaElement: maxLength property support added. + + + JavaScript: Missing setter for style.media added. + + + JavaScript: implement Promise.resolve(). + + + An Ajax request running in parallel to a form submit might influence the headers send by the submit. + + + JavaScript: rename host class CharacterDataImpl to CharacterData, + and ProcessingInstruction to extend CharacterData. + + + Upgrade Apache commons-lang to 3.4. + + + JavaScript: type property for anchor elements implemented. + + + Window: fix how events are handled in when a child iframe 'src' is empty. + + + HTMLIFrameElement: once the document is open()ed, + then the location should be the same as the enclosing page. + + + JavaScriptEngine: hasAttribute is available in IE8 also. + + + HTMLScriptElement: support 'onload' event (Chrome). + + + XMLHttpRequest: handle incorrect HTTP method name. + + + JavaScriptEngine: fix synchronization case. + + + Upgrade Apache HttpComponents to 4.4.1 + + + JavaScript: initial support for "Intl" namespace. + + + CSS: cssparser updated to 0.9.15. + + + JavaScript: fix the prototype of HTMLQuoteElement and HTMLInlineQuotationElement. + + + HtmlButton: 'type' attribute defaults to 'button' in quirks mode only (IE8). + + + JavaScript: fix HTMLImageElement.src attribute. + + + XSLTProcessor is not available in IE11. + + + BrowserVersion: deprecate FIREFOX_24 and remove deprecation of INTERNET_EXPLORER_8. + + + Initial support for HtmlBidirectionalIsolation, HtmlCommand, HtmlDetails, HtmlDialog, + HtmlLayer, HtmlMain, HtmlMenuItem, HtmlNoLayer, HtmlSummary and HtmlTrack elements. + + + WebClient: deprecate .closeAllWindows(), use .close() or try-with-resources statement. + + + Avoid exception when handling URLs with unknown protocols. + + + JavaScript: added basic support for Notification. + + + Package 'httpclient' added for our customizations of HttpClient. + + + JavaScript: fix many host class names. + + + Use the same parser for cookies when set from javascript as we use for cookies in the http header. + + + Use the same parser for cookies when set via meta tag as we use for cookies in the http header. + This fixes the missing support for various cookie attributes when set by meta tag (e.g. domain). + + + Iterator and StopIteration are only available in FF. + + + Event.metaKey is available in CHROME also. + + + MouseEvent.keyCode fixed for IE8 and CHROME. + + + JavaScript: Window is defined in Standards Mode (IE8). + + + Upgrade Apache HttpComponents to 4.4 + + + JavaScriptEngine: consider false jsObject. + + + JavaScript: XSLTProcessor supported methods (Chrome). + + + JavaScript: most elements prototype should be functions (Chrome and FF). + + + INCOMPATIBLE CHANGE: SVG: Rename SvgMpath to SvgMPath. + + + JavaScript: FunctionObject to also enumerate IDs of the parent objects. + + + JavaScript: do not set the window.location when triggered by anchor onclick (Chrome and FF). + + + JavaScript: Node.compareDocumentPosition() to handle argument which is not Node (Chrome). + + + JavaScript: constants should not be overwritten or deleted. + + + JavaScript: Node.insertBefore() throw exception for Chrome when second parameter is missing. + + + JavaScript: handle Node, Element, CSSValue and CSSPrimitiveValue as function not object (Chrome, FF). + + + Browsers are ignoring line breaks inside the src attribute of script/image/frames tags. + + + JavaScriptJobManager interface enhanced to support filtered access to the jobs. This helps to filter + out heartbeat jobs while waiting for the background jobs to finish. + + + Mock implementation of element.setCapture(), element.releaseCapture() and document.releaseCapture() added. + + + JavaScript: DocumentType: support 'publicId' and 'systemId', while 'prefix' is undefined in Chrome. + + + Upgrade Jetty to 9.2.10.v20150310. + + + Wrong encoding used by StringWebReponse if charset placed in content. + + + Fix handling nameless cookie. + + + Results for css selectors startsWith/endsWith/contains fixed for IE8 when searching with an empty string. + + + Result of document.all.namedItem('name') for many hits fixed when simulating IE. + + + Correct results when accessing window.ActiveXObject in IE11. + + + Boolean(document.all) fixed for FF and IE11 (core-js fix). + + + Many fixes for the select option javascript functions and the OptionsCollection. + + + WebResponse used for 'about:blank' was shared between different windows. Because the object + is not immutable this produces strange side effects. + + + Possible NullPointerException in ProxyAutoConfig.isInNet fixed. + + + Wrong activeElement for iFrames and their parents. + + + CSS pseudo selector ':checked' selects also selected options. + + + JavaScript: Support event parameter for event handlers created implicit by setAttribute. + + + AppletConfirmHandler added. It is possible to define this handler for a web client. + This handler is called before an applet code download. By implementing this handler you + can restrict the download per applet (like the confirm dialog in the browser). + + + Method isDisplayed() now works correct for HtmlImage, HtmlMap and HtmlArea. + + + WebClient.closeAllWindows() now kills the thread, if join does not succeed. This might happen, + if one of the javascript jobs runs in an endless loop. + + + WebClient.closeAllWindows() now stops the JS thread also of some onunload handler opens new windows or + refreshes iframes. + + + JavaScript: DOMTokenList#remove method remains tail-whitespace when the last token was removed. + + + Mandate Java 7 as a minimum requirement. + + + JavaScript: document.importNode() is supported in Chrome. + + + JavaScript: Improved width calculation if style is set to 'auto'. + + + JavaScript: Simplified synchronization in JavaScriptJobManagerImpl.waitForJobs methods. + + + Fix asText() of HtmlPreformattedText. + + + JavaScript: fix Storage prototype properties. + + + BrowserVersion: introduce .setHeaderNamesOrdered() to guide the order of the request HTTP headers. + + + JavaScript: fix writing to a read-only property in the prototype. + + + Firefox 31 ESR support added. + + + Upgrade Apache HttpClient to 4.3.5. + + + JavaScript: HTMLStyleElement.getSheet() is supported in Chrome. + + + Many minor fixes for implementation.hasFeature (retested with ff24, ff31 and Chrome added). + + + JavaScript: document.createNSResolver() and .evaluate() are supported in Chrome. + + + JavaScript: window.atob(), .btoa() and .getSelection() are supported in Chrome. + + + JavaScript: CSSStyleDeclaration.getPropertyCSSValue() is supported in Chrome. + + + Many minor fixes for the screen object (setters implemented, more testcases, Chrome support added). + + + ProxyAutoConfig package fixed (moved from com.gargoylesoftware.htmlunit.javascript to + com.gargoylesoftware.htmlunit). There is still a deprecated class at the original + location for backward compatibility. + + + Anchor or form did not load a page if the target URL differs from the current URL and ends with "#". + + + HtmlNoScript: expand empty tag. + + + JavaScript: fix class name of unknown elements with hyphen in their tag name. + + + Upgrade commons-logging to 1.2. + + + JavaScript: default value for XMLHttpRequest.open's async parameter is true. + + + JavaScript: XMLHttpRequest: overrideMimeType() to handle charset (Chrome and FF). + + + Window.external implementation fixed; the property is available in FF and + Chrome also. Additionally we added stubs for the functions AddSearchProvider + and IsSearchProviderInstalled. + + + Missing event listener functions addEventListener, removeEventListener + and dispatchEvent added to applicationCache. + + + Width and height of file inputs should be greater than zero. + + + JavaScript: XMLDocument.getElementById(): to return XML elements (Chrome). + + + JavaScript: XMLHttpRequest: support .onload for Chrome. + + + Methods setExpression and removeExpression are only available in IE8. + + + Image downloading: try to download only if the src attribute is not empty. + + + Unexpected POST parameters in case of malformed HTML. + + + JavaScript: ensure that values returned by __lookupG(S)etter__ are normal JavaScript objects. + Fixed related Rhino warning messages on System.err. (FF) + + + JavaScript: Image.complete support added. + + + URISyntaxException thrown while trying to load valid URL (invalid percent sign escaping) + + + Improved processing of malformed html. + + + JavaScript: button.type result fixed. + + + JavaScript: function.apply() to handle usual objects. + + + JavaScript: implement .style.length and indexed value. + + + JavaScript: .querySelector() is supported in Chrome. + + + JavaScript: .addEventListener() to handle native EventListener objects. + + + WebClientOptions: add .get and .setMaxInMemory(). + + + WebClientOptions: add .setSSLTrustStore(). + + + BrowserVersion: remove deprecated INTERNET_EXPLORER_9 and FIREFOX_17. + + + KeyDataPair: remove deprecated .getContentType(). + + + HttpWebConnection: Java 7: handle "handshake alert: unrecognized_name" with insecure SSL. + + + Upgrade Apache HttpComponents to 4.3.4. + + + Fix EOFException when processing responses with broken gzip'ed content. + + + + + + Upgrade NekoHtml to 1.9.21. + + + Fix NPE when processing postMessage(). + + + JavaScript: document and element .querySelectorAll() is supported in Chrome. + + + Some changes of the SOCKS proxy settings are ignored for HTTPS. + + + Avoid exception if the content-length provided by the server is not correct. + + + HtmlUnitRegExpProxy: better performance, as String.substring() implementation was changed in Java 7. + + + NoSuchElementException when parsing malformed HTML. + + + JavaScriptEngine: deprecate .shutdownJavaScriptExecutor(). + + + JavaScriptEngine: removes all postponed actions on webClient.closeAllWindows(); + + + JavaScript: handle RegExp constructed with 'undefined'. + + + WebClientOptions: add .setSSLClientProtocols(), .setSSLClientCipherSuites() and .setSSLInsecureProtocol(). + + + ConcurrentModificationException in WebWindowImpl.destroyChildren(). + + + JavaScript: fix .offsetHeight for empty <div>. + + + HTML parsing: move illegal content found within a table before the table. + + + JavaScript: Node.textContent can be set in Chrome. + + + JavaScript: ComputedCSSStyleDeclaration.getPropertyValue is supported in Chrome. + + + KeyDataPair: marked as internal API. + + + HttpWebConnection: set socket timeout also (regression in 2.14). + + + HtmlButton.getAttribute("type") now returns the correct value if no type was specified. + + + JavaScript: Function evaluate now returns the correct result when + called with XPathResult.BOOLEAN_TYPE as result type. + + + JavaScript: table.insertRow was broken when trying to insert a row + directly before the last one. + + + JavaScript: Window.name implementation fixed for IE11. + + + JavaScript: add support for the bgColor attribute on thead and tfoot element. + + + CookieManager: deprecate getCookies(URL). + + + Cookies: Different path interpretation done by IE11 fixed. + + + JavaScript: Some event definitions ignored when simulating IE11. + + + HashMap corruption (leads to an endless loop) because of concurrent access. + + + Cookies: Some fixes for the parsing of the expires date in IE11. + + + HttpWebConnection: socket reuse (regression in 2.14). + + + JavaScript: allow use of "in" operator with indexes for StaticNodeList and Attr. + + + File upload content type shouldn't contain charset. + + + JavaScript: setting outerHTML now works also for detached elements. + + + JavaScript: window.navigate(url) for IE browsers added. + + + Optimized image data handling; the finalizer needed for the ImageInputStream + no longer stops the image node itself from being gc'ed. + + + INCOMPATIBLE CHANGE: All public methods of CookieManager are taking care of the isCookiesEnabled() + state. Subclasses have to do the same. This was done as part of the migration to the new HttpClient + api. + + + HTML parsing: unknown closing tags can't close any other unknown tags. + + + JavaScript: type property now supported by ul and ol tag. + + + JavaScript: Fix handling of coordinate parameters when clicking on an image input. + + + JavaScript: fix setting value to toString() function. + + + Upgrade Apache commons-lang to 3.3.2. + + + JavaScript: Wrong charCode reported by the onKeyPress keyboard event for the space key. + + + JavaScript: Fix our implementation of innerText for table elements. + + + Upgrade Apache HttpComponents to 4.3.3. + + + JavaScript: The javascript inside the href attrib of an anchor executes in the context + of the anchors target. + + + + + + Upgrade NekoHtml to 1.9.20. + + + Sanitize filenames constructed from URL's. + + + JavaScript: Use the correct url for checking if the origin header has to be added + to a XMLHttpRequest. + + + JavaScript: Property contentDocument (Frame/iFrame) is available in IE8 also. + + + GAEJavaScriptExecutor is public again but marked as part of the internal api. + + + JavaScript: Fix encoding of innerHTML result for script content. + + + JavaScript: handle 'arguments' as a parameter. + + + JavaScript: Internal cleanup and some fixes for the innerHTML/outerHTML/insertAdjacentHTML. + Fix appendChild/insertBefore/replaceChild also. + Additionally trigger the correct notifications to inform about dom changes. + + + HtmlParser fixed for pages with scripts outside the html tag. + + + HtmlFileInput: ability to upload multiple files using setValueAttribute(String []). + + + HTMLObjectElement: classid could be affected by webClient.setActiveXObjectMap(). + + + Load iframe content when iframe is child of a node added by setting innerHTML. + + + JavaScript: body.background property handling fixed for FF. + + + JavaScript: Missing enctype property support added to forms. + + + JavaScript: Attr firstChild/lastChild fixed when no child at all (FF). + + + JavaScript: CORS handling is different in IE11 for the 'about:' protocol. + + + JavaScript: Window many property fixes for IE11 and Chrome. + + + JavaScript: CSSFontFace rule cssText property fixed for IE11. + + + JavaScript: style zIndex is of type integer in IE11. + + + JavaScript: DOMParser.parseFromString() type checking fixed. + + + JavaScript: Function HTMLelement.insertAdjacentText added (IE, Chrome). + + + BrowserVersion: deprecate INTERNET_EXPLORER_8 and INTERNET_EXPLORER_9. + + + JavaScript: improved width and height processing for html elements when simulating FF. + + + Fix IllegalArgumentException occuring for entities with invalid UTF16 code. + + + Upgrade Apache HttpClient to 4.3.2. + + + CSS: Parsing of the :not pseudo class fixed, only simple selectors are allowed. + This was a problem with CSSParser and is fixed in version 0.9.13. + + + JavaScript: ClientRect: add 'width' and 'height' properties. + + + CSSStyleDeclaration: fix serialization of StyleElement. + + + JavaScript: enumerating ordered numbers first (Chrome, FF and IE11). + + + Do not change the active element when the content of an iframe was changed. + + + JavaScript: conversion of anchor element into strings fixed. + + + JavaScript: hashChangeEvent processing fixed. + + + JavaScript: New event class PointerEvent and BeforeUnloadEvent (required for IE11). + + + CSS: cssparser updated to 0.9.12. + + + JavaScript: window.getComputedStyle and CSSStyleDeclaration.getPropertyValue() + are supported starting IE9. + + + BrowserVersion: deprecate FIREFOX_17, FIREFOX_24 is our preferred Firefox for the next months. + + + JavaScript: Document.inputEncoding and Document.characterSet are doing some kind of + normalization on the encoding string starting with FF24. + + + Upgrade Apache commons-lang to 3.2.1. + + + JavaScript: Window.opener is settable from javascript (FF24). + + + JavaScript: Node.attributes is no longer supported (since FF22). + + + JavaScript: XMLHttpRequest event processing fixed for FF24. + + + Return value fixed for element.height and element.width when element is not attached to the page. + + + JavaScript: String.contains() added for FF18 and later. + + + Return value fixed for element.height and element.width when element is not attached to the page. + + + Element.currentStyle returns null for elements not attached to the page. + + + Upgrade commons-codec to 1.9. + + + Some more tests converted into WebDriverTestCase. + + + Improved HTML parsing to be more compatible with real browsers. + + + JavaScript: Processing of events for checkbox, radiobutton and select fixed. + + + JavaScript: namespaceURI returns the correct value for html elements. + + + JavaScript: fix parseInt() when the value has a leading 0. + + + JavaScript: node and window.addEventListener() and .removeEventListener() are supported starting IE 9. + + + JavaScript: XMLDocument.firstChild() is now enabled to support more nodes at the + root level like ProcessingInstruction, Comment. + + + JavaScript: DomCharacterData.deleteData no longer wipes the string when called with an invalid + offset. Also the error handling is fixed. + + + Use the same accept headers as browsers do. + + + Possible dead lock in CSSStyleDeclaration fixed. + + + JavaScript: Setting the value property of a select element does not trigger + the onfocus event handler. + + + JavaScript: Fixed enctype form property default value. + + + JavaScript: location.hash returns '#' in ie mode if the location url ends with '#' + (e.g. http://localhost/something/#). + + + CSS: correct behavior of setting a style value to null. + + + WebClient: .closeAllWindows() to delete all temporary files. + + + JavaScript: add missing MessageEvent properties. + + + JavaScript: fix window.postMessage() to verify protocol, port and hostname. + + + JavaScript: XMLHttpRequest CORS handling fixed, some new tests added and implementation fixed. + + + JavaScript: Simplified/fixed implementation of the onReadyStateChange handler call. + + + JavaScript: XMLHttpRequest status and statusText throws an exception in IE8 depending + on the state of the request. + + + JavaScript: XMLHttpRequest property 'withCredentials' is not setable in sync mode (browsers specific). + + + JavaScript: XMLHttpRequest property 'withCredentials' is not available in IE8. + + + JavaScript: element.setAttributeNode() applies to XML as well. + + + JavaScript: HTMLElement.insertAdjacentHTML() is available in FF since version 8. + + + JavaScript: Embed now supports the width and height property. + + + JavaScript: send the correct Referer header when changing the location property. + + + SSL: use default algorithm for fetching the KeyManagerFactory. + + + BrowserVersion: remove deprecated FIREFOX_3_6, FIREFOX_10, CHROME_16, INTERNET_EXPLORER_6 + and INTERNET_EXPLORER_7. + + + HtmlElement: remove deprecated getElementById() and .hasHtmlElementWithId(), + and remove UrlUtils.encodeUrl(). + + + + + + HtmlImage: close imageReader in finalize(). + + + Upgrade NekoHtml to 1.9.19. + + + CSS: cssparser updated to 0.9.11. + + + Fixed wrong scripting scope assignment when handling attachments. + + + JavaScript: TextRange: add getBookmark() and moveToBookmark(). + + + JavaScript: .outerHTML don't check for correct tag closing in FF mode. + + + IEConditionalCompilationScriptPreProcessor fix when evaluated to false. + + + JavaScript: add SVGSVGElement.createSVGRect(). + + + JavaScript: .innerHTML to correctly process nested SVG elements. + + + Date.toUTCString and Date.toGMTString now returns the correct format in IE mode. + + + Date.toLocaleTimeString fixed in IE8 mode. + + + Some debug log output added if HTMLDocument.canAlreadyBeParsed(String) returns false. + + + Deprecate KeyDataPair. + + + JavaScript: array.sort() to use Arrays.LegacyMergeSort with Java 7. + + + JavaScript: support click method on any element for FF10+ too. + + + JavaScript: window.localStorage and .sessionStorage are supported in Chrome. + + + JavaScript: node and window.addEventListener() and .removeEventListener() are supported in Chrome. + + + CSS: Support selectors with more than one pseudo element (like '#list li:not(#item_1):not(#item_3)'). + This was a problem with CSSParser and is fixed in version 0.9.11. + + + JavaScript: HTMLStyleElement.type is writable. + + + JavaScript: Missing setter for element.outerHTML in FF17 fixed. + + + Upgrade Apache HttpClient to 4.3.1. + + + KeyDataPair: deprecate getContentType(). + + + JavaScript: fixed ClassCastException on TypedArray creation with start offset specified. + + + Correct processing of the target window for anchors with hash-only href attribute. + + + JavaScript: added support for the 'type' and 'media' property of style elements. + + + WebClient.getTopLevelWindows() now returns a snapshot of the list of top level windows + to avoid ConcurrentModificationExceptions while using this list. + + + In case the server reports an error via HTTP error code, the current page content + was not replaced with the content of that error page if the error was the result + of a form submit or an anchor click. + + + JavaScript: added (simple) support for window.postMessage. + + + XMLHttpRequest open(..) methods failed when called with null for userid/password. + + + XMLHttpRequest open(..) methods delivers wrong credentials. + + + attr.baseURI not supported for FF. + + + node.baseName not supported for XML nodes (IE). + + + node.text is unsupported for text nodes in XML documents. + + + XPathEvaluator.evaluate() ignores namespace resolver. + + + XPathResult types STRING_TYPE, NUMBER_TYPE and BOOLEAN_TYPE don't work. + + + Method document.createStyleSheet is more compatible with the IE; now the associated + link node is also created and inserted at the right place in the header. The new link + node is the ownerNode of the stylesheet. + + + Using a wrong index when addressing an StyleSheetList always throws an Exception in IE. + + + Fix the way we search for some java methods when creating a XML document from ActiveXObject. + This should work with all JavaVMs now. + + + Improved namespace support for XPath expressions. + + + Upgrade Apache HttpClient to 4.2.5. + + + Support for the label property added to the optgroup element. + + + Ensure that onchange event isn't called at focus lost after usage of HtmlInput.setValueAttribute. + + + JavaScript: add support for XPathEvaluator (FF & Chrome). + + + The display property now returns the correct default value for all HTML tags. + + + Respect the media type when processing the import rules from a CSS style sheet. + + + JavaScript: add basic support for window.navigator.security (FF only). + + + Make the handling of empty responses more error proof. + + + Textarea cols() and rows() property processing fixed. + + + Basefont support removed from Firefox after 3.6. + + + Adjust the window.outherHeight for the newer FF versions. + + + Use the correct frame/iframe for a given target if more than one exists for the given name. + + + The value of input controls changes when the defaultValue was changed in IE8ff. + + + The default value of input-file is no longer empty in IE8ff. + + + Checked state of radio buttons and checkboxes changes when setting defaultChecked in IE8. + + + Upgrade commons-codec to 1.8. + + + JavaScript: fix the mousedown/mouseup events triggered when clicking on an option. + + + JavaScript: starting with IE8 the radio button checked state is reseted to false + when adding to page. + + + JavaScript: load the source of a dynamically created HTML(I)FrameElement first when it is added to the DOM. + + + JavaScript: IE 9 supports String.trim(). + + + Upgrade commons-logging to 1.1.2. + + + Proxy configuration now respects the bypass host also after the proxy was used for another host before. + + + JavaScript: image.width() and image.height() are returning now the correct image size. + + + JavaScript: DOMTokenList now works like in FF (different from spec). Some NPE exceptions + are fixed, separator chars are fixed, and we are able to create an attribute if needed. + + + JavaScript: Removing frame tag removes the associated FrameWindow also. + + + HtmlPage.getElementById: always return the first element in document order (and not the first parsed one). + + + DomNode.querySelectorAll: return nodes matched by many selectors only once. + + + JavaScript: JS click() method triggers onchange handler on checkbox and radio button. + + + DomNode.removeAllChildren should not detach nested children from their parent node. + + + WebRequest: deprecate constructor (WebRequest, URL). + + + JavaScript: Attribute.expando now returns the correct value instead of the so far hard coded true (IE only). + + + WebClient: remove deprecated setPrintContentOnFailingStatusCode(), getPrintContentOnFailingStatusCode(), + setThrowExceptionOnFailingStatusCode(), isThrowExceptionOnFailingStatusCode(), setJavaScriptEnabled(), + isJavaScriptEnabled(), setCssEnabled(), isCssEnabled(), setAppletEnabled(), isAppletEnabled(), + setPopupBlockerEnabled(), isPopupBlockerEnabled(), getHomePage(), setHomePage(), getProxyConfig(), + setProxyConfig(), setRedirectEnabled(), isRedirectEnabled(), setUseInsecureSSL(), setActiveXNative(), + isActiveXNative(), getTimeout(), setTimeout(), isThrowExceptionOnScriptError(), + setThrowExceptionOnScriptError() and setSSLClientCertificate(). + + + Remove deprecated BaseFrame, Htmlpage.getElementByAccessKey(), HtmlPage.getElementsByAccessKey(). + + + + + + BrowserVersion: support FF17, deprecate FF3.6. + + + JavaScript: add support for window.onchange handler (FF10+ and Chrome). + + + Fixed synchronization problem causing a task triggered by setTimeout to be executed to early, before event handlers. + + + CookieManager: changed getCookies to return a copy of the current set of cookies to avoid ConcurrentModificationException. + + + JavaScript: add empty implementations of CanvasRenderingContext2D methods createImageData, + createPattern, createRadialGradient, fillText, getImageData, getLineData, isPointInPath, + measureText, putImageData, rect, rotate, setTransform, strokeText, and transform (FF). + + + Support for CSS pseudo selector ':target' added. + + + JavaScript: add DocumentFragment.querySelectorAll()/DocumentFragment.querySelector(). + + + JavaScript: move method contains to Node, throw runtime exception on invalid argument. + + + Method innerHTML does not encode entities for style tags. + + + Initial support for HtmlMeter (FF 17). + + + JavaScript: fixed exception occurring while testing window or document == "some string". + + + Support for CSS pseudo selector ':focus' added. + + + When simulating IE, the initial focus for a page is on the html element. + + + JavaScript: fixed hanging problem (infinite loop) after Object function was called with a window as parameter. + + + JavaScript: determine default path for cookies set with document.cookie from current URL. + + + JavaScript: place document before window in scope chain for event handlers defined in HTML attributes. + + + JavaScript: added basic support for SVGAngle and SVGMatrix. + + + JavaScript: HTMLDocument.createElementNS can create SVG elements. + + + JavaScript: add support for SVGSVGElement's style property and basic support + for methods createSVGMatrix and getScreenCTM. + + + JavaScript: add support for CanvasRenderingContext2D.quadraticCurveTo (FF). + + + JavaScript: execute onload handler of pages loaded in a frame, replacing a previous content. + + + Upgrade Apache HttpClient to 4.2.3. + + + JavaScript: elements nested within an element with "display: none" have offsetHeight = offsetWidth = 0. + + + JavaScript: fixed wrong trigger of focus event in special cases when field loses focus. + + + JavaScript: ignore invalid indexes for History.go. + + + Some more elements to close "p": address, center, dd, dir, dl, dt, fieldset, listing, li, menu, + ol, pre, ul and xmp. + + + Set max number of simultaneous connections per server to 6. + + + Handle pages with "application/javascript" content type as JavaScriptPage. + + + CSS: support Selectors Level 3. + + + JavaScript: fix document/element . querySelectorAll()/querySelector() (IE8). + + + JavaScript: add document.documentMode (IE). + + + Fix URL handling of local files in Windows, if they have folders starting with dot. + + + JavaScript: add document.implementation.createDocument for Chrome. + + + UrlUtils: deprecate encodeUrl(URL, boolean). + + + Fix the encoding of clicked links to match the enclosing page (FF). + + + Upper-case the charset detected from "meta" tag. + + + JavaScript: adjust availability of window.console (Firefox 4+, IE9+ and Chrome). + + + Fixed typo in method names of com.gargoylesoftware.htmlunit.WebConsole.Formatter. + + + JavaScript: add document.charset, .characterSet, .defaultCharset and .inputEncoding. + + + CSS: fix DirectAdjacentSelector (E + F). + + + JavaScript: fix the value of "(i in x)" for NodeList, HTMLCollection and CSSRuleList. + + + HtmlElement: deprecate getElementById() and hasHtmlElementWithId(). + + + BrowserVersion: deprecate INTERNET_EXPLORER_6, INTERNET_EXPLORER_7, FIREFOX_10, CHROME_16, + and make INTERNET_EXPLORER_8 the default one. Add INTERNET_EXPLORER_9, + FIREFOX_17 and CHROME. + + + JavaScript: fix Date.toLocaleDateString() and .toLocaleTimeString(). + + + Add BrowserVersion.clone(). + + + Fix a potential ConcurrentModificationException, on calling WebClient.getWebWindows(). + + + WebClient.closeAllWindows() to delete all temporary created big files. + + + JavaScript: .outerHTML of "basefont", "col", "embed" and "wbr" have forbidden end tag (FF). + + + Escape "%%" in query string to avoid IllegalArgumentException. + + + JavaScript: initial support for HTMLBGSoundElement (IE). + + + JavaScript: HTMLElement.outerHTML use lower case for unknown, "spacer" and "multicol" elements (IE). + + + Fix URL manipulation (UrlUtils) for file URLs containing drive letter. + + + JavaScript: fix handling relations of document type comment with <html> element (IE). + + + JavaScript: properties of Array.prototype should be defined in standards mode (IE). + + + JavaScript: correctly process null function handlers. + + + JavaScript: correct select.value after enclosing form.reset(). + + + JavaScript: XML: element.removeAttribute() is case-sensitive. + + + Correctly handle local file URL if it is in a separate driver (Windows). + + + JavaScript: fix the return value of element.getAttribute() in standards mode (IE). + + + JavaScript: element.set/getAttribute() should fix the name (e.g. "className") only in quirks mode (IE). + + + Cookies: use 1970 as two digits year start for the expiration date. + + + Cookies: accept more non standard date formats for the expiration date. + + + Properly handle spaces after elements: "abbr", "acronym", "basefont", "bdo", "big", "blink", "cite", + "code", "del", "dfn", "em", "ins", "kbd", "label", "map", "nobr", "q", "s", "samp", "small", "strike", + "sub", "sup", "tt" and "var". + + + JavaScript: element.outerHTML should throw an error if the provided value closes the parent. + + + JavaScript: element.outerHTML should not print end tag if it is forbidden. + + + Change default RefreshHander to a NiceRefreshHandler(2). + + + Support Internationalized Domain Name (IDN). + + + Change default network timeout from infinite wait to 90 seconds. + + + JavaScript: function name referenced before its declaration should be visible (IE). + + + JavaScript: function name referenced before its declaration should throw an exception (FF). + + + JavaScript: prevent infinite loop during adding a DomNode to itself. + + + JavaScript: don't enumerate function properties "arguments" and "caller". + + + JavaScript: handle definition of "function object.property() {}" (IE). + + + JavaScript: implement property HTMLElement.dataset (FF10). + + + JavaScript: remove "constructor" property of host objects (IE). + + + Cookie: remove deprecated (String name, String value) constructor. + + + + + + Upgrade NekoHtml to 1.9.17. + + + JavaScript: remove unneeded global properties ("java", "Packages" and "getClass") (FF). + + + JavaScript: implement "constructor" property of all host objects (FF). + + + Properly handle spaces after "strong", "b", "i" and "u" elements. + + + JavaScript: node.outerHtml not allowed for body and head nodes. + + + JavaScript: "this === window" should be true. + + + CSS: cssparser updated to 0.9.8. + + + Avoid double form submission when the onclick handler of a submit button calls form.submit() and the submission is answered by a redirect. + + + JavaScript: implement window.dispatchEvent() (FF only). + + + JavaScript: Some more fixes for correct calling of the Image onload handler. + + + In some cases the javascript execution context was overwritten. This produces side effects like the one in this issue. + + + Handle NoHttpResponseException like an HTTP error and ignore it when option throwExceptionOnFailingStatusCode is set to true. + + + Handle 'deflate' Content-Encoding with content compressed using GZip compatible mode. + + + JavaScript: setting iframe.src to 'about:blank' should not load the page. + + + JavaScript: iframe.src should point to the related page. + + + HtmlEmbed: add saveAs(File). + + + JavaScript: XMLHttpRequest: support Cross-Origin Resource Sharing (CORS). + + + JavaScript: Image onload not called after src change (using setAttribute('src', ) instead of src property). + + + DomNode: make .querySelectorAll() and .querySelector() public. + + + JavaScript: 'focus' and 'blur' event is triggered for 'document' descendants (FF and Chrome). + + + Cookies: fix year with two digits. + + + IE Conditional comments: handle "downlevel revealed" conditional cases. + + + JavaScript: allow re-declaration of undefined, NaN and Infinity. + + + JavaScript: allow assignment to undefined, NaN and Infinity (FF3.6 and IE). + + + JavaScript: implement Typed Arrays, namely ArrayBuffer, DataView, Float32Array, Float64Array, + Int16Array, Int32Array, Int8Array, Uint16Array, Uint32Array, Uint8Array and Uint8ClampedArray. + + + JavaScript: document.domain now allows the change from localhost to a different domain. + + + JavaScript: exception.stack should not be defined in IE. + + + JavaScript: WebWindow: add getters and setters for window width and height. + + + JavaScript: add support for HTMLMediaElement.canPlayType(). + + + Fixed NPE in HtmlPage.getTitleText() and WebClient.closeAllWindows() occurring when document.documentElement has been removed. + + + JavaScript: add support for CSSFontFaceRule (Firefox). + + + JavaScript: ensure that property "argument" of a function is null outside of it's scope. + + + JavaScript: add support for getAttributeNS, hasAttributeNS, removeAttributeNS, and setAttributeNS on Element (Firefox). + + + Missing synchronization in StorageImpl fixed. + + + NPE fix for Range.htmlText. + + + NPE fix for Range.parentElement(). + + + Empty responses marked as GZip encoded no longer throwing an error. + + + UrlUtils: fix an infinite loop when base URL is relative. + + + JavaScript: ClassCastException in Window.jsxFunction_open() fixed. + + + Timeout configuration changes are now taken into account. + + + WebClient: deprecated setTimeout() and getTimeout(). + Use webClient.getOptions() instead. + + + JavaScript: HTMLTableElement.refresh is only available when simulating IE. + + + JavaScript: HTMLTableElement.moveRow, HTMLTableSectionElement.moveRow, Tfoot.moveRow, + and THead.moveRow are only available when simulating IE. + + + INCOMPATIBLE CHANGE: WebResponseDate.getInputStream(), BinaryPage.getInputStream(), UnexpectedPage.getInputStream(), + WebResponse.getContentAsStream(), and WebResponseWrapper.getContentAsStream() are throwing an IOException now. + + + JavaScript: fixed namespace handling for nodes imported from an xml document via document.importNode(). + + + DebuggingWebConnection: fixed IOException occurring while working with gzip encoded JavaScript responses. + + + JavaScript: disabled (limited) JavaScript execution in HtmlPage instances that are not "active" anymore. + + + JavaScript: improved verifications to avoid that background tasks continue to run when page has been unloaded. + + + Google App Engine support: don't follow redirects automatically in UrlFetchWebConnection. + + + Add SOCKS proxy support for HTTPS. + + + HttpWebConnection: removed setUseInsecureSSL. Settings is now read from WebClientOptions. + + + INCOMPATIBLE CHANGE: The interface HTMLParserListener is enhanced to be able to + handle the html source when parsing a snippet. + + + WebClient: getWebConnection() and setWebConnection() are part of the public APIs. + + + JavaScript: remove customized "eval", and depend on core-js. + + + BackgroundJavaScriptFactory is now configurable. + + + JavaScript: function.arguments can be read-only (Chrome). + + + JavaScript: align property support added to heading elements + + + JavaScript: setting script.text re-executes the script (IE) + (in IE mode). + + + JavaScript: fix various problems with re-execution of script + + + JavaScript: event handler functions should have a name. + + + JavaScript: implement function.arguments, and correct Arguments default value. + + + JavaScript: let event.type and .button, .clientX, .clientY to have setters. + + + JavaScript: fix cases when trying to set a read-only attribute. + + + Add support for "Do Not Track" feature (FF10 only). + + + WebClient: deprecate setJavaScriptEnabled(), isJavaScriptEnabled(), + setThrowExceptionOnScriptError(), isThrowExceptionOnScriptError(), + setThrowExceptionOnFailingStatusCode(), isThrowExceptionOnFailingStatusCode(), + setCssEnabled(), isCssEnabled(), setAppletEnabled(), isAppletEnabled(), + setPopupBlockerEnabled(), isPopupBlockerEnabled(), setRedirectEnabled(), isRedirectEnabled(), + setUseInsecureSSL() and setSSLClientCertificate(), setHomePage(), getHomePage(), + setPrintContentOnFailingStatusCode(), getPrintContentOnFailingStatusCode(), + getProxyConfig(), getProxyConfig(), setActiveXNative(), isActiveXNative(). + Use webClient.getOptions() instead. + + + JavaScript: implement navigator.buildID, .oscpu, .vendor and .vendorSub. + + + JavaScript: fix document.bgColor, .fgColor, body.aLink, .bgColor, .link, .text and .vLink. + + + JavaScript: implement document.getSelection(), .head, .alinkColor, .linkColor, + .vlinkColor, and window.dump(). + + + DOM: implement text.getWholeText(). + + + JavaScript: fix navigator.appMinorVersion, .cpuClass, + .systemLanguage and .userLanguage values. + + + Geolocation: primitive support (FF only). + + + Implement WebConsole and JavaScript Console (FF only) + + + JavaScript: implement element.classList (FF only). + + + JavaScript: add element.children (FF), it was implemented for only IE. + + + JavaScript: separate NodeList from previously existing HTMLCollection. + + + JavaScript: add node.attributes and element.baseURI. + + + JavaScript: incompatible objects with the respective BrowserVersion should be HTMLUnknownElement. + + + Initial support for HtmlProgress (FF 10). + + + JavaScript: implement document.scripts for FF 10 (in addition to already implemented IE). + + + JavaScript: implement node.parentElement (FF 10). + + + Initial SVG support. + + + INCOMPATIBLE CHANGE: rename IElementFactory to ElementFactory, + and change the return type of its methods from HtmlElement to DomElement. + + + HtmlPage: cloneNode() should clone the underlying ScriptObject. + + + HtmlElement: support special keys for .type(int). + + + BaseFrame: is now deprecated, please use BaseFrameElement instead. + + + BaseFrameElement: create a WebWindow for the new clone instance. + + + Cookies: enable cookies after being disabled, should work. + + + DomElement: now implements ElementTraversal, with the corresponding JavaScript getters (FF only). + + + JavaScript: implement more Range methods. + + + JavaScript: document.getElementById() finds non-HTML elements. + + + HtmlPage: deprecate .getElementByAccessKey(), use .getHtmlElementByAccessKey() instead. + + + INCOMPATIBLE CHANGE: change the return type of HtmlPage.getElementById(), + .getElementByName(), .getElementsByName(), + .getElementsByTagName(), .getElementsByIdAndOrName() + and HtmlElement.getChildElements() + from HtmlElement to DomElement. + + + Mandate Java 6 as a minimum requirement. + + + Delete temporary generated files on page.cleanUp(). + + + JavaScript: DocType is handled as Comment (IE only). + + + JavaScript: HTMLGenericElement instead of HTMLUnknownElement, + and HTMLCommentElement instead of Comment (IE only). + + + JavaScript: object default value to contain the name, in strict mode (IE only). + + + JavaScript: Node should not define '.innerText'. + + + JavaScript: comments are elements, most properties implemented (IE8 only). + + + JavaScript: document.getElementById() should not search by name, with strict mode (IE8 only). + + + JavaScript: initial WebSocket support. + + + Remove deprecated BrowserVersion.FIREFOX_3. + + + + + + CSS: handling attributes which do not need explicit values, e.g. [disabled]. + + + Google App Engine support: allow frame loading. + + + Cookie: null path is treated as "/" in .equals() and .hashCode() + + + Upgrade Apache HttpClient to 4.2.1. + + + JavaScript: window.onhashchange support added. + + + DomNode: fix potential NPE in DomNode.DescendantElementsIterator. + + + JavaScript: add window.mozInnerScreenX, .mozInnerScreenY and .mozPaintCount (FF only). + + + WebRequest: add default value for "Accept-Encoding" HTTP header. + + + Fixed error processing when the onerror handler throws an error. + + + JavaScript: add DocumentFragment.createAttribute(), createComment(), createDocumentFragment(), + createElement() and createTextNode() (IE only) + + + Some more style properties are now supported; IE8 simulation now supports the + same set of properties like the real one. + + + Correct the formating of the opacity style value. + + + Correct the handling of unsupported style properties when simulating IE. + + + Truncate file names in HtmlPage.savePage and DebuggingWebConnection to avoid exception due to too long file names. + + + JavaScript: querySelector(All) throws for invalid selectors. + + + Java 7: fix SSLPeerUnverifiedException for valid certificates when WebClient.setUseInsecureSSL(true) is used. + + + Upgrade commons-codec to 1.6 + + + Upgrade Apache HttpClient to 4.2. + + + WebClient: add .setSSLClientCertificate() for client certificate authentication. + + + CSS: The ':disabled' and the ':enabled' selector now works for all HtmlElements + implementing the DisabledElement interface. Now the selector + also checks e.g. Button and Textarea elements. + + + JavaScript: handle out of bound moves for TextRange (IE only). + + + Google App Engine support: added basic cookie support. + + + Fix XHR.onreadystatechange now supplies an event argument if simulating FF. + + + Unauthorized response should be received only once, and subsequent + requests should have the Authentication string. + + + INCOMPATIBLE CHANGE: do not allow WebClient.addRequestHeader("Cookie", value) + and Cookie must have a domain. + + + Fix default content encoding for XML files. + + + JavaScript: don't restrict XMLHttpRequest to same origin for FF 3.6 and upper. + + + Upgrade CSS Parser to 0.9.7. + + + Fix missing support for different handling of self closing tags + in HTML and XHTML. + + + Fixed cookie threading issue. + + + Fix a possible performance problem caused by a code fragment + no longer needed after the update to HttpClient 4.1. + + + Upgrade Apache commons-io to 2.2. + + + Check the onclick event for preventDefault/returnValue also when + the handler produces no result. + + + Don't create a new Attr when setAttributeNode(Attr) is called. This fixes + jQuery.attr for IE browsers. + + + HtmlElement attributes collection returns an empty attr for + 'class' if simulating IE. + + + Ignore gzip encoding problems when downloading external css content. + + + Methods element.getElementsByTagName() and XMLDocument.getElementsByTagName() + are now namespace aware. + + + Method element.querySelectorAll() now only selects descended + nodes of the element. + + + Upgrade Apache HttpClient to 4.1.3. + + + Call onload event for frames in the correct order. + + + Implement some more fixes for handling of '!important' rules. + + + Avoid calling class.getPackage() because of broken class loader + implementation in ColdFusion. + + + JavaScript: CSSStyleDeclaration.removeProperty is now available in FF mode. + + + Some not needed exception declarations are gone. + + + isDisplayed() has to return false for hidden form fields. + + + Cookies: add support for Set-Cookie attribute httpOnly. + + + JavaScript: fix strange return value + 'net.sourceforge.htmlunit.corejs.javascript.UniqueTag.NOT_FOUND' + of ComputedStyle.getPropertyValue. + + + JavaScript: make Element.getBoundingRect available when simulating FF too. + + + If JavaScript is disabled, don't download the image even if an onload + handler is defined. + + + JavaScript: document.forms(0) is not valid in FF. + + + JavaScript: Initialization of the popup window misses some steps. + + + JavaScript: Remove also the node parents from style cache when changing + a node, because some styles have an effect for the parent properties + also (e.g. height, width). + + + JavaScript: script.text works correct now for script nodes with more + than one child node. + + + JavaScript: possible ClassCastException fixed in JavaScriptExecutionJob. + Additionally cleaned up the code a bit and some more details added to the + error messages. + + + JavaScript: StyleSheet insertRule/addRule and deleteRule/removeRule + exception handling fixed. Now we reporting syntax errors back to + javascript. + + + CSS: cssparser updated to 0.9.7-SNAPSHOT. + + + Upgrade Apache commons-lang to 3.1. + + + JavaScript: document.getElementsByClassNameNS("*", "html") now returns + the HTML tag for a page. + + + JavaScript: concatenate all text nodes under a <script> tag when + calculating the script code. + + + JavaScript: No execution of javascript, if script tag + imported (replaceChild) from different dom (xml). + + + JavaScript: fix transformation of regular expressions like '{{something}}' into + java regular expressions. + + + HtmlScript.asXml(): don't insert CDATA if it is already present. + + + HtmlTable.getCellAt() now works in complex situations with colspan and rowspan. + + + Ignore expiration date if the format is incorrect for cookies set by the remote server. + Accept expiration dates enclosed with double quote. + + + JavaScript: NPE when the event handler performs only preventDefault(). + + + JavaScript: Selecting an option via javascript (e.g. sel.options[1].selected = true) + no longer triggers the focus event. + + + JavaScript: JavaScriptExecutor had a memory leak; the list of jobs was never cleaned. + + + JavaScript: addEventListener/attachEvent are behaving like the browser if called with + null event handler. + + + Rewritten applet support; we support now many jar archive files, the codebase attribute, parameters, + access to the codebase, documentbase and the parameters from the applet and LiveConnect (at the moment + this is only a small stub). + + + Upgrade Apache commons-io to 2.1. + + + JavaScript: fixed StackOverflowError occurring with onload handlers in documents created with document.write (IE only). + + + Better error message if browser configuration contains an unknown key. + + + JavaScript: 'onload' handler for iframes was not called if an iframe without + src attribute was added from javascript. + + + JavaScript: 'onload' handler for iframes was called if an iframe was added + to an document fragment. + + + JavaScript: 'onload' handler for iframes was not called in IE mode if an iframe was added + to an document fragment and after that the iframe was added to the document itself. + + + Malformed HTML code: handle nested forms. + + + Add NiceRefreshHandler. + + + Click on a selected option in a multiple select element unselects it. + + + JavaScript: StringIndexOutOfBoundsException when calling TextRange.text. + + + CSS: forward the URI of an style sheet to the CSS parser for better error messages. + + + JavaScript: IEConditionalCompilationScriptPreProcessor throws exceptions for some scripts. + + + JavaScript: document property 'activeElement' is now available in FF3.6 mode. + + + SSL: for web servers which support only SSLv3, try to explicitly reconnect with that version. + + + JavaScript: trim value of type attribute before to verify it (FF only). + + + CSS: support for @font-face fixed. + + + JavaScript: document property 'readyState' is now available in FF3.6 mode. + + + Remove deprecated WebRequestSettings, WebResponseImpl, some BrowserVersion constants, + DefaultCredentialsProvider.addProxyCredentials() and WebResponse.getContentAsBytes(). + + + + + + CSS: pseudo class 'disabled' now supported in FF mode. + + + JavaScript: properly handle XML inside frame. + + + JavaScript: Wrong offsetHeight for elements with height set to 0px fixed. + + + Initial support for css background shorthand added. + + + JavaScript: avoid encoding of % in Location.href when set as part of Location.hash. + + + HtmlPage.savePage: ensure that the right option is saved as selected. + + + JavaScript: ensure that first cell off each row has the same offsetLeft. + + + Missing history update during window.location.replace(newUrl) fixed. + + + NullPointerException in css parser error handler fixed. + + + JavaScript: Fix for null index handling when adding a select option. + + + JavaScript: zIndex handling fixed in many ways. + + + JavaScript: fixed IndexOutOfBoundsException when accessing the CSSRuleList. + + + JavaScript: add support for CssStyleSheet removeRule & deleteRule. + + + JavaScript: add support for element.removeAttributeNode() for IE too. + + + In some cases a new window was not attached to the JavaScript + background worker thread. + + + HtmlPage.save: fix exception occurring when a referenced image is not an image. + + + JavaScript: fix string conversion of native functions. + + + Parsing: accept self closing <iframe/> tags when simulating IE. + + + Fix a NPE because of bugs in NamedAttrNodeMapImpl. + + + CSS: support for media="all" added. + + + Wrong DOM node generated for tables. + + + CCS parsing not required for Page.getTitleText(). + + + JavaScript: add support for NamedNodeMap.removeNamedItem. + + + NPE fixed when CSS style declarations are addressed from JavaScript. + + + INCOMPATIBLE CHANGE: The whole construction/setup of the AbstractHttpClient is now done + by the factory method com.gargoylesoftware.htmlunit.HttpWebConnection.createHttpClient(). + Only the setup of our cookie spec factory is done outside this call because this is + really required later on. This gives you more flexibility setting up your own client. + If you already do this, please check your implementation for compatibility. + + + JavaScript property mediaText and function item added to class MediaList. + + + JavaScript support for class CSSMediaRule added. + + + Avoid exception occurring when script's src attribute is only "http://". + + + Recursion in CSS import causes stack overflow. + + + Fix order of steps during Window initialization to avoid NPE in later access. + + + DefaultCredentialsProvider: reactivate removed addNTLMCredentials and addNTLMProxyCredentials + as HttpClient 4.1 now provides full support for NTLM authentication. + + + Upgrade Apache HttpClient to 4.1.1. + + + Use correct separator for 'src' and 'href' attributes. + + + Follow hyperlink when click is performed on a nested element. + + + XMLSerializer.serializeToString() generate lower case tags for FF 3.6. + + + XMLSerializer.serializeToString() generates self closing tags as + defined by xhtml (only FF 3.6). + + + Fix synchronization problem causing wrong page to be occasionally loaded into a window. + + + INCOMPATIBLE CHANGE: The WebRequest no longer has a CredentialProvider as attribute. + Now there are two attributes of type Credentials named urlCredentials and credentials. + The attribute credentials has a getter and a setter method; the urlCredentials are + only addressable via getter call. This change was needed to support credentials as part + of the url. + + + Improved memory handling of JavaScriptExecutor. + + + Upgrade Apache commons-io to 2.0.1. + + + Calculation for the next execution time of jobs (setInterval) + fixed for some cases. + + + JavaScript: fix exception in getComputedStyle occurring while evaluating child selector + for node within a DocumentFragment. + + + Follow hyperlink when click is performed on a nested element. + + + IFrame created from javascript doesn't load source'. + + + Initialization of iframes corrected, if content was + written from javascript. + + + Remove expired cookies. + + + Serialization support fixed for Pages with unfinished + JavaScriptJob's. These jobs are NOT serialized. + + + JavaScript: user and password parameters for the + XMLHttpRequest.open method are optional; the check + of there existence is fixed. Only if a user is set, + a CredentialProvider is associated with the request + (witch overwrites the one from the WebClient). + + + NPE if URL contains basic auth info without password. + + + JavaScript: Use the right encoding for the implementation + of the loadXML and parseFromString methods. + + + JavaScript: un-selecting selected option in a (single) select + causes the first option to be selected (FF) or is ignored (IE). + + + Send cookies ordered by more specific path attribute. + + + The script tag supports now the type 'application/x-javascript' + in Firefox mode. + + + Improved synchronization and sleep() replaced by wait() + in JavaScriptJobManagerImpl. + + + Upgrade Apache commons-lang to 2.6. + + + Upgrade Apache HttpClient to 4.1. + + + File name is send to server if HtmlFileInput.setData was called. + + + Url's like 'http://www.google.com/..' reduced to 'http://www.google.com/'. + + + JavaScript: added support for CSSCharsetRule. + + + HtmlElement.type: respect maxLength (if any) for text and password input fields. + + + JavaScript: add dummy implementation of HTMLCanvasElement.toDataURL. + + + JavaScript: HTMLCanvasElement's width and height are of type Number not String. + + + JavaScript: added Range constants START_TO_START, START_TO_END, END_TO_START and END_TO_END as well as + basic implementation of Range.compareBoundaryPoints (FF only). + + + Accept cookies set by server responses even if the path doesn't match the one of the requested content. + + + NPE in XMLSerializer.save(page) if the page contains an image tag without src attribute or link without href. + + + JavaScript: support addressing a StaticNodeList like an array (e.g. node = staticNodeList[i]). + This is done by prototype 1.6.1 if the querySelector API is available. + + + JavaScript: add support for HTMLElement.querySelector and querySelectorAll for FF3.6 and IE8. + + + DefaultCredentialsProvider: removed addNTLMCredentials and addNTLMProxyCredentials as HtmlUnit doesn't provide NTLM + support out of the box anymore since release 2.8. See "NTLM authentication" documentation for details on how to work with NTLM. + + + JavaScript: make window.top writable. + + + JavaScript: octal support added to the regular expressions. + + + HtmlImage; reset image reader also if image is reloaded because of src attribute change. + + + JavaScript: add support for HTMLDocument.querySelector and querySelectorAll for FF3.6 and IE8. + + + JavaScriptErrorListener added (WebClient.setJavaScriptErrorListener(JavaScriptErrorListener)). + + + JavaScript: fixed internal error occurring in XMLDocument.loadXML with ill formed XML code. + + + JavaScript: HTMLElement.prototype.innertHTML should be undefined (FF). + + + Don't trim class attribute for FF3.6. + + + JavaScript: don't reduce multiple white spaces when reading innerHTML (FF only). + + + XMLSerializer should expand empty 'textarea'. + + + JavaScript: location.href returns the right value after clicking on a link that jumps only to a different hash. + + + Fixed reload handling if only the hash part of a url changed. + + + HtmlSelect.setSelectedAttribute now returns the page in the WebClient's current window. + + + Parsing: <ins> is an inline element. + + + JavaScript: don't escape "+" in hash value (FF). + + + Cookies: consider quotes surrounding the value as part of the cookie value. + + + JavaScript: allow "//" in argument string of "new Function(...)". + + + JavaScript: add support for function HTMLSelectElement.item. + + + JavaScript: don't throw an exception when setting incorrect value to HTMLSelectElement.selectedIndex for FF3.6. + + + Fix IE conditional compilation bug (IE only). + + + JavaScript: add support for RegExp.$1..9, RegExp.lastMatch, RegExp.lastParen, RegExp.leftContext and RegExp.rightContext. + + + JavaScript: add support for function HTMLOptionsCollection.remove (IE only). + + + Escape only <, & and " in attribute values where it was not yet the case (for instance HtmlSubmitInput). + + + Ignore leading and trailing spaces in namespace values. + + + HtmlTextArea.asXml(): don't append indent spaces before closing tag. + + + Fix exception when asking CookieManager for cookies of "about:blank". + + + JavaScript: add empty implementations of CanvasRenderingContext2D.translate and scale (FF). + + + Consider <noscript>'s body as plain text for FF and discard it totally for IE. + + + ObjectInstantiationException: updated to expose the underlying 'cause' exception. + + + Deprecate BrowserVersion.FIREFOX_3. + + + JavaScript: add support for anchor.rel, and .rev, and link.rev. + + + Remove deprecated BrowserVersion.FIREFOX_2, DomNode.getAllHtmlChildElements() and WebResponse.getRequestUrl(). + + + + + + HtmlOptionGroup: add utility method getEnclosingSelect(). + + + HtmlRadioButtonInput: trigger onchange event handler on losing focus with IE. + + + Configure JavaScript executor thread as daemon thread. + + + JavaScript: initial support for HTMLAudioElement, HTMLSourceElement and HTMLVideoElement. + + + Fix Content-Type header value on posting a form with "multipart/form-data" encoding. + + + JavaScript: document.cookie should not return cookies that have expired since they have been set. + + + JavaScript: ignore expired cookies set by document.cookie. + + + JavaScript: XSLTemplate and XMLDOMParseError are not instantiable. + + + HTTP headers: 'Host' to be the first (FF only). + + + JavaScript: XMLHttpRequest.setRequestHeader ignores prohibited headers. + + + JavaScript: fix 'typeof window'. + + + JavaScript: add dummy implementation of window.pageXOffset and .pageYOffset. + + + Add support for Google App Engine. + + + HtmlCheckBoxInput: trigger onchange event handler on losing focus. + + + Google App Engine support: WebClient uses per default UrlFetchWebConnection when Google App Engine is detected. + + + WebResponse.getLoadTime(): take body download time into account. + + + Remove MemoryInputStream and BinaryPage introduced since release 2.7. + Download large binary content to a temporary file. + + + FileUpload: send Content-Type headers for file parts. + + + JavaScript: allow access to lost elements per name from HTMLFormElement.elements in invalid HTML code. + + + XMLHttpRequest: post method to send query string. + + + JavaScript: set a maximum for infinite recursion. + + + Deprecate WebResponse.getContentAsBytes(). + + + JavaScript: make form elements only accessible by their original name (IE) + or by all the names they have had (FF). + + + Deprecated IsDescendantOfContextualFormFunction. + + + JavaScript: fire onchange for &lt;input type='password' ...&gt; when field loses focus and value has been changed. + + + Fix NullPointerExceptin occurring when for JavaScript submitting form with hash multiple times. + + + HtmlTextArea.asXml(): escape XML characters. + + + JavaScript: events fired by HTMLOptionElement should have 'srcElement' of the enclosing Select. + + + JavaScript: fix event.button of click events with IE. + + + JavaScript HtmlUnit RegExp proxy: use empty string for existing replacement groups without value. + + + HtmlPage.save: add support for (i)frames. + + + HtmlPage.save should not modify the current DOM. + + + JavaScript: window.execScript returns undefined and not null (IE only). + + + JavaScript: add support for function HTMLDocument.clear. + + + JavaScript: add support for globalStorage, localStorage and sessionStorage. + + + Page: add .getUrl(). + + + Add support for SOCKS proxy (at WebClient and WebRequest levels). + + + Add UrlFetchWebConnection, an experimental WebConnection with limited functionalities but that doesn't require HttpClient. + + + HtmlArea: set 'Referer' header on clicking. + + + Don't send charset information in Content-Type header for application/x-www-form-urlencoded POST requests. + + + Fix MemoryInputStream.read() for negative values. + + + Upgrade HttpClient to 4.0.1. + + + Deprecate BrowserVersion static constants. + + + StringWebResponse: take care of provided charset for parsing. + + + JavaScript: support string.trim(), .trimLeft() and .trimRight() (FF 3.6 only). + + + Initial support for FF 3.6. + + + Implement DomComment.getCanonicalXPath(). + + + INCOMPATIBLE CHANGE: WebResponse is now a class not an interface. WebResponseImpl is deprecated. + + + Fix asText() of HtmlCheckBoxInput and HtmlRadioButtonInput. + + + JavaScript: fix document.getElementsByTagName() for elements with prefix. + + + HtmlImageInput: fix submitted parameters. + + + BinaryPage: change threshold to 300 bytes, and handle chunked content. + + + Deprecate WebRequestSettings, WebResponse.getRequestSettings() and MockWebConnection.getLastWebRequestSettings(). + + + Correctly handle URLs with '%'. + + + JavaScript: add support for KeyboardEvent.which (FF only). + + + JavaScript: add support for navigator.productSub (FF only). + + + JavaScript: fix ClassCastException in window.open(). + + + DomElement.asXml(): escape only <, & and " in attribute values. + + + HtmlPage: add .isQuirksMode(), .querySelector() and .querySelectorAll(). + + + Remove StringScriptPreProcessor. + + + JavaScript: add empty implementation of window.stop (FF only). + + + JavaScript: fire (i)frames onload event even for non-HTML pages. + + + JavaScript: use a single Java thread for executing background JavaScript tasks. + + + WebRequestSettings: add support for basic authentication inside the URL. + + + DomNode.isDisplayed() (and by extension, DomNode.asText()) should ignore CSS styling when CSS has been disabled. + + + JavaScript: return window proxies from window.open(), window.top, window.parent, window.self, window.window and window.opener; + proxy window.document and frame.contentDocument, too. + + + JavaScript: add support for HTMLTableCellElement.width and .height attributes. + + + JavaScript HtmlUnit RegExp proxy: don't escape unicode escape sequence in regular expression. + + + Fix exception on HTTP response with code 302 without Location header. + + + JavaScript: implement stack property on exceptions. + + + HtmlTable.asText(): display first thead at the top, even if it appears after some tbody. + + + JavaScript: fixed ClassCastException occurring in IE simulation while accessing XMLHttpRequest.responseXML + when content uses XHTML namespace and contains a checked radio button. + + + JavaScript: offsetHeight and offsetWidth should be 0 for elements with display:none, regardless of their contents. + + + When applying CSS rules to elements, take the media type into account. + + + JavaScript: fixed exception when calling setTimeout during window unload. + + + Add BinaryPage to support download of large files. + + + JavaScript: Form elements are also functions that take a child element's id, name or index and return the corresponding element (IE only). + + + JavaScript: add support for element.removeAttributeNode() (FF only). + + + Add implementation of DomText.getCanonicalXPath(). + + + JavaScript: img.onload functions not always called when img.src modified. + + + JavaScript: Dynamically-added frame.onload and img.onload functions were sometimes being ignored. + + + Clicking an element should make enclosing window the current one. + + + Fixed ClassCastException occurring while accessing XMLHttpRequest.responseXML when content uses XHTML namespace and contains an (i)frame. + + + JavaScript: added simple implementation of TextRange.setEndPoint (IE only). + + + JavaScript: implement window.scroll(x, y), window.scrollBy(x, y), window.scrollTo(x, y), window.scrollByLines(lines) + and window.scrollByPages(pages). + + + Parser: place text located between </TD> and </TR> before the enclosing TABLE. + + + JavaScript HtmlUnit RegExp proxy: handle two digits replacement references. + + + JavaScript: allow to set HTMLTableColElement's width to null. + + + INCOMPATIBLE CHANGE: add an extra parameter (int lineNumber) to ScriptPreProcessor.preProcess(). + + + JavaScript: add dummy support for window.external.AutoCompletionSave() (IE only). + + + JavaScript: fix document.getElementsByName() to handle empty and null values. + + + Deprecation: remove DomText.splitDomText(), HtmlPage.getFirstAnchorByText(), WebClient.setIgnoreOutsideContent(), + WebResponse.getRequestUrl, .getRequestMethod() and .getContentCharSet(), HTMLParser.parse() + and WebRequestSettings.addAdditionalHeader(). + + + + + + JavaScript: allow access to a frame through document.frameName (IE only). + + + JavaScript: better implementation of element.scrollLeft and element.scrollTop properties. + + + JavaScript HtmlUnit RegExp proxy: handle $&, $' and $` in replacement string. + + + Removed public method HtmlForm.submit(SubmittableElement) without replacement (method was marked as internal API). + + + JavaScript: StringScriptPreProcessor to use Rhino AST. + + + JavaScript: many calls to form.submit after change of the action attribute causes many downloads + and only the last one is parsed and loaded into the window. + + + JavaScript: fix dynamically loading of external script when loading a page as result of a click. + + + JavaScript: resolve relative URLs from opener's URL when document.write is used in a window opened with window.open. + + + DomNode.asText(): don't include children of <noscript> if JavaScript is enabled. + + + JavaScript: empty implementation of CanvasRenderingContext2D.drawImage() (FF). + + + INCOMPATIBLE CHANGES (HttpClient 4 migration preparation): use internal NameValuePair class in the public + APIs (rather than HttpClient's NameValuePair class); use internal Cookie class in the public APIs (rather + than HttpClient's Cookie class). + + + JavaScript: execute script with event attribute only when value is "onload" (FF). + + + DomNode.asText(): H1, H2, H3, H4, H5 and H6 are blocks. + + + JavaScript: ensure that elements returned by Selection.getRangeAt are of the right type (FF only). + + + JavaScript: document body is selection's start element when designMode='on' is set and body has no child element (FF only). + + + Throw exception with explicit message when maximum of allowed HTTP redirects is reached. + + + JavaScript: fix parseFloat for values like "40em". + + + JavaScript: add support for Function.caller. + + + Update htmlunit-core-js to Rhino head of 07.01.2010 + custom patches. + + + Redirect limit should apply regardless of whether or not the redirects are to the same URL. + + + JavaScript: fix value of element.offsetTop attribute when element's position is relative. + + + JavaScript: fix format of document.lastModified attribute. + + + JavaScript: fix XMLHttpRequest with empty body of 'PUT' method. + + + JavaScript: allow setting element.width and .height to a value that ends with 'px'. + + + JavaScript: fix computed element widths and heights when percentages are involved in the CSS. + + + Deprecated BrowserVersion.FIREFOX_2. + + + Add WebClientUtils.attachVisualDebugger(WebClient). + + + JavaScript: add support for "onerror" event handlers on script nodes (FF only). + + + JavaScript: better value for document.body.clientHeight. + + + WebClient.closeAllWindows: improved JavaScript threads termination. + + + Add WebWindow.isClosed(). + + + JavaScript HtmlUnit RegExp proxy: escape dollar after escaped backslash. + + + JavaScript HtmlUnit RegExp proxy: un-escape illegally escaped characters. + + + Change TopLevelWindow and DialogWindow constructors' visibility to protected. + + + Don't pick invisible frame window as the current window. + + + CSS: don't override rules with a higher specificity. + + + JavaScript: window.getSelection() returns null for frame windows that are not displayed (FF only). + + + MetaTag: fix NPE in encoding detection. + + + Don't skip form submission to same URL when triggered from an anchor with href="#". + + + JavaScript: added support for functions ScriptEngine, ScriptEngineMajorVersion, ScriptEngineMinorVersion, and ScriptEngineBuildVersion (IE only). + + + JavaScript: keyCode of lower case characters is the same than upper case ones. + + + JavaScript: add support for HTMLTextArea.setSelectionRange (FF only). + + + JavaScript: enforce same-origin policy for XMLHttpRequest. + + + Use style sheets too to compute DomNode.isDisplayed. + + + HtmlNoFrames.asText() returns empty string. + + + JavaScript: XMLHttpRequest.responseXML is null when send() has not been called. + + + JavaScript: XMLHttpRequest.responseXML is accessible when no content type header is present. + + + JavaScript: log exceptions thrown in background threads. + + + IEConditionalCompilationScriptPreProcessor should ignore string literals. + + + HtmlNoFrames: preserve inner XML content. + + + JavaScript: add support for ProcessingInstruction during parsing. + + + JavaScript: better calculation of element.offsetTop and element.offsetHeight properties. + + + Implement setter and getter for textContent on DomAttr. + + + JavaScript: fix exception accessing selectionStart and selectionEnd on inputs of type password. + + + JavaScript: better calculation of element.offsetLeft property. + + + JavaScript: document.write() should have an affect (by implicit postponed call to close()). + + + Empty frames added via JavaScript shouldn't ever really become the "current window". + + + JavaScript: fix attribute.setNodeValue(). + + + JavaScript: fix NPE when element.setAttributeNode() is called for non-existing attribute. + + + JavaScript HtmlUnit RegExp proxy: escape "$" in replacement string for String.replace. + + + JavaScript HtmlUnit RegExp proxy: replace "$$" by "$" in replacement string for String.replace. + + + DefaultCredentialsProvider: addCredentials should overwrite previous values. + + + JavaScript: fix setting of element.innerText and .textContent with empty string or null. + + + Meta refresh: handle space as separator between delay and url. + + + JavaScript: events focus and blur don't apply to all kind of HTML elements. + + + JavaScript: add support for onerror handler. + + + Fix issue where WebClient.waitForBackgroundJavaScriptStartingBefore hangs (setInterval with short interval). + + + HtmlScript: "for" and "event" attributes for 'window' are ignored by FF. + + + JavaScript: MouseEvent.initMouseEvent and KeyboardEvent.initKeyEvent initialize metaKey + + + Fixed StringIndexOutOfBoundsException occurring when typing in a cloned text input or textarea node. + + + JavaScript: pre-process \xDD in string literals before IE conditional compilation. + + + JavaScript: allow MouseEvent to have independent client coordinate values, if necessary. + + + Fix the DomNodeList returned by DomNode.getChildNodes() so that it behaves correctly when children are removed from the DOM. + + + Deprecate DomNode.getAllHtmlChildElements(); replaced by the more intuitively named DomNode.getHtmlElementDescendants(). + + + JavaScript: implement range.extractContents() (Firefox only). + + + JavaScript: properly handle body elements with qualified name. + + + Fix Node.setTextContent() to set the text for comment, cdata, text and processing instruction nodes, + rather than appending a new text node. + + + JavaScript: mouse event 'ondblclick' should not trigger 'onclick' handler. + + + CSS: add support for rule priority. + + + JavaScript: properly escape XML entities in .xml property (IE) and XMLSerializer (FF). + + + JavaScript: add support for HTMLDocument.lastModified. + + + JavaScript: support the serialization of comments in .xml property (IE) and XMLSerializer (FF). + + + JavaScript: implement element.getAttributeNodeNS() (Firefox only). + + + JavaScript: XMLHttpRequest.open throws an exception when the provided url is null or an empty string. + + + Fix caching of page's document element even after the document element has been removed from the page. + + + JavaScript: add support for XMLHttpRequest.onload (Firefox only). + + + JavaScript: document.activeElement is the document body by default (IE only). + + + JavaScript: add support for selection.addRange(), selection.removeAllRanges() and selection.removeRange() (FF only). + + + JavaScript: add support for TextRange.htmlText and TextRange.moveToElementText (IE only). + + + JavaScript: handle namespaces when serializing XML. + + + JavaScript: window.location should start with 'file:///' instead of just 'file:/' when dealing with a local file. + + + JavaScript: HTMLTableCellElement.cellIndex, HTMLTableRowElement.rowIndex + and sectionRowIndex (FF only) return -1 when the element is not added to the document. + + + Don't allow JavaScript catch statements to catch HtmlUnit internal errors. + + + JavaScript: fix how document.write() detects complete string. + + + The default value of range.startContainer and range.endContainer is the document itself (Firefox only). + + + JavaScript: primitive support for xmlDocument.createNode() (IE only). + + + JavaScript: implement attributes.setNamedItem(). + + + Avoid errors triggered by images with onload attributes and invalid src URLs. + + + HtmlPage.getPageEncoding() was sometimes returning a different encoding than the encoding actually used to parse the page. + + + Implement DomAttr.getSpecified() and SgmlPage.createAttribute(). + + + JavaScript: HTMLElement.offsetWidth and offsetHeight are 0 when the element is hidden. + + + DomNode.asText() considers UL content that is not within a LI too. + + + Fix HtmlHtml.getCanonicalXPath() when document contains a doctype declaration. + + + Form submission: don't send a Content-Type header when method is GET. + + + FormEncodingType.getInstance returns URL_ENCODED if the requested encoding type doesn't exist. + + + JavaScript: don't call (i)frame's onload handler for the dummy page that fill the frame until the real content is loaded. + + + Loading about:blank in an existing window resets the JavaScript scope for the window. + + + JavaScript: window.opener is always writable for IE and only in special cases for FF. + + + When a textarea receives focus its content is not selected and call to type(...) causes content to be appended. + + + Click on a non form element removes focus from current element and triggers handlers if needed. + + + JavaScript: respect headers set by XMLHttpRequest.setRequestHeader(). + + + JavaScript: improve resolution performance of "someForm.someField" when many elements in the page + have "someField" as id or name attribute but only one in the provided form. + + + List returned by HtmlPage.getElementsByIdAndOrName is now mutable. + + + JavaScript: delete operator should not walk property chain. + + + Upgrade HtmlUnit-core-js to 2.7-SNAPSHOT (corresponds to head of Rhino trunk from Sep 21, 2009 + minimal adaptations). + + + JavaScript: remove String functions "equals" and "equalsIgnoreCase", + Array functions "reduce" and "reduceRight" (FF2 and IE), + global functions "isXMLName" and "uneval" (IE) as well as "toSource" on all objects (IE). + + + JavaScript: properly handle element.textContent with null value (FF only). + + + JavaScript: set the checked property of input of type 'radio' to defaultChecked when it is attached (IE only). + + + JavaScript: HTMLImageElement's height and width are numbers, not strings. + + + HTMLElement.offsetWidth tries to compute width depending on the content when CSS attribute float is set to "right" or "left". + + + CSS: add support for CSS3 pseudo classes :root, :enabled, :checked. + + + JavaScript: HTMLStyleElement.sheet parses all child nodes and not only the first one. + + + JavaScript: fix style 'pixel' attributes. + + + JavaScript: HTMLTableElement's properties caption, tHead and tFoot are writable (FF only) with right parameters, + otherwise an exception is thrown. + + + JavaScript: add support for HTMLTableRowElement.sectionRowIndex. + + + JavaScript: add support for DOMException constants (FF only). + + + JavaScript: HtmlDocument.createTreeWalker accepts function as filter (FF only). + + + Fix memory leak when many different BrowserVersion instances used. + + + JavaScript: HtmlButtonElement.type falls back to default value ("submit" for FF, "button" for IE) when attribute "type" is removed. + + + Add IE8 support. + + + JavaScript: appendChild, insertBefore and replaceChild throw exception (FF) or silently fail (IE) when parameter is the HTML node. + + + HtmlAnchor: fix characters escaping if 'href' is a javascript. + + + Correctly clean up "/./" and "/../" sequences from URLs. + + + JavaScript: fix button.type attribute. + + + JavaScript: perform delayed form submission with fields and target values at the moment where HtmlFormElement.submit is called. + + + JavaScript: add primitive support for MutationEvent. + + + JavaScript: use KeyboardEvent in htmlElement.type() and add support for .charCode. + + + JavaScript: normal submit button action has priority over HtmlFormElement.submit() called in onclick handler. + + + JavaScript: when link's onclick changes location the next page is still the one mentioned in href. + + + JavaScript: avoid multiple form submissions when HtmlFormElement.submit() is called multiple times. + + + BrowserVersion: remove deprecated methods related to JavaScript version. + + + Update JavaDoc of HtmlElement.click methods to reflect what already happens: click returns + the page in the WebClient's current window. + + + Remove deprecated ClickableElement and StyledElement. + + + + + + JavaScript: add basic support for element.scopeName and .tagUrn (IE only). + + + JavaScript: HtmlFormElement.action returns the fully qualified URL (FF only). + + + JavaScript: setting HtmlTextAreaElement's defaultValue changes the current value if it is still the initial one (FF only). + + + JavaScript: add primitive support for KeyboardEvent. + + + Allow "javascript:..." URLs with encoded script code. + + + Use the browser language (from the BrowserVersion being used) to set the value of the "Accept-Language" HTTP header. + + + Don't treat 304 responses as if they were redirections. + + + JavaScript: node.insertBefore() handles undefined variable. + + + Cache: use cache for all kinds of (cacheable) content. + + + CSS: resolve relative URLs in @import rule from URL of current style sheet. + + + JavaScript: HTMLSelectElement throw exception when invalid value is set to selectedIndex (FF only). + + + DebuggingWebConnection: display received headers in generated report, added addMark method. + + + CookieManager: handle cookies with null value. + + + JavaScript: handle empty code. + + + Upgrade commons-codec to 1.4 + + + JavaScript: document.getElementById() and document.getElementsByNames() trigger implicit document.close() calls (IE only). + + + JavaScript: window.frames returns a reference to the window itself. + + + Force NekoHtml and Xalan to use xercesImpl 2.9.1 dependency. + + + Add selection-related methods to HtmlPasswordInput. + + + JavaScript: fixed NPE calling inRange with selection range when nothing is selected (IE only). + + + Add TITLE to HEAD even if it is found in BODY. + + + Submit image button name too (FF only). + + + Include caption in HtmlTable's asText() representation. + + + Fix DomNode.compareDocumentPosition() (FF only). + + + JavaScript: add support for the compact attribute on ul, ol, menu, dl and dir elements. + + + JavaScript: implement node.normalize(). + + + JavaScript: support the serialization of CDATASection in .xml property (IE) and XMLSerializer (FF). + + + HtmlScript: fix the order of "type" and "language" attributes evaluation. + + + DomText: deprecate splitDomText(), use splitText() instead. + + + JavaScript: fix .prefix attribute of xml nodes. + + + JavaScript: fix text.splitText(). + + + JavaScript: implement xmlDocument.getElementsByTagName(), .getElementsByTagNameNS() and .nodeFromID(). + + + Fix many issues with WebClient serialization and deserialization. + + + Load stylesheets referenced via @import. + + + JavaScript: fix XMLSerializer for non-element nodes (FF only). + + + JavaScript: move .xml attribute from xmlElement to xmlNode (IE only). + + + INCOMPATIBLE CHANGE: rename DomCData to DomCDataSection. + + + JavaScript: node.appendChild() can be called inside xmlDocument. + + + XmlDocument: implement .createProcessingInstruction() and .createCDATASection(). + + + JavaScript: add support for map.areas attribute. + + + JavaScript: process scripts with 'application/javascript' type (FF only). + + + JavaScript: return collection if elements with duplicate IDs are found (IE only). + + + Properly handle unicode characters in requested URLs. + + + Deprecate WebClient.setIgnoreOutsideContent and HTMLParser.setIgnoreOutsideContent. + + + Set 'referer' header on loading pictures and CSS files. + + + JavaScript: add basic support for CSSValue, CSSPrimitiveValue, and CSSStyleDeclaration.getPropertyCSSValue (FF only). + + + JavaScript: set currentTarget on event when event handler is called after global event listener. + + + Cleanup "/./" and "/../" in URLs before to perform a request. + + + Fixed ConcurrentModificationException occurring in invalidation of computed styles when + an other page tried to access some style information at the same time. + + + JavaScript: about:blank (i)frame domain is the one of the container page (FF and IE) + and same rules apply to set domain (FF only). + + + CSS: invalidate style of child elements when node attribute is changed. + + + JavaScript: read only properties can't be written (FF3 only). + + + JavaScript: parseFloat trim leading new line signs. + + + Incorrect HTML: move DIV within TABLE before the TABLE. + + + HtmlPage.asXml(): don't escape XML special characters when style node contains an XML comment. + + + Correctly fire load events attached to script nodes via addEventListener (FF only). + + + JavaScript: document.namespaces can be used as a function (IE only). + + + Fix NullPointerException thrown for script tags referencing a resource that returns a 204 (No Content) response. + + + JavaScript: add support for the window.onbeforeunload attribute. + + + JavaScript: add support for textarea.rows and textarea.cols attributes. + + + Some CSS properties are inherited from parent elements (computed styles only). + + + JavaScript: form submission should consider event.preventDefault() (FF only). + + + JavaScript: make dummy implementation of HtmlDocument.elementFromPoint available for FF as well. + + + JavaScript: add support for the colSpan, rowSpan, noWrap, axis and abbr attributes on td and th elements. + + + JavaScript: add support for the bgColor attribute on table, tr, td and th elements. + + + Add support for Proxy Auto-Config. + + + JavaScript: call onbeforeunload handler when TopLevelWindow.close() is called. + + + JavaScript: reserve the duplicate ID attribute behavior on changing other attributes. + + + JavaScript: add support for attributes align, vAlign, ch and chOff for thead, tbody, tfoot, tr, td, and th elements. + + + CSS: properly handle 'lang' condition. + + + Handle HTML pages with empty 'Content-Type' HTTP header. + + + Handle 204 (No Content) HTTP responses correctly. + + + JavaScript: implement TextRange.inRange (IE only). + + + Check meta tags inside HTML pages for encoding information. + + + JavaScript: add support for br.clear attribute. + + + JavaScript: add support for option.form, legend.form, object.form and label.form attributes. + + + Add better support for XHTML pages (new XHtmlPage class extends HtmlPage class). + + + JavaScript: add support for fieldSet.form and fieldSet.align attributes. + + + JavaScript: add support for body.aLink, body.background, body.bgColor, body.link, body.text and + body.vLink attributes. + + + JavaScript: add support for attr.isId attribute (Firefox 3 only). + + + Update page URL when navigating to a local anchor. + + + JavaScript: implement placeholder functions history.back(), history.forward() and history.go(). + + + JavaScript: fix setting select.value. + + + Extending NodeList to implement List<E extends DomNode>. + + + JavaScript: fix document.referrer. + + + JavaScript: fix document.createAttribute(). + + + HtmlObject: "classid" is supported (using Jacob). + + + HtmlSelect: add .getOptionByText(). + + + HtmlPage and HtmlImage: add .save(). + + + Change default value for "Accept-Language" HTTP header to "en-us". + + + HtmlForm: properly handle 'action' which starts with a question mark. + + + Deprecate WebRequestSettings.addAdditionalHeader() and HtmlPage.getFirstAnchorByText(). + + + Handle XmlPage with NO_CONTENT HTTP status. + + + JavaScript: option.selected does not necessarily mean there is 'selected' attribute. + + + JavaScript: correct attribute .firstChild and .lastChild (FF only). + + + IE Conditional comments: handle comments with invalid expressions as plain text. + + + JavaScript: handle multiple conditional compilation comments (IE only). + + + JavaScript: document.getElementById() should be case insensitive (IE only). + + + JavaScript: body element of a frame has to be null while loading only as long as nothing has been loaded (IE only). + + + JavaScript: initially implement properties of HTMLMetaElement. + + + JavaScript: add support for iframe.width and iframe.height properties. + + + JavaScript: add element.document (IE only). + + + WebRequestSettings: add .removeAdditionalHeader() and make headers case-insensitive. + + + JavaScript: implement xmlDocument.createElementNS() (FF only). + + + JavaScript: 'class' attribute should be trimmed (FF only). + + + JavaScript: fix properties defined in super objects (IE only), + and fix .getAttribute() and .getAttributeNode(). + + + Parser: don't recognize &prod as incomplete entity. + + + JavaScript: fix incorrect escaping of backslash in replacement for String.replace(String, String). + + + JavaScript: primitive implementation of canvas (FF only). + + + JavaScript: better implementation for "node's attributes collection is never empty for IE". + + + JavaScript: option.value should not be affected by the text content (IE only). + + + JavaScript: add support for caption.align (IE and FF) and caption.vAlign (IE only). + + + Add WebClient.getTopLevelWindows(). + + + Ignore content-type meta tag if HTTP header is specified. + + + WebResponse: Deprecate .getContentCharSet(), .getRequestMethod(), and .getRequestUrl(). + Add .getContentCharset() and .getContentCharsetOrNull(). + + + JavaScript: add support for selection.empty() and selection.type (IE only). + + + JavaScript: setInterval() invocations with a 0 millisecond delay behave like setTimeout() invocations in IE. + + + JavaScript: add support for the col.align, col.vAlign, col.span, col.width, col.chOff and col.ch attributes. + + + JavaScript: add support for input.accessKey, label.accessKey, anchor.accessKey, button.accessKey, + legend.accessKey, textarea.accessKey and area.accessKey (Firefox only). + + + Deprecation: remove HtmlAttr, XmlElement, BrowserVersion.INTERNET_EXPLORER_6_0, .isNetscape(), getNickName(), + DomAttr.getHtmlValue(), .getAttributeValue(), + HtmlElement.isAttributeDefined(), .getAttributesCollection(), .getHtmlElementById(), .getHtmlElementsByAttribute(), + HtmlPage.createHtmlElement(), WebResponse.getLoadTimeInMilliSeconds(), .getResponseBody(), and .getUrl(). + + + + + + Upgrade HtmlUnit-core-js to 2.5. + + + Upgrade NekoHtml to 1.9.12. + + + JavaScript: fix ClassCastException setting or reading property readOnly of HtmlTextAreaElement. + + + JavaScript: added support for HTMLTableRowElement.deleteCell. + + + HtmlUnit-core-js now changes package names from org.mozilla.* to net.sourceforge.htmlunit.corejs.* to allow project + to use "original" Rhino together with HtmlUnit. + + + Add HtmlPage.getElementByName(String) method. + + + Remove leading "../" (if any) when resolving URLs. + + + JavaScript: don't try to instantiate applets accessed by JavaScript when applet support is disabled. + + + HtmlOption: handle markup in nested content when it has to be used as default value. + + + HtmlOption.asText(): no need to consider label attribute. + + + HtmlOption: label attribute should not be considered in asText(). + + + JavaScript: dynamically created iframe should load external scripts. + + + HtmlPage: getFullyQualifiedUrl() should be relative to page of the top window. + + + (EXPERIMENTAL) Add WebClient.waitForBackgroundJavaScript() and WebClient.waitForBackgroundJavaScriptStartingBefore(), + which allow waiting for JavaScript background jobs to finish (should be used instead of JavaScriptJobManager methods, + which are internal APIs). + + + Add DomNode.isDisplayed() to the public API. + + + JavaScript: add support for reading and writing img.align, p.align, table.align, thead.align, tbody.align, tfoot.align, + iframe.align, input.align and applet.align properties. + + + JavaScript: add support for reading and writing the base.href and base.target properties. + + + JavaScript: window.event should be available during execution of script.onreadystatechange handler (IE only). + + + JavaScript: element.getElementsByTagNameNS() can accept null 'namespaceURI'. + + + Correctly initialize style attribute of images created via JavaScript. + + + JavaScript: add support for 'oninput' events on text inputs (Firefox only). + + + JavaScript: window.open() can accept numeric name. + + + JavaScript: in an XMLHttpRequest handler, 'this' is the handler when simulating FF2 and the XHR otherwise. + + + ToplevelWindow.close() deregisters sub-frames. + + + JavaScript: add support for window.length. + + + HtmlForm: submit to the same page if 'action' attribute is not defined. + + + Apply ScriptPreProcessor to window.eval(). + + + HtmlPage.asXml(): expand empty UL and OL nodes to make generated XML readable as HTML on browsers. + + + Upgrade HtmlUnit-core-js to 2.5 (corresponds to head of Rhino branch 1.7R2 from Dec 12, 2008 + fix for Rhino issue 477604). + + + JavaScript: add support for selection.getRangeAt() (Firefox only). + + + JavaScript: add support for CSSImportRule. + + + Make password inputs listen to event.preventDefault(). + + + JavaScript: calling event.stopPropagation() shouldn't preclude using multiple event listeners of the same + type on a single node. + + + JavaScript: add support for event.cancelBubble in Firefox emulation mode (already present in IE emulation mode). + + + JavaScript: setting event.returnValue=false should abort the event (IE only). + + + JavaScript: add support form.item() (IE only). + + + When a form is submitted via JavaScript (form.submit()), form submittal should not actually occur until + after the current script finishes executing. + + + Fix content type sniffing for local XHTML files. + + + Fix case-sensitivity of XPath expressions for XHTML documents that are served as 'text/xml'. + + + JavaScript: add support for the window.onerror attribute. + + + JavaScript: document functions should be usable without a reference to the document (IE only). + + + JavaScript: add support for element.clearAttributes() and element.mergeAttributes() (IE only). + + + JavaScript: handle invalid back references in string.replace(...) as if they were escaped. + + + JavaScript: remove objects created by Rhino in window scope like 'com' that aren't available in browsers. + + + JavaScript: process false return value of handlers added by .attachEvent() or .addEventListener(). + + + JavaScript: make prototype available on DOM nodes as __proto__ (FF only). + + + JavaScript: hide standard Object and Array functions that don't exist on IE. + + + JavaScript: Expand support for document.namespaces collection. + + + JavaScript: XMLSerializer should properly handle Document. + + + JavaScript: Date.getYear() returns four digits for years before 1900 and after 1999 when simulating IE. + + + JavaScript: single submission of form if onclick handler of HTMLSubmitInput also submits the form. + + + Add default value for "Accept" and "Accept-Language" HTTP headers. + + + JavaScript: add support for HTMLElement.removeNode(). + + + JavaScript: move removeAttribute() from HTMLElement to Element. + + + JavaScript: element.doScroll() should throw an exception if page is not yet loaded. + + + JavaScript: fix the return value of node.insertBefore(). + + + JavaScript: fix behavior when document.cookie is set to an empty string or a string without an '=' character. + + + JavaScript: fix element.parentElement if the parent is DocumentFragment. + + + JavaScript: anchor's href attribute is empty string when no href was specified. + + + JavaScript: custom RegExp proxy now ignores back references in character class as browsers do. + + + Correct JavaScript parent scope after using WebClient.setCurrentWindow. + + + JavaScript: add support for Enumerator (IE only). + + + JavaScript: custom RegExp proxy now accepts unescaped opening square brackets in character class. + + + JavaScript: add support for HTMLDocument.dispatchEvent (FF only). + + + JavaScript: properties of XMLHttpRequest ActiveX object are case insensitive. + + + Allow numbers with decimal points in refresh meta tags. + + + JavaScript: XMLHttpRequest is supported in IE7. + + + Fail gracefully when script tags contain empty 'src' attributes. + + + Make the cookie manager thread-safe. + + + JavaScript: setting anchor.hash should accept values both with and without the '#' character. + + + JavaScript: values returned by anchor.hash should include the '#' character. + + + JavaScript: add support for HTMLElement.dir, .lang, .tabIndex and .spellcheck. + + + JavaScript: add support for window.atob() and btoa(). + + + JavaScript: compute URL relatively to owning page for showModelessDialog and showModalDialog. + + + IE Conditional comments: accept expressions that contain identifier other than IE (like mso). + + + If content-type meta tags contain empty encoding information, ignore it and use the default encoding. + + + Ignore namespaces if the tag name does not have a prefix. + + + DomElement.getElementsByTagName() should search in only sub-elements. + + + JavaScript: add support for document.createComment(). + + + Deprecate ClickableElement and StyledElement, directly use HtmlElement instead. + + + JavaScript: add initial support for TextRange.moveStart() and .moveEnd(). + + + JavaScript: add support for document.getElementsByClassName and HTMLElement.getElementsByClassName (FF3 only). + + + JavaScript: document.execCommand doesn't throw an exception when called with unknown command (FF3 only). + + + JavaScript: document.scripts doesn't exist for FF. + + + JavaScript: when simulating Firefox, document.write(ln) returns the function, + no matter if elements with this name are present or not. + + + JavaScript: document.createEvent doesn't initialize the target property under FF3. + + + JavaScript: document.all('notExisting') returns undefined for FF. + + + JavaScript: tags property exists on collections for FF2 but not for FF3. + + + JavaScript: prototype should not be enumerated (FF). + + + JavaScript: IE does not enumerate objects methods. + + + BrowserVersion: deprecate setJavaScriptVersion(), getJavaScriptVersion() and getJavaScriptVersionNumeric(). + + + Replace ThreadManager with JavaScriptJobManager, which internally uses the executor services provided by JDK 5. + + + Add HtmlAbbreviated, HtmlAcronym, HtmlBackgroundSound, HtmlBig, HtmlBlink, HtmlBold, HtmlCitation, HtmlCode, HtmlDefinition, + HtmlEmphasis, HtmlExample, HtmlItalic, HtmlKeyboard, HtmlListing, HtmlMarquee, HtmlMultiColumn, HtmlNoBreak, HtmlNoEmbed, HtmlPlainText, HtmlS, HtmlSample, + HtmlSmall, HtmlSpacer, HtmlStrike, HtmlStrong, HtmlSubscript, HtmlSuperscript, HtmlTeletype, HtmlUnderlined and HtmlVariable. + + + Deprecation: remove XmlAttr, SubmitMethod, WebRequestSettings.setURL(), and + WebClient methods: setCookiesEnabled(), setProxyHost(), setProxyPort(), addHostsToProxyBypass(), + and removeHostsFromProxyBypass(). + + + + + + Upgrade HtmlUnit-core-js to 2.4 (corresponds to head of Rhino branch 1.7R2 from Dec 12, 2008). + + + Upgrade NekoHtml to 1.9.11. + + + Add support for HtmlEmbed, HtmlCanvas and HtmlWordBreak. + + + JavaScript: correct the return value of EventNode.fireEvent(). + + + JavaScript: add dummy implementation for TextRange methods collapse and select (IE). + + + JavaScript: replace \n with \r\n for property defaultValue of HtmlTextAreaElement (IE) and ignore leading new line sign. + + + JavaScript: frame window object retrieved through should be live and reflect page loads in the window. + + + JavaScript: do not throw exception on invalid regular expressions. + + + Support for IE conditional comments in HTML code. + + + JavaScript: removeAttribute should delete node property too (IE only), + getAttribute returns property if no attribute is found (IE only). + + + JavaScript: fixed exception occurring while accessing src property of freshly created Image object. + + + HtmlPage.asXml(): expand empty table nodes to make generated XML readable as HTML on browsers. + + + HtmlTextArea.type(...) should not trigger onchange handler. + + + Delay execution of image onload handlers after the page finish to load. + + + First experiments to support applets. + + + 100% success with MochiKit unit tests. + + + JavaScript: HTMLElement.filters is not undefined (IE only). + + + JavaScript: offsetParent is undefined for detached nodes. + + + JavaScript: HTMLHtmlElement's clientWidth and clientHeight gives the available screen size. + + + CSS: font-size is inherited. + + + CSS: parse shorthand background to find background color. + + + CSS: parse individual border width from borderWidth. + + + JavaScript: add dummy implementation for HTMLElement's clientLeft and clientTop. + + + Deprecate HtmlPage.getHtmlElementByAccessKey(), HtmlPage.getHtmlElementsByAccessKey(), + HtmlPage.getHtmlElementsByName(), HtmlPage.getHtmlElementsByIdAndOrName(), + HtmlElement.getHtmlElementsByAttribute() and HtmlElement.getHtmlElementById(). + + + Deprecate DomElement methods getAttributeValue, setAttributeValue. + Usage of DOM 2 methods getAttribute, getAttributeNS, setAttribute and setAttributeNS is preferred. + + + Deprecate XmlPage.getDocumentXmlElement(), HtmlPage.createHtmlElement() and createHtmlElementNS(). + + + Document and Element.getElementsByTagName() should not be affected by namespaces. + + + JavaScript: node's attributes collection is never empty for IE. + + + JavaScript: add support for Comment object. + + + JavaScript: prototype for event handlers should be the function prototype. + + + JavaScript: add support for document.captureEvents (FF). + + + JavaScript: fix option.text. + + + JavaScript: add support for window.showModalDialog() and window.showModelessDialog(). + + + JavaScript: support Text object. + + + HtmlInput: typing enter should behave as clicking submit input. + + + JavaScript: added support for document.applets. + + + JavaScript: add support for getting and setting the image.onload attribute. + + + If an image has an onload handler, download the image and then invoke the onload handler. + + + JavaScript: add support for elements.nextNode() and elements.reset() for the element collection returned + by XmlDocument.selectNodes(...) (IE only). + + + JavaScript: fix setting input.type if it is the first child. + + + When querying elements for namespaced attributes, don't fall back to returning non-namespaced attributes. + + + JavaScript: add support for element.removeAttributeNS() (FF only). + + + JavaScript: dummy support for XUL element in HtmlDocument.createElementNS (FF only). + + + JavaScript: window.controllers is not null (FF only). + + + JavaScript: IE ignores empty text children. + + + JavaScript: add support for document.queryCommandEnabled(). + + + JavaScript: add partial support for window.getSelection() (FF only). + + + JavaScript: element.style.opacity only accepts numeric values when emulating FF. + + + JavaScript: fix element.style.display default values when emulating IE. + + + JavaScript: element.style length-related attributes should be converted to pixels (FF only). + + + JavaScript: postpone the execution of setting 'location.href'. + + + JavaScript: select.appendChild(option), .add(), and insertBefore() should update .selectedIndex. + + + Silently ignore HTTP Status code "USE_PROXY" (305), and treat it as success. + + + XPath: proper handling of upper cased HTML elements. + + + Implemented DomNode#compareDocumentPosition and add Node.compareDocumentPosition (FF only). + + + JavaScript: add support for element.contains() (IE only). + + + JavaScript: element.innerHTML should quote anchor href attributes and empty attributes when emulating IE. + + + JavaScript: In certain cases, node collections were returning elements when inexistent attributes were accessed. + + + As per browser conventions, the node for the top-level html tag should only ever contain the head and body tags -- + never any text nodes. + + + JavaScript: make sure element.offsetWidth is constrained by the element's parent's dimensions. + + + CSS rules specified in stylesheets should not override CSS rules specified directly in an element's "style" attribute. + + + JavaScript: implement element.style.pixelLeft, pixelRight, pixelTop and pixelBottom (IE only). + + + JavaScript: fire onchange for &lt;input type='file' ...&gt; when field loses focus and value has been changed. + + + JavaScript: fire focus event not only on &lt;input ...&gt;. + + + Add support for HTMLDocument.createTreeWalker (FF only). + + + Add support for 'deflate' Content-Encoding. + + + HtmlPage.asXml(): expand empty style nodes to make generated XML readable as HTML on Firefox 3. + + + HtmlTextInput: type() should remove selected text(). + + + JavaScript: add support for document.uniqueID (IE only). + + + Made static WebClient methods getJavaScriptTimeout() and setJavaScriptTimeout() non-static, so + that they can be configured on a per-WebClient basis. + + + JavaScript: add support for document.compatMode. + + + HtmlInput: add isReadOnly() and setReadOnly(). + + + JavaScript: node.appendBefore() should run added script element. + + + Set 'referer' header and other additional headers on loading external JavaScript files. + + + JavaScript: window.frames should return the ones with id attribute (IE only). + + + Add support for DocumentType. + + + Better formatting for asText() particularly with new lines for TR, BR or LI and tabs between cells. + + + HtmlElement: correctly handle getNodeName(). + + + JavaScript: correctly handle element.nodeName, .tagName, .prefix, .localName, and .namespaceURI. + + + JavaScript: add support for document.namespaces (IE only). + + + JavaScript: Firefox doesn't support select.options.childNodes. + + + XmlElement: is deprecated, use DomElement instead. + + + HtmlElement: deprecate getAttributesCollection() and isAttributeDefined(). + + + BrowserVersion: deprecate INTERNET_EXPLORER_6_0 and INTERNET_EXPLORER_7_0. + + + JavaScript: document.cookie should overwrite existing cookie. + + + Upgrade Xalan to 2.7.1 + + + FrameWindow: should be Serializable. + + + JavaScript: postpone the execution of dynamically added external scripts. + + + JavaScript: correct script.onreadystatechange behavior for external JavaScript files. + + + JavaScript: add support for script.onload (FF only). + + + JavaScript: Attr.specified queries owner node for attribute's existence. + + + JavaScript: HtmlOptionsElement.getAttributeNode returns a node for attributes "id", "value" and "selected" + even if these attributes weren't specified in HTML code (IE only). + + + JavaScript: HtmlOptionsCollection delegates to enclosing select for FF as well. + + + HtmlSelect: removeOption() and replaceOption() to inspect only HtmlOption children. + + + Upgrade JUnit to 4.5. + + + JavaScript: fireEvent calls handlers with received event object rather than with a copy (IE only). + + + JavaScript: trigger deferred scripts' onreadystatechange handler before onload event (IE only). + + + JavaScript: constant values like TEXT_NODE on elements are not available when simulating IE. + + + JavaScript: objects like HTMLElement don't have a their prototype property in their prototype chain (FF only). + + + JavaScript: use 'className' instead of 'class' to get/set class attribute (IE only). + + + JavaScript: Node.getAttributeNode returns null if no attribute exists with the specified name. + + + Form element can be included as HTML inside XML. + + + JavaScript: fix incorrect value of CSSStyleRule.selectorText when identified by id (like "#foo"). + + + JavaScript: define properties altKey, ctrlKey and shiftKey on UIEvent when simulating Firefox. + + + JavaScript: use UIEvent for keyboard events. + + + JavaScript: cloneNode copies event handlers when simulating IE. + + + Better generics: avoid the need for casting when calling HtmlElement.getHtmlElementById(), + HtmlForm.getInputByName(), and .getInputByValue(). + + + JavaScript: implemented workaround for NPE in CSSParser in some usage of CSSStyleSheet.insertRule. + + + JavaScript: finished implementation of insertRule (FF) and addRule (IE) on CSSStyleSheet. + + + JavaScript: CSSStyleRule.selectorText should return values like ".foo" rather than "*.foo". + + + Deprecation: remove HtmlUnitXPath class, DomNode.getXXXDomYYY(), HtmlPage.getDocumentHtmlElement(), + HtmlPage.moveFocusToElement(), HtmlPage.getFocusedElement(), WebClient.popFirstWindow(), + and WebClient.pushClearFirstWindow(). + + + ActiveX: add support for native ActiveX controls (using Jacob). + + + WebResponse interface: deprecate getResponseBody() in favor of getContentAsByteArray(), + deprecate getLoadTimeInMillSeconds() in favor of getLoadTime(), deprecate getUrl() in + favor of getRequestUrl(), add getContentAsString(String). + + + + + + Better generics: avoid the need for casting when calling methods like WebClient.getPage(), HtmlPage.getHtmlElementById(), ... + NOTE: This change avoids casting so that code like + 'HtmlImage e = (HtmlImage) page.getHtmlElementById("myImage")' + can be written as 'HtmlImage e = page.getHtmlElementById("myImage")'. + HOWEVER, due to a bug in Sun Java 5 compiler (fixed in Java 6 and not existing for instance in Eclipse), + calling directly a method from the base return type without assigning the result to a variable will produce a compilation error. + A simple workaround consists in changing + code like 'page.getHtmlElementById("foo").asText()' to + 'page.&lt;HtmlElement&gt;getHtmlElementById("foo").asText()' + (or assigning the result of the 'getHtmlElementById("foo")' call to an intermediate variable). + + + JavaScript: replace \n with \r\n for value property of HtmlTextAreaElement (IE) and ignore leading new line sign. + + + JavaScript: document.cookie value to be surrounded by double quotes if it contains space. + + + CookieManager: process server-side cookies. + + + Avoid NullPointerException when iframe.src is a "javascript:..." URL and JavaScript has been disabled. + + + JavaScript: add doScroll() method to bodies, divs, spans and textareas (IE only). + + + HtmlTextArea: replace new lines with '%0D%0A' and remove first occurrence in form submission. + + + JavaScript: when setting location.href, if the only real change is in the hash then just change the hash + and don't hit the server. + + + Allow custom CSS error handlers (via WebClient.getCssErrorHandler() and WebClient.setCssErrorHandler()) + and provide two error handler implementations out of the box (DefaultCssErrorHandler and + SilentCssErrorHandler). + + + Upgrade NekoHtml to 1.9.9. + + + Select element can be included as HTML inside XML. + + + JavaScript: setting select.selectedIndex should not change page focus. + + + Add facility method WebClient.closeAllWindows(). + + + JavaScript: StackOverFlowError when setting html fragment containing BODY tag to innerHTML of + an element inside BODY. Updated the parser to ignore HTML, HEAD (with contents in IE) and BODY tag + while parsing fragment. + + + JavaScript: Make innerHTML property read only in IE for following elements col, colgroup, + frameset, head, html, style, table, tbody, tfoot, thead, title, tr. + Property is writable for all the elements in FF. + + + JavaScript: Make innerText property read only for following elements html, table, tbody, + tfoot, thead, tr. FF do not have the property. + + + JavaScript: Add support for title.text. + + + WebRequestSettings: Add trailing slash to any URL that contains only hostname (with or without port). + + + Rework WebConnection class hierarchy: remove unnecessary WebConnection.getWebClient() and + WebConnection.getState() methods, delete unnecessary WebConnectionImpl abstract class, make + WebConnection classes part of the public API by removing their internal API warning. + + + Add CookieManager class which can be used to manage cookies on a per-WebClient basis. + + + Fix condition where CSS warnings and errors did not have a systemID to easily identify error origin. + + + JavaScript: add support for properties style (FF) and styleSheet (IE) on HTMLStyleElement + and dummy support for the methods insertRule (FF) and addRule (IE) on CSSStyleSheet. + + + XMLSerializer: includes attributes from HTMLElements. + + + XmlAttr: remove deprecated constructor with Map.Entry. + + + ThreadManager: add WebWindow name to the background threads name. + + + XmlPage: ClassCastException should not be thrown by .getByXPath(). + + + JavaScript: trigger focus event when clicking an element or typing in it. + + + JavaScript: trigger mousedown and mouseup event when an element is clicked. + + + JavaScript: make document.styleSheets[x] respect WebClient.printContentOnFailingStatusCode + and WebClient.throwExceptionOnFailingStatusCode settings when downloading external CSS files. + + + JavaScript: StackOverflowError when setting the location hash via the location.href attribute. + + + JavaScript: add stylesheet.href attribute. + + + Don't parse &lt;noscript&gt; content when JavaScript is enabled. + + + JavaScript: document.XXX allow to access forms by id (IE only). + + + JavaScript: silently ignore script nodes with event="..." for="..." when the target element can't be found (IE only). + + + JavaScript: copy dynamic properties from template in fireEvent (IE only). + + + JavaScript: fixed event order when setting the value of a text field. + + + JavaScript: escape quotes found in attribute values when accessing through innerHTML. + + + Make IE7 the default BrowserVersion (was IE6). + + + Add BrowserVersion for Firefox 3 emulation. + + + Fixed NullPointerException occurring document.styleSheets[x] with out of bound index. + + + Fixed NullPointerException occurring in HtmlPage.writeInParsedStream() when document.write is called after setting innerHTML of some element in page. + + + HTMLParser: now considers namespaces. + + + HtmlElement: asText() respects hidden visibility style attribute. + + + Add missing equals() methods to the PluginConfiguration and PluginConfiguration.MimeType classes. + + + WebClient.expandUrl doesn't handle references correctly. + + + Attribute values for cloned nodes were not available via JavaScript. + + + JavaScript: add support for navigator.product (FF only). + + + Upgrade Commons Collections to 3.2.1 + + + JavaScript: 'window.event' should be preserved after another event firing. + + + + + + JavaScript: fix endless recursion when innerHTML has script that modifies the innerHTML. + + + Accept \r and \n for HtmlTextArea.type(). + + + Avoid to perform multiple request for the same external stylesheet. Add facility to access referred content + from HtmlLink. + + + Fix memory leak of window objects when the windows contain long-running background JavaScript tasks + scheduled via setInterval() or setTimeout(). + + + JavaScript: fix JavaScript error with form.element, when element is located before closing form tag + but the tag balancing forces form to be closed earlier. + + + HtmlFileInput: allow to load data from memory. + + + JavaScript: add support for attribute.text and attribute.xml (IE only). + + + JavaScript: add support for document.activeElement and element.setActive() (IE only). + + + Ensure to focus element on calling HtmlElement.type(). + + + JavaScript: add support for script.text. + + + Fix exception when opening about:blank with Firefox. + + + Add classes AttachmentHandler, CollectingAttachmentHandler and Attachment to handle attachments + outside of the normal page flow (disabled by default for backwards compatibility). + + + JavaScript: postponed loading of frame content after script execution when src is set from a script. + + + JavaScript: window.execScript() now accepts undefined 'language' (IE only). + + + Fix current window's computation when a window is closed by JavaScript during onload processing. + + + ThreadManager: set BrowserVersion of HtmlUnitContextFactory of newly created threads. + + + JavaScript: fix variable scope after document.write. + + + Parsing: handle quotes in comments correctly within script nodes. + + + Cache compiled scripts and parsed stylesheets at the WebClient level. + + + INCOMPATIBLE CHANGE: HtmlElement.getPage() now returns SgmlPage instead of HtmlPage. + + + JavaScript: add support for TextRange.duplicate() (IE only). + + + JavaScript: add support for property xml on XML DOM nodes (IE only). + + + Remove ant build file. + + + Maintain CSS style attribute order, according to document definition. + + + Style attributes in upper case are not recognized. + + + JavaScript: fixed document.write(ln) handling of &lt;br&gt; and &lt;hr&gt;. + + + JavaScript: improved document.write(ln) support to add nodes to the right parent. + + + JavaScript: HTMLDocument.ownerDocument is always null. + + + Fix HtmlTextInput.type(), HtmlTextArea.type() and HtmlPasswordInput.type() to handle backspaces + correctly. + + + JavaScript: implemented a workaround for Rhino bug in number primitive resolution (Rhino bug 374918). + + + Move proxy-related methods from WebClient to new class ProxyConfig. + + + JavaScript: value of form elements is set before triggering keyUp event (was after). + + + Be more tolerant while extracting charset from incorrect Content-Type header. + + + JavaScript: add optionElement.disabled and optionGroupElement.disabled attributes. + + + HtmlOption.isDisabled() and HtmlOptionGroup.isDisabled() always return false when emulating IE. + + + Don't lose any custom request headers during redirection. + + + Allow PUT request with body content. + + + Fix extraneous load of frame contents cause by frame node cloning. + + + JavaScript: add support for methods getAttribute(), setAttribute() and removeAttribute() on + element.style and element.runtimeStyle (IE only). + + + Fix incorrect handling of conflicting return values in different event handlers during + event bubbling. + + + Malformed HTML code: associate form elements located before closing form tag to the form + even if tag balancing forced form to be closed earlier. + + + Be more lenient about spurious whitespace in node attributes containing relative URLs (image.src, + script.src, link.href, etc). + + + Fix document.cookie so that it works correctly when loading HTML pages from the local filesystem, + when there is no real domain available. + + + Allow calls to WebClient.openWindow() with null URLs. + + + JavaScript: add support for onpropertychange event type (IE only). + + + Fix HtmlPage.getHtmlElementsByIdAndOrName() returns same element twice. + + + JavaScript: implement textRange.text setter (IE only). + + + JavaScript: implement style.zIndex. + + + NamedNodeMap instances (element.attributes) are case-insensitive in HTML documents (but not XML documents). + + + Invalid HTML: when the same attribute appears more than one time, consider the first value rather than the last one. + + + JavaScript: HtmlInput.type value is always lower case. + + + Deprecated JavaScriptEngine.get/setTimeout(), added replacement methods WebClient.get/setJavaScriptTimeout(). + + + Fix serialization of HtmlPages (was broken in some scenarios). + + + Change license to Apache 2. + + + Fix IllegalStateException that occured using document.write assigned to a variable (IE only). + + + HtmlPasswordInput: type() appends text to the value. + + + JavaScript: XMLDocumet.getElementById retrieve elements with HTML namespace (FF only). + + + Improved logic to detect the window with the focus. + + + JavaScript: improved behavior of XMLHttpRequest in network error handling. + Added support for the onError callback (FF only). + + + Fixed ClassCastException in CSS child selector processing. + + + Allow to directly invoke URLs with javascript protocol. + + + Add facilities on HtmlImage to download the referenced image and read it. + + + Remove deprecated HtmlPage.executeJavaScriptIfPossible() and WebClient.assertionFailed(). + + + INCOMPATIBLE CHANGE: Replace SubmitMethod with HttpMethod (some methods with incompatible return types). + + + HtmlPage: add refresh(), deprecate HttpWebConnection.newWebResponseInstance() + (replaced with another method with different parameters), + and deprecate one of WebResponseImpl constructors (with replacement). + + + WebRequestSettings: deprecate getURL() and setURL(), use getUrl() and setUrl(). + + + JavaScript: don't store cookies when document.cookie is set and cookies are disabled. + + + JavaScript: add support for the link.href, link.type and link.rel properties. + + + JavaScript: initialize event.target correctly when using createEvent and dispatchEvent (FF only). + + + DomAttr: deprecate getHtmlValue() and setHtmlValue(). + + + INCOMPATIBLE CHANGE: HtmlAttr and XmlAttr are no more used, use DomAttr instead. + + + JavaScript: fix XMLElement.attributes. + + + &lt;span&gt;: empty tag is expanded as required by browsers. + + + JavaScript: add support for XMLElement.hasAttribute() (FF only). + + + JavaScript: add support for HTMLAnchorElement.click(). + + + Any onload events specified on frames and iframes are executed each time the frame + content changes -- not just the first time that the frame loads. + + + Make UTF-8 the default encoding for all XMLHttpRequests. + + + Encode and decode location.hash when emulating Firefox. + + + HtmlPage: cloned page handles XPath. + + + JavaScript: Add select.multiple support. + + + JavaScript: Add initial support for CSSRule and CSSStyleRule. + + + Add WebClient.setCssEnabled(boolean) and WebClient.isCssEnabled(). + + + JavaScript: object properties now returned in creation order. + + + Use HtmlUnit-core-js (which is a Rhino fork) instead of Rhino. + + + + + + Deprecate HtmlPage.getDocumentHtmlElement(). + + + Add support for DomNode.getTextContent() and setTextContent(). + + + JavaScript: add initial support for CSSRuleList. + + + HtmlTextInput and HtmlTextArea: fix type() space. + + + HtmlPage.getReadyState() now synchronized with the information from the documentElement. + + + CSS parsing optimization: avoid parsing CSS selectors multiple times. + + + Initialize mouse event coordinates lazily, in order to avoid unnecessary CSS processing overhead. + + + JavaScript: window.open without URL provided returns blank window when simulating Firefox too. + + + JavaScript: clear existing events handlers when page's content is changed with document.write. + + + JavaScript: fixed document.location in pages created with document.write. + + + JavaScript: fixed ClassCastException occurring when select() is called on form elements other than + text inputs. + + + + + + Upgrade NekoHtml to 1.9.7. + + + Deprecate DomNode non-DOM methods, i.e. getLastDomChild(), getParentDomNode(), getPreviousSibling(), + getNextDomSibling(), getFirstDomChild() and cloneDomNode(). + + + Deprecate HtmlUnitXPath. + + + DomNode: asXml() uses charset from HtmlPage.getPageEncoding(). + + + Upgrade Jetty to 6.1.9. + + + Upgrade Commons Lang to 2.4. + + + Deprecate popFirstWindow and pushClearFirstWindow on WebClient. + + + Add element.offsetParent to FF emulation mode. + + + Upgrade CSS Parser to 0.9.5. + + + Add initial support for data protocol (Firefox only). + + + Fix element.clientWidth, clientHeight, offsetTop, offsetLeft and offsetParent to reflect CSS configuration. + + + In BoxObject, add attributes element, firstChild, lastChild, nextSibling, previousSibling, x, y, width and height. + + + Fix element.offsetWidth and element.offsetHeight to include padding. + + + Add DomNode.getCanonicalXPath(). + + + Deprecate HtmlPage.moveFocusToElement() and getElementWithFocus(), + use setFocusedElement() and getFocusedElement(). + + + Meta Refresh: case-insensitive URL (#1924784). + + + Upgrade Rhino to 1.7R1. + + + JavaScript: add support for XMLElement.getElementsByTagNameNS() (FF only). + + + JavaScript: add support for input.setSelectionRange() (FF only). + + + HtmlSelect: if any HtmlOption is selected, focus is moved to HtmlSelect. + + + JavaScript: add support for 'onfocusin' and 'onfocusout' (IE only). + + + JavaScript: CSSStyleSheet added support for ownerNode (FF) and owningElement (IE). + + + JavaScript: allow direct access to nodes per id/name when simulating Firefox too. + + + JavaScript: fixed various issues with Node methods appendChild, insertBefore and replaceChild + when involved nodes don't belong to the same document. + + + HtmlPage.asXml(): place scripts in CDATA sections with comments. + + + JavaScript: fix window.location.hash so it always starts with '#'. + + + Upgrade Jetty to 6.1.8, Commons IO to 1.4 and FileUpload to 1.2.1. + + + INCOMPATIBLE CHANGE: Remove KeyValuePair, and hide HtmlForm.getParameterListForSubmit() and .getSubmittableElements(), + they shouldn't be directly called by users. + + + JavaScript: return undefined for out of bound element access on HtmlFormElement. + + + JavaScript: custom RegExp proxy now accepts unescaped curly braces. + + + JavaScript: ComputedCSSStyleDeclaration.getPropertyValue returns the same value as direct property access. + + + JavaScript: add support for HtmlElement.textContent (FF only). + + + Remove Jaxen dependency. + + + Remove deprecated methods in HtmlPage: assertAllIdAttributesUnique(), assertAllAccessKeyAttributesUnique(), + assertAllTabIndexAttributesSet() (use corresponding methods in WebAssert instead). + + + Remove deprecated WebRequestSettings.setCookiePolicy() and getCookiePolicy(). + + + JavaScript: element.currentStyle returns calculated (rather than static) style (IE only). + + + Add method Cache.clear(). + + + JavaScript: added support for (undocumented) method CollectGarbage (IE only). + + + DomNode.getByXPath(): when called with a string starting with slash, evaluation is relative + to the root element, not to the DomNode. You can add initial dot. + + + Add Xalan 2.7.0 as dependency. + + + JavaScript: fixed IndexOutOfBoundsException in processing of IE @elif pre processor instruction. + + + JavaScript: instanceof now works correctly with html elements (FF only). + + + JavaScript: property ownerDocument now defined on node. + + + JavaScript: ignore calls to document.open() during page parsing. + + + JavaScript: calling document.write() after a page has finished parsing results in overwriting the entire page. + + + Handle script elements with src attributes containing "javascript:..." URLs. + + + Correct the order of script element execution, deferred script element execution, script ready state changes, + deferred script ready state changes, and onload handlers. + + + JavaScript: add support for document.fireEvent (IE only) and document.onXXX event handlers (elements + already had these). + + + Don't reload page from server if window.location.hash is modified. + + + JavaScript: HTMLCollection.item and namedItem return null when element is not found. + + + JavaScript: avoid detection of document.all when simulating FF (property still available). + + + XPath: case-insensitive match for attribute names. + + + Add temporary body element when one is missing and document.write() is called. + + + Add implicit body element when one is missing and there is no content to trigger addition by NekoHTML. + + + When document is missing a body element, document.body returns null instead of undefined. + + + Execute JavaScript when a script element's src attribute is set (always when emulating IE, + only sometimes when emulating FF). + + + Add test-scoped dependency on slf4j, in order to trigger correct logging in Jetty during the unit tests. + + + JavaScript: add support for document.importNode() (FF only). + + + Upgrade Jetty to 6.1.7 and JCL to 1.1.1. + + + Fixed incorrect processing of multiple conditional compilation flags (IE only). + + + JavaScript: add empty implementation of HTMLElement.clientWidth and .clientHeight. + + + JavaScript: remove style attribute if it is empty. + + + Add support of having XML inside Html (IE only). + + + INCOMPATIBLE CHANGE: Rename UnknownHtmlElement to HtmlUnknownElement. + + + Beautify asXml() by removing unnecessary blanks. + + + XmlPage: fix asText() and asXml(). + + + JavaScript: add basic support for document.queryCommandSupported and document.execCommand. + + + XmlPage: correct XPath handling (#1883395). + + + Fixed User-Agent header for IE6. + + + JavaScript: changed simulated screen dimensions to 1024x768 (was 800x600). + + + JavaScript: add basic support for all missing style attributes. + + + JavaScript: Node.replaceChild() correctly processes DocumentFragment. + + + JavaScript: XMLHttpRequest should not call onreadystatechange handler if sync (FF only). + + + JavaScript: add support for Range.createContextualFragment (FF only). + + + JavaScript: ]]>__proto__]]> is only defined for Firefox. + + + Handle line comments in multiline onXxxx events handlers declarations. + + + Upgraded nekohtml to version 1.9.6.1 + + + INCOMPATIBLE CHANGE: Change html package to implement W3C DOM API interfaces, though + most methods are not yet implemented. Remove deprecated methods. Fix DomCData + derivation to be from DomText. Rename getAttributes methods that conflict with + W3C DOM API return type. (#1747878). + + + INCOMPATIBLE CHANGE: Rename HtmlHeader1 (to HtmlHeader6) to corresponding HtmlHeading1 (to HtmlHeading6). + + + INCOMPATIBLE CHANGE: Rename HtmlTextDirection to the correct name (HtmlDirectory). + + + JavaScript: XMLHttpRequest should not throw an exception when send() is called without args (for FF) + and when send content is specified but method is GET. + + + JavaScript: correct toString() for properties in 'window' scope (FF only). + + + JavaScript: detect encoding from XML declaration (#1876545). + + + JavaScript: HTMLAnchor href attribute should be reachable even if the URL is malformed. + + + JavaScript: add support for XMLElement.getAttributeNode() (#1874624). + + + JavaScript: document.cookie separates cookies with '; ' and not ';'. + + + Fixed ClassCastException occurring when a non HTML page is loaded with Firefox simulation (regression in 1.14). + + + Remove Assert, use WebAssert instead. + + + Upgrade JUnit to 4.4. + + + JavaScript: Add support for HTMLHtmlElement. + + + HtmlForm: Remove deprecated .getRadioButtonInput() and .setCheckedRadioButton(). + + + Remove deprecated HtmlForm.fakeCheckedRadioButton() and HtmlSelect.fakeSelectedAttribute(). + + + JavaScript: Add support for XPathResult.iterateNext() (FF only). + + + Remove deprecated HtmlElement.MapEntryWrappingIterator. + + + Deprecate HtmlElement.getAttributeEntriesIterator(), use .getAttributes() instead. + + + JavaScript: HTMLCollection should not have 'tags' property in Firefox + (except for ]]>document.all]]>). + + + HtmlTextInput and HtmlTextArea: Add support for select(), and fix tabIndex JavaScript property. + + + Add initial support for document.selection.createRange() (IE only). + + + Remove deprecated constants in BrowserVersion, in addition to HtmlForm.submit(). + + + Deprecate DomNode.getChildIterator(), use getChildren() instead. + + + INCOMPATIBLE CHANGE: DomNode.getAllHtmlChildElements() returns Iterable instead of Iterator. + + + DomNode: remove unused EventHandler, and deprecated PropertyChange methods. + + + Deprecate HtmlElement.getChildElementsIterator(), use getChildElements() instead. + + + JavaScript: add support for input.selectionStart, input.selectionEnd, and input.textLength. + + + Remove deprecated DomNode.XXXX_NODE, use org.w3c.dom.Node instead. + + + Remove the public (deprecated) constructor of HtmlElement and its subclasses. + + + + + + JavaScript: allow script node's onreadystatechange handler to be set to null. + + + Don't escape '+' in URL path. + + + JavaScript: add support for 'Node' prototype. + + + JavaScript: add support for window.resizeBy. + + + JavaScript: StyleSheetList correctly loads CSS content (FF only). + + + Correctly handle URLs with path starting with double slash. + + + JavaScript: add configurable support for supported plugins and mime types (FF only). + Per default a Shockwave Flash plugin is "configured" for Firefox 2. + + + JavaScript: XMLHttpRequest.responseXML.getElementById should always return null (#1854975). + + + JavaScript: add support for "for (i in collection)" (#1862054). + + + JavaScript: XSLT support (ActiveXObject 'Msxml2.XSLTemplate') (IE only). + + + XPath: is now namespace aware for XmlElements. + + + JavaScript: add initial support for XPathResult, and XSLTProcessor (FF only). + + + JavaScript: activate document.all for Firefox too. + + + Add DomElement with its JavaScript 'Element' prototype. + + + XPath: DomCharacterData is treated as text node. + + + XMLDocument: add support for .parseError property (IE only), createElement(), createNSResolver() (FF only), + evaluate() (FF only), and 'xml:space' attribute (IE only). + + + XMLPage handles qualified tag names. + + + JavaScript: added 'HTMLEvents' to the event types supported by document.createEvent (Firefox). + + + JavaScript: use custom JDK based regular expression evaluation for String.match + to avoid Rhino problems (speed and wrong evaluation). + + + HtmlTextInput and HtmlPasswordInput: type('\n') submits the enclosing form. + + + &lt;frame&gt; and &lt;iframe&gt; should trim values in 'src' attribute. + + + JavaScript: element.dispatchEvent() exactly behaves as calling ClickableElement.click() and .dblClick() + and returns correct value (based on event.preventDefault()) (#1813007). + + + JavaScript: add initial support for event.preventDefault() (anchor, checkbox, text input, textarea, others to follow) (#1813007). + + + HtmlTextInput: type() appends text to the value. + + + JavaScript: cache parsed JavaScript responses. + + + JavaScript [internal]: removed ScriptEngine, use JavaScriptEngine directly. + + + XMLPage: add support for comment node. + + + Deprecate FocusableElement. + + + JavaScript: add support for label.htmlFor (#1835550). + + + JavaScript: fix removeChild() for XML elements (#1836922). + + + JavaScript: Add style.borderBottom[Color,Style,Width], .borderLeft[Color,Style,Width], .borderRight[Color,Style,Width], + and .borderTop[Color,Style,Width] (#1835836). + + + Parse CSS files and use the result in window.getComputedStyle(), as well as providing accurate + values for document.styleSheets.length. All CSS file downloading and parsing occurs lazily. + NOTE: Adds a dependency on cssparser 0.9.4. + + + JavaScript: Tolerate empty string for DOMParser.parseFromString() (FF only), + and ActiveXObject('Microsoft.XMLDOM').loadXML() (IE only) (#1835090). + + + JavaScript: &lt;iframe&gt; src is now correctly handled via setAttribute() (#1828914). + + + JavaScript: add support for getAttributeNS and setAttributeNS on node (Firefox). + + + JavaScript: don't encode xml special characters for innerHTML property on script nodes. + + + Ignore &lt;script&gt; src that starts with "javascript:". + + + Handle file URLs with query portions (file://my/path?a=b) and ref portions (file://my/path#ref) without breaking. + + + Fixed possible ConcurrentModificationException and dead lock with HtmlAttributeChangeListener and DomChangeListener. + + + Add support for deferred script elements (IE only). + + + Avoid leaving the DOM in an inconsistent state when DomNode.replace(DomNode) is called and the + target node is used as the parameter. + + + JavaScript: delegate select.options.xxx property modifications to the parent select element + (property accesses were already being delegated correctly; IE only). + + + Add basic support for document.getBoxObjectFor() (FF only) (#1815602). + + + HtmlTextArea.asXml() now preserves content and expands empty tag to make generated xml interpretable as html by browsers. + + + Add WebAssert utility class for domain-specific assertions. + INCOMPATIBLE CHANGE: Deprecate assertion methods in HtmlPage in favor of using + WebAssert. The exceptions thrown are now java.lang classes instead of junit classes, + though they still function as before. + + + HtmlForm: on submitting a form without parameters, URL should not end with a question mark (IE7 only). + + + JavaScript: getElementsByTagName now returns empty collection when called with 'incorrect' name. + + + JavaScript: add support for hasAttribute and hasAttributeNS on node (Firefox), + getNamedItem on NamedNodeMap. + + + Add a popup blocker (WebClient.setPopupBlockerEnabled(boolean)). + + + Use browser-compatibility cookie handling by default, deprecate unnecessary + cookie settings in WebRequestSettings, ensure cookie policy used during HTTP + communication matches the cookie policy used by the document.cookie attribute, + use a single cookie header during HTTP communication. + + + HtmlFileInput: add support for non-ASCII name of uploaded files (#1818569). + + + JavaScript: accept ECMA reserved keywords like 'float' as normal identifier. + + + JavaScript: added support for DOMContentLoaded event (Firefox). + + + Add possibility to configure the mime type used when uploading a file. + + + JavaScript: add support for the htmlElement.attributes collection. + + + Add WebClient.setUseInsecureSSL(boolean): forces the client to trust all + hosts, regardless of their certificates. Makes it easy to work + around servers with expired or misconfigured certificates. + + + JavaScript: make focus and blur available on HtmlElement. + + + Don't use custom RetryHandler anymore to allow standard retry when server drops the connection + which caused NoHttpResponseException. + (see http://jakarta.apache.org/httpcomponents/httpclient-3.x/exception-handling.html). + + + Make the loading of external .js files referenced via script tags + listen to WebClient.getPrintContentOnFailingStatusCode() and + WebClient.isThrowExceptionOnFailingStatusCode(). + + + Add support for CDATA sections of xml documents. + + + Add facility method DomNode.getFirstByXPath(xpathExpr). + + + JavaScript exceptions: line number information now relative to the page. + + + Add HtmlPage.executeJavaScript to inject JavaScript code in a page. + + + JavaScript: add support for element.dispatchEvent(event) (Firefox only). + + + Cache JS server responses to avoid useless requests (script caching will come later). + + + Don't load the originally specified source of a frame, when its location has already been changed by JavaScript. + + + Add primitive support for document.styleSheets (#1805817). + + + Add support of setExpression and removeExpression for element and style (#1809522). + + + Update window.frames so it does not throw ClassCastException (#1802836). + + + JavaScript: document.all('notExistingElement') now returns null as IE does. + + + Fix loading content containing 'Content-Type' header with quoted charset (#1797235). + + + Upgrade Jetty to 6.1.5. + + + JavaScript: XMLDocument should not ignore descendants non-empty DomText in IE. + + + JavaScript: loadXML() supports relative URLs in ActiveXObjects: 'Microsoft.XmlDom' and 'MSXML.DOMDocument' (IE only). + + + Add basic support for attributes of XML elements. + + + Added FalsifyingWebConnection, a WebConnection wrapper that provides facility methods to + provide other content than the "real" one. + + + JavaScript: added backgroundImage to allowed style properties. + + + JavaScript: added Document.createRange() and basic support for Range (Firefox only). + + + JavaScript: add selectNodes() and selectSingleNode() (IE only), getElementsByTagName() + and .tagName property for XML elements. + + + JavaScript: add basic support of setProperty() function and .preserveWhiteSpace property for + ActiveXObjects: 'Microsoft.XmlDom' and 'MSXML.DOMDocument' (IE only). + + + DomNode.getByXPath() with 'id()' function should return empty list instead of throwing an exception (#1790308). + + + WebClient.loadWebResponse should not be final. + + + JavaScript: add UIEvent.initUIEvent() (FF only). + + + Allow HTTP methods DELETE, HEAD, OPTIONS, PUT and TRACE (in WebClient.getPage(WebRequestSettings) and in XMLHttpRequest). + + + JavaScript: add XMLSerializer (FF), and .xml property for ActiveXObjects: 'Microsoft.XmlDom' and + 'MSXML.DOMDocument' (IE). + + + JavaScript: add DOMParser, with implementation of parseFromString() (FF only). + + + JavaScript: add loadXML() and selectNodes() for ActiveXObjects: 'Microsoft.XmlDom' and 'MSXML.DOMDocument' (IE only). + + + JavaScript: ignore text nodes of loaded XML by ActiveXObjects: 'Microsoft.XmlDom' and + 'MSXML.DOMDocument' (IE). + + + Move getWebClient() from HtmlPage to SgmlPage. + + + JavaScript: correctly handle 'documentElement' property for + 'document.implementation.createDocument()' (FF), + and ActiveXObjects: 'Microsoft.XmlDom' and 'MSXML.DOMDocument' (IE). + + + JavaScript: add load() and getElementsByTagName() for 'document.implementation.createDocument()' (FF), and + ActiveXObjects: 'Microsoft.XmlDom' and 'MSXML.DOMDocument' (IE). + + + JavaScript: add support for function element.fireEvent() (IE only). + + + JavaScript: add support for function mouseEvent.initMouseEvent() (FF only). + + + ActiveXObject (XmlHttp): should not be created by case-sensitive string. (#1784330). + + + Add support for keypress and keyup events (keydown is already supported). Deprecate HtmlElement.keyDown() + methods in favor of HtmlElement.type() methods which simulate user typing rather than a single event type. + + + Add SgmlPage: moving towards having fully fledged XmlPage. + + + Regular Expressions: allow 'undefined' pattern, and tolerate improper patterns (trigger warning). + + + Upgrade Rhino to 1.6R7. + + + JavaScript: add support for function event.initEvent() (FF only). + + + Fix document.createEvent() and document.createEventObject(): set event prototypes correctly. + + + JavaScript: add 'async' property for 'document.implementation.createDocument()' (FF), and + ActiveXObjects: 'Microsoft.XmlDom' and 'MSXML.DOMDocument' (IE). + + + JavaScript: add support for read-only attributes uiEvent.detail and uiEvent.view (FF only). + + + JavaScript: fixed bug in String.replace (due to custom RegExp proxy) when first arg is a String + with special characters and not a RegExp. + + + JavaScript: add basic support for 'document.implementation.createDocument()' (FF), and ActiveXObjects: + 'Microsoft.XmlDom' and 'MSXML.DOMDocument' (IE). + + + JavaScript: select.size is used when only needed. + + + Upgrade HttpClient to 3.1. + + + JavaScript: document.createElement() to accept html as a valid parameter (IE only). + + + JavaScript: Make event.shiftKey, event.ctrlKey and event.altKey IE-only attributes; add + mouseEvent.shiftKey, mouseEvent.ctrlKey, mouseEvent.altKey and mouseEvent.metaKey FF-only + attributes. + + + JavaScript: add support for read-only attributes event.timeStamp, event.bubbles and + event.cancelable and event.eventPhase (FF only). + + + JavaScript: document.createElement() to accept "&lt;tagName&gt;" as a valid parameter. + + + JavaScript: element.setAttribute() sets corresponding event handler onXXX if found (FF only). + + + JavaScript: add primitive support for document.elementFromPoint (IE only). + + + Add namespace support for attributes: DomNode.getnamespaceURI, getLocalName, getPrefix, + setPrefix, hasAttributes, HtmlElement.getAttribute, getAttributeNS, hasAttributes, + hasAttribute, hasAttributeNS, setAttribute, setAttributeNS, setAttributeValue(NS), + and removeAttributeNS. (#1747878). + + + JavaScript: add support for element.uniqueID (IE only). + + + Deprecate unused class MapEntryWrappingIterator. (#1747878). + + + Deprecate String-to-String attribute map for HtmlElement. Add initial support for + namespaces for attributes. (#1747878). + + + Deprecate HtmlAttr implementing Map.Entry that conflicts with W3C DOM API. Replace + uses of Map.Entry with HtmlAttr. Add HtmlAttr.getName. (#1747878). + + + New interface com.gargoylesoftware.htmlunit.OnbeforeunloadHandler with associated WebClient getter and setter, to support 'onbeforeunload' event (#1498419). + + + JavaScript: document.getElementById() must not return elements added to newly created ones (not yet added to document). + + + JavaScript: add support for 'onunload' event handler. + + + + + + Add document.createEvent() and document.createEventObject(). + + + HtmlElement.asXml(): separate lines for empty element and the one after. + + + JavaScript: element.appendChild() and insertBefore() must recursively maintain document.getElementById() contract. + + + WebRequestSettings: add getter and setter of CookiePolicy. + + + JavaScript: for element.appendChild(), .insertBefore(), .innerHTML, and .innerText: if the element parentNode is null, create a DocumentFragment to be the parentNode (IE only). + + + Deprecated methods that conflict with W3C DOM API: DomTest.splitText, HtmlPage.getDocumentElement, + createElement, createElementNS, HtmlAttr.getValue, setValue, DomNode.getLastChild, + getParentNode, getPreviousSibling, getNextSibling, getFirstChild, cloneNode, appendChild, + HtmlElement.cloneNode. Added replacement Dom or Html methods. Renamed + HtmlPage.createDocumentFragment to createDomDocumentFragment. (#1747878). + + + Deprecated DomNode.XXXX_NODE. + + + Change DomNode.ATTRIBUTE_NODE to be 2 in order to match W3C DOM Node.ATTRIBUTE_NODE. + + + JavaScript: add support for document.createDocumentFragment(). + + + JavaScript: add basic support for element.getBoundingClientRect() and element.getClientRects(). + + + JavaScript: add support for node.isSameNode(). + + + WebClient: Remove deprecated moveFocusFromElement(), moveFocusToElement(), and getElementWithFocus(). + + + HtmlTitle.asXml(): empty tag is expanded as required by Internet Explorer. + + + JavaScript: if window object could not find a property or function, it returns 'undefined' instead of null (#1771549). + + + + + + Add method HtmlPage.getHtmlElementsByName(String). + + + HtmlSelect (in single-selection mode) selects the first option if none is selected. + + + JavaScript: add basic support for element.runtimeStyle. + + + JavaScript: add basic support for document.createStyleSheet (when emulating IE only). + + + JavaScript: implemented a workaround for Rhino bug in string primitive resolution (Rhino bug 374918). + + + Deprecate HtmlForm.submit(). + + + Deprecate HtmlForm.fakeCheckedRadioButton(). + + + The method element.style.getPropertyValue('foo') should expect property names to be + delimiter-separated (ie 'font-size') rather than camel case (ie 'fontSize'). + + + Basic document.implementation: hasFeature(). + + + Add support for oncontextmenu event type. + + + Fix element.innerHTML, element.innerText, element.outerHTML: uppercase tag names when + emulating IE; don't quote attributes when they don't contain whitespace and we're + emulating IE; always use separate open and close tags (even if the tag is empty); + escape XML characters inside text nodes. + + + HtmlElement: add rightClick(). + + + JavaScript added minimal support for MouseEvent properties + clientX, clientY, pageX, pageY, screenX, screenY + coherent with position of event's target. + + + Set Referer header for requests from XMLHttpRequest. + + + First option in a single-selection select input gets selected by default. + + + Add implementation of element.style.filter attribute (when emulating IE only). + + + JavaScript: added support for properties "button" and "which" on mouse events. + + + Add initial support for IE conditional compilation @if, @elif, @else, @end and @set instructions + as well as for conditional compilation variables. + + + Fix getElementsByTagName('*') at the document level (it was returning an empty + collection). + + + JavaScript: add support for style.getPropertyValue() (#1759750). + + + JavaScript: fixed eval scope bug when used within function. + + + Add an optional (disabled by default) debugger implementation which can make it easier + to debug complex interactions between HtmlUnit and JavaScript. + + + Deprecate BrowserVersion constants for Mozilla 1.0, Netscape 4.7.9 and Netscape 6.2.3; + add MSIE 7 and Firefox 2. + + + JavaScript: add basic support for element.currentStyle and window.getComputedStyle. + + + BrowserVersion: add equals() and hashCode(). + + + HtmlElement: add mouseOver(), mouseMove(), mouseOut(), mouseDown(), and mouseUp(). + + + JavaScript: implement navigator.cookieEnabled to match WebClient#isCookiesEnabled(). + + + Add empty implementation for table.refresh() (#1742662). + + + HTMLCollection: cache getElements() for better performance (#1751756). + + + Experimental: added AjaxController and NicelyResynchronizingAjaxController. + + + JavaScript: added support for window.captureEvents (FF). + + + JavaScript: fixed addEventListener cannot be called twice. + + + JavaScript: added support for event capturing and bubbling phases. + + + JavaScript: added support for Event.stopPropagation() (FF) and Event.cancelBubble() (IE). + + + JavaScript: added support for window.onclick and window.ondblclick. + + + Ignore &lt;base&gt; if inside &lt;body&gt; (#1579707). + + + FailingHttpStatusCodeException is thrown for failing frame (#1065041). + + + JavaScript: use custom JDK based regular expression evaluation for String.replace + to avoid Rhino problems (speed and wrong evaluation). + + + Elements inside &lt;noscript&gt; are ignored if isJavaScriptEnabled() (#1186639). + + + Version: add getProductName(), getProductVersion() and getCopyright() (#1748672). + + + DomNode: add/remove DomChangeListener. + + + Remove deprecated WebClient.getThrowExceptionOnFailingStatusCode and BaseFrame.FrameWindow. + + + HtmlImageInput, HtmlResetInput and HtmlSubmitInput can be clicked if exist outside an enclosing form. (#1747454). + + + JavaScript: allow FormField.onchange, form.onsubmit and frame.onload to be set to null (#1745024). + + + JavaScript: Add table.cellSpacing and table.cellPadding. + + + HtmlElement and HtmlPage: add/remove HtmlAttributeChangeListener (#1124781). + + + JavaScript: Implement insertAdjacentElement(). + + + HtmlSubmitInput: setting value to "Submit Query" if not specified, associated with asText(), asXml(), and submitValue changes. + + + HTMLElement.scrollIntoView() is added as an empty implementation (#1740086). + + + DomNode.asText() now correctly handles style elements (e.g. &lt;i&gt;, &lt;b&gt;, and &lt;font&gt;) (#1731042). + + + HtmlPage.clone() doesn't share idMap_ with original (#1708397). + + + ClickableElement: Add dblClick() (#1385295). + + + JavaScript: Add document.createElementNS(), element.namespaceURI, element.prefix, and element.localName (#1521790). + + + HtmlPage supports Serialization (#1685311). + + + Add partial support for IE Conditional Compilation (#1680026). + + + Meta Refresh: tolerate spaces before the semicolon (#1549916). + + + Allow setChecked of &lt;input type="radio"&gt; which is outside any &lt;form&gt; (#1587962). + + + Deprecated HtmlForm#getRadioButtonInput(String,String) and HtmlForm#setCheckedRadioButton(String,String). Use #getByXPath instead. + + + Allow HtmlFileInput to handle values starting with "file:/" (#1513928). + + + Align node types numeric values to W3C values. + + + JavaScript: allow comment nodes to be retrieved + + + HtmlSelectElement: ignores setting 'selectedIndex' to more than or equal to options size. + + + HtmlForm: #getTextAreaByName and #getButtonByName (#1713515). + + + Add UTF-16BE, and UTF-16LE charset detection (#1729467). + + + Use WebRequestSettings#getCharset() as the encoding of pages instead of "ISO-8859-1" (#1483301). + + + Proper handling of &nbsp; in DomNode#asText() (#1549745). + + + JavaScript: Simulate browser behavior for comments that have last line of "statement--&gt;", but not "statement//--&gt;". + + + JavaScript: Add support for location.toString() (#1725742). + + + asXml() now expands tags for div, iframe and script to make generated xml interpretable as html by browsers. + + + Add support for table.width (#1691024). + + + HtmlInput (HtmlCheckBoxInput and HtmlRadioButtonInput): #setChecked now returns Page (#1724889). + + + Javascript: Correct handling of comments (#1725162). + + + JavaScript [internal]: use Context.call(ContextAction) for faster JavaScript execution. + + + Meta Refresh empty URL is handled (#1722665). + + + JavaScript: add support for textarea.selectionStart, textarea.selectionEnd, and textarea.textLength (#1714772). + + + DomNode#getAllHtmlChildElements() now returns Iterator. + + + Fixed exception occurring handling script tag with one line content starting with &lt;!-- and without closing --!&gt;. + + + JavaScript: allow function named onload. + + + JavaScript: made equality tests on functions working. + + + JavaScript: don't allow usage of write(ln) detached from document object when simulating Firefox. + + + JavaScript [internal]: large refactoring for a better Rhino usage. + + + JavaScript: Add support for event.shiftKey, event.ctrlKey, and event.altKey. + + + Tolerate URL starting with http:/ and http: in Firefox. + + + Added IncorrectnessListener to get notified of things that HtmlUnit cope with but that don't respect standards. + + + JavaScript: provide the event object to onreset handlers. + + + Added ScriptException.printScriptStackTrace to retrieve the stack trace of the script execution. + + + WebClient can now enable/disable cookies support. + + + JavaScript: allow to set window.onload to something else than a function. + + + DomNode.DescendantElementsIterator.remove() now throws UnsupportedOperationException + (previous behavior was not correct). + + + JavaScript: added support for label property on Option objects. + + + JavaScript: added support for defaultSelected property on Option objects. + + + JavaScript: allow selected and defaultSelected attribute in Option constructor. + + + INCOMPATIBLE CHANGE: Remove HtmlOption#getValue() (deprecated nearly two years ago), + remove FailingHttpStatusCodeException#FailingHttpStatusCodeException(int, String) (deprecated + over a year ago), remove ScriptException#getEnclosedException() (deprecated over a year ago). + + + JavaScript: Add support for script.src, script.type, script.readyState and script.onreadystatechange. + + + When cloning nodes, clone the id attribute as well. + + + Avoid NPEs for responses with null bodies (ie 304 Not Modified responses). + + + JavaScript: Cloning a script node should not execute the script. + + + JavaScript: Don't run scripts after the window location changes. + + + Verify correct behavior of HtmlSelect#asText() with multiple selections, fix JavaDoc. + + + JavaScript: add support for frameset.rows and frameset.cols properties. + + + JavaScript: ignore invalid script.src attribute used by jQuery ("//:"). + + + Trim whitespace off of anchor href attributes. + + + JavaScript: add support for event.type property. + + + Fixed NPE exception triggered by invalid iframe/frame src attribute. + + + Fixed infinite loop triggered by recursive iframe/frame src attribute. + + + JavaScript: fixed set innerHTML uses 8bits for all chars and ignores some HTML. + + + JavaScript: handle out of bound indexes on options as browsers do (undefined when too high and exception when negative). + + + Added (limited) support for client side map. + + + Don't execute JavaScript in &lt;noframes&gt; and &lt;iframe&gt;. + + + Set Referer header on outgoing requests. + + + JavaScript: setting innerHTML to null shouldn't create any text node for Firefox. + + + JavaScript: fixed remaining problem of submitted select values when select.selectedIndex = -1 has been used before setting an other value. + + + JavaScript: setting innerHTML to empty string shouldn't create any text node. + + + JavaScript: added support for property parentElement on DOM nodes (IE specific). + + + JavaScript: configure correctly the prototype hierarchy on created host objects. + + + JavaScript: fixed non executed scripts added with document.write. + + + JavaScript: "this" should be the window and not the current node in JavaScript href of link and area as well as in JavaScript action of forms. + + + Fixed wrong parsing order of comment and text nodes. + + + JavaScript: added support for following properties on HtmlAnchor: hash, host, hostname, pathname, port, protocol, search and target. + + + Handle correctly anchors (alias reference) in URLs after form submission. + + + JavaScript: XMLHttpRequest now encodes post body in UTF-8. + + + + + + Respect non proxy hosts in redirects from a host using proxy. + + + JavaScript: resolve relative locations from the originating page for Location's href, replace and assign. + + + Renamed frame host class to avoid conflict when a frame has 'Frame' as name. + + + Form should not send push buttons on submit. + + + Added facility method DomNode.getByXPath(xpathExpr). + + + JavaScript: Option.setAttribute now works even if option has not yet been added to a select. + + + Parse as html all responses with content type ending with "xhtml+xml" like XHTML mobile profile documents (application/vnd.wap.xhtml+xml). + + + Improved HtmlPage.getAnchors's javadoc. + + + Added support for server side map (HtmlImage.click(int, int)). + + + Allow redirections to the same URL with a maximal number of 20. + + + Fixed HtmlHtml.getXmlLangAttribute(). + + + Upgraded dependencies to Jaxen 1.1, commons-lang 2.2, rhino 1.6R5, commons-io 1.3. + + + Changing element id should not impact child nodes. + + + JavaScript: provide event object as argument when calling onload listeners attached with attachEvent (Internet explorer). + + + JavaScript: provide the event object to onsubmit handlers. + + + Set cookies defined in meta tags with http-equiv equals to set-cookie. + + + Fixed NullPointerException occurring while submitting a from which onsubmit handler returns null. + + + JavaScript: fixed bad initialisation of JavaScript context when window content changes + (was introduced since last release in fixed for bug 1040244). + + + JavaScript: ensure that script execution is synchronized on the owning html page + (for instance using XMLHttpRequest asynchronously). + + + JavaScript: made ThreadManager thread safe. + + + JavaScript: perform correct setup of context for asynchronous execution of XMLHttpRequest. + + + JavaScript: don't wrap JavaScript primitive types when returned from a Java method. + + + Fixed Non-html reply in window.open() doesn't create window + object by restricting initialization of windows and pages. + Added line/column numbering of HTML elements for embedded + script names that are easier to debug. + + + JavaScript: fixed regression introduced in 1.10 on window.eval for local scope. + + + JavaScript: provide the event object to onfocus and onblur handlers. + + + Moved focus related methods from WebClient to HtmlPage and deprecated them on WebClient. + + + Fixed AREA elements can't handle JavaScript hrefs by + copying code from anchor element. + + + Fixed frames[i] return null for frames generated by + document.write by allowing JavaScript Window object to + be properly initialized with JavaScriptEngine. + + + Fixed document.write problem when &lt;a...&gt; written in 2 times + by checking for complete HTML tags before parsing. + + + Fixed document.write() does not keep ending spaces by reducing + text of adjacent text nodes as a whole instead of separately. + + + JavaScript: handle comments in event handlers. + + + JavaScript: if window with name 'myOldWin' exists, window.open('', 'myOldWin') should retrieve it + rather than opening a new one. + + + Fixed asText() for style node. Now returns an empty string. + + + JavaScript: fixed select.selectedIndex = -1 should not be irreversible. + + + JavaScript: setting option's selected status to false when it is already false + shouldn't reset the whole select. + + + JavaScript: fixed java.util.ConcurrentModificationException occurring when some onload event is + removed during execution of an onload event. + + + JavaScript: second argument DOM node's insertBefore is now optional + when simulating Internet Explorer. + + + Added support for comments: &lt;!-- some comment --&gt;. Patch from Karel Kolman. + + + JavaScript: added XMLHttpRequest.overrideMimeType. + + + JavaScript: fixed bug preventing to set non String style properties. + + + JavaScript: allow to add options to a select with an index as second argument + when simulating Internet Explorer. + + + Ignore invalid URLs specified in &lt;base href="..."/&gt;. + + + + + + Fixed asText() for script node. Now returns an empty string. + + + Removed ":" in project id to avoid problems on Windows with plugins like idea. + + + Upgraded jaxen to 1.1-beta-11 (even if it's a "beta", this is the version + recommended by jaxen developers). + + + Added Maven compliant scopes in project.xml. + + + JavaScript: added minimal support for navigator.mimeTypes (Firefox). + + + Fixed select's faked selections are ignored, if select is empty. + + + Fixed asText() for hidden input. Now returns an empty string. + + + JavaScript: only style's built in properties are of type String (with empty string as default value) + + + Use MultiThreadedHttpConnectionManager (avoids problems with requests started asynchronously from JavaScript). + + + JavaScript: property "all" now available on all html element (Internet explorer). + + + Fixed incorrect handling of web connections (missing call to releaseConnection()). + + + JavaScript: item(xx) method now works correctly on node list. + + + JavaScript: improved support for addEventListener on DOM nodes (Mozilla) and added support for attachEvent (Internet explorer). + + + JavaScript: build XMLHttpRequest for all ActiveX names starting with "Msxml2.XMLHTTP". + + + JavaScript: fixed bug in table.insertRow with empty tbody. + + + Follow redirection to the same Url if original method was a POST. Handle redirections + like browsers do rather than according to the RFC. + + + JavaScript: allow script to set a "javascript:..." location. + + + JavaScript: use of HTMLElement.innerHTML should not cause registration of a WebWindow. + + + JavaScript: window.eval now evaluates in the right window scope. + + + JavaScript: added basic support for addEventListener on DOM nodes (Mozilla). + + + JavaScript: added support for window.createPopup (Internet Explorer). + + + Added FrameWindow.getFrameElement and support for Javascript's frameElement property on windows. + + + Parser: automatically add an &lt;head&gt; element if none present in html source + (as done by Internet Explorer and Firefox). + + + JavaScript: Location.replace wrongly loaded new URL in top window. + + + XPath: fixed wrong behavior with following axis. + + + JavaScript: fixed double execution of external JavaScript files occurring when text contained + between &lt;script src=...&gt; and &lt;/script&gt;. + + + JavaScript: allow to specify a maximal script execution time. + + + INCOMPATIBLE CHANGE: OK button is now simulated for JavaScript confirm calls when no ConfirmHandler is + installed (it was was the Cancel button previously). + + + Removed Jelly support. + + + Updated doc to reflect migration from CVS to SVN. + + + Do not submit reset buttons in forms. + + + Transparently decompress server response if gzipped for transfer. + + + JavaScript: fixed default String conversion of objects (like table, table row, table cell, collection). + + + JavaScript: XMLHttpRequest.responseXml NodeList elements now accessible by index. + + + JavaScript: take expiration date into account when creating cookies. + + + JavaScript: cells collection for rows now takes th into account. + + + JavaScript: table/tbody.deleteRow(-1) will now delete the last row + + + + + + Upgraded commons-collections to version 3.2 + + + Upgraded commons-logging to version 1.1 + + + Upgraded commons-io to version 1.2 + + + JavaScript: added support IE style of events (window.event). + + + Added possibility to configure NTLM credentials for the DefaultCredentialsProvider. + + + Added facility method WebClient.getPage(String). + + + Upgraded jaxen to 1.1-beta-9 (even if it's a "beta", this is the version + recommended by jaxen developers). + + + JavaScript: set form as parent scope for form fields (allows handlers to call directly form + methods like submit()). + + + XmlPage: parse xml pages namespace aware. + + + JavaScript: ensure that the page being loaded has not already been replaced in its window + by a new one through JavaScript before executing onload handlers. + + + Use Byte Order Mark to recognize UTF-8 content when no charset header is provided. + + + JavaScript: added addEventListener/attachEvent, removeEventListener/detachEvent to Window, + allowing to register load events on a window. + + + Upgraded commons-httpclient to version 3.0.1. + + + JavaScript: added support for properties defaultView (Mozilla) and parentWindow (IE) on Document. + + + JavaScript: added support for property ownerDocument on HtmlElements. + + + DomText.asText() now cleans up &nbsp; and multiple blanks as other DomNodes do. + + + Added facility methods HtmlOption.getEnclosingSelect() and HtmlLabel.getReferencedElement(). + + + Fixed HtmlTable.getCellAt when table contains a rowspan. + + + Proxy settings now respected to load external JavaScript files. + + + HtmlCheckBoxInput.setChecked() now fires the JavaScript onchange event. + + + Implemented window.setTimeout(function, int) and window.setInterval(function, int) + + + HtmlOption.asText() now respects the label attribute as browsers do. + + + Encode path part of URLs containing illegal characters. + + + Added support for firing onkeydown events. + + + HtmlElement.getAttributeEntriesIterator now returns the attributes in the order in + which they appear in the html source code. + + + HttpWebConnection now allows extensions to simply override HttpClient creation. + + + Use configured proxy when performing a request after a redirection. + + + Allow &lt;button...&gt;s located outside of a form to be clicked and their onclick handler to be called. + + + + + + Cookies can now be shared between HTTP and HTTPS. + + + HttpWebConnection now uses a single instance of HttpClient (as it can now handle multiple connections). + + + Throw ScriptException (unless WebClient.isThrowExceptionOnScriptError() is false) when the source + of an external script can't be loaded. + + + Deprecated ScriptException.getEnclosedException. Use getCause instead. + + + Added URL of the failed request in message of FailingHttpStatusCodeException. + + + Fixed a bug that could cause a ConcurrentModificationException when navigating away + from a page with JavaScript running in the background. + + + DefaultPageCreator now builds an XmlPage and not a TextPage for responses with content type "text/vnd.wap.wml". + + + JavaScript: fixed parent scope wrongly set on Style object. + + + FailingHttpStatusCodeException now contains the failing WebResponse. + + + Modified XmlHttpRequest to use new thread management API for async requests. + + + JavaScript: fixed exception in access to a DOM node when the page contains + a custom object with the same name as the one used by htmlunit for the host object (caused error like: + "Form" is not a constructor). + + + Fixed bad handling of comma in Location header of redirections (30x) + + + Implemented setInterval/clearInterval and thread management for setTimeout + and setInterval threads. Thanks to Steven Grimm and Daniel Gredler for patches that + were helpful in the implementation. + + + JavaScript: added support for properties target and srcElement on events. + + + Upgraded commons-httpclient to version 3.0. + + + Fixed NPE thrown when JS error occurs on click when ThrowExceptionOnScriptError is false. + + + Added HtmlAnchor.openLinkInNewWindow() + + + JavaScript: changes on form's action attribute in onSubmit were ignored. + + + Allow external scripts to be loaded using file protocol. + + + JavaScript: added support for property cellIndex on td and th eleements. + + + BaseFrame.FrameWindow has been deprecated and replaced with a top level + FrameWindow class. + + + JavaScript: fixed exception occurring when addBehavior is called twice for the same + behavior. + + + JavaScript: Implement add() method for OptionsArray to avoid TypeError. + + + JavaScript: added the full URL of the file containing the script being executed + in the exception message when a script error occurs. + + + JavaScript: made Location properties writable. + + + Added possibility to bypass configured proxy for some hosts. + + + Fixed support for NTLM proxy. + + + JavaScript: setting options' length to a value greater than current. + size fills option array with empty options. + + + Fixed mangled binary files loaded with the file protocol for non ISO-8859-1 + default system file encoding. + + + Upgraded commons-io to 1.1. + + + Form's name now writable (both in DOM and in Javascript). + + + Javascript: getElementsByTagName now returns an ElementArray (instead of a + NativeArray) for html elements allowing expressions like + "myForm.getElementsByTagName('input')['one']". + + + JavaScript: when simulating IE, options collection delegates to select + when the requested property/method doesn't exist. + + + Consider inputs with invalid type as text inputs. + + + JavaScript: responses to XMLHttpRequest don't disturb window contents anymore. + + + All code deprecated prior to 1.6 has been removed + + + JavaScript: added implementation of IE behavior "#default#download". + + + Fixed HtmlSelect.getSelectedOptions to return an empty list if select has no option. + JavaScript: fixed select.value to return an empty string when select has no option. + + + HtmlOption.click() now returns correctly the page loaded by an onchange event. + + + Fixed requested URL for post form with empty action and original page containing + a query string or action containing only a query string. + + + Upgraded jaxen to 1.1-beta-8 (even if it's a "beta", this is the version + recommended by jaxen developers). + + + JavaScript: added support for property contentWindow on (i)frames. + + + Upgraded rhino JavaScript library to 1.6R2. + Noteworthy is that the JavaScript stack trace is now added in the normal Java + stack trace (bug 274467 reported by Daniel Gredler, + see http://www.mozilla.org/rhino/rhino16R2.html for full change log). + + + Fill frame windows with about:blank when the declaring tag is found + to allow JavaScript to run on it before the real content is loaded. + + + Upgraded commons-httpclient to version 3.0rc4 in ant as well. + Made HtmlForm.submit(SubmittableElement) public to simulate + keyboard submits (more to come later). + + + JavaScript: XMLHttpRequest.send now accepts null as parameter + and fails when simulating Mozilla if called with no parameter like the browser does. + + + Upgraded commons-httpclient to version 3.0rc4. + + + Javascript: allow to set current node's property within onclick event handler. + + + Javascript: XMLHttpRequest now accepts non xml responses. + + + Javascript: allow to change selected attribute of options created with + document.createElement('option') and not yet added to a select. + + + Load frames content first after the page is loaded to allow access to the whole page + for scripts contained in the frames. + + + JavaScript: added support for document.frames (specific to IE). + + + JavaScript: when simulating IE, second parameter in Select.add can be omitted. + + + JavaScript: in a frameset, document.body returns the frameset node. + + + JavaScript: added dummy implementation of the properties scrollHeight, scrollLeft, + scrollTop and scrollWidth for html elements. + + + JavaScript: added document.anchors. + + + JavaScript: XMLHttpRequest now accepts relative urls. + + + JavaScript: allow creation of XMLHttpRequest as new ActiveXObject('Microsoft.XMLHTTP') + when simulating Internet Explorer. + + + JavaScript: default conversion of host objects to string is now "[object Xxxx]" like what Mozilla does + + + DomNode.asXml() now produces correct xml encoding special characters. + + + JavaScript: implemented property offsetParent. + + + + + + JavaScript: img nodes can be accessed by id or name within a form. + + + Click on a JavaScript link loading a page containing frames now return + the main loaded page and not a frame anymore. + + + Trim the text of HtmlOption when it is used as initial value attribute + (when no attribute is found as defined in HTML 4.01). + + + JavaScript: fixed problem occurring while reading properties of nodes retrieved with childNodes(). + + + When posting a form as multipart/form-data don't send Content-Transfer-Encoding + headers for the parts and send Content-Type headers only for files like browsers + do. + + + When posting a form, use encoding from accept-charset attribute if any else + from page to encode the posted parameters. + + + Fixed infinite loop when DefaultCredentialsProvider provides invalid credential. + Ensure that the web connection uses the CredentialProvider configured for the WebClient. + + + Handle port correctly when handling a redirection to an other port on the same host. + + + JavaScript: fixed properties text, value and selected for Option objects + created from JavaScript and not yet added to a select. + + + Added WebResponse.getRequestMethod(). + ImmediateRefreshHandler now accepts a refresh to the same URL if the first request was a POST. + + + JavaScript: added support for window.closed. + + + HtmlOption's value attribute initial value is the text of the option if + no attribute is found as defined in HTML 4.01. + Deprecated HtmlOption.getValue(). + + + JavaScript: fixed execution of onchange handlers to really return + "The page that occupies this window after this method completes" as defined by + the javadoc. + + + JavaScript: fixed behavior of table.insertRow and table.rows.length for tables containing nested tables. + + + Improved the way getHtmlElementById handle pages containing multiple elements with the same id. + + + JavaScript: made input.setAttribute("type", xxx) behave the same than input.type = xxxx. + + + JavaScript: fixed double execution of script inside &lt;table&gt;. + + + Set state of radio button before executing onclick handler. + + + Upgraded nekohtml to version 0.9.5 + + + Load responses which content type matches regular expression + "application/.*\+xml" as XmlPage (rather than UnexpectedPage). + + + Children of removed nodes were erroneously still available by id using + HtmlPage.getElementById. + + + Upgraded commons-jelly to version 1.0 + + + Upgraded commons-httpclient to version 3.0rc3 + + + Added method for setting HttpClient's virtual host + + + INCOMPATIBLE CHANGE: HtmlElement.getAttributeEntriesIterator now return an iterator + on HtmlAttr (and not Map.Entry) allowing XPath expressions that return a list of node attributes. + + + Don't perform server request when a link is clicked if href is just an anchor (like "#"). + + + JavaScript: resolve relative locations from the originating page. + + + JavaScript: use the Window as the top scope in Rhino JavaScript engine. + + + JavaScript: Fixed bug with onchange handler being fired for all input type="file" + on creation. + + + JavaScript: handle position in insertAjacentHTML as case insensitive as IE does. + + + HtmlOption.click() now selects the option. + + + Handle content types in a case insensitive way (as of RFC 2045). + + + Implemented form reset, defaultValue and defaultChecked. + + + JavaScript: Added window.print() as unimplemented method. + + + Javascript: document.getElementsByTagName and document.getElementsByName + now return an ElementArray (instead of a NativeArray) allowing expressions + like "document.getElementsByTagName('a').item(0)". + + + In a script tag &lt;script type="..."&gt;, the value of the type attribute is case insensitive. + + + Send headers added with WebClient.addRequestHeader to the server again + (bug introduced in release 1.6). + + + Upgraded jaxen to 1.1-beta-6 (even if it's a "beta", this is the version + recommended by jaxen developers and it fixes the element order bug). + + + A click on a &lt;label ...&gt; is now propagated to the referenced element. + + + + + + Added XMLHttpRequest support. Patch submitted by Daniel Gredler. + + + Deprecated and renamed getAll&lt;Something&gt;s methods to get&lt;Something&gt;s to + make them easier to find. + + + More refactoring and deprecation to use WebRequestSettings. + WebRequestSettings now has get/setAdditionalHeaders, patch submitted by Daniel Gredler. + INCOMPATIBLE CHANGE: Third party extenders of WebConnection will need to + implement getResponse(WebRequestSettings) in place of other getResponse methods, + which have been deprecated and given default implementations that call this method. + + + Javascript: fixed exception occurring while changing type of input created via document.createElement(). + + + Upgraded commons-httpclient to version 3.0rc2 + + + Javascript: insertRow now accepts the number of rows as parameter value. + + + Javascript: the onchange event handler of a radio button is now invoked when its state is changed. + + + Javascript: implemented property contentDocument for frames and iframes on Mozilla. + + + Javascript: fixed error occurring in NodeImpl insertBefore() with null reference child object. + + + Now load the mapping of html classes to their respective JS classes from the configuration + file. + + + Javascript: when simulating IE, window.open("") handles empty string as "about:blank". + + + Reworked the processing of the JavaScript functions and properties. Names have all changed to start + with jsxXXX and now the functions and properties are registered with the prototypes when they are + defined. + + + INCOMPATIBLE CHANGE: replaced WebClient.setValidateHtml(boolean) with WebClient.setHTMLParserListener(HTMLParserListener) + allowing to programmatically catch parser messages. + + + Javascript: fixed infinite loop caused by onblur. + + + The URL of a page resulting of a form submission with the GET method now contains the query parameters + (which are encoded when needed according to the page's encoding). + + + Javascript: added navigator.language for Mozilla. + + + Javascript: added dummy implementation of Mozilla's window properties innerHeight, innerWidth, outerHeight, outerWidth. + + + Added to the JavaScript configuration page a column showing if a function is not implemented. + + + Reworked the JavaScript configuration. Configuration file is now used and supports the + browser constraints on the properties and functions. + + + Javascript: navigator properties now depend from used BrowserVersion. + + + Javascript: added dummy implementation for read only properties offsetHeight, offsetLeft, offsetTop and offsetWidth. + + + Javascript: added support for multiple arguments for document.write and document.writeln. + + + Added WebResponse.getResponseHeaders(). + + + Fixed NPE in loadWebResponse for responses with status code 204 (No Content). + + + Javascript: form's onsubmit property is now a function and can be assigned. + + + Javascript: added support for new Image() and changing src attribute. + + + + + + Determine content-type of uploaded files. + + + Javascript: implemented method removeAttribute for DOM nodes. + + + Javascript: Added support for document.scripts + + + Javascript: fixed getAttribute() to return null if the requested attribute is not defined. + + + Javascript: implemented property childNodes. + + + Fixed bug where document.write-ing a frame was causing an attempt + to load an invalid URL starting with http://first + + + Fixed node reference problem occurring when the text of a textarea is changed. + + + Javascript: document.links doesn't return tags with empty href anymore. + + + A RefeshHandler can now throw IOExceptions instead of handling them. + Updated ImmediateRefeshHandler and ThreadedRefeshHandler to make refresh failures + exceptions instead of just log messages. + Added WaitingRefeshHandler for waiting real time on the current thread. + + + Javascript: the type property of input elements can now be changed. + + + Fixed bug occurring when submitting from JavaScript a form with a JavaScript action. + + + HtmlElement's getHtmlElementsByAttribute, getHtmlElementsByTagName, and + getHtmlElementsByTagNames were all updated to ignore the case of the passed + in tag name as they're always compared with a lowercase version. + + + JavaScript: Implemented location.reload(). + + + Fixed bug with meta refresh that only contained a number. + + + INCOMPATIBLE CHANGE: RefeshHandler interface changed and they must now do the + refresh themselves. DefaultRefreshHandler was replaced with + ImmediateRefreshHandler (the new default) and ThreadedRefreshHandler. + + + INCOMPATIBLE CHANGE: com.gargoylesoftware.htmlunit.CredentialProvider has been removed. + You should now use org.apache.commons.httpclient.auth.CredentialsProvider instead. + This patch should allow support for NTLM and Digest authentication as well as + proxy authentication. + + + JavaScript: Pick up behaviors defined in style attribute when simulating IE. + + + JavaScript: expressions like myForm.myField now look for form fields with "myField" as id or name. + + + Clicked image button without name sends parameter x and y. + + + Submit form elements in the same order that they appear in the HTML form. + + + Upgraded commons-httpclient to version 3.0rc1 + + + JavaScript: fixed document.domain setter for domains like d1.d2.d3.d4.com. + + + JavaScript: fixed document.myForm.myField should not retrieve the field if it is an input of type image. + + + JavaScript: added empty implementation of type setter for input fields (already allowing some scripts to run). + + + Added HtmlElement.getEnclosingElement(String tagName). + + + JavaScript: added properties rowIndex and cells and function insertCell for table rows. + + + JavaScript: fixed insertRow when asked to insert at the end of the rows collection (was inserted one position before). + + + Guess content type for file content and file name when loading a file URL. + + + Parse responses of type "application/xml" as XmlPage. + + + Fixed wrong URLs expansion with "#". + + + JavaScript: improved window.execScript to execute JavaScript code. + + + Use commons-codec's Base64. Marked custom Base64 as deprecated. + + + Fixed NullPointerException thrown in JavaScript by createElement('input') + + + Javascript: implemented innerText for html elements (read/write). + + + Fixed ClassCastException occurring when unloading a frameset that contained a frame which content wasn't html. + + + Implemented WebRequestSettings parameter object. + Created new WebClient.getPage() methods and deprecated old ones. + + + Stopped httpclient from automatically retrying failed connections 5 times. + + + A failure when setting a location from JavaScript now throws an exception + + + Added support for misc table methods in JavaScript + + + JavaScript: added dummy implementation of window.setInterval and window.clearInterval doing nothing. + + + synchronized JavaScript execution for multi-threaded testing + + + parse application/xhtml+xml content type into HtmlPage + + + JavaScript: use js object Input for &lt;input type="image" .../&gt; and &lt;input type="button" .../&gt; + + + JavaScript: default conversion to string of an anchor returns the fully qualified URL specified by the href. + + + JavaScript: the DOM node of a &lt;frame&gt; or &lt;frame&gt; is now visible to the contained page while loading. + + + JavaScript: when simulating IE, a variable named after the id of a DOM node represents this DOM node. + + + Made window.name writable. + + + JavaScript: document.xxx now retrieves DOM node with name xxx only if it's an img or a form (input should not be retrieved). + + + JavaScript: Fixed bug in window.frames[i] (was introduced in 1.4). + + + JavaScript: Fixed bug with frames.length not working. + + + JavaScript: Implement writable document.location. + + + JavaScript: added window.status and removed erroneous document.status. + + + Fixed window.frames['frameName'] causes ClassCastException. + + + JavaScript: document.getElementById("") now returns null. + + + + + + Fixed platform specific encoding problem in test WebClientTest.testLoadPage_EncodeQueryString() + + + JavaScript: added window.clearTimeout. + + + JavaScript: dynamically compiled function runs in the scope of their creation. + + + JavaScript: fixed problem occurring for &lt;script for="window" event="onload()"&gt; with event value ending with "()". + + + JavaScript: added document.domain. + + + JavaScript: added implementation of IE behavior "#default#clientCaps". + + + JavaScript: added support to get/set the onload property as a function for window and for frames. + + + INCOMPATIBLE CHANGE: HtmlFrame and HtmlInlineFrame don't implement WebWindow anymore but now contain a WebWindow accessible + by getEnclosedWindow(). JavaScript handling of frames works better due to the distinction between frame element and contained window. + + + Added HtmlPage.getFrameByName + + + asText() now returns "checked" or "unchecked" for HtmlRadioButtonInput and HtmlCheckBoxInput + + + JavaScript: added dummy implementation of window.execScript doing nothing. + + + JavaScript: added attribute support. + + + Added WebClient.setThrowExceptionOnScriptError(boolean) and isThrowExceptionOnScriptError() to allow script errors + to stop only execution of current script as browsers do. + + + JavaScript: document.write(ln) writes directly in DOM which allows access to DOM nodes in the same script code. + + + Added WebClient.setTimeout(int) and WebClient.getTimeout() + + + JavaScript: all elements can now be accessed by name with syntax document.foo (like what was already working for forms). + + + JavaScript: setting the value attribute of a select object now selects the corresponding option. + + + document.images is now a "live" collection. + + + Added DebuggingWebConnection, a web connection that saves the received responses and builds an overview. + Sometimes useful at conception time to understand what is "browsed". + + + Extended JavaScript event handler to most common events: ondblclick, onmousedown, onmouseup, + onmousemove, onmouseover, onmouseout, onkeypress, onkeydown, onkeyup, onfocus, onblur. + + + Added JS support for outerHTML. + + + Upgraded commons-httpclient to version 3.0beta1 + + + Added dependency to commons-codec 1.3 + + + Possibly incompatible change: Removed fix trying to mimic browser kludge for non-RFC2019-compliant cookies as it causes new problems. + + + Possibly incompatible change: Don't set httpclient's cookie policy to COMPATIBILITY anymore what lets user configure it directly + or use the default (RFC2109). + + + Added support for setting cookies from JS (like document.cookie = "foo=something"). + + + Added dependency to commons-lang + + + Trying to set a JS property configured with writable="false" now generates a JS runtime error. + + + Added conversion to string and method toString on event handler functions. + + + Added support for JS document.links. + + + IFrames can now be seen in JS as an html element too. Expressions like window.myIFrame.style.display now work. + + + document.forms is now a "live" collection and forms can be accessed with document.forms["myFormId"] where "myFormId" is the id of a form. + + + Collections like document.all or form.elements now use xpath expressions and are "live" (thanks to Daniel Gredler for the idea). + + + Added the possibility to evaluate xpath expressions relatively to a particular node of a the html document. + + + Added node.children. + + + Fixed bug for JS wrapped in HTML comments on one line. + + + Allow to set commons-httpclient cookie policy using system property. + + + Added support for insertAdjacentHTML. + + + Fixed DomNode.replace() fails to set previousSibling on newNode and other problems when changing DomNode. + + + Allow onclick event handler to be set by JavaScript. + + + Added logic to WebClient to allow messages from parsing the HTML to be displayed on the + on the console. + + + Fixed bug changing "//" to "/" in query parameters of URLs called from a page. + + + When simulating IE, nodes can now be accessed directly by their name (ex: window.form1). + + + Improved ElementArray: fix for empty collection and addition of method namedItem(). + + + Fixed bug with setTimeout: a timeout is now only executed if the page that placed it is always "alive". + + + Fixed html element property access in JS: attributes are case sensitive. + + + Improved JS innerHTML to allow complex html code to be set. + + + Refactored different arrays of html elements in a generic ElementArray. Expressions like "document.all.tags('s').item(y)" can now be evaluated. + + + Upgraded rhino js to 1.6R1. + + + Fixed NullPointerException tossed by HtmlSelect.asText() if no option is selected. + + + Improved Refresh meta tag support: Take care of enclosing &lt;noscript&gt; tags and correctly interpret quoted urls. + + + Implemented IE specific behavior related methods as well as default behavior "#default#homePage". + + + Implemented screen methods. + + + Added missing (for IE) methods/properties of window.navigator. + + + Added support for window.location.replace(...). + + + Fixed problem with pages where body's onload contains a return statement. + + + Fixed bug in JS accessing form elements through syntax like myForm[i] and don't count inputs with type=image in form.length as browsers do. + + + Automatically add value="on" for radio buttons and checkboxes without value attribute (available for JS access and used when submitting a form as browsers do). + + + Added support for methods moveBy, scroll, scrollBy, scrollByLines, scrollByPages and scrollTo for JS window object. + + + Fixed bug where encoded "&", "=", "+", ",", and "$" in URLs would be decoded before + sending to the server. + + + getTypeAttribute now returns "text" for input without specified type attribute as it is the default value. + + + Added support for item function in JavaScript like "document.all(...).item(...). + + + Onchange script handlers not executed anymore if the field value is changed by JavaScript. This should for instance avoid infinite loops when field A changes field B and field B changes field A. + + + Upgraded nekohtml to version 0.9.4 + + + Automatically encode query string part of requested URLs if needed as browsers do (for instance change "http://first?a=b c" to "http://first?a=b%20c"). + + + Response of type "text/xml" are now represented as an XmlPage (rather that a TextPage) + which gives access to the Document object if the xml is well formed. + + + Fixed bug for JS location.protocol (was missing a ":", e.g. "http:" and not "http"). + + + Added support for getting and setting option.selected in JavaScript. + + + Fixed bug where a NullPointerException is thrown when leaving a page containing an iframe without src attribute. + + + Added support for window.resizeTo. + + + Fixed wrong values of window.opener: now null (instead of undefined) when no opener + and null when a link opens in "_top". + + + Upgraded commons-httpclient to version 2.0.2 + + + Added support for function syntax on document.all(). + + + Added support for InnerHTML(). + + + Added support for enabling the errors from + NekoHtml by setting a value on the WebClient. + + + Previously, if you clone an element, and set an attribute in either + the old or the new, the new setting appears in the other one as well. + This was because cloneNode just left the attributemap + alone, so the clones wound up using the same ones as + the old. + + + + + + Upgraded commons-jelly to version 1.0-beta-4 + + + Upgraded commons-jelly-tags-log to version 1.0 + + + Upgraded commons-jelly-tags-xml to version 1.0 + + + Upgraded commons-jelly-tags-junit to version 1.0 + + + Upgraded commons-jexl to version 1.0 + + + Upgraded commons-cli to version 1.0 + + + Upgraded dom4j to version 1.5 + + + Added dependencies to jaxen 1.0 and saxpath 1.0 as they are needed by the + latest dom4j. It would appear that saxpath will be rolled into jaxen in future + releases but for now it is a separate dependency. + + + Upgraded commons-collections to version 3.1 + + + Upgraded commons-beanutils to version 1.7.0 + + + Upgraded commons-httpclient to version 2.0.1 + + + Upgraded xercesImpl to version 2.6.2 + + + Upgraded nekohtml to version 0.9.1 + + + Upgraded commons-logging to version 1.0.4 + + + Upgraded gsbase to version 2.0.1 + + + Updated server names for cvs access. + + + Added support for the JavaScript document.images and also for getting and setting + the page title. + + + Patch for JS frames.length. + + + Fixed inconsistencies in the handling of isDisabled. + + + Initial support for Active X objects. + + + INCOMPATIBLE CHANGE: The common browsers will automatically insert a tbody tag inside + tables if there isn't one already there. Now HtmlUnit does that as well. + + + Fixed bug where calling document.body from JavaScript before the body tag had been + parsed was causing an exception. + + + Added support for JavaScript table.rows. + + + The common browsers always return uppercase values for the JavaScript nodeName property. + Now HtmlUnit does as well. + + + Added support for the IE attribute document.readyState. Also added the js.log custom + logger to aid in debugging JavaScript errors. + + + Added support for onchange handlers in textareas + + + Stubbed out window.moveTo(x,y) + + + Added dependency to commons-io + + + Initial support for file urls. + There is a bug in commons-io that will break this when trying to read + file URLs on another drive under windows: + http://issues.apache.org/bugzilla/show_bug.cgi?id=31884 + + + Fixes for buggy link management in DomNode.basicRemove() + + + Fix for bug where HttpWebConnection.getStateForUrl() fails with localhost URL + + + Added IE specific behaviour for getElementById() + + + Made WebTestCase abstract + + + Changed HtmlElement.getOneHtmlElement() to match the documented behaviour + in the case where multiple matches were found. + + + Added getElementsByTagName(), getClassName() and setClassName() to HTMLElement + + + getAttribute() and setAttribute() missing on HTMLElement. + + + Mimic browser kludge for non-RFC2019-compliant cookies. + + + Fixed bug where the getAttribute() and setAttribute() methods were not + ignoring the case of the attribute name when getting and + setting. + + + Fixed bug where a colon in a relative URL causes MalformedURLException in WebClient.expandUrl() + + + If the type attribute isn't specified on a button attribute then the default value according + to the spec is "submit". Internet Explorer doesn't obey the spec and returns "button". HtmlUnit + now does what the browsers do, depending which BrowserVersion is specified.. + + + Fixed bug in handling of onclick handlers for an HtmlCheckBoxInput. When an onclick + handler is specified on a HTML checkbox that causes a new page to be displayed, + the function HtmlCheckBoxInput.click() was not returning the new page. Rather it was + returning the original page. + + + Fixed bug where HtmlImageInput.click() was not including the name.x and + name.y attributes in the submitted request. + + + If form.submit() is called from JavaScript then the forms onsubmit handler should + not get executed. + + + Fixed OutOfMemoryError when submitting a form many times from the same HtmlPage + + + Clean up memory use in HttpWebConnection.makeWebResponse(). + + + + + + Added support for setting input.name in JavaScript + + + Added support for JavaScript document.body + + + Changed HtmlSelect.getSelectedOptions() to not auto-select the first + option if the list size > 1. + + + Refactored HtmlFileInput submission to include the filename even when + there is no file submitted. + + + Added support for JavaScript Window.close() + + + INCOMPATIBLE CHANGE: WebClient.moveFocusToElement() now takes a + FocusableElement as it's parameter instead of an HtmlElement. + FocusableElement is derived from HtmlElement. + Added framework for focus() and blur() as well as JavaScript support + for them on anchors and inputs. + + + Added support for JavaScript Element.setAttribute() + + + Added support for JavaScript Node.hasChildNodes() + + + Fix for Bug 916316 - this.form inside onclick should work now + + + Implemented JavaScript document.getElementsByName() + + + Added support for setting select.selectedIndex from JavaScript + + + Changed HtmlSelect.fakeSelectedAttribute() to use an empty string + as no value at all (nothing submitted) + + + Fixed bug where a select option with no value attribute was not + submitted with it's contents + + + DefaultPageCreator can now be easily extended to add custom + content type handling without affecting the default handlers. + + + INCOMPATIBLE CHANGE: PageCreator.createPage() no longer takes a + WebClient as a parameter. If you have an existing PageCreator + you can get the WebClient from the WebWindow parameter. + This change also occurred in DefaultPageCreator. + + + Deprecated HtmlPage(WebClient, URL, WebResponse, webWindow) in favor of + HtmlPage(URL, WebResponse, webWindow) + + + Deprecated HTMLParser() as you should never need an instance + + + Deprecated HTMLParser.parse(WebClient, WebRespose, WebWindow) in favor of + static HTMLParser.parse(WebRespose, WebWindow). + + + Updated HtmlRadioButtonInput.click() to select the clicked radio button + + + Fixed bug where the JavaScript value of a select list was always empty. + It should now correctly be the value of the selected option. + + + Fixed bug where the JavaScript value of an option element was empty + if the value attribute was not defined. The value should now correctly be + the contents of the element. + + + Added HtmlOption.getValue() that returns the value of the option as + it should be submitted + + + Fixed bug where submitting a form with a submit control that had no name + would submit an invalid name/value pair instead of ignoring the control + + + Fixed bug where submitting a form containing a select that had no options + caused a NullPointerException. + + + INCOMPATIBLE CHANGE: Changed HtmlPage so it is no longer derived from + HtmlElement. It is now derived from DomNode and a new HtmlHtml element + represents the root element of the document. Similarly, Document in + JavaScript is no longer derived from HTMLElement, but is derived from + NodeImpl instead. + + + Add HtmlPage.getDocumentElement() and Document.documentElement in JavaScript. + + + Improved speed of getElementById(). + + + Change the node type and node name for HtmlPage and Document in JavaScript. + + + Nested input elements, i.e. those that were not + immediate children of the enclosing form, were not handled. + + + Changed the behaviour of single select lists to match the common + browsers. When multiple items have the selected attribute then + the last one is returned to the server. When no items have been + selected, the first one is sent to the server. + + + Deprecated MockWebConnection.setContent() in favour of setDefaultResponse() + which is more descriptive. Changed all tests to use the new method. + + + Changed all tests to use MockWebConnection instead of FakeWebConnection. + The FakeWebConnection class has been deprecated and will be removed for + the next major release of HtmlUnit after 1.3. + + + The same hard coded URLs were being used over and over again throughout + the tests. Defined constants for the most frequently used URLs in + WebTestCase and changed tests to use these constants. This will reduce + the number of temporary objects during tests runs and will decrease the + chance of making a typo in the urls. + + + Fixed bug where forms without names were not being returned by + document.forms + + + Added support for the following attributes on Document.Location: + hash, host, hostname, href, pathname, port, protocol and search. + + + Added support for Anchor.href and Anchor.getAttribute(). + + + Fixed bug where getting the style attribute should return an empty + string instead of NOT_FOUND. + + + Fixed bug where calling select() on an HtmlInput from JavaScript caused an + exception about select being a function and a property (it's only a function) + + + Added initial support for refresh handlers. They will be invoked from meta + tag refreshes and response header refreshes but not currently from JavaScript + refreshes + + + Added serialVersionUID to all classes that are Serializable but didn't already + have one of these. + + + Fix for performance problem in JavaScript handling. + + + If the server returns an unsupported encoding type then the browsers assume + ISO-8859-1. Now HtmlUnit does the same. + + + + + + INCOMPATIBLE CHANGE: Added method to interface WebWindowListener for + window closing events. + + + INCOMPATIBLE CHANGE: There previously were three separate tree models + for any given page: 1) the HtmlElement hierarchy 2) The xml DOM model and + 3) the JavaScript element model. Now the first two tree models have + been merged into one. + + + Continued migration of the build process from ant to maven. + + + Patch for bug in onload handler submitted by Andreas Hangler + + + Added support for the about: protocol - patch from Jun Chen + + + Added support for window frames - patch from Jun Chen + + + an update of the version number in build.xml and outputting of + a src jar for the current build. Patch submitted by Brad Clarke + + + Added HtmlFileInput support. Patch submitted by Brad Clarke + + + Upgraded junit.jar to 3.8.1 + + + Fixed bug where HtmlPage.asText() would blow up if form tags were + found between tr and td tags. Clearly this is illegal html but + the browsers support it so HtmlUnit needs to as well. + + + Fixed bug where form elements without names were being submitted anyway. Patch + supplied by Brad Clarke + + + Fixed bug where disabled elements were being submitted anyway. + Patch supplied by Brad Clarke + + + Navigator.javaEnabled should be method not property + + + Added WebClient.getWebWindows() + + + Fixed bug where radio button and checkbox logic was case sensitive. + Patch supplied by Brad Clarke + + + Added support for Window.focus(). Patch supplied by Brad Clarke + + + Add support for getting HTMLElement.firstChild, lastChild, + nextSibling and previousSibling. HTMLElement.firstChild returns + the first node below the current node. HTMLElement.lastChild + returns the last node below the current node. HTMLElement.nextSibling + returns the node after the current node. HTMLElement.previousSibling + returns the node before the current node. They each return null + if there is no such node or the node type is not supported (not HTML). + + + Add support for HTMLElement.removeChild and insertBefore. + HTMLElement.removeChild removes an Element from the HTML document. + It returns the removed Element which is no longer part of the HTML + document. HTMLElement.insertBefore adds a new child element before + another child element. It returns the newly added child element. + + + Add support for HTMLElement.cloneNode and replaceChild and + Document.createTextNode to close RFE 805051. To support + createTextNode, added support for DOM text nodes and character + data nodes including the data and length properties and + appendData, deleteData, insertData, replaceData, substringData + and splitText functions. Updated DOM API properties and + methods of HTMLElement to work with text nodes. Also added + support for HTMLElement.nodeType, nodeName and nodeValue + properties. + + + Added method HtmlArea.click() + + + Add support for click() for all element types that have an + onClick attribute. This includes image. Removed extra + non-standard attributes (onClick, etc.) from BDO element. + Fixed support for button tags with type other than submit. + Added support for access keys to anchor, area, label, legend, + and textarea elements. + + + Fixed bug where variables defined in a script could not be referenced + as "window.myVariable". This prevented the google ads from working + on the HtmlUnit website. + + + Stubbed out Window.onerror + + + Fixed bug where an option without a value could not be selected. + + + Fixed bug where Select[index] wasn't returning options. + + + Fixed bug where button names would get submitted twice. Patch + submitted by Brad Clarke. + + + Added support for auto-refresh both from a Meta tag and from an + HTTP response header. + + + Added support for the format of &lt;script&gt; defined by DOM Level 2. + Patch submitted by Jun Chen + + + An HtmlTextArea should not contain anything but preformatted text, + so doing things such as converting &lt;br&gt; to line breaks and removing + extra white space should not happen. Patch supplied by Brad Clarke. + + + Fixed exception when trying to reference one frame by name from + another in JavaScript. For example "parent.nav.document", where + nav is the name of the frame. + + + Fixed exception when specifying an empty string for src on an a frame. + + + Fixed the bug where newly opened windows targeted at named + frames were not opening in the correct windows. + + Changed returned page from click() method to work with new + targets. That is, instead of just returning changes to the + immediate window, it returns any window that is opened. So, + if you call click() on an element that has a target set, you + will get the page in the window for that target. This is + particularly needed for the _blank target where you couldn't + find the new window without this change since it is not named. + + + Fixed a bug where windows that were overwritten were not + cleaned up so they would be returned from getWebWindowByName. + + + Added WebWindow.getTopWindow() and getParentWindow(). + + + Added support for the remaining special target names (_blank, + _parent, _top in addition to _self that was already supported). + These special target names are supported for a, area and form + elements as well as the JavaScript open() function. + + + Added support for DOM API node navigation methods in + HtmlElement so they are available within test cases. This + includes getParentNode, getNextSibling, getPreviousSibling, + getFirstChild, getLastChild, getNodeType, getNodeName, and + getNodeValue. + + + Added support for base elements to set a default target + using the target attribute. This affects a, area and form + elements. + + + Fixed a bug where a base element without an href attribute + was causing a MalformedURLException to be thrown. This can + be caused when the base element just sets a default target. + Similarly check for empty href attribute in a and area + elements. (The HTML 4 standard does not allow the action + attribute to be optional in form elements.) + + + Changed the behaviour of HtmlCheckBoxInput.click() to be consistent + with IE and Mozilla. Patch submitted by Jun Chen. + + + Fix return type from DomCharacterData.getData to be String. + + + Removed non-standard Element API from Text and CharacterData + Node classes by factoring out a DOM Node class in the html and + JavaScript implementations. Return type from DOM navigation + methods, e.g., getFirstChild(), standardized to be DomNode + instead of HtmlElement. + + + Added support for onload handlers on frames. This isn't supported + by the HTML specification but is supported by the popular browsers. + + + Upgraded commons-httpclient.jar to 2.0-rc2 + + + New method WebClient.loadWebResponseInto() which can be used to create + pages that were not loaded via HTTP. + + + New method StringWebResponse which can be used to easily create a + WebResponse based on a string containing html. + + + Finished the second variation of document.write(), writing to frames + other than the one that is loading. + + + New method TopLevelWindow.close() + + + Added "type" attribute to WebWindowEvent to make testing easier + + + Refactored test for window opening using the new type attribute. + + + Added support for window.status + + + New method HtmlForm.getInputByValue() to get a single input + + + New method HtmlForm.getInputsByValue() to get multiple inputs + + + Raise more specific exception from HtmlForm.getRadioButtonInput + if there is no radio button to match the name. + + + Added support for JavaScript editing of select options: add + new options, replace options, remove options, shorten options + list, set value, and set text. These features also available + through HtmlOption. + + + Fixed support for option label attribute so label value is + returned as text if label is set. + + + Add support for the id attribute of HTMLElement in JavaScript. + This partly fixes bug 757225. + + + Add HtmlElement.getId and setId. + + + Fix Document.getElementById in JavaScript so it returns null + when there is no element with the given ID. + + + Added support for jelly wrappers + + + Fixed bug with expansion of URLs that contain pound signs. + + + Upgraded NekoHTML to 0.8.1 + + + Added MockWebConnection in the deployable tree and changed FakeWebConnection + (in the test tree) to subclass that. + + + + + + Initial support for Maven + + + Fixed bug where checkboxes weren't getting properly mapped to the JavaScript + Checkbox object which resulted in incorrect behaviour. Add some additional + tests to prevent this kind of problem happening again. + + + Fixed bug in the setup of JavaScript form variables which resulted in situations where + input elements may not show up in the form depending on what had happened during page + load. + + + Refactored some logic out of Form into FormElementsArray for easier maintenance + + + Many classes had their own assertNotNull() method. Created an assert class and + changed all classes to use Assert.notNull() rather than separate methods. + + + Fixed bug in character encoding. Patch supplied by Noboru Sinohara. + + + Enhanced HtmlElement.asText() to behave more like a browser. Patch supplied + by Mike J. Bresnahan. + + + Updated NekoHTML to 0.7.7 + + + Changed the JavaScriptEngine to use weak references for HtmlPage objects. Previously + HtmlPage objects were never being garbage collected resulting in excessive memory + usage. + + + Fixed bug where the JavaScript textarea object was not properly getting and setting the 'value'. + + + Fixed bug where URL expansion wasn't obeying the base element as defined in the html. + + + Fixed bug where JavaScript form elements were not always being initialized correctly.. + + + Fixed typo in two of the samples in the getting started document. + + + Moved all tests under src/test/java + + + Fixed bug where onload handler would not execute a function if the brackets + weren't specified. Patch submitted by David K. Taylor. + + + Fixed bug "document.write of script element does not load script". Patch submitted + by David K. Taylor. + + + Fix for bug 740636 "getElementsByTagName should be case insensitive". + Patch submitted by David K. Taylor + + + Fix for bug 740605 "External script is executed before script element added". + Patch submitted by David K. Taylor + + + Fix for bug 740665 "Script attributes undefined when script executes". + Patch submitted by David K. Taylor + + + Fix for bug 742902 "document.location prints as object reference instead of URL". + Patch submitted by David K. Taylor + + + Fix for bug 743241 "document.write from external script is not added to document". + Patch submitted by David K. Taylor + + + Partial fix for RFE 741930 "document.createElement(...) and form.appendChild(...)". + This fix adds document.createElement for most element types. It does not support input tags. + + + Add support for setting window.onload within a script. Window.onload may be set to + the name of a function, e.g., window.onload=initFunc; + + + Partial fix for RFE 741930 "document.createElement(...) and form.appendChild(...)". + This fix adds HTMLElement.appendChild. + + + Add support for getting HTMLElement.parentNode. HTMLElement.parentNode returns the + node above the current node. It returns null if there is no parent or the parent node + type is not supported (not HTML). + + + Fixed broken behaviour in Input.onclick. Previously, if the onclick handler + for a submit input didn't return true then the form would not be submitted. + The html spec doesn't seem clear on this but Internet Explorer and Mozilla + both allow the form to be submitted no matter what is returned from + Input.onclick. + + + Moved all logic from the HtmlInput subclasses up into HtmlInput itself. + Patch provided by Barnaby Court. + + + Added instructions for the "how to compile from cvs" document. + Patch provided by Barnaby Court. + + + Changed HtmlTextArea.setText() to actually modify the DOM + Patch provided by Barnaby Court. + + + Fix for bug 738548 - "Form values are not Posted Properly to Server" + + + Added support for the property Window.name + + + Added read-only support for Document.cookie. + + + Added support for the JavaScript method Window.setTimeout() + + + Upgraded the rhino engine to 1.5R4.1 + + + Upgraded the xerces to 2.4 + + + New method HtmlPage.getAllForms() + + + Fixed bug where inputs would not submit properly if the type attribute + wasn't lowercase. + + + Changed behaviour of HtmlImageInput submission to be consistent with + + what the browsers do. If the input's name was foo we would previously + send the following values to the server: foo, foo.x and foo.y. The browsers + only send foo.x and foo.y. + + + Added docs on configuring JSSE - contributed by Tom Hamilton + + + + + + Started tracking more information about changes + + + Fixed bug where the checked attribute wasn't always returning the correct value. + + + Fixed bug where checkboxes were returning the wrong value if they hadn't explicitly + been set by the server. + + + Added support for JavaScript Document.getElementsByTagName() + + + Fixed bug where document.all wasn't being initialized correctly until after the entire page had + loaded. This meant that JavaScript that executed during page load would blow up when trying + to access document.all. + + + Added support for location.hostname which fixed all but one of the tests in the sanity check. + + + Added support for document.all[index] + + + Changed the JavaScript tagName attribute to return uppercase values according to spec + + + Updated configuration file with more functions/properties + + + Added support for document.all.tags() + + + Fixed bug in expansion of relative URLs + + + Added support for setting the src attribute on an iframe via JavaScript. Setting this attribute + will cause the iframe to be reloaded with new content. + + + Improved the documentation for WebWindowEvent handling as the behaviour wasn't really + self explanatory. + + + + + + Added method HtmlButtonInput#click(). + + + Fixed a bug in JavaScript loading where external scripts were being loaded after the page was fully + parsed rather than as each &lt;script&gt; tag was being handled. This resulted in situations where + JavaScript that was executed during the parsing of the page would not be able to access functions + declared in the external JavaScript files. + + + Fixed bug in HtmlForm.getRadioButtonsByName() where it would not match elements with an + uppercase value for "radio" + + + Fixed a bunch of places that were declared to throw ElementNotFoundException but never actually did. + + + + + + Fixed bug where redirection didn't happen correctly if the location header contained + multiple entries separated by commas + + + Fixed bug where some success status codes (not 200) were being reported as errors + + + Upgraded NekoHTML to version 0.7.4 + + + Upgraded commons-httpclient to 2.0beta3 + + + Upgraded xerces to 2.2.1 + + + Upgraded the rhino JavaScript engine to version 1.5b3 + + + Added support for the Window.opener property + + + Fixed bug where JavaScript that was enclosed in html comment tags would blow up + + + Initial support for keyboard navigation + + + Initial draft of a howto for keyboard navigation + + + New method: HtmlButton#isDisabled() + + + The click() method on buttons now do nothing if that element is disabled + + + Fixed bug where JavaScript Form.elements was not returning radio buttons + + + Refactored the interface between WebClient and WebConnection to make it easier to + add custom implementations of WebConnection. + + + Added support for the JavaScript Style object + + + Fixed bug where comments on the same line of an opening html comment inside a script tag + were being treated as JavaScript rather than as comment + + + Fixed bug where clicking on a checkbox would submit the form. + + + Fixed bug where form.submit() was always loading into the default WebWindow, not the + current one. + + + Added support for indexed properties in JavaScript forms + + + Changes in the latest versions of commons-httpclient are reusing buffers that they + previously weren't. This results in a situation where trying to get the content + out of a WebResponse after the initial load would result in no content. Buffering + is now done within HtmlUnit to avoid this problem. + + + New method WebResponse#getLoadTimeInMilliSeconds() + to measure load times of specific pages. This is intended for performance tuning of + web applications + + + Moved submission guidelines into their own document (submittingPatches.html). + + + Fixed bug where the variable "this" in an onclick handler was a Window rather than the + appropriate component. + + + Added support for onchange handlers in input tags + + + Added support for JavaScript document.referrer + + + Added support for JavaScript document.URL + + + Added initial support for JavaScript document.write(). Calling document.write() to add content + while the page is loading is working. Using it to write to a different frame is not. + + + + + + Fixed bug where loading of external JavaScript files would not follow redirects. + + + Fixed bug where accessing radio buttons by name wasn't working correctly + + + Stubbed out Window.close() + + + If there is only one radio button with a given name then JavaScript should be returning + the radio button, not an array of buttons. The code was always returning an array. + + + Fixed bug where the JavaScript Option.text was returning the wrong value + + + + + + Fixed bug where calling WebClient.open() would open a new top level window every time. + + + Fixed bug where javascript:Window.open() was not returning the new window object + + + Added support for onchange handler in HtmlSelect + + + Cleaned up some javadoc warnings + + + New method WebClient#loadWebResponse(URL, SubmitMethod, List) + + + Removed the need for HiddenWebWindow - JavaScript files are now loaded via + WebClient#loadWebResponse(URL, SubmitMethod, List). + This should fix an intermittent bug where an UnsupportedOperationException was being called from + the HiddenWebWindow if a JavaScript file was returned with a content type of "text/html" + + + Fixed bug where javascript:option.getValue() was returning the text, not the value + + + Improved some error handling when secondary pages are being loaded by frames + + + + + + Upgraded commons-logging.jar to 1.0.2 + + + Upgraded commons-httpclient.jar to Oct 20/2002 gump build + + + Added support for javascript:Input.disabled + + + Upgraded NekoHTML to version 0.6.8 + patches from the author + + + Changed window.open() to understand the magic name _self + + + Added HtmlOption#setSelected(boolean) + + + Completed support for reset buttons + + + Page load was blowing up if the name of an input was the same as the name of a + predefined property in Form (ie id or action). Fixed so that if the input has the + same name as a predefined property, the input wins. + + + Added support for the JavaScript method Window.confirm() + + + New interface ConfirmHandler + + + New method WebClient#setConfirmHandler(ConfirmHandler) and WebClient#getConfirmHandler() + + + Added support for the JavaScript method Window.prompt() + + + New interface PromptHandler + + + New method + WebClient#setPromptHandler(PromptHandler) and + WebClient#getPromptHandler() + + + New method HtmlForm#getParameterListForSubmit(). + This method is intended as a debugging aid. + + + Page load would blow up if no body tag found. Framesets aren't required to + have body tags + + + Added support for JavaScript URLs in Frame and IFrame src tags + + + Improved some error messages during initialization + + + New class ObjectInstantiationException + + + Added protocol package for URL protocols and added protocol/javascript package for + code that supports JavaScript URLs + + + Removed deprecated method WebClient.setBrowserVersion(BrowserVersion). No replacement + for this method - browser versions must be set in the constructor of the WebClient. + + + Removed deprecated method HtmlPage.executeJavascriptIfPossible(String,String). Use + HtmlPage.executeJavaScriptIfPossible(String,String,boolean) instead. + + + Removed deprecated method HtmlPage.getTitle(). Use HtmlPage.getTitleText() instead. + + + Added support for manipulating the disabled attribute of any element via JavaScript. + This is incorrect according to the html specification but Internet Explorer supports + it so we have to as well. This will print a warning if it is used. + + + Fixed bug where script tags that loaded external files would cause the new script + to overwrite the existing page in the window + + + Fixed bug where a redirect called from JavaScript in the page load would not replace + the page. + + + + + + Changed html parser from JTidy to CyberNeko. + CyberNeko is better at parsing really bad html but this now gives us a dependency on the + xerces parser from apache. + + + The directory structure has undergone a significant change and is now checked in under + a single module ("htmlunit") in cvs. This should only affect those people who are + checking out code directly from cvs. + + + Upgraded checkstyle to version 2.4 + + + Added support for document.location (an alias for window.location) + + + Changed initialization order in HtmlPage so that the enclosing window + is initialized before the JavaScript is run + + + BEHAVIOUR CHANGE: WebClients may no longer change browser versions after creation. + This is required because some of the JavaScript bits initialize differently + depending on which browser is in use. If we allowed the browser version to + change then behaviour would be very unpredictable. + + + Added method HtmlPage#getFirstAnchorByText(java.lang.String) + + + First steps towards having property/function information in a configuration file + + + Added method HtmlPage#getHtmlElementsByAccessKey(char) + + + Added support for javascript:document.getElementById() + + + Added support for javascript:document.all[string] + + + Fixed bug where relative URLs were not being expanded in certain situations + + + Fixed bug in relative URL expansion that was blowing up on URLs like //foo.com + + + Upgraded commons-httpclient.jar and commons-logging.jar to the Aug 30 gump build + + + Added HtmlElement#asXml() + + + Added WebClient#expandUrl(URL, String) + + + Fixed bug where relative URLs in redirects were not being expanded. + + + Fixed bug in HtmlSelect#getOptionByValue(String) + where searching for the option would start at the top of the page instead of at the select. + + + Applied patches to NekoHTML to fix problems with script tags and isindex + tags. Thanks to Andy Clark (author of NekoHTML) for extremely quick + responses to bug reports. + + + Added support for HtmlImageInput#click() and HtmlImageInput#click(int, int) + + + Changed redirect logic so that on a 302 or 303 status, if the method changes + from post to get, the parameters will be thrown away for the second request. + The HTTP spec is unclear on this exact behaviour but the common browsers seem + to do it this way. + + + Added the constant BrowserVersion.NETSCAPE_6_2_3 + + + + + + Changed the license used by HtmlUnit to an apache style one + + + Changed default value of WebClient.isRedirectEnabled() to false to be + consistent with pre2 + + + Updated look of documentation + + + Started migrating System.out.println calls over to commons-logging. Refer + to the logging tutorial (logging.html) for information on customizing this. + + + Support for onClick handlers in HtmlSubmitInput + + + Support for onClick handlers in HtmlButton + + + Fixed bug where NullPointerException would be thrown if window.alert() was + called and no AlertHandler had been registered + + + Support for onload handler on the body tag + + + Support for customizing the page types. See WebClient.setPageCreator() + + + Added HtmlElement.hasHtmlElementWithId() + + + Renamed DefaultAlertHandler to CollectingAlertHandler + + + Fixed NullPointerException in HtmlForm during submission of a form containing + a radio button + + + Stubbed out the following methods on Input: click(), focus(), blur(), select() + + + Added support for inherited functions to SimpleScriptable. Previously only getters + and setters were supported. + + + Changed SimpleScriptable.getLog() to create a new log object each time. This is + necessary since in rhino, functions don't know who their object is. A way for + functions to learn about their objects will have to be determined. + + + Added a JavaScript style object + + + Added new method HtmlElement.isAttributeDefined() + + + Changed HtmlElement.getAttributeValue() to return constants indicating whether + the attribute was defined with an empty value or just not defined. Both of + these constants are empty strings so the behaviour of this method hasn't + changed. + + + Added a tutorial section on the main page and added a link to the table tutorial + + + Started writing the table tutorial - still needs a lot of work + + + Added support for the JavaScript function Form.submit() + + + Fixed bug where javascript:document.forms[formName] was blowing up + + + Changed logic behind anchor onClick() handler to abort the click if JavaScript returns false + + + Changed logic behind form onSubmit() handler to abort the submit if JavaScript returns false + + + Fixed WebConnection so that it now passes the query string through on post requests + + + Added HtmlFrame class. Loading a page containing frames will cause those frames to be + automatically loaded as well. + + + Added support for loading iframes + + + Added HtmlFrameSet class + + + Added a coding conventions document (codingConventions.html) + + + Added a "how to get the latest code from cvs" document (buildingFromCvs.html) + + + Renamed WebWindow.getPage() and setPage() to getEnclosedPage() and setEnclosedPage() to + avoid conflict with getPage in HtmlElement + + + Added WebClient.getWebWindowByName() + + + New class WebWindowNotFoundException + + + When checking to see if a script is JavaScript we previously assumed that the + script was not and then looked for proof that it was. This gives us behaviour + that is different from browsers in some situations. The logic has been + changed so that now it assumed that any script IS JavaScript unless there + is proof otherwise. + + + New method HtmlPage.getFrames() + + + Initial support for resetting forms. None of the elements actually revert to + their previous values yet but onReset handlers will be run if specified. + + + New method HtmlTable.getCaptionText() + + + Deprecated HtmlPage.getTitle() to be replaced with HtmlPage.getTitleText(). This + will be removed before the final release of 1.1 + + + Added support for the JavaScript properties: Select.options, Select.selectedIndex, + Select.length and Option.value + + + + + + Added HtmlElement.getParent() + + + Added HtmlElement.getNextSibling() + + + Added HtmlElement.getPreviousSibling() + + + Changed WebConnection so that cookies will be shared among servers in + the same domain + + + Added support for redirection - WebClient.setRedirectEnabled(boolean) + + + Added method on WebResponse to access the response headers + + + Many new JavaScript objects - this will be transparent to users of HtmlUnit + + + Lots of refactoring in the JavaScript portion + + + Fixed a NullPointerException if the server doesn't return a content-type header + + + Fixed HtmlElement.childrenAsText() so that it ignores comments + + + Added support for Input.checked + + + Added some constants to BrowserVersion for various browsers + + + Upgraded gsbase.jar to version 1.8 + + + Replaced js.jar with a version that has been compiled with debug support + + + Upgraded commons-httpclient.jar to the July 27 gump build. + + + Added commons-logging.jar (July 27 gump build) which is needed by httpclient + + + Support for proxy server and ssl together + + + + + + Fixed NullPointerException due to a bug in JTidy - thanks to + Mike J Bresnahan for tracking this one right into the JTidy source. + + + HtmlAnchor now supports JavaScript URLs and onClick handlers + + + Ability to set the emulated browser via WebClient.setBrowserVersion(BrowserVersion) + + + Stubbed out a bunch of JavaScript methods that are used by the popular websites. + Each stubbed out method will print a diagnostic message when it is called + to alert the user to the fact that it was called. This is just a temporary + measure to ensure that HtmlUnit doesn't blow up when hitting common sites. + These methods *will* be implemented properly at some point. + + + Added WebWindow + + + Added TopLevelWindow + + + Added WebWindowListener + + + Added WebWindowEvent + + + Added WebWindowAdapter + + + Added initial support for javascript:open(). Does not currently support + features or browser history + + + Fixed some cases in HtmlPage.getFullyQualifiedUrl() that weren't expanding properly + + + Added HtmlTitle + + + Added HtmlPage.getTitle() + + + Added JavaScript window.location="some url" + + + Stubbed out the JavaScript history object + + + Added support JavaScript URLs in HtmlForm submission + + + Added support for HtmlForm.onSubmit() + + + Rewrote logic for handling relative URLs + + + Fixed bug in HtmlRadioButtonInput that was causing isChecked() to return false + in some cases even if the checked attribute was there. + + + + + + Added initial JavaScript support + + + Lots of bug fixes + + + + + + Initial release + + diff --git a/src/main/java/org/htmlunit/BrowserVersion.java b/src/main/java/org/htmlunit/BrowserVersion.java index dc43e7e6582..c5259711507 100644 --- a/src/main/java/org/htmlunit/BrowserVersion.java +++ b/src/main/java/org/htmlunit/BrowserVersion.java @@ -70,7 +70,7 @@ public final class BrowserVersion implements Serializable { /** Latest Firefox. */ - public static final BrowserVersion FIREFOX = new BrowserVersion(152, "FF"); + public static final BrowserVersion FIREFOX = new BrowserVersion(153, "FF"); private static final int FIREFOX_ESR_NUMERIC = 140; @@ -183,7 +183,7 @@ public final class BrowserVersion implements Serializable { HttpHeader.SEC_CH_UA, HttpHeader.SEC_CH_UA_MOBILE, HttpHeader.SEC_CH_UA_PLATFORM, - "Upgrade-Insecure-Requests", + HttpHeader.UPGRADE_INSECURE_REQUESTS, HttpHeader.USER_AGENT, HttpHeader.ACCEPT, HttpHeader.SEC_FETCH_SITE, @@ -230,7 +230,7 @@ public final class BrowserVersion implements Serializable { HttpHeader.SEC_CH_UA, HttpHeader.SEC_CH_UA_MOBILE, HttpHeader.SEC_CH_UA_PLATFORM, - "Upgrade-Insecure-Requests", + HttpHeader.UPGRADE_INSECURE_REQUESTS, HttpHeader.USER_AGENT, HttpHeader.ACCEPT, HttpHeader.SEC_FETCH_SITE, @@ -296,7 +296,6 @@ public final class BrowserVersion implements Serializable { private final HashSet maybeMediaResource_; private final HashSet probablyMediaResources_; - /** * Creates a new browser version instance. * @@ -920,7 +919,6 @@ public int getPixelsPerChar() { return 10; } - /** * Performs this operation. * diff --git a/src/main/java/org/htmlunit/BrowserVersionFeatures.java b/src/main/java/org/htmlunit/BrowserVersionFeatures.java index ea5b55acd39..3ecc539372b 100644 --- a/src/main/java/org/htmlunit/BrowserVersionFeatures.java +++ b/src/main/java/org/htmlunit/BrowserVersionFeatures.java @@ -168,10 +168,6 @@ public enum BrowserVersionFeatures { @BrowserFeature({FF, FF_ESR}) HTTP_HEADER_PRIORITY, - /** The anchor hostname setter ignores blank url's. */ - @BrowserFeature({FF, FF_ESR}) - JS_ANCHOR_HOSTNAME_IGNORE_BLANK, - /** * The anchor pathname detects url's starting with one letter as file url's * and replaces them with the file protocol. */ @@ -254,6 +250,10 @@ public enum BrowserVersionFeatures { @BrowserFeature({CHROME, EDGE}) JS_ERROR_STACK_TRACE_LIMIT, + /** Javascript {@code Error.stackTraceLimit}. */ + @BrowserFeature(FF) + JS_ERROR_STACK_TRACE_LIMIT_128, + /** Javascript InputEvent reads the inputType property from data. */ @BrowserFeature({FF, FF_ESR}) JS_EVENT_INPUT_CTOR_INPUTTYPE, @@ -284,6 +284,10 @@ public enum BrowserVersionFeatures { @BrowserFeature({FF, FF_ESR}) JS_IMAGE_WIDTH_HEIGHT_RETURNS_24x24_0x0, + /** Indicates that innerText add a nl when reaching svg element. */ + @BrowserFeature({FF, FF_ESR}) + JS_INNER_TEXT_SELECT_EMPTY, + /** Indicates that innerText add a nl when reaching svg element. */ @BrowserFeature({CHROME, EDGE}) JS_INNER_TEXT_SVG_NL, @@ -400,6 +404,10 @@ public enum BrowserVersionFeatures { @BrowserFeature({FF, FF_ESR}) XHR_LOAD_ALWAYS_AFTER_DONE, + /** Indicates if the XMLHttpRequest preflight request includes the 'Sec-Fetch-Mode=cors' header. */ + @BrowserFeature({CHROME, EDGE}) + XHR_PREFLIGHT_CORS, + /** If state unsent the response text is empty even if the response type is wrong. */ @BrowserFeature({FF, FF_ESR}) XHR_RESPONSE_TEXT_EMPTY_UNSENT, diff --git a/src/main/java/org/htmlunit/DefaultCssErrorHandler.java b/src/main/java/org/htmlunit/DefaultCssErrorHandler.java index 5f46bfc3fb8..cd3a5a44892 100644 --- a/src/main/java/org/htmlunit/DefaultCssErrorHandler.java +++ b/src/main/java/org/htmlunit/DefaultCssErrorHandler.java @@ -72,7 +72,7 @@ private static String buildMessage(final CSSParseException exception) { final int line = exception.getLineNumber(); final int col = exception.getColumnNumber(); - if (null == uri) { + if (uri == null) { return "[" + line + ":" + col + "] " + exception.getMessage(); } return "'" + uri + "' [" + line + ":" + col + "] " + exception.getMessage(); diff --git a/src/main/java/org/htmlunit/DefaultPageCreator.java b/src/main/java/org/htmlunit/DefaultPageCreator.java index d5c526e732a..224f1a42fa4 100644 --- a/src/main/java/org/htmlunit/DefaultPageCreator.java +++ b/src/main/java/org/htmlunit/DefaultPageCreator.java @@ -115,7 +115,7 @@ public enum PageType { * @return "xml", "html", "javascript", "text" or "unknown" */ public static PageType determinePageType(final String contentType) { - if (null == contentType) { + if (contentType == null) { return PageType.UNKNOWN; } @@ -150,7 +150,7 @@ public static PageType determinePageType(final String contentType) { /** * Determines the kind of page to create from the content type. * @param webResponse the response to investigate - * @exception IOException if an IO problem occurs + * @throws IOException if an IO problem occurs * @return "xml", "html", "javascript", "text" or "unknown" */ public static PageType determinePageType(final WebResponse webResponse) throws IOException { @@ -207,7 +207,7 @@ public static PageType determinePageType(final WebResponse webResponse) throws I * * @param webResponse the response from the server * @param webWindow the window that this page will be loaded into - * @exception IOException if an IO problem occurs + * @throws IOException if an IO problem occurs * @return the new page object */ @Override diff --git a/src/main/java/org/htmlunit/DownloadedContent.java b/src/main/java/org/htmlunit/DownloadedContent.java index 53d4c7440a2..edfac49df8c 100644 --- a/src/main/java/org/htmlunit/DownloadedContent.java +++ b/src/main/java/org/htmlunit/DownloadedContent.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Serializable; +import java.lang.ref.Cleaner; import java.nio.file.Files; import org.apache.commons.io.FileUtils; @@ -72,8 +73,25 @@ public long length() { * Implementation keeping content on the file system. */ class OnFile implements DownloadedContent { + private final File file_; - private final boolean temporary_; + private final Cleaner.Cleanable cleanable_; + + private static final class OnFileCleaningAction implements Runnable { + private File file_; + + OnFileCleaningAction(final File file) { + file_ = file; + } + + @Override + public synchronized void run() { + if (file_ != null) { + FileUtils.deleteQuietly(file_); + file_ = null; + } + } + } /** * Ctor. @@ -83,7 +101,12 @@ class OnFile implements DownloadedContent { */ OnFile(final File file, final boolean temporary) { file_ = file; - temporary_ = temporary; + if (temporary) { + cleanable_ = WebClient.registerCleanerAction(this, new OnFileCleaningAction(file)); + } + else { + cleanable_ = null; + } } @Override @@ -93,8 +116,8 @@ public InputStream getInputStream() throws IOException { @Override public void cleanUp() { - if (temporary_) { - FileUtils.deleteQuietly(file_); + if (cleanable_ != null) { + cleanable_.clean(); } } @@ -103,17 +126,12 @@ public boolean isEmpty() { return false; } - @Override - protected void finalize() throws Throwable { - super.finalize(); - cleanUp(); - } - @Override public long length() { if (file_ == null) { return 0; } + return file_.length(); } } diff --git a/src/main/java/org/htmlunit/HttpWebConnection.java b/src/main/java/org/htmlunit/HttpWebConnection.java index 7b57672a179..c24b89afc45 100644 --- a/src/main/java/org/htmlunit/HttpWebConnection.java +++ b/src/main/java/org/htmlunit/HttpWebConnection.java @@ -14,6 +14,9 @@ */ package org.htmlunit; +import static org.htmlunit.BrowserVersionFeatures.HTTP_HEADER_CH_UA; +import static org.htmlunit.BrowserVersionFeatures.HTTP_HEADER_PRIORITY; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.EOFException; @@ -108,6 +111,7 @@ import org.htmlunit.httpclient.HtmlUnitCookieStore; import org.htmlunit.httpclient.HtmlUnitRedirectStrategie; import org.htmlunit.httpclient.HtmlUnitSSLConnectionSocketFactory; +import org.htmlunit.httpclient.HttpClientConverter; import org.htmlunit.httpclient.SocksConnectionSocketFactory; import org.htmlunit.util.KeyDataPair; import org.htmlunit.util.MimeType; @@ -463,8 +467,7 @@ void buildFilePart(final KeyDataPair pairWithFile, final MultipartEntityBuilder filename = pairWithFile.getValue(); } - builder.addBinaryBody(pairWithFile.getName(), new ByteArrayInputStream(data), - contentType, filename); + builder.addBinaryBody(pairWithFile.getName(), data, contentType, filename); return; } @@ -809,19 +812,164 @@ protected WebResponse newWebResponseInstance( return new WebResponse(responseData, webRequest, loadTime); } + /** + * Returns the {@code Sec-Fetch-Mode} value to use for this request: the explicit + * override set on the request if any, otherwise the default mode implied by its + * {@link WebRequest.FetchDestination}. + * @param webRequest the request + * @return the {@code Sec-Fetch-Mode} header value + */ + private static String computeSecFetchMode(final WebRequest webRequest) { + final WebRequest.FetchMode override = webRequest.getFetchModeOverride(); + if (override != null) { + return override.getValue(); + } + return defaultFetchModeFor(webRequest.getFetchDestination()).getValue(); + } + + /** + * The default {@link WebRequest.FetchMode} implied by a given + * {@link WebRequest.FetchDestination}, absent an explicit override. + * @param destination the destination + * @return the default mode for that destination + */ + private static WebRequest.FetchMode defaultFetchModeFor(final WebRequest.FetchDestination destination) { + switch (destination) { + case DOCUMENT: + case IFRAME: + case FRAME: + return WebRequest.FetchMode.NAVIGATE; + + // fonts are always fetched in CORS mode regardless of crossorigin attribute; + // XHR/fetch() default to CORS mode too (fetch() can override to no-cors/same-origin, + // via WebRequest.setFetchModeOverride) + case FONT: + case MANIFEST: + case EMPTY: + return WebRequest.FetchMode.CORS; + + // workers can never be cross-origin + case WORKER: + case SHARED_WORKER: + case SERVICE_WORKER: + return WebRequest.FetchMode.SAME_ORIGIN; + + case WEBSOCKET: + return WebRequest.FetchMode.WEBSOCKET; + + // image, script, style, object, embed, audio, video, track, report + default: + return WebRequest.FetchMode.NO_CORS; + } + } + + /** + * Computes the {@code Sec-Fetch-Site} value for this request by comparing the + * request's {@link WebRequest#getRequestingUrl() initiator} against the target + * URL. + * @param webRequest the request + * @param targetUrl the target URL (passed separately since callers already have it) + * @return one of {@code none}, {@code same-origin}, {@code same-site} or {@code cross-site} + */ + private static String computeSecFetchSite(final WebRequest webRequest, final URL targetUrl) { + final URL requestingUrl = webRequest.getRequestingUrl(); + if (requestingUrl == null) { + // no initiator - e.g. a typed URL, bookmark, or other browser-chrome-initiated navigation + return "none"; + } + if (isSameOrigin(requestingUrl, targetUrl)) { + return "same-origin"; + } + if (isSameSite(requestingUrl, targetUrl)) { + return "same-site"; + } + return "cross-site"; + } + + private static boolean isSameOrigin(final URL a, final URL b) { + return a.getProtocol().equals(b.getProtocol()) + && a.getHost().equalsIgnoreCase(b.getHost()) + && effectivePort(a) == effectivePort(b); + } + + private static int effectivePort(final URL url) { + final int port = url.getPort(); + return port == -1 ? url.getDefaultPort() : port; + } + + /** + * Same-site comparison per the Fetch Metadata / HTML "same site" algorithm: same + * scheme and same registrable domain (eTLD+1), ignoring port and subdomain. + * + * @param a first URL + * @param b second URL + * @return whether both URLs are considered "same-site" + */ + private static boolean isSameSite(final URL a, final URL b) { + if (!a.getProtocol().equals(b.getProtocol())) { + return false; + } + + final String registrableDomainA = HttpClientConverter.registrableDomain(a.getHost()); + final String registrableDomainB = HttpClientConverter.registrableDomain(b.getHost()); + + // both are normalized and in lower case + return registrableDomainA.equals(registrableDomainB); + } + + /** + * Returns whether the given URL is a "potentially trustworthy origin" as defined by + * the Secure Contexts spec, which gates whether {@code Sec-Fetch-*} headers (and + * {@code Upgrade-Insecure-Requests}) are sent at all. Note that {@code localhost} + * and loopback addresses are considered trustworthy even over plain HTTP. + * @param url the target URL + * @return whether the origin is potentially trustworthy + */ + private static boolean isPotentiallyTrustworthy(final URL url) { + final String protocol = url.getProtocol(); + if ("https".equals(protocol) || "wss".equals(protocol) || "file".equals(protocol)) { + return true; + } + if (!"http".equals(protocol) && !"ws".equals(protocol)) { + // be conservative for schemes not explicitly handled here (e.g. about:, data:, blob: + // callers should special-case these before reaching HTTP request construction) + return false; + } + + final String host = url.getHost(); + return "localhost".equalsIgnoreCase(host) + || host.toLowerCase(java.util.Locale.ROOT).endsWith(".localhost") + || "127.0.0.1".equals(host) + || host.startsWith("127.") + || "::1".equals(host) + || "[::1]".equals(host); + } + private List getHttpRequestInterceptors(final WebRequest webRequest) { final List list = new ArrayList<>(); - final Map requestHeaders = webRequest.getAdditionalHeaders(); + final Map requestHeaders = new HashMap<>(webRequest.getAdditionalHeaders()); final URL url = webRequest.getUrl(); final StringBuilder host = new StringBuilder(url.getHost()); + final BrowserVersion browserVersion = webClient_.getBrowserVersion(); + final int port = url.getPort(); if (port > 0 && port != url.getDefaultPort()) { host.append(':').append(port); } + // Both Sec-Fetch-* (https://www.w3.org/TR/fetch-metadata/) and Client Hints + // (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-UA) are + // only sent to potentially-trustworthy target origins; computed once up front. + final boolean isSecureContext = isPotentiallyTrustworthy(url); + + // computed unconditionally: also drives Upgrade-Insecure-Requests below, + // which is not gated by origin trustworthiness the way Sec-Fetch-*/Client + // Hints are + final String secFetchMode = computeSecFetchMode(webRequest); + // make sure the headers are added in the right order - final String[] headerNames = webClient_.getBrowserVersion().getHeaderNamesOrdered(); + final String[] headerNames = browserVersion.getHeaderNamesOrdered(); for (final String header : headerNames) { if (HttpHeader.HOST.equals(header)) { list.add(new HostHeaderHttpRequestInterceptor(host.toString())); @@ -829,86 +977,154 @@ private List getHttpRequestInterceptors(final WebRequest else if (HttpHeader.USER_AGENT.equals(header)) { String headerValue = webRequest.getAdditionalHeader(HttpHeader.USER_AGENT); if (headerValue == null) { - headerValue = webClient_.getBrowserVersion().getUserAgent(); + headerValue = browserVersion.getUserAgent(); } list.add(new UserAgentHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.USER_AGENT); } else if (HttpHeader.ACCEPT.equals(header)) { final String headerValue = webRequest.getAdditionalHeader(HttpHeader.ACCEPT); if (headerValue != null) { list.add(new AcceptHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.ACCEPT); } } else if (HttpHeader.ACCEPT_LANGUAGE.equals(header)) { final String headerValue = webRequest.getAdditionalHeader(HttpHeader.ACCEPT_LANGUAGE); if (headerValue != null) { list.add(new AcceptLanguageHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.ACCEPT_LANGUAGE); } } else if (HttpHeader.ACCEPT_ENCODING.equals(header)) { final String headerValue = webRequest.getAdditionalHeader(HttpHeader.ACCEPT_ENCODING); if (headerValue != null) { list.add(new AcceptEncodingHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.ACCEPT_ENCODING); } } else if (HttpHeader.SEC_FETCH_DEST.equals(header)) { final String headerValue = webRequest.getAdditionalHeader(HttpHeader.SEC_FETCH_DEST); if (headerValue != null) { list.add(new SecFetchDestHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.SEC_FETCH_DEST); + } + else if (isSecureContext) { + list.add(new SecFetchDestHeaderHttpRequestInterceptor(webRequest.getFetchDestination().getValue())); } } else if (HttpHeader.SEC_FETCH_MODE.equals(header)) { final String headerValue = webRequest.getAdditionalHeader(HttpHeader.SEC_FETCH_MODE); if (headerValue != null) { list.add(new SecFetchModeHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.SEC_FETCH_MODE); + } + else if (isSecureContext) { + list.add(new SecFetchModeHeaderHttpRequestInterceptor(secFetchMode)); } } else if (HttpHeader.SEC_FETCH_SITE.equals(header)) { final String headerValue = webRequest.getAdditionalHeader(HttpHeader.SEC_FETCH_SITE); if (headerValue != null) { list.add(new SecFetchSiteHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.SEC_FETCH_SITE); + } + else if (isSecureContext) { + list.add(new SecFetchSiteHeaderHttpRequestInterceptor(computeSecFetchSite(webRequest, url))); } } else if (HttpHeader.SEC_FETCH_USER.equals(header)) { final String headerValue = webRequest.getAdditionalHeader(HttpHeader.SEC_FETCH_USER); if (headerValue != null) { list.add(new SecFetchUserHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.SEC_FETCH_USER); + } + + // Per spec, sent only for navigations backed by real user activation; + // real browsers omit it entirely otherwise (never send "?0"). + else if (isSecureContext + && WebRequest.FetchMode.NAVIGATE.getValue().equals(secFetchMode) + && webRequest.isUserActivation()) { + list.add(new SecFetchUserHeaderHttpRequestInterceptor("?1")); } } else if (HttpHeader.SEC_CH_UA.equals(header)) { - final String headerValue = webRequest.getAdditionalHeader(HttpHeader.SEC_CH_UA); - if (headerValue != null) { - list.add(new SecClientHintUserAgentHeaderHttpRequestInterceptor(headerValue)); + // Client Hints require a secure context, same as Sec-Fetch-* + // (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-UA) + if (isSecureContext) { + String headerValue = webRequest.getAdditionalHeader(HttpHeader.SEC_CH_UA); + if (headerValue != null) { + list.add(new SecClientHintUserAgentHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.SEC_CH_UA); + } + else { + if (browserVersion.hasFeature(HTTP_HEADER_CH_UA)) { + headerValue = browserVersion.getSecClientHintUserAgentHeader(); + list.add(new SecClientHintUserAgentHeaderHttpRequestInterceptor(headerValue)); + } + } } } else if (HttpHeader.SEC_CH_UA_MOBILE.equals(header)) { - final String headerValue = webRequest.getAdditionalHeader(HttpHeader.SEC_CH_UA_MOBILE); - if (headerValue != null) { - list.add(new SecClientHintUserAgentMobileHeaderHttpRequestInterceptor(headerValue)); + if (isSecureContext) { + final String headerValue = webRequest.getAdditionalHeader(HttpHeader.SEC_CH_UA_MOBILE); + if (headerValue != null) { + list.add(new SecClientHintUserAgentMobileHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.SEC_CH_UA_MOBILE); + } + else { + if (browserVersion.hasFeature(HTTP_HEADER_CH_UA)) { + list.add(new SecClientHintUserAgentMobileHeaderHttpRequestInterceptor("?0")); + } + } } } else if (HttpHeader.SEC_CH_UA_PLATFORM.equals(header)) { - final String headerValue = webRequest.getAdditionalHeader(HttpHeader.SEC_CH_UA_PLATFORM); - if (headerValue != null) { - list.add(new SecClientHintUserAgentPlatformHeaderHttpRequestInterceptor(headerValue)); + if (isSecureContext) { + String headerValue = webRequest.getAdditionalHeader(HttpHeader.SEC_CH_UA_PLATFORM); + if (headerValue != null) { + list.add(new SecClientHintUserAgentPlatformHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.SEC_CH_UA_PLATFORM); + } + else { + if (browserVersion.hasFeature(HTTP_HEADER_CH_UA)) { + headerValue = browserVersion.getSecClientHintUserAgentPlatformHeader(); + list.add(new SecClientHintUserAgentPlatformHeaderHttpRequestInterceptor(headerValue)); + } + } } } else if (HttpHeader.PRIORITY.equals(header)) { final String headerValue = webRequest.getAdditionalHeader(HttpHeader.PRIORITY); if (headerValue != null) { list.add(new PriorityHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.PRIORITY); + } + else { + if (browserVersion.hasFeature(HTTP_HEADER_PRIORITY)) { + list.add(new PriorityHeaderHttpRequestInterceptor("u=0, i")); + } } } else if (HttpHeader.UPGRADE_INSECURE_REQUESTS.equals(header)) { final String headerValue = webRequest.getAdditionalHeader(HttpHeader.UPGRADE_INSECURE_REQUESTS); if (headerValue != null) { list.add(new UpgradeInsecureRequestHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.UPGRADE_INSECURE_REQUESTS); + } + + // Real browsers only send this for navigations (top-level, iframe, frame), + // never for subresource fetches (image/script/style/xhr/...). + else if (WebRequest.FetchMode.NAVIGATE.getValue().equals(secFetchMode) + && HttpMethod.OPTIONS != webRequest.getHttpMethod()) { + list.add(new UpgradeInsecureRequestHeaderHttpRequestInterceptor("1")); } } else if (HttpHeader.REFERER.equals(header)) { final String headerValue = webRequest.getAdditionalHeader(HttpHeader.REFERER); if (headerValue != null) { list.add(new RefererHeaderHttpRequestInterceptor(headerValue)); + requestHeaders.remove(HttpHeader.REFERER); } } else if (HttpHeader.CONNECTION.equals(header)) { diff --git a/src/main/java/org/htmlunit/PageCreator.java b/src/main/java/org/htmlunit/PageCreator.java index b3777794b48..bf397b391e7 100644 --- a/src/main/java/org/htmlunit/PageCreator.java +++ b/src/main/java/org/htmlunit/PageCreator.java @@ -35,7 +35,7 @@ public interface PageCreator { * * @param webResponse the response from the server * @param webWindow the window that this page will be loaded into - * @exception IOException If an io problem occurs + * @throws IOException If an io problem occurs * @return the new page */ Page createPage(WebResponse webResponse, WebWindow webWindow) throws IOException; diff --git a/src/main/java/org/htmlunit/SgmlPage.java b/src/main/java/org/htmlunit/SgmlPage.java index 56d38fc2a13..f7b7febc68e 100644 --- a/src/main/java/org/htmlunit/SgmlPage.java +++ b/src/main/java/org/htmlunit/SgmlPage.java @@ -253,7 +253,7 @@ public DomAttr createAttribute(final String name) { @Override public URL getUrl() { final WebResponse wr = getWebResponse(); - if (null == wr) { + if (wr == null) { return UrlUtils.URL_ABOUT_BLANK; } return getWebResponse().getWebRequest().getUrl(); @@ -362,7 +362,7 @@ public Comment createComment(final String data) { * @param entityReferenceExpansion The value of this flag determines * whether entity reference nodes are expanded. * @return The newly created NodeIterator. - * @exception DOMException + * @throws DOMException * NOT_SUPPORTED_ERR: Raised if the specified root is null. */ public DomNodeIterator createNodeIterator(final Node root, final int whatToShow, final NodeFilter filter, diff --git a/src/main/java/org/htmlunit/WebClient.java b/src/main/java/org/htmlunit/WebClient.java index d176d5326c2..acd8fbcde20 100644 --- a/src/main/java/org/htmlunit/WebClient.java +++ b/src/main/java/org/htmlunit/WebClient.java @@ -16,8 +16,6 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.htmlunit.BrowserVersionFeatures.HTTP_HEADER_CH_UA; -import static org.htmlunit.BrowserVersionFeatures.HTTP_HEADER_PRIORITY; import java.io.BufferedInputStream; import java.io.File; @@ -26,6 +24,8 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.io.Serializable; +import java.lang.ref.Cleaner; +import java.lang.ref.Cleaner.Cleanable; import java.lang.ref.WeakReference; import java.net.MalformedURLException; import java.net.URL; @@ -164,6 +164,8 @@ public class WebClient implements Serializable, AutoCloseable { private static final WebResponseData RESPONSE_DATA_NO_HTTP_RESPONSE = new WebResponseData( 0, "No HTTP Response", Collections.emptyList()); + static final Cleaner CLEANER = Cleaner.create(); + /** * These response headers are not copied from a 304 response to the cached * response headers. This list is based on Chromium http_response_headers.cc @@ -1364,6 +1366,18 @@ public void deregisterWebWindow(final WebWindow webWindow) { } } + /** + * Registers an object and a cleaning action to run when the object + * becomes phantom reachable. This forwards the call to our static {@link Cleaner}. + * + * @param obj the object to monitor + * @param action a {@code Runnable} to invoke when the object becomes phantom reachable + * @return a {@code Cleanable} instance + */ + public static Cleanable registerCleanerAction(final Object obj, final Runnable action) { + return CLEANER.register(obj, action); + } + /** * Expands a relative URL relative to the specified base. In most situations * this is the same as new URL(baseUrl, relativeUrl) but @@ -1707,6 +1721,10 @@ && getOptions().isRedirectEnabled()) { for (final Map.Entry entry : webRequest.getAdditionalHeaders().entrySet()) { wrs.setAdditionalHeader(entry.getKey(), entry.getValue()); } + wrs.setFetchDestination(webRequest.getFetchDestination()); + wrs.setFetchModeOverride(webRequest.getFetchModeOverride()); + wrs.setRequestingUrl(webRequest.getRequestingUrl()); + return loadWebResponseFromWebConnection(wrs, allowedRedirects - 1); } else if (status == HttpStatus.TEMPORARY_REDIRECT_307 @@ -1832,40 +1850,8 @@ private void addDefaultHeaders(final WebRequest wrs) { wrs.setAdditionalHeader(HttpHeader.ACCEPT_LANGUAGE, getBrowserVersion().getAcceptLanguageHeader()); } - if (!wrs.isAdditionalHeader(HttpHeader.SEC_FETCH_DEST)) { - wrs.setAdditionalHeader(HttpHeader.SEC_FETCH_DEST, "document"); - } - if (!wrs.isAdditionalHeader(HttpHeader.SEC_FETCH_MODE)) { - wrs.setAdditionalHeader(HttpHeader.SEC_FETCH_MODE, "navigate"); - } - if (!wrs.isAdditionalHeader(HttpHeader.SEC_FETCH_SITE)) { - wrs.setAdditionalHeader(HttpHeader.SEC_FETCH_SITE, "same-origin"); - } - if (!wrs.isAdditionalHeader(HttpHeader.SEC_FETCH_USER)) { - wrs.setAdditionalHeader(HttpHeader.SEC_FETCH_USER, "?1"); - } - if (getBrowserVersion().hasFeature(HTTP_HEADER_PRIORITY) - && !wrs.isAdditionalHeader(HttpHeader.PRIORITY)) { - wrs.setAdditionalHeader(HttpHeader.PRIORITY, "u=0, i"); - } - - if (getBrowserVersion().hasFeature(HTTP_HEADER_CH_UA) - && !wrs.isAdditionalHeader(HttpHeader.SEC_CH_UA)) { - wrs.setAdditionalHeader(HttpHeader.SEC_CH_UA, getBrowserVersion().getSecClientHintUserAgentHeader()); - } - if (getBrowserVersion().hasFeature(HTTP_HEADER_CH_UA) - && !wrs.isAdditionalHeader(HttpHeader.SEC_CH_UA_MOBILE)) { - wrs.setAdditionalHeader(HttpHeader.SEC_CH_UA_MOBILE, "?0"); - } - if (getBrowserVersion().hasFeature(HTTP_HEADER_CH_UA) - && !wrs.isAdditionalHeader(HttpHeader.SEC_CH_UA_PLATFORM)) { - wrs.setAdditionalHeader(HttpHeader.SEC_CH_UA_PLATFORM, - getBrowserVersion().getSecClientHintUserAgentPlatformHeader()); - } - - if (!wrs.isAdditionalHeader(HttpHeader.UPGRADE_INSECURE_REQUESTS)) { - wrs.setAdditionalHeader(HttpHeader.UPGRADE_INSECURE_REQUESTS, "1"); - } + // the sec- stuff is done later in the HttpWebConnection + // this implies that stuff is not visible in the MockWebConnection } /** diff --git a/src/main/java/org/htmlunit/WebConnection.java b/src/main/java/org/htmlunit/WebConnection.java index cf721c52f6a..65731bff216 100644 --- a/src/main/java/org/htmlunit/WebConnection.java +++ b/src/main/java/org/htmlunit/WebConnection.java @@ -31,7 +31,7 @@ public interface WebConnection extends AutoCloseable { * Submits a request and retrieves a response. * @param request the request * @return the response to the request defined by the specified request - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ WebResponse getResponse(WebRequest request) throws IOException; diff --git a/src/main/java/org/htmlunit/WebRequest.java b/src/main/java/org/htmlunit/WebRequest.java index bc03cf74c64..8750b314eb3 100644 --- a/src/main/java/org/htmlunit/WebRequest.java +++ b/src/main/java/org/htmlunit/WebRequest.java @@ -67,11 +67,121 @@ public enum HttpHint { BlockCookies } + /** + * The destination of a request, as defined by the Fetch spec + * ( + * https://fetch.spec.whatwg.org/#concept-request-destination). + *

+ * This is used to compute the value of the {@code Sec-Fetch-Dest} request + * header (see + * https://www.w3.org/TR/fetch-metadata/) and also determines the default + * {@link FetchMode} to be used, unless explicitly overridden via + * {@link #setFetchModeOverride(FetchMode)}. + *

+ */ + public enum FetchDestination { + /** A top-level document, e.g. loaded by the address bar, a link, or a form submission. */ + DOCUMENT("document"), + /** A nested browsing context of type {@code "; + final String htmlResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: " + html.length() + "\r\n" + + "Content-Type: text/html\r\n" + + "Connection: close\r\n" + + "\r\n" + + html; + final String frameResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: 2\r\n" + + "Content-Type: text/html\r\n" + + "Connection: close\r\n" + + "\r\n" + + "Hi"; + + shutDownAll(); + try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, htmlResponse, frameResponse)) { + final WebDriver driver = getWebDriver(); + + driver.get("http://localhost:" + primitiveWebServer.getPort()); + + final String[] expectedHeaders = getExpectedAlertsWithHtmlReplacement(primitiveWebServer); + + final String request = primitiveWebServer.getRequests().get(1); + final String[] headers = request.split("\\r\\n"); + assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString()); + } + } + + /** + * Tests the Sec-Fetch-* headers sent for a same-origin <iframe crossorigin src> + * request - included for symmetry with {@link #imageCrossOrigin()} and + * {@link #scriptCrossOrigin()}, but note the crossorigin attribute is NOT part of the + * HTML spec for <iframe> (unlike img/script/link); real browsers should ignore it + * entirely here, so this should come out identical to {@link #iframeLoad()} - Sec-Fetch-Mode + * stays "navigate" regardless. Worth keeping mainly as a regression guard against + * accidentally wiring up a crossorigin-forces-cors rule for iframes the way it's wired + * for img/script/link. + * + * @throws Exception if the test fails + */ + @Test + @Alerts( + CHROME = {"GET /frame.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "Connection: keep-alive", + "sec-ch-ua: §§SEC_USER_AGENT§§", + "sec-ch-ua-mobile: ?0", + "sec-ch-ua-platform: \"Windows\"", + "Upgrade-Insecure-Requests: 1", + "User-Agent: §§USER_AGENT§§", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Sec-Fetch-Site: same-origin", + "Sec-Fetch-Mode: navigate", + "Sec-Fetch-Dest: iframe", + "Referer: http://localhost:§§PORT§§/", + "Accept-Encoding: gzip, deflate, br, zstd", + "Accept-Language: en-US,en;q=0.9"}, + EDGE = {"GET /frame.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "Connection: keep-alive", + "sec-ch-ua: §§SEC_USER_AGENT§§", + "sec-ch-ua-mobile: ?0", + "sec-ch-ua-platform: \"Windows\"", + "Upgrade-Insecure-Requests: 1", + "User-Agent: §§USER_AGENT§§", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Sec-Fetch-Site: same-origin", + "Sec-Fetch-Mode: navigate", + "Sec-Fetch-Dest: iframe", + "Referer: http://localhost:§§PORT§§/", + "Accept-Encoding: gzip, deflate, br, zstd", + "Accept-Language: en-US,en;q=0.9"}, + FF = {"GET /frame.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "User-Agent: §§USER_AGENT§§", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Language: en-US,en;q=0.9", + "Accept-Encoding: gzip, deflate, br, zstd", + "Connection: keep-alive", + "Referer: http://localhost:§§PORT§§/", + "Upgrade-Insecure-Requests: 1", + "Sec-Fetch-Dest: iframe", + "Sec-Fetch-Mode: navigate", + "Sec-Fetch-Site: same-origin", + "Priority: u=4"}, + FF_ESR = {"GET /frame.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "User-Agent: §§USER_AGENT§§", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Language: en-US,en;q=0.5", + "Accept-Encoding: gzip, deflate, br, zstd", + "Connection: keep-alive", + "Referer: http://localhost:§§PORT§§/", + "Upgrade-Insecure-Requests: 1", + "Sec-Fetch-Dest: iframe", + "Sec-Fetch-Mode: navigate", + "Sec-Fetch-Site: same-origin", + "Priority: u=4"}) + @HtmlUnitNYI( + CHROME = {"GET /frame.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "Connection: keep-alive", + "sec-ch-ua: §§SEC_USER_AGENT§§", + "sec-ch-ua-mobile: ?0", + "sec-ch-ua-platform: \"Windows\"", + "Upgrade-Insecure-Requests: 1", + "User-Agent: §§USER_AGENT§§", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Sec-Fetch-Site: same-origin", + "Sec-Fetch-Mode: navigate", + "Sec-Fetch-Dest: iframe", + "Referer: http://localhost:§§PORT§§/", + "Accept-Encoding: gzip, deflate, br", + "Accept-Language: en-US,en;q=0.9"}, + EDGE = {"GET /frame.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "Connection: keep-alive", + "sec-ch-ua: §§SEC_USER_AGENT§§", + "sec-ch-ua-mobile: ?0", + "sec-ch-ua-platform: \"Windows\"", + "Upgrade-Insecure-Requests: 1", + "User-Agent: §§USER_AGENT§§", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Sec-Fetch-Site: same-origin", + "Sec-Fetch-Mode: navigate", + "Sec-Fetch-Dest: iframe", + "Referer: http://localhost:§§PORT§§/", + "Accept-Encoding: gzip, deflate, br", + "Accept-Language: en-US,en;q=0.9"}, + FF = {"GET /frame.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "User-Agent: §§USER_AGENT§§", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Language: en-US,en;q=0.9", + "Accept-Encoding: gzip, deflate, br", + "Connection: keep-alive", + "Referer: http://localhost:§§PORT§§/", + "Upgrade-Insecure-Requests: 1", + "Sec-Fetch-Dest: iframe", + "Sec-Fetch-Mode: navigate", + "Sec-Fetch-Site: same-origin", + "Priority: u=0, i"}, + FF_ESR = {"GET /frame.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "User-Agent: §§USER_AGENT§§", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Language: en-US,en;q=0.5", + "Accept-Encoding: gzip, deflate, br", + "Connection: keep-alive", + "Referer: http://localhost:§§PORT§§/", + "Upgrade-Insecure-Requests: 1", + "Sec-Fetch-Dest: iframe", + "Sec-Fetch-Mode: navigate", + "Sec-Fetch-Site: same-origin", + "Priority: u=0, i"}) + public void iframeCrossOriginAttributeIsIgnored() throws Exception { + final String html = DOCTYPE_HTML + + ""; + final String htmlResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: " + html.length() + "\r\n" + + "Content-Type: text/html\r\n" + + "Connection: close\r\n" + + "\r\n" + + html; + final String frameResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: 2\r\n" + + "Content-Type: text/html\r\n" + + "Connection: close\r\n" + + "\r\n" + + "Hi"; + + shutDownAll(); + try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, htmlResponse, frameResponse)) { + final WebDriver driver = getWebDriver(); + + driver.get("http://localhost:" + primitiveWebServer.getPort()); + + final String[] expectedHeaders = getExpectedAlertsWithHtmlReplacement(primitiveWebServer); + + final String request = primitiveWebServer.getRequests().get(1); + final String[] headers = request.split("\\r\\n"); + assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString()); + } + } + + + /** + * Tests the Sec-Fetch-* headers sent for a same-origin <iframe crossorigin src> + * request - included for symmetry with {@link #imageCrossOrigin()} and + * {@link #scriptCrossOrigin()}, but note the crossorigin attribute is NOT part of the + * HTML spec for <iframe> (unlike img/script/link); real browsers should ignore it + * entirely here, so this should come out identical to {@link #iframeLoad()} - Sec-Fetch-Mode + * stays "navigate" regardless. Worth keeping mainly as a regression guard against + * accidentally wiring up a crossorigin-forces-cors rule for iframes the way it's wired + * for img/script/link. + * + * @throws Exception if the test fails + */ + @Test + @Alerts( + CHROME = {"POST /beacon.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "Connection: keep-alive", + "Content-Length: 8", + "sec-ch-ua-platform: \"Windows\"", + "User-Agent: §§USER_AGENT§§", + "sec-ch-ua: §§SEC_USER_AGENT§§", + "Content-Type: text/plain;charset=UTF-8", + "sec-ch-ua-mobile: ?0", + "Accept: */*", + "Origin: http://localhost:§§PORT§§", + "Sec-Fetch-Site: same-origin", + "Sec-Fetch-Mode: no-cors", + "Sec-Fetch-Dest: empty", + "Referer: http://localhost:§§PORT§§/", + "Accept-Encoding: gzip, deflate, br, zstd", + "Accept-Language: en-US,en;q=0.9", + "", + "HtmlUnit"}, + EDGE = {"POST /beacon.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "Connection: keep-alive", + "Content-Length: 8", + "sec-ch-ua-platform: \"Windows\"", + "User-Agent: §§USER_AGENT§§", + "sec-ch-ua: §§SEC_USER_AGENT§§", + "Content-Type: text/plain;charset=UTF-8", + "sec-ch-ua-mobile: ?0", + "Accept: */*", + "Origin: http://localhost:§§PORT§§", + "Sec-Fetch-Site: same-origin", + "Sec-Fetch-Mode: no-cors", + "Sec-Fetch-Dest: empty", + "Referer: http://localhost:§§PORT§§/", + "Accept-Encoding: gzip, deflate, br, zstd", + "Accept-Language: en-US,en;q=0.9", + "", + "HtmlUnit"}, + FF = {"POST /beacon.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "User-Agent: §§USER_AGENT§§", + "Accept: */*", + "Accept-Language: en-US,en;q=0.9", + "Accept-Encoding: gzip, deflate, br, zstd", + "Content-Type: text/plain;charset=UTF-8", + "Content-Length: 8", + "Origin: http://localhost:§§PORT§§", + "Connection: keep-alive", + "Referer: http://localhost:§§PORT§§/", + "Sec-Fetch-Dest: empty", + "Sec-Fetch-Mode: no-cors", + "Sec-Fetch-Site: same-origin", + "Priority: u=6", + "", + "HtmlUnit"}, + FF_ESR = {"POST /beacon.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "User-Agent: §§USER_AGENT§§", + "Accept: */*", + "Accept-Language: en-US,en;q=0.5", + "Accept-Encoding: gzip, deflate, br, zstd", + "Content-Type: text/plain;charset=UTF-8", + "Content-Length: 8", + "Origin: http://localhost:§§PORT§§", + "Connection: keep-alive", + "Referer: http://localhost:§§PORT§§/", + "Sec-Fetch-Dest: empty", + "Sec-Fetch-Mode: no-cors", + "Sec-Fetch-Site: same-origin", + "Priority: u=6", + "", + "HtmlUnit"}) + @HtmlUnitNYI( + CHROME = {"POST /beacon.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "Connection: keep-alive", + "sec-ch-ua: §§SEC_USER_AGENT§§", + "sec-ch-ua-mobile: ?0", + "sec-ch-ua-platform: \"Windows\"", + "User-Agent: §§USER_AGENT§§", + "Accept: */*", + "Sec-Fetch-Site: same-origin", + "Sec-Fetch-Mode: no-cors", + "Sec-Fetch-Dest: empty", + "Referer: http://localhost:§§PORT§§/", + "Accept-Encoding: gzip, deflate", + "Accept-Language: en-US,en;q=0.9", + "Origin: http://localhost:§§PORT§§", + "Content-Length: 8", + "Content-Type: text/plain; charset=UTF-8", + "", + "HtmlUnit"}, + EDGE = {"POST /beacon.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "Connection: keep-alive", + "sec-ch-ua: §§SEC_USER_AGENT§§", + "sec-ch-ua-mobile: ?0", + "sec-ch-ua-platform: \"Windows\"", + "User-Agent: §§USER_AGENT§§", + "Accept: */*", + "Sec-Fetch-Site: same-origin", + "Sec-Fetch-Mode: no-cors", + "Sec-Fetch-Dest: empty", + "Referer: http://localhost:§§PORT§§/", + "Accept-Encoding: gzip, deflate", + "Accept-Language: en-US,en;q=0.9", + "Origin: http://localhost:§§PORT§§", + "Content-Length: 8", + "Content-Type: text/plain; charset=UTF-8", + "", + "HtmlUnit"}, + FF = {"POST /beacon.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "User-Agent: §§USER_AGENT§§", + "Accept: */*", + "Accept-Language: en-US,en;q=0.9", + "Accept-Encoding: gzip, deflate", + "Connection: keep-alive", + "Referer: http://localhost:§§PORT§§/", + "Sec-Fetch-Dest: empty", + "Sec-Fetch-Mode: no-cors", + "Sec-Fetch-Site: same-origin", + "Priority: u=0, i", + "Origin: http://localhost:§§PORT§§", + "Content-Length: 8", + "Content-Type: text/plain; charset=UTF-8", + "", + "HtmlUnit"}, + FF_ESR = {"POST /beacon.html HTTP/1.1", + "Host: localhost:§§PORT§§", + "User-Agent: §§USER_AGENT§§", + "Accept: */*", + "Accept-Language: en-US,en;q=0.5", + "Accept-Encoding: gzip, deflate", + "Connection: keep-alive", + "Referer: http://localhost:§§PORT§§/", + "Sec-Fetch-Dest: empty", + "Sec-Fetch-Mode: no-cors", + "Sec-Fetch-Site: same-origin", + "Priority: u=0, i", + "Origin: http://localhost:§§PORT§§", + "Content-Length: 8", + "Content-Type: text/plain; charset=UTF-8", + "", + "HtmlUnit"}) + public void sendBeacon() throws Exception { + String html = DOCTYPE_HTML + + "" + + "\n" + + ""; + final String htmlResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: " + html.length() + "\r\n" + + "Content-Type: text/html\r\n" + + "Connection: close\r\n" + + "\r\n" + + html; + + shutDownAll(); + try (PrimitiveWebServer primitiveWebServer = new PrimitiveWebServer(null, htmlResponse, htmlResponse)) { + final WebDriver driver = getWebDriver(); + + driver.get("http://localhost:" + primitiveWebServer.getPort()); + if (useRealBrowser()) { + Thread.sleep(DEFAULT_WAIT_TIME.toMillis() / 100); + } + + final String[] expectedHeaders = getExpectedAlertsWithHtmlReplacement(primitiveWebServer); + + final String request = primitiveWebServer.getRequests().get(1); + final String[] headers = request.split("\\r\\n"); + assertEquals(Arrays.asList(expectedHeaders).toString(), Arrays.asList(headers).toString()); + } + } + + private String[] getExpectedAlertsWithHtmlReplacement(PrimitiveWebServer primitiveWebServer) { + final String[] expectedHeaders = getExpectedAlerts(); + for (int i = 0; i < expectedHeaders.length; i++) { + expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort()); + expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§", + getBrowserVersion().getUserAgent()); + expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§", + getBrowserVersion().getSecClientHintUserAgentHeader()); + expectedHeaders[i] = expectedHeaders[i].replaceAll("§§ACCEPT§§", + getBrowserVersion().getHtmlAcceptHeader()); + } + return expectedHeaders; + } + + private String[] getExpectedAlertsWithScriptReplacement(PrimitiveWebServer primitiveWebServer) { + final String[] expectedHeaders = getExpectedAlerts(); + for (int i = 0; i < expectedHeaders.length; i++) { + expectedHeaders[i] = expectedHeaders[i].replaceAll("§§PORT§§", "" + primitiveWebServer.getPort()); + expectedHeaders[i] = expectedHeaders[i].replaceAll("§§USER_AGENT§§", + getBrowserVersion().getUserAgent()); + expectedHeaders[i] = expectedHeaders[i].replaceAll("§§SEC_USER_AGENT§§", + getBrowserVersion().getSecClientHintUserAgentHeader()); + expectedHeaders[i] = expectedHeaders[i].replaceAll("§§ACCEPT§§", + getBrowserVersion().getScriptAcceptHeader()); + } + return expectedHeaders; + } +} \ No newline at end of file diff --git a/src/test/java/org/htmlunit/PageReloadTest.java b/src/test/java/org/htmlunit/PageReloadTest.java index ab5442dee13..a176f07aae6 100644 --- a/src/test/java/org/htmlunit/PageReloadTest.java +++ b/src/test/java/org/htmlunit/PageReloadTest.java @@ -38,7 +38,7 @@ public class PageReloadTest extends WebDriverTestCase { private static final String RELOAD_URL_ANCHOR = RELOAD_URL + ANCHOR; /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(PATHNAME) @@ -47,7 +47,7 @@ public void link_url_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -56,7 +56,7 @@ public void link_url_emptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_url_hash() throws Exception { @@ -64,7 +64,7 @@ public void link_url_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_url_differentHash() throws Exception { @@ -72,7 +72,7 @@ public void link_url_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_url_url() throws Exception { @@ -80,7 +80,7 @@ public void link_url_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_url_urlHash() throws Exception { @@ -88,7 +88,7 @@ public void link_url_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_url_differentUrl() throws Exception { @@ -96,7 +96,7 @@ public void link_url_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -105,7 +105,7 @@ public void link_url_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_url_differentUrlHash() throws Exception { @@ -113,7 +113,7 @@ public void link_url_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_url_differentUrlDifferentHash() throws Exception { @@ -121,7 +121,7 @@ public void link_url_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(PATHNAME) @@ -130,7 +130,7 @@ public void link_urlHash_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_urlHash_hash() throws Exception { @@ -138,7 +138,7 @@ public void link_urlHash_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_urlHash_differentHash() throws Exception { @@ -146,7 +146,7 @@ public void link_urlHash_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_urlHash_url() throws Exception { @@ -154,7 +154,7 @@ public void link_urlHash_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_urlHash_urlHash() throws Exception { @@ -162,7 +162,7 @@ public void link_urlHash_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_urlHash_differentUrl() throws Exception { @@ -170,7 +170,7 @@ public void link_urlHash_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -179,7 +179,7 @@ public void link_urlHash_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_urlHash_differentUrlHash() throws Exception { @@ -187,7 +187,7 @@ public void link_urlHash_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void link_urlHash_differentUrlDifferentHash() throws Exception { @@ -195,7 +195,7 @@ public void link_urlHash_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(PATHNAME) @@ -204,7 +204,7 @@ public void javascript_url_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -213,7 +213,7 @@ public void javascript_url_emptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_url_hash() throws Exception { @@ -221,7 +221,7 @@ public void javascript_url_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_url_differentHash() throws Exception { @@ -229,7 +229,7 @@ public void javascript_url_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_url_url() throws Exception { @@ -237,7 +237,7 @@ public void javascript_url_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_url_urlHash() throws Exception { @@ -245,7 +245,7 @@ public void javascript_url_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_url_differentUrl() throws Exception { @@ -253,7 +253,7 @@ public void javascript_url_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -262,7 +262,7 @@ public void javascript_url_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_url_differentUrlHash() throws Exception { @@ -270,7 +270,7 @@ public void javascript_url_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_url_differentUrlDifferentHash() throws Exception { @@ -278,7 +278,7 @@ public void javascript_url_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(PATHNAME) @@ -287,7 +287,7 @@ public void javascript_urlHash_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_urlHash_hash() throws Exception { @@ -295,7 +295,7 @@ public void javascript_urlHash_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_urlHash_differentHash() throws Exception { @@ -303,7 +303,7 @@ public void javascript_urlHash_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_urlHash_url() throws Exception { @@ -311,7 +311,7 @@ public void javascript_urlHash_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_urlHash_urlHash() throws Exception { @@ -319,7 +319,7 @@ public void javascript_urlHash_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_urlHash_differentUrl() throws Exception { @@ -327,7 +327,7 @@ public void javascript_urlHash_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -336,7 +336,7 @@ public void javascript_urlHash_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void javascript_urlHash_differentUrlHash() throws Exception { @@ -344,7 +344,7 @@ public void javascript_urlHash_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGet_url_emptyUrl() throws Exception { @@ -352,7 +352,7 @@ public void submitGet_url_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGetV_url_emptyUrl() throws Exception { @@ -360,7 +360,7 @@ public void submitGetV_url_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("1") @@ -369,7 +369,7 @@ public void submitGet_url_emptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGetV_url_emptyHash() throws Exception { @@ -377,7 +377,7 @@ public void submitGetV_url_emptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR}) @@ -387,7 +387,7 @@ public void submitGet_url_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -397,7 +397,7 @@ public void submitGetV_url_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR2 }) @@ -407,7 +407,7 @@ public void submitGet_url_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -416,7 +416,7 @@ public void submitGetV_url_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGet_url_url() throws Exception { @@ -424,7 +424,7 @@ public void submitGet_url_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGetV_url_url() throws Exception { @@ -432,7 +432,7 @@ public void submitGetV_url_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR}) @@ -442,7 +442,7 @@ public void submitGet_url_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -451,7 +451,7 @@ public void submitGetV_url_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGet_url_differentUrl() throws Exception { @@ -459,7 +459,7 @@ public void submitGet_url_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGetV_url_differentUrl() throws Exception { @@ -467,7 +467,7 @@ public void submitGetV_url_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGet_url_differentUrlEmptyHash() throws Exception { @@ -475,7 +475,7 @@ public void submitGet_url_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -485,7 +485,7 @@ public void submitGet_url_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGetV_url_differentUrlEmptyHash() throws Exception { @@ -493,7 +493,7 @@ public void submitGetV_url_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -503,7 +503,7 @@ public void submitGetV_url_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -512,7 +512,7 @@ public void submitGet_url_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -521,7 +521,7 @@ public void submitGetV_url_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR}) @@ -532,7 +532,7 @@ public void submitGet_urlHash_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -542,7 +542,7 @@ public void submitGetV_urlHash_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR}) @@ -552,7 +552,7 @@ public void submitGet_urlHash_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -561,7 +561,7 @@ public void submitGetV_urlHash_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR2 }) @@ -571,7 +571,7 @@ public void submitGet_urlHash_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -581,7 +581,7 @@ public void submitGetV_urlHash_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGet_urlHash_url() throws Exception { @@ -589,7 +589,7 @@ public void submitGet_urlHash_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGetV_urlHash_url() throws Exception { @@ -597,7 +597,7 @@ public void submitGetV_urlHash_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR}) @@ -607,7 +607,7 @@ public void submitGet_urlHash_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -617,7 +617,7 @@ public void submitGetV_urlHash_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGet_urlHash_differentUrl() throws Exception { @@ -625,7 +625,7 @@ public void submitGet_urlHash_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGetV_urlHash_differentUrl() throws Exception { @@ -633,7 +633,7 @@ public void submitGetV_urlHash_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGet_urlHash_differentUrlEmptyHash() throws Exception { @@ -641,7 +641,7 @@ public void submitGet_urlHash_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -650,7 +650,7 @@ public void submitGet_urlHash_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitGetV_urlHash_differentUrlEmptyHash() throws Exception { @@ -658,7 +658,7 @@ public void submitGetV_urlHash_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -667,7 +667,7 @@ public void submitGetV_urlHash_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -677,7 +677,7 @@ public void submitGet_urlHash_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -687,7 +687,7 @@ public void submitGetV_urlHash_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_url_emptyUrl() throws Exception { @@ -695,7 +695,7 @@ public void submitPost_url_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_url_emptyUrl() throws Exception { @@ -703,7 +703,7 @@ public void submitPostV_url_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -712,7 +712,7 @@ public void submitPost_url_emptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -721,7 +721,7 @@ public void submitPostV_url_emptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_url_hash() throws Exception { @@ -729,7 +729,7 @@ public void submitPost_url_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_url_hash() throws Exception { @@ -737,7 +737,7 @@ public void submitPostV_url_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_url_differentHash() throws Exception { @@ -745,7 +745,7 @@ public void submitPost_url_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_url_differentHash() throws Exception { @@ -753,7 +753,7 @@ public void submitPostV_url_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_url_url() throws Exception { @@ -761,7 +761,7 @@ public void submitPost_url_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_url_url() throws Exception { @@ -769,7 +769,7 @@ public void submitPostV_url_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_url_urlHash() throws Exception { @@ -777,7 +777,7 @@ public void submitPost_url_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_url_urlHash() throws Exception { @@ -785,7 +785,7 @@ public void submitPostV_url_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_url_differentUrl() throws Exception { @@ -793,7 +793,7 @@ public void submitPost_url_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_url_differentUrl() throws Exception { @@ -801,7 +801,7 @@ public void submitPostV_url_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -811,7 +811,7 @@ public void submitPost_url_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_url_differentUrlHash() throws Exception { @@ -819,7 +819,7 @@ public void submitPost_url_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -829,7 +829,7 @@ public void submitPostV_url_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_url_differentUrlHash() throws Exception { @@ -837,7 +837,7 @@ public void submitPostV_url_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_url_differentUrlDifferentHash() throws Exception { @@ -845,7 +845,7 @@ public void submitPost_url_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_url_differentUrlDifferentHash() throws Exception { @@ -853,7 +853,7 @@ public void submitPostV_url_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -863,7 +863,7 @@ public void submitPost_urlHash_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -873,7 +873,7 @@ public void submitPostV_urlHash_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_urlHash_hash() throws Exception { @@ -881,7 +881,7 @@ public void submitPost_urlHash_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_urlHash_hash() throws Exception { @@ -889,7 +889,7 @@ public void submitPostV_urlHash_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_urlHash_differentHash() throws Exception { @@ -897,7 +897,7 @@ public void submitPost_urlHash_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_urlHash_differentHash() throws Exception { @@ -905,7 +905,7 @@ public void submitPostV_urlHash_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_urlHash_url() throws Exception { @@ -913,7 +913,7 @@ public void submitPost_urlHash_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_urlHash_url() throws Exception { @@ -921,7 +921,7 @@ public void submitPostV_urlHash_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_urlHash_urlHash() throws Exception { @@ -929,7 +929,7 @@ public void submitPost_urlHash_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_urlHash_urlHash() throws Exception { @@ -937,7 +937,7 @@ public void submitPostV_urlHash_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_urlHash_differentUrl() throws Exception { @@ -945,7 +945,7 @@ public void submitPost_urlHash_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_urlHash_differentUrl() throws Exception { @@ -953,7 +953,7 @@ public void submitPostV_urlHash_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -963,7 +963,7 @@ public void submitPost_urlHash_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_urlHash_differentUrlHash() throws Exception { @@ -971,7 +971,7 @@ public void submitPost_urlHash_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -981,7 +981,7 @@ public void submitPostV_urlHash_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_urlHash_differentUrlHash() throws Exception { @@ -989,7 +989,7 @@ public void submitPostV_urlHash_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPost_urlHash_differentUrlDifferentHash() throws Exception { @@ -997,7 +997,7 @@ public void submitPost_urlHash_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void submitPostV_urlHash_differentUrlDifferentHash() throws Exception { @@ -1005,7 +1005,7 @@ public void submitPostV_urlHash_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGet_url_emptyUrl() throws Exception { @@ -1013,7 +1013,7 @@ public void jsSubmitGet_url_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGetV_url_emptyUrl() throws Exception { @@ -1021,7 +1021,7 @@ public void jsSubmitGetV_url_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("1") @@ -1030,7 +1030,7 @@ public void jsSubmitGet_url_emptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGetV_url_emptyHash() throws Exception { @@ -1038,7 +1038,7 @@ public void jsSubmitGetV_url_emptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR}) @@ -1048,7 +1048,7 @@ public void jsSubmitGet_url_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1057,7 +1057,7 @@ public void jsSubmitGetV_url_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR2 }) @@ -1067,7 +1067,7 @@ public void jsSubmitGet_url_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -1076,7 +1076,7 @@ public void jsSubmitGetV_url_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGet_url_url() throws Exception { @@ -1084,7 +1084,7 @@ public void jsSubmitGet_url_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGetV_url_url() throws Exception { @@ -1092,7 +1092,7 @@ public void jsSubmitGetV_url_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR}) @@ -1102,7 +1102,7 @@ public void jsSubmitGet_url_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1111,7 +1111,7 @@ public void jsSubmitGetV_url_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGet_url_differentUrl() throws Exception { @@ -1119,7 +1119,7 @@ public void jsSubmitGet_url_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGetV_url_differentUrl() throws Exception { @@ -1127,7 +1127,7 @@ public void jsSubmitGetV_url_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGet_url_differentUrlEmptyHash() throws Exception { @@ -1135,7 +1135,7 @@ public void jsSubmitGet_url_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1144,7 +1144,7 @@ public void jsSubmitGet_url_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGetV_url_differentUrlEmptyHash() throws Exception { @@ -1152,7 +1152,7 @@ public void jsSubmitGetV_url_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1161,7 +1161,7 @@ public void jsSubmitGetV_url_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -1170,7 +1170,7 @@ public void jsSubmitGet_url_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -1179,7 +1179,7 @@ public void jsSubmitGetV_url_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR}) @@ -1189,7 +1189,7 @@ public void jsSubmitGet_urlHash_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1199,7 +1199,7 @@ public void jsSubmitGetV_urlHash_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR}) @@ -1209,7 +1209,7 @@ public void jsSubmitGet_urlHash_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1218,7 +1218,7 @@ public void jsSubmitGetV_urlHash_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR2 }) @@ -1228,7 +1228,7 @@ public void jsSubmitGet_urlHash_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -1238,7 +1238,7 @@ public void jsSubmitGetV_urlHash_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGet_urlHash_url() throws Exception { @@ -1246,7 +1246,7 @@ public void jsSubmitGet_urlHash_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGetV_urlHash_url() throws Exception { @@ -1254,7 +1254,7 @@ public void jsSubmitGetV_urlHash_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", ANCHOR}) @@ -1264,7 +1264,7 @@ public void jsSubmitGet_urlHash_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1273,7 +1273,7 @@ public void jsSubmitGetV_urlHash_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGet_urlHash_differentUrl() throws Exception { @@ -1281,7 +1281,7 @@ public void jsSubmitGet_urlHash_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGetV_urlHash_differentUrl() throws Exception { @@ -1289,7 +1289,7 @@ public void jsSubmitGetV_urlHash_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGet_urlHash_differentUrlEmptyHash() throws Exception { @@ -1297,7 +1297,7 @@ public void jsSubmitGet_urlHash_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1306,7 +1306,7 @@ public void jsSubmitGet_urlHash_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitGetV_urlHash_differentUrlEmptyHash() throws Exception { @@ -1315,7 +1315,7 @@ public void jsSubmitGetV_urlHash_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1324,7 +1324,7 @@ public void jsSubmitGetV_urlHash_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -1334,7 +1334,7 @@ public void jsSubmitGet_urlHash_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR2) @@ -1344,7 +1344,7 @@ public void jsSubmitGetV_urlHash_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_url_emptyUrl() throws Exception { @@ -1352,7 +1352,7 @@ public void jsSubmitPost_url_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_url_emptyUrl() throws Exception { @@ -1360,7 +1360,7 @@ public void jsSubmitPostV_url_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -1369,7 +1369,7 @@ public void jsSubmitPost_url_EmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -1378,7 +1378,7 @@ public void jsSubmitPostV_url_EmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_url_hash() throws Exception { @@ -1386,7 +1386,7 @@ public void jsSubmitPost_url_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_url_hash() throws Exception { @@ -1394,7 +1394,7 @@ public void jsSubmitPostV_url_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_url_differentHash() throws Exception { @@ -1402,7 +1402,7 @@ public void jsSubmitPost_url_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_url_differentHash() throws Exception { @@ -1410,7 +1410,7 @@ public void jsSubmitPostV_url_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_url_url() throws Exception { @@ -1418,7 +1418,7 @@ public void jsSubmitPost_url_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_url_url() throws Exception { @@ -1426,7 +1426,7 @@ public void jsSubmitPostV_url_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_url_urlHash() throws Exception { @@ -1434,7 +1434,7 @@ public void jsSubmitPost_url_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_url_urlHash() throws Exception { @@ -1442,7 +1442,7 @@ public void jsSubmitPostV_url_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_url_differentUrl() throws Exception { @@ -1450,7 +1450,7 @@ public void jsSubmitPost_url_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_url_differentUrl() throws Exception { @@ -1458,7 +1458,7 @@ public void jsSubmitPostV_url_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -1468,7 +1468,7 @@ public void jsSubmitPost_url_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_url_differentUrlHash() throws Exception { @@ -1476,7 +1476,7 @@ public void jsSubmitPost_url_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -1486,7 +1486,7 @@ public void jsSubmitPostV_url_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_url_differentUrlHash() throws Exception { @@ -1494,7 +1494,7 @@ public void jsSubmitPostV_url_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_url_differentUrlDifferentHash() throws Exception { @@ -1502,7 +1502,7 @@ public void jsSubmitPost_url_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_url_differentUrlDifferentHash() throws Exception { @@ -1510,7 +1510,7 @@ public void jsSubmitPostV_url_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1520,7 +1520,7 @@ public void jsSubmitPost_urlHash_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts(ANCHOR) @@ -1530,7 +1530,7 @@ public void jsSubmitPostV_urlHash_emptyUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_urlHash_hash() throws Exception { @@ -1538,7 +1538,7 @@ public void jsSubmitPost_urlHash_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_urlHash_hash() throws Exception { @@ -1546,7 +1546,7 @@ public void jsSubmitPostV_urlHash_hash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_urlHash_differentHash() throws Exception { @@ -1554,7 +1554,7 @@ public void jsSubmitPost_urlHash_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_urlHash_differentHash() throws Exception { @@ -1562,7 +1562,7 @@ public void jsSubmitPostV_urlHash_differentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_urlHash_url() throws Exception { @@ -1570,7 +1570,7 @@ public void jsSubmitPost_urlHash_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_urlHash_url() throws Exception { @@ -1578,7 +1578,7 @@ public void jsSubmitPostV_urlHash_url() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_urlHash_urlHash() throws Exception { @@ -1586,7 +1586,7 @@ public void jsSubmitPost_urlHash_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_urlHash_urlHash() throws Exception { @@ -1594,7 +1594,7 @@ public void jsSubmitPostV_urlHash_urlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_urlHash_differentUrl() throws Exception { @@ -1602,7 +1602,7 @@ public void jsSubmitPost_urlHash_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_urlHash_differentUrl() throws Exception { @@ -1610,7 +1610,7 @@ public void jsSubmitPostV_urlHash_differentUrl() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -1620,7 +1620,7 @@ public void jsSubmitPost_urlHash_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_urlHash_differentUrlHash() throws Exception { @@ -1628,7 +1628,7 @@ public void jsSubmitPost_urlHash_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("") @@ -1638,7 +1638,7 @@ public void jsSubmitPostV_urlHash_differentUrlEmptyHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_urlHash_differentUrlHash() throws Exception { @@ -1646,7 +1646,7 @@ public void jsSubmitPostV_urlHash_differentUrlHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPost_urlHash_differentUrlDifferentHash() throws Exception { @@ -1654,7 +1654,7 @@ public void jsSubmitPost_urlHash_differentUrlDifferentHash() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void jsSubmitPostV_urlHash_differentUrlDifferentHash() throws Exception { diff --git a/src/test/java/org/htmlunit/TestCaseTest.java b/src/test/java/org/htmlunit/TestCaseTest.java index c431b86efb4..6cb4ac7204e 100644 --- a/src/test/java/org/htmlunit/TestCaseTest.java +++ b/src/test/java/org/htmlunit/TestCaseTest.java @@ -60,7 +60,8 @@ private void generateTestForHtmlElements(final File dir) throws Exception { if (file.isDirectory() && !".git".equals(file.getName())) { generateTestForHtmlElements(file); } - else if (file.getName().endsWith(".java")) { + else if (file.getName().endsWith(".java") + && !file.getName().endsWith("HtmlTagSupportTest.java")) { final List lines = FileUtils.readLines(file, ISO_8859_1); for (final String line : lines) { if (line.contains("(\"xmp\")")) { diff --git a/src/test/java/org/htmlunit/WebClientTest.java b/src/test/java/org/htmlunit/WebClientTest.java index 1dfd0f1b0e0..92ae189b2f4 100644 --- a/src/test/java/org/htmlunit/WebClientTest.java +++ b/src/test/java/org/htmlunit/WebClientTest.java @@ -2509,7 +2509,7 @@ public void reset() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void loginFlowClickSubmitRedirect() throws Exception { diff --git a/src/test/java/org/htmlunit/archunit/Architecture2Test.java b/src/test/java/org/htmlunit/archunit/Architecture2Test.java index f53361dbd4a..07173bacb2d 100644 --- a/src/test/java/org/htmlunit/archunit/Architecture2Test.java +++ b/src/test/java/org/htmlunit/archunit/Architecture2Test.java @@ -172,6 +172,8 @@ else if (oneTests.isEmpty()) { .and().doNotHaveFullyQualifiedName("org.htmlunit.general.huge.ElementClosesElementTest") .and().doNotHaveFullyQualifiedName("org.htmlunit.general.huge.ElementClosesElement2Test") + + .and().doNotHaveFullyQualifiedName("org.htmlunit.html.HtmlAreaTest") .should().callMethod(BrowserVersion.class, "isFirefox"); /** diff --git a/src/test/java/org/htmlunit/archunit/ArchitectureTest.java b/src/test/java/org/htmlunit/archunit/ArchitectureTest.java index 7df8ddd0efb..c72ec790d9b 100644 --- a/src/test/java/org/htmlunit/archunit/ArchitectureTest.java +++ b/src/test/java/org/htmlunit/archunit/ArchitectureTest.java @@ -543,6 +543,7 @@ public void check(final JavaMethod method, final ConditionEvents events) { public static final ArchRule androidImageio = noClasses() .that() .doNotHaveFullyQualifiedName("org.htmlunit.platform.image.ImageIOImageData") + .and().doNotHaveFullyQualifiedName("org.htmlunit.platform.image.ImageIOImageData$ImageIOImageDataCleaningAction") .and().doNotHaveFullyQualifiedName("org.htmlunit.platform.canvas.rendering.AwtRenderingBackend") .and().doNotHaveFullyQualifiedName("org.htmlunit.platform.canvas.rendering.AwtRenderingBackend") .and().resideOutsideOfPackage("org.htmlunit.jetty..") diff --git a/src/test/java/org/htmlunit/doc/InputTests.java b/src/test/java/org/htmlunit/doc/InputTests.java new file mode 100644 index 00000000000..dfad34bec86 --- /dev/null +++ b/src/test/java/org/htmlunit/doc/InputTests.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2002-2026 Gargoyle Software Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.htmlunit.doc; + +import org.htmlunit.WebClient; +import org.htmlunit.html.HtmlPage; +import org.htmlunit.html.HtmlTextInput; +import org.junit.jupiter.api.Test; + +/** + * Tests for code from the documentation. + * + * @author Ronald Brill + */ +public class InputTests { + + /** + * @throws Exception if the test fails + */ + @Test + public void value() throws Exception { + try (WebClient webClient = new WebClient()) { + final HtmlPage page = webClient.getPage("https://www.wetator.org/testform/"); + final HtmlTextInput input = page.getHtmlElementById("project"); + + // before any edit, all three agree + System.out.println(input.getValueAttribute()); // "initial" + System.out.println(input.getRawValue()); // "initial" + System.out.println(input.getValue()); // "initial" + + input.type("my fancy HtmlUnit project"); + + // the attribute never moved -- it is still the DEFAULT value + System.out.println(input.getValueAttribute()); // "initial" + // but the live value has + System.out.println(input.getRawValue()); // "edited" + System.out.println(input.getValue()); // "edited" + } + } +} diff --git a/src/test/java/org/htmlunit/general/ElementOwnPropertiesTest.java b/src/test/java/org/htmlunit/general/ElementOwnPropertiesTest.java index 0ad75e7a288..3e382e28ee1 100644 --- a/src/test/java/org/htmlunit/general/ElementOwnPropertiesTest.java +++ b/src/test/java/org/htmlunit/general/ElementOwnPropertiesTest.java @@ -1892,9 +1892,9 @@ public void applet() throws Exception { + "search[GSCE],shape[GSCE],target[GSCE],toString()," + "username[GSCE]", FF = "alt[GSCE],constructor(),coords[GSCE],download[GSCE],hash[GSCE],host[GSCE],hostname[GSCE]," - + "href[GSCE],noHref[GSCE],origin[GCE],password[GSCE],pathname[GSCE],ping[GSCE],port[GSCE]," - + "protocol[GSCE],referrerPolicy[GSCE],rel[GSCE],relList[GSCE],search[GSCE],shape[GSCE]," - + "target[GSCE],toString()," + + "href[GSCE],hreflang[GSCE],noHref[GSCE],origin[GCE],password[GSCE],pathname[GSCE],ping[GSCE]," + + "port[GSCE],protocol[GSCE],referrerPolicy[GSCE],rel[GSCE],relList[GSCE],search[GSCE],shape[GSCE]," + + "target[GSCE],toString(),type[GSCE]," + "username[GSCE]", FF_ESR = "alt[GSCE],constructor(),coords[GSCE],download[GSCE],hash[GSCE],host[GSCE],hostname[GSCE]," + "href[GSCE],noHref[GSCE],origin[GCE],password[GSCE],pathname[GSCE],ping[GSCE],port[GSCE]," @@ -1908,10 +1908,10 @@ public void applet() throws Exception { EDGE = "alt[GSCE],constructor(),coords[GSCE],hash[GSCE],host[GSCE],hostname[GSCE],href[GSCE]," + "origin[GCE],password[GSCE],pathname[GSCE],port[GSCE],protocol[GSCE],rel[GSCE],relList[GCE]," + "search[GSCE],username[GSCE]", - FF_ESR = "alt[GSCE],constructor(),coords[GSCE],hash[GSCE],host[GSCE],hostname[GSCE],href[GSCE]," - + "origin[GCE],password[GSCE],pathname[GSCE],port[GSCE],protocol[GSCE],rel[GSCE],relList[GCE]," - + "search[GSCE],username[GSCE]", FF = "alt[GSCE],constructor(),coords[GSCE],hash[GSCE],host[GSCE],hostname[GSCE],href[GSCE]," + + "origin[GCE],password[GSCE],pathname[GSCE],port[GSCE],protocol[GSCE],rel[GSCE],relList[GCE]," + + "search[GSCE],type[GSCE],username[GSCE]", + FF_ESR = "alt[GSCE],constructor(),coords[GSCE],hash[GSCE],host[GSCE],hostname[GSCE],href[GSCE]," + "origin[GCE],password[GSCE],pathname[GSCE],port[GSCE],protocol[GSCE],rel[GSCE],relList[GCE]," + "search[GSCE],username[GSCE]") public void area() throws Exception { @@ -3691,13 +3691,17 @@ public void br() throws Exception { + "type[GSCE],validationMessage[GCE],validity[GCE],value[GSCE]," + "willValidate[GCE]") @HtmlUnitNYI(CHROME = "checkValidity(),constructor(),disabled[GSCE],form[GCE],formNoValidate[GSCE]," - + "labels[GCE],name[GSCE],setCustomValidity(),type[GSCE],validity[GCE],value[GSCE],willValidate[GCE]", + + "labels[GCE],name[GSCE],reportValidity(),setCustomValidity(),type[GSCE]," + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]", EDGE = "checkValidity(),constructor(),disabled[GSCE],form[GCE],formNoValidate[GSCE]," - + "labels[GCE],name[GSCE],setCustomValidity(),type[GSCE],validity[GCE],value[GSCE],willValidate[GCE]", + + "labels[GCE],name[GSCE],reportValidity(),setCustomValidity(),type[GSCE]," + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]", FF_ESR = "checkValidity(),constructor(),disabled[GSCE],form[GCE],formNoValidate[GSCE]," - + "labels[GCE],name[GSCE],setCustomValidity(),type[GSCE],validity[GCE],value[GSCE],willValidate[GCE]", + + "labels[GCE],name[GSCE],reportValidity(),setCustomValidity(),type[GSCE]," + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]", FF = "checkValidity(),constructor(),disabled[GSCE],form[GCE],formNoValidate[GSCE]," - + "labels[GCE],name[GSCE],setCustomValidity(),type[GSCE],validity[GCE],value[GSCE],willValidate[GCE]") + + "labels[GCE],name[GSCE],reportValidity(),setCustomValidity(),type[GSCE]," + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]") public void button() throws Exception { test("button"); } @@ -5524,14 +5528,6 @@ public void em() throws Exception { FF_ESR = "checkValidity(),constructor(),disabled[GSCE],elements[GCE],form[GCE],name[GSCE],reportValidity()," + "setCustomValidity(),type[GCE],validationMessage[GCE],validity[GCE]," + "willValidate[GCE]") - @HtmlUnitNYI(CHROME = "checkValidity(),constructor(),disabled[GSCE],form[GCE],name[GSCE]," - + "setCustomValidity(),validity[GCE],willValidate[GCE]", - EDGE = "checkValidity(),constructor(),disabled[GSCE],form[GCE],name[GSCE]," - + "setCustomValidity(),validity[GCE],willValidate[GCE]", - FF_ESR = "checkValidity(),constructor(),disabled[GSCE],form[GCE],name[GSCE]," - + "setCustomValidity(),validity[GCE],willValidate[GCE]", - FF = "checkValidity(),constructor(),disabled[GSCE],form[GCE],name[GSCE]," - + "setCustomValidity(),validity[GCE],willValidate[GCE]") public void fieldset() throws Exception { test("fieldset"); } @@ -6038,16 +6034,16 @@ public void font() throws Exception { + "target[GSCE]") @HtmlUnitNYI(CHROME = "action[GSCE],checkValidity(),constructor(),elements[GCE],encoding[GSCE],enctype[GSCE]," + "length[GCE],method[GSCE],name[GSCE],noValidate[GSCE],rel[GSCE],relList[GSCE]," - + "requestSubmit(),reset(),submit(),target[GSCE]", + + "reportValidity(),requestSubmit(),reset(),submit(),target[GSCE]", EDGE = "action[GSCE],checkValidity(),constructor(),elements[GCE],encoding[GSCE],enctype[GSCE]," + "length[GCE],method[GSCE],name[GSCE],noValidate[GSCE],rel[GSCE],relList[GSCE]," - + "requestSubmit(),reset(),submit(),target[GSCE]", + + "reportValidity(),requestSubmit(),reset(),submit(),target[GSCE]", FF_ESR = "action[GSCE],checkValidity(),constructor(),elements[GCE],encoding[GSCE],enctype[GSCE]," + "length[GCE],method[GSCE],name[GSCE],noValidate[GSCE],rel[GSCE],relList[GSCE]," - + "requestSubmit(),reset(),submit(),target[GSCE]", + + "reportValidity(),requestSubmit(),reset(),submit(),target[GSCE]", FF = "action[GSCE],checkValidity(),constructor(),elements[GCE],encoding[GSCE],enctype[GSCE]," + "length[GCE],method[GSCE],name[GSCE],noValidate[GSCE],rel[GSCE],relList[GSCE]," - + "requestSubmit(),reset(),submit(),target[GSCE]") + + "reportValidity(),requestSubmit(),reset(),submit(),target[GSCE]") public void form() throws Exception { test("form"); } @@ -9786,13 +9782,17 @@ public void noscript() throws Exception { + "width[GSCE]," + "willValidate[GCE]") @HtmlUnitNYI(CHROME = "align[GSCE],border[GSCE],checkValidity(),constructor(),form[GCE],height[GSCE]," - + "name[GSCE],setCustomValidity(),validity[GCE],width[GSCE],willValidate[GCE]", + + "name[GSCE],reportValidity(),setCustomValidity(),validationMessage[GCE]," + + "validity[GCE],width[GSCE],willValidate[GCE]", EDGE = "align[GSCE],border[GSCE],checkValidity(),constructor(),form[GCE],height[GSCE]," - + "name[GSCE],setCustomValidity(),validity[GCE],width[GSCE],willValidate[GCE]", + + "name[GSCE],reportValidity(),setCustomValidity(),validationMessage[GCE]," + + "validity[GCE],width[GSCE],willValidate[GCE]", FF_ESR = "align[GSCE],border[GSCE],checkValidity(),constructor(),form[GCE],height[GSCE]," - + "name[GSCE],setCustomValidity(),validity[GCE],width[GSCE],willValidate[GCE]", + + "name[GSCE],reportValidity(),setCustomValidity(),validationMessage[GCE]," + + "validity[GCE],width[GSCE],willValidate[GCE]", FF = "align[GSCE],border[GSCE],checkValidity(),constructor(),form[GCE],height[GSCE]," - + "name[GSCE],setCustomValidity(),validity[GCE],width[GSCE],willValidate[GCE]") + + "name[GSCE],reportValidity(),setCustomValidity(),validationMessage[GCE]," + + "validity[GCE],width[GSCE],willValidate[GCE]") public void object() throws Exception { test("object"); } @@ -9873,14 +9873,14 @@ public void option() throws Exception { FF_ESR = "checkValidity(),constructor(),defaultValue[GSCE],form[GCE],htmlFor[GSCE],labels[GCE],name[GSCE]," + "reportValidity(),setCustomValidity(),type[GCE],validationMessage[GCE],validity[GCE],value[GSCE]," + "willValidate[GCE]") - @HtmlUnitNYI(CHROME = "checkValidity(),constructor(),form[GCE],labels[GCE],name[GSCE],setCustomValidity()," - + "validity[GCE],willValidate[GCE]", - EDGE = "checkValidity(),constructor(),form[GCE],labels[GCE],name[GSCE],setCustomValidity()," - + "validity[GCE],willValidate[GCE]", - FF_ESR = "checkValidity(),constructor(),form[GCE],labels[GCE],name[GSCE],setCustomValidity()," - + "validity[GCE],willValidate[GCE]", - FF = "checkValidity(),constructor(),form[GCE],labels[GCE],name[GSCE],setCustomValidity()," - + "validity[GCE],willValidate[GCE]") + @HtmlUnitNYI(CHROME = "checkValidity(),constructor(),form[GCE],labels[GCE],name[GSCE],reportValidity(),setCustomValidity()," + + "validationMessage[GCE],validity[GCE],willValidate[GCE]", + EDGE = "checkValidity(),constructor(),form[GCE],labels[GCE],name[GSCE],reportValidity(),setCustomValidity()," + + "validationMessage[GCE],validity[GCE],willValidate[GCE]", + FF_ESR = "checkValidity(),constructor(),form[GCE],labels[GCE],name[GSCE],reportValidity(),setCustomValidity()," + + "validationMessage[GCE],validity[GCE],willValidate[GCE]", + FF = "checkValidity(),constructor(),form[GCE],labels[GCE],name[GSCE],reportValidity(),setCustomValidity()," + + "validationMessage[GCE],validity[GCE],willValidate[GCE]") public void output() throws Exception { test("output"); } @@ -12101,21 +12101,21 @@ public void section() throws Exception { + "showPicker(),size[GSCE],type[GCE],validationMessage[GCE],validity[GCE],value[GSCE]," + "willValidate[GCE]") @HtmlUnitNYI(CHROME = "add(),checkValidity(),constructor(),disabled[GSCE],form[GCE],item()," - + "labels[GCE],length[GSCE],multiple[GSCE],name[GSCE],options[GCE],remove(),required[GSCE]," - + "selectedIndex[GSCE],setCustomValidity(),size[GSCE],type[GCE],validity[GCE],value[GSCE]," - + "willValidate[GCE]", + + "labels[GCE],length[GSCE],multiple[GSCE],name[GSCE],options[GCE],remove(),reportValidity(),required[GSCE]," + + "selectedIndex[GSCE],setCustomValidity(),size[GSCE],type[GCE]," + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]", EDGE = "add(),checkValidity(),constructor(),disabled[GSCE],form[GCE],item()," - + "labels[GCE],length[GSCE],multiple[GSCE],name[GSCE],options[GCE],remove(),required[GSCE]," - + "selectedIndex[GSCE],setCustomValidity(),size[GSCE],type[GCE],validity[GCE],value[GSCE]," - + "willValidate[GCE]", + + "labels[GCE],length[GSCE],multiple[GSCE],name[GSCE],options[GCE],remove(),reportValidity(),required[GSCE]," + + "selectedIndex[GSCE],setCustomValidity(),size[GSCE],type[GCE]," + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]", FF_ESR = "add(),checkValidity(),constructor(),disabled[GSCE],form[GCE],item()," - + "labels[GCE],length[GSCE],multiple[GSCE],name[GSCE],options[GCE],remove(),required[GSCE]," - + "selectedIndex[GSCE],setCustomValidity(),size[GSCE],type[GCE],validity[GCE],value[GSCE]," - + "willValidate[GCE]", + + "labels[GCE],length[GSCE],multiple[GSCE],name[GSCE],options[GCE],remove(),reportValidity(),required[GSCE]," + + "selectedIndex[GSCE],setCustomValidity(),size[GSCE],type[GCE]," + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]", FF = "add(),checkValidity(),constructor(),disabled[GSCE],form[GCE],item()," - + "labels[GCE],length[GSCE],multiple[GSCE],name[GSCE],options[GCE],remove(),required[GSCE]," - + "selectedIndex[GSCE],setCustomValidity(),size[GSCE],type[GCE],validity[GCE],value[GSCE]," - + "willValidate[GCE]") + + "labels[GCE],length[GSCE],multiple[GSCE],name[GSCE],options[GCE],remove(),reportValidity(),required[GSCE]," + + "selectedIndex[GSCE],setCustomValidity(),size[GSCE],type[GCE]," + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]") public void select() throws Exception { test("select"); } @@ -13783,26 +13783,30 @@ public void tr() throws Exception { + "wrap[GSCE]") @HtmlUnitNYI(CHROME = "checkValidity(),cols[GSCE],constructor(),defaultValue[GSCE],disabled[GSCE]," + "form[GCE],labels[GCE]," - + "maxLength[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE],required[GSCE]," + + "maxLength[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE]," + + "reportValidity(),required[GSCE]," + "rows[GSCE],select(),selectionEnd[GSCE]," + "selectionStart[GSCE],setCustomValidity(),setSelectionRange(),textLength[GCE],type[GCE]," - + "validity[GCE],value[GSCE],willValidate[GCE]", + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]", EDGE = "checkValidity(),cols[GSCE],constructor(),defaultValue[GSCE],disabled[GSCE]," + "form[GCE],labels[GCE]," - + "maxLength[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE],required[GSCE]," + + "maxLength[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE]," + + "reportValidity(),required[GSCE]," + "rows[GSCE],select(),selectionEnd[GSCE]," + "selectionStart[GSCE],setCustomValidity(),setSelectionRange(),textLength[GCE],type[GCE]," - + "validity[GCE],value[GSCE],willValidate[GCE]", + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]", FF_ESR = "checkValidity(),cols[GSCE],constructor(),defaultValue[GSCE],disabled[GSCE]," + "form[GCE],labels[GCE],maxLength[GSCE],minLength[GSCE],name[GSCE]," - + "placeholder[GSCE],readOnly[GSCE],required[GSCE],rows[GSCE],select(),selectionEnd[GSCE]," + + "placeholder[GSCE],readOnly[GSCE]," + + "reportValidity(),required[GSCE],rows[GSCE],select(),selectionEnd[GSCE]," + "selectionStart[GSCE],setCustomValidity(),setSelectionRange(),textLength[GCE],type[GCE]," - + "validity[GCE],value[GSCE],willValidate[GCE]", + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]", FF = "checkValidity(),cols[GSCE],constructor(),defaultValue[GSCE],disabled[GSCE]," + "form[GCE],labels[GCE],maxLength[GSCE],minLength[GSCE],name[GSCE]," - + "placeholder[GSCE],readOnly[GSCE],required[GSCE],rows[GSCE],select(),selectionEnd[GSCE]," + + "placeholder[GSCE],readOnly[GSCE]," + + "reportValidity(),required[GSCE],rows[GSCE],select(),selectionEnd[GSCE]," + "selectionStart[GSCE],setCustomValidity(),setSelectionRange(),textLength[GCE],type[GCE]," - + "validity[GCE],value[GSCE],willValidate[GCE]") + + "validationMessage[GCE],validity[GCE],value[GSCE],willValidate[GCE]") public void textarea() throws Exception { test("textarea"); } @@ -14618,7 +14622,8 @@ public void var() throws Exception { + "width[GSCE]", FF = "cancelVideoFrameCallback(),constructor(),disablePictureInPicture[GSCE],getVideoPlaybackQuality()," + "height[GSCE],mozDecodedFrames[GCE],mozFrameDelay[GCE],mozHasAudio[GCE],mozPaintedFrames[GCE]," - + "mozParsedFrames[GCE],mozPresentedFrames[GCE],poster[GSCE],requestVideoFrameCallback()," + + "mozParsedFrames[GCE],mozPresentedFrames[GCE],onenterpictureinpicture[GSCE]," + + "onleavepictureinpicture[GSCE],poster[GSCE],requestPictureInPicture(),requestVideoFrameCallback()," + "videoHeight[GCE],videoWidth[GCE]," + "width[GSCE]", FF_ESR = "cancelVideoFrameCallback(),constructor(),disablePictureInPicture[GSCE],getVideoPlaybackQuality()," @@ -14937,31 +14942,31 @@ public void xmp() throws Exception { @HtmlUnitNYI(CHROME = "accept[GSCE],align[GSCE],alt[GSCE],autocomplete[GSCE],checked[GSCE],checkValidity()," + "constructor(),defaultChecked[GSCE],defaultValue[GSCE],disabled[GSCE],files[GCE],form[GCE]," + "formNoValidate[GSCE],height[GSCE],labels[GCE],max[GSCE],maxLength[GSCE]," - + "min[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE],required[GSCE]," + + "min[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE],reportValidity(),required[GSCE]," + "select(),selectionEnd[GSCE],selectionStart[GSCE],setCustomValidity()," - + "setSelectionRange(),size[GSCE],src[GSCE],step[GSCE],type[GSCE],validity[GCE],value[GSCE]," - + "width[GSCE],willValidate[GCE]", + + "setSelectionRange(),size[GSCE],src[GSCE],step[GSCE],type[GSCE]," + + "validationMessage[GCE],validity[GCE],value[GSCE],width[GSCE],willValidate[GCE]", EDGE = "accept[GSCE],align[GSCE],alt[GSCE],autocomplete[GSCE],checked[GSCE],checkValidity()," + "constructor(),defaultChecked[GSCE],defaultValue[GSCE],disabled[GSCE],files[GCE],form[GCE]," + "formNoValidate[GSCE],height[GSCE],labels[GCE],max[GSCE],maxLength[GSCE]," - + "min[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE],required[GSCE]," + + "min[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE],reportValidity(),required[GSCE]," + "select(),selectionEnd[GSCE],selectionStart[GSCE],setCustomValidity()," - + "setSelectionRange(),size[GSCE],src[GSCE],step[GSCE],type[GSCE],validity[GCE],value[GSCE]," - + "width[GSCE],willValidate[GCE]", + + "setSelectionRange(),size[GSCE],src[GSCE],step[GSCE],type[GSCE]," + + "validationMessage[GCE],validity[GCE],value[GSCE],width[GSCE],willValidate[GCE]", FF_ESR = "accept[GSCE],align[GSCE],alt[GSCE],autocomplete[GSCE],checked[GSCE],checkValidity()," + "constructor(),defaultChecked[GSCE],defaultValue[GSCE],disabled[GSCE],files[GCE],form[GCE]," + "formNoValidate[GSCE],height[GSCE],labels[GCE],max[GSCE],maxLength[GSCE]," - + "min[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE],required[GSCE]," + + "min[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE],reportValidity(),required[GSCE]," + "select(),selectionEnd[GSCE],selectionStart[GSCE],setCustomValidity()," + "setSelectionRange(),size[GSCE],src[GSCE],step[GSCE],textLength[GCE],type[GSCE]," - + "validity[GCE],value[GSCE],width[GSCE],willValidate[GCE]", + + "validationMessage[GCE],validity[GCE],value[GSCE],width[GSCE],willValidate[GCE]", FF = "accept[GSCE],align[GSCE],alt[GSCE],autocomplete[GSCE],checked[GSCE],checkValidity()," + "constructor(),defaultChecked[GSCE],defaultValue[GSCE],disabled[GSCE],files[GCE],form[GCE]," + "formNoValidate[GSCE],height[GSCE],labels[GCE],max[GSCE],maxLength[GSCE]," - + "min[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE],required[GSCE]," + + "min[GSCE],minLength[GSCE],name[GSCE],placeholder[GSCE],readOnly[GSCE],reportValidity(),required[GSCE]," + "select(),selectionEnd[GSCE],selectionStart[GSCE],setCustomValidity()," + "setSelectionRange(),size[GSCE],src[GSCE],step[GSCE],textLength[GCE],type[GSCE]," - + "validity[GCE],value[GSCE],width[GSCE],willValidate[GCE]") + + "validationMessage[GCE],validity[GCE],value[GSCE],width[GSCE],willValidate[GCE]") public void input() throws Exception { test("input"); } @@ -16443,18 +16448,19 @@ public void slot() throws Exception { + "createRange(),createTextNode(),createTreeWalker(),currentScript[GCE],defaultView[GCE]," + "designMode[GSCE],dir[GSCE],doctype[GCE],documentElement[GCE],documentURI[GCE],domain[GSCE]," + "elementFromPoint(),elementsFromPoint(),embeds[GCE],enableStyleSheetsForSet(),evaluate()," - + "execCommand(),exitFullscreen(),exitPointerLock(),fgColor[GSCE],firstElementChild[GCE],fonts[GCE]," - + "forms[GCE],fragmentDirective[GCE],fullscreen[GSCE],fullscreenElement[GSCE]," - + "fullscreenEnabled[GSCE],getAnimations(),getElementById(),getElementsByClassName()," - + "getElementsByName(),getElementsByTagName(),getElementsByTagNameNS(),getSelection(),hasFocus()," - + "hasStorageAccess(),head[GCE],hidden[GCE],images[GCE],implementation[GCE],importNode()," - + "inputEncoding[GCE],lastElementChild[GCE],lastModified[GCE],lastStyleSheetSet[GCE]," - + "linkColor[GSCE],links[GCE],moveBefore(),mozCancelFullScreen(),mozFullScreen[GCE]," - + "mozFullScreenElement[GCE],mozFullScreenEnabled[GCE],mozSetImageElement(),onabort[GSCE]," - + "onanimationcancel[GSCE],onanimationend[GSCE],onanimationiteration[GSCE],onanimationstart[GSCE]," - + "onauxclick[GSCE],onbeforeinput[GSCE],onbeforematch[GSCE],onbeforetoggle[GSCE],onblur[GSCE]," - + "oncancel[GSCE],oncanplay[GSCE],oncanplaythrough[GSCE],onchange[GSCE],onclick[GSCE],onclose[GSCE]," - + "oncommand[GSCE],oncontentvisibilityautostatechange[GSCE],oncontextlost[GSCE],oncontextmenu[GSCE]," + + "execCommand(),exitFullscreen(),exitPictureInPicture(),exitPointerLock(),fgColor[GSCE]," + + "firstElementChild[GCE],fonts[GCE],forms[GCE],fragmentDirective[GCE],fullscreen[GSCE]," + + "fullscreenElement[GSCE],fullscreenEnabled[GSCE],getAnimations(),getElementById()," + + "getElementsByClassName(),getElementsByName(),getElementsByTagName(),getElementsByTagNameNS()," + + "getSelection(),hasFocus(),hasStorageAccess(),head[GCE],hidden[GCE],images[GCE]," + + "implementation[GCE],importNode(),inputEncoding[GCE],lastElementChild[GCE],lastModified[GCE]," + + "lastStyleSheetSet[GCE],linkColor[GSCE],links[GCE],moveBefore(),mozCancelFullScreen()," + + "mozFullScreen[GCE],mozFullScreenElement[GCE],mozFullScreenEnabled[GCE],mozSetImageElement()," + + "onabort[GSCE],onanimationcancel[GSCE],onanimationend[GSCE],onanimationiteration[GSCE]," + + "onanimationstart[GSCE],onauxclick[GSCE],onbeforeinput[GSCE],onbeforematch[GSCE]," + + "onbeforetoggle[GSCE],onblur[GSCE],oncancel[GSCE],oncanplay[GSCE],oncanplaythrough[GSCE]," + + "onchange[GSCE],onclick[GSCE],onclose[GSCE],oncommand[GSCE]," + + "oncontentvisibilityautostatechange[GSCE],oncontextlost[GSCE],oncontextmenu[GSCE]," + "oncontextrestored[GSCE],oncopy[GSCE],oncuechange[GSCE],oncut[GSCE],ondblclick[GSCE],ondrag[GSCE]," + "ondragend[GSCE],ondragenter[GSCE],ondragexit[GSCE],ondragleave[GSCE],ondragover[GSCE]," + "ondragstart[GSCE],ondrop[GSCE],ondurationchange[GSCE],onemptied[GSCE],onended[GSCE]," @@ -16473,14 +16479,14 @@ public void slot() throws Exception { + "onsuspend[GSCE],ontimeupdate[GSCE],ontoggle[GSCE],ontransitioncancel[GSCE],ontransitionend[GSCE]," + "ontransitionrun[GSCE],ontransitionstart[GSCE],onvisibilitychange[GSCE],onvolumechange[GSCE]," + "onwaiting[GSCE],onwebkitanimationend[GSCE],onwebkitanimationiteration[GSCE]," - + "onwebkitanimationstart[GSCE],onwebkittransitionend[GSCE],onwheel[GSCE],open(),plugins[GCE]," - + "pointerLockElement[GCE],preferredStyleSheetSet[GCE],prepend(),queryCommandEnabled()," - + "queryCommandIndeterm(),queryCommandState(),queryCommandSupported(),queryCommandValue()," - + "querySelector(),querySelectorAll(),readyState[GCE],referrer[GCE],releaseCapture()," - + "releaseEvents(),replaceChildren(),requestStorageAccess(),rootElement[GCE],scripts[GCE]," - + "scrollingElement[GCE],selectedStyleSheetSet[GSCE],startViewTransition(),styleSheets[GCE]," - + "styleSheetSets[GCE],timeline[GCE],title[GSCE],URL[GCE],visibilityState[GCE],vlinkColor[GSCE]," - + "write()," + + "onwebkitanimationstart[GSCE],onwebkittransitionend[GSCE],onwheel[GSCE],open()," + + "pictureInPictureElement[GCE],pictureInPictureEnabled[GCE],plugins[GCE],pointerLockElement[GCE]," + + "preferredStyleSheetSet[GCE],prepend(),queryCommandEnabled(),queryCommandIndeterm()," + + "queryCommandState(),queryCommandSupported(),queryCommandValue(),querySelector()," + + "querySelectorAll(),readyState[GCE],referrer[GCE],releaseCapture(),releaseEvents()," + + "replaceChildren(),requestStorageAccess(),rootElement[GCE],scripts[GCE],scrollingElement[GCE]," + + "selectedStyleSheetSet[GSCE],startViewTransition(),styleSheets[GCE],styleSheetSets[GCE]," + + "timeline[GCE],title[GSCE],URL[GCE],visibilityState[GCE],vlinkColor[GSCE],write()," + "writeln()", FF_ESR = "activeElement[GCE],adoptedStyleSheets[GSCE],adoptNode(),alinkColor[GSCE],all[GCE],anchors[GCE]," + "append(),applets[GCE],bgColor[GSCE],body[GSCE],captureEvents(),caretPositionFromPoint()," @@ -19217,19 +19223,19 @@ public void mimeType() throws Exception { @HtmlUnitNYI(CHROME = "appCodeName[GCE],appName[GCE],appVersion[GCE],connection[GCE],constructor()," + "cookieEnabled[GCE],doNotTrack[GCE],geolocation[GCE],javaEnabled(),language[GCE],languages[GCE]," + "mediaDevices[GCE],mimeTypes[GCE],onLine[GCE],pdfViewerEnabled[GCE],platform[GCE],plugins[GCE]," - + "product[GCE],productSub[GCE],userAgent[GCE],vendor[GCE],vendorSub[GCE]", + + "product[GCE],productSub[GCE],sendBeacon(),userAgent[GCE],vendor[GCE],vendorSub[GCE]", EDGE = "appCodeName[GCE],appName[GCE],appVersion[GCE],connection[GCE],constructor()," + "cookieEnabled[GCE],doNotTrack[GCE],geolocation[GCE],javaEnabled(),language[GCE],languages[GCE]," + "mediaDevices[GCE],mimeTypes[GCE],onLine[GCE],pdfViewerEnabled[GCE],platform[GCE],plugins[GCE]," - + "product[GCE],productSub[GCE],userAgent[GCE],vendor[GCE],vendorSub[GCE]", + + "product[GCE],productSub[GCE],sendBeacon(),userAgent[GCE],vendor[GCE],vendorSub[GCE]", FF = "appCodeName[GCE],appName[GCE],appVersion[GCE],buildID[GCE],constructor(),cookieEnabled[GCE]," + "doNotTrack[GCE],geolocation[GCE],javaEnabled(),language[GCE],languages[GCE],mediaDevices[GCE]," + "mimeTypes[GCE],onLine[GCE],oscpu[GCE],pdfViewerEnabled[GCE],platform[GCE],plugins[GCE]," - + "product[GCE],productSub[GCE],taintEnabled(),userAgent[GCE],vendor[GCE],vendorSub[GCE]", + + "product[GCE],productSub[GCE],sendBeacon(),taintEnabled(),userAgent[GCE],vendor[GCE],vendorSub[GCE]", FF_ESR = "appCodeName[GCE],appName[GCE],appVersion[GCE],buildID[GCE],constructor(),cookieEnabled[GCE]," + "doNotTrack[GCE],geolocation[GCE],javaEnabled(),language[GCE],languages[GCE],mediaDevices[GCE]," + "mimeTypes[GCE],onLine[GCE],oscpu[GCE],pdfViewerEnabled[GCE],platform[GCE],plugins[GCE]," - + "product[GCE],productSub[GCE],taintEnabled(),userAgent[GCE],vendor[GCE],vendorSub[GCE]") + + "product[GCE],productSub[GCE],sendBeacon(),taintEnabled(),userAgent[GCE],vendor[GCE],vendorSub[GCE]") public void navigator() throws Exception { testString("", "navigator"); } @@ -19660,8 +19666,10 @@ public void intl_DateTimeFormat() throws Exception { + "getTimeZones(),getWeekInfo(),hourCycle[GC],language[GC],maximize(),minimize()," + "numberingSystem[GC],numeric[GC],region[GC],script[GC],toString()," + "variants[GC]", - FF = "baseName[GC],calendar[GC],caseFirst[GC],collation[GC],constructor(),hourCycle[GC],language[GC]," - + "maximize(),minimize(),numberingSystem[GC],numeric[GC],region[GC],script[GC],toString()," + FF = "baseName[GC],calendar[GC],caseFirst[GC],collation[GC],constructor(),firstDayOfWeek[GC]," + + "getCalendars(),getCollations(),getHourCycles(),getNumberingSystems(),getTextInfo()," + + "getTimeZones(),getWeekInfo(),hourCycle[GC],language[GC],maximize(),minimize()," + + "numberingSystem[GC],numeric[GC],region[GC],script[GC],toString()," + "variants[GC]", FF_ESR = "baseName[GC],calendar[GC],caseFirst[GC],collation[GC],constructor(),hourCycle[GC],language[GC]," + "maximize(),minimize(),numberingSystem[GC],numeric[GC],region[GC],script[GC]," diff --git a/src/test/java/org/htmlunit/general/ElementPropertiesTest.java b/src/test/java/org/htmlunit/general/ElementPropertiesTest.java index 6eedbdaf4dc..73a4849e558 100644 --- a/src/test/java/org/htmlunit/general/ElementPropertiesTest.java +++ b/src/test/java/org/htmlunit/general/ElementPropertiesTest.java @@ -1366,8 +1366,9 @@ public void applet() throws Exception { EDGE = "alt,attributionSrc,coords,download,hash,host,hostname,href,interestForElement,noHref,origin," + "password,pathname,ping,port,protocol,referrerPolicy,rel,relList,search,shape,target," + "username", - FF = "alt,coords,download,hash,host,hostname,href,noHref,origin,password,pathname,ping,port," - + "protocol,referrerPolicy,rel,relList,search,shape,target,username", + FF = "alt,coords,download,hash,host,hostname,href,hreflang,noHref,origin,password,pathname,ping,port," + + "protocol,referrerPolicy,rel,relList,search,shape,target,type," + + "username", FF_ESR = "alt,coords,download,hash,host,hostname,href,noHref,origin,password,pathname,ping,port," + "protocol,referrerPolicy,rel,relList,search,shape,target,username") @HtmlUnitNYI( @@ -1375,9 +1376,9 @@ public void applet() throws Exception { + "rel,relList,search,username", EDGE = "alt,coords,hash,host,hostname,href,origin,password,pathname,port,protocol," + "rel,relList,search,username", - FF_ESR = "alt,coords,hash,host,hostname,href,origin,password,pathname,port,protocol," - + "rel,relList,search,username", FF = "alt,coords,hash,host,hostname,href,origin,password,pathname,port,protocol," + + "rel,relList,search,type,username", + FF_ESR = "alt,coords,hash,host,hostname,href,origin,password,pathname,port,protocol," + "rel,relList,search,username") public void area() throws Exception { test("area"); @@ -1619,14 +1620,14 @@ public void br() throws Exception { + "name,popoverTargetAction,popoverTargetElement,reportValidity(),setCustomValidity(),type," + "validationMessage,validity,value," + "willValidate") - @HtmlUnitNYI(CHROME = "checkValidity(),disabled,form,formNoValidate,labels,name,setCustomValidity()" - + ",type,validity,value,willValidate", - EDGE = "checkValidity(),disabled,form,formNoValidate,labels,name,setCustomValidity()," - + "type,validity,value,willValidate", - FF_ESR = "checkValidity(),disabled,form,formNoValidate,labels,name,setCustomValidity()," - + "type,validity,value,willValidate", - FF = "checkValidity(),disabled,form,formNoValidate,labels,name,setCustomValidity()," - + "type,validity,value,willValidate") + @HtmlUnitNYI(CHROME = "checkValidity(),disabled,form,formNoValidate,labels,name,reportValidity(),setCustomValidity()" + + ",type,validationMessage,validity,value,willValidate", + EDGE = "checkValidity(),disabled,form,formNoValidate,labels,name,reportValidity(),setCustomValidity()," + + "type,validationMessage,validity,value,willValidate", + FF_ESR = "checkValidity(),disabled,form,formNoValidate,labels,name,reportValidity(),setCustomValidity()," + + "type,validationMessage,validity,value,willValidate", + FF = "checkValidity(),disabled,form,formNoValidate,labels,name,reportValidity(),setCustomValidity()," + + "type,validationMessage,validity,value,willValidate") public void button() throws Exception { test("button"); } @@ -1864,10 +1865,6 @@ public void em() throws Exception { @Test @Alerts("checkValidity(),disabled,elements,form,name,reportValidity(),setCustomValidity(),type," + "validationMessage,validity,willValidate") - @HtmlUnitNYI(CHROME = "checkValidity(),disabled,form,name,setCustomValidity(),validity,willValidate", - EDGE = "checkValidity(),disabled,form,name,setCustomValidity(),validity,willValidate", - FF_ESR = "checkValidity(),disabled,form,name,setCustomValidity(),validity,willValidate", - FF = "checkValidity(),disabled,form,name,setCustomValidity(),validity,willValidate") public void fieldset() throws Exception { test("fieldset"); } @@ -1924,13 +1921,13 @@ public void font() throws Exception { + "noValidate,rel,relList,reportValidity(),requestSubmit(),reset(),submit()," + "target") @HtmlUnitNYI(CHROME = "action,checkValidity(),elements,encoding,enctype,length,method,name," - + "noValidate,rel,relList,requestSubmit(),reset(),submit(),target", + + "noValidate,rel,relList,reportValidity(),requestSubmit(),reset(),submit(),target", EDGE = "action,checkValidity(),elements,encoding,enctype,length,method,name," - + "noValidate,rel,relList,requestSubmit(),reset(),submit(),target", + + "noValidate,rel,relList,reportValidity(),requestSubmit(),reset(),submit(),target", FF_ESR = "action,checkValidity(),elements,encoding,enctype,length,method,name," - + "noValidate,rel,relList,requestSubmit(),reset(),submit(),target", + + "noValidate,rel,relList,reportValidity(),requestSubmit(),reset(),submit(),target", FF = "action,checkValidity(),elements,encoding,enctype,length,method,name," - + "noValidate,rel,relList,requestSubmit(),reset(),submit(),target") + + "noValidate,rel,relList,reportValidity(),requestSubmit(),reset(),submit(),target") public void form() throws Exception { test("form"); } @@ -2557,14 +2554,14 @@ public void noscript() throws Exception { FF_ESR = "align,archive,border,checkValidity(),code,codeBase,codeType,contentDocument,contentWindow,data," + "declare,form,getSVGDocument(),height,hspace,name,reportValidity(),setCustomValidity(),standby," + "type,useMap,validationMessage,validity,vspace,width,willValidate") - @HtmlUnitNYI(CHROME = "align,border,checkValidity(),form,height,name,setCustomValidity()," - + "validity,width,willValidate", - EDGE = "align,border,checkValidity(),form,height,name,setCustomValidity()," - + "validity,width,willValidate", - FF_ESR = "align,border,checkValidity(),form,height,name,setCustomValidity()," - + "validity,width,willValidate", - FF = "align,border,checkValidity(),form,height,name,setCustomValidity()," - + "validity,width,willValidate") + @HtmlUnitNYI(CHROME = "align,border,checkValidity(),form,height,name,reportValidity(),setCustomValidity()," + + "validationMessage,validity,width,willValidate", + EDGE = "align,border,checkValidity(),form,height,name,reportValidity(),setCustomValidity()," + + "validationMessage,validity,width,willValidate", + FF_ESR = "align,border,checkValidity(),form,height,name,reportValidity(),setCustomValidity()," + + "validationMessage,validity,width,willValidate", + FF = "align,border,checkValidity(),form,height,name,reportValidity(),setCustomValidity()," + + "validationMessage,validity,width,willValidate") public void object() throws Exception { test("object"); } @@ -2614,10 +2611,14 @@ public void option() throws Exception { @Test @Alerts("checkValidity(),defaultValue,form,htmlFor,labels,name,reportValidity(),setCustomValidity(),type," + "validationMessage,validity,value,willValidate") - @HtmlUnitNYI(CHROME = "checkValidity(),form,labels,name,setCustomValidity(),validity,willValidate", - EDGE = "checkValidity(),form,labels,name,setCustomValidity(),validity,willValidate", - FF_ESR = "checkValidity(),form,labels,name,setCustomValidity(),validity,willValidate", - FF = "checkValidity(),form,labels,name,setCustomValidity(),validity,willValidate") + @HtmlUnitNYI(CHROME = "checkValidity(),form,labels,name,reportValidity(),setCustomValidity()," + + "validationMessage,validity,willValidate", + EDGE = "checkValidity(),form,labels,name,reportValidity(),setCustomValidity()," + + "validationMessage,validity,willValidate", + FF_ESR = "checkValidity(),form,labels,name,reportValidity(),setCustomValidity()," + + "validationMessage,validity,willValidate", + FF = "checkValidity(),form,labels,name,reportValidity(),setCustomValidity()," + + "validationMessage,validity,willValidate") public void output() throws Exception { test("output"); } @@ -2866,13 +2867,17 @@ public void section() throws Exception { + "size,type,validationMessage,validity,value," + "willValidate") @HtmlUnitNYI(CHROME = "add(),checkValidity(),disabled,form,item(),labels,length,multiple,name,options," - + "required,selectedIndex,setCustomValidity(),size,type,validity,value,willValidate", + + "reportValidity(),required,selectedIndex,setCustomValidity(),size,type," + + "validationMessage,validity,value,willValidate", EDGE = "add(),checkValidity(),disabled,form,item(),labels,length,multiple,name,options," - + "required,selectedIndex,setCustomValidity(),size,type,validity,value,willValidate", + + "reportValidity(),required,selectedIndex,setCustomValidity(),size,type," + + "validationMessage,validity,value,willValidate", FF_ESR = "add(),checkValidity(),disabled,form,item(),labels,length,multiple,name,options," - + "required,selectedIndex,setCustomValidity(),size,type,validity,value,willValidate", + + "reportValidity(),required,selectedIndex,setCustomValidity(),size,type," + + "validationMessage,validity,value,willValidate", FF = "add(),checkValidity(),disabled,form,item(),labels,length,multiple,name,options," - + "required,selectedIndex,setCustomValidity(),size,type,validity,value,willValidate") + + "reportValidity(),required,selectedIndex,setCustomValidity(),size,type," + + "validationMessage,validity,value,willValidate") public void select() throws Exception { test("select"); } @@ -3135,17 +3140,17 @@ public void tr() throws Exception { + "type,validationMessage,validity,value,willValidate," + "wrap") @HtmlUnitNYI(CHROME = "checkValidity(),cols,defaultValue,disabled,form,labels,maxLength,minLength,name," - + "placeholder,readOnly,required,rows,select(),selectionEnd,selectionStart" - + ",setCustomValidity(),setSelectionRange(),textLength,type,validity,value,willValidate", + + "placeholder,readOnly,reportValidity(),required,rows,select(),selectionEnd,selectionStart" + + ",setCustomValidity(),setSelectionRange(),textLength,type,validationMessage,validity,value,willValidate", EDGE = "checkValidity(),cols,defaultValue,disabled,form,labels,maxLength,minLength,name," - + "placeholder,readOnly,required,rows,select(),selectionEnd,selectionStart," - + "setCustomValidity(),setSelectionRange(),textLength,type,validity,value,willValidate", + + "placeholder,readOnly,reportValidity(),required,rows,select(),selectionEnd,selectionStart," + + "setCustomValidity(),setSelectionRange(),textLength,type,validationMessage,validity,value,willValidate", FF_ESR = "checkValidity(),cols,defaultValue,disabled,form,labels,maxLength,minLength,name,placeholder," - + "readOnly,required,rows,select(),selectionEnd,selectionStart," - + "setCustomValidity(),setSelectionRange(),textLength,type,validity,value,willValidate", + + "readOnly,reportValidity(),required,rows,select(),selectionEnd,selectionStart," + + "setCustomValidity(),setSelectionRange(),textLength,type,validationMessage,validity,value,willValidate", FF = "checkValidity(),cols,defaultValue,disabled,form,labels,maxLength,minLength,name,placeholder," - + "readOnly,required,rows,select(),selectionEnd,selectionStart," - + "setCustomValidity(),setSelectionRange(),textLength,type,validity,value,willValidate") + + "readOnly,reportValidity(),required,rows,select(),selectionEnd,selectionStart," + + "setCustomValidity(),setSelectionRange(),textLength,type,validationMessage,validity,value,willValidate") public void textarea() throws Exception { test("textarea"); } @@ -3290,8 +3295,9 @@ public void var() throws Exception { + "loop,mediaKeys,mozAudioCaptured,mozCaptureStream(),mozCaptureStreamUntilEnded(),mozDecodedFrames," + "mozFragmentEnd,mozFrameDelay,mozGetMetadata(),mozHasAudio,mozPaintedFrames,mozParsedFrames," + "mozPresentedFrames,muted,NETWORK_EMPTY,NETWORK_IDLE,NETWORK_LOADING,NETWORK_NO_SOURCE," - + "networkState,onencrypted,onwaitingforkey,pause(),paused,play(),playbackRate,played,poster," - + "preload,preservesPitch,readyState,requestVideoFrameCallback(),seekable,seeking,setMediaKeys()," + + "networkState,onencrypted,onenterpictureinpicture,onleavepictureinpicture,onwaitingforkey,pause()," + + "paused,play(),playbackRate,played,poster,preload,preservesPitch,readyState," + + "requestPictureInPicture(),requestVideoFrameCallback(),seekable,seeking,setMediaKeys()," + "setSinkId(),sinkId,src,srcObject,textTracks,videoHeight,videoWidth,volume," + "width", FF_ESR = "addTextTrack(),autoplay,buffered,cancelVideoFrameCallback(),canPlayType(),controls,crossOrigin," @@ -3387,26 +3393,24 @@ public void xmp() throws Exception { + "willValidate") @HtmlUnitNYI(CHROME = "accept,align,alt,autocomplete,checked,checkValidity(),defaultChecked,defaultValue," + "disabled,files,form,formNoValidate," - + "height,labels,max,maxLength,min,minLength,name,placeholder,readOnly," - + "required,select(),selectionEnd,selectionStart," - + "setCustomValidity(),setSelectionRange(),size,src,step,type,validity,value,width,willValidate", + + "height,labels,max,maxLength,min,minLength,name,placeholder,readOnly,reportValidity()," + + "required,select(),selectionEnd,selectionStart,setCustomValidity(),setSelectionRange()," + + "size,src,step,type,validationMessage,validity,value,width,willValidate", EDGE = "accept,align,alt,autocomplete,checked,checkValidity(),defaultChecked,defaultValue," + "disabled,files,form,formNoValidate," - + "height,labels,max,maxLength,min,minLength,name,placeholder,readOnly," - + "required,select(),selectionEnd,selectionStart," - + "setCustomValidity(),setSelectionRange(),size,src,step,type,validity,value,width,willValidate", + + "height,labels,max,maxLength,min,minLength,name,placeholder,readOnly,reportValidity()," + + "required,select(),selectionEnd,selectionStart,setCustomValidity(),setSelectionRange()," + + "size,src,step,type,validationMessage,validity,value,width,willValidate", FF_ESR = "accept,align,alt,autocomplete,checked,checkValidity(),defaultChecked,defaultValue,disabled," + "files,form,formNoValidate," - + "height,labels,max,maxLength,min,minLength,name,placeholder,readOnly,required," - + "select(),selectionEnd,selectionStart," - + "setCustomValidity(),setSelectionRange(),size,src,step,textLength,type," - + "validity,value,width,willValidate", + + "height,labels,max,maxLength,min,minLength,name,placeholder,readOnly,reportValidity()," + + "required,select(),selectionEnd,selectionStart,setCustomValidity(),setSelectionRange()," + + "size,src,step,textLength,type,validationMessage,validity,value,width,willValidate", FF = "accept,align,alt,autocomplete,checked,checkValidity(),defaultChecked,defaultValue,disabled," + "files,form,formNoValidate," - + "height,labels,max,maxLength,min,minLength,name,placeholder,readOnly,required," - + "select(),selectionEnd,selectionStart," - + "setCustomValidity(),setSelectionRange(),size,src,step,textLength,type," - + "validity,value,width,willValidate") + + "height,labels,max,maxLength,min,minLength,name,placeholder,readOnly,reportValidity()," + + "required,select(),selectionEnd,selectionStart,setCustomValidity(),setSelectionRange()," + + "size,src,step,textLength,type,validationMessage,validity,value,width,willValidate") public void input() throws Exception { test("input"); } @@ -5909,8 +5913,8 @@ public void slot() throws Exception { + "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC,DOCUMENT_POSITION_PRECEDING,DOCUMENT_TYPE_NODE," + "documentElement,documentURI,domain,ELEMENT_NODE,elementFromPoint(),elementsFromPoint(),embeds," + "enableStyleSheetsForSet(),ENTITY_NODE,ENTITY_REFERENCE_NODE,evaluate(),execCommand()," - + "exitFullscreen(),exitPointerLock(),fgColor,firstChild,firstElementChild,fonts,forms," - + "fragmentDirective,fullscreen,fullscreenElement,fullscreenEnabled,getAnimations()," + + "exitFullscreen(),exitPictureInPicture(),exitPointerLock(),fgColor,firstChild,firstElementChild," + + "fonts,forms,fragmentDirective,fullscreen,fullscreenElement,fullscreenEnabled,getAnimations()," + "getElementById(),getElementsByClassName(),getElementsByName(),getElementsByTagName()," + "getElementsByTagNameNS(),getRootNode(),getSelection(),hasChildNodes(),hasFocus()," + "hasStorageAccess(),head,hidden,images,implementation,importNode(),inputEncoding,insertBefore()," @@ -5933,8 +5937,9 @@ public void slot() throws Exception { + "onselectionchange,onselectstart,onslotchange,onstalled,onsubmit,onsuspend,ontimeupdate,ontoggle," + "ontransitioncancel,ontransitionend,ontransitionrun,ontransitionstart,onvisibilitychange," + "onvolumechange,onwaiting,onwebkitanimationend,onwebkitanimationiteration,onwebkitanimationstart," - + "onwebkittransitionend,onwheel,open(),ownerDocument,parentElement,parentNode,plugins," - + "pointerLockElement,preferredStyleSheetSet,prepend(),previousSibling,PROCESSING_INSTRUCTION_NODE," + + "onwebkittransitionend,onwheel,open(),ownerDocument,parentElement,parentNode," + + "pictureInPictureElement,pictureInPictureEnabled,plugins,pointerLockElement," + + "preferredStyleSheetSet,prepend(),previousSibling,PROCESSING_INSTRUCTION_NODE," + "queryCommandEnabled(),queryCommandIndeterm(),queryCommandState(),queryCommandSupported()," + "queryCommandValue(),querySelector(),querySelectorAll(),readyState,referrer,releaseCapture()," + "releaseEvents(),removeChild(),removeEventListener(),replaceChild(),replaceChildren()," @@ -6120,8 +6125,8 @@ public void document() throws Exception { + "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC,DOCUMENT_POSITION_PRECEDING,DOCUMENT_TYPE_NODE," + "documentElement,documentURI,domain,ELEMENT_NODE,elementFromPoint(),elementsFromPoint(),embeds," + "enableStyleSheetsForSet(),ENTITY_NODE,ENTITY_REFERENCE_NODE,evaluate(),execCommand()," - + "exitFullscreen(),exitPointerLock(),fgColor,firstChild,firstElementChild,fonts,forms," - + "fragmentDirective,fullscreen,fullscreenElement,fullscreenEnabled,getAnimations()," + + "exitFullscreen(),exitPictureInPicture(),exitPointerLock(),fgColor,firstChild,firstElementChild," + + "fonts,forms,fragmentDirective,fullscreen,fullscreenElement,fullscreenEnabled,getAnimations()," + "getElementById(),getElementsByClassName(),getElementsByName(),getElementsByTagName()," + "getElementsByTagNameNS(),getRootNode(),getSelection(),hasChildNodes(),hasFocus()," + "hasStorageAccess(),head,hidden,images,implementation,importNode(),inputEncoding,insertBefore()," @@ -6145,13 +6150,14 @@ public void document() throws Exception { + "ontimeupdate,ontoggle,ontransitioncancel,ontransitionend,ontransitionrun,ontransitionstart," + "onvisibilitychange,onvolumechange,onwaiting,onwebkitanimationend,onwebkitanimationiteration," + "onwebkitanimationstart,onwebkittransitionend,onwheel,open(),ownerDocument,parentElement," - + "parentNode,plugins,pointerLockElement,preferredStyleSheetSet,prepend(),previousSibling," - + "PROCESSING_INSTRUCTION_NODE,queryCommandEnabled(),queryCommandIndeterm(),queryCommandState()," - + "queryCommandSupported(),queryCommandValue(),querySelector(),querySelectorAll(),readyState," - + "referrer,releaseCapture(),releaseEvents(),removeChild(),removeEventListener(),replaceChild()," - + "replaceChildren(),requestStorageAccess(),rootElement,scripts,scrollingElement," - + "selectedStyleSheetSet,startViewTransition(),styleSheets,styleSheetSets,TEXT_NODE,textContent," - + "timeline,title,URL,visibilityState,vlinkColor,write()," + + "parentNode,pictureInPictureElement,pictureInPictureEnabled,plugins,pointerLockElement," + + "preferredStyleSheetSet,prepend(),previousSibling,PROCESSING_INSTRUCTION_NODE," + + "queryCommandEnabled(),queryCommandIndeterm(),queryCommandState(),queryCommandSupported()," + + "queryCommandValue(),querySelector(),querySelectorAll(),readyState,referrer,releaseCapture()," + + "releaseEvents(),removeChild(),removeEventListener(),replaceChild(),replaceChildren()," + + "requestStorageAccess(),rootElement,scripts,scrollingElement,selectedStyleSheetSet," + + "startViewTransition(),styleSheets,styleSheetSets,TEXT_NODE,textContent,timeline,title,URL," + + "visibilityState,vlinkColor,write()," + "writeln()", FF_ESR = "activeElement,addEventListener(),adoptedStyleSheets,adoptNode(),alinkColor,all,anchors,append()," + "appendChild(),applets,ATTRIBUTE_NODE,baseURI,bgColor,body,captureEvents()," @@ -6455,8 +6461,8 @@ public void htmlDocument() throws Exception { + "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC,DOCUMENT_POSITION_PRECEDING,DOCUMENT_TYPE_NODE," + "documentElement,documentURI,domain,ELEMENT_NODE,elementFromPoint(),elementsFromPoint(),embeds," + "enableStyleSheetsForSet(),ENTITY_NODE,ENTITY_REFERENCE_NODE,evaluate(),execCommand()," - + "exitFullscreen(),exitPointerLock(),fgColor,firstChild,firstElementChild,fonts,forms," - + "fragmentDirective,fullscreen,fullscreenElement,fullscreenEnabled,getAnimations()," + + "exitFullscreen(),exitPictureInPicture(),exitPointerLock(),fgColor,firstChild,firstElementChild," + + "fonts,forms,fragmentDirective,fullscreen,fullscreenElement,fullscreenEnabled,getAnimations()," + "getElementById(),getElementsByClassName(),getElementsByName(),getElementsByTagName()," + "getElementsByTagNameNS(),getRootNode(),getSelection(),hasChildNodes(),hasFocus()," + "hasStorageAccess(),head,hidden,images,implementation,importNode(),inputEncoding,insertBefore()," @@ -6479,8 +6485,9 @@ public void htmlDocument() throws Exception { + "onselectionchange,onselectstart,onslotchange,onstalled,onsubmit,onsuspend,ontimeupdate,ontoggle," + "ontransitioncancel,ontransitionend,ontransitionrun,ontransitionstart,onvisibilitychange," + "onvolumechange,onwaiting,onwebkitanimationend,onwebkitanimationiteration,onwebkitanimationstart," - + "onwebkittransitionend,onwheel,open(),ownerDocument,parentElement,parentNode,plugins," - + "pointerLockElement,preferredStyleSheetSet,prepend(),previousSibling,PROCESSING_INSTRUCTION_NODE," + + "onwebkittransitionend,onwheel,open(),ownerDocument,parentElement,parentNode," + + "pictureInPictureElement,pictureInPictureEnabled,plugins,pointerLockElement," + + "preferredStyleSheetSet,prepend(),previousSibling,PROCESSING_INSTRUCTION_NODE," + "queryCommandEnabled(),queryCommandIndeterm(),queryCommandState(),queryCommandSupported()," + "queryCommandValue(),querySelector(),querySelectorAll(),readyState,referrer,releaseCapture()," + "releaseEvents(),removeChild(),removeEventListener(),replaceChild(),replaceChildren()," @@ -10684,16 +10691,16 @@ public void mimeType() throws Exception { + "webdriver") @HtmlUnitNYI(CHROME = "appCodeName,appName,appVersion,connection,cookieEnabled,doNotTrack,geolocation," + "javaEnabled(),language,languages,mediaDevices,mimeTypes,onLine,pdfViewerEnabled,platform," - + "plugins,product,productSub,userAgent,vendor,vendorSub", + + "plugins,product,productSub,sendBeacon(),userAgent,vendor,vendorSub", EDGE = "appCodeName,appName,appVersion,connection,cookieEnabled,doNotTrack,geolocation," + "javaEnabled(),language,languages,mediaDevices,mimeTypes,onLine,pdfViewerEnabled,platform," - + "plugins,product,productSub,userAgent,vendor,vendorSub", + + "plugins,product,productSub,sendBeacon(),userAgent,vendor,vendorSub", FF = "appCodeName,appName,appVersion,buildID,cookieEnabled,doNotTrack,geolocation,javaEnabled()," + "language,languages,mediaDevices,mimeTypes,onLine,oscpu,pdfViewerEnabled,platform,plugins," - + "product,productSub,taintEnabled(),userAgent,vendor,vendorSub", + + "product,productSub,sendBeacon(),taintEnabled(),userAgent,vendor,vendorSub", FF_ESR = "appCodeName,appName,appVersion,buildID,cookieEnabled,doNotTrack,geolocation," + "javaEnabled(),language,languages,mediaDevices,mimeTypes,onLine,oscpu,pdfViewerEnabled," - + "platform,plugins,product,productSub,taintEnabled(),userAgent,vendor,vendorSub") + + "platform,plugins,product,productSub,sendBeacon(),taintEnabled(),userAgent,vendor,vendorSub") public void navigator() throws Exception { testString("", "navigator"); } diff --git a/src/test/java/org/htmlunit/general/huge/ElementClosesElement2Test.java b/src/test/java/org/htmlunit/general/huge/ElementClosesElement2Test.java index 77ec90a4d18..cecb34b8188 100644 --- a/src/test/java/org/htmlunit/general/huge/ElementClosesElement2Test.java +++ b/src/test/java/org/htmlunit/general/huge/ElementClosesElement2Test.java @@ -55,6 +55,18 @@ public class ElementClosesElement2Test extends WebDriverTestCase { public static Collection data() throws Exception { final List list = new ArrayList<>(); final List strings = new ArrayList<>(DefaultElementFactory.SUPPORTED_TAGS_); + + // no longer supported but we still like to test this + strings.add("blink"); + strings.add("ilayer"); + strings.add("layer"); + strings.add("multicol"); + strings.add("nextid"); + strings.add("nolayer"); + strings.add("sound"); + strings.add("spacer"); + strings.add("xml"); + strings.add("unknown"); for (final String parent : strings) { @@ -210,6 +222,11 @@ void _area_p() throws Exception { test("area", "p"); } + @Alerts("0") + void _body_a() throws Exception { + test("body", "a"); + } + @Alerts("0") void _body_abbr() throws Exception { test("body", "abbr"); @@ -220,11 +237,6 @@ void _body_acronym() throws Exception { test("body", "acronym"); } - @Alerts("0") - void _body_a() throws Exception { - test("body", "a"); - } - @Alerts("0") void _body_address() throws Exception { test("body", "address"); @@ -250,6 +262,11 @@ void _body_audio() throws Exception { test("body", "audio"); } + @Alerts("0") + void _body_b() throws Exception { + test("body", "b"); + } + @Alerts("0") void _body_base() throws Exception { test("body", "base"); @@ -275,6 +292,11 @@ void _body_big() throws Exception { test("body", "big"); } + @Alerts("0") + void _body_blink() throws Exception { + test("body", "blink"); + } + @Alerts("0") void _body_blockquote() throws Exception { test("body", "blockquote"); @@ -285,11 +307,6 @@ void _body_body() throws Exception { test("body", "body"); } - @Alerts("0") - void _body_b() throws Exception { - test("body", "b"); - } - @Alerts("0") void _body_button() throws Exception { test("body", "button"); @@ -320,6 +337,16 @@ void _body_code() throws Exception { test("body", "code"); } + @Alerts("0") + void _body_col() throws Exception { + test("body", "col"); + } + + @Alerts("0") + void _body_colgroup() throws Exception { + test("body", "colgroup"); + } + @Alerts("0") void _body_data() throws Exception { test("body", "data"); @@ -330,11 +357,6 @@ void _body_datalist() throws Exception { test("body", "datalist"); } - @Alerts("0") - void _body_dfn() throws Exception { - test("body", "dfn"); - } - @Alerts("0") void _body_dd() throws Exception { test("body", "dd"); @@ -350,6 +372,11 @@ void _body_details() throws Exception { test("body", "details"); } + @Alerts("0") + void _body_dfn() throws Exception { + test("body", "dfn"); + } + @Alerts("0") void _body_dialog() throws Exception { test("body", "dialog"); @@ -376,13 +403,13 @@ void _body_dt() throws Exception { } @Alerts("0") - void _body_embed() throws Exception { - test("body", "embed"); + void _body_em() throws Exception { + test("body", "em"); } @Alerts("0") - void _body_em() throws Exception { - test("body", "em"); + void _body_embed() throws Exception { + test("body", "embed"); } @Alerts("0") @@ -406,13 +433,13 @@ void _body_font() throws Exception { } @Alerts("0") - void _body_form() throws Exception { - test("body", "form"); + void _body_footer() throws Exception { + test("body", "footer"); } @Alerts("0") - void _body_footer() throws Exception { - test("body", "footer"); + void _body_form() throws Exception { + test("body", "form"); } @Alerts("0") @@ -425,16 +452,6 @@ void _body_frameset() throws Exception { test("body", "frameset"); } - @Alerts("0") - void _body_head() throws Exception { - test("body", "head"); - } - - @Alerts("0") - void _body_header() throws Exception { - test("body", "header"); - } - @Alerts("0") void _body_h1() throws Exception { test("body", "h1"); @@ -465,6 +482,16 @@ void _body_h6() throws Exception { test("body", "h6"); } + @Alerts("0") + void _body_head() throws Exception { + test("body", "head"); + } + + @Alerts("0") + void _body_header() throws Exception { + test("body", "header"); + } + @Alerts("0") void _body_hgroup() throws Exception { test("body", "hgroup"); @@ -481,18 +508,18 @@ void _body_html() throws Exception { } @Alerts("0") - void _body_iframe() throws Exception { - test("body", "iframe"); + void _body_i() throws Exception { + test("body", "i"); } @Alerts("0") - void _body_q() throws Exception { - test("body", "q"); + void _body_iframe() throws Exception { + test("body", "iframe"); } @Alerts("0") - void _body_img() throws Exception { - test("body", "img"); + void _body_ilayer() throws Exception { + test("body", "ilayer"); } @Alerts("0") @@ -500,6 +527,11 @@ void _body_image() throws Exception { test("body", "image"); } + @Alerts("0") + void _body_img() throws Exception { + test("body", "img"); + } + @Alerts("0") void _body_input() throws Exception { test("body", "input"); @@ -510,11 +542,6 @@ void _body_ins() throws Exception { test("body", "ins"); } - @Alerts("0") - void _body_i() throws Exception { - test("body", "i"); - } - @Alerts("0") void _body_kbd() throws Exception { test("body", "kbd"); @@ -535,11 +562,6 @@ void _body_legend() throws Exception { test("body", "legend"); } - @Alerts("0") - void _body_listing() throws Exception { - test("body", "listing"); - } - @Alerts("0") void _body_li() throws Exception { test("body", "li"); @@ -550,6 +572,11 @@ void _body_link() throws Exception { test("body", "link"); } + @Alerts("0") + void _body_listing() throws Exception { + test("body", "listing"); + } + @Alerts("0") void _body_main() throws Exception { test("body", "main"); @@ -585,11 +612,21 @@ void _body_meter() throws Exception { test("body", "meter"); } + @Alerts("0") + void _body_multicol() throws Exception { + test("body", "multicol"); + } + @Alerts("0") void _body_nav() throws Exception { test("body", "nav"); } + @Alerts("0") + void _body_nextid() throws Exception { + test("body", "nextid"); + } + @Alerts("0") void _body_nobr() throws Exception { test("body", "nobr"); @@ -665,6 +702,11 @@ void _body_progress() throws Exception { test("body", "progress"); } + @Alerts("0") + void _body_q() throws Exception { + test("body", "q"); + } + @Alerts("0") void _body_rb() throws Exception { test("body", "rb"); @@ -725,11 +767,21 @@ void _body_small() throws Exception { test("body", "small"); } + @Alerts("0") + void _body_sound() throws Exception { + test("body", "sound"); + } + @Alerts("0") void _body_source() throws Exception { test("body", "source"); } + @Alerts("0") + void _body_spacer() throws Exception { + test("body", "spacer"); + } + @Alerts("0") void _body_span() throws Exception { test("body", "span"); @@ -775,16 +827,6 @@ void _body_table() throws Exception { test("body", "table"); } - @Alerts("0") - void _body_col() throws Exception { - test("body", "col"); - } - - @Alerts("0") - void _body_colgroup() throws Exception { - test("body", "colgroup"); - } - @Alerts("0") void _body_tbody() throws Exception { test("body", "tbody"); @@ -796,13 +838,8 @@ void _body_td() throws Exception { } @Alerts("0") - void _body_th() throws Exception { - test("body", "th"); - } - - @Alerts("0") - void _body_tr() throws Exception { - test("body", "tr"); + void _body_template() throws Exception { + test("body", "template"); } @Alerts("0") @@ -816,18 +853,13 @@ void _body_tfoot() throws Exception { } @Alerts("0") - void _body_thead() throws Exception { - test("body", "thead"); - } - - @Alerts("0") - void _body_tt() throws Exception { - test("body", "tt"); + void _body_th() throws Exception { + test("body", "th"); } @Alerts("0") - void _body_template() throws Exception { - test("body", "template"); + void _body_thead() throws Exception { + test("body", "thead"); } @Alerts("0") @@ -840,11 +872,21 @@ void _body_title() throws Exception { test("body", "title"); } + @Alerts("0") + void _body_tr() throws Exception { + test("body", "tr"); + } + @Alerts("0") void _body_track() throws Exception { test("body", "track"); } + @Alerts("0") + void _body_tt() throws Exception { + test("body", "tt"); + } + @Alerts("0") void _body_u() throws Exception { test("body", "u"); @@ -855,6 +897,11 @@ void _body_ul() throws Exception { test("body", "ul"); } + @Alerts("0") + void _body_unknown() throws Exception { + test("body", "unknown"); + } + @Alerts("0") void _body_var() throws Exception { test("body", "var"); @@ -871,13 +918,13 @@ void _body_wbr() throws Exception { } @Alerts("0") - void _body_xmp() throws Exception { - test("body", "xmp"); + void _body_xml() throws Exception { + test("body", "xml"); } @Alerts("0") - void _body_unknown() throws Exception { - test("body", "unknown"); + void _body_xmp() throws Exception { + test("body", "xmp"); } @Alerts("2") @@ -900,6 +947,11 @@ void _embed_p() throws Exception { test("embed", "p"); } + @Alerts("0") + void _frameset_a() throws Exception { + test("frameset", "a"); + } + @Alerts("0") void _frameset_abbr() throws Exception { test("frameset", "abbr"); @@ -910,11 +962,6 @@ void _frameset_acronym() throws Exception { test("frameset", "acronym"); } - @Alerts("0") - void _frameset_a() throws Exception { - test("frameset", "a"); - } - @Alerts("0") void _frameset_address() throws Exception { test("frameset", "address"); @@ -940,6 +987,11 @@ void _frameset_audio() throws Exception { test("frameset", "audio"); } + @Alerts("0") + void _frameset_b() throws Exception { + test("frameset", "b"); + } + @Alerts("0") void _frameset_base() throws Exception { test("frameset", "base"); @@ -965,6 +1017,11 @@ void _frameset_big() throws Exception { test("frameset", "big"); } + @Alerts("0") + void _frameset_blink() throws Exception { + test("frameset", "blink"); + } + @Alerts("0") void _frameset_blockquote() throws Exception { test("frameset", "blockquote"); @@ -975,11 +1032,6 @@ void _frameset_body() throws Exception { test("frameset", "body"); } - @Alerts("0") - void _frameset_b() throws Exception { - test("frameset", "b"); - } - @Alerts("0") void _frameset_br() throws Exception { test("frameset", "br"); @@ -1015,6 +1067,16 @@ void _frameset_code() throws Exception { test("frameset", "code"); } + @Alerts("0") + void _frameset_col() throws Exception { + test("frameset", "col"); + } + + @Alerts("0") + void _frameset_colgroup() throws Exception { + test("frameset", "colgroup"); + } + @Alerts("0") void _frameset_data() throws Exception { test("frameset", "data"); @@ -1025,11 +1087,6 @@ void _frameset_datalist() throws Exception { test("frameset", "datalist"); } - @Alerts("0") - void _frameset_dfn() throws Exception { - test("frameset", "dfn"); - } - @Alerts("0") void _frameset_dd() throws Exception { test("frameset", "dd"); @@ -1045,6 +1102,11 @@ void _frameset_details() throws Exception { test("frameset", "details"); } + @Alerts("0") + void _frameset_dfn() throws Exception { + test("frameset", "dfn"); + } + @Alerts("0") void _frameset_dialog() throws Exception { test("frameset", "dialog"); @@ -1071,13 +1133,13 @@ void _frameset_dt() throws Exception { } @Alerts("0") - void _frameset_embed() throws Exception { - test("frameset", "embed"); + void _frameset_em() throws Exception { + test("frameset", "em"); } @Alerts("0") - void _frameset_em() throws Exception { - test("frameset", "em"); + void _frameset_embed() throws Exception { + test("frameset", "embed"); } @Alerts("0") @@ -1101,13 +1163,13 @@ void _frameset_font() throws Exception { } @Alerts("0") - void _frameset_form() throws Exception { - test("frameset", "form"); + void _frameset_footer() throws Exception { + test("frameset", "footer"); } @Alerts("0") - void _frameset_footer() throws Exception { - test("frameset", "footer"); + void _frameset_form() throws Exception { + test("frameset", "form"); } @Alerts("0") @@ -1120,16 +1182,6 @@ void _frameset_frameset() throws Exception { test("frameset", "frameset"); } - @Alerts("0") - void _frameset_head() throws Exception { - test("frameset", "head"); - } - - @Alerts("0") - void _frameset_header() throws Exception { - test("frameset", "header"); - } - @Alerts("0") void _frameset_h1() throws Exception { test("frameset", "h1"); @@ -1161,13 +1213,23 @@ void _frameset_h6() throws Exception { } @Alerts("0") - void _frameset_hgroup() throws Exception { - test("frameset", "hgroup"); + void _frameset_head() throws Exception { + test("frameset", "head"); } @Alerts("0") - void _frameset_hr() throws Exception { - test("frameset", "hr"); + void _frameset_header() throws Exception { + test("frameset", "header"); + } + + @Alerts("0") + void _frameset_hgroup() throws Exception { + test("frameset", "hgroup"); + } + + @Alerts("0") + void _frameset_hr() throws Exception { + test("frameset", "hr"); } @Alerts("0") @@ -1176,18 +1238,18 @@ void _frameset_html() throws Exception { } @Alerts("0") - void _frameset_iframe() throws Exception { - test("frameset", "iframe"); + void _frameset_i() throws Exception { + test("frameset", "i"); } @Alerts("0") - void _frameset_q() throws Exception { - test("frameset", "q"); + void _frameset_iframe() throws Exception { + test("frameset", "iframe"); } @Alerts("0") - void _frameset_img() throws Exception { - test("frameset", "img"); + void _frameset_ilayer() throws Exception { + test("frameset", "ilayer"); } @Alerts("0") @@ -1195,6 +1257,11 @@ void _frameset_image() throws Exception { test("frameset", "image"); } + @Alerts("0") + void _frameset_img() throws Exception { + test("frameset", "img"); + } + @Alerts("0") void _frameset_input() throws Exception { test("frameset", "input"); @@ -1205,11 +1272,6 @@ void _frameset_ins() throws Exception { test("frameset", "ins"); } - @Alerts("0") - void _frameset_i() throws Exception { - test("frameset", "i"); - } - @Alerts("0") void _frameset_kbd() throws Exception { test("frameset", "kbd"); @@ -1230,11 +1292,6 @@ void _frameset_legend() throws Exception { test("frameset", "legend"); } - @Alerts("0") - void _frameset_listing() throws Exception { - test("frameset", "listing"); - } - @Alerts("0") void _frameset_li() throws Exception { test("frameset", "li"); @@ -1245,6 +1302,11 @@ void _frameset_link() throws Exception { test("frameset", "link"); } + @Alerts("0") + void _frameset_listing() throws Exception { + test("frameset", "listing"); + } + @Alerts("0") void _frameset_main() throws Exception { test("frameset", "main"); @@ -1280,11 +1342,21 @@ void _frameset_meter() throws Exception { test("frameset", "meter"); } + @Alerts("0") + void _frameset_multicol() throws Exception { + test("frameset", "multicol"); + } + @Alerts("0") void _frameset_nav() throws Exception { test("frameset", "nav"); } + @Alerts("0") + void _frameset_nextid() throws Exception { + test("frameset", "nextid"); + } + @Alerts("0") void _frameset_nobr() throws Exception { test("frameset", "nobr"); @@ -1365,6 +1437,11 @@ void _frameset_progress() throws Exception { test("frameset", "progress"); } + @Alerts("0") + void _frameset_q() throws Exception { + test("frameset", "q"); + } + @Alerts("0") void _frameset_rb() throws Exception { test("frameset", "rb"); @@ -1425,11 +1502,21 @@ void _frameset_small() throws Exception { test("frameset", "small"); } + @Alerts("0") + void _frameset_sound() throws Exception { + test("frameset", "sound"); + } + @Alerts("0") void _frameset_source() throws Exception { test("frameset", "source"); } + @Alerts("0") + void _frameset_spacer() throws Exception { + test("frameset", "spacer"); + } + @Alerts("0") void _frameset_span() throws Exception { test("frameset", "span"); @@ -1475,16 +1562,6 @@ void _frameset_table() throws Exception { test("frameset", "table"); } - @Alerts("0") - void _frameset_col() throws Exception { - test("frameset", "col"); - } - - @Alerts("0") - void _frameset_colgroup() throws Exception { - test("frameset", "colgroup"); - } - @Alerts("0") void _frameset_tbody() throws Exception { test("frameset", "tbody"); @@ -1496,13 +1573,8 @@ void _frameset_td() throws Exception { } @Alerts("0") - void _frameset_th() throws Exception { - test("frameset", "th"); - } - - @Alerts("0") - void _frameset_tr() throws Exception { - test("frameset", "tr"); + void _frameset_template() throws Exception { + test("frameset", "template"); } @Alerts("0") @@ -1516,18 +1588,13 @@ void _frameset_tfoot() throws Exception { } @Alerts("0") - void _frameset_thead() throws Exception { - test("frameset", "thead"); - } - - @Alerts("0") - void _frameset_tt() throws Exception { - test("frameset", "tt"); + void _frameset_th() throws Exception { + test("frameset", "th"); } @Alerts("0") - void _frameset_template() throws Exception { - test("frameset", "template"); + void _frameset_thead() throws Exception { + test("frameset", "thead"); } @Alerts("0") @@ -1540,11 +1607,21 @@ void _frameset_title() throws Exception { test("frameset", "title"); } + @Alerts("0") + void _frameset_tr() throws Exception { + test("frameset", "tr"); + } + @Alerts("0") void _frameset_track() throws Exception { test("frameset", "track"); } + @Alerts("0") + void _frameset_tt() throws Exception { + test("frameset", "tt"); + } + @Alerts("0") void _frameset_u() throws Exception { test("frameset", "u"); @@ -1555,6 +1632,11 @@ void _frameset_ul() throws Exception { test("frameset", "ul"); } + @Alerts("0") + void _frameset_unknown() throws Exception { + test("frameset", "unknown"); + } + @Alerts("0") void _frameset_var() throws Exception { test("frameset", "var"); @@ -1570,14 +1652,19 @@ void _frameset_wbr() throws Exception { test("frameset", "wbr"); } + @Alerts("0") + void _frameset_xml() throws Exception { + test("frameset", "xml"); + } + @Alerts("0") void _frameset_xmp() throws Exception { test("frameset", "xmp"); } - @Alerts("0") - void _frameset_unknown() throws Exception { - test("frameset", "unknown"); + @Alerts("2") + void _head_a() throws Exception { + test("head", "a"); } @Alerts("2") @@ -1590,11 +1677,6 @@ void _head_acronym() throws Exception { test("head", "acronym"); } - @Alerts("2") - void _head_a() throws Exception { - test("head", "a"); - } - @Alerts("2") void _head_address() throws Exception { test("head", "address"); @@ -1620,6 +1702,11 @@ void _head_audio() throws Exception { test("head", "audio"); } + @Alerts("2") + void _head_b() throws Exception { + test("head", "b"); + } + @Alerts("2") void _head_base() throws Exception { test("head", "base"); @@ -1645,6 +1732,11 @@ void _head_big() throws Exception { test("head", "big"); } + @Alerts("2") + void _head_blink() throws Exception { + test("head", "blink"); + } + @Alerts("2") void _head_blockquote() throws Exception { test("head", "blockquote"); @@ -1655,11 +1747,6 @@ void _head_body() throws Exception { test("head", "body"); } - @Alerts("2") - void _head_b() throws Exception { - test("head", "b"); - } - @Alerts("2") void _head_br() throws Exception { test("head", "br"); @@ -1695,6 +1782,16 @@ void _head_code() throws Exception { test("head", "code"); } + @Alerts("2") + void _head_col() throws Exception { + test("head", "col"); + } + + @Alerts("2") + void _head_colgroup() throws Exception { + test("head", "colgroup"); + } + @Alerts("2") void _head_data() throws Exception { test("head", "data"); @@ -1705,11 +1802,6 @@ void _head_datalist() throws Exception { test("head", "datalist"); } - @Alerts("2") - void _head_dfn() throws Exception { - test("head", "dfn"); - } - @Alerts("2") void _head_dd() throws Exception { test("head", "dd"); @@ -1725,6 +1817,11 @@ void _head_details() throws Exception { test("head", "details"); } + @Alerts("2") + void _head_dfn() throws Exception { + test("head", "dfn"); + } + @Alerts("2") void _head_dialog() throws Exception { test("head", "dialog"); @@ -1751,13 +1848,13 @@ void _head_dt() throws Exception { } @Alerts("2") - void _head_embed() throws Exception { - test("head", "embed"); + void _head_em() throws Exception { + test("head", "em"); } @Alerts("2") - void _head_em() throws Exception { - test("head", "em"); + void _head_embed() throws Exception { + test("head", "embed"); } @Alerts("2") @@ -1781,13 +1878,13 @@ void _head_font() throws Exception { } @Alerts("2") - void _head_form() throws Exception { - test("head", "form"); + void _head_footer() throws Exception { + test("head", "footer"); } @Alerts("2") - void _head_footer() throws Exception { - test("head", "footer"); + void _head_form() throws Exception { + test("head", "form"); } @Alerts("2") @@ -1800,16 +1897,6 @@ void _head_frameset() throws Exception { test("head", "frameset"); } - @Alerts("2") - void _head_head() throws Exception { - test("head", "head"); - } - - @Alerts("2") - void _head_header() throws Exception { - test("head", "header"); - } - @Alerts("2") void _head_h1() throws Exception { test("head", "h1"); @@ -1840,6 +1927,16 @@ void _head_h6() throws Exception { test("head", "h6"); } + @Alerts("2") + void _head_head() throws Exception { + test("head", "head"); + } + + @Alerts("2") + void _head_header() throws Exception { + test("head", "header"); + } + @Alerts("2") void _head_hgroup() throws Exception { test("head", "hgroup"); @@ -1856,18 +1953,18 @@ void _head_html() throws Exception { } @Alerts("2") - void _head_iframe() throws Exception { - test("head", "iframe"); + void _head_i() throws Exception { + test("head", "i"); } @Alerts("2") - void _head_q() throws Exception { - test("head", "q"); + void _head_iframe() throws Exception { + test("head", "iframe"); } @Alerts("2") - void _head_img() throws Exception { - test("head", "img"); + void _head_ilayer() throws Exception { + test("head", "ilayer"); } @Alerts("2") @@ -1875,6 +1972,11 @@ void _head_image() throws Exception { test("head", "image"); } + @Alerts("2") + void _head_img() throws Exception { + test("head", "img"); + } + @Alerts("2") void _head_input() throws Exception { test("head", "input"); @@ -1885,11 +1987,6 @@ void _head_ins() throws Exception { test("head", "ins"); } - @Alerts("2") - void _head_i() throws Exception { - test("head", "i"); - } - @Alerts("2") void _head_kbd() throws Exception { test("head", "kbd"); @@ -1910,11 +2007,6 @@ void _head_legend() throws Exception { test("head", "legend"); } - @Alerts("2") - void _head_listing() throws Exception { - test("head", "listing"); - } - @Alerts("2") void _head_li() throws Exception { test("head", "li"); @@ -1925,6 +2017,11 @@ void _head_link() throws Exception { test("head", "link"); } + @Alerts("2") + void _head_listing() throws Exception { + test("head", "listing"); + } + @Alerts("2") void _head_main() throws Exception { test("head", "main"); @@ -1960,11 +2057,21 @@ void _head_meter() throws Exception { test("head", "meter"); } + @Alerts("2") + void _head_multicol() throws Exception { + test("head", "multicol"); + } + @Alerts("2") void _head_nav() throws Exception { test("head", "nav"); } + @Alerts("2") + void _head_nextid() throws Exception { + test("head", "nextid"); + } + @Alerts("2") void _head_nobr() throws Exception { test("head", "nobr"); @@ -2045,6 +2152,11 @@ void _head_progress() throws Exception { test("head", "progress"); } + @Alerts("2") + void _head_q() throws Exception { + test("head", "q"); + } + @Alerts("2") void _head_rb() throws Exception { test("head", "rb"); @@ -2105,11 +2217,21 @@ void _head_small() throws Exception { test("head", "small"); } + @Alerts("2") + void _head_sound() throws Exception { + test("head", "sound"); + } + @Alerts("2") void _head_source() throws Exception { test("head", "source"); } + @Alerts("2") + void _head_spacer() throws Exception { + test("head", "spacer"); + } + @Alerts("2") void _head_span() throws Exception { test("head", "span"); @@ -2155,16 +2277,6 @@ void _head_table() throws Exception { test("head", "table"); } - @Alerts("2") - void _head_col() throws Exception { - test("head", "col"); - } - - @Alerts("2") - void _head_colgroup() throws Exception { - test("head", "colgroup"); - } - @Alerts("2") void _head_tbody() throws Exception { test("head", "tbody"); @@ -2176,13 +2288,8 @@ void _head_td() throws Exception { } @Alerts("2") - void _head_th() throws Exception { - test("head", "th"); - } - - @Alerts("2") - void _head_tr() throws Exception { - test("head", "tr"); + void _head_template() throws Exception { + test("head", "template"); } @Alerts("2") @@ -2196,18 +2303,13 @@ void _head_tfoot() throws Exception { } @Alerts("2") - void _head_thead() throws Exception { - test("head", "thead"); - } - - @Alerts("2") - void _head_tt() throws Exception { - test("head", "tt"); + void _head_th() throws Exception { + test("head", "th"); } @Alerts("2") - void _head_template() throws Exception { - test("head", "template"); + void _head_thead() throws Exception { + test("head", "thead"); } @Alerts("2") @@ -2220,11 +2322,21 @@ void _head_title() throws Exception { test("head", "title"); } + @Alerts("2") + void _head_tr() throws Exception { + test("head", "tr"); + } + @Alerts("2") void _head_track() throws Exception { test("head", "track"); } + @Alerts("2") + void _head_tt() throws Exception { + test("head", "tt"); + } + @Alerts("2") void _head_u() throws Exception { test("head", "u"); @@ -2235,6 +2347,11 @@ void _head_ul() throws Exception { test("head", "ul"); } + @Alerts("2") + void _head_unknown() throws Exception { + test("head", "unknown"); + } + @Alerts("2") void _head_var() throws Exception { test("head", "var"); @@ -2251,13 +2368,13 @@ void _head_wbr() throws Exception { } @Alerts("2") - void _head_xmp() throws Exception { - test("head", "xmp"); + void _head_xml() throws Exception { + test("head", "xml"); } @Alerts("2") - void _head_unknown() throws Exception { - test("head", "unknown"); + void _head_xmp() throws Exception { + test("head", "xmp"); } @Alerts("2") @@ -2270,6 +2387,11 @@ void _hr_p() throws Exception { test("hr", "p"); } + @Alerts("0") + void _html_a() throws Exception { + test("html", "a"); + } + @Alerts("0") void _html_abbr() throws Exception { test("html", "abbr"); @@ -2280,11 +2402,6 @@ void _html_acronym() throws Exception { test("html", "acronym"); } - @Alerts("0") - void _html_a() throws Exception { - test("html", "a"); - } - @Alerts("0") void _html_address() throws Exception { test("html", "address"); @@ -2310,6 +2427,11 @@ void _html_audio() throws Exception { test("html", "audio"); } + @Alerts("0") + void _html_b() throws Exception { + test("html", "b"); + } + @Alerts("0") void _html_base() throws Exception { test("html", "base"); @@ -2335,6 +2457,11 @@ void _html_big() throws Exception { test("html", "big"); } + @Alerts("0") + void _html_blink() throws Exception { + test("html", "blink"); + } + @Alerts("0") void _html_blockquote() throws Exception { test("html", "blockquote"); @@ -2345,11 +2472,6 @@ void _html_body() throws Exception { test("html", "body"); } - @Alerts("0") - void _html_b() throws Exception { - test("html", "b"); - } - @Alerts("0") void _html_button() throws Exception { test("html", "button"); @@ -2380,6 +2502,16 @@ void _html_code() throws Exception { test("html", "code"); } + @Alerts("0") + void _html_col() throws Exception { + test("html", "col"); + } + + @Alerts("0") + void _html_colgroup() throws Exception { + test("html", "colgroup"); + } + @Alerts("0") void _html_data() throws Exception { test("html", "data"); @@ -2390,11 +2522,6 @@ void _html_datalist() throws Exception { test("html", "datalist"); } - @Alerts("0") - void _html_dfn() throws Exception { - test("html", "dfn"); - } - @Alerts("0") void _html_dd() throws Exception { test("html", "dd"); @@ -2410,6 +2537,11 @@ void _html_details() throws Exception { test("html", "details"); } + @Alerts("0") + void _html_dfn() throws Exception { + test("html", "dfn"); + } + @Alerts("0") void _html_dialog() throws Exception { test("html", "dialog"); @@ -2436,13 +2568,13 @@ void _html_dt() throws Exception { } @Alerts("0") - void _html_embed() throws Exception { - test("html", "embed"); + void _html_em() throws Exception { + test("html", "em"); } @Alerts("0") - void _html_em() throws Exception { - test("html", "em"); + void _html_embed() throws Exception { + test("html", "embed"); } @Alerts("0") @@ -2466,13 +2598,13 @@ void _html_font() throws Exception { } @Alerts("0") - void _html_form() throws Exception { - test("html", "form"); + void _html_footer() throws Exception { + test("html", "footer"); } @Alerts("0") - void _html_footer() throws Exception { - test("html", "footer"); + void _html_form() throws Exception { + test("html", "form"); } @Alerts("0") @@ -2485,16 +2617,6 @@ void _html_frameset() throws Exception { test("html", "frameset"); } - @Alerts("0") - void _html_head() throws Exception { - test("html", "head"); - } - - @Alerts("0") - void _html_header() throws Exception { - test("html", "header"); - } - @Alerts("0") void _html_h1() throws Exception { test("html", "h1"); @@ -2525,6 +2647,16 @@ void _html_h6() throws Exception { test("html", "h6"); } + @Alerts("0") + void _html_head() throws Exception { + test("html", "head"); + } + + @Alerts("0") + void _html_header() throws Exception { + test("html", "header"); + } + @Alerts("0") void _html_hgroup() throws Exception { test("html", "hgroup"); @@ -2541,18 +2673,18 @@ void _html_html() throws Exception { } @Alerts("0") - void _html_iframe() throws Exception { - test("html", "iframe"); + void _html_i() throws Exception { + test("html", "i"); } @Alerts("0") - void _html_q() throws Exception { - test("html", "q"); + void _html_iframe() throws Exception { + test("html", "iframe"); } @Alerts("0") - void _html_img() throws Exception { - test("html", "img"); + void _html_ilayer() throws Exception { + test("html", "ilayer"); } @Alerts("0") @@ -2560,6 +2692,11 @@ void _html_image() throws Exception { test("html", "image"); } + @Alerts("0") + void _html_img() throws Exception { + test("html", "img"); + } + @Alerts("0") void _html_input() throws Exception { test("html", "input"); @@ -2570,11 +2707,6 @@ void _html_ins() throws Exception { test("html", "ins"); } - @Alerts("0") - void _html_i() throws Exception { - test("html", "i"); - } - @Alerts("0") void _html_kbd() throws Exception { test("html", "kbd"); @@ -2595,11 +2727,6 @@ void _html_legend() throws Exception { test("html", "legend"); } - @Alerts("0") - void _html_listing() throws Exception { - test("html", "listing"); - } - @Alerts("0") void _html_li() throws Exception { test("html", "li"); @@ -2610,6 +2737,11 @@ void _html_link() throws Exception { test("html", "link"); } + @Alerts("0") + void _html_listing() throws Exception { + test("html", "listing"); + } + @Alerts("0") void _html_main() throws Exception { test("html", "main"); @@ -2645,11 +2777,21 @@ void _html_meter() throws Exception { test("html", "meter"); } + @Alerts("0") + void _html_multicol() throws Exception { + test("html", "multicol"); + } + @Alerts("0") void _html_nav() throws Exception { test("html", "nav"); } + @Alerts("0") + void _html_nextid() throws Exception { + test("html", "nextid"); + } + @Alerts("0") void _html_nobr() throws Exception { test("html", "nobr"); @@ -2725,6 +2867,11 @@ void _html_progress() throws Exception { test("html", "progress"); } + @Alerts("0") + void _html_q() throws Exception { + test("html", "q"); + } + @Alerts("0") void _html_rb() throws Exception { test("html", "rb"); @@ -2785,11 +2932,21 @@ void _html_small() throws Exception { test("html", "small"); } + @Alerts("0") + void _html_sound() throws Exception { + test("html", "sound"); + } + @Alerts("0") void _html_source() throws Exception { test("html", "source"); } + @Alerts("0") + void _html_spacer() throws Exception { + test("html", "spacer"); + } + @Alerts("0") void _html_span() throws Exception { test("html", "span"); @@ -2835,16 +2992,6 @@ void _html_table() throws Exception { test("html", "table"); } - @Alerts("0") - void _html_col() throws Exception { - test("html", "col"); - } - - @Alerts("0") - void _html_colgroup() throws Exception { - test("html", "colgroup"); - } - @Alerts("0") void _html_tbody() throws Exception { test("html", "tbody"); @@ -2856,13 +3003,8 @@ void _html_td() throws Exception { } @Alerts("0") - void _html_th() throws Exception { - test("html", "th"); - } - - @Alerts("0") - void _html_tr() throws Exception { - test("html", "tr"); + void _html_template() throws Exception { + test("html", "template"); } @Alerts("0") @@ -2876,18 +3018,13 @@ void _html_tfoot() throws Exception { } @Alerts("0") - void _html_thead() throws Exception { - test("html", "thead"); - } - - @Alerts("0") - void _html_tt() throws Exception { - test("html", "tt"); + void _html_th() throws Exception { + test("html", "th"); } @Alerts("0") - void _html_template() throws Exception { - test("html", "template"); + void _html_thead() throws Exception { + test("html", "thead"); } @Alerts("0") @@ -2900,11 +3037,21 @@ void _html_title() throws Exception { test("html", "title"); } + @Alerts("0") + void _html_tr() throws Exception { + test("html", "tr"); + } + @Alerts("0") void _html_track() throws Exception { test("html", "track"); } + @Alerts("0") + void _html_tt() throws Exception { + test("html", "tt"); + } + @Alerts("0") void _html_u() throws Exception { test("html", "u"); @@ -2915,6 +3062,11 @@ void _html_ul() throws Exception { test("html", "ul"); } + @Alerts("0") + void _html_unknown() throws Exception { + test("html", "unknown"); + } + @Alerts("0") void _html_var() throws Exception { test("html", "var"); @@ -2931,33 +3083,33 @@ void _html_wbr() throws Exception { } @Alerts("0") - void _html_xmp() throws Exception { - test("html", "xmp"); + void _html_xml() throws Exception { + test("html", "xml"); } @Alerts("0") - void _html_unknown() throws Exception { - test("html", "unknown"); + void _html_xmp() throws Exception { + test("html", "xmp"); } @Alerts("2") - void _img_br() throws Exception { - test("img", "br"); + void _image_br() throws Exception { + test("image", "br"); } @Alerts("2") - void _img_p() throws Exception { - test("img", "p"); + void _image_p() throws Exception { + test("image", "p"); } @Alerts("2") - void _image_br() throws Exception { - test("image", "br"); + void _img_br() throws Exception { + test("img", "br"); } @Alerts("2") - void _image_p() throws Exception { - test("image", "p"); + void _img_p() throws Exception { + test("img", "p"); } @Alerts("2") @@ -3000,6 +3152,11 @@ void _param_p() throws Exception { test("param", "p"); } + @Alerts("0") + void _script_a() throws Exception { + test("script", "a"); + } + @Alerts("0") void _script_abbr() throws Exception { test("script", "abbr"); @@ -3010,11 +3167,6 @@ void _script_acronym() throws Exception { test("script", "acronym"); } - @Alerts("0") - void _script_a() throws Exception { - test("script", "a"); - } - @Alerts("0") void _script_address() throws Exception { test("script", "address"); @@ -3040,6 +3192,11 @@ void _script_audio() throws Exception { test("script", "audio"); } + @Alerts("0") + void _script_b() throws Exception { + test("script", "b"); + } + @Alerts("0") void _script_base() throws Exception { test("script", "base"); @@ -3065,6 +3222,11 @@ void _script_big() throws Exception { test("script", "big"); } + @Alerts("0") + void _script_blink() throws Exception { + test("script", "blink"); + } + @Alerts("0") void _script_blockquote() throws Exception { test("script", "blockquote"); @@ -3075,11 +3237,6 @@ void _script_body() throws Exception { test("script", "body"); } - @Alerts("0") - void _script_b() throws Exception { - test("script", "b"); - } - @Alerts("0") void _script_br() throws Exception { test("script", "br"); @@ -3115,6 +3272,16 @@ void _script_code() throws Exception { test("script", "code"); } + @Alerts("0") + void _script_col() throws Exception { + test("script", "col"); + } + + @Alerts("0") + void _script_colgroup() throws Exception { + test("script", "colgroup"); + } + @Alerts("0") void _script_data() throws Exception { test("script", "data"); @@ -3125,11 +3292,6 @@ void _script_datalist() throws Exception { test("script", "datalist"); } - @Alerts("0") - void _script_dfn() throws Exception { - test("script", "dfn"); - } - @Alerts("0") void _script_dd() throws Exception { test("script", "dd"); @@ -3145,6 +3307,11 @@ void _script_details() throws Exception { test("script", "details"); } + @Alerts("0") + void _script_dfn() throws Exception { + test("script", "dfn"); + } + @Alerts("0") void _script_dialog() throws Exception { test("script", "dialog"); @@ -3171,13 +3338,13 @@ void _script_dt() throws Exception { } @Alerts("0") - void _script_embed() throws Exception { - test("script", "embed"); + void _script_em() throws Exception { + test("script", "em"); } @Alerts("0") - void _script_em() throws Exception { - test("script", "em"); + void _script_embed() throws Exception { + test("script", "embed"); } @Alerts("0") @@ -3201,13 +3368,13 @@ void _script_font() throws Exception { } @Alerts("0") - void _script_form() throws Exception { - test("script", "form"); + void _script_footer() throws Exception { + test("script", "footer"); } @Alerts("0") - void _script_footer() throws Exception { - test("script", "footer"); + void _script_form() throws Exception { + test("script", "form"); } @Alerts("0") @@ -3220,16 +3387,6 @@ void _script_frameset() throws Exception { test("script", "frameset"); } - @Alerts("0") - void _script_head() throws Exception { - test("script", "head"); - } - - @Alerts("0") - void _script_header() throws Exception { - test("script", "header"); - } - @Alerts("0") void _script_h1() throws Exception { test("script", "h1"); @@ -3260,6 +3417,16 @@ void _script_h6() throws Exception { test("script", "h6"); } + @Alerts("0") + void _script_head() throws Exception { + test("script", "head"); + } + + @Alerts("0") + void _script_header() throws Exception { + test("script", "header"); + } + @Alerts("0") void _script_hgroup() throws Exception { test("script", "hgroup"); @@ -3276,18 +3443,18 @@ void _script_html() throws Exception { } @Alerts("0") - void _script_iframe() throws Exception { - test("script", "iframe"); + void _script_i() throws Exception { + test("script", "i"); } @Alerts("0") - void _script_q() throws Exception { - test("script", "q"); + void _script_iframe() throws Exception { + test("script", "iframe"); } @Alerts("0") - void _script_img() throws Exception { - test("script", "img"); + void _script_ilayer() throws Exception { + test("script", "ilayer"); } @Alerts("0") @@ -3295,6 +3462,11 @@ void _script_image() throws Exception { test("script", "image"); } + @Alerts("0") + void _script_img() throws Exception { + test("script", "img"); + } + @Alerts("0") void _script_input() throws Exception { test("script", "input"); @@ -3305,11 +3477,6 @@ void _script_ins() throws Exception { test("script", "ins"); } - @Alerts("0") - void _script_i() throws Exception { - test("script", "i"); - } - @Alerts("0") void _script_kbd() throws Exception { test("script", "kbd"); @@ -3330,11 +3497,6 @@ void _script_legend() throws Exception { test("script", "legend"); } - @Alerts("0") - void _script_listing() throws Exception { - test("script", "listing"); - } - @Alerts("0") void _script_li() throws Exception { test("script", "li"); @@ -3345,6 +3507,11 @@ void _script_link() throws Exception { test("script", "link"); } + @Alerts("0") + void _script_listing() throws Exception { + test("script", "listing"); + } + @Alerts("0") void _script_main() throws Exception { test("script", "main"); @@ -3380,11 +3547,21 @@ void _script_meter() throws Exception { test("script", "meter"); } + @Alerts("0") + void _script_multicol() throws Exception { + test("script", "multicol"); + } + @Alerts("0") void _script_nav() throws Exception { test("script", "nav"); } + @Alerts("0") + void _script_nextid() throws Exception { + test("script", "nextid"); + } + @Alerts("0") void _script_nobr() throws Exception { test("script", "nobr"); @@ -3465,6 +3642,11 @@ void _script_progress() throws Exception { test("script", "progress"); } + @Alerts("0") + void _script_q() throws Exception { + test("script", "q"); + } + @Alerts("0") void _script_rb() throws Exception { test("script", "rb"); @@ -3525,11 +3707,21 @@ void _script_small() throws Exception { test("script", "small"); } + @Alerts("0") + void _script_sound() throws Exception { + test("script", "sound"); + } + @Alerts("0") void _script_source() throws Exception { test("script", "source"); } + @Alerts("0") + void _script_spacer() throws Exception { + test("script", "spacer"); + } + @Alerts("0") void _script_span() throws Exception { test("script", "span"); @@ -3575,16 +3767,6 @@ void _script_table() throws Exception { test("script", "table"); } - @Alerts("0") - void _script_col() throws Exception { - test("script", "col"); - } - - @Alerts("0") - void _script_colgroup() throws Exception { - test("script", "colgroup"); - } - @Alerts("0") void _script_tbody() throws Exception { test("script", "tbody"); @@ -3596,13 +3778,8 @@ void _script_td() throws Exception { } @Alerts("0") - void _script_th() throws Exception { - test("script", "th"); - } - - @Alerts("0") - void _script_tr() throws Exception { - test("script", "tr"); + void _script_template() throws Exception { + test("script", "template"); } @Alerts("0") @@ -3616,18 +3793,13 @@ void _script_tfoot() throws Exception { } @Alerts("0") - void _script_thead() throws Exception { - test("script", "thead"); - } - - @Alerts("0") - void _script_tt() throws Exception { - test("script", "tt"); + void _script_th() throws Exception { + test("script", "th"); } @Alerts("0") - void _script_template() throws Exception { - test("script", "template"); + void _script_thead() throws Exception { + test("script", "thead"); } @Alerts("0") @@ -3640,11 +3812,21 @@ void _script_title() throws Exception { test("script", "title"); } + @Alerts("0") + void _script_tr() throws Exception { + test("script", "tr"); + } + @Alerts("0") void _script_track() throws Exception { test("script", "track"); } + @Alerts("0") + void _script_tt() throws Exception { + test("script", "tt"); + } + @Alerts("0") void _script_u() throws Exception { test("script", "u"); @@ -3655,6 +3837,11 @@ void _script_ul() throws Exception { test("script", "ul"); } + @Alerts("0") + void _script_unknown() throws Exception { + test("script", "unknown"); + } + @Alerts("0") void _script_var() throws Exception { test("script", "var"); @@ -3671,13 +3858,13 @@ void _script_wbr() throws Exception { } @Alerts("0") - void _script_xmp() throws Exception { - test("script", "xmp"); + void _script_xml() throws Exception { + test("script", "xml"); } @Alerts("0") - void _script_unknown() throws Exception { - test("script", "unknown"); + void _script_xmp() throws Exception { + test("script", "xmp"); } @Alerts("2") diff --git a/src/test/java/org/htmlunit/general/huge/ElementClosesElementTest.java b/src/test/java/org/htmlunit/general/huge/ElementClosesElementTest.java index 2e46e379ec3..1358c9d2d79 100644 --- a/src/test/java/org/htmlunit/general/huge/ElementClosesElementTest.java +++ b/src/test/java/org/htmlunit/general/huge/ElementClosesElementTest.java @@ -48,7 +48,7 @@ public class ElementClosesElementTest extends WebDriverTestCase { "command", "col", "colgroup", "embed", "frame", "frameset", "head", "hr", "iframe", "image", "img", "input", "keygen", "link", "meta", "noembed", "noframes", "noscript", "param", "plaintext", - "script", "select", "source", "style", + "script", "source", "style", "table", "tbody", "template", "textarea", "tfoot", "thead", "title", "tr", "track", "wbr", "xmp"); @@ -75,6 +75,18 @@ public class ElementClosesElementTest extends WebDriverTestCase { public static Collection data() throws Exception { final List list = new ArrayList<>(); final List strings = new ArrayList<>(DefaultElementFactory.SUPPORTED_TAGS_); + + // no longer supported but we still like to test this + strings.add("blink"); + strings.add("ilayer"); + strings.add("layer"); + strings.add("multicol"); + strings.add("nextid"); + strings.add("nolayer"); + strings.add("sound"); + strings.add("spacer"); + strings.add("xml"); + strings.add("unknown"); for (final String parent : strings) { @@ -927,34 +939,19 @@ void _p_xmp() throws Exception { test("p", "xmp"); } - @Alerts("1") - void _ruby_blink() throws Exception { - test("ruby", "blink"); - } - - @Alerts("1") - void _select_hr() throws Exception { - test("select", "hr"); - } - - @Alerts("1") - void _select_optgroup() throws Exception { - test("select", "optgroup"); - } - - @Alerts("1") - void _select_option() throws Exception { - test("select", "option"); + @Alerts("0") + void _select_input() throws Exception { + test("select", "input"); } - @Alerts("1") - void _select_script() throws Exception { - test("select", "script"); + @Alerts("0") + void _select_select() throws Exception { + test("select", "select"); } @Alerts("1") - void _select_template() throws Exception { - test("select", "template"); + void _ruby_blink() throws Exception { + test("ruby", "blink"); } @Alerts("1") diff --git a/src/test/java/org/htmlunit/html/HtmlAnchor2Test.java b/src/test/java/org/htmlunit/html/HtmlAnchor2Test.java index b773fbc833c..a358795da3f 100644 --- a/src/test/java/org/htmlunit/html/HtmlAnchor2Test.java +++ b/src/test/java/org/htmlunit/html/HtmlAnchor2Test.java @@ -768,7 +768,7 @@ public void asText_getTextContent() throws Exception { /** * Not testable with Selenium. * - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", "First"}) @@ -796,7 +796,7 @@ public void clickWithDownloadAttribute() throws Exception { /** * Not testable with Selenium. * - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", "First"}) @@ -830,7 +830,7 @@ public void clickWithDownloadAttributeFromJs() throws Exception { /** * Not testable with Selenium. * - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", "First", diff --git a/src/test/java/org/htmlunit/html/HtmlAnchorTest.java b/src/test/java/org/htmlunit/html/HtmlAnchorTest.java index 1397efe444e..da6b82e3431 100644 --- a/src/test/java/org/htmlunit/html/HtmlAnchorTest.java +++ b/src/test/java/org/htmlunit/html/HtmlAnchorTest.java @@ -688,7 +688,7 @@ public void javascriptWithReturnWhitespace() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", "First"}) @@ -719,7 +719,7 @@ public void shiftClick() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", "First"}) diff --git a/src/test/java/org/htmlunit/html/HtmlAreaTest.java b/src/test/java/org/htmlunit/html/HtmlAreaTest.java index f38fb15b8e8..52226fa2f62 100644 --- a/src/test/java/org/htmlunit/html/HtmlAreaTest.java +++ b/src/test/java/org/htmlunit/html/HtmlAreaTest.java @@ -30,7 +30,9 @@ import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; +import org.openqa.selenium.WebElement; import org.openqa.selenium.htmlunit.HtmlUnitDriver; +import org.openqa.selenium.interactions.Actions; /** * Tests for {@link HtmlArea}. @@ -386,7 +388,7 @@ public void click_javascriptUrl() throws Exception { + "\n" + "\n" + "\n" - + " \n" + + " \n" + ""; final WebDriver driver = loadPage2(html); @@ -400,7 +402,13 @@ public void click_javascriptUrl() throws Exception { verifyTitle2(driver); - driver.findElement(By.id("a2")).click(); + if (useRealBrowser() && getBrowserVersion().isFirefox()) { + final WebElement img = driver.findElement(By.tagName("img")); + new Actions(driver).moveToElement(img, 10, 10).click().perform(); + } + else { + driver.findElement(By.id("a2")).click(); + } verifyTitle2(driver, "clicked"); if (driver instanceof HtmlUnitDriver) { @@ -414,7 +422,6 @@ public void click_javascriptUrl() throws Exception { */ @Test @Alerts("clicked") - @BuggyWebDriver(FF = "Todo", FF_ESR = "Todo") public void click_javascriptUrlMixedCase() throws Exception { try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) { final byte[] directBytes = IOUtils.toByteArray(is); @@ -426,7 +433,7 @@ public void click_javascriptUrlMixedCase() throws Exception { + "\n" + "\n" + "\n" - + " \n" + + " \n" + "\n" + ""; @@ -441,7 +448,13 @@ public void click_javascriptUrlMixedCase() throws Exception { verifyTitle2(driver); - driver.findElement(By.id("a2")).click(); + if (useRealBrowser() && getBrowserVersion().isFirefox()) { + final WebElement img = driver.findElement(By.tagName("img")); + new Actions(driver).moveToElement(img, 10, 10).click().perform(); + } + else { + driver.findElement(By.id("a2")).click(); + } verifyTitle2(driver, getExpectedAlerts()); if (driver instanceof HtmlUnitDriver) { @@ -455,7 +468,6 @@ public void click_javascriptUrlMixedCase() throws Exception { */ @Test @Alerts("clicked") - @BuggyWebDriver(FF = "Todo", FF_ESR = "Todo") public void click_javascriptUrlLeadingWhitespace() throws Exception { try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) { final byte[] directBytes = IOUtils.toByteArray(is); @@ -467,7 +479,7 @@ public void click_javascriptUrlLeadingWhitespace() throws Exception { + "\n" + "\n" + "\n" - + " \n" + + " \n" + ""; final WebDriver driver = loadPage2(html); @@ -481,7 +493,13 @@ public void click_javascriptUrlLeadingWhitespace() throws Exception { verifyTitle2(driver); - driver.findElement(By.id("a2")).click(); + if (useRealBrowser() && getBrowserVersion().isFirefox()) { + final WebElement img = driver.findElement(By.tagName("img")); + new Actions(driver).moveToElement(img, 10, 10).click().perform(); + } + else { + driver.findElement(By.id("a2")).click(); + } verifyTitle2(driver, getExpectedAlerts()); if (driver instanceof HtmlUnitDriver) { @@ -496,7 +514,6 @@ public void click_javascriptUrlLeadingWhitespace() throws Exception { */ @Test @Alerts("true") - @BuggyWebDriver(FF = "Todo", FF_ESR = "Todo") public void thisInJavascriptHref() throws Exception { try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) { final byte[] directBytes = IOUtils.toByteArray(is); @@ -508,7 +525,7 @@ public void thisInJavascriptHref() throws Exception { + "\n" + "\n" + "\n" - + " \n" + + " \n" + ""; final WebDriver driver = loadPage2(html); @@ -522,7 +539,13 @@ public void thisInJavascriptHref() throws Exception { verifyTitle2(driver); - driver.findElement(By.id("a2")).click(); + if (useRealBrowser() && getBrowserVersion().isFirefox()) { + final WebElement img = driver.findElement(By.tagName("img")); + new Actions(driver).moveToElement(img, 10, 10).click().perform(); + } + else { + driver.findElement(By.id("a2")).click(); + } verifyTitle2(driver, getExpectedAlerts()); if (driver instanceof HtmlUnitDriver) { diff --git a/src/test/java/org/htmlunit/html/HtmlFileInput2Test.java b/src/test/java/org/htmlunit/html/HtmlFileInput2Test.java index 50d1240915a..0ca24910bfe 100644 --- a/src/test/java/org/htmlunit/html/HtmlFileInput2Test.java +++ b/src/test/java/org/htmlunit/html/HtmlFileInput2Test.java @@ -15,6 +15,7 @@ package org.htmlunit.html; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; @@ -762,4 +763,74 @@ public void clearFromJava() throws Exception { file.setValue(""); assertEquals(0, file.getFiles().length); } + + /** + * Methods setData()/getData() are pure Java API (not exposed to JS at all, since + * real browsers have no equivalent) and are completely untested in this + * file. Verifies the getter/setter round-trip and that in-memory data is + * actually used during submission instead of reading the file from disk. + * @throws Exception if an error occurs + */ + @Test + public void setDataIsUsedInsteadOfFileContentOnSubmit() throws Exception { + final String htmlContent = DOCTYPE_HTML + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "\n"; + getMockWebConnection().setDefaultResponse("hello", MimeType.TEXT_PLAIN); + + final HtmlPage page = loadPage(htmlContent); + final HtmlFileInput input = (HtmlFileInput) page.getElementById("myInput"); + + final File tmpFile = File.createTempFile("htmlunit-test", ".txt"); + try { + org.apache.commons.io.FileUtils.writeStringToFile(tmpFile, "content on disk", "UTF-8"); + input.setFiles(tmpFile); + + input.setData("in-memory content".getBytes("UTF-8")); + page.getElementById("mySubmit").click(); + } + finally { + assertTrue(tmpFile.delete()); + } + + final String requestBody = getMockWebConnection().getLastWebRequest().getRequestBody(); + assertTrue(requestBody, requestBody.contains("in-memory content")); + assertFalse(requestBody, requestBody.contains("content on disk")); + } + + /** + * Plain Java-level round trip for setData()/getData()/setContentType()/ + * getContentType(). + * @throws Exception if an error occurs + */ + @Test + public void setDataGetDataSetContentTypeRoundTrip() throws Exception { + final String htmlContent = DOCTYPE_HTML + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + final HtmlPage page = loadPage(htmlContent); + final HtmlFileInput input = (HtmlFileInput) page.getElementById("f"); + + assertNull(input.getData()); + assertNull(input.getContentType()); + + final byte[] data = "hello".getBytes("UTF-8"); + input.setData(data); + input.setContentType("text/custom"); + + assertArrayEquals(data, input.getData()); + assertEquals("text/custom", input.getContentType()); + + input.setContentType(null); + assertNull(input.getContentType()); + } } diff --git a/src/test/java/org/htmlunit/html/HtmlFileInputTest.java b/src/test/java/org/htmlunit/html/HtmlFileInputTest.java index 1da0e84701b..77890d27bf1 100644 --- a/src/test/java/org/htmlunit/html/HtmlFileInputTest.java +++ b/src/test/java/org/htmlunit/html/HtmlFileInputTest.java @@ -339,7 +339,7 @@ public void resetByClick() throws Exception { + " var file = document.getElementById('testId');\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" - + " document.getElementById('testReset').click;\n" + + " document.getElementById('testReset').click();\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" + " try{\n" @@ -347,13 +347,13 @@ public void resetByClick() throws Exception { + " } catch(e) { logEx(e); }\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" - + " document.getElementById('testReset').click;\n" + + " document.getElementById('testReset').click();\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" + " file.defaultValue = 'newDefault';\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" - + " document.forms[0].reset;\n" + + " document.forms[0].reset();\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" + " }\n" + "\n" @@ -383,7 +383,7 @@ public void resetByJS() throws Exception { + " var file = document.getElementById('testId');\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" - + " document.forms[0].reset;\n" + + " document.forms[0].reset();\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" + " try{\n" @@ -391,13 +391,13 @@ public void resetByJS() throws Exception { + " } catch(e) { logEx(e); }\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" - + " document.forms[0].reset;\n" + + " document.forms[0].reset();\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" + " file.defaultValue = 'newDefault';\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" - + " document.forms[0].reset;\n" + + " document.forms[0].reset();\n" + " log(file.value + '-' + file.defaultValue + '-' + file.getAttribute('value'));\n" + " }\n" + "\n" @@ -896,6 +896,20 @@ public void validationRequired() throws Exception { validation("\n", ""); } + /** + * A DISABLED + required file input with no files selected must + * still report itself as valid, since disabled fields are barred from + * constraint validation entirely. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", + "false-false-false-false-false-false-false-false-false-false-true", + "false"}) + public void validationRequiredDisabled() throws Exception { + validation("\n", ""); + } + private void validation(final String htmlPart, final String jsPart) throws Exception { final String html = DOCTYPE_HTML + "\n" @@ -1021,4 +1035,118 @@ public void valueWebkitdirectory() throws Exception { driver.findElement(By.id("clickMe")).click(); verifyTitle2(driver, getExpectedAlerts()); } + + /** + * Method reset() must not fire a change event, and must not try to + * resurrect a fake File from the 'value' attribute. This uses + * a REAL file selection (via sendKeys) so reset() has something genuine to + * clear, and counts onchange firings across the whole sequence. + * @throws Exception if the test fails + */ + @Test + @Alerts("0-1") + public void resetClearsRealFileSelectionWithoutSpuriousChange() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final File tmpFile = File.createTempFile("htmlunit-test", ".txt"); + try { + driver.findElement(By.id("f")).sendKeys(tmpFile.getAbsolutePath()); + } + finally { + assertTrue(tmpFile.delete()); + } + + driver.findElement(By.id("resetBtn")).click(); + driver.findElement(By.id("check")).click(); + + verifyTitle2(driver, getExpectedAlerts()); + } + + /** + * Calling reset() on a file input that was NEVER touched (no real selection made) + * must be a true no-op -- specifically must NOT fire a change event, since + * nothing actually changed. + * @throws Exception if the test fails + */ + @Test + @Alerts("0") + public void resetOnNeverTouchedFileInput_noChangeEventFired() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + driver.findElement(By.id("go")).click(); + + verifyTitle2(DEFAULT_WAIT_TIME, driver, getExpectedAlerts()); + } + + /** + * Changing the 'type' attribute of an + * input away from 'file' and then back to 'file' should leave it with an + * empty value/file selection, not retain a stale selection from before the + * type change. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"", "0"}) + public void changingTypeAwayFromFileAndBackClearsSelection() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "\n" + + " \n" + + " \n" + + ""; + + final WebDriver driver = loadPage2(html); + final File tmpFile = File.createTempFile("htmlunit-test", ".txt"); + try { + driver.findElement(By.id("f")).sendKeys(tmpFile.getAbsolutePath()); + } + finally { + assertTrue(tmpFile.delete()); + } + + driver.findElement(By.id("go")).click(); + verifyTitle2(driver, getExpectedAlerts()); // expect "" and "0" + } } diff --git a/src/test/java/org/htmlunit/html/HtmlFormTest.java b/src/test/java/org/htmlunit/html/HtmlFormTest.java index d427e3cfafc..7d8d3c5645c 100644 --- a/src/test/java/org/htmlunit/html/HtmlFormTest.java +++ b/src/test/java/org/htmlunit/html/HtmlFormTest.java @@ -51,7 +51,7 @@ public class HtmlFormTest extends SimpleWebTestCase { /** * Tests the good case for setCheckedRatdioButton(). - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void setSelectedRadioButton_ValueExists() throws Exception { @@ -85,7 +85,7 @@ public void setSelectedRadioButton_ValueExists() throws Exception { /** * Tests setCheckedRadioButton() with a value that doesn't exist. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void setSelectedRadioButton_ValueDoesNotExist_DoNotForceSelection() throws Exception { diff --git a/src/test/java/org/htmlunit/html/HtmlInlineFrameTest.java b/src/test/java/org/htmlunit/html/HtmlInlineFrameTest.java index 23489bc9631..bf3d800746c 100644 --- a/src/test/java/org/htmlunit/html/HtmlInlineFrameTest.java +++ b/src/test/java/org/htmlunit/html/HtmlInlineFrameTest.java @@ -490,7 +490,7 @@ public void asNormalizedText() throws Exception { /** * See issue #1825. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void brokenIframe() throws Exception { diff --git a/src/test/java/org/htmlunit/html/HtmlInput2Test.java b/src/test/java/org/htmlunit/html/HtmlInput2Test.java index 8251261e0cc..5f324a5da51 100644 --- a/src/test/java/org/htmlunit/html/HtmlInput2Test.java +++ b/src/test/java/org/htmlunit/html/HtmlInput2Test.java @@ -277,7 +277,7 @@ public void badInputType() throws Exception { /** * Tests that clicking a radio button will select it. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"undefined", "undefined", "undefined", "undefined", "undefined"}) diff --git a/src/test/java/org/htmlunit/html/HtmlInputTest.java b/src/test/java/org/htmlunit/html/HtmlInputTest.java index c19b3b51d15..63f597373ee 100644 --- a/src/test/java/org/htmlunit/html/HtmlInputTest.java +++ b/src/test/java/org/htmlunit/html/HtmlInputTest.java @@ -42,7 +42,7 @@ public final class HtmlInputTest extends SimpleWebTestCase { /** * Tests that selecting one radio button will deselect all the others. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void radioButtonsAreMutuallyExclusive() throws Exception { @@ -163,7 +163,7 @@ public void checkboxDefaultValue() throws Exception { /** * Tests that clicking a radio button will select it. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void clickRadioButton() throws Exception { @@ -189,7 +189,7 @@ public void clickRadioButton() throws Exception { /** * Tests that default type of input is text. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void inputNoType() throws Exception { diff --git a/src/test/java/org/htmlunit/html/HtmlNumberInput2Test.java b/src/test/java/org/htmlunit/html/HtmlNumberInput2Test.java index 1cc4eca5b09..e26b08ce172 100644 --- a/src/test/java/org/htmlunit/html/HtmlNumberInput2Test.java +++ b/src/test/java/org/htmlunit/html/HtmlNumberInput2Test.java @@ -69,6 +69,7 @@ public void typingAndClone() throws Exception { input.type("4711"); assertEquals("", input.getValueAttribute()); assertEquals("4711", input.getValue()); + assertEquals("4711", input.getRawValue()); } /** @@ -95,6 +96,7 @@ public void typingAndReset() throws Exception { assertEquals("", input.getValueAttribute()); assertEquals("0815", input.getValue()); + assertEquals("0815", input.getRawValue()); } /** @@ -121,6 +123,7 @@ public void typingAndSetValueAttribute() throws Exception { assertEquals("", input.getValueAttribute()); assertEquals("47110815", input.getValue()); + assertEquals("47110815", input.getRawValue()); } /** @@ -147,6 +150,7 @@ public void typingAndSetValue() throws Exception { assertEquals("", input.getValueAttribute()); assertEquals("0815", input.getValue()); + assertEquals("0815", input.getRawValue()); } /** @@ -308,6 +312,7 @@ public void typeWhileSelected() throws Exception { input.type("9876543333210"); assertEquals("123456789012345", input.getValueAttribute()); assertEquals("9876543333210", input.getValue()); + assertEquals("9876543333210", input.getRawValue()); } /** @@ -323,15 +328,22 @@ public void typeLeftArrow() throws Exception { t.type('6'); assertEquals("", t.getValueAttribute()); assertEquals("246", t.getValue()); + assertEquals("246", t.getRawValue()); + t.type(KeyboardEvent.DOM_VK_LEFT); assertEquals("", t.getValueAttribute()); assertEquals("246", t.getValue()); + assertEquals("246", t.getRawValue()); + t.type('0'); assertEquals("", t.getValueAttribute()); assertEquals("2406", t.getValue()); + assertEquals("2406", t.getRawValue()); + t.type(KeyboardEvent.DOM_VK_SPACE); assertEquals("", t.getValueAttribute()); - assertEquals("240 6", t.getValue()); + assertEquals("", t.getValue()); + assertEquals("240 6", t.getRawValue()); } /** @@ -347,13 +359,18 @@ public void typeDelKey() throws Exception { t.type('7'); assertEquals("", t.getValueAttribute()); assertEquals("247", t.getValue()); + assertEquals("247", t.getRawValue()); + t.type(KeyboardEvent.DOM_VK_LEFT); t.type(KeyboardEvent.DOM_VK_LEFT); assertEquals("", t.getValueAttribute()); assertEquals("247", t.getValue()); + assertEquals("247", t.getRawValue()); + t.type(KeyboardEvent.DOM_VK_DELETE); assertEquals("", t.getValueAttribute()); assertEquals("27", t.getValue()); + assertEquals("27", t.getRawValue()); } /** @@ -383,6 +400,7 @@ public void maxLengthValidation() throws Exception { assertEquals(getExpectedAlerts()[2], Boolean.toString(input.isValid())); assertEquals(getExpectedAlerts()[3], input.getValueAttribute()); assertEquals(getExpectedAlerts()[4], input.getValue()); + assertEquals(getExpectedAlerts()[4], input.getRawValue()); } /** @@ -412,5 +430,6 @@ public void minLengthValidation() throws Exception { assertEquals(getExpectedAlerts()[2], Boolean.toString(input.isValid())); assertEquals(getExpectedAlerts()[3], input.getValueAttribute()); assertEquals(getExpectedAlerts()[4], input.getValue()); + assertEquals(getExpectedAlerts()[4], input.getRawValue()); } } diff --git a/src/test/java/org/htmlunit/html/HtmlNumberInputTest.java b/src/test/java/org/htmlunit/html/HtmlNumberInputTest.java index eaa499a0ac7..dd4b0d09d57 100644 --- a/src/test/java/org/htmlunit/html/HtmlNumberInputTest.java +++ b/src/test/java/org/htmlunit/html/HtmlNumberInputTest.java @@ -41,6 +41,125 @@ */ public class HtmlNumberInputTest extends WebDriverTestCase { + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"1234", "-12.34", "", "4.321", "", "4", "", "0", "", "-0", "", "", "", ""}) + public void getSetValue() throws Exception { + final String htmlContent = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(htmlContent); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = {"1234", "-12.34", "", "4.321", "", "", "", "4", "", "", "", "-0", "-0", "", "", ""}, + FF = {"1234", "-12.34", "", "4.321", "", "", "", "4", "", "", "", "-0", "-0", "1", "-34", ""}, + FF_ESR = {"1234", "-12.34", "+12.34", "4.321", "", "", "", "4", "", "", "", "-0", "-0", "1", "-34", ""}) + @HtmlUnitNYI(FF_ESR = {"1234", "-12.34", "", "4.321", "", "", "", "4", "", "", "", "-0", "-0", "1", "-34", ""}) + public void getValue() throws Exception { + final String htmlContent = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(htmlContent); + } + /** * Verifies getVisibleText(). * @throws Exception if the test fails @@ -126,6 +245,111 @@ public void typeInteger() throws Exception { assertEquals("", t.getDomProperty("value")); } + /** + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = {"", "true-false-false-false-false-false-false-false-false-false-false", "false", + "5", "false-false-false-false-false-false-false-false-false-true-false", "true"}, + FF = {"", "true-false-false-false-false-false-false-false-false-false-false", "false", + "", "true-false-false-false-false-false-false-false-false-false-false", "false"}, + FF_ESR = {"", "true-false-false-false-false-false-false-false-false-false-false", "false", + "+5", "false-false-false-false-false-false-false-false-false-true-false", "true"}) + @HtmlUnitNYI( + FF_ESR = {"", "true-false-false-false-false-false-false-false-false-false-false", "false", + "", "true-false-false-false-false-false-false-false-false-false-false", "false"}) + public void typeLeadingPlusWithDigits() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + " \n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + driver.findElement(By.id("inpt")).sendKeys("+"); + driver.findElement(By.id("check")).click(); + + driver.findElement(By.id("inpt")).sendKeys("5"); + driver.findElement(By.id("check")).click(); + + verifyTitle2(driver, getExpectedAlerts()); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"", "true-false-false-false-false-false-false-false-false-false-false", "false", + "-5", "false-false-false-false-false-false-false-false-false-true-false", "true"}) + public void typeLeadingMinusWithDigits() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + " \n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + driver.findElement(By.id("inpt")).sendKeys("-"); + driver.findElement(By.id("check")).click(); + + driver.findElement(By.id("inpt")).sendKeys("5"); + driver.findElement(By.id("check")).click(); + + verifyTitle2(driver, getExpectedAlerts()); + } + /** * @throws Exception if the test fails */ @@ -228,22 +452,34 @@ public void typeIntegerTooSmall() throws Exception { * @throws Exception if the test fails */ @Test - @Alerts({"1", "1--null-true", "1", "1--null-true", "1.2", "1.2--null-false"}) - @HtmlUnitNYI(CHROME = {"1", "1--null-true", "1.", "1.--null-true", "1.2", "1.2--null-false"}, - EDGE = {"1", "1--null-true", "1.", "1.--null-true", "1.2", "1.2--null-false"}, - FF = {"1", "1--null-true", "", "--null-false", "1.2", "1.2--null-false"}, - FF_ESR = {"1", "1--null-true", "", "--null-false", "1.2", "1.2--null-false"}) + @Alerts({"1", "1--null-true-false-false-false-false-false-false-false-false-false-true-false", + "1", "1--null-true-false-false-false-false-false-false-false-false-false-true-false", + "1.2", "1.2--null-false-false-false-false-false-false-true-false-false-false-false-false"}) public void typeIntegerWithDot() throws Exception { final String html = DOCTYPE_HTML + "\n" + "\n" + "\n" + "\n" @@ -1814,12 +2050,12 @@ public void patternValidationWhitespace() throws Exception { */ @Test @Alerts({" 210 ", - "", - "true", - "false-false-false-false-false-false-false-false-false-true-false", - "true", - "§§URL§§?k=", - "2"}) + "", + "true", + "false-false-false-false-false-false-false-false-false-true-false", + "true", + "§§URL§§?k=", + "2"}) public void patternValidationTrimInitial() throws Exception { validation("\n", "", null); } @@ -1829,35 +2065,23 @@ public void patternValidationTrimInitial() throws Exception { */ @Test @Alerts(DEFAULT = {"null", - "210", - "true", - "false-false-false-false-false-false-false-false-false-true-false", - "true", - "§§URL§§?k=210", "2"}, + "210", + "true", + "false-false-false-false-false-false-false-false-false-true-false", + "true", + "§§URL§§?k=210", "2"}, FF = {"null", - "", - "false", - "true-false-false-false-false-false-false-false-false-false-false", - "true", - "§§URL§§", "1"}, + "", + "false", + "true-false-false-false-false-false-false-false-false-false-false", + "true", + "§§URL§§", "1"}, FF_ESR = {"null", - "", - "false", - "true-false-false-false-false-false-false-false-false-false-false", - "true", - "§§URL§§", "1"}) - @HtmlUnitNYI(FF = {"null", - " 210 ", - "false", - "false-false-false-false-false-false-false-false-false-true-false", - "true", - "§§URL§§", "1"}, - FF_ESR = {"null", - " 210 ", - "false", - "false-false-false-false-false-false-false-false-false-true-false", - "true", - "§§URL§§", "1"}) + "", + "false", + "true-false-false-false-false-false-false-false-false-false-false", + "true", + "§§URL§§", "1"}) public void patternValidationTrimType() throws Exception { validation("\n", "", " 210 "); } @@ -2161,4 +2385,283 @@ private void validation(final String htmlPart, final String jsPart, final String assertEquals(getExpectedAlerts()[5], getMockWebConnection().getLastWebRequest().getUrl()); assertEquals(Integer.parseInt(getExpectedAlerts()[6]), getMockWebConnection().getRequestCount()); } + + /** + * Matches the maxValidation boundary already covered for min: + * a value EQUAL to max must NOT be an overflow. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "false"}) + public void maxValidationBoundary_valueEqualsMax() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A malformed (non-numeric) value, checked against the FULL + * validity state (not just the aggregate checkValidity() boolean) -- + * badInput must be true while rangeOverflow/rangeUnderflow/stepMismatch + * all stay false, even though min/max/step are all present and would + * otherwise be checkable. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"", "false", "false", "false", "false", "true"}) + public void badInputFullValidityState_malformedValueNotRangeOrStep() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same as above, but for a sign-only value ('-') specifically -- a + * different unparseable-intermediate-state case than plain garbage text. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"", "false", "false", "false", "false"}) + public void badInputFullValidityState_signOnlyNotRangeOrStep() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void validationMessageNonEmptyForRangeOverflow() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The validationMessage must be empty for a valid value. + * @throws Exception if an error occurs + */ + @Test + @Alerts("") + public void validationMessageEmptyWhenValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The customError must take priority over rangeOverflow in + * validationMessage. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "true", "custom message wins"}) + public void validationMessageCustomErrorBeatsRangeOverflow() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "false"}) + public void reportValidityMatchesCheckValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"invalid fired","false"}) + public void checkValidityFiresInvalidEventForRangeOverflow() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void checkValidityDoesNotFireInvalidWhenInRange() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A DISABLED input with a genuinely out-of-range value must + * report checkValidity() true -- the existing willValidate() test (o1-o5) + * checks disabled/hidden/readonly/style generically, but never combines + * disabled with an actual constraint-violating value the way this does. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "true"}) + public void rangeOverflowIgnoredWhenDisabled() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/html/HtmlPage3Test.java b/src/test/java/org/htmlunit/html/HtmlPage3Test.java index 1aa2c2c1027..57577c58cfa 100644 --- a/src/test/java/org/htmlunit/html/HtmlPage3Test.java +++ b/src/test/java/org/htmlunit/html/HtmlPage3Test.java @@ -153,7 +153,7 @@ public void onLoadHandler_ScriptNameRead() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void constructor() throws Exception { @@ -203,7 +203,7 @@ public void getInputByName() throws Exception { } /** - * @exception Exception if the test fails + * @throws Exception if the test fails */ @Test @Alerts({"[object HTMLInputElement]", "1"}) @@ -228,7 +228,7 @@ public void write_getElementById_afterParsing() throws Exception { } /** - * @exception Exception if the test fails + * @throws Exception if the test fails */ @Test @Alerts({"[object HTMLInputElement]", "1"}) diff --git a/src/test/java/org/htmlunit/html/HtmlPage4Test.java b/src/test/java/org/htmlunit/html/HtmlPage4Test.java index f62ca19d51e..8d51ee3557d 100644 --- a/src/test/java/org/htmlunit/html/HtmlPage4Test.java +++ b/src/test/java/org/htmlunit/html/HtmlPage4Test.java @@ -49,7 +49,7 @@ public class HtmlPage4Test extends WebServerTestCase { /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void refresh() throws Exception { @@ -111,7 +111,7 @@ protected void doPost(final HttpServletRequest req, final HttpServletResponse re } /** - * @exception Exception if an error occurs + * @throws Exception if an error occurs */ @Test @Alerts("hello") diff --git a/src/test/java/org/htmlunit/html/HtmlPageTest.java b/src/test/java/org/htmlunit/html/HtmlPageTest.java index dec5876d76a..78a88b5f21c 100644 --- a/src/test/java/org/htmlunit/html/HtmlPageTest.java +++ b/src/test/java/org/htmlunit/html/HtmlPageTest.java @@ -942,7 +942,7 @@ public void onLoadReturn() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void asXml() throws Exception { @@ -961,7 +961,7 @@ public void asXml() throws Exception { /** * Tests that the generated XML is valid as HTML code too. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void asXmlValidHtmlOutput() throws Exception { @@ -990,7 +990,7 @@ public void asXmlValidHtmlOutput() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void asXml2() throws Exception { @@ -1055,7 +1055,7 @@ public void asXml_noscript() throws Exception { } /** - * @exception Exception if the test fails + * @throws Exception if the test fails */ @Test public void getElementsById() throws Exception { @@ -1082,7 +1082,7 @@ public void getElementsById() throws Exception { } /** - * @exception Exception if the test fails + * @throws Exception if the test fails */ @Test public void getElementsByName() throws Exception { @@ -1103,7 +1103,7 @@ public void getElementsByName() throws Exception { } /** - * @exception Exception if the test fails + * @throws Exception if the test fails */ @Test public void getElementByName() throws Exception { @@ -1121,7 +1121,7 @@ public void getElementByName() throws Exception { } /** - * @exception Exception if the test fails + * @throws Exception if the test fails */ @Test public void getElementByNameNotfound() throws Exception { @@ -1136,7 +1136,7 @@ public void getElementByNameNotfound() throws Exception { } /** - * @exception Exception if the test fails + * @throws Exception if the test fails */ @Test public void getHtmlElementsByIdAndOrName() throws Exception { @@ -1160,7 +1160,7 @@ public void getHtmlElementsByIdAndOrName() throws Exception { /** * Regression test for bug #287. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void getHtmlElementByIdAfterRemove() throws Exception { @@ -1198,7 +1198,7 @@ public void getHtmlElementByIdAfterRemove() throws Exception { /** * Test getHtmlElementById() when 2 elements have the same id and the first one * is removed. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void getHtmlElementById_idTwice() throws Exception { @@ -1783,7 +1783,7 @@ public void srcJavaScript() throws Exception { /** * Regression test for asNormalizedText() which would blow up. * - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void asNormalizedText() throws Exception { @@ -1838,7 +1838,7 @@ public void getElementsByTagName() throws Exception { /** * HtmlPage.getReadyState() should give the same information than the document element. * @see 402 - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void readyState() throws Exception { @@ -1853,7 +1853,7 @@ public void readyState() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void cloneNode() throws Exception { @@ -1870,7 +1870,7 @@ public void cloneNode() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void cloneHtmlPageWithFrame() throws Exception { @@ -1924,7 +1924,7 @@ public void cloneHtmlPageWithFrame() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void addAutoCloseable() throws Exception { @@ -1937,7 +1937,7 @@ public void addAutoCloseable() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void addAutoCloseableNull() throws Exception { @@ -1948,7 +1948,7 @@ public void addAutoCloseableNull() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void getBaseUrl() throws Exception { diff --git a/src/test/java/org/htmlunit/html/HtmlScript2Test.java b/src/test/java/org/htmlunit/html/HtmlScript2Test.java index 060f62b2b8e..b999ff7c641 100644 --- a/src/test/java/org/htmlunit/html/HtmlScript2Test.java +++ b/src/test/java/org/htmlunit/html/HtmlScript2Test.java @@ -118,7 +118,7 @@ public void simpleScriptable() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("Hello") @@ -137,7 +137,7 @@ public void type_case_sensitivity() throws Exception { /** * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#JavaScript_types. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G"}) @@ -172,7 +172,7 @@ public void typeValues() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"1", "5", "7"}) @@ -981,7 +981,7 @@ public void incorrectCharset() throws Exception { + "\n" + ""; - final String script = new String(ByteOrderMark.UTF_8.getBytes()) + final String script = new String(ByteOrderMark.UTF_8.getBytes(), UTF_8) + "log('" + "\u0623\u0647\u0644\u0627\u064b\u0623\u0647\u0644\u0627" + "\u064b\u0623\u0647\u0644\u0627\u064b\u0623\u0647\u0644\u0627\u064b" + "');"; getMockWebConnection().setResponse(URL_SECOND, script, MimeType.TEXT_JAVASCRIPT, UTF_8); diff --git a/src/test/java/org/htmlunit/html/HtmlSelect2Test.java b/src/test/java/org/htmlunit/html/HtmlSelect2Test.java index 24e964222cb..98fb139841a 100644 --- a/src/test/java/org/htmlunit/html/HtmlSelect2Test.java +++ b/src/test/java/org/htmlunit/html/HtmlSelect2Test.java @@ -35,7 +35,7 @@ public class HtmlSelect2Test extends WebDriverTestCase { /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"false", "false", "false", "true"}) @@ -70,7 +70,7 @@ public void select() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"false", "true", "true", "true"}) @@ -106,7 +106,7 @@ public void shiftClick() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts({"false", "true", "false", "true"}) diff --git a/src/test/java/org/htmlunit/html/HtmlSelectTest.java b/src/test/java/org/htmlunit/html/HtmlSelectTest.java index 1c26a6e7363..f30cd0cdfa3 100644 --- a/src/test/java/org/htmlunit/html/HtmlSelectTest.java +++ b/src/test/java/org/htmlunit/html/HtmlSelectTest.java @@ -47,7 +47,7 @@ public class HtmlSelectTest extends SimpleWebTestCase { /** * Test the good path of submitting a select. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void select() throws Exception { @@ -81,7 +81,7 @@ public void select() throws Exception { /** * Tests submitting the select with no options selected. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void select_MultipleSelectNoneSelected() throws Exception { @@ -114,7 +114,7 @@ public void select_MultipleSelectNoneSelected() throws Exception { /** * Tests changing the selected option. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void select_ChangeSelectedOption_SingleSelect() throws Exception { @@ -148,7 +148,7 @@ public void select_ChangeSelectedOption_SingleSelect() throws Exception { /** * Tests changing the selected option. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void select_ChangeSelectedOption_MultipleSelect() throws Exception { @@ -184,7 +184,7 @@ public void select_ChangeSelectedOption_MultipleSelect() throws Exception { /** * Tests multiple selected options on multiple select lists. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void select_MultipleSelectMultipleSelected() throws Exception { @@ -213,7 +213,7 @@ public void select_MultipleSelectMultipleSelected() throws Exception { * Test multiple selected options on single select lists. This is erroneous HTML, but * browsers simply use the last option. * - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void select_SingleSelectMultipleSelected() throws Exception { @@ -241,7 +241,7 @@ public void select_SingleSelectMultipleSelected() throws Exception { * Test no selected options on single select lists. This is erroneous HTML, but * browsers simply assume the first one to be selected * - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void select_SingleSelectNoneSelected() throws Exception { @@ -268,7 +268,7 @@ public void select_SingleSelectNoneSelected() throws Exception { /** * Tests no selected options on single select lists with a size more than 1. * - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void select_SingleSelectNoneSelectedButSizeGreaterThanOne() throws Exception { @@ -291,7 +291,7 @@ public void select_SingleSelectNoneSelectedButSizeGreaterThanOne() throws Except /** * Tests changing the selected option. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void setSelected_IllegalValue() throws Exception { @@ -547,7 +547,7 @@ void appendOption(final HtmlSelect select, final String value) { /** * Test that asNormalizedText() returns a blank string if nothing is selected. * - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void asNormalizedTextWhenNothingSelected() throws Exception { @@ -588,7 +588,7 @@ public void asNormalizedTextWithMultipleSelect() throws Exception { /** * Test that setSelectedAttribute returns the right page. * - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void setSelectedAttributeReturnedPage() throws Exception { diff --git a/src/test/java/org/htmlunit/html/HtmlTableTest.java b/src/test/java/org/htmlunit/html/HtmlTableTest.java index c9b875e33e5..fd888bcd8a8 100644 --- a/src/test/java/org/htmlunit/html/HtmlTableTest.java +++ b/src/test/java/org/htmlunit/html/HtmlTableTest.java @@ -32,7 +32,7 @@ public class HtmlTableTest extends SimpleWebTestCase { /** * Tests getTableCell(int,int). - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void getCellAt() throws Exception { @@ -64,7 +64,7 @@ public void getCellAt() throws Exception { /** * Tests getCellAt(int,int) with colspan. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void getCellAtColspan() throws Exception { @@ -106,7 +106,7 @@ public void getCellAtColspan() throws Exception { /** * Tests getCellAt(int,int). - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void getCellAtComplex() throws Exception { @@ -264,7 +264,7 @@ public void getCellAtComplex() throws Exception { /** * Tests getTableCell(int,int) for a cell that doesn't exist. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void getTableCell_NotFound() throws Exception { diff --git a/src/test/java/org/htmlunit/html/HtmlTagSupportTest.java b/src/test/java/org/htmlunit/html/HtmlTagSupportTest.java new file mode 100644 index 00000000000..1ededa7d72f --- /dev/null +++ b/src/test/java/org/htmlunit/html/HtmlTagSupportTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2002-2026 Gargoyle Software Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.htmlunit.html; + +import org.htmlunit.WebDriverTestCase; +import org.htmlunit.junit.annotation.Alerts; +import org.junit.jupiter.api.Test; + +/** + * Tests whether the various {@code BrowserVersion}s still need dedicated + * support for the legacy tags. + * + * @author Ronald Brill + */ +public class HtmlTagSupportTest extends WebDriverTestCase { + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"BLINK - HTMLUnknownElement", "BLINK - HTMLUnknownElement"}) + public void blink() throws Exception { + tagSupport("blink"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"COMMENT - HTMLUnknownElement", "COMMENT - HTMLUnknownElement"}) + public void comment() throws Exception { + tagSupport("comment"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"DIV - HTMLDivElement", "DIV - HTMLDivElement"}) + public void div() throws Exception { + tagSupport("div"); + } + + /** + * The tag actually in question. + * + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = {"LAYER - HTMLElement", "LAYER - HTMLElement"}, + FF = {"LAYER - HTMLUnknownElement", "LAYER - HTMLUnknownElement"}, + FF_ESR = {"LAYER - HTMLUnknownElement", "LAYER - HTMLUnknownElement"}) + public void layer() throws Exception { + tagSupport("layer"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"ILAYER - HTMLUnknownElement", "ILAYER - HTMLUnknownElement"}) + public void ilayer() throws Exception { + tagSupport("ilayer"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"LISTING - HTMLPreElement", "LISTING - HTMLPreElement"}) + public void listing() throws Exception { + tagSupport("listing"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"MULTICOL - HTMLUnknownElement", "MULTICOL - HTMLUnknownElement"}) + public void multicol() throws Exception { + tagSupport("multicol"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"NEXTID - HTMLUnknownElement", "NEXTID - HTMLUnknownElement"}) + public void nextid() throws Exception { + tagSupport("nextid"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = {"NOLAYER - HTMLElement", "NOLAYER - HTMLElement"}, + FF = {"NOLAYER - HTMLUnknownElement", "NOLAYER - HTMLUnknownElement"}, + FF_ESR = {"NOLAYER - HTMLUnknownElement", "NOLAYER - HTMLUnknownElement"}) + public void nolayer() throws Exception { + tagSupport("nolayer"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"PLAINTEXT - HTMLElement", "PLAINTEXT - HTMLElement"}) + public void plaintext() throws Exception { + tagSupport("plaintext"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"SOUND - HTMLUnknownElement", "SOUND - HTMLUnknownElement"}) + public void sound() throws Exception { + tagSupport("sound"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"SPACER - HTMLUnknownElement", "SPACER - HTMLUnknownElement"}) + public void spacer() throws Exception { + tagSupport("spacer"); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"XMP - HTMLPreElement", "XMP - HTMLPreElement"}) + public void xmp() throws Exception { + tagSupport("xmp"); + } + + private void tagSupport(final String tagName) throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "<" + tagName + " id='t'>" + + ""; + + loadPageVerifyTitle2(html); + } +} diff --git a/src/test/java/org/htmlunit/html/HtmlTextAreaTest.java b/src/test/java/org/htmlunit/html/HtmlTextAreaTest.java index 3f5bd6d2daa..66bb7454dc6 100644 --- a/src/test/java/org/htmlunit/html/HtmlTextAreaTest.java +++ b/src/test/java/org/htmlunit/html/HtmlTextAreaTest.java @@ -330,7 +330,8 @@ public void typingAndClone() throws Exception { HtmlTextArea input = (HtmlTextArea) page.getElementById("foo"); input = (HtmlTextArea) input.cloneNode(true); input.type("4711"); - assertEquals("4711", input.getTextContent()); + assertEquals("4711", input.getText()); + assertEquals("", input.getTextContent()); } /** @@ -355,7 +356,8 @@ public void typingAndReset() throws Exception { input.reset(); input.type("0815"); - assertEquals("0815", input.getTextContent()); + assertEquals("0815", input.getText()); + assertEquals("", input.getTextContent()); } /** @@ -380,6 +382,7 @@ public void typingAndSetTextContent() throws Exception { input.setTextContent(""); input.type("0815"); - assertEquals("0815", input.getTextContent()); + assertEquals("47110815", input.getText()); + assertEquals("", input.getTextContent()); } } diff --git a/src/test/java/org/htmlunit/html/parser/HTMLParser2Test.java b/src/test/java/org/htmlunit/html/parser/HTMLParser2Test.java index 83d45a6ec1a..95eb6481da6 100644 --- a/src/test/java/org/htmlunit/html/parser/HTMLParser2Test.java +++ b/src/test/java/org/htmlunit/html/parser/HTMLParser2Test.java @@ -1165,4 +1165,58 @@ public void childNodesDynamicUpdateDuringParsing() throws Exception { loadPageVerifyTitle2(html); } + + /** + * Verifies that {@code basefont} is handled as specified in the HTML parsing algorithm: + * the start tag is processed as if found in the head ("redirect to 'in head'"), the element + * is inserted and immediately popped off the stack of open elements, so it can never have + * children even without a matching end tag. + * + * @throws Exception if the test fails + */ + @Test + @Alerts("0") + public void basefont() throws Exception { + final String html = + "\n" + + "\n" + + "\n" + + "

Hello

\n" + + "\n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Verifies that {@code bgsound} is handled as specified in the HTML parsing algorithm: + * the start tag is processed as if found in the head ("redirect to 'in head'"), the element + * is inserted and immediately popped off the stack of open elements, so it can never have + * children even without a matching end tag. + * + * @throws Exception if the test fails + */ + @Test + @Alerts("0") + public void bgsound() throws Exception { + final String html = + "\n" + + "\n" + + "\n" + + "

Hello

\n" + + "\n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/html/parser/HTMLParser4Test.java b/src/test/java/org/htmlunit/html/parser/HTMLParser4Test.java index 7d54b1250d7..7cac3e1b4fc 100644 --- a/src/test/java/org/htmlunit/html/parser/HTMLParser4Test.java +++ b/src/test/java/org/htmlunit/html/parser/HTMLParser4Test.java @@ -983,7 +983,7 @@ public void noscriptBrokenComment() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test @Alerts("ti 1234 ") diff --git a/src/test/java/org/htmlunit/html/parser/HTMLParserListenerTest.java b/src/test/java/org/htmlunit/html/parser/HTMLParserListenerTest.java index 5e244f40203..e2b0a3f9bf5 100644 --- a/src/test/java/org/htmlunit/html/parser/HTMLParserListenerTest.java +++ b/src/test/java/org/htmlunit/html/parser/HTMLParserListenerTest.java @@ -112,7 +112,7 @@ public int hashCode() { * to an (accepted - at least in a first time -) regression in * NekoHTML, it doesn't work anymore. * testSimple_withWrongLineCol ensures that no other regression occurs here. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void simple() throws Exception { @@ -123,7 +123,7 @@ public void simple() throws Exception { * Currently, NekoHtml doesn't deliver right information about the line * for the warning. Let this test run with wrong expectation * on line and col to avoid that other regression occur. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void simple_withWrongLineCol() throws Exception { @@ -176,7 +176,7 @@ public void warning(final String message, final URL url, final String html, /** * Test parsing of a fragment. - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void parseFragment() throws Exception { diff --git a/src/test/java/org/htmlunit/html/parser/HtmlNumberParserTest.java b/src/test/java/org/htmlunit/html/parser/HtmlNumberParserTest.java new file mode 100644 index 00000000000..2550128ef8b --- /dev/null +++ b/src/test/java/org/htmlunit/html/parser/HtmlNumberParserTest.java @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2002-2026 Gargoyle Software Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.htmlunit.html.parser; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.math.BigDecimal; + +import org.junit.jupiter.api.Test; + +/** + * @author Ronald Brill + */ +public class HtmlNumberParserTest { + + /** + * @throws Exception if the test fails + */ + @Test + public void validIntegers() { + valid( + "0", + "1", + "-1", + "01", + "999999999999999999999999"); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void validFractions() { + valid( + ".5", + "0.5", + "1.0", + "123.456", + "-.5"); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void validExponent() { + valid( + "0e0", + "-0e0", + "01e2", + "123E0", + "1e0", + "1e1", + "1e+1", + "1e-1", + ".5e2", + "1.e2", + "-1.5E-123", + "1e999999", + "1e-999999"); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void invalidEmpty() { + invalid( + "", + "+", + "-", + "."); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void invalidIntegers() { + invalid( + "+1"); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void invalidFractions() { + invalid( + "+.5", + "1.", + "-123.", + "..", + "...", + ".1.", + "..1", + "-.", + "-.e1"); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void invalidExponent() { + invalid( + "e", + "e1", + "1e", + "1e+", + "1e-", + ".e1", + "+1E999", + "1.e+", + "1e++1", + "1e--1", + "1e+-1", + "1e-+1", + "1E", + "1E+", + "1E-"); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void invalidSyntax() { + invalid( + "NaN", + "Infinity", + "-Infinity", + "0x10", + "0b10", + "1f", + "1d", + "1_000", + "1..0", + "1.2.3", + "--1", + "++1", + "+-1"); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void invalidWhitespace() { + invalid( + " 1", + "1 ", + "\t1", + "1\n"); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void invalidUnicodeDigits() { + invalid( + "١", + "123"); + } + + private static void valid(final String... values) { + for (final String value : values) { + assertTrue(HtmlNumberParser.isValid(value, false, false), value); + assertNotNull(HtmlNumberParser.parse(value, false, false), value); + } + } + + private static void invalid(final String... values) { + for (final String value : values) { + assertFalse(HtmlNumberParser.isValid(value, false, false), value); + assertNull(HtmlNumberParser.parse(value, false, false), value); + } + } + + /** + * @throws Exception if the test fails + */ + @Test + public void parse() { + assertEquals(new BigDecimal("123"), HtmlNumberParser.parse("123", false, false)); + assertEquals(new BigDecimal("1.5"), HtmlNumberParser.parse("1.5", false, false)); + assertEquals(new BigDecimal("1E2"), HtmlNumberParser.parse("1e2", false, false)); + assertEquals(new BigDecimal("1E5"), HtmlNumberParser.parse("1e+5", false, false)); + assertEquals(new BigDecimal("0.01"), HtmlNumberParser.parse("1e-2", false, false)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void validPlainIntegers() { + assertTrue(HtmlNumberParser.isValid("0", false, false)); + assertTrue(HtmlNumberParser.isValid("1234", false, false)); + assertTrue(HtmlNumberParser.isValid("-1234", false, false)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void leadingPlusIsInvalid() { + assertFalse(HtmlNumberParser.isValid("+12.34", false, false)); + assertFalse(HtmlNumberParser.isValid("+1234", false, false)); + assertFalse(HtmlNumberParser.isValid("+", false, false)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void exponentSignBothAccepted() { + assertTrue(HtmlNumberParser.isValid("1e+5", false, false)); + assertTrue(HtmlNumberParser.isValid("1e-5", false, false)); + assertTrue(HtmlNumberParser.isValid("1E5", false, false)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void signOnlyIsInvalid() { + assertFalse(HtmlNumberParser.isValid("-", false, false)); + assertFalse(HtmlNumberParser.isValid("+", false, false)); + assertFalse(HtmlNumberParser.isValid(".", false, false)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void trailingWhitespaceIsInvalid() { + assertFalse(HtmlNumberParser.isValid("7 ", false, false)); + assertFalse(HtmlNumberParser.isValid(" 7", false, false)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void negativeZeroPreservedByCallerNotByParser() { + // parse() succeeding is all that matters here -- the CALLER must + // keep the original raw string ("-0"), not regenerate it from the + // returned BigDecimal, which normalizes to "0" + assertTrue(HtmlNumberParser.isValid("-0", false, false)); + final BigDecimal parsed = HtmlNumberParser.parse("-0", false, false); + // documents the trap: this is "0", NOT "-0" -- callers must not + // use parsed.toString() as the sanitized value + assertEquals("0", parsed.toString()); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void lonePeriodIsInvalid() { + assertFalse(HtmlNumberParser.isValid(".", false, false)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void leadingDecimalPointNoIntegerPart() { + assertTrue(HtmlNumberParser.isValid(".5", false, false)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void trailingDecimalPointNoFractionalPart() { + assertFalse(HtmlNumberParser.isValid("1.", false, false)); + + assertTrue(HtmlNumberParser.isValid("1.", false, true)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void emptyAndNullAreInvalid() { + assertFalse(HtmlNumberParser.isValid("", false, false)); + assertFalse(HtmlNumberParser.isValid(null, false, false)); + + assertNull(HtmlNumberParser.parse("", false, false)); + assertNull(HtmlNumberParser.parse(null, false, false)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void leadingZerosAccepted() { + assertTrue(HtmlNumberParser.isValid("007", false, false)); + assertEquals(new BigDecimal("7"), HtmlNumberParser.parse("007", false, false)); + } + + /** + * @throws Exception if the test fails + */ + @Test + public void plusSignInExponentStillAccepted() { + assertTrue(HtmlNumberParser.isValid("1e+2", false, false)); + assertEquals(new BigDecimal("1E2"), HtmlNumberParser.parse("1e+2", false, false)); + } + +} diff --git a/src/test/java/org/htmlunit/html/parser/MalformedHtmlTest.java b/src/test/java/org/htmlunit/html/parser/MalformedHtmlTest.java index 71b61920272..40db65584b4 100644 --- a/src/test/java/org/htmlunit/html/parser/MalformedHtmlTest.java +++ b/src/test/java/org/htmlunit/html/parser/MalformedHtmlTest.java @@ -361,28 +361,32 @@ public void sectionWithUnknownClosingTag() throws Exception { * @throws Exception if an error occurs */ @Test - @Alerts({"4", "#text:\\n\\s\\s", "A:null", "DIV:null", "#text:Z\\n\\n\\n", "3", - "innerDiv", "BODY:null", "3", "A:null", "A:null", "#text:Y", - "outerA", "BODY:null", "1", "#text:V", "true", "false", - "outerA", "DIV:null", "1", "#text:W", "false", "false", - "innerA", "DIV:null", "1", "#text:X", "false", "true"}) + @Alerts({"4", "#text:\\n\\s\\s", "A:null", "DIV:null", "#text:Z\\n\\n\\n", + "3", "innerDiv", "BODY:null", "3", "A:null", "A:null", "#text:Y", + "outerA", "BODY:null", "1", "#text:V", "true", "false", + "outerA", "DIV:null", "1", "#text:W", "false", "false", + "innerA", "DIV:null", "1", "#text:X", "false", "true"}) @HtmlUnitNYI( - CHROME = {"4", "#text:\\n\\s\\s", "A:null", "A:null", "#text:YZ\\n\\n", - "2", "innerDiv", "A:null", "1", "#text:W", "TypeError", + CHROME = {"4", "#text:\\n\\s\\s", "A:null", "DIV:null", "#text:Z\\n\\n", + "3", "innerDiv", "A:null", "1", "#text:W", "TypeError", "outerA", "BODY:null", "2", "#text:V", "true", "false", - "innerA", "BODY:null", "1", "#text:X", "false", "true", "TypeError"}, - EDGE = {"4", "#text:\\n\\s\\s", "A:null", "A:null", "#text:YZ\\n\\n", - "2", "innerDiv", "A:null", "1", "#text:W", "TypeError", + "outerA", "DIV:null", "0", "TypeError", + "innerA", "DIV:null", "1", "#text:X", "false", "true"}, + EDGE = {"4", "#text:\\n\\s\\s", "A:null", "DIV:null", "#text:Z\\n\\n", + "3", "innerDiv", "A:null", "1", "#text:W", "TypeError", "outerA", "BODY:null", "2", "#text:V", "true", "false", - "innerA", "BODY:null", "1", "#text:X", "false", "true", "TypeError"}, - FF = {"4", "#text:\\n\\s\\s", "A:null", "A:null", "#text:YZ\\n\\n", - "2", "innerDiv", "A:null", "1", "#text:W", "TypeError", + "outerA", "DIV:null", "0", "TypeError", + "innerA", "DIV:null", "1", "#text:X", "false", "true"}, + FF = {"4", "#text:\\n\\s\\s", "A:null", "DIV:null", "#text:Z\\n\\n", + "3", "innerDiv", "A:null", "1", "#text:W", "TypeError", "outerA", "BODY:null", "2", "#text:V", "true", "false", - "innerA", "BODY:null", "1", "#text:X", "false", "true", "TypeError"}, - FF_ESR = {"4", "#text:\\n\\s\\s", "A:null", "A:null", "#text:YZ\\n\\n", - "2", "innerDiv", "A:null", "1", "#text:W", "TypeError", + "outerA", "DIV:null", "0", "TypeError", + "innerA", "DIV:null", "1", "#text:X", "false", "true"}, + FF_ESR = {"4", "#text:\\n\\s\\s", "A:null", "DIV:null", "#text:Z\\n\\n", + "3", "innerDiv", "A:null", "1", "#text:W", "TypeError", "outerA", "BODY:null", "2", "#text:V", "true", "false", - "innerA", "BODY:null", "1", "#text:X", "false", "true", "TypeError"}) + "outerA", "DIV:null", "0", "TypeError", + "innerA", "DIV:null", "1", "#text:X", "false", "true"}) // Input: // VZ // CHROME and IE generate: diff --git a/src/test/java/org/htmlunit/html/serializer/HtmlSerializerInnerOuterText2Test.java b/src/test/java/org/htmlunit/html/serializer/HtmlSerializerInnerOuterText2Test.java index e19a768571f..ac472442f36 100644 --- a/src/test/java/org/htmlunit/html/serializer/HtmlSerializerInnerOuterText2Test.java +++ b/src/test/java/org/htmlunit/html/serializer/HtmlSerializerInnerOuterText2Test.java @@ -24,7 +24,7 @@ import org.openqa.selenium.WebElement; /** - * Tests for {@link HtmlSerializerVisibleText}. + * Tests for {@link HtmlSerializerInnerOuterText}. * This contains the tests for plain controls. * * @author Ronald Brill @@ -729,10 +729,6 @@ private void getInnerTextWhiteSpaceTitle(final String whiteSpace) throws Excepti @Alerts(DEFAULT = "A B C D EF G H I\nSecond", FF = "", FF_ESR = "") - @HtmlUnitNYI(CHROME = "A B C D EF G H I Second", - EDGE = "A B C D EF G H I Second", - FF = "A B C D EF G H I Second", - FF_ESR = "A B C D EF G H I Second") public void getInnerTextWhiteSpaceSelect() throws Exception { getInnerTextWhiteSpaceSelect(null); } @@ -745,10 +741,6 @@ public void getInnerTextWhiteSpaceSelect() throws Exception { @Alerts(DEFAULT = "A B C D EF G H I\nSecond", FF = "", FF_ESR = "") - @HtmlUnitNYI(CHROME = "A B C D EF G H I Second", - EDGE = "A B C D EF G H I Second", - FF = "A B C D EF G H I Second", - FF_ESR = "A B C D EF G H I Second") public void getInnerTextWhiteSpaceSelectNormal() throws Exception { getInnerTextWhiteSpaceSelect("normal"); } @@ -761,10 +753,6 @@ public void getInnerTextWhiteSpaceSelectNormal() throws Exception { @Alerts(DEFAULT = "A B C D EF G H I\nSecond", FF = "", FF_ESR = "") - @HtmlUnitNYI(CHROME = "A B C D EF G H I Second", - EDGE = "A B C D EF G H I Second", - FF = "A B C D EF G H I Second", - FF_ESR = "A B C D EF G H I Second") public void getInnerTextWhiteSpaceSelectNowrap() throws Exception { getInnerTextWhiteSpaceSelect("nowrap"); } @@ -777,10 +765,6 @@ public void getInnerTextWhiteSpaceSelectNowrap() throws Exception { @Alerts(DEFAULT = "A B C D EF G H I\nSecond", FF = "", FF_ESR = "") - @HtmlUnitNYI(CHROME = " A B C\t \t D \nEF\nG \n H I \n Second\n ", - EDGE = " A B C\t \t D \nEF\nG \n H I \n Second\n ", - FF = " A B C\t \t D \nEF\nG \n H I \n Second\n ", - FF_ESR = " A B C\t \t D \nEF\nG \n H I \n Second\n ") public void getInnerTextWhiteSpaceSelectPre() throws Exception { getInnerTextWhiteSpaceSelect("pre"); } @@ -793,10 +777,6 @@ public void getInnerTextWhiteSpaceSelectPre() throws Exception { @Alerts(DEFAULT = "A B C D EF G H I\nSecond", FF = "", FF_ESR = "") - @HtmlUnitNYI(CHROME = " A B C\t \t D \nEF\nG \n H I \n Second\n ", - EDGE = " A B C\t \t D \nEF\nG \n H I \n Second\n ", - FF = " A B C\t \t D \nEF\nG \n H I \n Second\n ", - FF_ESR = " A B C\t \t D \nEF\nG \n H I \n Second\n ") public void getInnerTextWhiteSpaceSelectPreWrap() throws Exception { getInnerTextWhiteSpaceSelect("pre-wrap"); } @@ -809,10 +789,6 @@ public void getInnerTextWhiteSpaceSelectPreWrap() throws Exception { @Alerts(DEFAULT = "A B C D EF G H I\nSecond", FF = "", FF_ESR = "") - @HtmlUnitNYI(CHROME = "A B C D\nEF\nG\nH I\nSecond\n", - EDGE = "A B C D\nEF\nG\nH I\nSecond\n", - FF = "A B C D\nEF\nG\nH I\nSecond\n", - FF_ESR = "A B C D\nEF\nG\nH I\nSecond\n") public void getInnerTextWhiteSpaceSelectPreLine() throws Exception { getInnerTextWhiteSpaceSelect("pre-line"); } @@ -836,6 +812,105 @@ private void getInnerTextWhiteSpaceSelect(final String whiteSpace) throws Except assertEquals(getExpectedAlerts()[0], text); } + + /** + * Verifies getInnerText(). + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = "A B C D EF G H I\nJ K L M\nSecond\nThird Fourth\nLast", + FF = "", + FF_ESR = "") + public void getInnerTextWhiteSpaceOptgroupSelect() throws Exception { + getInnerTextWhiteSpaceSelectOptgroup(null); + } + + /** + * Verifies getInnerText(). + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = "A B C D EF G H I\nJ K L M\nSecond\nThird Fourth\nLast", + FF = "", + FF_ESR = "") + public void getInnerTextWhiteSpaceSelectOptgroupNormal() throws Exception { + getInnerTextWhiteSpaceSelectOptgroup("normal"); + } + + /** + * Verifies getInnerText(). + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = "A B C D EF G H I\nJ K L M\nSecond\nThird Fourth\nLast", + FF = "", + FF_ESR = "") + public void getInnerTextWhiteSpaceSelectOptgroupNowrap() throws Exception { + getInnerTextWhiteSpaceSelectOptgroup("nowrap"); + } + + /** + * Verifies getInnerText(). + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = "A B C D EF G H I\nJ K L M\nSecond\nThird Fourth\nLast", + FF = "", + FF_ESR = "") + public void getInnerTextWhiteSpaceSelectOptgroupPre() throws Exception { + getInnerTextWhiteSpaceSelectOptgroup("pre"); + } + + /** + * Verifies getInnerText(). + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = "A B C D EF G H I\nJ K L M\nSecond\nThird Fourth\nLast", + FF = "", + FF_ESR = "") + public void getInnerTextWhiteSpaceSelectOptgroupPreWrap() throws Exception { + getInnerTextWhiteSpaceSelectOptgroup("pre-wrap"); + } + + /** + * Verifies getInnerText(). + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = "A B C D EF G H I\nJ K L M\nSecond\nThird Fourth\nLast", + FF = "", + FF_ESR = "") + public void getInnerTextWhiteSpaceSelectOptgroupPreLine() throws Exception { + getInnerTextWhiteSpaceSelectOptgroup("pre-line"); + } + + private void getInnerTextWhiteSpaceSelectOptgroup(final String whiteSpace) throws Exception { + final String htmlContent = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + ""; + + final WebDriver driver = loadPage2(htmlContent); + final String text = (String) ((JavascriptExecutor) driver) + .executeScript("return document.getElementById('tester').innerText"); + assertEquals(getExpectedAlerts()[0], text); + } + /** * Verifies getInnerText(). * @throws Exception if the test fails diff --git a/src/test/java/org/htmlunit/html/serializer/HtmlSerializerNormalizedText2Test.java b/src/test/java/org/htmlunit/html/serializer/HtmlSerializerNormalizedText2Test.java index 4968a6cae5a..56dcc0082b0 100644 --- a/src/test/java/org/htmlunit/html/serializer/HtmlSerializerNormalizedText2Test.java +++ b/src/test/java/org/htmlunit/html/serializer/HtmlSerializerNormalizedText2Test.java @@ -757,8 +757,7 @@ private void getNormalizedTextWhiteSpaceTitle(final String whiteSpace) throws Ex * @throws Exception if the test fails */ @Test - @Alerts("A B C D EF G H" - + " I") + @Alerts("A B C D EF G H \n I") public void getNormalizedTextWhiteSpaceSelect() throws Exception { getNormalizedTextWhiteSpaceSelect(null); } @@ -768,8 +767,7 @@ public void getNormalizedTextWhiteSpaceSelect() throws Exception { * @throws Exception if the test fails */ @Test - @Alerts("A B C D EF G H" - + " I") + @Alerts("A B C D EF G H \n I") public void getNormalizedTextWhiteSpaceSelectNormal() throws Exception { getNormalizedTextWhiteSpaceSelect("normal"); } @@ -779,8 +777,7 @@ public void getNormalizedTextWhiteSpaceSelectNormal() throws Exception { * @throws Exception if the test fails */ @Test - @Alerts("A B C D EF G H" - + " I") + @Alerts("A B C D EF G H \n I") public void getNormalizedTextWhiteSpaceSelectNowrap() throws Exception { getNormalizedTextWhiteSpaceSelect("nowrap"); } @@ -790,8 +787,7 @@ public void getNormalizedTextWhiteSpaceSelectNowrap() throws Exception { * @throws Exception if the test fails */ @Test - @Alerts("A B C D EF G H" - + " I") + @Alerts("A B C D EF G H \n I") public void getNormalizedTextWhiteSpaceSelectPre() throws Exception { getNormalizedTextWhiteSpaceSelect("pre"); } @@ -801,8 +797,7 @@ public void getNormalizedTextWhiteSpaceSelectPre() throws Exception { * @throws Exception if the test fails */ @Test - @Alerts("A B C D EF G H" - + " I") + @Alerts("A B C D EF G H \n I") public void getNormalizedTextWhiteSpaceSelectPreWrap() throws Exception { getNormalizedTextWhiteSpaceSelect("pre-wrap"); } @@ -812,8 +807,7 @@ public void getNormalizedTextWhiteSpaceSelectPreWrap() throws Exception { * @throws Exception if the test fails */ @Test - @Alerts("A B C D EF G H" - + " I") + @Alerts("A B C D EF G H \n I") public void getNormalizedTextWhiteSpaceSelectPreLine() throws Exception { getNormalizedTextWhiteSpaceSelect("pre-line"); } @@ -1761,7 +1755,7 @@ public void asTextInsideSpan() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void tableCell() throws Exception { @@ -1798,7 +1792,7 @@ public void tableCell() throws Exception { } /** - * @exception Exception If the test fails + * @throws Exception If the test fails */ @Test public void tableCellWithLineBreaks() throws Exception { diff --git a/src/test/java/org/htmlunit/html/serializer/HtmlSerializerVisibleText2Test.java b/src/test/java/org/htmlunit/html/serializer/HtmlSerializerVisibleText2Test.java index a3e8fc9bad5..c02978e25a6 100644 --- a/src/test/java/org/htmlunit/html/serializer/HtmlSerializerVisibleText2Test.java +++ b/src/test/java/org/htmlunit/html/serializer/HtmlSerializerVisibleText2Test.java @@ -797,10 +797,11 @@ private void getVisibleTextWhiteSpaceTitle(final String whiteSpace) throws Excep */ @Test @Alerts(DEFAULT = " A B C D EF G H\nI\n Second\n ", - FF = "A B C D EF G H I\nSecond", + FF = "A B C D EF G H\nI\nSecond", FF_ESR = "A B C D EF G H I\nSecond") - @HtmlUnitNYI(CHROME = "A B C D EF G H I\nSecond", - EDGE = "A B C D EF G H I\nSecond") + @HtmlUnitNYI(CHROME = "A B C D EF G H\nI\nSecond", + EDGE = "A B C D EF G H\nI\nSecond", + FF_ESR = "A B C D EF G H\nI\nSecond") public void getVisibleTextWhiteSpaceSelect() throws Exception { getVisibleTextWhiteSpaceSelect(null); } @@ -811,10 +812,8 @@ public void getVisibleTextWhiteSpaceSelect() throws Exception { */ @Test @Alerts(DEFAULT = "A B C D EF G H\nI\nSecond", - FF = "A B C D EF G H I\nSecond", FF_ESR = "A B C D EF G H I\nSecond") - @HtmlUnitNYI(CHROME = "A B C D EF G H I\nSecond", - EDGE = "A B C D EF G H I\nSecond") + @HtmlUnitNYI(FF_ESR = "A B C D EF G H\nI\nSecond") public void getVisibleTextWhiteSpaceSelectNormal() throws Exception { getVisibleTextWhiteSpaceSelect("normal"); } @@ -825,10 +824,8 @@ public void getVisibleTextWhiteSpaceSelectNormal() throws Exception { */ @Test @Alerts(DEFAULT = "A B C D EF G H\nI\nSecond", - FF = "A B C D EF G H I\nSecond", FF_ESR = "A B C D EF G H I\nSecond") - @HtmlUnitNYI(CHROME = "A B C D EF G H I\nSecond", - EDGE = "A B C D EF G H I\nSecond") + @HtmlUnitNYI(FF_ESR = "A B C D EF G H\nI\nSecond") public void getVisibleTextWhiteSpaceSelectNowrap() throws Exception { getVisibleTextWhiteSpaceSelect("nowrap"); } @@ -839,12 +836,12 @@ public void getVisibleTextWhiteSpaceSelectNowrap() throws Exception { */ @Test @Alerts(DEFAULT = " A B C D EF G H\nI\n Second\n ", - FF = "A B C D EF G H I\nSecond", + FF = "A B C D EF G H\nI\nSecond", FF_ESR = "A B C D EF G H I\nSecond") - @HtmlUnitNYI(CHROME = " A B C D \nEF\nG \n H I \n Second\n ", - EDGE = " A B C D \nEF\nG \n H I \n Second\n ", - FF = " A B C D \nEF\nG \n H I \n Second\n ", - FF_ESR = " A B C D \nEF\nG \n H I \n Second\n ") + @HtmlUnitNYI(CHROME = " A B C D \nEF\nG \n H \n I \n Second\n ", + EDGE = " A B C D \nEF\nG \n H \n I \n Second\n ", + FF = " A B C D \nEF\nG \n H \n I \n Second\n ", + FF_ESR = " A B C D \nEF\nG \n H \n I \n Second\n ") public void getVisibleTextWhiteSpaceSelectPre() throws Exception { getVisibleTextWhiteSpaceSelect("pre"); } @@ -855,12 +852,12 @@ public void getVisibleTextWhiteSpaceSelectPre() throws Exception { */ @Test @Alerts(DEFAULT = " A B C D EF G H\nI\n Second\n ", - FF = "A B C D EF G H I\nSecond", + FF = "A B C D EF G H\nI\nSecond", FF_ESR = "A B C D EF G H I\nSecond") - @HtmlUnitNYI(CHROME = " A B C D \nEF\nG \n H I \n Second\n ", - EDGE = " A B C D \nEF\nG \n H I \n Second\n ", - FF = " A B C D \nEF\nG \n H I \n Second\n ", - FF_ESR = " A B C D \nEF\nG \n H I \n Second\n ") + @HtmlUnitNYI(CHROME = " A B C D \nEF\nG \n H \n I \n Second\n ", + EDGE = " A B C D \nEF\nG \n H \n I \n Second\n ", + FF = " A B C D \nEF\nG \n H \n I \n Second\n ", + FF_ESR = " A B C D \nEF\nG \n H \n I \n Second\n ") public void getVisibleTextWhiteSpaceSelectPreWrap() throws Exception { getVisibleTextWhiteSpaceSelect("pre-wrap"); } @@ -871,12 +868,11 @@ public void getVisibleTextWhiteSpaceSelectPreWrap() throws Exception { */ @Test @Alerts(DEFAULT = "A B C D EF G H\nI\nSecond", - FF = "A B C D EF G H I\nSecond", FF_ESR = "A B C D EF G H I\nSecond") - @HtmlUnitNYI(CHROME = "A B C D \nEF\nG \n H I\n Second", - EDGE = "A B C D \nEF\nG \n H I\n Second", - FF = "A B C D \nEF\nG \n H I\n Second", - FF_ESR = "A B C D \nEF\nG \n H I\n Second") + @HtmlUnitNYI(CHROME = "A B C D \nEF\nG \n H\nI\n Second", + EDGE = "A B C D \nEF\nG \n H\nI\n Second", + FF = "A B C D \nEF\nG \n H\nI\n Second", + FF_ESR = "A B C D \nEF\nG \n H\nI\n Second") public void getVisibleTextWhiteSpaceSelectPreLine() throws Exception { getVisibleTextWhiteSpaceSelect("pre-line"); } diff --git a/src/test/java/org/htmlunit/httpclient/HttpClientConverterTest.java b/src/test/java/org/htmlunit/httpclient/HttpClientConverterTest.java new file mode 100644 index 00000000000..a0b1fcfdb9c --- /dev/null +++ b/src/test/java/org/htmlunit/httpclient/HttpClientConverterTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2002-2026 Gargoyle Software Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.htmlunit.httpclient; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import org.junit.jupiter.api.Test; + +/** + * Tests for {@link HttpClientConverter}. + * + * @author Ronald Brill + */ +public class HttpClientConverterTest { + + @Test + public void plainDomain() { + assertEquals("blah.com", HttpClientConverter.registrableDomain("blah.com")); + } + + @Test + public void subdomainIsReducedToRegistrableDomain() { + assertEquals("example.com", HttpClientConverter.registrableDomain("www.example.com")); + assertEquals("example.com", HttpClientConverter.registrableDomain("a.b.c.example.com")); + } + + @Test + public void multiPartPublicSuffix() { + // the case a naive "last two labels" heuristic gets wrong + assertEquals("example.co.uk", HttpClientConverter.registrableDomain("example.co.uk")); + assertEquals("example.co.uk", HttpClientConverter.registrableDomain("www.example.co.uk")); + } + + @Test + public void privateSectionSuffixIsHonored() { + // appspot.com is a PRIVATE-section PSL entry; real browsers treat it as its + // own site boundary too, same as the public suffix list's ICANN section + assertEquals("appspot.com", HttpClientConverter.registrableDomain("test.appspot.com")); + } + + @Test + public void singleLabelHostFallsBackToItself() { + assertEquals("localhost", HttpClientConverter.registrableDomain("localhost")); + } + + @Test + public void mixedCaseHost() { + assertEquals("example.com", HttpClientConverter.registrableDomain("WWW.EXAMPLE.COM")); + assertEquals("example.com", HttpClientConverter.registrableDomain("WWW.eXaMpLE.coM")); + + assertEquals(HttpClientConverter.registrableDomain("WWW.EXAMPLE.COM"), + HttpClientConverter.registrableDomain("www.example.com")); + } + + @Test + public void idnPunycodeHost() { + // the ASCII/Punycode encoding of münchen.de + assertEquals("xn--mnchen-3ya.de", HttpClientConverter.registrableDomain("xn--mnchen-3ya.de")); + } + + @Test + public void idnUnicodeAndPunycodeAgree() { + // IMPORTANT: this is the one to actually watch. If this fails, it means the + // Unicode and Punycode forms of the identical domain are being treated as + // different registrable domains - i.e. two URLs for the same real-world site + // could wrongly compute as cross-site depending on which form their host + // string happens to be in. If it fails, the fix is to normalize the host via + // java.net.IDN.toASCII(host) before calling getDomainRoot(), not to "fix" this + // test's expectation. + assertEquals("xn--mnchen-3ya.de", HttpClientConverter.registrableDomain("xn--mnchen-3ya.de")); + assertEquals("xn--mnchen-3ya.de", HttpClientConverter.registrableDomain("münchen.de")); + + assertEquals(HttpClientConverter.registrableDomain("xn--mnchen-3ya.de"), + HttpClientConverter.registrableDomain("münchen.de")); + } + + @Test + public void trailingDotFqdnHost() { + // DNS absolute-FQDN form; unclear whether getDomainRoot() strips this or + // treats the trailing empty label as breaking the match - verify and adjust + assertEquals("", HttpClientConverter.registrableDomain("example.com.")); + assertEquals("example.com", HttpClientConverter.registrableDomain("example.com")); + + assertNotEquals(HttpClientConverter.registrableDomain("example.com"), + HttpClientConverter.registrableDomain("example.com.")); + } + + @Test + public void underscoreInHost() { + // technically invalid per strict DNS hostname rules, but seen in the wild + // (e.g. some internal/test domains) - just confirming it doesn't throw and + // produces something sane, not asserting a specific known-correct value + assertEquals("example.com", HttpClientConverter.registrableDomain("my_host.example.com")); + assertEquals("my_example.com", HttpClientConverter.registrableDomain("myhost.my_example.com")); + } + + @Test + public void emptyHost() { + // shouldn't normally happen (url.getHost() on a well-formed URL), but a public + // static utility can be called with anything - worth knowing whether this + // throws or returns something before some other caller hits it unexpectedly + assertEquals("", HttpClientConverter.registrableDomain("")); + } + + @Test + public void ipv4AddressIsNeverRunThroughPublicSuffixList() { + assertEquals("127.0.0.1", HttpClientConverter.registrableDomain("127.0.0.1")); + assertEquals("192.168.1.1", HttpClientConverter.registrableDomain("192.168.1.1")); + } + + @Test + public void ipv6AddressIsNeverRunThroughPublicSuffixList() { + assertEquals("::1", HttpClientConverter.registrableDomain("::1")); + } +} diff --git a/src/test/java/org/htmlunit/httpclient/HttpClientTest.java b/src/test/java/org/htmlunit/httpclient/HttpClientTest.java index 511b66cfe8d..d09dda2f23f 100644 --- a/src/test/java/org/htmlunit/httpclient/HttpClientTest.java +++ b/src/test/java/org/htmlunit/httpclient/HttpClientTest.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.Writer; import java.net.URL; +import java.net.http.HttpClient; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -41,7 +42,6 @@ import org.apache.http.entity.mime.content.FileBody; import org.apache.http.impl.client.HttpClientBuilder; import org.htmlunit.WebServerTestCase; -import org.htmlunit.html.HtmlFileInput; import org.htmlunit.util.MimeType; import org.junit.jupiter.api.Test; @@ -52,7 +52,7 @@ import jakarta.servlet.http.HttpServletResponse; /** - * Tests for {@link HtmlFileInput}. + * Tests for {@link HttpClient}. * * @author Marc Guillemot * @author Ahmed Ashour diff --git a/src/test/java/org/htmlunit/javascript/JavaScriptEngine2Test.java b/src/test/java/org/htmlunit/javascript/JavaScriptEngine2Test.java index 0cd2d8bdfd6..2202e644431 100644 --- a/src/test/java/org/htmlunit/javascript/JavaScriptEngine2Test.java +++ b/src/test/java/org/htmlunit/javascript/JavaScriptEngine2Test.java @@ -1273,4 +1273,31 @@ public void generatorFunction() throws Exception { } } + /** + * Test for https://github.com/HtmlUnit/htmlunit/issues/239. + * + * @throws Exception if the test fails + */ + @Test + @Alerts({"pt1 = [object Promise]", "pt2 = [object Object]", "true"}) + public void symbolSpecies() throws Exception { + final String html = DOCTYPE_HTML + + "" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/NativeErrorTest.java b/src/test/java/org/htmlunit/javascript/NativeErrorTest.java index 62d5ae1c97f..454ccbac4e5 100644 --- a/src/test/java/org/htmlunit/javascript/NativeErrorTest.java +++ b/src/test/java/org/htmlunit/javascript/NativeErrorTest.java @@ -248,7 +248,7 @@ public void stackOverwrite() throws Exception { */ @Test @Alerts(DEFAULT = "10", - FF = "undefined", + FF = "128", FF_ESR = "undefined") public void stackTraceLimit() throws Exception { final String html = DOCTYPE_HTML diff --git a/src/test/java/org/htmlunit/javascript/NativeReflectTest.java b/src/test/java/org/htmlunit/javascript/NativeReflectTest.java index b692a903fc6..1d2133d74d2 100644 --- a/src/test/java/org/htmlunit/javascript/NativeReflectTest.java +++ b/src/test/java/org/htmlunit/javascript/NativeReflectTest.java @@ -467,6 +467,11 @@ public void defineOwnPropertyOutOfBoundsWriteIsDiscarded() throws Exception { loadPageVerifyTitle2(html); } + /** + * Test common workaround for subclassing built-in objects (like Set) without using ES6 + * class/extends syntax, by using Reflect.construct() with a newTarget argument. + * @throws Exception if the test fails + */ @Test @Alerts({"1,2,3,4", "true", "true", "true"}) public void constructSubclassBuiltin() throws Exception { @@ -491,4 +496,196 @@ public void constructSubclassBuiltin() throws Exception { loadPageVerifyTitle2(html); } + + /** + * Test common workaround for subclassing built-in objects (like Map) without using ES6 + * class/extends syntax, by using Reflect.construct() with a newTarget argument. + * @throws Exception if the test fails + */ + @Test + @Alerts({"a,b,c", "true", "true", "true"}) + public void constructSubclassBuiltinMap() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Test the same workaround for Array, which additionally propagates the subclass through + * derived methods (map/filter/slice/...) via Symbol.species, and has exotic "length" and + * isArray behavior that Set/Map don't. + * @throws Exception if the test fails + */ + @Test + @Alerts({"1,2,3", "true", "true", "true", "false", "true"}) + public void constructSubclassBuiltinArray() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Test the workaround for WeakSet, which has no Symbol.iterator/Array.from support, so + * membership must be verified via has() instead of reading contents out. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "true", "true", "true"}) + public void constructSubclassBuiltinWeakSet() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Test the workaround for a typed array (Uint8Array), which is species-driven like Array + * (slice/subarray return instances via Symbol.species) and has an overloaded constructor + * signature (length vs buffer vs iterable) that Set/Map don't have. + * @throws Exception if the test fails + */ + @Test + @Alerts({"1,2,3", "true", "false", "true", "true"}) + public void constructSubclassBuiltinTypedArray() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Test the workaround applied to Proxy, which is expected to diverge from Set/Map/Array: a + * Proxy without a getPrototypeOf trap forwards [[GetPrototypeOf]] to its target rather than to + * whatever prototype Reflect.construct's newTarget would otherwise assign, since ProxyCreate + * ignores newTarget entirely. So the proxy's actual prototype must be Object.prototype + * (inherited from its target, a plain object), and must NOT be CustomProxy.prototype, even + * though construction otherwise looks identical to the Set/Map/Array cases. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "true", "true"}) + public void constructSubclassBuiltinProxy() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Test the workaround for Error, included as a contrast case: unlike Set/Map/Array, naive + * ES5-style inheritance (Error.call(this, message)) already gets most behavior "for free" + * without Reflect.construct, since Error does not hold hidden internal slots the way the + * collection/typed-array types do. This test documents that the Reflect.construct approach + * still works, and still correctly wires up the prototype chain and instanceof checks. + * @throws Exception if the test fails + */ + @Test + @Alerts({"boom", "true", "true", "true"}) + public void constructSubclassBuiltinError() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/RhinoTest.java b/src/test/java/org/htmlunit/javascript/RhinoTest.java index b02e44e147d..4aae34eb336 100644 --- a/src/test/java/org/htmlunit/javascript/RhinoTest.java +++ b/src/test/java/org/htmlunit/javascript/RhinoTest.java @@ -16,7 +16,6 @@ import org.htmlunit.WebDriverTestCase; import org.htmlunit.junit.annotation.Alerts; -import org.htmlunit.junit.annotation.HtmlUnitNYI; import org.htmlunit.util.MimeType; import org.junit.jupiter.api.Test; @@ -59,10 +58,6 @@ public void isStrict_GlobalThis() throws Exception { */ @Test @Alerts("true") - @HtmlUnitNYI(CHROME = "false", - EDGE = "false", - FF = "false", - FF_ESR = "false") public void isStrict_evalVar() throws Exception { final String html = DOCTYPE_HTML + "\n" diff --git a/src/test/java/org/htmlunit/javascript/host/NavigatorTest.java b/src/test/java/org/htmlunit/javascript/host/NavigatorTest.java index 19b165603e5..004e9450d1c 100644 --- a/src/test/java/org/htmlunit/javascript/host/NavigatorTest.java +++ b/src/test/java/org/htmlunit/javascript/host/NavigatorTest.java @@ -14,9 +14,13 @@ */ package org.htmlunit.javascript.host; +import java.util.List; + +import org.htmlunit.HttpHeader; import org.htmlunit.WebDriverTestCase; import org.htmlunit.junit.annotation.Alerts; import org.htmlunit.junit.annotation.HtmlUnitNYI; +import org.htmlunit.util.NameValuePair; import org.junit.jupiter.api.Test; /** @@ -575,4 +579,176 @@ public void pdfViewerEnabled() throws Exception { loadPageVerifyTitle2(html); } + + /** + * Tests {@code navigator.sendBeacon()} with a plain string payload. + * @throws Exception if the test fails + */ + @Test + @Alerts("true") + public void sendBeaconString() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + + if (useRealBrowser()) { + Thread.sleep(DEFAULT_WAIT_TIME.toMillis() / 100); + } + assertEquals(URL_SECOND, getMockWebConnection().getLastWebRequest().getUrl()); + + final String contentType = getMockWebConnection().getLastWebRequest() + .getAdditionalHeader(HttpHeader.CONTENT_TYPE); + final String requestBody = getMockWebConnection().getLastWebRequest().getRequestBody(); + + assertEquals("text/plain;charset=utf-8", contentType.replace(" ", "")); + assertEquals("HtmlUnit", requestBody); + } + + /** + * Tests {@code navigator.sendBeacon()} with a {@code Blob} payload. + * + * @throws Exception if the test fails + */ + @Test + @Alerts("true") + public void sendBeaconBlob() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + + if (useRealBrowser()) { + Thread.sleep(DEFAULT_WAIT_TIME.toMillis() / 100); + } + assertEquals(URL_SECOND, getMockWebConnection().getLastWebRequest().getUrl()); + + final String contentType = getMockWebConnection().getLastWebRequest() + .getAdditionalHeader(HttpHeader.CONTENT_TYPE); + final String requestBody = getMockWebConnection().getLastWebRequest().getRequestBody(); + + assertEquals("text/plain", contentType); + assertEquals("HtmlUnit", requestBody); + } + + /** + * Tests {@code navigator.sendBeacon()} with a {@code URLSearchParams} payload. + * + * @throws Exception if the test fails + */ + @Test + @Alerts("true") + public void sendBeaconURLSearchParams() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + + if (useRealBrowser()) { + Thread.sleep(DEFAULT_WAIT_TIME.toMillis() / 100); + } + assertEquals(URL_SECOND, getMockWebConnection().getLastWebRequest().getUrl()); + + final String contentType = getMockWebConnection().getLastWebRequest() + .getAdditionalHeader(HttpHeader.CONTENT_TYPE); + final List requestParams = getMockWebConnection().getLastWebRequest().getRequestParameters(); + + assertEquals("application/x-www-form-urlencoded;charset=utf-8", contentType.replace(" ", "")); + assertEquals(1, requestParams.size()); + assertEquals("[key=value]", requestParams.toString()); + } + + /** + * Tests {@code navigator.sendBeacon()} with a {@code FormData} payload. + * + * @throws Exception if the test fails + */ + @Test + @Alerts("true") + public void sendBeaconFormData() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + + if (useRealBrowser()) { + Thread.sleep(DEFAULT_WAIT_TIME.toMillis() / 100); + } + assertEquals(URL_SECOND, getMockWebConnection().getLastWebRequest().getUrl()); + + final String contentType = getMockWebConnection().getLastWebRequest() + .getAdditionalHeader(HttpHeader.CONTENT_TYPE); + final String requestBody = getMockWebConnection().getLastWebRequest().getRequestBody(); + + assertTrue(contentType.startsWith("multipart/form-data; boundary=")); + assertTrue(requestBody.contains("name=\"key\"")); + assertTrue(requestBody.contains("value")); + } + + /** + * Tests {@code navigator.sendBeacon()} with a typed-array (ArrayBufferView) payload. + * + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "null"}) + @HtmlUnitNYI( + CHROME = {"true", "text/plain; charset=iso-8859-1"}, + EDGE = {"true", "text/plain; charset=iso-8859-1"}, + FF = {"true", "text/plain; charset=iso-8859-1"}, + FF_ESR = {"true", "text/plain; charset=iso-8859-1"}) + public void sendBeaconArrayBufferView() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + ""; + + loadPageVerifyTitle2(html, getExpectedAlerts()[0]); + + if (useRealBrowser()) { + Thread.sleep(DEFAULT_WAIT_TIME.toMillis() / 100); + } + assertEquals(URL_SECOND, getMockWebConnection().getLastWebRequest().getUrl()); + + final String contentType = getMockWebConnection().getLastWebRequest() + .getAdditionalHeader(HttpHeader.CONTENT_TYPE); + final String requestBody = getMockWebConnection().getLastWebRequest().getRequestBody(); + + assertEquals(getExpectedAlerts()[1], "" + contentType); + assertEquals("HtmlUnit", requestBody); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/URLTest.java b/src/test/java/org/htmlunit/javascript/host/URLTest.java index 353a3343494..aea35781741 100644 --- a/src/test/java/org/htmlunit/javascript/host/URLTest.java +++ b/src/test/java/org/htmlunit/javascript/host/URLTest.java @@ -17,9 +17,9 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1; import java.io.File; -import java.util.List; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; import org.htmlunit.WebDriverTestCase; import org.htmlunit.junit.annotation.Alerts; import org.htmlunit.junit.annotation.HtmlUnitNYI; @@ -233,6 +233,7 @@ public void createObjectURL() throws Exception { + "\n" + "\n" + "\n" @@ -274,12 +275,12 @@ public void createObjectURL() throws Exception { driver.findElement(By.id("testBtn")).click(); - final List alerts = getCollectedAlerts(driver, 4); - final String blobUrl = alerts.get(0); + final String[] alerts = StringUtils.split(driver.getTitle(), "§"); + final String blobUrl = alerts[0]; assertEquals("blob:http://localhost:" + PORT + "/", blobUrl.substring(0, blobUrl.lastIndexOf('/') + 1)); - assertEquals("200:Hello HtmlUnit", alerts.get(1)); - assertEquals("200:Hello HtmlUnit", alerts.get(2)); - assertEquals("No entry for '" + blobUrl + "' in the BlobUrlStore.", alerts.get(3)); + assertEquals("200:Hello HtmlUnit", alerts[1]); + assertEquals("200:Hello HtmlUnit", alerts[2]); + assertEquals("No entry for '" + blobUrl + "' in the BlobUrlStore.", alerts[3]); } finally { FileUtils.deleteQuietly(tstFile); @@ -530,31 +531,62 @@ public void host() throws Exception { loadPageVerifyTitle2(html); } + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"developer.mozilla.org", + "developer.mozilla.org", "https://developer.mozilla.org/en-US/docs/Web/API/URL/host", + "htmlunit-dev.org", "https://htmlunit-dev.org/en-US/docs/Web/API/URL/host"}) + public void hostname() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + "\n" + + "\n" + + "\n" + + ""; + loadPageVerifyTitle2(html); + } + /** * @throws Exception if the test fails */ @Test @Alerts(DEFAULT = {"developer.mozilla.org", "developer.mozilla.org", "https://developer.mozilla.org/en-US/docs/Web/API/URL/host", - "htmlunit-dev.org", "https://htmlunit-dev.org/en-US/docs/Web/API/URL/host", - "htmlunit-dev.org", "https://htmlunit-dev.org/en-US/docs/Web/API/URL/host"}, + "developer.mozilla.org", "https://developer.mozilla.org/en-US/docs/Web/API/URL/host"}, + CHROME = {"developer.mozilla.org", + "%20%20", "https://%20%20/en-US/docs/Web/API/URL/host", + "html%20unit", "https://html%20unit/en-US/docs/Web/API/URL/host"}, + EDGE = {"developer.mozilla.org", + "%20%20", "https://%20%20/en-US/docs/Web/API/URL/host", + "html%20unit", "https://html%20unit/en-US/docs/Web/API/URL/host"}) + @HtmlUnitNYI( CHROME = {"developer.mozilla.org", "developer.mozilla.org", "https://developer.mozilla.org/en-US/docs/Web/API/URL/host", - "htmlunit-dev.org", "https://htmlunit-dev.org/en-US/docs/Web/API/URL/host", - "%20%20", "https://%20%20/en-US/docs/Web/API/URL/host"}, + "developer.mozilla.org", "https://developer.mozilla.org/en-US/docs/Web/API/URL/host"}, EDGE = {"developer.mozilla.org", "developer.mozilla.org", "https://developer.mozilla.org/en-US/docs/Web/API/URL/host", - "htmlunit-dev.org", "https://htmlunit-dev.org/en-US/docs/Web/API/URL/host", - "%20%20", "https://%20%20/en-US/docs/Web/API/URL/host"}) - @HtmlUnitNYI(CHROME = {"developer.mozilla.org", - "developer.mozilla.org", "https://developer.mozilla.org/en-US/docs/Web/API/URL/host", - "htmlunit-dev.org", "https://htmlunit-dev.org/en-US/docs/Web/API/URL/host", - "%20%20", "https:// /en-US/docs/Web/API/URL/host"}, - EDGE = {"developer.mozilla.org", - "developer.mozilla.org", "https://developer.mozilla.org/en-US/docs/Web/API/URL/host", - "htmlunit-dev.org", "https://htmlunit-dev.org/en-US/docs/Web/API/URL/host", - "%20%20", "https:// /en-US/docs/Web/API/URL/host"}) - public void hostname() throws Exception { + "developer.mozilla.org", "https://developer.mozilla.org/en-US/docs/Web/API/URL/host"}) + public void hostnameBlank() throws Exception { final String html = DOCTYPE_HTML + "\n" + "\n" @@ -565,15 +597,46 @@ public void hostname() throws Exception { + " var u = new URL('https://developer.mozilla.org:443/en-US/docs/Web/API/URL/host');\n" + " log(u.hostname);\n" - + " u.hostname = '';\n" + + " u.hostname = ' ';\n" + " log(u.hostname);\n" + " log(u.toString());\n" - + " u.hostname = 'htmlunit-dev.org';\n" + + " u.hostname = 'html unit';\n" + " log(u.hostname);\n" + " log(u.toString());\n" + + " }\n" + + " }\n" + + " \n" + + "\n" + + "\n" + + "\n" + + ""; + loadPageVerifyTitle2(html); + } - + " u.hostname = ' ';\n" + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"developer.mozilla.org", + "html", "https://html/en-US/docs/Web/API/URL/host", + "html", "https://html/en-US/docs/Web/API/URL/host"}) + public void hostnameInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + "\n" + + " \n" + + " \n" + + " \n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A default (type='submit') button with a custom validity message matches + * :invalid and not :valid. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true"}) + public void cssInvalidMatchesSubmitButtonWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A type='button' element is barred from constraint validation -- + * it must match NEITHER :valid NOR :invalid, even with no custom validity + * issue at all. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesPlainButtonType() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same as above, but ALSO with a custom validity message set -- the barring + * must take priority over the (otherwise would-be-invalid) custom error; + * neither pseudo-class should match. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesPlainButtonTypeEvenWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A type='reset' is barred the same way as type='button' -- neither + * pseudo-class should match, custom validity or not. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesResetButtonType() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A DISABLED submit button is also barred from constraint + * validation -- neither pseudo-class should match, even with a custom + * validity message set. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesDisabledSubmitButton() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Redundant-barring sanity check: type='button' AND disabled AND a custom + * validity message all at once -- still neither pseudo-class should match. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesDisabledPlainButtonWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Dynamic transition: a button barred via type='button' (with a leftover + * custom validity message set while barred) is switched to type='submit' at + * runtime. It must now correctly participate in validation and show + * :invalid -- confirms the barred/not-barred state is evaluated fresh each + * time, not cached from whatever it was when setCustomValidity() was + * originally called. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false", "false", "true"}) + public void cssMatchingUpdatesWhenTypeChangesFromButtonToSubmit() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Dynamic transition, the other direction: an initially-valid submit button + * is switched to type='button' at runtime -- it must stop matching :valid + * (or :invalid) entirely once barred, even though it was clean before the + * change. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "false", "false", "false"}) + public void cssMatchingUpdatesWhenTypeChangesFromSubmitToButton() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A textarea with no 'required' and no custom validity issue + * matches :valid and not :invalid. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "false"}) + public void cssValidMatchesTextareaWithNoError() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A textarea with a custom validity message matches :invalid and not + * :valid. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true"}) + public void cssInvalidMatchesTextareaWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A required, empty textarea matches :invalid (valueMissing). + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true"}) + public void cssInvalidMatchesRequiredEmptyTextarea() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A required, non-empty textarea matches :valid. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "false"}) + public void cssValidMatchesRequiredNonEmptyTextarea() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A DISABLED, required, + * empty textarea must match NEITHER :valid NOR :invalid -- disabled bars it + * from constraint validation entirely, regardless of the would-be + * valueMissing violation. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesDisabledRequiredEmptyTextarea() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A READONLY, required, empty textarea. Per spec, readonly bars an element + * from constraint validation the same way disabled does. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesReadonlyRequiredEmptyTextarea() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same as above but with a custom validity message set as well -- readonly + * barring must take priority over the custom error too, same as disabled + * does. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesReadonlyTextareaEvenWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Redundant-barring sanity check: disabled AND readonly AND required AND a + * custom validity message, all at once -- still neither pseudo-class should + * match. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesDisabledAndReadonlyTextarea() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Dynamic transition: a required, empty textarea starts out correctly + * :invalid, then is made readonly at runtime -- must stop matching + * :invalid (or :valid) once barred, confirming the barred state is + * evaluated fresh rather than cached from page load. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "false", "false", "true"}) + public void cssMatchingUpdatesWhenReadonlyToggledAtRuntime() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Dynamic transition, disabled variant: same idea as above but toggling + * disabled instead of readonly. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "false", "false", "true"}) + public void cssMatchingUpdatesWhenDisabledToggledAtRuntime() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Disabled propagated via an enclosing <fieldset disabled> must bar + * the textarea from validation the same way an own 'disabled' attribute + * does -- exercises the isDisabled() parent-chain walk in combination with + * CSS matching, not just the element's own attribute. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesTextareaInDisabledFieldset() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A text input with no 'required' and no custom validity issue + * matches :valid and not :invalid. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "false"}) + public void cssValidMatchesInputTextWithNoError() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A text input with a custom validity message matches :invalid and not + * :valid. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true"}) + public void cssInvalidMatchesInputTextWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A required, empty text input matches :invalid (valueMissing). + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true"}) + public void cssInvalidMatchesRequiredEmptyInputText() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A required, non-empty text input matches :valid. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "false"}) + public void cssValidMatchesRequiredNonEmptyInputText() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A DISABLED, required, + * empty text input must match NEITHER :valid NOR :invalid -- disabled bars it + * from constraint validation entirely, regardless of the would-be + * valueMissing violation. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesDisabledRequiredEmptyInputText() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A READONLY, required, empty text input. Per spec, readonly bars an element + * from constraint validation the same way disabled does. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesReadonlyRequiredEmptyInputText() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same as above but with a custom validity message set as well -- readonly + * barring must take priority over the custom error too, same as disabled + * does. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesReadonlyInputTextEvenWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " content\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Redundant-barring sanity check: disabled AND readonly AND required AND a + * custom validity message, all at once -- still neither pseudo-class should + * match. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesDisabledAndReadonlyInputText() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Dynamic transition: a required, empty text starts out correctly + * :invalid, then is made readonly at runtime -- must stop matching + * :invalid (or :valid) once barred, confirming the barred state is + * evaluated fresh rather than cached from page load. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "false", "false", "true"}) + public void cssMatchingUpdatesInputTestWhenReadonlyToggledAtRuntime() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Dynamic transition, disabled variant: same idea as above but toggling + * disabled instead of readonly. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "false", "false", "true"}) + public void cssMatchingInputTextUpdatesWhenDisabledToggledAtRuntime() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Disabled propagated via an enclosing <fieldset disabled> must bar + * the text input from validation the same way an own 'disabled' attribute + * does -- exercises the isDisabled() parent-chain walk in combination with + * CSS matching, not just the element's own attribute. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void cssNeitherMatchesInputTextInDisabledFieldset() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/dom/RangeTest.java b/src/test/java/org/htmlunit/javascript/host/dom/RangeTest.java index fff75701741..0a66bafe720 100644 --- a/src/test/java/org/htmlunit/javascript/host/dom/RangeTest.java +++ b/src/test/java/org/htmlunit/javascript/host/dom/RangeTest.java @@ -408,20 +408,20 @@ public void getClientRectsEmpty() throws Exception { @Test @Alerts( DEFAULT = {"4", - "x=15.109375 y=8 w=8 h=17", - "x=15.109375 y=8 w=8 h=17", - "x=23.109375 y=8 w=7.109375 h=17", - "x=23.109375 y=8 w=7.109375 h=17"}, + "x=15.104166984558105 y=8 w=8.000000953674316 h=17.33333396911621", + "x=15.104166984558105 y=8 w=8.000000953674316 h=17.33333396911621", + "x=23.104167938232422 y=8 w=7.104166030883789 h=17.33333396911621", + "x=23.104167938232422 y=8 w=7.104166030883789 h=17.33333396911621"}, FF = {"4", - "x=15.100006103515625 y=8.5 w=8 h=17", - "x=15.100006103515625 y=8.5 w=8 h=17", - "x=23.100006103515625 y=8.5 w=7.0999908447265625 h=17", - "x=23.100006103515625 y=8.5 w=7.0999908447265625 h=17"}, + "x=15.100006103515625 y=8.666671752929688 w=8 h=17.333328247070312", + "x=15.100006103515625 y=8.666671752929688 w=8 h=17.333328247070312", + "x=23.100006103515625 y=8.666671752929688 w=7.0999908447265625 h=17.333328247070312", + "x=23.100006103515625 y=8.666671752929688 w=7.0999908447265625 h=17.333328247070312"}, FF_ESR = {"4", - "x=15.100006103515625 y=8.5 w=8 h=17", - "x=15.100006103515625 y=8.5 w=8 h=17", - "x=23.100006103515625 y=8.5 w=7.0999908447265625 h=17", - "x=23.100006103515625 y=8.5 w=7.0999908447265625 h=17"}) + "x=15.100006103515625 y=8.666671752929688 w=8 h=17.333328247070312", + "x=15.100006103515625 y=8.666671752929688 w=8 h=17.333328247070312", + "x=23.100006103515625 y=8.666671752929688 w=7.0999908447265625 h=17.333328247070312", + "x=23.100006103515625 y=8.666671752929688 w=7.0999908447265625 h=17.333328247070312"}) @HtmlUnitNYI( CHROME = {"4", "x=18 y=8 w=10 h=18", "x=18 y=8 w=10 h=18", "x=28 y=8 w=10 h=18", "x=28 y=8 w=10 h=18"}, EDGE = {"4", "x=18 y=8 w=10 h=18", "x=18 y=8 w=10 h=18", "x=28 y=8 w=10 h=18", "x=28 y=8 w=10 h=18"}, @@ -456,20 +456,18 @@ public void getClientRectsMany() throws Exception { /** * Tests getClientRects() for a range over a text node (setStart/setEnd with char offsets). - * Previously returned an empty list because DomText nodes were skipped in the - * HTMLElement instanceof check, and containedNodes() returned empty for same-node ranges. * @throws Exception if an error occurs */ @Test @Alerts( - DEFAULT = {"1", "x=8 y=8 w=35.546875 h=17"}, - FF = {"1", "x=8 y=8.5 w=35.55000305175781 h=17"}, - FF_ESR = {"1", "x=8 y=8.5 w=35.55000305175781 h=17"}) + DEFAULT = {"1", "x=8 y=8 w=35.552085876464844 h=17.33333396911621"}, + FF = {"1", "x=8 y=8.666671752929688 w=35.55000305175781 h=17.333328247070312"}, + FF_ESR = {"1", "x=8 y=8.666671752929688 w=35.55000305175781 h=17.333328247070312"}) @HtmlUnitNYI( - CHROME = {"1", "x=8 y=8 w=1240 h=18"}, - EDGE = {"1", "x=8 y=8 w=1240 h=18"}, - FF = {"1", "x=8 y=8 w=1240 h=18"}, - FF_ESR = {"1", "x=8 y=8 w=1240 h=18"}) + CHROME = {"1", "x=8 y=8 w=50 h=18"}, + EDGE = {"1", "x=8 y=8 w=50 h=18"}, + FF = {"1", "x=8 y=8 w=50 h=18"}, + FF_ESR = {"1", "x=8 y=8 w=50 h=18"}) public void getClientRectsOnTextNode() throws Exception { final String html = DOCTYPE_HTML + "\n" @@ -601,13 +599,13 @@ public void getClientRectsDoesNotMutateTextContent() throws Exception { * @throws Exception if an error occurs */ @Test - @Alerts(DEFAULT = "x=8 y=8 w=78.859375 h=17", - FF = "x=8 y=8.5 w=79.14999389648438 h=17", - FF_ESR = "x=8 y=8.5 w=79.14999389648438 h=17") - @HtmlUnitNYI(CHROME = "x=8 y=8 w=1240 h=18", - EDGE = "x=8 y=8 w=1240 h=18", - FF = "x=8 y=8 w=1240 h=18", - FF_ESR = "x=8 y=8 w=1240 h=18") + @Alerts(DEFAULT = "x=8 y=8 w=78.85417175292969 h=17.33333396911621", + FF = "x=8 y=8.666671752929688 w=79.14999389648438 h=17.333328247070312", + FF_ESR = "x=8 y=8.666671752929688 w=79.14999389648438 h=17.333328247070312") + @HtmlUnitNYI(CHROME = "x=8 y=8 w=110 h=18", + EDGE = "x=8 y=8 w=110 h=18", + FF = "x=8 y=8 w=110 h=18", + FF_ESR = "x=8 y=8 w=110 h=18") public void getBoundingClientRect() throws Exception { final String html = DOCTYPE_HTML + "
Hello World
\n" @@ -798,4 +796,209 @@ public void cloneContentsSameTextNode() throws Exception { + ""; loadPageVerifyTitle2(html); } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = {"text: x=8 y=8 w=35.552085876464844 h=17.33333396911621", + "element: x=43.552085876464844 y=8 w=39.59375 h=17.33333396911621"}, + FF = {"text: x=8 y=8.666671752929688 w=35.55000305175781 h=17.333328247070312", + "element: x=43.55000305175781 y=8.666671752929688 w=39.59999084472656 h=17.333328247070312"}, + FF_ESR = {"text: x=8 y=8.666671752929688 w=35.55000305175781 h=17.333328247070312", + "element: x=43.55000305175781 y=8.666671752929688 w=39.59999084472656 h=17.333328247070312"}) + @HtmlUnitNYI( + CHROME = {"text: x=8 y=8 w=50 h=18", "element: x=58 y=8 w=50 h=18"}, + EDGE = {"text: x=8 y=8 w=50 h=18", "element: x=58 y=8 w=50 h=18"}, + FF = {"text: x=8 y=8 w=50 h=18", "element: x=58 y=8 w=50 h=18"}, + FF_ESR = {"text: x=8 y=8 w=50 h=18", "element: x=58 y=8 w=50 h=18"}) + public void getClientRectsCoordinates() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
HelloWorld
\n" + + ""; + loadPageVerifyTitle2(html); + } + + /** + * Tests the coordinates returned by getBoundingClientRect() for a range over a text node. + * The rect should match the getClientRects() result since it's the union of a single rect. + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = {"x=8 y=8 w=35.552085876464844 h=17.33333396911621"}, + FF = {"x=8 y=8.666671752929688 w=35.55000305175781 h=17.333328247070312"}, + FF_ESR = {"x=8 y=8.666671752929688 w=35.55000305175781 h=17.333328247070312"}) + @HtmlUnitNYI(CHROME = "x=8 y=8 w=50 h=18", + EDGE = "x=8 y=8 w=50 h=18", + FF = "x=8 y=8 w=50 h=18", + FF_ESR = "x=8 y=8 w=50 h=18") + public void getBoundingClientRectOnTextNodeCoordinates() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
Hello
\n" + + ""; + loadPageVerifyTitle2(html); + } + + /** + * Tests that getClientRects() x coordinate shifts right for a mid-string start offset. + * A range starting at char 5 must have a greater x than one starting at char 0. + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void getClientRectsTextNodeXOffsetIncreases() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
Hello World
\n" + + ""; + loadPageVerifyTitle2(html); + } + + /** + * Tests that getClientRects() x coordinate of a text node accounts for preceding inline siblings. + * The text node after a must have a greater x than the same text as the first child. + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void getClientRectsTextNodeXOffsetAfterSibling() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
AAAHello
\n" + + "
Hello
\n" + + ""; + loadPageVerifyTitle2(html); + } + + /** + * Tests that getClientRects() width for a partial text range is positive + * and less than the full parent element width. + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void getClientRectsTextNodeWidthSane() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
Hello World
\n" + + ""; + loadPageVerifyTitle2(html); + } + + /** + * Tests that getClientRects() x coordinate of a text node preceded by + * a whitespace-only text node is not shifted by the whitespace width. + * Whitespace-only text nodes collapse visually in HTML and must not + * contribute to the sibling offset calculation. + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void getClientRectsTextNodeWhitespaceOnlySiblingIgnored() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
\n" // has whitespace-only text node before 'Hello' + + "Hello
\n" + + "
Hello
\n" // no preceding whitespace text node + + ""; + loadPageVerifyTitle2(html); + } + + /** + * Tests that getClientRects() x coordinate of a text node preceded by + * an inline element sibling correctly accounts for that sibling's width. + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void getClientRectsTextNodeAfterInlineSiblingShifted() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
AAAHello
\n" + + "
Hello
\n" + + ""; + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLAnchorElement2Test.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLAnchorElement2Test.java index 1b1f3bbb39b..e7e92fb423e 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLAnchorElement2Test.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLAnchorElement2Test.java @@ -1560,15 +1560,21 @@ public void readWriteAnchorHostname() throws Exception { */ @Test @Alerts(DEFAULT = {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O", + "localhost", "http://localhost:§§URL§§/foo.html#O", "localhost", "http://localhost:§§URL§§/foo.html#O"}, CHROME = {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O", - "%20%20%20%20", "http://%20%20%20%20:§§URL§§/foo.html#O"}, + "%20%20", "http://%20%20:§§URL§§/foo.html#O", + "html%20unit", "http://html%20unit:§§URL§§/foo.html#O"}, EDGE = {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O", - "%20%20%20%20", "http://%20%20%20%20:§§URL§§/foo.html#O"}) - @HtmlUnitNYI(CHROME = {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O", - "%20%20%20%20", "http:// :§§URL§§/foo.html#O"}, - EDGE = {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O", - "%20%20%20%20", "http:// :§§URL§§/foo.html#O"}) + "%20%20", "http://%20%20:§§URL§§/foo.html#O", + "html%20unit", "http://html%20unit:§§URL§§/foo.html#O"}) + @HtmlUnitNYI( + CHROME = {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O", + "localhost", "http://localhost:§§URL§§/foo.html#O", + "localhost", "http://localhost:§§URL§§/foo.html#O"}, + EDGE = {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O", + "localhost", "http://localhost:§§URL§§/foo.html#O", + "localhost", "http://localhost:§§URL§§/foo.html#O"}) public void readWriteAnchorHostnameEmpty() throws Exception { final String html = DOCTYPE_HTML + "\n" @@ -1583,7 +1589,47 @@ public void readWriteAnchorHostnameEmpty() throws Exception { + " log(tester.hostname);\n" + " log(tester.href);\n" - + " tester.hostname = ' ';\n" + + " tester.hostname = ' ';\n" + + " log(tester.hostname);\n" + + " log(tester.href);\n" + + + " tester.hostname = 'html unit';\n" + + " log(tester.hostname);\n" + + " log(tester.href);\n" + + " }\n" + + " \n" + + " \n" + + " \n" + + " link 1\n" + + " \n" + + ""; + + expandExpectedAlertsVariables("" + PORT); + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"localhost", + "html", "http://html:22222/foo.html#O", + "html", "http://html:22222/foo.html#O"}) + public void readWriteAnchorHostnameInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + " \n" + + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = {"undefined", "", " TExT/hTMl ", "unknown", "application/pdf"}, + FF = {"text/html", "", " TExT/hTMl ", "unknown", "application/pdf"}) + public void setType() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "\n" + + " \n" + + LOG_TEXTAREA + + ""; + + loadPageVerifyTextArea2(html); + } + /** * @throws Exception if the test fails */ diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLButtonElementTest.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLButtonElementTest.java index 52c735d8ca8..f04fb3f84a1 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLButtonElementTest.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLButtonElementTest.java @@ -16,9 +16,11 @@ import org.htmlunit.WebDriverTestCase; import org.htmlunit.junit.annotation.Alerts; +import org.htmlunit.junit.annotation.HtmlUnitNYI; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; /** @@ -466,4 +468,485 @@ public void willValidate() throws Exception { loadPageVerifyTitle2(html); } + + /** + * A button with type='button' is barred from constraint validation + * (per willValidate() already returning false for it) -- so setting a custom + * validity message on it must NOT make checkValidity()/validity.valid report + * it as invalid. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "true"}) + public void setCustomValidityWithTypeButton_notInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same as above, but for type='reset'. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "true"}) + public void setCustomValidityWithTypeReset_notInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Baseline/contrast case: a default (type='submit') button DOES participate + * in constraint validation, so a custom validity message must correctly make + * it invalid. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "true", "false", "false"}) + public void setCustomValidityWithTypeSubmit_isInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Clearing a previously-set custom validity message (empty string) must + * restore validity for a type='submit' button. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false", "true"}) + public void clearCustomValidity_restoresValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Baseline checkValidity()/validity.valid without any custom validity set at + * all. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "true", "true"}) + public void checkValidityWithoutCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "true", "false", "false", "true", "true", + "true", "true", "true", "true", "true", "true", + "true", "true", "true", "true", "true", "true"}) + public void checkValidityDisabled() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The reportValidity() returns the same boolean as checkValidity() for + * a button with a custom validity message set. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void reportValidityMatchesCheckValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts("§§URL§§?") + @HtmlUnitNYI(CHROME = "§§URL§§", + EDGE = "§§URL§§", + FF = "§§URL§§", + FF_ESR = "§§URL§§") + public void clickSubmitButtonSubmitsForm() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + final WebDriver driver = loadPage2(html); + driver.findElement(By.id("btn")).click(); + + if (useRealBrowser()) { + Thread.sleep(DEFAULT_WAIT_TIME.toMillis() / 100); + } + expandExpectedAlertsVariables(URL_SECOND); + assertEquals(getExpectedAlerts()[0], driver.getCurrentUrl()); + } + + /** + * A type='reset' button click should reset the form's fields without + * navigating away. + * @throws Exception if the test fails + */ + @Test + @Alerts("original") + public void clickResetButtonResetsForm() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement text1 = driver.findElement(By.id("text1")); + text1.click(); + text1.sendKeys("-changed"); + + driver.findElement(By.id("btn")).click(); + + assertEquals(getExpectedAlerts()[0], text1.getDomProperty("value")); + } + + /** + * A type='button' click must neither submit nor reset the form. + * @throws Exception if the test fails + */ + @Test + @Alerts({"§§URL§§", "original-changed"}) + public void clickPlainButtonDoesNotSubmitOrReset() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement text1 = driver.findElement(By.id("text1")); + text1.click(); + text1.sendKeys("-changed"); + + driver.findElement(By.id("btn")).click(); + + expandExpectedAlertsVariables(URL_FIRST); + assertEquals(getExpectedAlerts()[0], driver.getCurrentUrl()); + assertEquals(getExpectedAlerts()[1], text1.getDomProperty("value")); + } + + /** + * Clicking a disabled submit button must not submit the form. + * @throws Exception if the test fails + */ + @Test + @Alerts("§§URL§§") + public void clickDisabledSubmitButtonDoesNotSubmit() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + final WebDriver driver = loadPage2(html); + driver.findElement(By.id("btn")).click(); + + expandExpectedAlertsVariables(URL_FIRST); + assertEquals(getExpectedAlerts()[0], driver.getCurrentUrl()); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void disabledFieldsetPropagatesToButton() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The form.reset() with a button present must be a silent no-op for the button + * itself (HtmlButton.reset() is documented as intentionally doing nothing). + * @throws Exception if the test fails + */ + @Test + @Alerts("true") + public void formResetDoesNotAffectButton() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Button has no 'required' concept, so this uses setCustomValidity() to + * force an invalid state instead. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"invalid fired", "false"}) + public void buttonCheckValidityFiresInvalidEvent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void buttonCheckValidityDoesNotFireInvalidWhenActuallyValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void buttonCheckValidityDoesNotFireInvalidOnDisabledControl() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"invalid fired", "false"}) + public void buttonReportValidityFiresInvalidEvent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLDocumentWrite2Test.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLDocumentWrite2Test.java index 1d74431908d..ddd0ce16fda 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLDocumentWrite2Test.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLDocumentWrite2Test.java @@ -152,7 +152,7 @@ public void write2_html_endhtml_in_head() throws Exception { /** * We couldn't document.write() script elements that contained the '<' character... - * @exception Exception if the test fails + * @throws Exception if the test fails */ @Test @Alerts("true") diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLElementTest.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLElementTest.java index 90607937cf4..d521bcbe881 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLElementTest.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLElementTest.java @@ -2854,6 +2854,80 @@ public void getBoundingClientRect_WidthPercent() throws Exception { loadPageVerifyTitle2(html); } + /** + * A block div with only text content should shrink-wrap to its text width, + * not inherit the full parent/viewport width. + * Previously getBoundingClientRect().width returned the full viewport width (e.g. 1256px) + * for any block div with no explicit width, even when it contained only short text. + * @throws Exception if the test fails + */ + @Test + @Alerts("true") + public void getBoundingClientRect_blockDivTextOnlyShrinkWraps() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
Hi
\n" + + ""; + loadPageVerifyTitle2(html); + } + + /** + * A block div with block children should still fill the parent width, not shrink-wrap. + * Verifies that the shrink-wrap fix only applies to inline/text-only content. + * @throws Exception if the test fails + */ + @Test + @Alerts("true") + public void getBoundingClientRect_blockDivWithBlockChildrenFillsParent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
Hi
\n" + + ""; + loadPageVerifyTitle2(html); + } + + /** + * An inline-block div should always shrink-wrap regardless of content type. + * Baseline check to ensure inline-block behaviour is unaffected by the block fix. + * @throws Exception if the test fails + */ + @Test + @Alerts("true") + public void getBoundingClientRect_inlineBlockShrinkWraps() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
Hi
\n" + + ""; + loadPageVerifyTitle2(html); + } + /** * @throws Exception if the test fails */ diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLFieldSetElementTest.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLFieldSetElementTest.java index d3f50b4fedf..38bf8c1460d 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLFieldSetElementTest.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLFieldSetElementTest.java @@ -188,4 +188,898 @@ public void willValidateChild() throws Exception { loadPageVerifyTitle2(html); } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "true", "true", "true", "true"}) + public void checkValidityAlwaysTrueOnFieldsetItself() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
fs
" + + "
" + + " " + + "
" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "true", "true", "true", "true"}) + public void reportValidityAlwaysTrueOnFieldsetItself() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
fs
" + + "
" + + " " + + "
" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Since a fieldset is never itself a candidate for constraint + * validation, a custom validity message set on it must have NO effect on + * checkValidity() -- must still report true, and .validity.valid must + * still be true. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "false", "true", ""}) + public void setCustomValidityOnFieldset_doesNotAffectCheckValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Flag disabled must propagate through a non-fieldset wrapper element (e.g. a + * plain <div>), not just to a DIRECT child of the fieldset. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "false"}) + public void disabledPropagatesThroughWrapperElement() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Flag disabled on an OUTER fieldset must propagate transitively through a + * nested INNER fieldset (which is not itself marked disabled) down to the + * inner fieldset's own descendants. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "false", "false"}) + public void disabledPropagatesThroughNestedFieldsets() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + "
" + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A form control inside the FIRST <legend> of a disabled + * fieldset must NOT be disabled by it, while a control elsewhere in the + * same fieldset's body MUST be disabled. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "false", "false", "false"}) + public void disabledDoesNotApplyToControlsInsideFirstLegend() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + " " + + " " + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The legend exception applies ONLY to the FIRST legend child -- + * a control inside a SECOND legend element (technically non-conforming + * markup, but browsers still parse it) must still be disabled. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "false"}) + public void disabledExceptionAppliesOnlyToFirstLegend() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + " " + + " " + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The legend exception must NOT apply if the fieldset itself isn't + * disabled in the first place -- baseline sanity check that a control + * inside a legend of an ENABLED fieldset just behaves normally. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "false"}) + public void legendControlUnaffectedWhenFieldsetNotDisabled() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + " " + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Toggling fieldset.disabled via script at runtime must propagate to a + * child control's willValidate/disabled state immediately, both when + * turning it on and back off. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "true", "false", "false", "false", "true"}) + public void dynamicDisabledTogglePropagatesToChildren() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * HTMLFieldSetElement.elements should return an HTMLCollection of the + * fieldset's form-associated descendants, mirroring HTMLFormElement's + * .elements. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"2", "i1", "i2"}) + public void elementsContainsFormAssociatedDescendants() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * HTMLFieldSetElement.type must always report the constant "fieldset", + * regardless of any attributes on the element. + * @throws Exception if an error occurs + */ + @Test + @Alerts("fieldset") + public void typeIsAlwaysFieldset() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The 'name' attribute should be reflected as the .name property. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"myFieldset", ""}) + public void nameAttributeReflectedAsProperty() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Direct-child listed elements (input, textarea, select, button) must all + * appear in .elements, in document order. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"4", "i1", "i2", "i3", "i4"}) + public void elementsBasicInclusionAndOrder() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A listed element must still be included even when nested inside a plain + * (non-fieldset) wrapper element, not just as a direct child. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"1", "i1"}) + public void elementsIncludeNestedThroughWrapper() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Non-listed elements (plain containers, and the fieldset's own <legend>) + * must NOT appear in .elements, even though legend is a direct, meaningful + * child of the fieldset. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"1", "onlyListed"}) + public void elementsExcludeNonListedElementsAndLegend() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " caption\n" + + "
\n" + + " \n" + + "

text

\n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * An input with type='image' must be included from .elements. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"2", "imageInput", "textInput"}) + public void elementsIcludeImageTypeInput() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * An outer fieldset's {@code elements} collection includes listed elements + * contained within nested fieldsets, as well as the nested fieldset elements + * themselves. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"3", "outerInput", "inner", "innerInput"}) + public void elementsExcludeDescendantsOfNestedFieldset() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The INNER fieldset's own .elements must + * include its own descendant, since the inner fieldset IS that element's + * closest fieldset ancestor. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"1", "innerInput"}) + public void elementsOfInnerFieldsetIncludeItsOwnDescendants() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The inner <fieldset> element ITSELF (as opposed to its + * descendants) is a listed element whose closest fieldset ancestor is the + * OUTER fieldset -- so the inner fieldset element must appear in the + * outer's .elements, even though the inner fieldset's own children do not. + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void elementsOfOuterFieldsetIncludeInnerFieldsetItself() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Triple nesting sanity check: with three levels of fieldset nesting, the + * OUTERMOST fieldset's .elements must exclude descendants of BOTH inner + * levels, not just the immediately-nested one. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"3", "middle", "innermost", "deepInput"}) + public void elementsExcludeDescendantsAcrossTripleNesting() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A control physically nested inside the fieldset, but explicitly + * associated with a DIFFERENT form via the 'form' attribute, must still + * appear in the fieldset's .elements -- inclusion is tree-based, not + * form-ownership-based. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"1", "i1"}) + public void elementsIncludeControlRegardlessOfFormAttribute() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A control that IS associated with the same form via the 'form' attribute, + * but sits OUTSIDE the fieldset entirely in the tree, must NOT appear in + * that fieldset's .elements. + * @throws Exception if an error occurs + */ + @Test + @Alerts("0") + public void elementsExcludeControlOutsideFieldsetEvenIfSameForm() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The .elements must be a LIVE collection: appending a new listed element after + * the initial read must be reflected without re-querying. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"1", "2", "added"}) + public void elementsIsLiveOnAppend() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The .elements must also live-update on removal. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"2", "1"}) + public void elementsIsLiveOnRemove() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Named access: an element with a matching 'name' attribute should be + * reachable via elements.namedItem(...) and bracket/dot-style named access, + * mirroring HTMLFormElement.elements' named-getter behavior. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"i1", "i1"}) + public void elementsNamedAccess() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * An empty fieldset (no listed descendants at all) reports + * .elements.length as 0, not an error/undefined. + * @throws Exception if an error occurs + */ + @Test + @Alerts("0") + public void elementsEmptyFieldset() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A fieldset with a custom validity message set must + * never fire 'invalid' via checkValidity(). + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void fieldsetCheckValidityNeverFiresInvalidEvenWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The reportValidity() must also never focus the fieldset, since it + * never counts as invalid in the first place. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "false"}) + public void fieldsetReportValidityNeverFocusesEvenWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLFormElementTest.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLFormElementTest.java index 3a344170932..e7a6e0b99d6 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLFormElementTest.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLFormElementTest.java @@ -3645,4 +3645,330 @@ public void elementsForOf() throws Exception { loadPageVerifyTitle2(html); } + + /** + * A control with a CUSTOM validity message (not a built-in constraint like + * required) must also block submission. + * @throws Exception if the test fails + */ + @Test + @Alerts("first") + public void submitBlockedByCustomValidityOnAnyControl() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "first\n" + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " " + + "
\n" + + ""; + + final String html2 = "\n" + + "\n" + + "second\n" + + "OK"; + getMockWebConnection().setDefaultResponse(html2); + + final WebDriver driver = loadPage2(html); + driver.findElement(By.id("submit")).click(); + if (useRealBrowser()) { + Thread.sleep(400); + } + + assertEquals(getExpectedAlerts()[0], driver.getTitle()); + } + + /** + * A DISABLED, required, empty field must NOT block submission. + * @throws Exception if the test fails + */ + @Test + @Alerts("second") + @HtmlUnitNYI(CHROME = "first", + EDGE = "first", + FF = "first", + FF_ESR = "first") + public void submitNotBlockedByDisabledRequiredEmptyField() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "first\n" + + "\n" + + "
\n" + + " \n" + + " " + + "
\n" + + ""; + + final String html2 = "\n" + + "\n" + + "second\n" + + "OK"; + getMockWebConnection().setDefaultResponse(html2); + + final WebDriver driver = loadPage2(html); + driver.findElement(By.id("submit")).click(); + if (useRealBrowser()) { + Thread.sleep(400); + } + + assertEquals(getExpectedAlerts()[0], driver.getTitle()); + } + + /** + * The form.checkValidity() must return false when a required field is empty. + * @throws Exception if an error occurs + */ + @Test + @Alerts("false") + public void formCheckValidityFalseWhenRequiredFieldEmpty() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The form.checkValidity() must return true when all fields are individually + * valid. + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void formCheckValidityTrueWhenAllFieldsValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A disabled, required, empty field must be SKIPPED by + * form.checkValidity() (since willValidate is false for it), not counted + * as either passing or failing -- so the form is valid overall as long as + * every OTHER, non-barred field is valid. + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void formCheckValidityIgnoresDisabledFields() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A <button type='button'> with a custom validity message + * set must NOT cause form.checkValidity() to fail. + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void formCheckValidityIgnoresBarredButtonType() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The form.reportValidity() must return the same boolean as + * form.checkValidity() for the same invalid form. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "false"}) + public void formReportValidityMatchesCheckValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The form.reportValidity() -- interactive validation -- must focus + * the FIRST invalid control it finds when the form is invalid. + * @throws Exception if an error occurs + */ + @Test + @Alerts("invalid1") + @HtmlUnitNYI(CHROME = "", + EDGE = "", + FF = "", + FF_ESR = "") + public void formReportValidityFocusesFirstInvalidControl() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Contrast to the above: form.checkValidity() -- static validation -- must + * NOT move focus at all, even though the form is invalid. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "true"}) + public void formCheckValidityDoesNotMoveFocus() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The form.checkValidity() must fire an 'invalid' event on the failing control. + * @throws Exception if an error occurs + */ + @Test + @Alerts("invalid fired") + public void formCheckValidityFiresInvalidEventOnFailingControl() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * With MULTIPLE invalid controls, form.checkValidity() must fire + * 'invalid' on EACH of them. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"i1 invalid", "i2 invalid", "false"}) + public void formCheckValidityFiresInvalidEventOnAllFailingControls() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLIFrameElement3Test.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLIFrameElement3Test.java index 2162eff7fb4..a53b2eda02a 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLIFrameElement3Test.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLIFrameElement3Test.java @@ -403,9 +403,8 @@ public void height() throws Exception { * @throws Exception if the test fails */ @Test - @Alerts(DEFAULT = {"uninitialized", "complete"}, - CHROME = {"complete", "complete"}, - EDGE = {"complete", "complete"}) + @Alerts(DEFAULT = {"complete", "complete"}, + FF_ESR = {"uninitialized", "complete"}) @HtmlUnitNYI(CHROME = {"loading", "complete"}, EDGE = {"loading", "complete"}, FF = {"loading", "complete"}, diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLInputElementTest.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLInputElementTest.java index 24a3eb562ce..1e463741ea6 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLInputElementTest.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLInputElementTest.java @@ -25,6 +25,7 @@ import org.htmlunit.util.MimeType; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; @@ -2554,8 +2555,6 @@ public void willValidateHidden() throws Exception { @Alerts(DEFAULT = {"false", "false", "false", "false", "false"}, FF = {"true", "false", "true", "false", "true"}, FF_ESR = {"true", "false", "true", "false", "true"}) - @HtmlUnitNYI(FF = {"false", "false", "false", "false", "false"}, - FF_ESR = {"false", "false", "false", "false", "false"}) public void willValidateImage() throws Exception { willValidate("type='image'"); } @@ -2756,4 +2755,1429 @@ public void formNoValidate() throws Exception { loadPageVerifyTitle2(html); } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"original", "from js", "original", "changed"}) + public void reset() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \r\n" + + "
\r\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Setting .value to the value it already holds must not move the selection + * (per spec, comparing against oldAPIValue before the assignment). + * @throws Exception if the test fails + */ + @Test + @Alerts({"1", "2"}) + public void settingValueToSameValue_selectionUnchanged() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Even though a same-value assignment leaves the selection + * untouched, the dirty flag must still flip to true. Proven indirectly: if + * the flag were still false, a later change to the 'value' content attribute + * would still be reflected in .value; if the flag correctly flipped true, + * that later attribute change must be ignored. + * @throws Exception if the test fails + */ + @Test + @Alerts("hello") + public void settingValueToSameValue_stillSetsDirtyFlag() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Selection must be preserved across MULTIPLE consecutive same-value + * assignments, not just the first one. + * @throws Exception if the test fails + */ + @Test + @Alerts({"1", "2"}) + public void settingValueToSameValueTwice_selectionPreservedBothTimes() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The "old value" comparison must be against the CURRENT raw value, not the + * page's originally-parsed value attribute. After dirtying to 'X', setting + * .value back to the ORIGINAL text ('hello') is a change relative to the + * current raw value ('X'), so the cursor MUST move -- even though 'hello' + * matches the original value attribute. + * @throws Exception if the test fails + */ + @Test + @Alerts({"5", "5"}) + public void settingValueBackToOriginalText_cursorMovesBecauseCurrentValueDiffers() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Assigning the empty string to an already-empty value should + * also be treated as "no change" -- no cursor move, but still dirties the + * flag. + * @throws Exception if the test fails + */ + @Test + @Alerts("") + public void settingEmptyValueToAlreadyEmptyValue_selectionUnchangedButDirty() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The ordinary changing-value path must still + * move the cursor to the end -- guards against the same-value fix + * accidentally suppressing the cursor move for genuine changes too. + * @throws Exception if the test fails + */ + @Test + @Alerts({"7", "7"}) + public void settingValueToDifferentValue_cursorMovesToEnd() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * After reset(), selectionStart and selectionEnd must be + * consistent with each other (start <= end), not left in an inverted state. + * Targets the current HtmlSelectableTextInput.reset() implementation, which + * only calls setSelectionEnd(0) without also resetting selectionStart -- + * after the preceding setValue() call moved selectionStart to the END of + * the default value, this leaves start > end unless something else clamps + * it. + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = {"8", "8"}, + FF = {"1", "2"}, + FF_ESR = {"1", "2"}) + @HtmlUnitNYI(FF = {"8", "8"}, + FF_ESR = {"8", "8"}) + public void resetSetsSelectionStartAndEndConsistently() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * If the 'value' content + * attribute is changed by script WHILE .value is dirty (so the + * dirty-flag guard suppresses the sync), a subsequent reset() must pick up + * whatever the attribute CURRENTLY holds -- not the page's originally-parsed + * value. + * @throws Exception if the test fails + */ + @Test + @Alerts("updated") + public void resetReflectsCurrentAttributeNotOriginalParsedValue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Reset triggered via a real click on a <input type=reset> button + * should behave identically to a scripted form.reset() call -- the existing + * reset() test only exercises the scripted path. + * @throws Exception if the test fails + */ + @Test + @Alerts("original") + public void resetViaResetButtonClick_matchesScriptedReset() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement input = driver.findElement(By.id("theInput")); + input.click(); + input.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + input.sendKeys("-typed"); + + driver.findElement(By.id("resetBtn")).click(); + + final String value = input.getDomProperty("value"); + assertEquals(getExpectedAlerts()[0], value); + } + + /** + * The reset() called on a field whose value was NEVER + * changed (dirty flag never set) -- with the setValue() fix applied, the + * cursor-move there is conditional on old-value != new-value, so when + * reset() restores the SAME value that was already showing, that condition + * is false and the cursor-move is skipped entirely. This checks what + * selectionStart/selectionEnd end up being in that case: whatever they were + * BEFORE reset() (since nothing moves them), which may or may not match what + * real browsers do -- real browsers might unconditionally reposition the + * cursor as part of the reset algorithm itself, independent of the value + * setter's own conditional logic. + * @throws Exception if the test fails + */ + @Test + @Alerts({"5", "5", "original", "5", "5"}) + public void resetOnNeverDirtiedInput_selectionPosition() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement input = driver.findElement(By.id("theInput")); + + // click into the field and move the caret somewhere in the middle, + // WITHOUT ever changing its value (no sendKeys/typing, no .value set) + input.click(); + input.sendKeys(Keys.ARROW_LEFT, Keys.ARROW_LEFT, Keys.ARROW_LEFT); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + final Long selStartBeforeReset = (Long) js.executeScript( + "return arguments[0].selectionStart;", input); + final Long selEndBeforeReset = (Long) js.executeScript( + "return arguments[0].selectionEnd;", input); + + driver.findElement(By.id("resetBtn")).click(); + + final Long selStartAfterReset = (Long) js.executeScript( + "return arguments[0].selectionStart;", input); + final Long selEndAfterReset = (Long) js.executeScript( + "return arguments[0].selectionEnd;", input); + final String valueAfterReset = input.getDomProperty("value"); + + assertEquals(getExpectedAlerts()[0], String.valueOf(selStartBeforeReset)); + assertEquals(getExpectedAlerts()[1], String.valueOf(selEndBeforeReset)); + assertEquals(getExpectedAlerts()[2], valueAfterReset); + assertEquals(getExpectedAlerts()[3], String.valueOf(selStartAfterReset)); + assertEquals(getExpectedAlerts()[4], String.valueOf(selEndAfterReset)); + } + + /** + * Same "never touched" scenario, but with an explicit + * mid-field selection RANGE (not just a collapsed caret) set beforehand via + * script, to check whether reset() collapses/repositions a real selection + * range too, or only affects a collapsed caret position. + * @throws Exception if the test fails + */ + @Test + @Alerts({"original", "2", "5"}) + public void resetOnNeverDirtiedInputWithExplicitSelectionRange_selectionPosition() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement input = driver.findElement(By.id("theInput")); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + js.executeScript("arguments[0].setSelectionRange(2, 5);", input); + + driver.findElement(By.id("resetBtn")).click(); + + final Long selStartAfterReset = (Long) js.executeScript( + "return arguments[0].selectionStart;", input); + final Long selEndAfterReset = (Long) js.executeScript( + "return arguments[0].selectionEnd;", input); + final String valueAfterReset = input.getDomProperty("value"); + + assertEquals(getExpectedAlerts()[0], valueAfterReset); + assertEquals(getExpectedAlerts()[1], String.valueOf(selStartAfterReset)); + assertEquals(getExpectedAlerts()[2], String.valueOf(selEndAfterReset)); + } + + /** + * Confirms that typing into a text input (real keyboard simulation via + * sendKeys, not a scripted .value assignment) updates .value but leaves the + * 'value' content attribute untouched. + * @throws Exception if the test fails + */ + @Test + @Alerts({"seed-typed", "seed"}) + public void typingUpdatesValueButNotAttribute() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement input = driver.findElement(By.id("foo")); + input.click(); + input.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + input.sendKeys("-typed"); + + final String value = input.getDomProperty("value"); + final String attribute = input.getDomAttribute("value"); + + assertEquals(getExpectedAlerts()[0], value); + assertEquals(getExpectedAlerts()[1], attribute); + } + + /** + * After dirtying .value via real typing, a clone must preserve the + * dirtied value rather than reverting to the (cloned) 'value' attribute. + * @throws Exception if the test fails + */ + @Test + @Alerts({"seed-typed", "seed"}) + public void cloneNodeAfterTyping_cloneRetainsDirtiedValue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement input = driver.findElement(By.id("foo")); + input.click(); + input.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + input.sendKeys("-typed"); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + final String cloneValue = (String) js.executeScript( + "return arguments[0].cloneNode(true).value;", input); + final String cloneAttribute = (String) js.executeScript( + "return arguments[0].cloneNode(true).getAttribute('value');", input); + + assertEquals(getExpectedAlerts()[0], cloneValue); + assertEquals(getExpectedAlerts()[1], cloneAttribute); + } + + /** + * After cloning a still-CLEAN input and attaching the clone to the document, + * typing independently into the original and the clone must not + * cross-contaminate either one's value. + * @throws Exception if the test fails + */ + @Test + @Alerts({"original-text", "clone-text"}) + public void cloneNodeThenIndependentTyping_noCrossContamination() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement original = driver.findElement(By.id("foo")); + final WebElement clone = driver.findElement(By.id("clone")); + + original.click(); + original.sendKeys("original-text"); + clone.click(); + clone.sendKeys("clone-text"); + + final String originalValue = original.getDomProperty("value"); + final String cloneValue = clone.getDomProperty("value"); + + assertEquals(getExpectedAlerts()[0], originalValue); + assertEquals(getExpectedAlerts()[1], cloneValue); + } + + /** + * Resetting a clone (via a real click on its OWN form's reset button) must + * only affect the clone -- the original, sitting in a separate form, must be + * untouched. + * @throws Exception if the test fails + */ + @Test + @Alerts({"seed-original-dirtied", "seed"}) + public void cloneNodeThenResetOnCloneOnly_doesNotAffectOriginal() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement original = driver.findElement(By.id("foo")); + final WebElement clone = driver.findElement(By.id("clone")); + + original.click(); + original.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + original.sendKeys("-original-dirtied"); + + clone.click(); + clone.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + clone.sendKeys("-clone-dirtied"); + + // reset only form2, which contains the clone + driver.findElement(By.id("resetBtn2")).click(); + + final String originalValue = original.getDomProperty("value"); + final String cloneValue = clone.getDomProperty("value"); + + assertEquals(getExpectedAlerts()[0], originalValue); + assertEquals(getExpectedAlerts()[1], cloneValue); + } + + /** + * An editable text input with a custom validity message must + * report checkValidity() false. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "true", "false", "false"}) + public void setCustomValidityOnEditableInput_isInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A DISABLED input with a custom validity message must still + * report checkValidity() true -- disabled bars it from constraint + * validation entirely, so the custom error must not surface through + * checkValidity(), even though willValidate is already known to be false + * for this case. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "true"}) + public void setCustomValidityOnDisabledInput_notInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same as above but for READONLY instead of disabled -- readonly + * also bars a text-type input from constraint validation per spec. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "true"}) + public void setCustomValidityOnReadonlyInput_notInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same as above but for type='hidden' -- a hidden-type input is + * barred from constraint validation via a THIRD, distinct mechanism (its + * own type state), not disabled or readonly. willValidateHidden() already + * confirms willValidate is false for this type; this confirms + * checkValidity() is consistent with that, given the routing bug found + * elsewhere was specifically about checkValidity() not always consulting + * willValidate() even when willValidate() itself was correct. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "true"}) + public void setCustomValidityOnHiddenInput_notInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A required, empty text input is genuinely invalid (valueMissing) + * when editable, but must report checkValidity() true if ALSO disabled -- + * confirms the disabled-barring check takes priority over an actual + * constraint violation, not just over a custom validity message. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true"}) + public void requiredEmptyDisabledInput_checkValidityTrue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same as above, but for readonly instead of disabled. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true"}) + public void requiredEmptyReadonlyInput_checkValidityTrue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Clearing a previously-set custom validity message (empty string) must + * restore validity for an editable input -- confirms setCustomValidity is + * reversible, not just settable. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false", "true"}) + public void clearCustomValidity_restoresValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The validationMessage should reflect the custom validity message for a + * validation-participating (editable) input, and should be empty for a + * barred-from-validation (disabled) one, regardless of a custom message + * being set. + * @throws Exception if the test fails + */ + @Test + @Alerts({"editable error", ""}) + public void validationMessageReflectsCustomValidityWhereApplicable() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The reportValidity() is untested anywhere in this file -- basic coverage that + * it returns the same boolean as checkValidity() for an input with a custom + * validity message set. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void reportValidityMatchesCheckValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Basic .validity object coverage independent of setCustomValidity() -- + * only the bare checkValidity() boolean is tested anywhere currently; this + * confirms .validity.valueMissing and .validity.valid reflect a genuine + * (non-custom) constraint violation correctly. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "false", "false", "true"}) + public void validityValueMissingForRequiredEmptyInput() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"invalid fired", "false"}) + public void elementCheckValidityFiresInvalidEventDirectly() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void checkValidityDoesNotFireInvalidWhenActuallyValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Companion negative check for a BARRED (disabled) control: even though a + * disabled+required+empty input has an underlying constraint violation, + * 'invalid' must not fire since it's excluded from validation entirely. + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void checkValidityDoesNotFireInvalidOnDisabledControl() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"invalid fired", "false"}) + public void inputReportValidityFiresInvalidEvent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "Please fill out this field."}) + public void validationMessage_valueMissing_input() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "Please select an item in the list."}) + public void validationMessage_valueMissing_select() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "Please fill out this field."}) + public void validationMessage_valueMissing_textarea() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "Please match the requested format."}) + public void validationMessage_patternMismatch() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts( + DEFAULT = "Please match the requested format.", + FF = "Please match the requested format: digits only.", + FF_ESR = "Please match the requested format: digits only.") + @HtmlUnitNYI(FF = "Please match the requested format.", + FF_ESR = "Please match the requested format.") + public void validationMessage_patternMismatch_withTitle() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", ""}) + public void validationMessage_tooLong_input() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", ""}) + public void validationMessage_tooShort_input() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts( + DEFAULT = {"true", "Value must be less than or equal to 10."}, + FF = {"true", "Please select a value that is no more than 10."}, + FF_ESR = {"true", "Please select a value that is no more than 10."}) + @HtmlUnitNYI( + CHROME = {"true", "Value must be less than or equal to the maximum."}, + EDGE = {"true", "Value must be less than or equal to the maximum."}, + FF = {"true", "Value must be less than or equal to the maximum."}, + FF_ESR = {"true", "Value must be less than or equal to the maximum."}) + public void validationMessage_rangeOverflow() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts( + DEFAULT = {"true", "Value must be greater than or equal to 10."}, + FF = {"true", "Please select a value that is no less than 10."}, + FF_ESR = {"true", "Please select a value that is no less than 10."}) + @HtmlUnitNYI( + CHROME = {"true", "Value must be greater than or equal to the minimum."}, + EDGE = {"true", "Value must be greater than or equal to the minimum."}, + FF = {"true", "Value must be greater than or equal to the minimum."}, + FF_ESR = {"true", "Value must be greater than or equal to the minimum."}) + public void validationMessage_rangeUnderflow() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts( + DEFAULT = {"true", "Please enter a valid value. The two nearest valid values are 2 and 4."}, + FF = {"true", "Please select a valid value. The two nearest valid values are 2 and 4."}, + FF_ESR = {"true", "Please select a valid value. The two nearest valid values are 2 and 4."}) + @HtmlUnitNYI( + CHROME = {"true", "Please enter a valid value."}, + EDGE = {"true", "Please enter a valid value."}, + FF = {"true", "Please enter a valid value."}, + FF_ESR = {"true", "Please enter a valid value."}) + public void validationMessage_stepMismatch() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts( + DEFAULT = {"true", "Please include an '@' in the email address. 'not-an-email' is missing an '@'."}, + FF = {"true", "Please enter an email address."}, + FF_ESR = {"true", "Please enter an email address."}) + @HtmlUnitNYI(CHROME = {"true", "Please enter an email address."}, + EDGE = {"true", "Please enter an email address."}) + public void validationMessage_typeMismatch_email() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "Please enter a URL."}) + public void validationMessage_typeMismatch_url() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "Please enter a valid value, thanks!"}) + public void validationMessage_customError_exactStringEchoedBack() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "true", "Please match the requested format."}) + public void validationMessage_priority_patternMismatchAlone() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true","true", "custom message wins"}) + public void validationMessage_priority_customErrorBeatsValueMissing() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("") + public void validationMessage_emptyWhenValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("") + public void validationMessage_emptyWhenBarredViaDisabled() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLObjectElement2Test.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLObjectElement2Test.java index c9fb4a8a7be..fc4bdc98914 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLObjectElement2Test.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLObjectElement2Test.java @@ -81,4 +81,224 @@ public void responseXML_htmlObject() throws Exception { loadPage2(html); verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts()); } + + /** + * Method willValidate must always be false + * for an <object>, regardless of hidden/style/disabled-ancestor + * state. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "false", "false", "false"}) + public void willValidateAlwaysFalse() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + " " + + " " + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The checkValidity() must always return true on an <object>, regardless + * of hidden/style/disabled-ancestor state. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "true", "true", "true"}) + public void checkValidityAlwaysTrue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + " " + + " " + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The reportValidity() must always return true on an <object>, mirroring + * checkValidity(). + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "true", "true", "true"}) + public void reportValidityAlwaysTrue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + " " + + " " + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Since an <object> is never itself a candidate for + * constraint validation, a custom validity message set on it must have NO + * effect on checkValidity() -- must still report true, and + * .validity.valid must still be true. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "false", "true", ""}) + public void setCustomValidityDoesNotAffectCheckValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The validationMessage must always be empty on an <object>, even with a + * custom validity message set and even when additionally barred via an + * ancestor disabled fieldset. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"", ""}) + public void validationMessageAlwaysEmpty() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A object with a custom validity message set must + * never fire 'invalid' via checkValidity(). + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void objectCheckValidityNeverFiresInvalidEvenWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The reportValidity() must also never focus the object. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "false"}) + public void objectReportValidityNeverFocusesEvenWithCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLOptionElement2Test.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLOptionElement2Test.java index d98f58530af..8425b4ca180 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLOptionElement2Test.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLOptionElement2Test.java @@ -1442,8 +1442,8 @@ public void selectAndAttribute() throws Exception { @Test @Alerts(DEFAULT = {"false-null", "true-true", "true-null", "false-selected", "false-null", "true-true"}, - FF = {"false-null", "true-true", "true-null", - "false-selected", "false-null", "false-true"}, + FF = {"false-null", "false-true", "false-null", + "true-selected", "false-null", "true-true"}, FF_ESR = {"false-null", "true-true", "true-null", "false-selected", "false-null", "false-true"}) @HtmlUnitNYI(FF = {"false-null", "true-true", "true-null", "false-selected", "false-null", "true-true"}, diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLOutputElementTest.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLOutputElementTest.java index 23f0d147171..40ea30d8378 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLOutputElementTest.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLOutputElementTest.java @@ -94,4 +94,214 @@ public void willValidate() throws Exception { loadPageVerifyTitle2(html); } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "true", "false", "true", ""}) + public void setCustomValidityOnPlainOutput() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "true", "true", "true", "true"}) + public void checkValidityMirrorsWillValidateAcrossAllCases() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " button" + + " " + + " " + + " " + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The reportValidity() coverage, entirely absent currently -- confirms it + * returns the same boolean as checkValidity() for a plain output with a + * custom validity message set. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "true"}) + public void reportValidityMatchesCheckValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Clearing a previously-set custom validity message (empty string) must be + * reversible -- checked via .validity.customError and .validity.valid + * regardless of which way the plain-output ambiguity above resolves. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "false", "true"}) + public void clearCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * An output that IS a descendant of a disabled fieldset. Since + * willValidate() already reports false uniformly for output regardless of + * its OWN attributes, this checks whether fieldset-ancestor disabling is + * even independently observable for output at all, or whether it's just + * redundant with the element's own always-false state. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "true"}) + public void outputInsideDisabledFieldset() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void outputCheckValidityInvalidEventBehaviorOnPlainOutput() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "false"}) + public void outputReportValidityFocusBehaviorOnPlainOutput() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLSelectElementTest.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLSelectElementTest.java index 3a2c520dfa2..87d38312bff 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLSelectElementTest.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLSelectElementTest.java @@ -1015,6 +1015,7 @@ public void addWithIndexEmptySelect() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodIndexMinusOneEmptySelect() throws Exception { removeOptionMethod("-1", true, false); + removeOptionOptgoupMethod("-1", true, false); } /** @@ -1024,6 +1025,7 @@ public void removeOptionMethodIndexMinusOneEmptySelect() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodIndexMinusOneEmptySelectMulti() throws Exception { removeOptionMethod("-1", true, true); + removeOptionOptgoupMethod("-1", true, true); } /** @@ -1033,6 +1035,7 @@ public void removeOptionMethodIndexMinusOneEmptySelectMulti() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodIndexZeroEmptySelect() throws Exception { removeOptionMethod("0", true, false); + removeOptionOptgoupMethod("0", true, false); } /** @@ -1042,6 +1045,7 @@ public void removeOptionMethodIndexZeroEmptySelect() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodIndexZeroEmptySelectMulti() throws Exception { removeOptionMethod("0", true, true); + removeOptionOptgoupMethod("0", true, true); } /** @@ -1051,6 +1055,7 @@ public void removeOptionMethodIndexZeroEmptySelectMulti() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodIndexOneEmptySelect() throws Exception { removeOptionMethod("1", true, false); + removeOptionOptgoupMethod("1", true, false); } /** @@ -1060,6 +1065,7 @@ public void removeOptionMethodIndexOneEmptySelect() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodIndexOneEmptySelectMulti() throws Exception { removeOptionMethod("1", true, true); + removeOptionOptgoupMethod("1", true, true); } /** @@ -1069,6 +1075,7 @@ public void removeOptionMethodIndexOneEmptySelectMulti() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodIndexFourEmptySelect() throws Exception { removeOptionMethod("4", true, false); + removeOptionOptgoupMethod("4", true, false); } /** @@ -1078,6 +1085,7 @@ public void removeOptionMethodIndexFourEmptySelect() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodIndexFourEmptySelectMulti() throws Exception { removeOptionMethod("4", true, true); + removeOptionOptgoupMethod("4", true, true); } /** @@ -1087,6 +1095,7 @@ public void removeOptionMethodIndexFourEmptySelectMulti() throws Exception { @Alerts({"3", "3", "1", "One", "Two*", "Three"}) public void removeOptionMethodIndexMinusOne() throws Exception { removeOptionMethod("-1", false, false); + removeOptionOptgoupMethod("-1", false, false); } /** @@ -1096,6 +1105,7 @@ public void removeOptionMethodIndexMinusOne() throws Exception { @Alerts({"3", "3", "1", "One", "Two*", "Three*"}) public void removeOptionMethodIndexMinusOneMulti() throws Exception { removeOptionMethod("-1", false, true); + removeOptionOptgoupMethod("-1", false, true); } /** @@ -1105,6 +1115,7 @@ public void removeOptionMethodIndexMinusOneMulti() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three"}) public void removeOptionMethodIndexZero() throws Exception { removeOptionMethod("0", false, false); + removeOptionOptgoupMethod("0", false, false); } /** @@ -1114,6 +1125,7 @@ public void removeOptionMethodIndexZero() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three*"}) public void removeOptionMethodIndexZeroMulti() throws Exception { removeOptionMethod("0", false, true); + removeOptionOptgoupMethod("0", false, true); } /** @@ -1123,6 +1135,7 @@ public void removeOptionMethodIndexZeroMulti() throws Exception { @Alerts({"3", "2", "0", "One*", "Three"}) public void removeOptionMethodIndexOne() throws Exception { removeOptionMethod("1", false, false); + removeOptionOptgoupMethod("1", false, false); } /** @@ -1132,6 +1145,7 @@ public void removeOptionMethodIndexOne() throws Exception { @Alerts({"3", "2", "1", "One", "Three*"}) public void removeOptionMethodIndexOneMulti() throws Exception { removeOptionMethod("1", false, true); + removeOptionOptgoupMethod("1", false, true); } /** @@ -1141,6 +1155,7 @@ public void removeOptionMethodIndexOneMulti() throws Exception { @Alerts({"3", "2", "1", "One", "Two*"}) public void removeOptionMethodhIndexTwo() throws Exception { removeOptionMethod("2", false, false); + removeOptionOptgoupMethod("2", false, false); } /** @@ -1150,6 +1165,7 @@ public void removeOptionMethodhIndexTwo() throws Exception { @Alerts({"3", "2", "1", "One", "Two*"}) public void removeOptionMethodhIndexTwoMulti() throws Exception { removeOptionMethod("2", false, true); + removeOptionOptgoupMethod("2", false, true); } /** @@ -1159,6 +1175,7 @@ public void removeOptionMethodhIndexTwoMulti() throws Exception { @Alerts({"3", "3", "1", "One", "Two*", "Three"}) public void removeOptionMethodIndexThree() throws Exception { removeOptionMethod("3", false, false); + removeOptionOptgoupMethod("3", false, false); } /** @@ -1168,6 +1185,7 @@ public void removeOptionMethodIndexThree() throws Exception { @Alerts({"3", "3", "1", "One", "Two*", "Three*"}) public void removeOptionMethodIndexThreeMulti() throws Exception { removeOptionMethod("3", false, true); + removeOptionOptgoupMethod("3", false, true); } /** @@ -1177,6 +1195,7 @@ public void removeOptionMethodIndexThreeMulti() throws Exception { @Alerts({"3", "3", "1", "One", "Two*", "Three"}) public void removeOptionMethodIndexFour() throws Exception { removeOptionMethod("4", false, false); + removeOptionOptgoupMethod("4", false, false); } /** @@ -1186,6 +1205,7 @@ public void removeOptionMethodIndexFour() throws Exception { @Alerts({"3", "3", "1", "One", "Two*", "Three*"}) public void removeOptionMethodIndexFourMulti() throws Exception { removeOptionMethod("4", false, true); + removeOptionOptgoupMethod("4", false, true); } /** @@ -1195,6 +1215,7 @@ public void removeOptionMethodIndexFourMulti() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodOptionNullEmptySelect() throws Exception { removeOptionMethod("null", true, false); + removeOptionOptgoupMethod("null", true, false); } /** @@ -1204,6 +1225,7 @@ public void removeOptionMethodOptionNullEmptySelect() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodOptionNullEmptySelectMulti() throws Exception { removeOptionMethod("null", true, true); + removeOptionOptgoupMethod("null", true, true); } /** @@ -1213,6 +1235,7 @@ public void removeOptionMethodOptionNullEmptySelectMulti() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodNewOptionEmptySelect() throws Exception { removeOptionMethod("new Option('foo', '123')", true, false); + removeOptionOptgoupMethod("new Option('foo', '123')", true, false); } /** @@ -1222,6 +1245,7 @@ public void removeOptionMethodNewOptionEmptySelect() throws Exception { @Alerts({"0", "0", "-1"}) public void removeOptionMethodNewOptionEmptySelectMulti() throws Exception { removeOptionMethod("new Option('foo', '123')", true, true); + removeOptionOptgoupMethod("new Option('foo', '123')", true, true); } /** @@ -1231,6 +1255,7 @@ public void removeOptionMethodNewOptionEmptySelectMulti() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three"}) public void removeOptionMethodOptionNull() throws Exception { removeOptionMethod("null", false, false); + removeOptionOptgoupMethod("null", false, false); } /** @@ -1240,6 +1265,7 @@ public void removeOptionMethodOptionNull() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three*"}) public void removeOptionMethodOptionNullMulti() throws Exception { removeOptionMethod("null", false, true); + removeOptionOptgoupMethod("null", false, true); } /** @@ -1249,6 +1275,7 @@ public void removeOptionMethodOptionNullMulti() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three"}) public void removeOptionMethodNewOption() throws Exception { removeOptionMethod("new Option('foo', '123')", false, false); + removeOptionOptgoupMethod("new Option('foo', '123')", false, false); } /** @@ -1258,6 +1285,7 @@ public void removeOptionMethodNewOption() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three*"}) public void removeOptionMethodNewOptionMulti() throws Exception { removeOptionMethod("new Option('foo', '123')", false, true); + removeOptionOptgoupMethod("new Option('foo', '123')", false, true); } /** @@ -1267,6 +1295,7 @@ public void removeOptionMethodNewOptionMulti() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three"}) public void removeOptionMethodOptionFirst() throws Exception { removeOptionMethod("oSelect.options[0]", false, false); + removeOptionOptgoupMethod("oSelect.options[0]", false, false); } /** @@ -1276,6 +1305,7 @@ public void removeOptionMethodOptionFirst() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three*"}) public void removeOptionMethodOptionFirstMulti() throws Exception { removeOptionMethod("oSelect.options[0]", false, true); + removeOptionOptgoupMethod("oSelect.options[0]", false, true); } /** @@ -1294,6 +1324,7 @@ public void removeOptionMethodOptionSecond() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three*"}) public void removeOptionMethodOptionSecondMulti() throws Exception { removeOptionMethod("oSelect.options[1]", false, true); + removeOptionOptgoupMethod("oSelect.options[1]", false, true); } /** @@ -1303,6 +1334,7 @@ public void removeOptionMethodOptionSecondMulti() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three"}) public void removeOptionMethodOptionThird() throws Exception { removeOptionMethod("oSelect.options[2]", false, false); + removeOptionOptgoupMethod("oSelect.options[2]", false, false); } /** @@ -1312,6 +1344,7 @@ public void removeOptionMethodOptionThird() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three*"}) public void removeOptionMethodOptionThirdMulti() throws Exception { removeOptionMethod("oSelect.options[2]", false, true); + removeOptionOptgoupMethod("oSelect.options[2]", false, true); } /** @@ -1321,6 +1354,7 @@ public void removeOptionMethodOptionThirdMulti() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three"}) public void removeOptionMethodOptionLast() throws Exception { removeOptionMethod("oSelect.options[3]", false, false); + removeOptionOptgoupMethod("oSelect.options[3]", false, false); } /** @@ -1330,6 +1364,7 @@ public void removeOptionMethodOptionLast() throws Exception { @Alerts({"3", "2", "0", "Two*", "Three*"}) public void removeOptionMethodOptionLastMulti() throws Exception { removeOptionMethod("oSelect.options[3]", false, true); + removeOptionOptgoupMethod("oSelect.options[3]", false, true); } private void removeOptionMethod(final String param, final boolean empty, final boolean multi) throws Exception { @@ -1370,6 +1405,48 @@ private void removeOptionMethod(final String param, final boolean empty, final b loadPageVerifyTitle2(html); } + private void removeOptionOptgoupMethod(final String param, final boolean empty, final boolean multi) throws Exception { + String html = DOCTYPE_HTML + + "\n" + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + /** * @throws Exception if the test fails */ @@ -1960,7 +2037,7 @@ private void defaultSelectedValue(final String size, final boolean multiple) * @throws Exception if the test fails */ @Test - @Alerts("5") + @Alerts({"5", "null"}) public void size() throws Exception { final String html = DOCTYPE_HTML + "\n" @@ -1969,7 +2046,8 @@ public void size() throws Exception { + LOG_TITLE_FUNCTION + " function test() {\n" + " var select = document.getElementById('mySelect');\n" - + " log(select.size + 5);//to test if int or string\n" + + " log(select.size + 5);\n" //to test if int or string + + " log(select.getAttribute('size'));\n" + " }\n" + "\n" + "\n" @@ -1980,6 +2058,57 @@ public void size() throws Exception { loadPageVerifyTitle2(html); } + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"0", "one"}) + public void sizeNotNumeric() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + " \n" + + ""; + + loadPageVerifyTitle2(html); + } + /** * @throws Exception if an error occurs */ @@ -2855,4 +2984,413 @@ public void willValidate() throws Exception { loadPageVerifyTitle2(html); } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "true", "true", "true", "true"}) + public void checkValidityMirrorsWillValidateAcrossAllCases() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + " " + + " " + + " " + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * An editable select with a custom validity message must report + * checkValidity() false. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "true", "false", "false"}) + public void setCustomValidityOnEditableSelect_isInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A DISABLED select with a custom validity message must still + * report checkValidity() true -- disabled bars it from constraint + * validation entirely, so the custom error must not surface through + * checkValidity(), even though willValidate is already known to be false + * for this case. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "true", "false", "true"}) + public void setCustomValidityOnDisabledSelect_notInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A required select with no option selected (valueMissing) is + * genuinely invalid when editable, but must report checkValidity() true if + * ALSO disabled -- confirms the disabled-barring check takes priority over + * an actual constraint violation, not just over a custom validity message. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "true"}) + public void requiredNoSelectionDisabledSelect_checkValidityTrue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A required-select validity without any custom validity involved: + * confirms .validity.valueMissing/.valid react correctly to selecting a + * real option vs. leaving the empty placeholder selected. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"true", "false", "false", "true"}) + public void validityValueMissingForRequiredSelectWithNoSelection() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Clearing a previously-set custom validity message (empty string) must + * restore validity for an editable select -- confirms setCustomValidity is + * reversible, not just settable. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "false", "true"}) + public void clearCustomValidity_restoresValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The validationMessage should reflect the custom validity message for a + * validation-participating (editable) select, and should be empty for a + * barred-from-validation (disabled) one, regardless of a custom message + * being set. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"editable error", ""}) + public void validationMessageReflectsCustomValidityWhereApplicable() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "false"}) + public void reportValidityMatchesCheckValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + " " + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A DISABLED select inside a disabled fieldset (propagated disabling, + * rather than the select's own 'disabled' attribute) must also report + * checkValidity() true despite a custom validity message -- confirms the + * barring check consults isDisabled()'s ancestor-propagated result, not + * just the select's own attribute presence. + * @throws Exception if an error occurs + */ + @Test + @Alerts({"false", "true"}) + public void setCustomValidityOnSelectDisabledViaFieldset_notInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"invalid fired", "false"}) + public void selectCheckValidityFiresInvalidEvent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void selectCheckValidityDoesNotFireInvalidWhenActuallyValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void selectCheckValidityDoesNotFireInvalidOnDisabledControl() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"invalid fired", "false"}) + public void selectReportValidityFiresInvalidEvent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/html/HTMLTextAreaElementTest.java b/src/test/java/org/htmlunit/javascript/host/html/HTMLTextAreaElementTest.java index a97af36c602..928b21169a4 100644 --- a/src/test/java/org/htmlunit/javascript/host/html/HTMLTextAreaElementTest.java +++ b/src/test/java/org/htmlunit/javascript/host/html/HTMLTextAreaElementTest.java @@ -18,6 +18,8 @@ import org.htmlunit.junit.annotation.Alerts; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; @@ -90,30 +92,1661 @@ public void onChange() throws Exception { } /** - * Tests that setValue doesn't has side effect. Test for bug 1155063. + * Verifies that repeatedly setting a textarea's value via JavaScript reuses + * the existing child text node instead of removing and recreating it on every + * assignment. * @throws Exception if the test fails */ @Test - @Alerts({"TEXTAREA", "INPUT"}) - public void setValue() throws Exception { + @Alerts({"true", "true", "TEXTAREA"}) + public void setValuePreservesChildTextNodeIdentity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Verifies that the text node created by the *first* .value assignment + * on an initially-empty textarea is then reused (not recreated) on the + * *second* assignment -- i.e. the "no child yet" -> "has child, reuse it" + * transition works correctly. + * @throws Exception if the test fails + */ + @Test + @Alerts("true") + public void setValueReusesNodeCreatedByPreviousAssignment() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Verifies the "scan forward past non-text siblings" branch of + * setTextInternal() -- when a comment node precedes the text node, setting + * .value should locate and update the existing text node in place (via + * setData()) rather than disturbing the comment or creating a new node. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "2"}) + public void setValueWithLeadingCommentReusesTextNode() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Verifies the remove-and-recreate fallback path -- when a textarea + * has children but none of them is a text node (e.g. only a comment), setting + * .value should remove the non-text child and end up with exactly one text + * node containing the new value. + * @throws Exception if the test fails + */ + @Test + @Alerts({"2", "created"}) + public void setValueWithNoExistingTextNodeCreatesOne() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Checks whether setting .value when a textarea has + * MULTIPLE pre-existing text-node children only updates the first one via + * setData(), while getText()/.value concatenates all text children. If so, + * the reported value after assignment would incorrectly include leftover + * content from the second (untouched) text node. This is a separate concern + * from the node-identity fix and may expose an independent bug; confirm + * expected behavior against a real browser before trusting the @Alerts value. + * @throws Exception if the test fails + */ + @Test + @Alerts({"foobar", "2", "X", "2"}) + public void setValueWithMultipleExistingTextNodes() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Case 5: verifies the selection/caret position lands at the end of the new + * value after a .value assignment that reuses an existing text node -- to + * confirm the identity fix didn't inadvertently change the selectionStart/ + * selectionEnd behavior at the end of setTextInternal(). + * @throws Exception if the test fails + */ + @Test + @Alerts({"5", "5"}) + public void setValueMovesSelectionToEndAfterReuse() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Case 4a: pins down WHICH of two existing text-node children actually receives + * the new value, and which gets cleared, when .value is set on a textarea with + * multiple pre-existing text nodes. Resolves the ambiguity left open by + * setValueWithMultipleExistingTextNodes() (which only checked the combined + * .value and childNodes.length, not per-node data or identity/position). + * @throws Exception if the test fails + */ + @Test + @Alerts({"foo", "bar", "true", "true"}) + public void setValueWithMultipleExistingTextNodes_identifiesTargetNode() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Verifies the "clear all but one" behavior generalizes to three or + * more pre-existing text nodes, rather than a rule that only happens to look + * correct with exactly two (e.g. a pairwise first/last swap). + * @throws Exception if the test fails + */ + @Test + @Alerts({"X", "3", "a", "b", "c"}) + public void setValueWithThreeExistingTextNodes() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Verifies that text nodes separated by a non-text sibling (a comment) + * are still all cleared-not-removed, and that the comment itself is left + * untouched and in its original position. + * @throws Exception if the test fails + */ + @Test + @Alerts({"X", "3", "3", "8", "3", "foo", "c", "bar"}) + public void setValueWithTextNodesInterleavedWithComment() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Verifies behavior when the new value itself is the empty string, + * with multiple pre-existing text nodes -- checks whether "clear, don't remove" + * still holds, or whether browsers collapse/remove nodes differently when the + * net result is empty. + * @throws Exception if the test fails + */ + @Test + @Alerts({"", "2", "foo", "bar"}) + public void setValueEmptyStringWithMultipleExistingTextNodes() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Verifies the still-unconfirmed fallback branch -- setting + * .value when a textarea has children but NONE of them is a text node (only a + * comment). Determines whether the comment is removed and replaced by a new + * text node, or kept alongside a newly-appended text node. + * @throws Exception if the test fails + */ + @Test + @Alerts({"created", "1"}) + public void setValueWithOnlyNonTextChildCreatesTextNode() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A textarea parsed with text content should report that content as both + * its .value and its .defaultValue immediately, with no script interaction + * required. + * @throws Exception if the test fails + */ + @Test + @Alerts({"hello world", "hello world"}) + public void initialValueMatchesParsedContent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Per the HTML parsing algorithm, a single leading newline immediately + * after the opening tag is stripped from both .value and .defaultValue. + * @throws Exception if the test fails + */ + @Test + @Alerts({"hello", "5"}) + public void initialValueStripsLeadingNewline() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * An empty textarea has an empty .value and .defaultValue, and no + * childNodes. + * @throws Exception if the test fails + */ + @Test + @Alerts({"", "", "0"}) + public void initialStateOfEmptyTextarea() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Appending a text node to a textarea whose value has never been set via + * script (dirty flag still false) should update .value to include the new + * text, since children-changed-steps re-derive the raw value from child + * content while clean. + * @throws Exception if the test fails + */ + @Test + @Alerts("foobar") + public void appendingTextNodeUpdatesValueWhileClean() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Removing a child text node from a still-clean textarea should update + * .value to reflect the remaining content. + * @throws Exception if the test fails + */ + @Test + @Alerts("") + public void removingTextNodeUpdatesValueWhileClean() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Directly mutating an existing child text node's data (not replacing + * the node, just its data) while still clean should also update .value. + * @throws Exception if the test fails + */ + @Test + @Alerts("changed") + public void mutatingChildTextNodeDataUpdatesValueWhileClean() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Setting .textContent on a still-clean textarea should update .value, + * per the spec's explicit "textContent IDL attribute changes value" hook. + * @throws Exception if the test fails + */ + @Test + @Alerts("bar") + public void settingTextContentUpdatesValueWhileClean() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Setting .innerHTML on a still-clean textarea replaces its children, + * which should also trigger the same children-changed sync as any other + * child mutation. + * @throws Exception if the test fails + */ + @Test + @Alerts("bar") + public void settingInnerHtmlUpdatesValueWhileClean() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Per spec discussion, browsers move the text entry cursor to the end of + * the control when .textContent changes while the dirty flag is false (the + * same cursor-repositioning behavior as the .value setter). Confirms whether + * this applies here too. + * @throws Exception if the test fails + */ + @Test + @Alerts({"0", "0"}) + public void settingTextContentMovesCursorToEndWhileClean() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Once .value has been set via script, the dirty flag is true, so a + * subsequent child-append no longer affects .value. + * @throws Exception if the test fails + */ + @Test + @Alerts("X") + public void settingValueThenAppendingChild_appendHasNoEffect() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same as settingValueThenAppendingChild_appendHasNoEffect, + * but removing an existing child after dirtying should also + * have no effect on .value. + * @throws Exception if the test fails + */ + @Test + @Alerts("X") + public void settingValueThenRemovingChild_removeHasNoEffect() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Guard applies to .textContent assignment after dirtying -- once + * .value has been set, setting .textContent should NOT change .value (only + * the children, decoupled from the raw value). + * @throws Exception if the test fails + */ + @Test + @Alerts("X") + public void settingValueThenSettingTextContent_textContentHasNoEffectOnValue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The .value setter itself must not touch the DOM child nodes at all -- + * childNodes.length and content should be exactly what they were before the + * assignment. + * @throws Exception if the test fails + */ + @Test + @Alerts({"1", "true", "foo"}) + public void settingValueDoesNotModifyChildNodes() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The .value setter moves the text entry cursor to the end of the + * control. + * @throws Exception if the test fails + */ + @Test + @Alerts({"5", "5"}) + public void settingValueMovesCursorToEnd() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Per spec discussion, browsers should do nothing (not even move the + * cursor) when .value is set to the SAME value it already holds. Worth + * confirming since this is a known point of spec/browser divergence. + * @throws Exception if the test fails + */ + @Test + @Alerts({"1", "2"}) + public void settingValueToSameValue_selectionUnchanged() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * After dirtying via .value, calling the form's reset() should bring + * .value back to the current child text content and clear the dirty flag, + * so that a SUBSEQUENT child mutation is once again reflected in .value. + * @throws Exception if the test fails + */ + @Test + @Alerts({"foo", "foobar"}) + public void resetClearsDirtyFlag_laterChildMutationAffectsValueAgain() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * If the child nodes were mutated WHILE the dirty flag was + * true (so children-changed-steps were suppressed and never synced), reset() + * should still pick up whatever the children currently contain at the moment + * of reset, NOT the original text present when the page first loaded. + * @throws Exception if the test fails + */ + @Test + @Alerts("original-appended") + public void resetReflectsCurrentChildContentNotOriginalParsedContent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Baseline reset case -- dirty then reset with untouched children should + * simply restore the original parsed text. + * @throws Exception if the test fails + */ + @Test + @Alerts("original") + public void resetRestoresOriginalValueWhenChildrenUntouched() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Reset triggered via a <button type=reset> click (real user-style + * reset path) should behave identically to a scripted form.reset() call. + * @throws Exception if the test fails + */ + @Test + @Alerts("original") + public void resetViaResetButtonClickBehavesSameAsScriptedReset() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + driver.findElement(By.id("resetBtn")).click(); + final String value = (String) ((JavascriptExecutor) driver) + .executeScript("return document.form1.question.value;"); + assertEquals(getExpectedAlerts()[0], value); + } + + /** + * The reset() called on a field whose + * value was NEVER changed. Unlike the current HtmlInput.setValue() fix + * (conditional on old-value != new-value), HtmlTextArea.reset() as currently + * written ALWAYS moves the cursor to the end unconditionally -- it does not + * go through setText()/setTextInternal() at all, so it has no "did the value + * actually change" guard. This checks whether that unconditional behavior + * matches real browsers, or whether real browsers also skip the cursor move + * when nothing actually changed (in which case HtmlTextArea.reset() would + * need the same kind of conditional guard added). + * @throws Exception if the test fails + */ + @Test + @Alerts({"5", "5", "original", "5", "5"}) + public void resetOnNeverDirtiedTextarea_selectionPosition() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement textarea = driver.findElement(By.id("theTextarea")); + + // click into the field and move the caret, WITHOUT ever changing its + // value (no sendKeys typing, no .value assignment) + textarea.click(); + textarea.sendKeys(Keys.ARROW_LEFT, Keys.ARROW_LEFT, Keys.ARROW_LEFT); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + final Long selStartBeforeReset = (Long) js.executeScript( + "return arguments[0].selectionStart;", textarea); + final Long selEndBeforeReset = (Long) js.executeScript( + "return arguments[0].selectionEnd;", textarea); + + driver.findElement(By.id("resetBtn")).click(); + + final Long selStartAfterReset = (Long) js.executeScript( + "return arguments[0].selectionStart;", textarea); + final Long selEndAfterReset = (Long) js.executeScript( + "return arguments[0].selectionEnd;", textarea); + final String valueAfterReset = textarea.getDomProperty("value"); + + assertEquals(getExpectedAlerts()[0], String.valueOf(selStartBeforeReset)); + assertEquals(getExpectedAlerts()[1], String.valueOf(selEndBeforeReset)); + assertEquals(getExpectedAlerts()[2], valueAfterReset); + assertEquals(getExpectedAlerts()[3], String.valueOf(selStartAfterReset)); + assertEquals(getExpectedAlerts()[4], String.valueOf(selEndAfterReset)); + } + + /** + * Same "never touched" scenario, but with + * an explicit mid-field selection RANGE set beforehand via script, to check + * whether reset() collapses/repositions a real selection range too, or only + * affects a collapsed caret position. + * @throws Exception if the test fails + */ + @Test + @Alerts({"original", "2", "5"}) + public void resetOnNeverDirtiedTextareaWithExplicitSelectionRange_selectionPosition() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement textarea = driver.findElement(By.id("theTextarea")); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + js.executeScript("arguments[0].setSelectionRange(2, 5);", textarea); + + driver.findElement(By.id("resetBtn")).click(); + + final Long selStartAfterReset = (Long) js.executeScript( + "return arguments[0].selectionStart;", textarea); + final Long selEndAfterReset = (Long) js.executeScript( + "return arguments[0].selectionEnd;", textarea); + final String valueAfterReset = textarea.getDomProperty("value"); + + assertEquals(getExpectedAlerts()[0], valueAfterReset); + assertEquals(getExpectedAlerts()[1], String.valueOf(selStartAfterReset)); + assertEquals(getExpectedAlerts()[2], String.valueOf(selEndAfterReset)); + } + + /** + * The .defaultValue always reflects the current child text content, + * regardless of the dirty flag -- even after .value has been dirtied and + * decoupled from the children. + * @throws Exception if the test fails + */ + @Test + @Alerts({"original", "X"}) + public void defaultValueReflectsChildContentRegardlessOfDirtyFlag() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Setting .defaultValue mutates the child nodes (it's specified in terms + * of textContent), which in turn triggers children-changed-steps -- so while + * still CLEAN, setting .defaultValue should also update .value. + * @throws Exception if the test fails + */ + @Test + @Alerts("newDefault") + public void settingDefaultValueWhileClean_alsoUpdatesValue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same operation as E2, but performed AFTER .value has already been + * dirtied -- setting .defaultValue should still update the children (so + * .defaultValue itself changes) but must NOT affect the already-dirtied + * .value. + * @throws Exception if the test fails + */ + @Test + @Alerts({"newDefault", "X"}) + public void settingDefaultValueWhileDirty_doesNotUpdateValue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Per spec discussion, textContent/defaultValue/value + * "should" all agree when a textarea has nested-element children containing + * text (rather than direct text-node children) -- but real browsers are + * known to disagree with the spec AND with each other on this exact case. + * Run this primarily to document actual current behavior across browsers, + * not to assert a single "correct" answer. + * @throws Exception if the test fails + */ + @Test + @Alerts({"TEXT", "", ""}) + public void nestedElementTextContentInteraction() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Even though a same-value assignment leaves the selection + * untouched, the dirty flag must still flip to true (per spec: "set the + * element's dirty value flag to true" happens unconditionally, only the + * cursor move is conditional). Proven indirectly: if the flag were still + * false, a later child mutation would still be reflected in .value; if the + * flag correctly flipped true, the later child mutation must be ignored. + * @throws Exception if the test fails + */ + @Test + @Alerts("hello") + public void settingValueToSameValue_stillSetsDirtyFlag() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Selection must be preserved across MULTIPLE consecutive same-value + * assignments, not just the first one -- confirms the comparison is always + * against the current value at the time of each call, not just a one-time + * check. + * @throws Exception if the test fails + */ + @Test + @Alerts({"1", "2"}) + public void settingValueToSameValueTwice_selectionPreservedBothTimes() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The "old value" comparison must be against the CURRENT raw value, not the + * page's originally-parsed text. After dirtying to 'X', setting .value back + * to the ORIGINAL text ('hello') is a change relative to the current raw + * value ('X'), so the cursor MUST move -- even though 'hello' matches what + * was there at parse time. + * @throws Exception if the test fails + */ + @Test + @Alerts({"5", "5"}) + public void settingValueBackToOriginalText_cursorMovesBecauseCurrentValueDiffers() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Edge case: assigning the empty string to an already-empty value should + * also be treated as "no change" -- no cursor move, but still dirties the + * flag. + * @throws Exception if the test fails + */ + @Test + @Alerts("") + public void settingEmptyValueToAlreadyEmptyValue_selectionUnchangedButDirty() throws Exception { final String html = DOCTYPE_HTML + "\n" + "\n" + "\n" + "
\n" + " \n" - + " \n" + "
\n" + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Confirms the ordinary changing-value path still moves the cursor to the + * end -- guards against the new conditional accidentally suppressing the + * cursor move for genuine changes, not just same-value assignments. + * @throws Exception if the test fails + */ + @Test + @Alerts({"7", "7"}) + public void settingValueToDifferentValue_cursorStillMovesToEnd() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + "\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Confirms that typing into a textarea (real keyboard simulation, not a + * scripted .value assignment) updates .value but leaves .textContent / + * childNodes untouched -- the JS-observable version of the typingAndClone() + * Java-level test, verifying the same value/textContent split holds for real + * browsers, not just HtmlUnit's internal model. + * @throws Exception if the test fails + */ + @Test + @Alerts({"4711", "", "0"}) + public void typingUpdatesValueButNotTextContent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement textarea = driver.findElement(By.id("foo")); + textarea.click(); + textarea.sendKeys("4711"); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + final String value = (String) js.executeScript("return arguments[0].value;", textarea); + final String textContent = (String) js.executeScript("return arguments[0].textContent;", textarea); + final Long childNodeCount = (Long) js.executeScript("return arguments[0].childNodes.length;", textarea); + + assertEquals(getExpectedAlerts()[0], value); + assertEquals(getExpectedAlerts()[1], textContent); + assertEquals(getExpectedAlerts()[2], String.valueOf(childNodeCount)); + } + + /** + * Companion case: same real-keyboard-typing scenario, but starting from a + * textarea that already has parsed content -- confirms typed characters + * don't get appended to (or otherwise disturb) the existing child text node, + * even though .value correctly reflects the combined typed result. + * @throws Exception if the test fails + */ + @Test + @Alerts({"seed-typed", "seed"}) + public void typingIntoNonEmptyTextareaLeavesOriginalChildTextNodeUnchanged() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement textarea = driver.findElement(By.id("foo")); + textarea.click(); + // move caret to end before typing, since click() alone doesn't guarantee position + textarea.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + textarea.sendKeys("-typed"); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + final String value = (String) js.executeScript("return arguments[0].value;", textarea); + final String textContent = (String) js.executeScript("return arguments[0].textContent;", textarea); + + assertEquals(getExpectedAlerts()[0], value); + assertEquals(getExpectedAlerts()[1], textContent); + } + + /** + * After typing (which dirties .value but never touches the DOM + * children), clicking a reset button should bring .value back in sync with + * .textContent -- since reset() clears the dirty flag and .textContent was + * never disturbed by typing in the first place, the two must now be equal. + * @throws Exception if the test fails + */ + @Test + @Alerts({"seed-typed", "seed", "seed"}) + public void resetAfterTyping_valueMatchesTextContentAgain() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement textarea = driver.findElement(By.id("foo")); + textarea.click(); + textarea.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + textarea.sendKeys("-typed"); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + final String valueBeforeReset = (String) js.executeScript("return arguments[0].value;", textarea); + final String textContentBeforeReset = + (String) js.executeScript("return arguments[0].textContent;", textarea); + + driver.findElement(By.id("resetBtn")).click(); + + final String valueAfterReset = (String) js.executeScript("return arguments[0].value;", textarea); + final String textContentAfterReset = + (String) js.executeScript("return arguments[0].textContent;", textarea); + + assertEquals(getExpectedAlerts()[0], valueBeforeReset); + assertEquals(getExpectedAlerts()[1], textContentBeforeReset); + assertEquals(getExpectedAlerts()[2], valueAfterReset); + assertEquals(textContentAfterReset, valueAfterReset); + } + + /** + * If the DOM children are mutated by script WHILE .value is dirty + * (typing already happened, so children-changed effects on .value are + * suppressed), a subsequent reset() must pick up whatever the children + * CURRENTLY contain -- including that mutation -- not the page's original + * parsed text. Confirmed here by asserting .value equals the LIVE + * .textContent (which already reflects the mutation) immediately after the + * reset button click, using real typing + a real click rather than only + * scripted reset(). + * @throws Exception if the test fails + */ + @Test + @Alerts({"seed-typed", "seed-appended", "seed-appended"}) + public void resetAfterTypingAndChildMutationWhileDirty_valueMatchesCurrentTextContent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement textarea = driver.findElement(By.id("foo")); + textarea.click(); + textarea.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + textarea.sendKeys("-typed"); // dirties .value; children still just "seed" + + final JavascriptExecutor js = (JavascriptExecutor) driver; + // mutate the children directly WHILE .value is dirty -- must have no + // effect on .value yet, but DOES change what reset() should pick up + js.executeScript("arguments[0].appendChild(document.createTextNode('-appended'));", textarea); + + final String valueBeforeReset = (String) js.executeScript("return arguments[0].value;", textarea); + final String textContentBeforeReset = + (String) js.executeScript("return arguments[0].textContent;", textarea); + + driver.findElement(By.id("resetBtn")).click(); + + final String valueAfterReset = (String) js.executeScript("return arguments[0].value;", textarea); + + assertEquals(getExpectedAlerts()[0], valueBeforeReset); + assertEquals(getExpectedAlerts()[1], textContentBeforeReset); + assertEquals(getExpectedAlerts()[2], valueAfterReset); + } + + /** + * After dirtying .value via real typing (so it has diverged from + * the child text content), a deep clone must preserve BOTH the dirtied value + * AND its decoupling from textContent -- not silently revert to the (cloned) + * children's content. + * @throws Exception if the test fails + */ + @Test + @Alerts({"seed-typed", "seed"}) + public void cloneNodeAfterTyping_cloneRetainsDirtiedValue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement textarea = driver.findElement(By.id("foo")); + textarea.click(); + textarea.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + textarea.sendKeys("-typed"); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + final String cloneValue = (String) js.executeScript( + "return arguments[0].cloneNode(true).value;", textarea); + final String cloneTextContent = (String) js.executeScript( + "return arguments[0].cloneNode(true).textContent;", textarea); + + assertEquals(getExpectedAlerts()[0], cloneValue); + assertEquals(getExpectedAlerts()[1], cloneTextContent); + } + + /** + * A deep clone's children must be independent of the original's -- mutating + * the original's children AFTER cloning must not affect the clone's + * .textContent or (for a still-clean clone) its .value. + * @throws Exception if the test fails + */ + @Test + @Alerts({"changed", "seed"}) + public void cloneNodeDeep_childrenAreIndependentOfOriginal() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement textarea = driver.findElement(By.id("foo")); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + js.executeScript( + "var c = arguments[0].cloneNode(true);" + + "c.id = 'clone';" + + "document.body.appendChild(c);", + textarea); + + // mutate the ORIGINAL's children only, after cloning + js.executeScript( + "arguments[0].removeChild(arguments[0].firstChild);" + + "arguments[0].appendChild(document.createTextNode('changed'));", + textarea); + + final String originalValue = (String) js.executeScript("return arguments[0].value;", textarea); + final String cloneValue = (String) js.executeScript( + "return document.getElementById('clone').value;"); + + assertEquals(getExpectedAlerts()[0], originalValue); + assertEquals(getExpectedAlerts()[1], cloneValue); + } + + /** + * A shallow clone (deep=false) doesn't copy children at all -- but since the + * dirtied value lives on the element itself, not in the DOM tree, a shallow + * clone of an already-dirtied textarea must still preserve the dirtied + * value, even though its childNodes/textContent end up empty. + * @throws Exception if the test fails + */ + @Test + @Alerts({"seed-typed", ""}) + public void cloneNodeShallowAfterTyping_stillRetainsDirtiedValue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement textarea = driver.findElement(By.id("foo")); + textarea.click(); + textarea.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + textarea.sendKeys("-typed"); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + final String cloneValue = (String) js.executeScript( + "return arguments[0].cloneNode(false).value;", textarea); + final String cloneTextContent = (String) js.executeScript( + "return arguments[0].cloneNode(false).textContent;", textarea); + + assertEquals(getExpectedAlerts()[0], cloneValue); + assertEquals(getExpectedAlerts()[1], cloneTextContent); + } + + /** + * After cloning a still-CLEAN textarea and attaching the clone to the + * document, typing independently into the original and the clone (real + * keyboard input on each) must not cross-contaminate either one's value. + * @throws Exception if the test fails + */ + @Test + @Alerts({"original-text", "clone-text"}) + public void cloneNodeThenIndependentTyping_noCrossContamination() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + " \n" + + " \n" + + "\n" + + ""; + + final WebDriver driver = loadPage2(html); + final WebElement original = driver.findElement(By.id("foo")); + final WebElement clone = driver.findElement(By.id("clone")); + + original.click(); + original.sendKeys("original-text"); + clone.click(); + clone.sendKeys("clone-text"); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + final String originalValue = (String) js.executeScript("return arguments[0].value;", original); + final String cloneValue = (String) js.executeScript("return arguments[0].value;", clone); + + assertEquals(getExpectedAlerts()[0], originalValue); + assertEquals(getExpectedAlerts()[1], cloneValue); + } + + /** + * Resetting a clone (via a real click on its OWN form's reset button) must + * only affect the clone -- the original, sitting in a separate form, must be + * untouched. + * @throws Exception if the test fails + */ + @Test + @Alerts({"seed-original-dirtied", "seed"}) + public void cloneNodeThenResetOnCloneOnly_doesNotAffectOriginal() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + " \n" + "\n" + ""; - loadPageVerifyTitle2(html); + final WebDriver driver = loadPage2(html); + final WebElement original = driver.findElement(By.id("foo")); + final WebElement clone = driver.findElement(By.id("clone")); + + original.click(); + original.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + original.sendKeys("-original-dirtied"); + + clone.click(); + clone.sendKeys(Keys.chord(Keys.CONTROL, Keys.END)); + clone.sendKeys("-clone-dirtied"); + + // reset only form2, which contains the clone + driver.findElement(By.id("resetBtn2")).click(); + + final JavascriptExecutor js = (JavascriptExecutor) driver; + final String originalValue = (String) js.executeScript("return arguments[0].value;", original); + final String cloneValue = (String) js.executeScript("return arguments[0].value;", clone); + + assertEquals(getExpectedAlerts()[0], originalValue); + assertEquals(getExpectedAlerts()[1], cloneValue); } /** @@ -929,4 +2562,343 @@ public void willValidate() throws Exception { loadPageVerifyTitle2(html); } + + /** + * An enabled, editable textarea with no custom validity issue + * reports checkValidity() true and an empty validationMessage. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", ""}) + public void checkValidityWithoutCustomValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * An enabled, editable textarea with a custom validity message set must + * report checkValidity() false. + * @throws Exception if the test fails + */ + @Test + @Alerts({"true", "true", "false", "false"}) + public void setCustomValidityOnEditableTextarea_isInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A DISABLED textarea with a custom validity message must still + * report checkValidity() true -- disabled bars it from constraint + * validation entirely, so the custom error must not surface through + * checkValidity(), even though willValidate is already known to be false + * for this case. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "true"}) + public void setCustomValidityOnDisabledTextarea_notInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Same as above but for READONLY instead of disabled -- the + * existing willValidate() test already confirms readonly returns + * willValidate=false. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true", "false", "true"}) + public void setCustomValidityOnReadonlyTextarea_notInvalid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * Clearing a previously-set custom validity message (empty string) must + * restore validity for an editable textarea. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false", "true"}) + public void clearCustomValidity_restoresValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * The validationMessage should reflect the custom validity message for a + * validation-participating (editable) textarea, and should be empty for a + * barred-from-validation (disabled) one, regardless of a custom message + * being set. + * @throws Exception if the test fails + */ + @Test + @Alerts({"editable error", ""}) + public void validationMessageReflectsCustomValidityWhereApplicable() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "false"}) + public void reportValidityMatchesCheckValidity() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * A required, empty textarea is genuinely invalid (valueMissing) + * when editable, but must report checkValidity() true if ALSO disabled. + * @throws Exception if the test fails + */ + @Test + @Alerts({"false", "true"}) + public void requiredEmptyDisabledTextarea_checkValidityTrue() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"invalid fired", "false"}) + public void textareaCheckValidityFiresInvalidEvent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void textareaCheckValidityDoesNotFireInvalidWhenActuallyValid() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts("true") + public void textareaCheckValidityDoesNotFireInvalidOnDisabledControl() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts({"invalid fired", "false"}) + public void textareaReportValidityFiresInvalidEvent() throws Exception { + final String html = DOCTYPE_HTML + + "\n" + + "\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + ""; + + loadPageVerifyTitle2(html); + } } diff --git a/src/test/java/org/htmlunit/javascript/host/worker/WorkerNavigatorTest.java b/src/test/java/org/htmlunit/javascript/host/worker/WorkerNavigatorTest.java index dff4acf7936..05bd74c422b 100644 --- a/src/test/java/org/htmlunit/javascript/host/worker/WorkerNavigatorTest.java +++ b/src/test/java/org/htmlunit/javascript/host/worker/WorkerNavigatorTest.java @@ -166,7 +166,7 @@ public void product() throws Exception { + "(KHTML,\\slike\\sGecko)\\sChrome/150.0.0.0\\sSafari/537.36", EDGE = "Mozilla/5.0\\s(Windows\\sNT\\s10.0;\\sWin64;\\sx64)\\sAppleWebKit/537.36\\s" + "(KHTML,\\slike\\sGecko)\\sChrome/150.0.0.0\\sSafari/537.36\\sEdg/150.0.0.0", - FF = "Mozilla/5.0\\s(Windows\\sNT\\s10.0;\\sWin64;\\sx64;\\srv:152.0)\\sGecko/20100101\\sFirefox/152.0", + FF = "Mozilla/5.0\\s(Windows\\sNT\\s10.0;\\sWin64;\\sx64;\\srv:153.0)\\sGecko/20100101\\sFirefox/153.0", FF_ESR = "Mozilla/5.0\\s(Windows\\sNT\\s10.0;\\sWin64;\\sx64;\\srv:140.0)\\sGecko/20100101\\sFirefox/140.0") public void userAgent() throws Exception { final String workerJs = "postMessage(navigator.userAgent);\n"; diff --git a/src/test/java/org/htmlunit/libraries/TinyMceTest.java b/src/test/java/org/htmlunit/libraries/TinyMceTest.java index 395877ff535..5ac1bd6275f 100644 --- a/src/test/java/org/htmlunit/libraries/TinyMceTest.java +++ b/src/test/java/org/htmlunit/libraries/TinyMceTest.java @@ -64,8 +64,8 @@ public void api() throws Exception { EDGE = {"89", "1"}) @HtmlUnitNYI(CHROME = {"70", "50"}, EDGE = {"70", "50"}, - FF = {"70", "50"}, - FF_ESR = {"70", "50"}) + FF = {"89", "45"}, + FF_ESR = {"89", "45"}) public void basic() throws Exception { test("basic", Integer.parseInt(getExpectedAlerts()[0]), Integer.parseInt(getExpectedAlerts()[1])); } diff --git a/src/test/java/org/htmlunit/platform/font/AwtFontUtilTest.java b/src/test/java/org/htmlunit/platform/font/AwtFontUtilTest.java new file mode 100644 index 00000000000..e9d8e6a144d --- /dev/null +++ b/src/test/java/org/htmlunit/platform/font/AwtFontUtilTest.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2002-2026 Gargoyle Software Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.htmlunit.platform.font; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link AwtFontUtil}. + * + * @author Ronald Brill + */ +public class AwtFontUtilTest { + + private final FontUtil fontUtil_ = new AwtFontUtil(); + + /** + * A single short line, wide enough box, should never wrap: exactly one line. + */ + @Test + public void countLines_singleShortLine() { + assertEquals(1, fontUtil_.countLines("Hello", 1000, "12px")); + } + + /** + * Empty content should report zero lines. + */ + @Test + public void countLines_emptyContent() { + assertEquals(0, fontUtil_.countLines("", 1000, "12px")); + } + + /** + * {@code null} content should not throw and should report zero lines, + * relying on the null-safety of {@code StringUtils.split(null, ...)}. + */ + @Test + public void countLines_nullContent() { + assertEquals(0, fontUtil_.countLines(null, 1000, "12px")); + } + + /** + * Explicit newlines with real text on each line: two lines in, two lines out + * (given a pixel width wide enough that neither line wraps). + */ + @Test + public void countLines_multipleExplicitLines() { + assertEquals(2, fontUtil_.countLines("Hello\nWorld", 1000, "12px")); + } + + /** + * Blank lines (whitespace-only or empty, between explicit newlines) should + * each count as exactly one line rather than being skipped or merged. + * This directly probes the interaction between + * {@code StringUtils.split(content, '\n')} and the blank-line branch. + */ + @Test + public void countLines_blankLineBetweenTextLines() { + assertEquals(3, fontUtil_.countLines("Hello\n\nWorld", 1000, "12px")); + } + + /** + * A line consisting only of whitespace should still count as one line. + */ + @Test + public void countLines_whitespaceOnlyLine() { + assertEquals(1, fontUtil_.countLines(" ", 1000, "12px")); + } + + /** + * Multiple consecutive blank lines should each be counted individually, + * not collapsed into fewer lines by the underlying split. + */ + @Test + public void countLines_multipleConsecutiveBlankLines() { + assertEquals(5, fontUtil_.countLines("A\n\n\n\nB", 1000, "12px")); + } + + /** + * A trailing newline at the end of the content: verifies whether a + * trailing empty segment is (or is not) counted as an extra line. + * Documents current behavior rather than asserting a "correct" answer, + * since the semantics of a trailing newline are easy to get wrong silently. + */ + @Test + public void countLines_trailingNewline() { + final int lines = fontUtil_.countLines("Hello\n", 1000, "12px"); + assertTrue(lines == 1 || lines == 2, + "Unexpected line count for trailing newline: " + lines); + } + + /** + * A long line with a narrow pixel width should wrap into more than one + * layout line, exercising the {@code LineBreakMeasurer} branch. + */ + @Test + public void countLines_longLineWrapsWithNarrowWidth() { + final String longLine = + "The quick brown fox jumps over the lazy dog. ".repeat(10); + final int wideLines = fontUtil_.countLines(longLine, 5000, "12px"); + final int narrowLines = fontUtil_.countLines(longLine, 50, "12px"); + + assertTrue(narrowLines > wideLines, + "Narrower pixel width should force more line breaks: " + + "wide=" + wideLines + " narrow=" + narrowLines); + } + + /** + * A single line with no whitespace at all (so {@code LineBreakMeasurer} + * cannot find a break point) combined with a very narrow width should not + * loop forever; it must terminate at or before the internal safety cap. + * Currently that cap is a hardcoded {@code 1000} inside + * {@link AwtFontUtil#countLines}. + */ + @Test + public void countLines_unbreakableLineRespectsSafetyCap() { + final String unbreakable = "a".repeat(5000); + final int lines = fontUtil_.countLines(unbreakable, 1, "12px"); + + assertTrue(lines <= 1000, + "countLines should never exceed the internal safety cap, got: " + lines); + } + + /** + * Sanity check that a larger font size, at a fixed pixel width, tends to + * produce at least as many wrapped lines as a smaller font size (larger + * glyphs need more line breaks to fit the same width). This exercises the + * {@code fontSizeInt / 1.1} scaling factor indirectly. + */ + @Test + public void countLines_largerFontSizeWrapsAtLeastAsMuch() { + final String longLine = + "The quick brown fox jumps over the lazy dog. ".repeat(10); + final int smallFontLines = fontUtil_.countLines(longLine, 300, "10px"); + final int largeFontLines = fontUtil_.countLines(longLine, 300, "30px"); + + assertTrue(largeFontLines >= smallFontLines, + "Larger font size should not produce fewer wrapped lines: " + + "small=" + smallFontLines + " large=" + largeFontLines); + } + + /** + * Multiple paragraphs, each independently subject to wrapping, should sum + * their individual line counts. + */ + @Test + public void countLines_multipleWrappingParagraphs() { + final String paragraph = "The quick brown fox jumps over the lazy dog. ".repeat(5); + final String content = paragraph + "\n" + paragraph; + + final int singleParagraphLines = fontUtil_.countLines(paragraph, 200, "12px"); + final int combinedLines = fontUtil_.countLines(content, 200, "12px"); + + assertEquals(singleParagraphLines * 2, combinedLines); + } +} diff --git a/src/test/java/org/htmlunit/util/PrimitiveWebServer.java b/src/test/java/org/htmlunit/util/PrimitiveWebServer.java index 8a0f63eeef6..1def296c77f 100644 --- a/src/test/java/org/htmlunit/util/PrimitiveWebServer.java +++ b/src/test/java/org/htmlunit/util/PrimitiveWebServer.java @@ -27,6 +27,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.apache.commons.io.IOUtils; @@ -46,10 +47,11 @@ public class PrimitiveWebServer implements Closeable { private final int port_; private final String firstResponse_; + private final String secondResponse_; private final String otherResponse_; private ServerSocket server_; private Charset charset_ = StandardCharsets.ISO_8859_1; - private final List requests_ = new ArrayList<>(); + private final List requests_ = Collections.synchronizedList(new ArrayList<>()); /** * Constructs a new SimpleWebServer. @@ -61,8 +63,38 @@ public class PrimitiveWebServer implements Closeable { */ public PrimitiveWebServer(final Charset charset, final String firstResponse, final String otherResponse) throws Exception { - port_ = WebTestCase.PORT_PRIMITIVE_SERVER; + this(charset, firstResponse, null, otherResponse); + } + + /** + * Constructs a new SimpleWebServer. + * + * @param charset the charset + * @param firstResponse the first response, must contain the full response (to start with "HTTP/1.1 200 OK") + * @param secondResponse the second response, must contain the full response (to start with "HTTP/1.1 200 OK") or null if not used + * @param otherResponse the subsequent response, must contain the full response (to start with "HTTP/1.1 200 OK") + * @throws Exception in case of error + */ + public PrimitiveWebServer(final Charset charset, final String firstResponse, final String secondResponse, final String otherResponse) + throws Exception { + this(WebTestCase.PORT_PRIMITIVE_SERVER, charset, firstResponse, secondResponse, otherResponse); + } + + /** + * Constructs a new SimpleWebServer. + * + * @param port the port + * @param charset the charset + * @param firstResponse the first response, must contain the full response (to start with "HTTP/1.1 200 OK") + * @param secondResponse the second response, must contain the full response (to start with "HTTP/1.1 200 OK") or null if not used + * @param otherResponse the subsequent response, must contain the full response (to start with "HTTP/1.1 200 OK") + * @throws Exception in case of error + */ + public PrimitiveWebServer(final int port, final Charset charset, final String firstResponse, final String secondResponse, final String otherResponse) + throws Exception { + port_ = port; firstResponse_ = firstResponse; + secondResponse_ = secondResponse; otherResponse_ = otherResponse; if (charset != null) { charset_ = charset; @@ -95,60 +127,64 @@ private void start() throws Exception { } new Thread(() -> { - boolean first = true; + int responseCount = 0; try { while (true) { - final Socket socket = server_.accept(); - final InputStream in = socket.getInputStream(); - final CharArrayWriter writer = new CharArrayWriter(); + try (final Socket socket = server_.accept()) { + final InputStream in = socket.getInputStream(); + final CharArrayWriter writer = new CharArrayWriter(); - String requestString = writer.toString(); - int i; + String requestString = writer.toString(); + int i; - while ((i = in.read()) != -1) { - writer.append((char) i); - requestString = writer.toString(); + while ((i = in.read()) != -1) { + writer.append((char) i); + requestString = writer.toString(); - if (i == '\n' && requestString.endsWith("\r\n\r\n")) { - break; + if (i == '\n' && requestString.endsWith("\r\n\r\n")) { + break; + } } - } - final int contentLengthPos = StringUtils.indexOfIgnoreCase(requestString, HttpHeader.CONTENT_LENGTH); - if (contentLengthPos > -1) { - final int endPos = requestString.indexOf('\n', contentLengthPos + 16); - final String toParse = requestString.substring(contentLengthPos + 16, endPos); - final int contentLength = Integer.parseInt(toParse.trim()); - - if (contentLength > 0) { - final byte[] charArray = new byte[contentLength]; - IOUtils.read(in, charArray, 0, contentLength); - requestString += new String(charArray); + final int contentLengthPos = StringUtils.indexOfIgnoreCase(requestString, HttpHeader.CONTENT_LENGTH); + if (contentLengthPos > -1) { + final int endPos = requestString.indexOf('\n', contentLengthPos + 16); + final String toParse = requestString.substring(contentLengthPos + 16, endPos); + final int contentLength = Integer.parseInt(toParse.trim()); + + if (contentLength > 0) { + final byte[] charArray = new byte[contentLength]; + IOUtils.readFully(in, charArray); + requestString += new String(charArray); + } } - } - final String response; - if (requestString.isEmpty() - || requestString.contains("/favicon.ico")) { - response = "HTTP/1.1 404 Not Found\r\n" - + "Content-Length: 0\r\n" - + "Connection: close\r\n" - + "\r\n"; - } - else { - requests_.add(requestString); - if (first || otherResponse_ == null) { - response = firstResponse_; + final String response; + if (requestString.isEmpty() + || requestString.contains("/favicon.ico")) { + response = "HTTP/1.1 404 Not Found\r\n" + + "Content-Length: 0\r\n" + + "Connection: close\r\n" + + "\r\n"; } else { - response = otherResponse_; + requests_.add(requestString); + if (responseCount == 0 || otherResponse_ == null) { + response = firstResponse_; + } + else if (responseCount == 1 && secondResponse_ != null) { + response = secondResponse_; + } + else { + response = otherResponse_; + } + responseCount++; } - first = false; - } - try (OutputStream out = socket.getOutputStream()) { + final OutputStream out = socket.getOutputStream(); final int headPos = response.indexOf("\r\n\r\n"); out.write(response.substring(0, headPos + 4).getBytes(StandardCharsets.US_ASCII)); out.write(response.substring(headPos + 4).getBytes(charset_)); + out.flush(); } } } diff --git a/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_Chrome.png b/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_Chrome.png index 5b5db985791..dd24cf46074 100644 Binary files a/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_Chrome.png and b/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_Chrome.png differ diff --git a/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_Edge.png b/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_Edge.png index 5b5db985791..226419e5354 100644 Binary files a/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_Edge.png and b/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_Edge.png differ diff --git a/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_FF-ESR.png b/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_FF-ESR.png index 5b5db985791..226419e5354 100644 Binary files a/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_FF-ESR.png and b/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_FF-ESR.png differ diff --git a/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_FF.png b/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_FF.png index 5b5db985791..226419e5354 100644 Binary files a/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_FF.png and b/src/test/resources/org/htmlunit/libraries/html2canvas/helloworld/nyi_FF.png differ