summaryrefslogtreecommitdiffstats
path: root/dom/tests/mochitest/ajax/prototype/test
diff options
context:
space:
mode:
Diffstat (limited to 'dom/tests/mochitest/ajax/prototype/test')
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/browser.html229
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/console.html110
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/functional/event.html243
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/lib/unittest.js602
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/test.css50
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/ajax_test.js286
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/array_test.js190
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/base_test.js511
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/dom_test.js1404
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/element_mixins_test.js32
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/enumerable_test.js263
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/event_test.js286
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/ajax.html2
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/ajax.js42
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/array.html1
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/base.html6
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/base.js106
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/content.html1
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/data.json1
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.css85
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.html285
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.js17
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/element_mixins.html4
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/element_mixins.js2
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/empty.html0
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/empty.js1
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/enumerable.html8
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/enumerable.js23
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/event.html4
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/form.html112
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/hash.js25
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/hello.js1
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/logo.gifbin0 -> 3502 bytes
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/position.html9
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/selector.html69
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/string.js8
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/fixtures/unittest.html18
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/form_test.js384
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/hash_test.js178
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/number_test.js44
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/position_test.js44
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/range_test.js58
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/selector_test.js377
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/string_test.js540
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/ajax_test.html42
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/array_test.html39
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/base_test.html45
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/dom_test.html326
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/element_mixins_test.html43
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/enumerable_test.html48
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/event_test.html42
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/form_test.html150
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/hash_test.html40
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/number_test.html38
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/position_test.html47
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/range_test.html38
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/selector_test.html107
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/string_test.html40
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/tmp/unit_test.html56
-rw-r--r--dom/tests/mochitest/ajax/prototype/test/unit/unittest_test.js143
60 files changed, 7905 insertions, 0 deletions
diff --git a/dom/tests/mochitest/ajax/prototype/test/browser.html b/dom/tests/mochitest/ajax/prototype/test/browser.html
new file mode 100644
index 0000000000..ec699f9d45
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/browser.html
@@ -0,0 +1,229 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <title>Prototype object browser</title>
+ <style type="text/css" media="screen">
+ body {
+ font-family: Lucida Grande, Verdana, sans-serif;
+ font-size: 13px;
+ }
+
+ .inspector {
+ margin: 1%;
+ float: left;
+ width: 31%;
+ border: 1px solid #ccc;
+ background-color: white;
+ }
+
+ .inspector h2 {
+ font-size: 13px;
+ margin: 0;
+ text-align: center;
+ padding: 5px;
+ background-color: #e6e6e6;
+ border-bottom: 1px solid #999;
+ }
+
+ .inspector ul {
+ height: 200px;
+ overflow: auto;
+ margin: 0;
+ padding-left: 0;
+ }
+
+ .inspector li {
+ cursor: pointer;
+ list-style-type: none;
+ padding: 2px 5px 2px 30px;
+ color: #333;
+ }
+
+ .inspector li.selected {
+ background-color: #888;
+ color: #fff;
+ }
+
+ .inspector.active li.selected {
+ background-color: #1a76fd;
+ color: #fff;
+ }
+
+ #path, #value {
+ width: 97%;
+ margin: 1%;
+ }
+
+ #path {
+ margin-bottom: 0;
+ border: 1px solid #ccc;
+ border-bottom: 1px solid #999;
+ background-color: #e6e6e6;
+ }
+
+ #value {
+ margin-top: 0;
+ border: 1px solid #ccc;
+ border-top: none;
+ overflow: auto;
+ }
+
+ #path_content, #value_content {
+ display: block;
+ padding: 15px 30px 15px 30px;
+ }
+
+ </style>
+ <script type="text/javascript" src="../dist/prototype.js"></script>
+ <script type="text/javascript">
+ var Browser = Class.create();
+ Browser.prototype = {
+ initialize: function(element, name, value, options) {
+ this.element = $(element);
+ this.name = name;
+ this.value = value;
+ this.history = [];
+ Object.extend(this, options || {});
+ this.reset();
+ },
+
+ reset: function() {
+ this.go(this.name, this.value);
+ },
+
+ refresh: function() {
+ var children = $A(this.element.childNodes),
+ history = this.history.toArray(),
+ elements = history.slice(-3).pluck('element');
+
+ children.each(function(element) {
+ if (element && !elements.include(element))
+ this.element.removeChild(element);
+ }.bind(this));
+
+ children = $A(this.element.childNodes);
+
+ elements.each(function(element, index) {
+ Element.removeClassName(element, 'active');
+ var child = children[index];
+ if (!child)
+ this.element.appendChild(element);
+ else if (!element.parentNode)
+ this.element.insertBefore(element, child);
+ }.bind(this));
+
+ this.setTitle();
+ this.setValue();
+ },
+
+ setTitle: function() {
+ if (this.titleElement)
+ this.titleElement.innerHTML =
+ this.history.pluck('name').invoke('escapeHTML').join('.');
+ },
+
+ setValue: function() {
+ if (this.valueElement)
+ this.valueElement.innerHTML =
+ this.currentValue().escapeHTML() + '&nbsp;';
+ },
+
+ currentValue: function() {
+ try {
+ return Object.inspect(this.current());
+ } catch (e) {
+ return '(Internal Function)';
+ }
+ },
+
+ current: function() {
+ return this.history.last().value;
+ },
+
+ go: function(name, value) {
+ var from = this.history.last();
+ this.history.push(new Inspector(this, name, value));
+ this.refresh();
+ if (from)
+ Element.addClassName(from.element, 'active');
+ }
+ }
+
+ var Inspector = Class.create();
+ Inspector.prototype = {
+ initialize: function(browser, name, value) {
+ this.browser = browser;
+ this.name = name;
+ this.value = value;
+ this.id = 'inspector_' + new Date().getTime();
+ this.history = this.browser.history.toArray();
+ this.history.push(this);
+ this.createElement();
+ this.populate();
+ },
+
+ properties: function() {
+ var properties = [];
+ for (var property in this.value)
+ properties.push(property);
+ properties.sort();
+ return properties;
+ },
+
+ createElement: function() {
+ var element = document.createElement('div');
+ element.className = 'inspector';
+ element.id = this.id;
+ this.element = element;
+
+ var title = document.createElement('h2');
+ title.innerHTML = this.name.toString().escapeHTML();
+ this.titleElement = title;
+
+ var list = document.createElement('ul');
+ this.listElement = list;
+
+ element.appendChild(title);
+ element.appendChild(list);
+ },
+
+ populate: function() {
+ this.properties().each(function(property) {
+ var li = document.createElement('li');
+ li.innerHTML = property.toString().escapeHTML();
+ li.onclick = this.select.bind(this, li);
+ li._property = property;
+ this.listElement.appendChild(li);
+ }.bind(this));
+ },
+
+ select: function(element) {
+ this.unselect();
+ Element.addClassName(element, 'selected');
+ this.selectedProperty = element;
+ this.browser.history = this.history.toArray();
+ this.browser.go(element._property, this.value[element._property]);
+ },
+
+ unselect: function() {
+ if (this.selectedProperty)
+ Element.removeClassName(this.selectedProperty, 'selected');
+ this.selectedProperty = null;
+ }
+ }
+ </script>
+ </head>
+ <body>
+ <div id="browser_wrapper">
+ <div id="browser"></div>
+ <div style="clear: left"></div>
+ </div>
+ <h1 id="path"><span id="path_content"></span></h1>
+ <pre id="value"><div id="value_content"></div></pre>
+ <script type="text/javascript">
+ new Browser('browser', 'window', window, {titleElement: $('path_content'), valueElement: $('value_content')})
+ </script>
+ </body>
+</html> \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/console.html b/dom/tests/mochitest/ajax/prototype/test/console.html
new file mode 100644
index 0000000000..2b586ee426
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/console.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+ <head>
+ <title>Prototype Console</title>
+ <script src="../dist/prototype.js" type="text/javascript"></script>
+ <script type="text/javascript">
+ Prototype.Console = Class.create();
+ Prototype.Console.prototype = {
+ initialize: function(element, form, input) {
+ this.element = $(element);
+ this.form = $(form);
+ this.input = $(input);
+ this.context = window.eval.bind(window);
+ this.registerCallbacks();
+ document.title = 'Prototype Console ' + Prototype.Version;
+ Field.activate(this.input);
+ },
+
+ registerCallbacks: function() {
+ Event.observe(this.form, 'submit', function(event) {
+ this.eval($F(this.input));
+ this.input.value = '';
+ Field.activate(this.input);
+ Event.stop(event);
+ }.bind(this));
+ },
+
+ log: function(type, message) {
+ new Insertion.Bottom(this.element,
+ '<tr class="' + type + '"><td>' +
+ message.escapeHTML() + '</td></tr>');
+ Element.scrollTo(this.form);
+ },
+
+ eval: function(expression) {
+ if (expression.match(/^\s*$/)) return;
+ try {
+ this.log('input', expression);
+ window.$_ = this.context.call(window, expression);
+ this.log('output', Object.inspect($_));
+ } catch (e) {
+ this.log('error', e.toString());
+ }
+ },
+
+ clear: function() {
+ this.element.innerHTML = '';
+ }
+ }
+ </script>
+ <style type="text/css">
+ body {
+ margin: 0;
+ padding: 0;
+ }
+
+ .console {
+ width: 100%;
+ border-collapse: collapse;
+ margin-bottom: 50px;
+ }
+
+ .console td {
+ padding: 5px;
+ font-family: monospace;
+ font-size: 14px;
+ }
+
+ .console tr.input td {
+ background-color: #eee;
+ font-weight: bold;
+ }
+
+ .console tr.error td,
+ .console tr.output td {
+ color: #333;
+ border-bottom: 1px solid #ccc;
+ }
+
+ .console tr.error td {
+ color: #f00;
+ }
+
+ #input-form {
+ width: 100%;
+ background-color: #f0f5b8;
+ border-top: 1px solid #333;
+ padding: 10px;
+ position: fixed;
+ height: 25px;
+ bottom: 0;
+ margin: 0;
+ }
+ </style>
+ </head>
+ <body>
+ <table class="console">
+ <tbody id="console">
+ </tbody>
+ </table>
+ <form id="input-form">
+ <input type="text" size="60" id="input" />
+ <input type="submit" value="Evaluate" />
+ </form>
+ <script type="text/javascript">
+ window.console = new Prototype.Console('console', 'input-form', 'input');
+ </script>
+ </body>
+</html>
diff --git a/dom/tests/mochitest/ajax/prototype/test/functional/event.html b/dom/tests/mochitest/ajax/prototype/test/functional/event.html
new file mode 100644
index 0000000000..526e711f9a
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/functional/event.html
@@ -0,0 +1,243 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype functional test file</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script src="../../dist/prototype.js" type="text/javascript"></script>
+
+ <style type="text/css" media="screen">
+ /* <![CDATA[ */
+ body { margin:1em 2em; padding:0; font-size:0.8em }
+ hr { width:31.2em; margin:1em 0; text-align:left }
+ p { width:30em; margin:0.5em 0; padding:0.3em 0.6em; color:#222; background:#eee; border:1px solid silver; }
+ .subtest { margin-top:-0.5em }
+ .passed { color:green; border-color:olive }
+ .failed { color:firebrick; border-color:firebrick }
+ .button { padding:0.2em 0.4em; background:#ccc; border:1px solid #aaa }
+ #log { position:absolute; left:35em; top:5em; width:20em; font-size:13px !important }
+ h2 { font:normal 1.1em Verdana,Arial,sans-serif; font-style:italic; color:gray; margin-top:-1.2em }
+ h2 *, h2 a:visited { color:#444 }
+ h2 a:hover { color:blue }
+ a:visited { color:blue }
+ a:hover { color:red }
+ /* ]]> */
+ </style>
+
+ <script type="text/javascript">
+ Element.addMethods({
+ passed: function(el, message) {
+ el = $(el);
+ el.className = 'passed';
+ (el.down('span') || el).update(message || 'Test passed!');
+ },
+
+ failed: function(el, message) {
+ el = $(el);
+ el.className = 'failed';
+ (el.down('span') || el).update(message || 'Test failed');
+ }
+ });
+
+ function log(obj) {
+ var line, all = [];
+ for (prop in obj) {
+ if (typeof obj[prop] == 'function' || /^[A-Z]|[XY]$/.test(prop)) continue;
+ line = prop + ": " + Object.inspect(obj[prop]);
+ all.push(line.escapeHTML());
+ }
+ $('log').update(all.join('<br />'));
+ }
+ </script>
+</head>
+<body>
+ <h1>Prototype functional tests for the Event module</h1>
+
+ <div id="log">log empty</div>
+
+ <p id="basic">A basic event test - <strong>click here</strong></p>
+ <p id="basic_remove" class="subtest"><strong>click</strong> to stop observing the first test</p>
+
+ <p id="inline_test" onclick="Event.stop(event); $(this).passed();"><strong>click</strong> to ensure generic Event methods work on inline handlers</p>
+
+ <script type="text/javascript">
+ var basic_callback = function(e){
+ $('basic').passed();
+ if ($('basic_remove')) $('basic_remove').show()
+ else $('basic').failed()
+ log(e);
+ }
+ $('basic').observe('click', basic_callback)
+ $('basic_remove').observe('click', function(e){
+ el = $('basic')
+ el.passed('This test should now be inactive (try clicking)')
+ el.stopObserving('click')
+ $('basic_remove').remove()
+ log(e);
+ }).hide()
+ </script>
+
+ <p id="basic2"><strong>Scope</strong> test - scope of the handler should be this element</p>
+
+ <script type="text/javascript">
+ $('basic2').observe('click', function(e) {
+ if (this === window) $('basic2').failed('Window scope! (needs scope correction)');
+ else this.passed();
+ log(e);
+ });
+ </script>
+
+ <p id="basic3"><strong>Event object</strong> test - should be present as a first argument</p>
+
+ <script type="text/javascript">
+ $('basic3').observe('click', function(evt) {
+ el = $('basic3');
+ if (typeof evt != 'object') this.failed('Expected event object for first argument');
+ else this.passed('Good first argument');
+ log(evt);
+ });
+ </script>
+
+ <p><a href="#wrong" id="hijack">Hijack link test</a> (preventDefault)</p>
+
+ <script type="text/javascript">
+ $('hijack').observe('click', function(e){
+ el = $(this.parentNode);
+ log(e); // this makes it fail?!?
+ e.preventDefault();
+
+ setTimeout(function() {
+ if (window.location.hash == '#wrong') el.failed('Hijack failed (<a href="' +
+ window.location.toString().replace(/#.+$/, '') + '">remove the fragment</a>)')
+ else el.passed();
+ }, 50)
+ })
+ </script>
+
+ <hr />
+
+
+ <p>Mouse click:
+ <span class="button" id="left">left</span> <span class="button" id="middle">middle</span> <span class="button" id="right">right</span></p>
+
+ <script type="text/javascript">
+ $w('left middle right').each(function(button) {
+ Event.observe(button, 'mousedown', function(e) {
+ if (Event['is' + this.id.capitalize() + 'Click'](e)) this.passed('Squeak!')
+ else this.failed('OH NO!');
+ log(e);
+ });
+ });
+ </script>
+
+ <p id="context">Context menu event (tries to prevent default)</p>
+
+ <script type="text/javascript">
+ $('context').observe('contextmenu', function(e){
+ this.passed();
+ Event.stop(e);
+ log(e);
+ })
+ </script>
+
+ <p id="target">Event.element() test</p>
+
+ <script type="text/javascript">
+ $('target').observe('click', function(e) {
+ if (e.element() == this && e.target == this) this.passed();
+ else this.failed();
+ log(e);
+ });
+ </script>
+
+ <p id="currentTarget"><span>Event.currentTarget test</span></p>
+
+ <script type="text/javascript">
+ $('currentTarget').observe('click', function(e){
+ if (e.currentTarget !== this) this.failed();
+ else this.passed();
+ log(e);
+ })
+ </script>
+
+ <p id="findElement"><span>Event.findElement() test</span></p>
+
+ <script type="text/javascript">
+ $('findElement').observe('click', function(e){
+ if (e.findElement('p') == this && e.findElement('body') == document.body &&
+ e.findElement('foo') == null) this.passed();
+ else this.failed();
+ log(e);
+ })
+ </script>
+
+ <div id="container"><p id="stop"><strong>Stop propagation</strong> test (bubbling)</p></div>
+
+ <script type="text/javascript">
+ $('stop').observe('click', function(e){
+ e.stop();
+ this.passed();
+ log(e);
+ })
+ $('container').observe('click', function(e){
+ $('stop').failed();
+ log(e);
+ })
+ </script>
+
+ <div>
+ <p id="keyup_log"><strong>Keyup</strong> test - focus on the textarea and type</p>
+ <textarea id="keyup" class="subtest"></textarea>
+ </div>
+
+ <script type="text/javascript">
+ $('keyup').observe('keyup', function(e){
+ el = $('keyup_log');
+ el.passed('Key captured: the length is ' + $('keyup').value.length);
+ log(e);
+ })
+ </script>
+
+ <p id="bind"><code>bindAsEventListener()</code> test</p>
+
+ <script type="text/javascript">
+ $('bind').observe('click', function(e, str, arr){
+ el = $('bind')
+ try {
+ if (arguments.length != 3) throw arguments.length + ' arguments: ' + $A(arguments).inspect()
+ if (str != 'foo') throw 'wrong string: ' + str
+ if (arr.constructor != Array) throw '3rd parameter is not an array'
+ el.passed();
+ }
+ catch (err) { el.failed(err.toString()) }
+ log(e);
+ }.bindAsEventListener(document.body, 'foo', [1,2,3]))
+ </script>
+
+ <p id="obj_inspect"><code>Object.inspect(event)</code> test</p>
+
+ <script type="text/javascript">
+ $('obj_inspect').observe('click', function(e){
+ el = $('obj_inspect')
+ try { el.passed(Object.inspect(e)) }
+ catch (err) { el.failed('Failed! Error thrown') }
+ log(e);
+ })
+ </script>
+
+ <p id="addunload">Add unload events</p>
+
+ <script type="text/javascript">
+ $('addunload').observe('click', function(e){
+ if (this._done) return
+
+ window.onunload = function(){ alert('inline unload fired!') }
+ Event.observe(window, 'unload', function(){ alert('observed unload fired!') })
+
+ this.update('Registered two unload events, one inline ("onunload") and one regular - try to refresh, both should fire')
+ this._done = true
+ log(e);
+ })
+ </script>
+</body>
+</html>
diff --git a/dom/tests/mochitest/ajax/prototype/test/lib/unittest.js b/dom/tests/mochitest/ajax/prototype/test/lib/unittest.js
new file mode 100644
index 0000000000..4f92d13dc0
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/lib/unittest.js
@@ -0,0 +1,602 @@
+// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005 Jon Tirsen (http://www.tirsen.com)
+// (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+// experimental, Firefox-only
+Event.simulateMouse = function(element, eventName) {
+ var options = Object.extend({
+ pointerX: 0,
+ pointerY: 0,
+ buttons: 0
+ }, arguments[2] || {});
+ var oEvent = document.createEvent("MouseEvents");
+ oEvent.initMouseEvent(eventName, true, true, document.defaultView,
+ options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
+ false, false, false, false, 0, $(element));
+
+ if (this.mark) Element.remove(this.mark);
+
+ var style = 'position: absolute; width: 5px; height: 5px;' +
+ 'top: #{pointerY}px; left: #{pointerX}px;'.interpolate(options) +
+ 'border-top: 1px solid red; border-left: 1px solid red;'
+
+ this.mark = new Element('div', { style: style });
+ this.mark.appendChild(document.createTextNode(" "));
+ document.body.appendChild(this.mark);
+
+ if (this.step)
+ alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options));
+
+ $(element).dispatchEvent(oEvent);
+};
+
+// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2.
+// You need to downgrade to 1.0.4 for now to get this working
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much
+Event.simulateKey = function(element, eventName) {
+ var options = Object.extend({
+ ctrlKey: false,
+ altKey: false,
+ shiftKey: false,
+ metaKey: false,
+ keyCode: 0,
+ charCode: 0
+ }, arguments[2] || {});
+
+ var oEvent = document.createEvent("KeyboardEvent");
+ oEvent.initKeyEvent(eventName, true, true, window,
+ options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
+ options.keyCode, options.charCode );
+ $(element).dispatchEvent(oEvent);
+};
+
+Event.simulateKeys = function(element, command) {
+ for (var i=0; i<command.length; i++) {
+ Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)});
+ }
+};
+
+var Test = {
+ Unit: {
+ inspect: Object.inspect // security exception workaround
+ }
+};
+
+Test.Unit.Logger = Class.create({
+ initialize: function(element) {
+ this.element = $(element);
+ if (this.element) this._createLogTable();
+ this.tbody = $(this.element.getElementsByTagName('tbody')[0]);
+ },
+
+ start: function(testName) {
+ this.testName = testName;
+ if (!this.element) return;
+ this.tbody.insert('<tr><td>' + testName + '</td><td></td><td></td></tr>');
+ },
+
+ setStatus: function(status) {
+ this.getLastLogLine().addClassName(status);
+ $(this.getLastLogLine().getElementsByTagName('td')[1]).update(status);
+ },
+
+ finish: function(status, summary) {
+ if (!this.element) return;
+ this.setStatus(status);
+ this.message(summary);
+ },
+
+ message: function(message) {
+ if (!this.element) return;
+ this.getMessageCell().update(this._toHTML(message));
+ },
+
+ summary: function(summary) {
+ if (!this.element) return;
+ var div = $(this.element.getElementsByTagName('div')[0]);
+ div.update(this._toHTML(summary));
+ },
+
+ getLastLogLine: function() {
+ //return this.element.descendants('tr').last();
+ var trs = this.element.getElementsByTagName('tr');
+ return $(trs[trs.length - 1]);
+ },
+
+ getMessageCell: function() {
+ return this.getLastLogLine().down('td', 2);
+ var tds = this.getLastLogLine().getElementsByTagName('td');
+ return $(tds[2]);
+ },
+
+ _createLogTable: function() {
+ var html = '<div class="logsummary">running...</div>' +
+ '<table class="logtable">' +
+ '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
+ '<tbody class="loglines"></tbody>' +
+ '</table>';
+ this.element.update(html);
+
+ },
+
+ appendActionButtons: function(actions) {
+ actions = $H(actions);
+ if (!actions.any()) return;
+ var div = new Element("div", {className: 'action_buttons'});
+ actions.inject(div, function(container, action) {
+ var button = new Element("input").setValue(action.key).observe("click", action.value);
+ button.type = "button";
+ return container.insert(button);
+ });
+ this.getMessageCell().insert(div);
+ },
+
+ _toHTML: function(txt) {
+ return txt.escapeHTML().replace(/\n/g,"<br />");
+ }
+});
+
+Test.Unit.Runner = Class.create({
+ initialize: function(testcases) {
+ var options = this.options = Object.extend({
+ testLog: 'testlog'
+ }, arguments[1] || {});
+
+ options.resultsURL = this.queryParams.resultsURL;
+
+ this.tests = this.getTests(testcases);
+ this.currentTest = 0;
+
+ Event.observe(window, "load", function() {
+ this.logger = new Test.Unit.Logger($(options.testLog));
+ this.runTests.bind(this).delay(0.1);
+ }.bind(this));
+ },
+
+ queryParams: window.location.search.parseQuery(),
+
+ getTests: function(testcases) {
+ var tests, options = this.options;
+ if (this.queryParams.tests) tests = this.queryParams.tests.split(',');
+ else if (options.tests) tests = options.tests;
+ else if (options.test) tests = [option.test];
+ else tests = Object.keys(testcases).grep(/^test/);
+
+ return tests.map(function(test) {
+ if (testcases[test])
+ return new Test.Unit.Testcase(test, testcases[test], testcases.setup, testcases.teardown);
+ }).compact();
+ },
+
+ getResult: function() {
+ var results = {
+ tests: this.tests.length,
+ assertions: 0,
+ failures: 0,
+ errors: 0
+ };
+
+ return this.tests.inject(results, function(results, test) {
+ results.assertions += test.assertions;
+ results.failures += test.failures;
+ results.errors += test.errors;
+ return results;
+ });
+ },
+
+ postResults: function() {
+ if (this.options.resultsURL) {
+ new Ajax.Request(this.options.resultsURL,
+ { method: 'get', parameters: this.getResult(), asynchronous: false });
+ }
+ },
+
+ runTests: function() {
+ var test = this.tests[this.currentTest], actions;
+
+ if (!test) return this.finish();
+ if (test.timerID > 0) test.timerID = -1;
+ if (!test.isWaiting) this.logger.start(test.name);
+ test.run();
+ if (test.isWaiting) {
+ if (test.timeToWait) {
+ this.logger.message("Waiting for " + test.timeToWait + "ms");
+ test.timerID = setTimeout(this.runTests.bind(this), test.timeToWait);
+ } else {
+ this.logger.message("Waiting for finish");
+ }
+ test.runner = this;
+ return;
+ }
+
+ this.logger.finish(test.status(), test.summary());
+ if (actions = test.actions) this.logger.appendActionButtons(actions);
+ this.currentTest++;
+ // tail recursive, hopefully the browser will skip the stackframe
+ this.runTests();
+ },
+
+ finish: function() {
+ this.postResults();
+ this.logger.summary(this.summary());
+ },
+
+ summary: function() {
+ return '#{tests} tests, #{assertions} assertions, #{failures} failures, #{errors} errors'
+ .interpolate(this.getResult());
+ }
+});
+
+Test.Unit.MessageTemplate = Class.create({
+ initialize: function(string) {
+ var parts = [];
+ (string || '').scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/, function(part) {
+ parts.push(part[0]);
+ });
+ this.parts = parts;
+ },
+
+ evaluate: function(params) {
+ return this.parts.map(function(part) {
+ return part == '?' ? Test.Unit.inspect(params.shift()) : part.replace(/\\\?/, '?');
+ }).join('');
+ }
+});
+
+Test.Unit.Assertions = {
+ buildMessage: function(message, template) {
+ var args = $A(arguments).slice(2);
+ return (message ? message + '\n' : '') + new Test.Unit.MessageTemplate(template).evaluate(args);
+ },
+
+ flunk: function(message) {
+ this.assertBlock(message || 'Flunked', function() { return false });
+ },
+
+ assertBlock: function(message, block) {
+ try {
+ block.call(this) ? this.pass() : this.fail(message);
+ } catch(e) { this.error(e) }
+ },
+
+ assert: function(expression, message) {
+ message = this.buildMessage(message || 'assert', 'got <?>', expression);
+ this.assertBlock(message, function() { return expression });
+ },
+
+ assertEqual: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertEqual', 'expected <?>, actual: <?>', expected, actual);
+ this.assertBlock(message, function() { return expected == actual });
+ },
+
+ assertNotEqual: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertNotEqual', 'expected <?>, actual: <?>', expected, actual);
+ this.assertBlock(message, function() { return expected != actual });
+ },
+
+ assertEnumEqual: function(expected, actual, message) {
+ expected = $A(expected);
+ actual = $A(actual);
+ message = this.buildMessage(message || 'assertEnumEqual', 'expected <?>, actual: <?>', expected, actual);
+ this.assertBlock(message, function() {
+ return expected.length == actual.length && expected.zip(actual).all(function(pair) { return pair[0] == pair[1] });
+ });
+ },
+
+ assertEnumNotEqual: function(expected, actual, message) {
+ expected = $A(expected);
+ actual = $A(actual);
+ message = this.buildMessage(message || 'assertEnumNotEqual', '<?> was the same as <?>', expected, actual);
+ this.assertBlock(message, function() {
+ return expected.length != actual.length || expected.zip(actual).any(function(pair) { return pair[0] != pair[1] });
+ });
+ },
+
+ assertHashEqual: function(expected, actual, message) {
+ expected = $H(expected);
+ actual = $H(actual);
+ var expected_array = expected.toArray().sort(), actual_array = actual.toArray().sort();
+ message = this.buildMessage(message || 'assertHashEqual', 'expected <?>, actual: <?>', expected, actual);
+ // from now we recursively zip & compare nested arrays
+ var block = function() {
+ return expected_array.length == actual_array.length &&
+ expected_array.zip(actual_array).all(function(pair) {
+ return pair.all(Object.isArray) ?
+ pair[0].zip(pair[1]).all(arguments.callee) : pair[0] == pair[1];
+ });
+ };
+ this.assertBlock(message, block);
+ },
+
+ assertHashNotEqual: function(expected, actual, message) {
+ expected = $H(expected);
+ actual = $H(actual);
+ var expected_array = expected.toArray().sort(), actual_array = actual.toArray().sort();
+ message = this.buildMessage(message || 'assertHashNotEqual', '<?> was the same as <?>', expected, actual);
+ // from now we recursively zip & compare nested arrays
+ var block = function() {
+ return !(expected_array.length == actual_array.length &&
+ expected_array.zip(actual_array).all(function(pair) {
+ return pair.all(Object.isArray) ?
+ pair[0].zip(pair[1]).all(arguments.callee) : pair[0] == pair[1];
+ }));
+ };
+ this.assertBlock(message, block);
+ },
+
+ assertIdentical: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertIdentical', 'expected <?>, actual: <?>', expected, actual);
+ this.assertBlock(message, function() { return expected === actual });
+ },
+
+ assertNotIdentical: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertNotIdentical', 'expected <?>, actual: <?>', expected, actual);
+ this.assertBlock(message, function() { return expected !== actual });
+ },
+
+ assertNull: function(obj, message) {
+ message = this.buildMessage(message || 'assertNull', 'got <?>', obj);
+ this.assertBlock(message, function() { return obj === null });
+ },
+
+ assertNotNull: function(obj, message) {
+ message = this.buildMessage(message || 'assertNotNull', 'got <?>', obj);
+ this.assertBlock(message, function() { return obj !== null });
+ },
+
+ assertUndefined: function(obj, message) {
+ message = this.buildMessage(message || 'assertUndefined', 'got <?>', obj);
+ this.assertBlock(message, function() { return typeof obj == "undefined" });
+ },
+
+ assertNotUndefined: function(obj, message) {
+ message = this.buildMessage(message || 'assertNotUndefined', 'got <?>', obj);
+ this.assertBlock(message, function() { return typeof obj != "undefined" });
+ },
+
+ assertNullOrUndefined: function(obj, message) {
+ message = this.buildMessage(message || 'assertNullOrUndefined', 'got <?>', obj);
+ this.assertBlock(message, function() { return obj == null });
+ },
+
+ assertNotNullOrUndefined: function(obj, message) {
+ message = this.buildMessage(message || 'assertNotNullOrUndefined', 'got <?>', obj);
+ this.assertBlock(message, function() { return obj != null });
+ },
+
+ assertMatch: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertMatch', 'regex <?> did not match <?>', expected, actual);
+ this.assertBlock(message, function() { return new RegExp(expected).exec(actual) });
+ },
+
+ assertNoMatch: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertNoMatch', 'regex <?> matched <?>', expected, actual);
+ this.assertBlock(message, function() { return !(new RegExp(expected).exec(actual)) });
+ },
+
+ assertHidden: function(element, message) {
+ message = this.buildMessage(message || 'assertHidden', '? isn\'t hidden.', element);
+ this.assertBlock(message, function() { return element.style.display == 'none' });
+ },
+
+ assertInstanceOf: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertInstanceOf', '<?> was not an instance of the expected type', actual);
+ this.assertBlock(message, function() { return actual instanceof expected });
+ },
+
+ assertNotInstanceOf: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertNotInstanceOf', '<?> was an instance of the expected type', actual);
+ this.assertBlock(message, function() { return !(actual instanceof expected) });
+ },
+
+ assertRespondsTo: function(method, obj, message) {
+ message = this.buildMessage(message || 'assertRespondsTo', 'object doesn\'t respond to <?>', method);
+ this.assertBlock(message, function() { return (method in obj && typeof obj[method] == 'function') });
+ },
+
+ assertRaise: function(exceptionName, method, message) {
+ message = this.buildMessage(message || 'assertRaise', '<?> exception expected but none was raised', exceptionName);
+ var block = function() {
+ try {
+ method();
+ return false;
+ } catch(e) {
+ if (e.name == exceptionName) return true;
+ else throw e;
+ }
+ };
+ this.assertBlock(message, block);
+ },
+
+ assertNothingRaised: function(method, message) {
+ try {
+ method();
+ this.assert(true, "Expected nothing to be thrown");
+ } catch(e) {
+ message = this.buildMessage(message || 'assertNothingRaised', '<?> was thrown when nothing was expected.', e);
+ this.flunk(message);
+ }
+ },
+
+ _isVisible: function(element) {
+ element = $(element);
+ if (!element.parentNode) return true;
+ this.assertNotNull(element);
+ if (element.style && Element.getStyle(element, 'display') == 'none')
+ return false;
+
+ return arguments.callee.call(this, element.parentNode);
+ },
+
+ assertVisible: function(element, message) {
+ message = this.buildMessage(message, '? was not visible.', element);
+ this.assertBlock(message, function() { return this._isVisible(element) });
+ },
+
+ assertNotVisible: function(element, message) {
+ message = this.buildMessage(message, '? was not hidden and didn\'t have a hidden parent either.', element);
+ this.assertBlock(message, function() { return !this._isVisible(element) });
+ },
+
+ assertElementsMatch: function() {
+ var pass = true, expressions = $A(arguments), elements = $A(expressions.shift());
+ if (elements.length != expressions.length) {
+ message = this.buildMessage('assertElementsMatch', 'size mismatch: ? elements, ? expressions (?).', elements.length, expressions.length, expressions);
+ this.flunk(message);
+ pass = false;
+ }
+ elements.zip(expressions).all(function(pair, index) {
+ var element = $(pair.first()), expression = pair.last();
+ if (element.match(expression)) return true;
+ message = this.buildMessage('assertElementsMatch', 'In index <?>: expected <?> but got ?', index, expression, element);
+ this.flunk(message);
+ pass = false;
+ }.bind(this))
+
+ if (pass) this.assert(true, "Expected all elements to match.");
+ },
+
+ assertElementMatches: function(element, expression, message) {
+ this.assertElementsMatch([element], expression);
+ }
+};
+
+Test.Unit.Testcase = Class.create(Test.Unit.Assertions, {
+ initialize: function(name, test, setup, teardown) {
+ this.name = name;
+ this.test = test || Prototype.emptyFunction;
+ this.setup = setup || Prototype.emptyFunction;
+ this.teardown = teardown || Prototype.emptyFunction;
+ this.messages = [];
+ this.actions = {};
+ },
+
+ isWaiting: false,
+ timeToWait: null,
+ timerID: -1,
+ runner: null,
+ assertions: 0,
+ failures: 0,
+ errors: 0,
+ isRunningFromRake: window.location.port == 4711,
+
+ wait: function(time, nextPart) {
+ this.isWaiting = true;
+ this.test = nextPart;
+ this.timeToWait = time;
+ },
+
+ waitForFinish: function() {
+ this.isWaiting = true;
+ },
+
+ finish: function() {
+ if (this.timerID > 0) {
+ clearTimeout(this.timerID);
+ this.timerID = -1;
+ this.timeToWait = null;
+ }
+ this.test = function(){};
+ // continue test
+ if (this.runner)
+ this.runner.runTests();
+ },
+
+ run: function(rethrow) {
+ try {
+ try {
+ if (!this.isWaiting) this.setup();
+ this.isWaiting = false;
+ this.test();
+ } finally {
+ if (!this.isWaiting) {
+ this.teardown();
+ }
+ }
+ }
+ catch(e) {
+ if (rethrow) throw e;
+ this.error(e, this);
+ }
+ },
+
+ summary: function() {
+ var msg = '#{assertions} assertions, #{failures} failures, #{errors} errors\n';
+ return msg.interpolate(this) + this.messages.join("\n");
+ },
+
+ pass: function() {
+ this.assertions++;
+ },
+
+ fail: function(message) {
+ this.failures++;
+ var line = "";
+ try {
+ throw new Error("stack");
+ } catch(e){
+ match = /.*\/(.*_test\.js):(\d+)/.exec(e.stack || '') || ['','',''];
+ file = match[1];
+ line = match[2];
+ }
+ this.messages.push("Failure: " + message + (line ? " " + file + ": Line #" + line : ""));
+ },
+
+ info: function(message) {
+ this.messages.push("Info: " + message);
+ },
+
+ error: function(error, test) {
+ this.errors++;
+ this.actions['retry with throw'] = function() { test.run(true) };
+ this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) + ")");
+ },
+
+ status: function() {
+ if (this.failures > 0) return 'failed';
+ if (this.errors > 0) return 'error';
+ return 'passed';
+ },
+
+ benchmark: function(operation, iterations) {
+ var startAt = new Date();
+ (iterations || 1).times(operation);
+ var timeTaken = ((new Date())-startAt);
+ this.info((arguments[2] || 'Operation') + ' finished ' +
+ iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+ return timeTaken;
+ }
+});
+
+if ( parent.SimpleTest && parent.runAJAXTest ) (function(){
+ var finish = Test.Unit.Logger.prototype.finish;
+ Test.Unit.Logger.prototype.finish = function(status,summary){
+ parent.SimpleTest.ok( status == "passed", `${this.testName}: ${summary}` );
+ return finish.apply( this, arguments );
+ };
+
+ // Intentionally overwrite (to stop the Ajax request)
+ Test.Unit.Runner.prototype.postResults = parent.runAJAXTest;
+})();
+
+
diff --git a/dom/tests/mochitest/ajax/prototype/test/test.css b/dom/tests/mochitest/ajax/prototype/test/test.css
new file mode 100644
index 0000000000..6fe8f51c9b
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/test.css
@@ -0,0 +1,50 @@
+body, div, p, h1, h2, h3, ul, ol, span, a, table, td, form, img, li {
+ font-family: sans-serif;
+}
+
+body {
+ font-size:0.8em;
+}
+
+#log {
+ padding-bottom: 1em;
+ border-bottom: 2px solid #000;
+ margin-bottom: 2em;
+}
+
+.logsummary {
+ margin-top: 1em;
+ margin-bottom: 1em;
+ padding: 1ex;
+ border: 1px solid #000;
+ font-weight: bold;
+}
+
+.logtable {
+ width:100%;
+ border-collapse: collapse;
+ border: 1px dotted #666;
+}
+
+.logtable td, .logtable th {
+ text-align: left;
+ padding: 3px 8px;
+ border: 1px dotted #666;
+}
+
+.logtable .passed {
+ background-color: #cfc;
+}
+
+.logtable .failed, .logtable .error {
+ background-color: #fcc;
+}
+
+.logtable td div.action_buttons {
+ display: inline;
+}
+
+.logtable td div.action_buttons input {
+ margin: 0 5px;
+ font-size: 10px;
+} \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/ajax_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/ajax_test.js
new file mode 100644
index 0000000000..9ceb985186
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/ajax_test.js
@@ -0,0 +1,286 @@
+var extendDefault = function(options) {
+ return Object.extend({
+ asynchronous: false,
+ method: 'get',
+ onException: function(request, e) { throw e }
+ }, options);
+};
+
+new Test.Unit.Runner({
+ setup: function() {
+ $('content').update('');
+ $('content2').update('');
+ },
+
+ teardown: function() {
+ // hack to cleanup responders
+ Ajax.Responders.responders = [Ajax.Responders.responders[0]];
+ },
+
+ testSynchronousRequest: function() {
+ this.assertEqual("", $("content").innerHTML);
+
+ this.assertEqual(0, Ajax.activeRequestCount);
+ new Ajax.Request("../fixtures/hello.js", extendDefault({
+ asynchronous: false,
+ method: 'GET',
+ evalJS: 'force'
+ }));
+ this.assertEqual(0, Ajax.activeRequestCount);
+
+ var h2 = $("content").firstChild;
+ this.assertEqual("Hello world!", h2.innerHTML);
+ },
+
+ testUpdaterOptions: function() {
+ var options = {
+ method: 'get',
+ asynchronous: false,
+ evalJS: 'force',
+ onComplete: Prototype.emptyFunction
+ }
+ var request = new Ajax.Updater("content", "../fixtures/hello.js", options);
+ request.options.onComplete = function() {};
+ this.assertIdentical(Prototype.emptyFunction, options.onComplete);
+ },
+
+ testEvalResponseShouldBeCalledBeforeOnComplete: function() {
+ if (this.isRunningFromRake) {
+ this.assertEqual("", $("content").innerHTML);
+
+ this.assertEqual(0, Ajax.activeRequestCount);
+ new Ajax.Request("../fixtures/hello.js", extendDefault({
+ onComplete: function(response) { this.assertNotEqual("", $("content").innerHTML) }.bind(this)
+ }));
+ this.assertEqual(0, Ajax.activeRequestCount);
+
+ var h2 = $("content").firstChild;
+ this.assertEqual("Hello world!", h2.innerHTML);
+ } else {
+ this.info(message);
+ }
+ },
+
+ testContentTypeSetForSimulatedVerbs: function() {
+ if (this.isRunningFromRake) {
+ new Ajax.Request('/inspect', extendDefault({
+ method: 'put',
+ contentType: 'application/bogus',
+ onComplete: function(response) {
+ this.assertEqual('application/bogus; charset=UTF-8', response.responseJSON.headers['content-type']);
+ }.bind(this)
+ }));
+ } else {
+ this.info(message);
+ }
+ },
+
+ testOnCreateCallback: function() {
+ new Ajax.Request("../fixtures/content.html", extendDefault({
+ onCreate: function(transport) { this.assertEqual(0, transport.readyState) }.bind(this),
+ onComplete: function(transport) { this.assertNotEqual(0, transport.readyState) }.bind(this)
+ }));
+ },
+
+ testEvalJS: function() {
+ if (this.isRunningFromRake) {
+
+ $('content').update();
+ new Ajax.Request("/response", extendDefault({
+ parameters: Fixtures.js,
+ onComplete: function(transport) {
+ var h2 = $("content").firstChild;
+ this.assertEqual("Hello world!", h2.innerHTML);
+ }.bind(this)
+ }));
+
+ $('content').update();
+ new Ajax.Request("/response", extendDefault({
+ evalJS: false,
+ parameters: Fixtures.js,
+ onComplete: function(transport) {
+ this.assertEqual("", $("content").innerHTML);
+ }.bind(this)
+ }));
+ } else {
+ this.info(message);
+ }
+
+ $('content').update();
+ new Ajax.Request("../fixtures/hello.js", extendDefault({
+ evalJS: 'force',
+ onComplete: function(transport) {
+ var h2 = $("content").firstChild;
+ this.assertEqual("Hello world!", h2.innerHTML);
+ }.bind(this)
+ }));
+ },
+
+ testCallbacks: function() {
+ var options = extendDefault({
+ onCreate: function(transport) { this.assertInstanceOf(Ajax.Response, transport) }.bind(this)
+ });
+
+ Ajax.Request.Events.each(function(state){
+ options['on' + state] = options.onCreate;
+ });
+
+ new Ajax.Request("../fixtures/content.html", options);
+ },
+
+ testResponseText: function() {
+ new Ajax.Request("../fixtures/empty.html", extendDefault({
+ onComplete: function(transport) { this.assertEqual('', transport.responseText) }.bind(this)
+ }));
+
+ new Ajax.Request("../fixtures/content.html", extendDefault({
+ onComplete: function(transport) { this.assertEqual(sentence, transport.responseText.toLowerCase()) }.bind(this)
+ }));
+ },
+
+ testResponseXML: function() {
+ if (this.isRunningFromRake) {
+ new Ajax.Request("/response", extendDefault({
+ parameters: Fixtures.xml,
+ onComplete: function(transport) {
+ this.assertEqual('foo', transport.responseXML.getElementsByTagName('name')[0].getAttribute('attr'))
+ }.bind(this)
+ }));
+ } else {
+ this.info(message);
+ }
+ },
+
+ testResponseJSON: function() {
+ if (this.isRunningFromRake) {
+ new Ajax.Request("/response", extendDefault({
+ parameters: Fixtures.json,
+ onComplete: function(transport) { this.assertEqual(123, transport.responseJSON.test) }.bind(this)
+ }));
+
+ new Ajax.Request("/response", extendDefault({
+ parameters: {
+ 'Content-Length': 0,
+ 'Content-Type': 'application/json'
+ },
+ onComplete: function(transport) { this.assertNull(transport.responseJSON) }.bind(this)
+ }));
+
+ new Ajax.Request("/response", extendDefault({
+ evalJSON: false,
+ parameters: Fixtures.json,
+ onComplete: function(transport) { this.assertNull(transport.responseJSON) }.bind(this)
+ }));
+
+ new Ajax.Request("/response", extendDefault({
+ parameters: Fixtures.jsonWithoutContentType,
+ onComplete: function(transport) { this.assertNull(transport.responseJSON) }.bind(this)
+ }));
+
+ new Ajax.Request("/response", extendDefault({
+ sanitizeJSON: true,
+ parameters: Fixtures.invalidJson,
+ onException: function(request, error) {
+ this.assert(error.message.include('Badly formed JSON string'));
+ this.assertInstanceOf(Ajax.Request, request);
+ }.bind(this)
+ }));
+ } else {
+ this.info(message);
+ }
+
+ new Ajax.Request("../fixtures/data.json", extendDefault({
+ evalJSON: 'force',
+ onComplete: function(transport) { this.assertEqual(123, transport.responseJSON.test) }.bind(this)
+ }));
+ },
+
+ testHeaderJSON: function() {
+ if (this.isRunningFromRake) {
+ new Ajax.Request("/response", extendDefault({
+ parameters: Fixtures.headerJson,
+ onComplete: function(transport, json) {
+ this.assertEqual('hello #éà', transport.headerJSON.test);
+ this.assertEqual('hello #éà', json.test);
+ }.bind(this)
+ }));
+
+ new Ajax.Request("/response", extendDefault({
+ onComplete: function(transport, json) {
+ this.assertNull(transport.headerJSON)
+ this.assertNull(json)
+ }.bind(this)
+ }));
+ } else {
+ this.info(message);
+ }
+ },
+
+ testGetHeader: function() {
+ if (this.isRunningFromRake) {
+ new Ajax.Request("/response", extendDefault({
+ parameters: { 'X-TEST': 'some value' },
+ onComplete: function(transport) {
+ this.assertEqual('some value', transport.getHeader('X-Test'));
+ this.assertNull(transport.getHeader('X-Inexistant'));
+ }.bind(this)
+ }));
+ } else {
+ this.info(message);
+ }
+ },
+
+ testParametersCanBeHash: function() {
+ if (this.isRunningFromRake) {
+ new Ajax.Request("/response", extendDefault({
+ parameters: $H({ "one": "two", "three": "four" }),
+ onComplete: function(transport) {
+ this.assertEqual("two", transport.getHeader("one"));
+ this.assertEqual("four", transport.getHeader("three"));
+ this.assertNull(transport.getHeader("toObject"));
+ }.bind(this)
+ }));
+ } else {
+ this.info(message);
+ }
+ },
+
+ testIsSameOriginMethod: function() {
+ var isSameOrigin = Ajax.Request.prototype.isSameOrigin;
+ this.assert(isSameOrigin.call({ url: '/foo/bar.html' }), '/foo/bar.html');
+ this.assert(isSameOrigin.call({ url: window.location.toString() }), window.location);
+ this.assert(!isSameOrigin.call({ url: 'http://example.com' }), 'http://example.com');
+
+ if (this.isRunningFromRake) {
+ Ajax.Request.prototype.isSameOrigin = function() {
+ return false
+ };
+
+ $("content").update('same origin policy');
+ new Ajax.Request("/response", extendDefault({
+ parameters: Fixtures.js,
+ onComplete: function(transport) {
+ this.assertEqual("same origin policy", $("content").innerHTML);
+ }.bind(this)
+ }));
+
+ new Ajax.Request("/response", extendDefault({
+ parameters: Fixtures.invalidJson,
+ onException: function(request, error) {
+ this.assert(error.message.include('Badly formed JSON string'));
+ }.bind(this)
+ }));
+
+ new Ajax.Request("/response", extendDefault({
+ parameters: { 'X-JSON': '{});window.attacked = true;({}' },
+ onException: function(request, error) {
+ this.assert(error.message.include('Badly formed JSON string'));
+ }.bind(this)
+ }));
+
+ Ajax.Request.prototype.isSameOrigin = isSameOrigin;
+ } else {
+ this.info(message);
+ }
+ }
+});
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/array_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/array_test.js
new file mode 100644
index 0000000000..c3f9d41147
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/array_test.js
@@ -0,0 +1,190 @@
+var globalArgsTest = 'nothing to see here';
+
+new Test.Unit.Runner({
+ test$A: function(){
+ this.assertEnumEqual([], $A({}));
+ },
+
+ testToArrayOnArguments: function(){
+ function toArrayOnArguments(){
+ globalArgsTest = $A(arguments);
+ }
+ toArrayOnArguments();
+ this.assertEnumEqual([], globalArgsTest);
+ toArrayOnArguments('foo');
+ this.assertEnumEqual(['foo'], globalArgsTest);
+ toArrayOnArguments('foo','bar');
+ this.assertEnumEqual(['foo','bar'], globalArgsTest);
+ },
+
+ testToArrayOnNodeList: function(){
+ // direct HTML
+ this.assertEqual(3, $A($('test_node').childNodes).length);
+
+ // DOM
+ var element = document.createElement('div');
+ element.appendChild(document.createTextNode('22'));
+ (2).times(function(){ element.appendChild(document.createElement('span')) });
+ this.assertEqual(3, $A(element.childNodes).length);
+
+ // HTML String
+ element = document.createElement('div');
+ $(element).update('22<span></span><span></span');
+ this.assertEqual(3, $A(element.childNodes).length);
+ },
+
+ testClear: function(){
+ this.assertEnumEqual([], [].clear());
+ this.assertEnumEqual([], [1].clear());
+ this.assertEnumEqual([], [1,2].clear());
+ },
+
+ testClone: function(){
+ this.assertEnumEqual([], [].clone());
+ this.assertEnumEqual([1], [1].clone());
+ this.assertEnumEqual([1,2], [1,2].clone());
+ this.assertEnumEqual([0,1,2], [0,1,2].clone());
+ var a = [0,1,2];
+ var b = a;
+ this.assertIdentical(a, b);
+ b = a.clone();
+ this.assertNotIdentical(a, b);
+ },
+
+ testFirst: function(){
+ this.assertUndefined([].first());
+ this.assertEqual(1, [1].first());
+ this.assertEqual(1, [1,2].first());
+ },
+
+ testLast: function(){
+ this.assertUndefined([].last());
+ this.assertEqual(1, [1].last());
+ this.assertEqual(2, [1,2].last());
+ },
+
+ testCompact: function(){
+ this.assertEnumEqual([], [].compact());
+ this.assertEnumEqual([1,2,3], [1,2,3].compact());
+ this.assertEnumEqual([0,1,2,3], [0,null,1,2,undefined,3].compact());
+ this.assertEnumEqual([1,2,3], [null,1,2,3,null].compact());
+ },
+
+ testFlatten: function(){
+ this.assertEnumEqual([], [].flatten());
+ this.assertEnumEqual([1,2,3], [1,2,3].flatten());
+ this.assertEnumEqual([1,2,3], [1,[[[2,3]]]].flatten());
+ this.assertEnumEqual([1,2,3], [[1],[2],[3]].flatten());
+ this.assertEnumEqual([1,2,3], [[[[[[[1]]]]]],2,3].flatten());
+ },
+
+ testIndexOf: function(){
+ this.assertEqual(-1, [].indexOf(1));
+ this.assertEqual(-1, [0].indexOf(1));
+ this.assertEqual(0, [1].indexOf(1));
+ this.assertEqual(1, [0,1,2].indexOf(1));
+ this.assertEqual(0, [1,2,1].indexOf(1));
+ this.assertEqual(2, [1,2,1].indexOf(1, -1));
+ this.assertEqual(1, [undefined,null].indexOf(null));
+ },
+
+ testLastIndexOf: function(){
+ this.assertEqual(-1,[].lastIndexOf(1));
+ this.assertEqual(-1, [0].lastIndexOf(1));
+ this.assertEqual(0, [1].lastIndexOf(1));
+ this.assertEqual(2, [0,2,4,6].lastIndexOf(4));
+ this.assertEqual(3, [4,4,2,4,6].lastIndexOf(4));
+ this.assertEqual(3, [0,2,4,6].lastIndexOf(6,3));
+ this.assertEqual(-1, [0,2,4,6].lastIndexOf(6,2));
+ this.assertEqual(0, [6,2,4,6].lastIndexOf(6,2));
+
+ var fixture = [1,2,3,4,3];
+ this.assertEqual(4, fixture.lastIndexOf(3));
+ this.assertEnumEqual([1,2,3,4,3],fixture);
+
+ //tests from http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:lastIndexOf
+ var array = [2, 5, 9, 2];
+ this.assertEqual(3,array.lastIndexOf(2));
+ this.assertEqual(-1,array.lastIndexOf(7));
+ this.assertEqual(3,array.lastIndexOf(2,3));
+ this.assertEqual(0,array.lastIndexOf(2,2));
+ this.assertEqual(0,array.lastIndexOf(2,-2));
+ this.assertEqual(3,array.lastIndexOf(2,-1));
+ },
+
+ testInspect: function(){
+ this.assertEqual('[]',[].inspect());
+ this.assertEqual('[1]',[1].inspect());
+ this.assertEqual('[\'a\']',['a'].inspect());
+ this.assertEqual('[\'a\', 1]',['a',1].inspect());
+ },
+
+ testIntersect: function(){
+ this.assertEnumEqual([1,3], [1,1,3,5].intersect([1,2,3]));
+ this.assertEnumEqual([1], [1,1].intersect([1,1]));
+ this.assertEnumEqual([0], [0,2].intersect([1,0]));
+ this.assertEnumEqual([], [1,1,3,5].intersect([4]));
+ this.assertEnumEqual([], [1].intersect(['1']));
+
+ this.assertEnumEqual(
+ ['B','C','D'],
+ $R('A','Z').toArray().intersect($R('B','D').toArray())
+ );
+ },
+
+ testToJSON: function(){
+ this.assertEqual('[]', [].toJSON());
+ this.assertEqual('[\"a\"]', ['a'].toJSON());
+ this.assertEqual('[\"a\", 1]', ['a', 1].toJSON());
+ this.assertEqual('[\"a\", {\"b\": null}]', ['a', {'b': null}].toJSON());
+ },
+
+ testReduce: function(){
+ this.assertUndefined([].reduce());
+ this.assertNull([null].reduce());
+ this.assertEqual(1, [1].reduce());
+ this.assertEnumEqual([1,2,3], [1,2,3].reduce());
+ this.assertEnumEqual([1,null,3], [1,null,3].reduce());
+ },
+
+ testReverse: function(){
+ this.assertEnumEqual([], [].reverse());
+ this.assertEnumEqual([1], [1].reverse());
+ this.assertEnumEqual([2,1], [1,2].reverse());
+ this.assertEnumEqual([3,2,1], [1,2,3].reverse());
+ },
+
+ testSize: function(){
+ this.assertEqual(4, [0, 1, 2, 3].size());
+ this.assertEqual(0, [].size());
+ },
+
+ testUniq: function(){
+ this.assertEnumEqual([1], [1, 1, 1].uniq());
+ this.assertEnumEqual([1], [1].uniq());
+ this.assertEnumEqual([], [].uniq());
+ this.assertEnumEqual([0, 1, 2, 3], [0, 1, 2, 2, 3, 0, 2].uniq());
+ this.assertEnumEqual([0, 1, 2, 3], [0, 0, 1, 1, 2, 3, 3, 3].uniq(true));
+ },
+
+ testWithout: function(){
+ this.assertEnumEqual([], [].without(0));
+ this.assertEnumEqual([], [0].without(0));
+ this.assertEnumEqual([1], [0,1].without(0));
+ this.assertEnumEqual([1,2], [0,1,2].without(0));
+ },
+
+ test$w: function(){
+ this.assertEnumEqual(['a', 'b', 'c', 'd'], $w('a b c d'));
+ this.assertEnumEqual([], $w(' '));
+ this.assertEnumEqual([], $w(''));
+ this.assertEnumEqual([], $w(null));
+ this.assertEnumEqual([], $w(undefined));
+ this.assertEnumEqual([], $w());
+ this.assertEnumEqual([], $w(10));
+ this.assertEnumEqual(['a'], $w('a'));
+ this.assertEnumEqual(['a'], $w('a '));
+ this.assertEnumEqual(['a'], $w(' a'));
+ this.assertEnumEqual(['a', 'b', 'c', 'd'], $w(' a b\nc\t\nd\n'));
+ }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/base_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/base_test.js
new file mode 100644
index 0000000000..f2843128a0
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/base_test.js
@@ -0,0 +1,511 @@
+new Test.Unit.Runner({
+ testFunctionArgumentNames: function() {
+ this.assertEnumEqual([], (function() {}).argumentNames());
+ this.assertEnumEqual(["one"], (function(one) {}).argumentNames());
+ this.assertEnumEqual(["one", "two", "three"], (function(one, two, three) {}).argumentNames());
+ this.assertEnumEqual(["one", "two", "three"], (function( one , two
+ , three ) {}).argumentNames());
+ this.assertEqual("$super", (function($super) {}).argumentNames().first());
+
+ function named1() {};
+ this.assertEnumEqual([], named1.argumentNames());
+ function named2(one) {};
+ this.assertEnumEqual(["one"], named2.argumentNames());
+ function named3(one, two, three) {};
+ this.assertEnumEqual(["one", "two", "three"], named3.argumentNames());
+ },
+
+ testFunctionBind: function() {
+ function methodWithoutArguments() { return this.hi };
+ function methodWithArguments() { return this.hi + ',' + $A(arguments).join(',') };
+ var func = Prototype.emptyFunction;
+
+ this.assertIdentical(func, func.bind());
+ this.assertIdentical(func, func.bind(undefined));
+ this.assertNotIdentical(func, func.bind(null));
+
+ this.assertEqual('without', methodWithoutArguments.bind({ hi: 'without' })());
+ this.assertEqual('with,arg1,arg2', methodWithArguments.bind({ hi: 'with' })('arg1','arg2'));
+ this.assertEqual('withBindArgs,arg1,arg2',
+ methodWithArguments.bind({ hi: 'withBindArgs' }, 'arg1', 'arg2')());
+ this.assertEqual('withBindArgsAndArgs,arg1,arg2,arg3,arg4',
+ methodWithArguments.bind({ hi: 'withBindArgsAndArgs' }, 'arg1', 'arg2')('arg3', 'arg4'));
+ },
+
+ testFunctionCurry: function() {
+ var split = function(delimiter, string) { return string.split(delimiter); };
+ var splitOnColons = split.curry(":");
+ this.assertNotIdentical(split, splitOnColons);
+ this.assertEnumEqual(split(":", "0:1:2:3:4:5"), splitOnColons("0:1:2:3:4:5"));
+ this.assertIdentical(split, split.curry());
+ },
+
+ testFunctionDelay: function() {
+ window.delayed = undefined;
+ var delayedFunction = function() { window.delayed = true; };
+ var delayedFunctionWithArgs = function() { window.delayedWithArgs = $A(arguments).join(' '); };
+ delayedFunction.delay(0.8);
+ delayedFunctionWithArgs.delay(0.8, 'hello', 'world');
+ this.assertUndefined(window.delayed);
+ this.wait(1000, function() {
+ this.assert(window.delayed);
+ this.assertEqual('hello world', window.delayedWithArgs);
+ });
+ },
+
+ testFunctionWrap: function() {
+ function sayHello(){
+ return 'hello world';
+ };
+
+ this.assertEqual('HELLO WORLD', sayHello.wrap(function(proceed) {
+ return proceed().toUpperCase();
+ })());
+
+ var temp = String.prototype.capitalize;
+ String.prototype.capitalize = String.prototype.capitalize.wrap(function(proceed, eachWord) {
+ if (eachWord && this.include(' ')) return this.split(' ').map(function(str){
+ return str.capitalize();
+ }).join(' ');
+ return proceed();
+ });
+ this.assertEqual('Hello world', 'hello world'.capitalize());
+ this.assertEqual('Hello World', 'hello world'.capitalize(true));
+ this.assertEqual('Hello', 'hello'.capitalize());
+ String.prototype.capitalize = temp;
+ },
+
+ testFunctionDefer: function() {
+ window.deferred = undefined;
+ var deferredFunction = function() { window.deferred = true; };
+ deferredFunction.defer();
+ this.assertUndefined(window.deferred);
+ this.wait(50, function() {
+ this.assert(window.deferred);
+
+ window.deferredValue = 0;
+ var deferredFunction2 = function(arg) { window.deferredValue = arg; };
+ deferredFunction2.defer('test');
+ this.wait(50, function() {
+ this.assertEqual('test', window.deferredValue);
+ });
+ });
+ },
+
+ testFunctionMethodize: function() {
+ var Foo = { bar: function(baz) { return baz } };
+ var baz = { quux: Foo.bar.methodize() };
+
+ this.assertEqual(Foo.bar.methodize(), baz.quux);
+ this.assertEqual(baz, Foo.bar(baz));
+ this.assertEqual(baz, baz.quux());
+ },
+
+ testObjectExtend: function() {
+ var object = {foo: 'foo', bar: [1, 2, 3]};
+ this.assertIdentical(object, Object.extend(object));
+ this.assertHashEqual({foo: 'foo', bar: [1, 2, 3]}, object);
+ this.assertIdentical(object, Object.extend(object, {bla: 123}));
+ this.assertHashEqual({foo: 'foo', bar: [1, 2, 3], bla: 123}, object);
+ this.assertHashEqual({foo: 'foo', bar: [1, 2, 3], bla: null},
+ Object.extend(object, {bla: null}));
+ },
+
+ testObjectToQueryString: function() {
+ this.assertEqual('a=A&b=B&c=C&d=D%23', Object.toQueryString({a: 'A', b: 'B', c: 'C', d: 'D#'}));
+ },
+
+ testObjectClone: function() {
+ var object = {foo: 'foo', bar: [1, 2, 3]};
+ this.assertNotIdentical(object, Object.clone(object));
+ this.assertHashEqual(object, Object.clone(object));
+ this.assertHashEqual({}, Object.clone());
+ var clone = Object.clone(object);
+ delete clone.bar;
+ this.assertHashEqual({foo: 'foo'}, clone,
+ "Optimizing Object.clone perf using prototyping doesn't allow properties to be deleted.");
+ },
+
+ testObjectInspect: function() {
+ this.assertEqual('undefined', Object.inspect());
+ this.assertEqual('undefined', Object.inspect(undefined));
+ this.assertEqual('null', Object.inspect(null));
+ this.assertEqual("'foo\\\\b\\\'ar'", Object.inspect('foo\\b\'ar'));
+ this.assertEqual('[]', Object.inspect([]));
+ this.assertNothingRaised(function() { Object.inspect(window.Node) });
+ },
+
+ testObjectToJSON: function() {
+ this.assertUndefined(Object.toJSON(undefined));
+ this.assertUndefined(Object.toJSON(Prototype.K));
+ this.assertEqual('\"\"', Object.toJSON(''));
+ this.assertEqual('[]', Object.toJSON([]));
+ this.assertEqual('[\"a\"]', Object.toJSON(['a']));
+ this.assertEqual('[\"a\", 1]', Object.toJSON(['a', 1]));
+ this.assertEqual('[\"a\", {\"b\": null}]', Object.toJSON(['a', {'b': null}]));
+ this.assertEqual('{\"a\": \"hello!\"}', Object.toJSON({a: 'hello!'}));
+ this.assertEqual('{}', Object.toJSON({}));
+ this.assertEqual('{}', Object.toJSON({a: undefined, b: undefined, c: Prototype.K}));
+ this.assertEqual('{\"b\": [false, true], \"c\": {\"a\": \"hello!\"}}',
+ Object.toJSON({'b': [undefined, false, true, undefined], c: {a: 'hello!'}}));
+ this.assertEqual('{\"b\": [false, true], \"c\": {\"a\": \"hello!\"}}',
+ Object.toJSON($H({'b': [undefined, false, true, undefined], c: {a: 'hello!'}})));
+ this.assertEqual('true', Object.toJSON(true));
+ this.assertEqual('false', Object.toJSON(false));
+ this.assertEqual('null', Object.toJSON(null));
+ var sam = new Person('sam');
+ this.assertEqual('-sam', Object.toJSON(sam));
+ this.assertEqual('-sam', sam.toJSON());
+ var element = $('test');
+ this.assertUndefined(Object.toJSON(element));
+ element.toJSON = function(){return 'I\'m a div with id test'};
+ this.assertEqual('I\'m a div with id test', Object.toJSON(element));
+ },
+
+ testObjectToHTML: function() {
+ this.assertIdentical('', Object.toHTML());
+ this.assertIdentical('', Object.toHTML(''));
+ this.assertIdentical('', Object.toHTML(null));
+ this.assertIdentical('0', Object.toHTML(0));
+ this.assertIdentical('123', Object.toHTML(123));
+ this.assertEqual('hello world', Object.toHTML('hello world'));
+ this.assertEqual('hello world', Object.toHTML({toHTML: function() { return 'hello world' }}));
+ },
+
+ testObjectIsArray: function() {
+ this.assert(Object.isArray([]));
+ this.assert(Object.isArray([0]));
+ this.assert(Object.isArray([0, 1]));
+ this.assert(!Object.isArray({}));
+ this.assert(!Object.isArray($('list').childNodes));
+ this.assert(!Object.isArray());
+ this.assert(!Object.isArray(''));
+ this.assert(!Object.isArray('foo'));
+ this.assert(!Object.isArray(0));
+ this.assert(!Object.isArray(1));
+ this.assert(!Object.isArray(null));
+ this.assert(!Object.isArray(true));
+ this.assert(!Object.isArray(false));
+ this.assert(!Object.isArray(undefined));
+ },
+
+ testObjectIsHash: function() {
+ this.assert(Object.isHash($H()));
+ this.assert(Object.isHash(new Hash()));
+ this.assert(!Object.isHash({}));
+ this.assert(!Object.isHash(null));
+ this.assert(!Object.isHash());
+ this.assert(!Object.isHash(''));
+ this.assert(!Object.isHash(2));
+ this.assert(!Object.isHash(false));
+ this.assert(!Object.isHash(true));
+ this.assert(!Object.isHash([]));
+ },
+
+ testObjectIsElement: function() {
+ this.assert(Object.isElement(document.createElement('div')));
+ this.assert(Object.isElement(new Element('div')));
+ this.assert(Object.isElement($('testlog')));
+ this.assert(!Object.isElement(document.createTextNode('bla')));
+
+ // falsy variables should not mess up return value type
+ this.assertIdentical(false, Object.isElement(0));
+ this.assertIdentical(false, Object.isElement(''));
+ this.assertIdentical(false, Object.isElement(NaN));
+ this.assertIdentical(false, Object.isElement(null));
+ this.assertIdentical(false, Object.isElement(undefined));
+ },
+
+ testObjectIsFunction: function() {
+ this.assert(Object.isFunction(function() { }));
+ this.assert(Object.isFunction(Class.create()));
+ this.assert(!Object.isFunction("a string"));
+ this.assert(!Object.isFunction($("testlog")));
+ this.assert(!Object.isFunction([]));
+ this.assert(!Object.isFunction({}));
+ this.assert(!Object.isFunction(0));
+ this.assert(!Object.isFunction(false));
+ this.assert(!Object.isFunction(undefined));
+ this.assert(!Object.isFunction(/foo/));
+ this.assert(!Object.isFunction(document.getElementsByTagName('div')));
+ },
+
+ testObjectIsString: function() {
+ this.assert(!Object.isString(function() { }));
+ this.assert(Object.isString("a string"));
+ this.assert(!Object.isString(0));
+ this.assert(!Object.isString([]));
+ this.assert(!Object.isString({}));
+ this.assert(!Object.isString(false));
+ this.assert(!Object.isString(undefined));
+ },
+
+ testObjectIsNumber: function() {
+ this.assert(Object.isNumber(0));
+ this.assert(Object.isNumber(1.0));
+ this.assert(!Object.isNumber(function() { }));
+ this.assert(!Object.isNumber("a string"));
+ this.assert(!Object.isNumber([]));
+ this.assert(!Object.isNumber({}));
+ this.assert(!Object.isNumber(false));
+ this.assert(!Object.isNumber(undefined));
+ },
+
+ testObjectIsUndefined: function() {
+ this.assert(Object.isUndefined(undefined));
+ this.assert(!Object.isUndefined(null));
+ this.assert(!Object.isUndefined(false));
+ this.assert(!Object.isUndefined(0));
+ this.assert(!Object.isUndefined(""));
+ this.assert(!Object.isUndefined(function() { }));
+ this.assert(!Object.isUndefined([]));
+ this.assert(!Object.isUndefined({}));
+ },
+
+ // sanity check
+ testDoesntExtendObjectPrototype: function() {
+ // for-in is supported with objects
+ var iterations = 0, obj = { a: 1, b: 2, c: 3 };
+ for (property in obj) iterations++;
+ this.assertEqual(3, iterations);
+
+ // for-in is not supported with arrays
+ iterations = 0;
+ var arr = [1,2,3];
+ for (property in arr) iterations++;
+ this.assert(iterations > 3);
+ },
+
+
+ testBindAsEventListener: function() {
+ for ( var i = 0; i < 10; ++i ) {
+ var div = document.createElement('div');
+ div.setAttribute('id','test-'+i);
+ document.body.appendChild(div);
+ var tobj = new TestObj();
+ var eventTest = { test: true };
+ var call = tobj.assertingEventHandler.bindAsEventListener(tobj,
+ this.assertEqual.bind(this, eventTest),
+ this.assertEqual.bind(this, arg1),
+ this.assertEqual.bind(this, arg2),
+ this.assertEqual.bind(this, arg3), arg1, arg2, arg3 );
+ call(eventTest);
+ }
+ },
+
+ testDateToJSON: function() {
+ this.assertEqual('\"1970-01-01T00:00:00Z\"', new Date(Date.UTC(1970, 0, 1)).toJSON());
+ },
+
+ testRegExpEscape: function() {
+ this.assertEqual('word', RegExp.escape('word'));
+ this.assertEqual('\\/slashes\\/', RegExp.escape('/slashes/'));
+ this.assertEqual('\\\\backslashes\\\\', RegExp.escape('\\backslashes\\'));
+ this.assertEqual('\\\\border of word', RegExp.escape('\\border of word'));
+
+ this.assertEqual('\\(\\?\\:non-capturing\\)', RegExp.escape('(?:non-capturing)'));
+ this.assertEqual('non-capturing', new RegExp(RegExp.escape('(?:') + '([^)]+)').exec('(?:non-capturing)')[1]);
+
+ this.assertEqual('\\(\\?\\=positive-lookahead\\)', RegExp.escape('(?=positive-lookahead)'));
+ this.assertEqual('positive-lookahead', new RegExp(RegExp.escape('(?=') + '([^)]+)').exec('(?=positive-lookahead)')[1]);
+
+ this.assertEqual('\\(\\?<\\=positive-lookbehind\\)', RegExp.escape('(?<=positive-lookbehind)'));
+ this.assertEqual('positive-lookbehind', new RegExp(RegExp.escape('(?<=') + '([^)]+)').exec('(?<=positive-lookbehind)')[1]);
+
+ this.assertEqual('\\(\\?\\!negative-lookahead\\)', RegExp.escape('(?!negative-lookahead)'));
+ this.assertEqual('negative-lookahead', new RegExp(RegExp.escape('(?!') + '([^)]+)').exec('(?!negative-lookahead)')[1]);
+
+ this.assertEqual('\\(\\?<\\!negative-lookbehind\\)', RegExp.escape('(?<!negative-lookbehind)'));
+ this.assertEqual('negative-lookbehind', new RegExp(RegExp.escape('(?<!') + '([^)]+)').exec('(?<!negative-lookbehind)')[1]);
+
+ this.assertEqual('\\[\\\\w\\]\\+', RegExp.escape('[\\w]+'));
+ this.assertEqual('character class', new RegExp(RegExp.escape('[') + '([^\\]]+)').exec('[character class]')[1]);
+
+ this.assertEqual('<div>', new RegExp(RegExp.escape('<div>')).exec('<td><div></td>')[0]);
+
+ this.assertEqual('false', RegExp.escape(false));
+ this.assertEqual('undefined', RegExp.escape());
+ this.assertEqual('null', RegExp.escape(null));
+ this.assertEqual('42', RegExp.escape(42));
+
+ this.assertEqual('\\\\n\\\\r\\\\t', RegExp.escape('\\n\\r\\t'));
+ this.assertEqual('\n\r\t', RegExp.escape('\n\r\t'));
+ this.assertEqual('\\{5,2\\}', RegExp.escape('{5,2}'));
+
+ this.assertEqual(
+ '\\/\\(\\[\\.\\*\\+\\?\\^\\=\\!\\:\\$\\{\\}\\(\\)\\|\\[\\\\\\]\\\\\\\/\\\\\\\\\\]\\)\\/g',
+ RegExp.escape('/([.*+?^=!:${}()|[\\]\\/\\\\])/g')
+ );
+ },
+
+ testBrowserDetection: function() {
+ var results = $H(Prototype.Browser).map(function(engine){
+ return engine;
+ }).partition(function(engine){
+ return engine[1] === true
+ });
+ var trues = results[0], falses = results[1];
+
+ this.info('User agent string is: ' + navigator.userAgent);
+
+ this.assert(trues.size() == 0 || trues.size() == 1,
+ 'There should be only one or no browser detected.');
+
+ // we should have definite trues or falses here
+ trues.each(function(result) {
+ this.assert(result[1] === true);
+ }, this);
+ falses.each(function(result) {
+ this.assert(result[1] === false);
+ }, this);
+
+ if (navigator.userAgent.indexOf('AppleWebKit/') > -1) {
+ this.info('Running on WebKit');
+ this.assert(Prototype.Browser.WebKit);
+ }
+
+ if (!!window.opera) {
+ this.info('Running on Opera');
+ this.assert(Prototype.Browser.Opera);
+ }
+
+ if (!!(window.attachEvent && !window.opera)) {
+ this.info('Running on IE');
+ this.assert(Prototype.Browser.IE);
+ }
+
+ if (navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1) {
+ this.info('Running on Gecko');
+ this.assert(Prototype.Browser.Gecko);
+ }
+ },
+
+ testClassCreate: function() {
+ this.assert(Object.isFunction(Animal), 'Animal is not a constructor');
+ this.assertEnumEqual([Cat, Mouse, Dog, Ox], Animal.subclasses);
+ Animal.subclasses.each(function(subclass) {
+ this.assertEqual(Animal, subclass.superclass);
+ }, this);
+
+ var Bird = Class.create(Animal);
+ this.assertEqual(Bird, Animal.subclasses.last());
+ // for..in loop (for some reason) doesn't iterate over the constructor property in top-level classes
+ this.assertEnumEqual(Object.keys(new Animal).sort(), Object.keys(new Bird).without('constructor').sort());
+ },
+
+ testClassInstantiation: function() {
+ var pet = new Animal("Nibbles");
+ this.assertEqual("Nibbles", pet.name, "property not initialized");
+ this.assertEqual('Nibbles: Hi!', pet.say('Hi!'));
+ this.assertEqual(Animal, pet.constructor, "bad constructor reference");
+ this.assertUndefined(pet.superclass);
+
+ var Empty = Class.create();
+ this.assert('object', typeof new Empty);
+ },
+
+ testInheritance: function() {
+ var tom = new Cat('Tom');
+ this.assertEqual(Cat, tom.constructor, "bad constructor reference");
+ this.assertEqual(Animal, tom.constructor.superclass, 'bad superclass reference');
+ this.assertEqual('Tom', tom.name);
+ this.assertEqual('Tom: meow', tom.say('meow'));
+ this.assertEqual('Tom: Yuk! I only eat mice.', tom.eat(new Animal));
+ },
+
+ testSuperclassMethodCall: function() {
+ var tom = new Cat('Tom');
+ this.assertEqual('Tom: Yum!', tom.eat(new Mouse));
+
+ // augment the constructor and test
+ var Dodo = Class.create(Animal, {
+ initialize: function($super, name) {
+ $super(name);
+ this.extinct = true;
+ },
+
+ say: function($super, message) {
+ return $super(message) + " honk honk";
+ }
+ });
+
+ var gonzo = new Dodo('Gonzo');
+ this.assertEqual('Gonzo', gonzo.name);
+ this.assert(gonzo.extinct, 'Dodo birds should be extinct');
+ this.assertEqual("Gonzo: hello honk honk", gonzo.say("hello"));
+ },
+
+ testClassAddMethods: function() {
+ var tom = new Cat('Tom');
+ var jerry = new Mouse('Jerry');
+
+ Animal.addMethods({
+ sleep: function() {
+ return this.say('ZZZ');
+ }
+ });
+
+ Mouse.addMethods({
+ sleep: function($super) {
+ return $super() + " ... no, can't sleep! Gotta steal cheese!";
+ },
+ escape: function(cat) {
+ return this.say('(from a mousehole) Take that, ' + cat.name + '!');
+ }
+ });
+
+ this.assertEqual('Tom: ZZZ', tom.sleep(), "added instance method not available to subclass");
+ this.assertEqual("Jerry: ZZZ ... no, can't sleep! Gotta steal cheese!", jerry.sleep());
+ this.assertEqual("Jerry: (from a mousehole) Take that, Tom!", jerry.escape(tom));
+ // insure that a method has not propagated *up* the prototype chain:
+ this.assertUndefined(tom.escape);
+ this.assertUndefined(new Animal().escape);
+
+ Animal.addMethods({
+ sleep: function() {
+ return this.say('zZzZ');
+ }
+ });
+
+ this.assertEqual("Jerry: zZzZ ... no, can't sleep! Gotta steal cheese!", jerry.sleep());
+ },
+
+ testBaseClassWithMixin: function() {
+ var grass = new Plant('grass', 3);
+ this.assertRespondsTo('getValue', grass);
+ this.assertEqual('#<Plant: grass>', grass.inspect());
+ },
+
+ testSubclassWithMixin: function() {
+ var snoopy = new Dog('Snoopy', 12, 'male');
+ this.assertRespondsTo('reproduce', snoopy);
+ },
+
+ testSubclassWithMixins: function() {
+ var cow = new Ox('cow', 400, 'female');
+ this.assertEqual('#<Ox: cow>', cow.inspect());
+ this.assertRespondsTo('reproduce', cow);
+ this.assertRespondsTo('getValue', cow);
+ },
+
+ testClassWithToStringAndValueOfMethods: function() {
+ var Foo = Class.create({
+ toString: function() { return "toString" },
+ valueOf: function() { return "valueOf" }
+ });
+
+ var Parent = Class.create({
+ m1: function(){ return 'm1' },
+ m2: function(){ return 'm2' }
+ });
+ var Child = Class.create(Parent, {
+ m1: function($super) { return 'm1 child' },
+ m2: function($super) { return 'm2 child' }
+ });
+
+ this.assert(new Child().m1.toString().indexOf('m1 child') > -1);
+
+ this.assertEqual("toString", new Foo().toString());
+ this.assertEqual("valueOf", new Foo().valueOf());
+ }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/dom_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/dom_test.js
new file mode 100644
index 0000000000..ebb3b383ec
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/dom_test.js
@@ -0,0 +1,1404 @@
+var getInnerHTML = function(id) {
+ return $(id).innerHTML.toString().toLowerCase().gsub(/[\r\n\t]/, '');
+};
+var createParagraph = function(text) {
+ var p = document.createElement('p');
+ p.appendChild(document.createTextNode(text));
+ return p;
+}
+
+new Test.Unit.Runner({
+ setup: function() {
+ if (documentViewportProperties) return;
+ // Based on properties check from http://www.quirksmode.org/viewport/compatibility.html
+ documentViewportProperties = {
+ properties : [
+ 'self.pageXOffset', 'self.pageYOffset',
+ 'self.screenX', 'self.screenY',
+ 'self.innerHeight', 'self.innerWidth',
+ 'self.outerHeight', 'self.outerWidth',
+ 'self.screen.height', 'self.screen.width',
+ 'self.screen.availHeight', 'self.screen.availWidth',
+ 'self.screen.availTop', 'self.screen.availLeft',
+ 'self.screen.Top', 'self.screen.Left',
+ 'self.screenTop', 'self.screenLeft',
+ 'document.body.clientHeight', 'document.body.clientWidth',
+ 'document.body.scrollHeight', 'document.body.scrollWidth',
+ 'document.body.scrollLeft', 'document.body.scrollTop',
+ 'document.body.offsetHeight', 'document.body.offsetWidth',
+ 'document.body.offsetTop', 'document.body.offsetLeft'
+ ].inject([], function(properties, prop) {
+ if (!self.screen && prop.include('self.screen')) return;
+ if (!document.body && prop.include('document.body')) return;
+ properties.push(prop);
+ if (prop.include('.body') && document.documentElement)
+ properties.push(prop.sub('.body', '.documentElement'));
+ return properties;
+ }),
+
+ inspect : function() {
+ var props = [];
+ this.properties.each(function(prop) {
+ if (eval(prop)) props[prop] = eval(prop);
+ }, this);
+ return props;
+ }
+ };
+ },
+
+ testDollarFunction: function() {
+ this.assertUndefined($());
+
+ this.assertNull(document.getElementById('noWayThisIDExists'));
+ this.assertNull($('noWayThisIDExists'));
+
+ this.assertIdentical(document.getElementById('testdiv'), $('testdiv'));
+ this.assertEnumEqual([ $('testdiv'), $('container') ], $('testdiv', 'container'));
+ this.assertEnumEqual([ $('testdiv'), undefined, $('container') ],
+ $('testdiv', 'noWayThisIDExists', 'container'));
+ var elt = $('testdiv');
+ this.assertIdentical(elt, $(elt));
+ this.assertRespondsTo('hide', elt);
+ this.assertRespondsTo('childOf', elt);
+ },
+
+ testGetElementsByClassName: function() {
+ if (document.getElementsByClassName.toString().include('[native code]')) {
+ this.info("browser uses native getElementsByClassName; skipping tests");
+ return;
+ }
+
+
+ var div = $('class_names'), list = $('class_names_ul');
+
+ this.assertElementsMatch(document.getElementsByClassName('A'), 'p.A', 'ul#class_names_ul.A', 'li.A.C');
+
+ if (Prototype.Browser.IE)
+ this.assertUndefined(document.getElementById('unextended').show);
+
+ this.assertElementsMatch(div.getElementsByClassName('B'), 'ul#class_names_ul.A.B', 'div.B.C.D');
+ this.assertElementsMatch(div.getElementsByClassName('D C B'), 'div.B.C.D');
+ this.assertElementsMatch(div.getElementsByClassName(' D\nC\tB '), 'div.B.C.D');
+ this.assertElementsMatch(div.getElementsByClassName($w('D C B')));
+ this.assertElementsMatch(list.getElementsByClassName('A'), 'li.A.C');
+ this.assertElementsMatch(list.getElementsByClassName(' A '), 'li.A.C');
+ this.assertElementsMatch(list.getElementsByClassName('C A'), 'li.A.C');
+ this.assertElementsMatch(list.getElementsByClassName("C\nA "), 'li.A.C');
+ this.assertElementsMatch(list.getElementsByClassName('B'));
+ this.assertElementsMatch(list.getElementsByClassName('1'), 'li.1');
+ this.assertElementsMatch(list.getElementsByClassName([1]), 'li.1');
+ this.assertElementsMatch(list.getElementsByClassName(['1 junk']));
+ this.assertElementsMatch(list.getElementsByClassName(''));
+ this.assertElementsMatch(list.getElementsByClassName(' '));
+ this.assertElementsMatch(list.getElementsByClassName(['']));
+ this.assertElementsMatch(list.getElementsByClassName([' ', '']));
+ this.assertElementsMatch(list.getElementsByClassName({}));
+
+ // those lookups shouldn't have extended all nodes in document
+ if (Prototype.Browser.IE) this.assertUndefined(document.getElementById('unextended')['show']);
+ },
+
+ testElementInsertWithHTML: function() {
+ Element.insert('insertions-main', {before:'<p><em>before</em> text</p><p>more testing</p>'});
+ this.assert(getInnerHTML('insertions-container').startsWith('<p><em>before</em> text</p><p>more testing</p>'));
+ Element.insert('insertions-main', {after:'<p><em>after</em> text</p><p>more testing</p>'});
+ this.assert(getInnerHTML('insertions-container').endsWith('<p><em>after</em> text</p><p>more testing</p>'));
+ Element.insert('insertions-main', {top:'<p><em>top</em> text.</p><p>more testing</p>'});
+ this.assert(getInnerHTML('insertions-main').startsWith('<p><em>top</em> text.</p><p>more testing</p>'));
+ Element.insert('insertions-main', {bottom:'<p><em>bottom</em> text.</p><p>more testing</p>'});
+ this.assert(getInnerHTML('insertions-main').endsWith('<p><em>bottom</em> text.</p><p>more testing</p>'));
+ },
+
+ testElementInsertWithDOMNode: function() {
+ Element.insert('insertions-node-main', {before: createParagraph('node before')});
+ this.assert(getInnerHTML('insertions-node-container').startsWith('<p>node before</p>'));
+ Element.insert('insertions-node-main', {after: createParagraph('node after')});
+ this.assert(getInnerHTML('insertions-node-container').endsWith('<p>node after</p>'));
+ Element.insert('insertions-node-main', {top:createParagraph('node top')});
+ this.assert(getInnerHTML('insertions-node-main').startsWith('<p>node top</p>'));
+ Element.insert('insertions-node-main', {bottom:createParagraph('node bottom')});
+ this.assert(getInnerHTML('insertions-node-main').endsWith('<p>node bottom</p>'));
+ this.assertEqual($('insertions-node-main'), $('insertions-node-main').insert(document.createElement('p')));
+ },
+
+ testElementInsertWithToElementMethod: function() {
+ Element.insert('insertions-node-main', {toElement: createParagraph.curry('toElement') });
+ this.assert(getInnerHTML('insertions-node-main').endsWith('<p>toelement</p>'));
+ Element.insert('insertions-node-main', {bottom: {toElement: createParagraph.curry('bottom toElement') }});
+ this.assert(getInnerHTML('insertions-node-main').endsWith('<p>bottom toelement</p>'));
+ },
+
+ testElementInsertWithToHTMLMethod: function() {
+ Element.insert('insertions-node-main', {toHTML: function() { return '<p>toHTML</p>'} });
+ this.assert(getInnerHTML('insertions-node-main').endsWith('<p>tohtml</p>'));
+ Element.insert('insertions-node-main', {bottom: {toHTML: function() { return '<p>bottom toHTML</p>'} }});
+ this.assert(getInnerHTML('insertions-node-main').endsWith('<p>bottom tohtml</p>'));
+ },
+
+ testElementInsertWithNonString: function() {
+ Element.insert('insertions-main', {bottom:3});
+ this.assert(getInnerHTML('insertions-main').endsWith('3'));
+ },
+
+ testElementInsertInTables: function() {
+ Element.insert('second_row', {after:'<tr id="third_row"><td>Third Row</td></tr>'});
+ this.assert($('second_row').descendantOf('table'));
+
+ $('a_cell').insert({top:'hello world'});
+ this.assert($('a_cell').innerHTML.startsWith('hello world'));
+ $('a_cell').insert({after:'<td>hi planet</td>'});
+ this.assertEqual('hi planet', $('a_cell').next().innerHTML);
+ $('table_for_insertions').insert('<tr><td>a cell!</td></tr>');
+ this.assert($('table_for_insertions').innerHTML.gsub('\r\n', '').toLowerCase().include('<tr><td>a cell!</td></tr>'));
+ $('row_1').insert({after:'<tr></tr><tr></tr><tr><td>last</td></tr>'});
+ this.assertEqual('last', $A($('table_for_row_insertions').getElementsByTagName('tr')).last().lastChild.innerHTML);
+ },
+
+ testElementInsertInSelect: function() {
+ var selectTop = $('select_for_insert_top'), selectBottom = $('select_for_insert_bottom');
+ selectBottom.insert('<option value="33">option 33</option><option selected="selected">option 45</option>');
+ this.assertEqual('option 45', selectBottom.getValue());
+ selectTop.insert({top:'<option value="A">option A</option><option value="B" selected="selected">option B</option>'});
+ this.assertEqual(4, selectTop.options.length);
+ },
+
+ testElementMethodInsert: function() {
+ $('element-insertions-main').insert({before:'some text before'});
+ this.assert(getInnerHTML('element-insertions-container').startsWith('some text before'));
+ $('element-insertions-main').insert({after:'some text after'});
+ this.assert(getInnerHTML('element-insertions-container').endsWith('some text after'));
+ $('element-insertions-main').insert({top:'some text top'});
+ this.assert(getInnerHTML('element-insertions-main').startsWith('some text top'));
+ $('element-insertions-main').insert({bottom:'some text bottom'});
+ this.assert(getInnerHTML('element-insertions-main').endsWith('some text bottom'));
+
+ $('element-insertions-main').insert('some more text at the bottom');
+ this.assert(getInnerHTML('element-insertions-main').endsWith('some more text at the bottom'));
+
+ $('element-insertions-main').insert({TOP:'some text uppercase top'});
+ this.assert(getInnerHTML('element-insertions-main').startsWith('some text uppercase top'));
+
+ $('element-insertions-multiple-main').insert({
+ top:'1', bottom:2, before: new Element('p').update('3'), after:'4'
+ });
+ this.assert(getInnerHTML('element-insertions-multiple-main').startsWith('1'));
+ this.assert(getInnerHTML('element-insertions-multiple-main').endsWith('2'));
+ this.assert(getInnerHTML('element-insertions-multiple-container').startsWith('<p>3</p>'));
+ this.assert(getInnerHTML('element-insertions-multiple-container').endsWith('4'));
+
+ $('element-insertions-main').update('test');
+ $('element-insertions-main').insert(null);
+ $('element-insertions-main').insert({bottom:null});
+ this.assertEqual('test', getInnerHTML('element-insertions-main'));
+ $('element-insertions-main').insert(1337);
+ this.assertEqual('test1337', getInnerHTML('element-insertions-main'));
+ },
+
+ testNewElementInsert: function() {
+ var container = new Element('div');
+ element = new Element('div');
+ container.insert(element);
+
+ element.insert({ before: '<p>a paragraph</p>' });
+ this.assertEqual('<p>a paragraph</p><div></div>', getInnerHTML(container));
+ element.insert({ after: 'some text' });
+ this.assertEqual('<p>a paragraph</p><div></div>some text', getInnerHTML(container));
+
+ element.insert({ top: '<p>a paragraph</p>' });
+ this.assertEqual('<p>a paragraph</p>', getInnerHTML(element));
+ element.insert('some text');
+ this.assertEqual('<p>a paragraph</p>some text', getInnerHTML(element));
+ },
+
+ testInsertionBackwardsCompatibility: function() {
+ new Insertion.Before('element-insertions-main', 'some backward-compatibility testing before');
+ this.assert(getInnerHTML('element-insertions-container').include('some backward-compatibility testing before'));
+ new Insertion.After('element-insertions-main', 'some backward-compatibility testing after');
+ this.assert(getInnerHTML('element-insertions-container').include('some backward-compatibility testing after'));
+ new Insertion.Top('element-insertions-main', 'some backward-compatibility testing top');
+ this.assert(getInnerHTML('element-insertions-main').startsWith('some backward-compatibility testing top'));
+ new Insertion.Bottom('element-insertions-main', 'some backward-compatibility testing bottom');
+ this.assert(getInnerHTML('element-insertions-main').endsWith('some backward-compatibility testing bottom'));
+ },
+
+ testElementWrap: function() {
+ var element = $('wrap'), parent = document.createElement('div');
+ element.wrap();
+ this.assert(getInnerHTML('wrap-container').startsWith('<div><p'));
+ element.wrap('div');
+ this.assert(getInnerHTML('wrap-container').startsWith('<div><div><p'));
+
+ element.wrap(parent);
+ this.assert(Object.isFunction(parent.setStyle));
+ this.assert(getInnerHTML('wrap-container').startsWith('<div><div><div><p'));
+
+ element.wrap('div', {className: 'wrapper'});
+ this.assert(element.up().hasClassName('wrapper'));
+ element.wrap({className: 'other-wrapper'});
+ this.assert(element.up().hasClassName('other-wrapper'));
+ element.wrap(new Element('div'), {className: 'yet-other-wrapper'});
+ this.assert(element.up().hasClassName('yet-other-wrapper'));
+
+ var orphan = new Element('p'), div = new Element('div');
+ orphan.wrap(div);
+ this.assertEqual(orphan.parentNode, div);
+ },
+
+ testElementWrapReturnsWrapper: function() {
+ var element = new Element("div");
+ var wrapper = element.wrap("div");
+ this.assertNotEqual(element, wrapper);
+ this.assertEqual(element.up(), wrapper);
+ },
+
+ testElementVisible: function(){
+ this.assertNotEqual('none', $('test-visible').style.display);
+ this.assertEqual('none', $('test-hidden').style.display);
+ },
+
+ testElementToggle: function(){
+ $('test-toggle-visible').toggle();
+ this.assert(!$('test-toggle-visible').visible());
+ $('test-toggle-visible').toggle();
+ this.assert($('test-toggle-visible').visible());
+ $('test-toggle-hidden').toggle();
+ this.assert($('test-toggle-hidden').visible());
+ $('test-toggle-hidden').toggle();
+ this.assert(!$('test-toggle-hidden').visible());
+ },
+
+ testElementShow: function(){
+ $('test-show-visible').show();
+ this.assert($('test-show-visible').visible());
+ $('test-show-hidden').show();
+ this.assert($('test-show-hidden').visible());
+ },
+
+ testElementHide: function(){
+ $('test-hide-visible').hide();
+ this.assert(!$('test-hide-visible').visible());
+ $('test-hide-hidden').hide();
+ this.assert(!$('test-hide-hidden').visible());
+ },
+
+ testElementRemove: function(){
+ $('removable').remove();
+ this.assert($('removable-container').empty());
+ },
+
+ testElementUpdate: function() {
+ $('testdiv').update('hello from div!');
+ this.assertEqual('hello from div!', $('testdiv').innerHTML);
+
+ Element.update('testdiv', 'another hello from div!');
+ this.assertEqual('another hello from div!', $('testdiv').innerHTML);
+
+ Element.update('testdiv', 123);
+ this.assertEqual('123', $('testdiv').innerHTML);
+
+ Element.update('testdiv');
+ this.assertEqual('', $('testdiv').innerHTML);
+
+ Element.update('testdiv', '&nbsp;');
+ this.assert(!$('testdiv').innerHTML.empty());
+ },
+
+ testElementUpdateWithScript: function() {
+ $('testdiv').update('hello from div!<script>\ntestVar="hello!";\n</'+'script>');
+ this.assertEqual('hello from div!',$('testdiv').innerHTML);
+ this.wait(100,function(){
+ this.assertEqual('hello!',testVar);
+
+ Element.update('testdiv','another hello from div!\n<script>testVar="another hello!"</'+'script>\nhere it goes');
+
+ // note: IE normalizes whitespace (like line breaks) to single spaces, thus the match test
+ this.assertMatch(/^another hello from div!\s+here it goes$/,$('testdiv').innerHTML);
+ this.wait(100,function(){
+ this.assertEqual('another hello!',testVar);
+
+ Element.update('testdiv','a\n<script>testVar="a"\ntestVar="b"</'+'script>');
+ this.wait(100,function(){
+ this.assertEqual('b', testVar);
+
+ Element.update('testdiv',
+ 'x<script>testVar2="a"</'+'script>\nblah\n'+
+ 'x<script>testVar2="b"</'+'script>');
+ this.wait(100,function(){
+ this.assertEqual('b', testVar2);
+ });
+ });
+ });
+ });
+ },
+
+ testElementUpdateInTableRow: function() {
+ $('second_row').update('<td id="i_am_a_td">test</td>');
+ this.assertEqual('test',$('i_am_a_td').innerHTML);
+
+ Element.update('second_row','<td id="i_am_a_td">another <span>test</span></td>');
+ this.assertEqual('another <span>test</span>',$('i_am_a_td').innerHTML.toLowerCase());
+ },
+
+ testElementUpdateInTableCell: function() {
+ Element.update('a_cell','another <span>test</span>');
+ this.assertEqual('another <span>test</span>',$('a_cell').innerHTML.toLowerCase());
+ },
+
+ testElementUpdateInTable: function() {
+ Element.update('table','<tr><td>boo!</td></tr>');
+ this.assertMatch(/^<tr>\s*<td>boo!<\/td><\/tr>$/,$('table').innerHTML.toLowerCase());
+ },
+
+ testElementUpdateInSelect: function() {
+ var select = $('select_for_update');
+ select.update('<option value="3">option 3</option><option selected="selected">option 4</option>');
+ this.assertEqual('option 4', select.getValue());
+ },
+
+ testElementUpdateWithDOMNode: function() {
+ $('testdiv').update(new Element('div').insert('bla'));
+ this.assertEqual('<div>bla</div>', getInnerHTML('testdiv'));
+ },
+
+ testElementUpdateWithToElementMethod: function() {
+ $('testdiv').update({toElement: createParagraph.curry('foo')});
+ this.assertEqual('<p>foo</p>', getInnerHTML('testdiv'));
+ },
+
+ testElementUpdateWithToHTMLMethod: function() {
+ $('testdiv').update({toHTML: function() { return 'hello world' }});
+ this.assertEqual('hello world', getInnerHTML('testdiv'));
+ },
+
+ testElementReplace: function() {
+ $('testdiv-replace-1').replace('hello from div!');
+ this.assertEqual('hello from div!', $('testdiv-replace-container-1').innerHTML);
+
+ $('testdiv-replace-2').replace(123);
+ this.assertEqual('123', $('testdiv-replace-container-2').innerHTML);
+
+ $('testdiv-replace-3').replace();
+ this.assertEqual('', $('testdiv-replace-container-3').innerHTML);
+
+ $('testrow-replace').replace('<tr><td>hello</td></tr>');
+ this.assert(getInnerHTML('testrow-replace-container').include('<tr><td>hello</td></tr>'));
+
+ $('testoption-replace').replace('<option>hello</option>');
+ this.assert($('testoption-replace-container').innerHTML.include('hello'));
+
+ Element.replace('testinput-replace', '<p>hello world</p>');
+ this.assertEqual('<p>hello world</p>', getInnerHTML('testform-replace'));
+
+ Element.replace('testform-replace', '<form></form>');
+ this.assertEqual('<p>some text</p><form></form><p>some text</p>', getInnerHTML('testform-replace-container'));
+ },
+
+ testElementReplaceWithScript: function() {
+ $('testdiv-replace-4').replace('hello from div!<script>testVarReplace="hello!"</'+'script>');
+ this.assertEqual('hello from div!', $('testdiv-replace-container-4').innerHTML);
+ this.wait(100,function(){
+ this.assertEqual('hello!',testVarReplace);
+
+ $('testdiv-replace-5').replace('another hello from div!\n<script>testVarReplace="another hello!"</'+'script>\nhere it goes');
+
+ // note: IE normalizes whitespace (like line breaks) to single spaces, thus the match test
+ this.assertMatch(/^another hello from div!\s+here it goes$/,$('testdiv-replace-container-5').innerHTML);
+ this.wait(100,function(){
+ this.assertEqual('another hello!',testVarReplace);
+ });
+ });
+ },
+
+ testElementReplaceWithDOMNode: function() {
+ $('testdiv-replace-element').replace(createParagraph('hello'));
+ this.assertEqual('<p>hello</p>', getInnerHTML('testdiv-replace-container-element'));
+ },
+
+ testElementReplaceWithToElementMethod: function() {
+ $('testdiv-replace-toelement').replace({toElement: createParagraph.curry('hello')});
+ this.assertEqual('<p>hello</p>', getInnerHTML('testdiv-replace-container-toelement'));
+ },
+
+ testElementReplaceWithToHTMLMethod: function() {
+ $('testdiv-replace-tohtml').replace({toHTML: function() { return 'hello' }});
+ this.assertEqual('hello', getInnerHTML('testdiv-replace-container-tohtml'));
+ },
+
+ testElementSelectorMethod: function() {
+ ['getElementsBySelector','select'].each(function(method) {
+ var testSelector = $('container')[method]('p.test');
+ this.assertEqual(testSelector.length, 4);
+ this.assertEqual(testSelector[0], $('intended'));
+ this.assertEqual(testSelector[0], $$('#container p.test')[0]);
+ }, this);
+ },
+
+ testElementAdjacent: function() {
+ var elements = $('intended').adjacent('p');
+ this.assertEqual(elements.length, 3);
+ elements.each(function(element){
+ this.assert(element != $('intended'));
+ }, this);
+ },
+
+ testElementIdentify: function() {
+ var parent = $('identification');
+ this.assertEqual(parent.down().identify(), 'predefined_id');
+ this.assert(parent.down(1).identify().startsWith('anonymous_element_'));
+ this.assert(parent.down(2).identify().startsWith('anonymous_element_'));
+ this.assert(parent.down(3).identify().startsWith('anonymous_element_'));
+
+ this.assert(parent.down(3).id !== parent.down(2).id);
+ },
+
+ testElementClassNameMethod: function() {
+ var testClassNames = $('container').getElementsByClassName('test');
+ var testSelector = $('container').getElementsBySelector('p.test');
+ this.assertEqual(testClassNames[0], $('intended'));
+ this.assertEqual(testClassNames.length, 4);
+ this.assertEqual(testSelector[3], testClassNames[3]);
+ this.assertEqual(testClassNames.length, testSelector.length);
+ },
+
+ testElementAncestors: function() {
+ var ancestors = $('navigation_test_f').ancestors();
+ this.assertElementsMatch(ancestors, 'ul', 'li', 'ul#navigation_test',
+ 'div#nav_tests_isolator', 'body', 'html');
+ this.assertElementsMatch(ancestors.last().ancestors());
+
+ var dummy = $(document.createElement('DIV'));
+ dummy.innerHTML = '<div></div>'.times(3);
+ this.assert(typeof $(dummy.childNodes[0]).ancestors()[0]['setStyle'] == 'function');
+ },
+
+ testElementDescendants: function() {
+ this.assertElementsMatch($('navigation_test').descendants(),
+ 'li', 'em', 'li', 'em.dim', 'li', 'em', 'ul', 'li',
+ 'em.dim', 'li#navigation_test_f', 'em', 'li', 'em');
+ this.assertElementsMatch($('navigation_test_f').descendants(), 'em');
+
+ var dummy = $(document.createElement('DIV'));
+ dummy.innerHTML = '<div></div>'.times(3);
+ this.assert(typeof dummy.descendants()[0].setStyle == 'function');
+ },
+
+ testElementFirstDescendant: function() {
+ this.assertElementMatches($('navigation_test').firstDescendant(), 'li.first');
+ this.assertNull($('navigation_test_next_sibling').firstDescendant());
+ },
+
+ testElementChildElements: function() {
+ this.assertElementsMatch($('navigation_test').childElements(),
+ 'li.first', 'li', 'li#navigation_test_c', 'li.last');
+ this.assertNotEqual(0, $('navigation_test_next_sibling').childNodes.length);
+ this.assertEnumEqual([], $('navigation_test_next_sibling').childElements());
+
+ var dummy = $(document.createElement('DIV'));
+ dummy.innerHTML = '<div></div>'.times(3);
+ this.assert(typeof dummy.childElements()[0].setStyle == 'function');
+ },
+
+ testElementImmediateDescendants: function() {
+ this.assertIdentical(Element.Methods.childElements, Element.Methods.immediateDescendants);
+ },
+
+ testElementPreviousSiblings: function() {
+ this.assertElementsMatch($('navigation_test').previousSiblings(),
+ 'span#nav_test_prev_sibling', 'p.test', 'div', 'div#nav_test_first_sibling');
+ this.assertElementsMatch($('navigation_test_f').previousSiblings(), 'li');
+
+ var dummy = $(document.createElement('DIV'));
+ dummy.innerHTML = '<div></div>'.times(3);
+ this.assert(typeof $(dummy.childNodes[1]).previousSiblings()[0].setStyle == 'function');
+ },
+
+ testElementNextSiblings: function() {
+ this.assertElementsMatch($('navigation_test').nextSiblings(),
+ 'div#navigation_test_next_sibling', 'p');
+ this.assertElementsMatch($('navigation_test_f').nextSiblings());
+
+ var dummy = $(document.createElement('DIV'));
+ dummy.innerHTML = '<div></div>'.times(3);
+ this.assert(typeof $(dummy.childNodes[0]).nextSiblings()[0].setStyle == 'function');
+ },
+
+ testElementSiblings: function() {
+ this.assertElementsMatch($('navigation_test').siblings(),
+ 'div#nav_test_first_sibling', 'div', 'p.test',
+ 'span#nav_test_prev_sibling', 'div#navigation_test_next_sibling', 'p');
+
+ var dummy = $(document.createElement('DIV'));
+ dummy.innerHTML = '<div></div>'.times(3);
+ this.assert(typeof $(dummy.childNodes[0]).siblings()[0].setStyle == 'function');
+ },
+
+ testElementUp: function() {
+ var element = $('navigation_test_f');
+ this.assertElementMatches(element.up(), 'ul');
+ this.assertElementMatches(element.up(0), 'ul');
+ this.assertElementMatches(element.up(1), 'li');
+ this.assertElementMatches(element.up(2), 'ul#navigation_test');
+ this.assertElementsMatch(element.up('li').siblings(), 'li.first', 'li', 'li.last');
+ this.assertElementMatches(element.up('ul', 1), 'ul#navigation_test');
+ this.assertEqual(undefined, element.up('garbage'));
+ this.assertEqual(undefined, element.up(6));
+ this.assertElementMatches(element.up('.non-existant, ul'), 'ul');
+
+ var dummy = $(document.createElement('DIV'));
+ dummy.innerHTML = '<div></div>'.times(3);
+ this.assert(typeof $(dummy.childNodes[0]).up().setStyle == 'function');
+ },
+
+ testElementDown: function() {
+ var element = $('navigation_test');
+ this.assertElementMatches(element.down(), 'li.first');
+ this.assertElementMatches(element.down(0), 'li.first');
+ this.assertElementMatches(element.down(1), 'em');
+ this.assertElementMatches(element.down('li', 5), 'li.last');
+ this.assertElementMatches(element.down('ul').down('li', 1), 'li#navigation_test_f');
+ this.assertElementMatches(element.down('.non-existant, .first'), 'li.first');
+
+ var dummy = $(document.createElement('DIV'));
+ dummy.innerHTML = '<div></div>'.times(3);
+ this.assert(typeof dummy.down().setStyle == 'function');
+
+ var input = $$('input')[0];
+ this.assertNothingRaised(function(){ input.down('span') });
+ this.assertUndefined(input.down('span'));
+ },
+
+ testElementPrevious: function() {
+ var element = $('navigation_test').down('li.last');
+ this.assertElementMatches(element.previous(), 'li#navigation_test_c');
+ this.assertElementMatches(element.previous(1), 'li');
+ this.assertElementMatches(element.previous('.first'), 'li.first');
+ this.assertEqual(undefined, element.previous(3));
+ this.assertEqual(undefined, $('navigation_test').down().previous());
+ this.assertElementMatches(element.previous('.non-existant, .first'), 'li.first');
+
+ var dummy = $(document.createElement('DIV'));
+ dummy.innerHTML = '<div></div>'.times(3);
+ this.assert(typeof $(dummy.childNodes[1]).previous().setStyle == 'function');
+ },
+
+ testElementNext: function() {
+ var element = $('navigation_test').down('li.first');
+ this.assertElementMatches(element.next(), 'li');
+ this.assertElementMatches(element.next(1), 'li#navigation_test_c');
+ this.assertElementMatches(element.next(2), 'li.last');
+ this.assertElementMatches(element.next('.last'), 'li.last');
+ this.assertEqual(undefined, element.next(3));
+ this.assertEqual(undefined, element.next(2).next());
+ this.assertElementMatches(element.next('.non-existant, .last'), 'li.last');
+
+ var dummy = $(document.createElement('DIV'));
+ dummy.innerHTML = '<div></div>'.times(3);
+ this.assert(typeof $(dummy.childNodes[0]).next().setStyle == 'function');
+ },
+
+ testElementInspect: function() {
+ this.assertEqual('<ul id="navigation_test">', $('navigation_test').inspect());
+ this.assertEqual('<li class="first">', $('navigation_test').down().inspect());
+ this.assertEqual('<em>', $('navigation_test').down(1).inspect());
+ },
+
+ testElementMakeClipping: function() {
+ var chained = Element.extend(document.createElement('DIV'));
+ this.assertEqual(chained, chained.makeClipping());
+ this.assertEqual(chained, chained.makeClipping());
+ this.assertEqual(chained, chained.makeClipping().makeClipping());
+
+ this.assertEqual(chained, chained.undoClipping());
+ this.assertEqual(chained, chained.undoClipping());
+ this.assertEqual(chained, chained.undoClipping().makeClipping());
+
+ ['hidden','visible','scroll'].each( function(overflowValue) {
+ var element = $('element_with_'+overflowValue+'_overflow');
+
+ this.assertEqual(overflowValue, element.getStyle('overflow'));
+ element.makeClipping();
+ this.assertEqual('hidden', element.getStyle('overflow'));
+ element.undoClipping();
+ this.assertEqual(overflowValue, element.getStyle('overflow'));
+ }, this);
+ },
+
+ testElementExtend: function() {
+ var element = $('element_extend_test');
+ this.assertRespondsTo('show', element);
+
+ var XHTML_TAGS = $w(
+ 'a abbr acronym address applet area '+
+ 'b bdo big blockquote br button caption '+
+ 'cite code col colgroup dd del dfn div dl dt '+
+ 'em fieldset form h1 h2 h3 h4 h5 h6 hr '+
+ 'i iframe img input ins kbd label legend li '+
+ 'map object ol optgroup option p param pre q samp '+
+ 'script select small span strong style sub sup '+
+ 'table tbody td textarea tfoot th thead tr tt ul var');
+
+ XHTML_TAGS.each(function(tag) {
+ var element = document.createElement(tag);
+ this.assertEqual(element, Element.extend(element));
+ this.assertRespondsTo('show', element);
+ }, this);
+
+ [null,'','a','aa'].each(function(content) {
+ var textnode = document.createTextNode(content);
+ this.assertEqual(textnode, Element.extend(textnode));
+ this.assert(typeof textnode['show'] == 'undefined');
+ }, this);
+ },
+
+ testElementExtendReextendsDiscardedNodes: function() {
+ this.assertRespondsTo('show', $('discard_1'));
+ $('element_reextend_test').innerHTML += '<div id="discard_2"></div>';
+ this.assertRespondsTo('show', $('discard_1'));
+ },
+
+ testElementCleanWhitespace: function() {
+ Element.cleanWhitespace("test_whitespace");
+ this.assertEqual(3, $("test_whitespace").childNodes.length);
+
+ this.assertEqual(1, $("test_whitespace").firstChild.nodeType);
+ this.assertEqual('SPAN', $("test_whitespace").firstChild.tagName);
+
+ this.assertEqual(1, $("test_whitespace").firstChild.nextSibling.nodeType);
+ this.assertEqual('DIV', $("test_whitespace").firstChild.nextSibling.tagName);
+
+ this.assertEqual(1, $("test_whitespace").firstChild.nextSibling.nextSibling.nodeType);
+ this.assertEqual('SPAN', $("test_whitespace").firstChild.nextSibling.nextSibling.tagName);
+
+ var element = document.createElement('DIV');
+ element.appendChild(document.createTextNode(''));
+ element.appendChild(document.createTextNode(''));
+ this.assertEqual(2, element.childNodes.length);
+ Element.cleanWhitespace(element);
+ this.assertEqual(0, element.childNodes.length);
+ },
+
+ testElementEmpty: function() {
+ this.assert($('test-empty').empty());
+ this.assert($('test-empty-but-contains-whitespace').empty());
+ this.assert(!$('test-full').empty());
+ },
+
+ testDescendantOf: function() {
+ this.assert($('child').descendantOf('ancestor'));
+ this.assert($('child').descendantOf($('ancestor')));
+
+ this.assert(!$('ancestor').descendantOf($('child')));
+
+ this.assert($('great-grand-child').descendantOf('ancestor'), 'great-grand-child < ancestor');
+ this.assert($('grand-child').descendantOf('ancestor'), 'grand-child < ancestor');
+ this.assert($('great-grand-child').descendantOf('grand-child'), 'great-grand-child < grand-child');
+ this.assert($('grand-child').descendantOf('child'), 'grand-child < child');
+ this.assert($('great-grand-child').descendantOf('child'), 'great-grand-child < child');
+
+ this.assert($('sibling').descendantOf('ancestor'), 'sibling < ancestor');
+ this.assert($('grand-sibling').descendantOf('sibling'), 'grand-sibling < sibling');
+ this.assert($('grand-sibling').descendantOf('ancestor'), 'grand-sibling < ancestor');
+
+ this.assert($('grand-sibling').descendantOf(document.body), 'grand-sibling < body');
+
+ this.assert(!$('great-grand-child').descendantOf('great-grand-child'), 'great-grand-child < great-grand-child');
+ this.assert(!$('great-grand-child').descendantOf('sibling'), 'great-grand-child < sibling');
+ this.assert(!$('sibling').descendantOf('child'), 'sibling < child');
+ this.assert(!$('great-grand-child').descendantOf('not-in-the-family'), 'great-grand-child < not-in-the-family');
+ this.assert(!$('child').descendantOf('not-in-the-family'), 'child < not-in-the-family');
+
+ this.assert(!$(document.body).descendantOf('great-grand-child'));
+
+ // dynamically-created elements
+ $('ancestor').insert(new Element('div', { id: 'weird-uncle' }));
+ this.assert($('weird-uncle').descendantOf('ancestor'));
+
+ $(document.body).insert(new Element('div', { id: 'impostor' }));
+ this.assert(!$('impostor').descendantOf('ancestor'));
+
+ // test descendantOf document
+ this.assert($(document.body).descendantOf(document));
+ this.assert($(document.documentElement).descendantOf(document));
+ },
+
+ testChildOf: function() {
+ this.assert($('child').childOf('ancestor'));
+ this.assert($('child').childOf($('ancestor')));
+ this.assert($('great-grand-child').childOf('ancestor'));
+ this.assert(!$('great-grand-child').childOf('not-in-the-family'));
+ this.assertIdentical(Element.Methods.childOf, Element.Methods.descendantOf);
+ },
+
+ testElementSetStyle: function() {
+ Element.setStyle('style_test_3',{ 'left': '2px' });
+ this.assertEqual('2px', $('style_test_3').style.left);
+
+ Element.setStyle('style_test_3',{ marginTop: '1px' });
+ this.assertEqual('1px', $('style_test_3').style.marginTop);
+
+ $('style_test_3').setStyle({ marginTop: '2px', left: '-1px' });
+ this.assertEqual('-1px', $('style_test_3').style.left);
+ this.assertEqual('2px', $('style_test_3').style.marginTop);
+
+ this.assertEqual('none', $('style_test_3').getStyle('float'));
+ $('style_test_3').setStyle({ 'float': 'left' });
+ this.assertEqual('left', $('style_test_3').getStyle('float'));
+
+ $('style_test_3').setStyle({ cssFloat: 'none' });
+ this.assertEqual('none', $('style_test_3').getStyle('float'));
+
+ this.assertEqual(1, $('style_test_3').getStyle('opacity'));
+
+ $('style_test_3').setStyle({ opacity: 0.5 });
+ this.assertEqual(0.5, $('style_test_3').getStyle('opacity'));
+
+ $('style_test_3').setStyle({ opacity: '' });
+ this.assertEqual(1, $('style_test_3').getStyle('opacity'));
+
+ $('style_test_3').setStyle({ opacity: 0 });
+ this.assertEqual(0, $('style_test_3').getStyle('opacity'));
+
+ $('test_csstext_1').setStyle('font-size: 15px');
+ this.assertEqual('15px', $('test_csstext_1').getStyle('font-size'));
+
+ $('test_csstext_2').setStyle({height: '40px'});
+ $('test_csstext_2').setStyle('font-size: 15px');
+ this.assertEqual('15px', $('test_csstext_2').getStyle('font-size'));
+ this.assertEqual('40px', $('test_csstext_2').getStyle('height'));
+
+ $('test_csstext_3').setStyle('font-size: 15px');
+ this.assertEqual('15px', $('test_csstext_3').getStyle('font-size'));
+ this.assertEqual('1px', $('test_csstext_3').getStyle('border-top-width'));
+
+ $('test_csstext_4').setStyle('font-size: 15px');
+ this.assertEqual('15px', $('test_csstext_4').getStyle('font-size'));
+
+ $('test_csstext_4').setStyle('float: right; font-size: 10px');
+ this.assertEqual('right', $('test_csstext_4').getStyle('float'));
+ this.assertEqual('10px', $('test_csstext_4').getStyle('font-size'));
+
+ $('test_csstext_5').setStyle('float: left; opacity: .5; font-size: 10px');
+ this.assertEqual(parseFloat('0.5'), parseFloat($('test_csstext_5').getStyle('opacity')));
+ },
+
+ testElementSetStyleCamelized: function() {
+ this.assertNotEqual('30px', $('style_test_3').style.marginTop);
+ $('style_test_3').setStyle({ marginTop: '30px'}, true);
+ this.assertEqual('30px', $('style_test_3').style.marginTop);
+ },
+
+ testElementSetOpacity: function() {
+ [0,0.1,0.5,0.999].each(function(opacity){
+ $('style_test_3').setOpacity(opacity);
+
+ // b/c of rounding issues on IE special case
+ var realOpacity = $('style_test_3').getStyle('opacity');
+
+ // opera rounds off to two significant digits, so we check for a
+ // ballpark figure
+ this.assert((Number(realOpacity) - opacity) <= 0.002, 'setting opacity to ' + opacity);
+ }, this);
+
+ this.assertEqual(0,
+ $('style_test_3').setOpacity(0.0000001).getStyle('opacity'));
+
+ // for Firefox, we don't set to 1, because of flickering
+ this.assert(
+ $('style_test_3').setOpacity(0.9999999).getStyle('opacity') > 0.999
+ );
+ if (Prototype.Browser.IE) {
+ this.assert($('style_test_4').setOpacity(0.5).currentStyle.hasLayout);
+ this.assert(2, $('style_test_5').setOpacity(0.5).getStyle('zoom'));
+ this.assert(0.5, new Element('div').setOpacity(0.5).getOpacity());
+ this.assert(2, new Element('div').setOpacity(0.5).setStyle('zoom: 2;').getStyle('zoom'));
+ this.assert(2, new Element('div').setStyle('zoom: 2;').setOpacity(0.5).getStyle('zoom'));
+ }
+ },
+
+ testElementGetStyle: function() {
+ this.assertEqual("none",
+ $('style_test_1').getStyle('display'));
+
+ // not displayed, so "null" ("auto" is tranlated to "null")
+ this.assertNull(Element.getStyle('style_test_1', 'width'), 'elements that are hidden should return null on getStyle("width")');
+
+ $('style_test_1').show();
+
+ // from id rule
+ this.assertEqual("pointer",
+ Element.getStyle('style_test_1','cursor'));
+
+ this.assertEqual("block",
+ Element.getStyle('style_test_2','display'));
+
+ // we should always get something for width (if displayed)
+ // firefox and safari automatically send the correct value,
+ // IE is special-cased to do the same
+ this.assertEqual($('style_test_2').offsetWidth+'px', Element.getStyle('style_test_2','width'));
+
+ this.assertEqual("static",Element.getStyle('style_test_1','position'));
+ // from style
+ this.assertEqual("11px",
+ Element.getStyle('style_test_2','font-size'));
+ // from class
+ this.assertEqual("1px",
+ Element.getStyle('style_test_2','margin-left'));
+
+ ['not_floating_none','not_floating_style','not_floating_inline'].each(function(element) {
+ this.assertEqual('none', $(element).getStyle('float'));
+ this.assertEqual('none', $(element).getStyle('cssFloat'));
+ }, this);
+
+ ['floating_style','floating_inline'].each(function(element) {
+ this.assertEqual('left', $(element).getStyle('float'));
+ this.assertEqual('left', $(element).getStyle('cssFloat'));
+ }, this);
+
+ this.assertEqual(0.5, $('op1').getStyle('opacity'));
+ this.assertEqual(0.5, $('op2').getStyle('opacity'));
+ this.assertEqual(1.0, $('op3').getStyle('opacity'));
+
+ $('op1').setStyle({opacity: '0.3'});
+ $('op2').setStyle({opacity: '0.3'});
+ $('op3').setStyle({opacity: '0.3'});
+
+ this.assertEqual(0.3, $('op1').getStyle('opacity'));
+ this.assertEqual(0.3, $('op2').getStyle('opacity'));
+ this.assertEqual(0.3, $('op3').getStyle('opacity'));
+
+ $('op3').setStyle({opacity: 0});
+ this.assertEqual(0, $('op3').getStyle('opacity'));
+
+ if (navigator.appVersion.match(/MSIE/)) {
+ this.assertEqual('alpha(opacity=30)', $('op1').getStyle('filter'));
+ this.assertEqual('progid:DXImageTransform.Microsoft.Blur(strength=10)alpha(opacity=30)', $('op2').getStyle('filter'));
+ $('op2').setStyle({opacity:''});
+ this.assertEqual('progid:DXImageTransform.Microsoft.Blur(strength=10)', $('op2').getStyle('filter'));
+ this.assertEqual('alpha(opacity=0)', $('op3').getStyle('filter'));
+ this.assertEqual(0.3, $('op4-ie').getStyle('opacity'));
+ }
+ // verify that value is still found when using camelized
+ // strings (function previously used getPropertyValue()
+ // which expected non-camelized strings)
+ this.assertEqual("12px", $('style_test_1').getStyle('fontSize'));
+
+ // getStyle on width/height should return values according to
+ // the CSS box-model, which doesn't include
+ // margin, padding, or borders
+ // TODO: This test fails on IE because there seems to be no way
+ // to calculate this properly (clientWidth/Height returns 0)
+ if (!navigator.appVersion.match(/MSIE/)) {
+ this.assertEqual("14px", $('style_test_dimensions').getStyle('width'));
+ this.assertEqual("17px", $('style_test_dimensions').getStyle('height'));
+ }
+
+ // height/width could always be calculated if it's set to "auto" (Firefox)
+ this.assertNotNull($('auto_dimensions').getStyle('height'));
+ this.assertNotNull($('auto_dimensions').getStyle('width'));
+ },
+
+ testElementGetOpacity: function() {
+ this.assertEqual(0.45, $('op1').setOpacity(0.45).getOpacity());
+ },
+
+ testElementReadAttribute: function() {
+ var attribFormIssues = $('attributes_with_issues_form');
+ this.assertEqual('blah-class', attribFormIssues.readAttribute('class'));
+ this.assertEqual('post', attribFormIssues.readAttribute('method'));
+ this.assertEqual('string', typeof(attribFormIssues.readAttribute('action')));
+ this.assertEqual('string', typeof(attribFormIssues.readAttribute('id')));
+
+ $(document.body).insert('<div id="ie_href_test_div"></div>');
+ $('ie_href_test_div').insert('<p>blah blah</p><a id="ie_href_test" href="test.html">blah</a>');
+ this.assertEqual('test.html', $('ie_href_test').readAttribute('href'));
+
+ this.assertEqual('test.html' , $('attributes_with_issues_1').readAttribute('href'));
+ this.assertEqual('L' , $('attributes_with_issues_1').readAttribute('accesskey'));
+ this.assertEqual('50' , $('attributes_with_issues_1').readAttribute('tabindex'));
+ this.assertEqual('a link' , $('attributes_with_issues_1').readAttribute('title'));
+
+ $('cloned_element_attributes_issue').readAttribute('foo')
+ var clone = $('cloned_element_attributes_issue').cloneNode(true);
+ clone.writeAttribute('foo', 'cloned');
+ this.assertEqual('cloned', clone.readAttribute('foo'));
+ this.assertEqual('original', $('cloned_element_attributes_issue').readAttribute('foo'));
+
+ ['href', 'accesskey', 'accesskey', 'title'].each(function(attr) {
+ this.assertEqual('' , $('attributes_with_issues_2').readAttribute(attr));
+ }, this);
+
+ ['checked','disabled','readonly','multiple'].each(function(attr) {
+ this.assertEqual(attr, $('attributes_with_issues_'+attr).readAttribute(attr));
+ }, this);
+
+ this.assertEqual("alert('hello world');", $('attributes_with_issues_1').readAttribute('onclick'));
+ this.assertNull($('attributes_with_issues_1').readAttribute('onmouseover'));
+
+ this.assertEqual('date', $('attributes_with_issues_type').readAttribute('type'));
+ this.assertEqual('text', $('attributes_with_issues_readonly').readAttribute('type'));
+
+ var elements = $('custom_attributes').immediateDescendants();
+ this.assertEnumEqual(['1', '2'], elements.invoke('readAttribute', 'foo'));
+ this.assertEnumEqual(['2', null], elements.invoke('readAttribute', 'bar'));
+
+ var table = $('write_attribute_table');
+ this.assertEqual('4', table.readAttribute('cellspacing'));
+ this.assertEqual('6', table.readAttribute('cellpadding'));
+
+ // test for consistent flag value across browsers
+ ["true", true, " ", 'rEadOnLy'].each(function(value) {
+ $('attributes_with_issues_readonly').writeAttribute('readonly', value);
+ this.assertEqual('readonly', $('attributes_with_issues_readonly').readAttribute('readonly'));
+ }, this);
+ },
+
+ testElementWriteAttribute: function() {
+ var element = Element.extend(document.body.appendChild(document.createElement('p')));
+ this.assertRespondsTo('writeAttribute', element);
+ this.assertEqual(element, element.writeAttribute('id', 'write_attribute_test'));
+ this.assertEqual('write_attribute_test', element.id);
+ this.assertEqual('http://prototypejs.org/', $('write_attribute_link').
+ writeAttribute({href: 'http://prototypejs.org/', title: 'Home of Prototype'}).href);
+ this.assertEqual('Home of Prototype', $('write_attribute_link').title);
+
+ var element2 = Element.extend(document.createElement('p'));
+ element2.writeAttribute('id', 'write_attribute_without_hash');
+ this.assertEqual('write_attribute_without_hash', element2.id);
+ element2.writeAttribute('animal', 'cat');
+ this.assertEqual('cat', element2.readAttribute('animal'));
+ },
+
+ testElementWriteAttributeWithBooleans: function() {
+ var input = $('write_attribute_input'),
+ select = $('write_attribute_select'),
+ checkbox = $('write_attribute_checkbox'),
+ checkedCheckbox = $('write_attribute_checked_checkbox');
+ this.assert( input. writeAttribute('readonly'). hasAttribute('readonly'));
+ this.assert(!input. writeAttribute('readonly', false). hasAttribute('readonly'));
+ this.assert( input. writeAttribute('readonly', true). hasAttribute('readonly'));
+ this.assert(!input. writeAttribute('readonly', null). hasAttribute('readonly'));
+ this.assert( input. writeAttribute('readonly', 'readonly').hasAttribute('readonly'));
+ this.assert( select. writeAttribute('multiple'). hasAttribute('multiple'));
+ this.assert( input. writeAttribute('disabled'). hasAttribute('disabled'));
+ this.assert( checkbox. writeAttribute('checked'). checked);
+ this.assert(!checkedCheckbox.writeAttribute('checked', false). checked);
+ },
+
+ testElementWriteAttributeWithIssues: function() {
+ var input = $('write_attribute_input').writeAttribute({maxlength: 90, minlength:80, tabindex: 10}),
+ td = $('write_attribute_td').writeAttribute({valign: 'bottom', colspan: 2, rowspan: 2});
+ this.assertEqual(80, input.readAttribute('minlength'));
+ this.assertEqual(90, input.readAttribute('maxlength'));
+ this.assertEqual(10, input.readAttribute('tabindex'));
+ this.assertEqual(2, td.readAttribute('colspan'));
+ this.assertEqual(2, td.readAttribute('rowspan'));
+ this.assertEqual('bottom', td.readAttribute('valign'));
+
+ var p = $('write_attribute_para'), label = $('write_attribute_label');
+ this.assertEqual('some-class', p. writeAttribute({'class': 'some-class'}). readAttribute('class'));
+ this.assertEqual('some-className', p. writeAttribute({className: 'some-className'}).readAttribute('class'));
+ this.assertEqual('some-id', label.writeAttribute({'for': 'some-id'}). readAttribute('for'));
+ this.assertEqual('some-other-id', label.writeAttribute({htmlFor: 'some-other-id'}). readAttribute('for'));
+
+ this.assert(p.writeAttribute({style: 'width: 5px;'}).readAttribute('style').toLowerCase().include('width'));
+
+ var table = $('write_attribute_table');
+ table.writeAttribute('cellspacing', '2')
+ table.writeAttribute('cellpadding', '3')
+ this.assertEqual('2', table.readAttribute('cellspacing'));
+ this.assertEqual('3', table.readAttribute('cellpadding'));
+
+ var iframe = new Element('iframe', { frameborder: 0 });
+ this.assertIdentical(0, parseInt(iframe.readAttribute('frameborder')));
+ },
+
+ testElementWriteAttributeWithCustom: function() {
+ var p = $('write_attribute_para').writeAttribute({name: 'martin', location: 'stockholm', age: 26});
+ this.assertEqual('martin', p.readAttribute('name'));
+ this.assertEqual('stockholm', p.readAttribute('location'));
+ this.assertEqual('26', p.readAttribute('age'));
+ },
+
+ testElementHasAttribute: function() {
+ var label = $('write_attribute_label');
+ this.assertIdentical(true, label.hasAttribute('for'));
+ this.assertIdentical(false, label.hasAttribute('htmlFor'));
+ this.assertIdentical(false, label.hasAttribute('className'));
+ this.assertIdentical(false, label.hasAttribute('rainbows'));
+
+ var input = $('write_attribute_input');
+ this.assertNotIdentical(null, input.hasAttribute('readonly'));
+ this.assertNotIdentical(null, input.hasAttribute('readOnly'));
+ },
+
+ testNewElement: function() {
+ this.assert(new Element('h1'));
+
+ var XHTML_TAGS = $w(
+ 'a abbr acronym address area '+
+ 'b bdo big blockquote br button caption '+
+ 'cite code col colgroup dd del dfn div dl dt '+
+ 'em fieldset form h1 h2 h3 h4 h5 h6 hr '+
+ 'i iframe img input ins kbd label legend li '+
+ 'map object ol optgroup option p param pre q samp '+
+ 'script select small span strong style sub sup '+
+ 'table tbody td textarea tfoot th thead tr tt ul var');
+
+ XHTML_TAGS.each(function(tag, index) {
+ var id = tag + '_' + index, element = document.body.appendChild(new Element(tag, {id: id}));
+ this.assertEqual(tag, element.tagName.toLowerCase());
+ this.assertEqual(element, document.body.lastChild);
+ this.assertEqual(id, element.id);
+ }, this);
+
+
+ this.assertRespondsTo('update', new Element('div'));
+ Element.addMethods({
+ cheeseCake: function(){
+ return 'Cheese cake';
+ }
+ });
+
+ this.assertRespondsTo('cheeseCake', new Element('div'));
+
+ /* window.ElementOld = function(tagName, attributes) {
+ if (Prototype.Browser.IE && attributes && attributes.name) {
+ tagName = '<' + tagName + ' name="' + attributes.name + '">';
+ delete attributes.name;
+ }
+ return Element.extend(document.createElement(tagName)).writeAttribute(attributes || {});
+ };
+
+ this.benchmark(function(){
+ XHTML_TAGS.each(function(tagName) { new Element(tagName) });
+ }, 5);
+
+ this.benchmark(function(){
+ XHTML_TAGS.each(function(tagName) { new ElementOld(tagName) });
+ }, 5); */
+
+ this.assertEqual('foobar', new Element('a', {custom: 'foobar'}).readAttribute('custom'));
+ var input = document.body.appendChild(new Element('input',
+ {id: 'my_input_field_id', name: 'my_input_field'}));
+ this.assertEqual(input, document.body.lastChild);
+ this.assertEqual('my_input_field', $(document.body.lastChild).name);
+ if (Prototype.Browser.IE)
+ this.assertMatch(/name=["']?my_input_field["']?/, $('my_input_field').outerHTML);
+
+ if (originalElement && Prototype.BrowserFeatures.ElementExtensions) {
+ Element.prototype.fooBar = Prototype.emptyFunction
+ this.assertRespondsTo('fooBar', new Element('div'));
+ }
+
+ //test IE setting "type" property of newly created button element
+ var button = new Element('button', {id:'button_type_test',type: 'reset'});
+ var form = $('attributes_with_issues_form');
+ var input = $('attributes_with_issues_regular');
+
+ form.insert(button);
+ input.value = 1;
+ button.click();
+
+ this.assertEqual('0', input.value);
+ button.remove();
+ },
+
+ testElementGetHeight: function() {
+ this.assertIdentical(100, $('dimensions-visible').getHeight());
+ this.assertIdentical(100, $('dimensions-display-none').getHeight());
+ },
+
+ testElementGetWidth: function() {
+ this.assertIdentical(200, $('dimensions-visible').getWidth());
+ this.assertIdentical(200, $('dimensions-display-none').getWidth());
+ },
+
+ testElementGetDimensions: function() {
+ this.assertIdentical(100, $('dimensions-visible').getDimensions().height);
+ this.assertIdentical(200, $('dimensions-visible').getDimensions().width);
+ this.assertIdentical(100, $('dimensions-display-none').getDimensions().height);
+ this.assertIdentical(200, $('dimensions-display-none').getDimensions().width);
+
+ this.assertIdentical(100, $('dimensions-visible-pos-rel').getDimensions().height);
+ this.assertIdentical(200, $('dimensions-visible-pos-rel').getDimensions().width);
+ this.assertIdentical(100, $('dimensions-display-none-pos-rel').getDimensions().height);
+ this.assertIdentical(200, $('dimensions-display-none-pos-rel').getDimensions().width);
+
+ this.assertIdentical(100, $('dimensions-visible-pos-abs').getDimensions().height);
+ this.assertIdentical(200, $('dimensions-visible-pos-abs').getDimensions().width);
+ this.assertIdentical(100, $('dimensions-display-none-pos-abs').getDimensions().height);
+ this.assertIdentical(200, $('dimensions-display-none-pos-abs').getDimensions().width);
+
+ // known failing issue
+ // this.assert($('dimensions-nestee').getDimensions().width <= 500, 'check for proper dimensions of hidden child elements');
+
+ $('dimensions-td').hide();
+ this.assertIdentical(100, $('dimensions-td').getDimensions().height);
+ this.assertIdentical(200, $('dimensions-td').getDimensions().width);
+ $('dimensions-td').show();
+
+ $('dimensions-tr').hide();
+ this.assertIdentical(100, $('dimensions-tr').getDimensions().height);
+ this.assertIdentical(200, $('dimensions-tr').getDimensions().width);
+ $('dimensions-tr').show();
+
+ $('dimensions-table').hide();
+ this.assertIdentical(100, $('dimensions-table').getDimensions().height);
+ this.assertIdentical(200, $('dimensions-table').getDimensions().width);
+
+ },
+
+ testDOMAttributesHavePrecedenceOverExtendedElementMethods: function() {
+ this.assertNothingRaised(function() { $('dom_attribute_precedence').down('form') });
+ this.assertEqual($('dom_attribute_precedence').down('input'), $('dom_attribute_precedence').down('form').update);
+ },
+
+ testClassNames: function() {
+ this.assertEnumEqual([], $('class_names').classNames());
+ this.assertEnumEqual(['A'], $('class_names').down().classNames());
+ this.assertEnumEqual(['A', 'B'], $('class_names_ul').classNames());
+ },
+
+ testHasClassName: function() {
+ this.assertIdentical(false, $('class_names').hasClassName('does_not_exist'));
+ this.assertIdentical(true, $('class_names').down().hasClassName('A'));
+ this.assertIdentical(false, $('class_names').down().hasClassName('does_not_exist'));
+ this.assertIdentical(true, $('class_names_ul').hasClassName('A'));
+ this.assertIdentical(true, $('class_names_ul').hasClassName('B'));
+ this.assertIdentical(false, $('class_names_ul').hasClassName('does_not_exist'));
+ },
+
+ testAddClassName: function() {
+ $('class_names').addClassName('added_className');
+ this.assertEnumEqual(['added_className'], $('class_names').classNames());
+
+ $('class_names').addClassName('added_className'); // verify that className cannot be added twice.
+ this.assertEnumEqual(['added_className'], $('class_names').classNames());
+
+ $('class_names').addClassName('another_added_className');
+ this.assertEnumEqual(['added_className', 'another_added_className'], $('class_names').classNames());
+ },
+
+ testRemoveClassName: function() {
+ $('class_names').removeClassName('added_className');
+ this.assertEnumEqual(['another_added_className'], $('class_names').classNames());
+
+ $('class_names').removeClassName('added_className'); // verify that removing a non existent className is safe.
+ this.assertEnumEqual(['another_added_className'], $('class_names').classNames());
+
+ $('class_names').removeClassName('another_added_className');
+ this.assertEnumEqual([], $('class_names').classNames());
+ },
+
+ testToggleClassName: function() {
+ $('class_names').toggleClassName('toggled_className');
+ this.assertEnumEqual(['toggled_className'], $('class_names').classNames());
+
+ $('class_names').toggleClassName('toggled_className');
+ this.assertEnumEqual([], $('class_names').classNames());
+
+ $('class_names_ul').toggleClassName('toggled_className');
+ this.assertEnumEqual(['A', 'B', 'toggled_className'], $('class_names_ul').classNames());
+
+ $('class_names_ul').toggleClassName('toggled_className');
+ this.assertEnumEqual(['A', 'B'], $('class_names_ul').classNames());
+ },
+
+ testElementScrollTo: function() {
+ var elem = $('scroll_test_2');
+ Element.scrollTo('scroll_test_2');
+ this.assertEqual(Position.page(elem)[1], 0);
+ window.scrollTo(0, 0);
+
+ elem.scrollTo();
+ this.assertEqual(Position.page(elem)[1], 0);
+ window.scrollTo(0, 0);
+ },
+
+ testCustomElementMethods: function() {
+ var elem = $('navigation_test_f');
+ this.assertRespondsTo('hashBrowns', elem);
+ this.assertEqual('hash browns', elem.hashBrowns());
+
+ this.assertRespondsTo('hashBrowns', Element);
+ this.assertEqual('hash browns', Element.hashBrowns(elem));
+ },
+
+ testSpecificCustomElementMethods: function() {
+ var elem = $('navigation_test_f');
+
+ this.assert(Element.Methods.ByTag[elem.tagName]);
+ this.assertRespondsTo('pancakes', elem);
+ this.assertEqual("pancakes", elem.pancakes());
+
+ var elem2 = $('test-visible');
+
+ this.assert(Element.Methods.ByTag[elem2.tagName]);
+ this.assertUndefined(elem2.pancakes);
+ this.assertRespondsTo('waffles', elem2);
+ this.assertEqual("waffles", elem2.waffles());
+
+ this.assertRespondsTo('orangeJuice', elem);
+ this.assertRespondsTo('orangeJuice', elem2);
+ this.assertEqual("orange juice", elem.orangeJuice());
+ this.assertEqual("orange juice", elem2.orangeJuice());
+
+ this.assert(typeof Element.orangeJuice == 'undefined');
+ this.assert(typeof Element.pancakes == 'undefined');
+ this.assert(typeof Element.waffles == 'undefined');
+
+ },
+
+ testScriptFragment: function() {
+ var element = document.createElement('div');
+ // tests an issue with Safari 2.0 crashing when the ScriptFragment
+ // regular expression is using a pipe-based approach for
+ // matching any character
+ ['\r','\n',' '].each(function(character){
+ $(element).update("<script>"+character.times(10000)+"</scr"+"ipt>");
+ this.assertEqual('', element.innerHTML);
+ }, this);
+ $(element).update("<script>var blah='"+'\\'.times(10000)+"'</scr"+"ipt>");
+ this.assertEqual('', element.innerHTML);
+ },
+
+ testPositionedOffset: function() {
+ this.assertEnumEqual([10,10],
+ $('body_absolute').positionedOffset());
+ this.assertEnumEqual([10,10],
+ $('absolute_absolute').positionedOffset());
+ this.assertEnumEqual([10,10],
+ $('absolute_relative').positionedOffset());
+ this.assertEnumEqual([0,10],
+ $('absolute_relative_undefined').positionedOffset());
+ this.assertEnumEqual([10,10],
+ $('absolute_fixed_absolute').positionedOffset());
+
+ var afu = $('absolute_fixed_undefined');
+ this.assertEnumEqual([afu.offsetLeft, afu.offsetTop],
+ afu.positionedOffset());
+
+ var element = new Element('div'), offset = element.positionedOffset();
+ this.assertEnumEqual([0,0], offset);
+ this.assertIdentical(0, offset.top);
+ this.assertIdentical(0, offset.left);
+ },
+
+ testCumulativeOffset: function() {
+ var element = new Element('div'), offset = element.cumulativeOffset();
+ this.assertEnumEqual([0,0], offset);
+ this.assertIdentical(0, offset.top);
+ this.assertIdentical(0, offset.left);
+ },
+
+ testViewportOffset: function() {
+ this.assertEnumEqual([10,10],
+ $('body_absolute').viewportOffset());
+ this.assertEnumEqual([20,20],
+ $('absolute_absolute').viewportOffset());
+ this.assertEnumEqual([20,20],
+ $('absolute_relative').viewportOffset());
+ this.assertEnumEqual([20,30],
+ $('absolute_relative_undefined').viewportOffset());
+ var element = new Element('div'), offset = element.viewportOffset();
+ this.assertEnumEqual([0,0], offset);
+ this.assertIdentical(0, offset.top);
+ this.assertIdentical(0, offset.left);
+ },
+
+ testOffsetParent: function() {
+ this.assertEqual('body_absolute', $('absolute_absolute').getOffsetParent().id);
+ this.assertEqual('body_absolute', $('absolute_relative').getOffsetParent().id);
+ this.assertEqual('absolute_relative', $('inline').getOffsetParent().id);
+ this.assertEqual('absolute_relative', $('absolute_relative_undefined').getOffsetParent().id);
+
+ this.assertEqual(document.body, new Element('div').getOffsetParent());
+ },
+
+ testAbsolutize: function() {
+ $('notInlineAbsoluted', 'inlineAbsoluted').each(function(elt) {
+ if ('_originalLeft' in elt) delete elt._originalLeft;
+ elt.absolutize();
+ this.assertUndefined(elt._originalLeft, 'absolutize() did not detect absolute positioning');
+ }, this);
+ // invoking on "absolute" positioned element should return element
+ var element = $('absolute_fixed_undefined').setStyle({position: 'absolute'});
+ this.assertEqual(element, element.absolutize());
+
+ // test relatively positioned element with no height specified for IE7
+ var element = $('absolute_relative'), dimensions = element.getDimensions();
+ element.absolutize();
+ this.assertIdentical(dimensions.width, element.getDimensions().width);
+ this.assertIdentical(dimensions.height, element.getDimensions().height);
+ },
+
+ testRelativize: function() {
+ // invoking on "relative" positioned element should return element
+ var element = $('absolute_fixed_undefined').setStyle({position: 'relative'});
+ this.assertEqual(element, element.relativize());
+
+ var assertPositionEqual = function(modifier, element) {
+ element = $(element);
+ var offsets = element.cumulativeOffset();
+ Element[modifier](element);
+ this.assertEnumEqual(offsets, element.cumulativeOffset());
+ }.bind(this);
+
+ var testRelativize = assertPositionEqual.curry('relativize');
+ testRelativize('notInlineAbsoluted');
+ testRelativize('inlineAbsoluted');
+ testRelativize('absolute_absolute');
+ },
+
+ testElementToViewportDimensionsDoesNotAffectDocumentProperties: function() {
+ // No properties on the document should be affected when resizing
+ // an absolute positioned(0,0) element to viewport dimensions
+ var vd = document.viewport.getDimensions();
+
+ var before = documentViewportProperties.inspect();
+ $('elementToViewportDimensions').setStyle({ height: vd.height + 'px', width: vd.width + 'px' }).show();
+ var after = documentViewportProperties.inspect();
+ $('elementToViewportDimensions').hide();
+
+ documentViewportProperties.properties.each(function(prop) {
+ this.assertEqual(before[prop], after[prop], prop + ' was affected');
+ }, this);
+ },
+
+ testNodeConstants: function() {
+ this.assert(window.Node, 'window.Node is unavailable');
+
+ var constants = $H({
+ ELEMENT_NODE: 1,
+ ATTRIBUTE_NODE: 2,
+ TEXT_NODE: 3,
+ CDATA_SECTION_NODE: 4,
+ ENTITY_REFERENCE_NODE: 5,
+ ENTITY_NODE: 6,
+ PROCESSING_INSTRUCTION_NODE: 7,
+ COMMENT_NODE: 8,
+ DOCUMENT_NODE: 9,
+ DOCUMENT_TYPE_NODE: 10,
+ DOCUMENT_FRAGMENT_NODE: 11,
+ NOTATION_NODE: 12
+ });
+
+ constants.each(function(pair) {
+ this.assertEqual(Node[pair.key], pair.value);
+ }, this);
+ }
+});
+
+function preservingBrowserDimensions(callback) {
+ var original = document.viewport.getDimensions();
+ window.resizeTo(640, 480);
+ var resized = document.viewport.getDimensions();
+ original.width += 640 - resized.width, original.height += 480 - resized.height;
+
+ try {
+ window.resizeTo(original.width, original.height);
+ callback();
+ } finally {
+ window.resizeTo(original.width, original.height);
+ }
+}
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/element_mixins_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/element_mixins_test.js
new file mode 100644
index 0000000000..239179375c
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/element_mixins_test.js
@@ -0,0 +1,32 @@
+new Test.Unit.Runner({
+ testInput: function() {
+ this.assert($("input").present != null);
+ this.assert(typeof $("input").present == 'function');
+ this.assert($("input").select != null);
+ this.assertRespondsTo('present', Form.Element);
+ this.assertRespondsTo('present', Form.Element.Methods);
+ this.assertRespondsTo('coffee', $('input'));
+ this.assertIdentical(Prototype.K, Form.Element.coffee);
+ this.assertIdentical(Prototype.K, Form.Element.Methods.coffee);
+ },
+
+ testForm: function() {
+ this.assert($("form").reset != null);
+ this.assert($("form").getInputs().length == 2);
+ },
+
+ testEvent: function() {
+ this.assert($("form").observe != null)
+ // Can't really test this one with TestUnit...
+ $('form').observe("submit", function(e) {
+ alert("yeah!");
+ Event.stop(e);
+ });
+ },
+
+ testCollections: function() {
+ this.assert($$("input").all(function(input) {
+ return (input.focus != null);
+ }));
+ }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/enumerable_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/enumerable_test.js
new file mode 100644
index 0000000000..fdc7c019d0
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/enumerable_test.js
@@ -0,0 +1,263 @@
+function prime(value) {
+ for (var i = 2; i < value; i++)
+ if (value % i == 0) return false;
+ return true;
+}
+
+new Test.Unit.Runner({
+ testEachBreak: function() {
+ var result = 0;
+ Fixtures.Basic.each(function(value) {
+ if ((result = value) == 2) throw $break;
+ });
+
+ this.assertEqual(2, result);
+ },
+
+ testEachReturnActsAsContinue: function() {
+ var results = [];
+ Fixtures.Basic.each(function(value) {
+ if (value == 2) return;
+ results.push(value);
+ });
+
+ this.assertEqual('1, 3', results.join(', '));
+ },
+
+ testEachChaining: function() {
+ this.assertEqual(Fixtures.Primes, Fixtures.Primes.each(Prototype.emptyFunction));
+ this.assertEqual(3, Fixtures.Basic.each(Prototype.emptyFunction).length);
+ },
+
+ testEnumContext: function() {
+ var results = [];
+ Fixtures.Basic.each(function(value) {
+ results.push(value * this.i);
+ }, { i: 2 });
+
+ this.assertEqual('2 4 6', results.join(' '));
+
+ this.assert(Fixtures.Basic.all(function(value){
+ return value >= this.min && value <= this.max;
+ }, { min: 1, max: 3 }));
+ this.assert(!Fixtures.Basic.all(function(value){
+ return value >= this.min && value <= this.max;
+ }));
+ this.assert(Fixtures.Basic.any(function(value){
+ return value == this.target_value;
+ }, { target_value: 2 }));
+ },
+
+ testAny: function() {
+ this.assert(!([].any()));
+
+ this.assert([true, true, true].any());
+ this.assert([true, false, false].any());
+ this.assert(![false, false, false].any());
+
+ this.assert(Fixtures.Basic.any(function(value) {
+ return value > 2;
+ }));
+ this.assert(!Fixtures.Basic.any(function(value) {
+ return value > 5;
+ }));
+ },
+
+ testAll: function() {
+ this.assert([].all());
+
+ this.assert([true, true, true].all());
+ this.assert(![true, false, false].all());
+ this.assert(![false, false, false].all());
+
+ this.assert(Fixtures.Basic.all(function(value) {
+ return value > 0;
+ }));
+ this.assert(!Fixtures.Basic.all(function(value) {
+ return value > 1;
+ }));
+ },
+
+ testCollect: function() {
+ this.assertEqual(Fixtures.Nicknames.join(', '),
+ Fixtures.People.collect(function(person) {
+ return person.nickname;
+ }).join(", "));
+
+ this.assertEqual(26, Fixtures.Primes.map().length);
+ },
+
+ testDetect: function() {
+ this.assertEqual('Marcel Molina Jr.',
+ Fixtures.People.detect(function(person) {
+ return person.nickname.match(/no/);
+ }).name);
+ },
+
+ testEachSlice: function() {
+ this.assertEnumEqual([], [].eachSlice(2));
+ this.assertEqual(1, [1].eachSlice(1).length);
+ this.assertEnumEqual([1], [1].eachSlice(1)[0]);
+ this.assertEqual(2, Fixtures.Basic.eachSlice(2).length);
+ this.assertEnumEqual(
+ [3, 2, 1, 11, 7, 5, 19, 17, 13, 31, 29, 23, 43, 41, 37, 59, 53, 47, 71, 67, 61, 83, 79, 73, 97, 89],
+ Fixtures.Primes.eachSlice( 3, function(slice){ return slice.reverse() }).flatten()
+ );
+ this.assertEnumEqual(Fixtures.Basic, Fixtures.Basic.eachSlice(-10));
+ this.assertEnumEqual(Fixtures.Basic, Fixtures.Basic.eachSlice(0));
+ this.assertNotIdentical(Fixtures.Basic, Fixtures.Basic.eachSlice(0));
+ },
+
+ testEachWithIndex: function() {
+ var nicknames = [], indexes = [];
+ Fixtures.People.each(function(person, index) {
+ nicknames.push(person.nickname);
+ indexes.push(index);
+ });
+
+ this.assertEqual(Fixtures.Nicknames.join(', '),
+ nicknames.join(', '));
+ this.assertEqual('0, 1, 2, 3', indexes.join(', '));
+ },
+
+ testFindAll: function() {
+ this.assertEqual(Fixtures.Primes.join(', '),
+ Fixtures.Z.findAll(prime).join(', '));
+ },
+
+ testGrep: function() {
+ this.assertEqual('noradio, htonl',
+ Fixtures.Nicknames.grep(/o/).join(", "));
+
+ this.assertEqual('NORADIO, HTONL',
+ Fixtures.Nicknames.grep(/o/, function(nickname) {
+ return nickname.toUpperCase();
+ }).join(", "))
+
+ this.assertEnumEqual($('grepHeader', 'grepCell'),
+ $('grepTable', 'grepTBody', 'grepRow', 'grepHeader', 'grepCell').grep(new Selector('.cell')));
+ },
+
+ testInclude: function() {
+ this.assert(Fixtures.Nicknames.include('sam-'));
+ this.assert(Fixtures.Nicknames.include('noradio'));
+ this.assert(!Fixtures.Nicknames.include('gmosx'));
+ this.assert(Fixtures.Basic.include(2));
+ this.assert(Fixtures.Basic.include('2'));
+ this.assert(!Fixtures.Basic.include('4'));
+ },
+
+ testInGroupsOf: function() {
+ this.assertEnumEqual([], [].inGroupsOf(3));
+
+ var arr = [1, 2, 3, 4, 5, 6].inGroupsOf(3);
+ this.assertEqual(2, arr.length);
+ this.assertEnumEqual([1, 2, 3], arr[0]);
+ this.assertEnumEqual([4, 5, 6], arr[1]);
+
+ arr = [1, 2, 3, 4, 5, 6].inGroupsOf(4);
+ this.assertEqual(2, arr.length);
+ this.assertEnumEqual([1, 2, 3, 4], arr[0]);
+ this.assertEnumEqual([5, 6, null, null], arr[1]);
+
+ var basic = Fixtures.Basic
+
+ arr = basic.inGroupsOf(4,'x');
+ this.assertEqual(1, arr.length);
+ this.assertEnumEqual([1, 2, 3, 'x'], arr[0]);
+
+ this.assertEnumEqual([1,2,3,'a'], basic.inGroupsOf(2, 'a').flatten());
+
+ arr = basic.inGroupsOf(5, '');
+ this.assertEqual(1, arr.length);
+ this.assertEnumEqual([1, 2, 3, '', ''], arr[0]);
+
+ this.assertEnumEqual([1,2,3,0], basic.inGroupsOf(2, 0).flatten());
+ this.assertEnumEqual([1,2,3,false], basic.inGroupsOf(2, false).flatten());
+ },
+
+ testInject: function() {
+ this.assertEqual(1061,
+ Fixtures.Primes.inject(0, function(sum, value) {
+ return sum + value;
+ }));
+ },
+
+ testInvoke: function() {
+ var result = [[2, 1, 3], [6, 5, 4]].invoke('sort');
+ this.assertEqual(2, result.length);
+ this.assertEqual('1, 2, 3', result[0].join(', '));
+ this.assertEqual('4, 5, 6', result[1].join(', '));
+
+ result = result.invoke('invoke', 'toString', 2);
+ this.assertEqual('1, 10, 11', result[0].join(', '));
+ this.assertEqual('100, 101, 110', result[1].join(', '));
+ },
+
+ testMax: function() {
+ this.assertEqual(100, Fixtures.Z.max());
+ this.assertEqual(97, Fixtures.Primes.max());
+ this.assertEqual(2, [ -9, -8, -7, -6, -4, -3, -2, 0, -1, 2 ].max());
+ this.assertEqual('sam-', Fixtures.Nicknames.max()); // ?s > ?U
+ },
+
+ testMin: function() {
+ this.assertEqual(1, Fixtures.Z.min());
+ this.assertEqual(0, [ 1, 2, 3, 4, 5, 6, 7, 8, 0, 9 ].min());
+ this.assertEqual('Ulysses', Fixtures.Nicknames.min()); // ?U < ?h
+ },
+
+ testPartition: function() {
+ var result = Fixtures.People.partition(function(person) {
+ return person.name.length < 15;
+ }).invoke('pluck', 'nickname');
+
+ this.assertEqual(2, result.length);
+ this.assertEqual('sam-, htonl', result[0].join(', '));
+ this.assertEqual('noradio, Ulysses', result[1].join(', '));
+ },
+
+ testPluck: function() {
+ this.assertEqual(Fixtures.Nicknames.join(', '),
+ Fixtures.People.pluck('nickname').join(', '));
+ },
+
+ testReject: function() {
+ this.assertEqual(0,
+ Fixtures.Nicknames.reject(Prototype.K).length);
+
+ this.assertEqual('sam-, noradio, htonl',
+ Fixtures.Nicknames.reject(function(nickname) {
+ return nickname != nickname.toLowerCase();
+ }).join(', '));
+ },
+
+ testSortBy: function() {
+ this.assertEqual('htonl, noradio, sam-, Ulysses',
+ Fixtures.People.sortBy(function(value) {
+ return value.nickname.toLowerCase();
+ }).pluck('nickname').join(', '));
+ },
+
+ testToArray: function() {
+ var result = Fixtures.People.toArray();
+ this.assert(result != Fixtures.People); // they're different objects...
+ this.assertEqual(Fixtures.Nicknames.join(', '),
+ result.pluck('nickname').join(', ')); // but the values are the same
+ },
+
+ testZip: function() {
+ var result = [1, 2, 3].zip([4, 5, 6], [7, 8, 9]);
+ this.assertEqual('[[1, 4, 7], [2, 5, 8], [3, 6, 9]]', result.inspect());
+
+ result = [1, 2, 3].zip([4, 5, 6], [7, 8, 9], function(array) { return array.reverse() });
+ this.assertEqual('[[7, 4, 1], [8, 5, 2], [9, 6, 3]]', result.inspect());
+ },
+
+ testSize: function() {
+ this.assertEqual(4, Fixtures.People.size());
+ this.assertEqual(4, Fixtures.Nicknames.size());
+ this.assertEqual(26, Fixtures.Primes.size());
+ this.assertEqual(0, [].size());
+ }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/event_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/event_test.js
new file mode 100644
index 0000000000..ae10a77a7f
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/event_test.js
@@ -0,0 +1,286 @@
+var documentLoaded = document.loaded;
+
+new Test.Unit.Runner({
+
+ // test firing an event and observing it on the element it's fired from
+ testCustomEventFiring: function() {
+ var span = $("span"), fired = false, observer = function(event) {
+ this.assertEqual(span, event.element());
+ this.assertEqual(1, event.memo.index);
+ fired = true;
+ }.bind(this);
+
+ span.observe("test:somethingHappened", observer);
+ span.fire("test:somethingHappened", { index: 1 });
+ this.assert(fired);
+
+ fired = false;
+ span.fire("test:somethingElseHappened");
+ this.assert(!fired);
+
+ span.stopObserving("test:somethingHappened", observer);
+ span.fire("test:somethingHappened");
+ this.assert(!fired);
+ },
+
+ // test firing an event and observing it on a containing element
+ testCustomEventBubbling: function() {
+ var span = $("span"), outer = $("outer"), fired = false, observer = function(event) {
+ this.assertEqual(span, event.element());
+ fired = true;
+ }.bind(this);
+
+ outer.observe("test:somethingHappened", observer);
+ span.fire("test:somethingHappened");
+ this.assert(fired);
+
+ fired = false;
+ span.fire("test:somethingElseHappened");
+ this.assert(!fired);
+
+ outer.stopObserving("test:somethingHappened", observer);
+ span.fire("test:somethingHappened");
+ this.assert(!fired);
+ },
+
+ testCustomEventCanceling: function() {
+ var span = $("span"), outer = $("outer"), inner = $("inner");
+ var fired = false, stopped = false;
+
+ function outerObserver(event) {
+ fired = span == event.element();
+ }
+
+ function innerObserver(event) {
+ event.stop();
+ stopped = true;
+ }
+
+ inner.observe("test:somethingHappened", innerObserver);
+ outer.observe("test:somethingHappened", outerObserver);
+ span.fire("test:somethingHappened");
+ this.assert(stopped);
+ this.assert(!fired);
+
+ fired = stopped = false;
+ inner.stopObserving("test:somethingHappened", innerObserver);
+ span.fire("test:somethingHappened");
+ this.assert(!stopped);
+ this.assert(fired);
+
+ outer.stopObserving("test:somethingHappened", outerObserver);
+ },
+
+ testEventObjectIsExtended: function() {
+ var span = $("span"), event, observedEvent, observer = function(e) { observedEvent = e };
+ span.observe("test:somethingHappened", observer);
+ event = span.fire("test:somethingHappened");
+ this.assertEqual(event, observedEvent);
+ this.assertEqual(Event.Methods.stop.methodize(), event.stop);
+ span.stopObserving("test:somethingHappened", observer);
+
+ event = span.fire("test:somethingHappenedButNoOneIsListening");
+ this.assertEqual(Event.Methods.stop.methodize(), event.stop);
+ },
+
+ testEventObserversAreBoundToTheObservedElement: function() {
+ var span = $("span"), target, observer = function() { target = this };
+
+ span.observe("test:somethingHappened", observer);
+ span.fire("test:somethingHappened");
+ span.stopObserving("test:somethingHappened", observer);
+ this.assertEqual(span, target);
+ target = null;
+
+ var outer = $("outer");
+ outer.observe("test:somethingHappened", observer);
+ span.fire("test:somethingHappened");
+ outer.stopObserving("test:somethingHappened", observer);
+ this.assertEqual(outer, target);
+ },
+
+ testMultipleCustomEventObserversWithTheSameHandler: function() {
+ var span = $("span"), count = 0, observer = function() { count++ };
+
+ span.observe("test:somethingHappened", observer);
+ span.observe("test:somethingElseHappened", observer);
+ span.fire("test:somethingHappened");
+ this.assertEqual(1, count);
+ span.fire("test:somethingElseHappened");
+ this.assertEqual(2, count);
+ span.stopObserving("test:somethingHappened", observer);
+ span.stopObserving("test:somethingElseHappened", observer);
+ },
+
+ testStopObservingWithoutArguments: function() {
+ var span = $("span"), count = 0, observer = function() { count++ };
+
+ span.observe("test:somethingHappened", observer);
+ span.observe("test:somethingElseHappened", observer);
+ span.stopObserving();
+ span.fire("test:somethingHappened");
+ this.assertEqual(0, count);
+ span.fire("test:somethingElseHappened");
+ this.assertEqual(0, count);
+
+ this.assertEqual(window, Event.stopObserving(window));
+
+ // test element with no observers
+ this.assertNothingRaised(function() { $(document.body).stopObserving() });
+ },
+
+ testStopObservingWithoutHandlerArgument: function() {
+ var span = $("span"), count = 0, observer = function() { count++ };
+
+ span.observe("test:somethingHappened", observer);
+ span.observe("test:somethingElseHappened", observer);
+ span.stopObserving("test:somethingHappened");
+ span.fire("test:somethingHappened");
+ this.assertEqual(0, count);
+ span.fire("test:somethingElseHappened");
+ this.assertEqual(1, count);
+ span.stopObserving("test:somethingElseHappened");
+ span.fire("test:somethingElseHappened");
+ this.assertEqual(1, count);
+
+ // test element with no observers
+ this.assertNothingRaised(function() { $(document.body).stopObserving("test:somethingHappened") });
+ },
+
+ testStopObservingRemovesHandlerFromCache: function() {
+ var span = $("span"), observer = function() { }, eventID;
+
+ span.observe("test:somethingHappened", observer);
+ eventID = span._prototypeEventID;
+
+ this.assert(Event.cache[eventID]);
+ this.assert(Object.isArray(Event.cache[eventID]["test:somethingHappened"]));
+ this.assertEqual(1, Event.cache[eventID]["test:somethingHappened"].length);
+
+ span.stopObserving("test:somethingHappened", observer);
+ this.assert(Event.cache[eventID]);
+ this.assert(Object.isArray(Event.cache[eventID]["test:somethingHappened"]));
+ this.assertEqual(0, Event.cache[eventID]["test:somethingHappened"].length);
+ },
+
+ testObserveAndStopObservingAreChainable: function() {
+ var span = $("span"), observer = function() { };
+
+ this.assertEqual(span, span.observe("test:somethingHappened", observer));
+ this.assertEqual(span, span.stopObserving("test:somethingHappened", observer));
+
+ span.observe("test:somethingHappened", observer);
+ this.assertEqual(span, span.stopObserving("test:somethingHappened"));
+
+ span.observe("test:somethingHappened", observer);
+ this.assertEqual(span, span.stopObserving());
+ this.assertEqual(span, span.stopObserving()); // assert it again, after there are no observers
+
+ span.observe("test:somethingHappened", observer);
+ this.assertEqual(span, span.observe("test:somethingHappened", observer)); // try to reuse the same observer
+ span.stopObserving();
+ },
+
+ testObserveInsideHandlers: function() {
+ var fired = false, observer = function(event) {
+ fired = true;
+ };
+
+ document.observe("test:somethingHappened", function() {
+ document.observe("test:somethingHappened", observer);
+ });
+
+ document.fire("test:somethingHappened");
+ this.assert(!fired);
+
+ document.fire("test:somethingHappened");
+ this.assert(fired);
+ document.stopObserving("test:somethingHappened");
+ },
+
+ testStopObservingInsideHandlers: function() {
+ var fired = false, observer = function(event) {
+ fired = true;
+ };
+
+ document.observe("test:somethingHappened", observer);
+ document.observe("test:somethingHappened", function() {
+ document.stopObserving("test:somethingHappened", observer);
+ });
+
+ document.fire("test:somethingHappened");
+ this.assert(fired);
+
+ fired = false;
+ document.fire("test:somethingHappened");
+ document.stopObserving("test:somethingHappened");
+ this.assert(!fired);
+ },
+
+ testDocumentLoaded: function() {
+ this.assert(!documentLoaded);
+ this.assert(document.loaded);
+ },
+
+ testDocumentContentLoadedEventFiresBeforeWindowLoad: function() {
+ this.assert(eventResults.contentLoaded, "contentLoaded");
+ this.assert(eventResults.contentLoaded.endOfDocument, "contentLoaded.endOfDocument");
+ this.assert(!eventResults.contentLoaded.windowLoad, "!contentLoaded.windowLoad");
+ this.assert(eventResults.windowLoad, "windowLoad");
+ this.assert(eventResults.windowLoad.endOfDocument, "windowLoad.endOfDocument");
+ this.assert(eventResults.windowLoad.contentLoaded, "windowLoad.contentLoaded");
+ },
+
+ testEventStopped: function() {
+ var span = $("span"), event;
+
+ span.observe("test:somethingHappened", function() { });
+ event = span.fire("test:somethingHappened");
+ this.assert(!event.stopped, "event.stopped should be false with an empty observer");
+ span.stopObserving("test:somethingHappened");
+
+ span.observe("test:somethingHappened", function(e) { e.stop() });
+ event = span.fire("test:somethingHappened");
+ this.assert(event.stopped, "event.stopped should be true for an observer that calls stop");
+ span.stopObserving("test:somethingHappened");
+ },
+
+ testEventFindElement: function() {
+ var span = $("span"), event;
+ event = span.fire("test:somethingHappened");
+ this.assertElementMatches(event.findElement(), 'span#span');
+ this.assertElementMatches(event.findElement('span'), 'span#span');
+ this.assertElementMatches(event.findElement('p'), 'p#inner');
+ this.assertEqual(null, event.findElement('div.does_not_exist'));
+ this.assertElementMatches(event.findElement('.does_not_exist, span'), 'span#span');
+ },
+
+ testEventIDDuplication: function() {
+ $('container').down().observe("test:somethingHappened", Prototype.emptyFunction);
+ $('container').innerHTML += $('container').innerHTML;
+ this.assertUndefined($('container').down(1)._prototypeEventID);
+ },
+
+ testHandlerCallsPreserveOrder: function() {
+ var span = $("span"), order = [ ];
+ span.observe("test:somethingHappened", function(e) { order.push('first') });
+ span.observe("test:somethingHappened", function(e) { order.push('second') });
+ span.fire("test:somethingHappened");
+ this.assertEnumEqual(['first', 'second'], order);
+ span.stopObserving("test:somethingHappened");
+ }
+});
+
+document.observe("dom:loaded", function(event) {
+ eventResults.contentLoaded = {
+ endOfDocument: eventResults.endOfDocument,
+ windowLoad: eventResults.windowLoad
+ };
+});
+
+Event.observe(window, "load", function(event) {
+ eventResults.windowLoad = {
+ endOfDocument: eventResults.endOfDocument,
+ contentLoaded: eventResults.contentLoaded
+ };
+});
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/ajax.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/ajax.html
new file mode 100644
index 0000000000..4af5e267ac
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/ajax.html
@@ -0,0 +1,2 @@
+<div id="content"></div>
+<div id="content2" style="color:red"></div>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/ajax.js b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/ajax.js
new file mode 100644
index 0000000000..8487943f73
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/ajax.js
@@ -0,0 +1,42 @@
+var Fixtures = {
+ js: {
+ responseBody: '$("content").update("<H2>Hello world!</H2>");',
+ 'Content-Type': ' text/javascript '
+ },
+
+ html: {
+ responseBody: "Pack my box with <em>five dozen</em> liquor jugs! " +
+ "Oh, how <strong>quickly</strong> daft jumping zebras vex..."
+ },
+
+ xml: {
+ responseBody: '<?xml version="1.0" encoding="UTF-8" ?><name attr="foo">bar</name>',
+ 'Content-Type': 'application/xml'
+ },
+
+ json: {
+ responseBody: '{\n\r"test": 123}',
+ 'Content-Type': 'application/json'
+ },
+
+ jsonWithoutContentType: {
+ responseBody: '{"test": 123}'
+ },
+
+ invalidJson: {
+ responseBody: '{});window.attacked = true;({}',
+ 'Content-Type': 'application/json'
+ },
+
+ headerJson: {
+ 'X-JSON': '{"test": "hello #éà"}'
+ }
+};
+
+var responderCounter = 0;
+
+// lowercase comparison because of MSIE which presents HTML tags in uppercase
+var sentence = ("Pack my box with <em>five dozen</em> liquor jugs! " +
+"Oh, how <strong>quickly</strong> daft jumping zebras vex...").toLowerCase();
+
+var message = 'You must be running your tests from rake to test this feature.'; \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/array.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/array.html
new file mode 100644
index 0000000000..8f091878c8
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/array.html
@@ -0,0 +1 @@
+<div id="test_node">22<span id="span_1"></span><span id="span_2"></span></div>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/base.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/base.html
new file mode 100644
index 0000000000..5a08fbd554
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/base.html
@@ -0,0 +1,6 @@
+<div id="test"></div>
+<ul id="list">
+ <li></li>
+ <li></li>
+ <li></li>
+</ul> \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/base.js b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/base.js
new file mode 100644
index 0000000000..8e9e00bd54
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/base.js
@@ -0,0 +1,106 @@
+var Person = function(name){
+ this.name = name;
+};
+
+Person.prototype.toJSON = function() {
+ return '-' + this.name;
+};
+
+var arg1 = 1;
+var arg2 = 2;
+var arg3 = 3;
+function TestObj() { };
+TestObj.prototype.assertingEventHandler =
+ function(event, assertEvent, assert1, assert2, assert3, a1, a2, a3) {
+ assertEvent(event);
+ assert1(a1);
+ assert2(a2);
+ assert3(a3);
+ };
+
+var globalBindTest = null;
+
+
+// base class
+var Animal = Class.create({
+ initialize: function(name) {
+ this.name = name;
+ },
+ name: "",
+ eat: function() {
+ return this.say("Yum!");
+ },
+ say: function(message) {
+ return this.name + ": " + message;
+ }
+});
+
+// subclass that augments a method
+var Cat = Class.create(Animal, {
+ eat: function($super, food) {
+ if (food instanceof Mouse) return $super();
+ else return this.say("Yuk! I only eat mice.");
+ }
+});
+
+// empty subclass
+var Mouse = Class.create(Animal, {});
+
+//mixins
+var Sellable = {
+ getValue: function(pricePerKilo) {
+ return this.weight * pricePerKilo;
+ },
+
+ inspect: function() {
+ return '#<Sellable: #{weight}kg>'.interpolate(this);
+ }
+};
+
+var Reproduceable = {
+ reproduce: function(partner) {
+ if (partner.constructor != this.constructor || partner.sex == this.sex)
+ return null;
+ var weight = this.weight / 10, sex = Math.random(1).round() ? 'male' : 'female';
+ return new this.constructor('baby', weight, sex);
+ }
+};
+
+// base class with mixin
+var Plant = Class.create(Sellable, {
+ initialize: function(name, weight) {
+ this.name = name;
+ this.weight = weight;
+ },
+
+ inspect: function() {
+ return '#<Plant: #{name}>'.interpolate(this);
+ }
+});
+
+// subclass with mixin
+var Dog = Class.create(Animal, Reproduceable, {
+ initialize: function($super, name, weight, sex) {
+ this.weight = weight;
+ this.sex = sex;
+ $super(name);
+ }
+});
+
+// subclass with mixins
+var Ox = Class.create(Animal, Sellable, Reproduceable, {
+ initialize: function($super, name, weight, sex) {
+ this.weight = weight;
+ this.sex = sex;
+ $super(name);
+ },
+
+ eat: function(food) {
+ if (food instanceof Plant)
+ this.weight += food.weight;
+ },
+
+ inspect: function() {
+ return '#<Ox: #{name}>'.interpolate(this);
+ }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/content.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/content.html
new file mode 100644
index 0000000000..ee3701d3c3
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/content.html
@@ -0,0 +1 @@
+Pack my box with <em>five dozen</em> liquor jugs! Oh, how <strong>quickly</strong> daft jumping zebras vex... \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/data.json b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/data.json
new file mode 100644
index 0000000000..85391eb939
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/data.json
@@ -0,0 +1 @@
+{test: 123} \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.css b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.css
new file mode 100644
index 0000000000..453a569c26
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.css
@@ -0,0 +1,85 @@
+#style_test_1 { cursor: pointer; font-size:12px;}
+div.style-test { margin-left: 1px }
+
+#style_test_dimensions_container {
+ position: absolute;
+ top: 0;
+ left: 500px;
+ width: 20px;
+ height: 30px;
+ margin: 10px;
+ padding: 10px;
+ border: 3px solid red;
+}
+
+#not_floating_style { float: none }
+#floating_style { float: left }
+#op2 { opacity:0.5;filter:alpha(opacity=50)progid:DXImageTransform.Microsoft.Blur(strength=10);}
+
+#scroll_test_1 {
+ margin: 10px;
+ padding: 10px;
+ position: relative;
+}
+
+#scroll_test_2 {
+ position: absolute;
+ left: 10px;
+ top: 10px;
+}
+
+#dimensions-visible,
+#dimensions-display-none,
+#dimensions-visible-pos-rel,
+#dimensions-display-none-pos-rel,
+#dimensions-visible-pos-abs,
+#dimensions-display-none-pos-abs {
+ font-size: 10px;
+ height: 10em;
+ width: 20em;
+}
+
+#dimensions-visible-pos-abs,
+#dimensions-display-none-pos-abs {
+ position: absolute;
+ top: 15px;
+ left: 15px;
+}
+
+#dimensions-visible-pos-rel,
+#dimensions-display-none-pos-rel {
+ position: relative;
+ top: 15px;
+ left: 15px;
+}
+
+#dimensions-display-none, #dimensions-display-none-pos-rel, #dimensions-display-none-pos-abs {
+ display: none;
+}
+
+#dimensions-table, #dimensions-tbody, #dimensions-tr, #dimensions-td {
+ font-size: 10px;
+ margin: 0;
+ padding: 0;
+ border: 0;
+ border-spacing: 0;
+ height: 10em;
+ width: 20em;
+}
+
+
+#notInlineAbsoluted { position: absolute; }
+
+#elementToViewportDimensions {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 10px;
+ width: 10px;
+ background: #000;
+}
+
+/* for scroll test on really big screens */
+body {
+ height: 40000px;
+} \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.html
new file mode 100644
index 0000000000..1273098e6d
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.html
@@ -0,0 +1,285 @@
+<div id="scroll_test_1">
+ <p id="scroll_test_2">Scroll test</p>
+</div>
+
+<div id="test-visible">visible</div>
+<div id="test-hidden" style="display:none;">hidden</div>
+<div id="test-toggle-visible">visible</div>
+<div id="test-toggle-hidden" style="display:none;">hidden</div>
+<div id="test-hide-visible">visible</div>
+<div id="test-hide-hidden" style="display:none;">hidden</div>
+<div id="test-show-visible">visible</div>
+<div id="test-show-hidden" style="display:none;">hidden</div>
+<div id="removable-container"><div id="removable"></div></div>
+
+<div>
+ <table>
+ <tbody id="table">
+ <tr>
+ <td>Data</td>
+ </tr>
+ <tr>
+ <td id="a_cell">First Row</td>
+ </tr>
+ <tr id="second_row">
+ <td>Second Row</td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+
+<div id="table-container-to-replace">
+ <table>
+ <tbody id="table-to-replace">
+ <tr>
+ <td>Data</td>
+ </tr>
+ <tr>
+ <td id="a_cell-to-replace">First Row</td>
+ </tr>
+ <tr id="second_row-to-replace">
+ <td>Second Row</td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+
+<p class="test">Test paragraph outside of container</p>
+
+<div id="container">
+ <p class="test" id="intended">Test paragraph 1 inside of container</p>
+ <p class="test">Test paragraph 2 inside of container</p>
+ <p class="test">Test paragraph 3 inside of container</p>
+ <p class="test">Test paragraph 4 inside of container</p>
+</div>
+
+<div id="testdiv">to be updated</div>
+<div id="testdiv-replace-container-1"><div id="testdiv-replace-1"></div></div>
+<div id="testdiv-replace-container-2"><div id="testdiv-replace-2"></div></div>
+<div id="testdiv-replace-container-3"><div id="testdiv-replace-3"></div></div>
+<div id="testdiv-replace-container-4"><div id="testdiv-replace-4"></div></div>
+<div id="testdiv-replace-container-5"><div id="testdiv-replace-5"></div></div>
+<div id="testdiv-replace-container-element"><div id="testdiv-replace-element"></div></div>
+<div id="testdiv-replace-container-toelement"><div id="testdiv-replace-toelement"></div></div>
+<div id="testdiv-replace-container-tohtml"><div id="testdiv-replace-tohtml"></div></div>
+<div id="testtable-replace-container"><table id="testtable-replace"></table></div>
+<table id="testrow-replace-container"><tr id="testrow-replace"></tr></table>
+<select id="testoption-replace-container"><option id="testoption-replace"></option><option>stays</option></select>
+<div id="testform-replace-container"><p>some text</p><form id="testform-replace"><input id="testinput-replace" type="text" /></form><p>some text</p></div>
+
+<div id="element_with_visible_overflow" style="overflow:visible">V</div>
+<div id="element_with_hidden_overflow" style="overflow:hidden">H</div>
+<div id="element_with_scroll_overflow" style="overflow:scroll">S</div>
+
+<div id="element_extend_test"> </div>
+
+<div id="element_reextend_test"><div id="discard_1"></div></div>
+
+<div id="test_whitespace"> <span> </span>
+
+
+<div><div></div> </div><span> </span>
+</div>
+
+
+<div id="nav_tests_isolator">
+ <div id="nav_test_first_sibling"></div>
+ <div></div>
+ <p id="nav_test_p" class="test"></p>
+ <span id="nav_test_prev_sibling"></span>
+
+ <ul id="navigation_test" style="display: none">
+ <!-- comment node to screw things up -->
+ <li class="first"><em>A</em></li>
+ <li><em class="dim">B</em></li>
+ <li id="navigation_test_c">
+ <em>C</em>
+ <ul>
+ <li><em class="dim">E</em></li>
+ <li id="navigation_test_f"><em>F</em></li>
+ </ul>
+ </li>
+ <li class="last"><em>D</em></li>
+ </ul>
+
+ <div id="navigation_test_next_sibling">
+ <!-- -->
+ </div>
+
+ <p></p>
+</div>
+
+<div id="class_names">
+ <p class="A"></p>
+ <ul class="A B" id="class_names_ul">
+ <li class="C"></li>
+ <li class="A C"></li>
+ <li class="1"></li>
+ </ul>
+ <div class="B C D"></div>
+ <div id="unextended"></div>
+</div>
+
+<div id="style_test_1" style="display:none;"></div>
+<div id="style_test_2" class="style-test" style="font-size:11px;"></div>
+
+<div id="style_test_3">blah</div>
+<span id="style_test_4">blah</span>
+<span id="style_test_5">blah</span>
+
+<div id="style_test_dimensions_container">
+ <div id="style_test_dimensions" style="background:#ddd;padding:1px;margin:1px;border:1px solid #00f"><div style="height:5px;background:#eee;width:5px;padding:2px;margin:2px;border:2px solid #0f0"> </div>
+ </div>
+</div>
+
+<div id="test_csstext_1">test_csstext_1</div>
+<div id="test_csstext_2">test_csstext_2</div>
+<div id="test_csstext_3" style="border: 1px solid red">test_csstext_3</div>
+<div id="test_csstext_4" style="font-size: 20px">test_csstext_4</div>
+<div id="test_csstext_5">test_csstext_5</div>
+
+<div id="custom_attributes">
+ <div foo="1" bar="2"></div>
+ <div foo="2"></div>
+</div>
+
+<div id="cloned_element_attributes_issue" foo="original"></div>
+<a id="attributes_with_issues_1" href="test.html" accesskey="L" tabindex="50" title="a link" onclick="alert('hello world');"></a>
+<a id="attributes_with_issues_2" href="" accesskey="" tabindex="" title=""></a>
+<a id="attributes_with_issues_3"></a>
+<form id="attributes_with_issues_form" method="post" action="blah" class="blah-class">
+ <input type="hidden" id="id" />
+ <input type="hidden" name="id" />
+ <input type="checkbox" id="action" />
+ <input type="checkbox" name="action" />
+ <input type="text" id="method" />
+ <input type="hidden" name="class" />
+ <input type="checkbox" id="attributes_with_issues_checked" name="a" checked="checked"/>
+ <input type="checkbox" id="attributes_with_issues_disabled" name="b" checked="checked" disabled="disabled"/>
+ <input type="text" id="attributes_with_issues_readonly" name="c" readonly="readonly" value="blech"/>
+ <input type="text" id="attributes_with_issues_regular" name="d" value="0"/>
+ <input type="date" id="attributes_with_issues_type" value="blech" />
+ <select id="attributes_with_issues_multiple" name="e" multiple="multiple">
+ <option>blech</option>
+ <option>blah</option>
+ </select>
+</form>
+
+<!-- writeAttributes -->
+<p id="write_attribute_para"></p>
+<a id="write_attribute_link" href="test.html"></a>
+<form action="/dev/null" id="write_attribute_form" method="get" accept-charset="utf-8">
+ <label id="write_attribute_label"></label>
+ <input type="checkbox" name="write_attribute_checkbox" value="" id="write_attribute_checkbox">
+ <input type="checkbox" checked="checked" name="write_attribute_checked_checkbox" value="" id="write_attribute_checked_checkbox">
+ <input type="text" name="write_attribute_input" value="" id="write_attribute_input">
+ <select id="write_attribute_select">
+ <option>Cat</option>
+ <option>Dog</option>
+ </select>
+</form>
+
+<table id="write_attribute_table" cellpadding="6" cellspacing="4">
+ <tr><td id="write_attribute_td">A</td><td>B</td></tr>
+ <tr><td>C</td></tr>
+ <tr><td>D</td><td>E</td><td>F</td></tr>
+</table>
+
+<div id="dom_attribute_precedence">
+ <form action="blech" method="post">
+ <input type="submit" id="update" />
+ </form>
+</div>
+
+<div id="not_floating_none">NFN</div>
+<div id="not_floating_inline" style="float:none">NFI</div>
+<div id="not_floating_style">NFS</div>
+
+<div id="floating_inline" style="float:left">FI</div>
+<div id="floating_style">FS</div>
+<!-- Test Element opacity functions -->
+<img id="op1" alt="op2" src="fixtures/logo.gif" style="opacity:0.5;filter:alpha(opacity=50)" />
+<img id="op2" alt="op2" src="fixtures/logo.gif"/>
+<img id="op3" alt="op3" src="fixtures/logo.gif"/>
+<img id="op4-ie" alt="op3" src="fixtures/logo.gif" style="filter:alpha(opacity=30)" />
+<div id="dimensions-visible"></div>
+<div id="dimensions-display-none"></div>
+<div id="dimensions-visible-pos-rel"></div>
+<div id="dimensions-display-none-pos-rel"></div>
+<div id="dimensions-visible-pos-abs"></div>
+<div id="dimensions-display-none-pos-abs"></div>
+<table border="0" cellspacing="0" cellpadding="0" id="dimensions-table">
+ <tbody id="dimensions-tbody">
+ <tr id="dimensions-tr">
+ <td id="dimensions-td">Data</td>
+ </tr>
+ </tbody>
+</table>
+
+<div id="dimensions-nester" style="width: 500px;">
+ <div id="dimensions-nestee" style="display: none">This is a nested DIV. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
+</div>
+
+
+<p id="test-empty"></p>
+<p id="test-empty-but-contains-whitespace">
+
+
+</p>
+<p id="test-full">content</p>
+<div id="ancestor">
+ <div id="child">
+ <div id="grand-child">
+ <div id="great-grand-child"></div>
+ </div></div><!-- intentional formatting; don't change this line -->
+ <div id="sibling"><div id="grand-sibling"></div></div>
+</div>
+<div id="not-in-the-family"></div>
+
+<div id="insertions-container"><div id="insertions-main"><p>some content.</p></div></div>
+<div id="insertions-node-container"><div id="insertions-node-main"><p>some content.</p></div></div>
+<div id="element-insertions-container"><div id="element-insertions-main"><p>some content.</p></div></div>
+<div id="element-insertions-multiple-container"><div id="element-insertions-multiple-main"><p>some content.</p></div></div>
+<table id="table_for_insertions"></table>
+<table id="table_for_row_insertions"><tr id="row_1"></tr></table>
+<form method="post" action="blah">
+ <select id="select_for_update" name="select_for_update">
+ <option>option 1</option>
+ <option>option 2</option>
+ </select>
+ <select id="select_for_insert_bottom" name="select_for_insert_bottom">
+ <option>option 1</option>
+ <option>option 2</option>
+ </select>
+ <select id="select_for_insert_top" name="select_for_insert_top">
+ <option>option 1</option>
+ <option>option 2</option>
+ </select>
+</form>
+<div id="wrap-container"><p id="wrap"></p></div>
+
+<!-- Positioning methods bench -->
+<div id="body_absolute" style="position: absolute; top: 10px; left: 10px">
+ <div id="absolute_absolute" style="position: absolute; top: 10px; left:10px"> </div>
+ <div id="absolute_relative" style="position: relative; top: 10px; left:10px">
+ <div style="height:10px;font-size:2px">test<span id="inline">test</span></div>
+ <div id="absolute_relative_undefined">XYZ</div>
+ </div>
+ <div id="absolute_fixed" style="position: fixed; top: 10px; left: 10px">
+ <span id="absolute_fixed_absolute" style="position: absolute; top: 10px; left: 10px">foo</span>
+ <span id="absolute_fixed_undefined" style="display:block">bar</span>
+ </div></div>
+<div id="notInlineAbsoluted"></div>
+<div id="inlineAbsoluted" style="position: absolute"></div>
+
+<div id="unextended"></div>
+<div id="identification">
+ <div id="predefined_id"></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div id="anonymous_element_3"></div>
+</div>
+
+<div id='elementToViewportDimensions' style='display: none'></div>
+<div id="auto_dimensions" style="height:auto"></div> \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.js b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.js
new file mode 100644
index 0000000000..18f62f354c
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/dom.js
@@ -0,0 +1,17 @@
+var testVar = 'to be updated', testVar2 = '', documentViewportProperties;
+
+Element.addMethods({
+ hashBrowns: function(element) { return 'hash browns'; }
+});
+
+Element.addMethods("LI", {
+ pancakes: function(element) { return "pancakes"; }
+});
+
+Element.addMethods("DIV", {
+ waffles: function(element) { return "waffles"; }
+});
+
+Element.addMethods($w("li div"), {
+ orangeJuice: function(element) { return "orange juice"; }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/element_mixins.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/element_mixins.html
new file mode 100644
index 0000000000..583d0e5f30
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/element_mixins.html
@@ -0,0 +1,4 @@
+<form id="form">
+ <input type="text" id="input" value="4" />
+ <input type="submit" />
+</form> \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/element_mixins.js b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/element_mixins.js
new file mode 100644
index 0000000000..22b1c3fd14
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/element_mixins.js
@@ -0,0 +1,2 @@
+Form.Element.Methods.coffee = Prototype.K;
+Element.addMethods(); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/empty.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/empty.html
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/empty.html
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/empty.js b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/empty.js
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/empty.js
@@ -0,0 +1 @@
+
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/enumerable.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/enumerable.html
new file mode 100644
index 0000000000..5e7e8f3b3c
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/enumerable.html
@@ -0,0 +1,8 @@
+<table id="grepTable">
+<tbody id="grepTBody">
+ <tr id="grepRow">
+ <th id="grepHeader" class="cell"></th>
+ <td id="grepCell" class="cell"></td>
+ </tr>
+</tbody>
+</table>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/enumerable.js b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/enumerable.js
new file mode 100644
index 0000000000..5fae7662dd
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/enumerable.js
@@ -0,0 +1,23 @@
+var Fixtures = {
+ People: [
+ {name: 'Sam Stephenson', nickname: 'sam-'},
+ {name: 'Marcel Molina Jr.', nickname: 'noradio'},
+ {name: 'Scott Barron', nickname: 'htonl'},
+ {name: 'Nicholas Seckar', nickname: 'Ulysses'}
+ ],
+
+ Nicknames: $w('sam- noradio htonl Ulysses'),
+
+ Basic: [1, 2, 3],
+
+ Primes: [
+ 1, 2, 3, 5, 7, 11, 13, 17, 19, 23,
+ 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
+ 71, 73, 79, 83, 89, 97
+ ],
+
+ Z: []
+};
+
+for (var i = 1; i <= 100; i++)
+ Fixtures.Z.push(i);
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/event.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/event.html
new file mode 100644
index 0000000000..baa88a7d10
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/event.html
@@ -0,0 +1,4 @@
+<div id="outer" style="display: none">
+ <p id="inner">One two three <span id="span">four</span></p>
+</div>
+<div id="container"><div></div></div>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/form.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/form.html
new file mode 100644
index 0000000000..dc7f171bf2
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/form.html
@@ -0,0 +1,112 @@
+<form id="form" method="get" action="fixtures/empty.js">
+ <input type="text" name="val1" id="input_enabled" value="4" />
+ <div>This is not a form element</div>
+ <input type="text" name="val2" id="input_disabled" disabled="disabled" value="5" />
+ <input type="submit" name="first_submit" value="Commit it!" />
+ <input type="submit" name="second_submit" value="Delete it!" />
+ <input type="text" name="action" value="blah" />
+</form>
+
+<form id="bigform" method="get" action="fixtures/empty.js">
+ <div id="inputs">
+ <input type="text" name="dummy" id="dummy_disabled" disabled="disabled"/>
+ <input type="submit" name="commit" id="submit" />
+ <input type="button" name="clicky" value="click me" />
+ <input type="reset" name="revert" />
+ <input type="text" name="greeting" id="focus_text" value="Hello" />
+ </div>
+
+ <div id="buttons">
+ <button type="button" id="button_type_button" name="button">Click Me</button>
+ </div>div>
+
+ <!-- some edge cases in serialization -->
+ <div id="value_checks">
+ <input name="twin" type="text" value="" />
+ <input name="twin" type="text" value="siamese" />
+ <!-- Rails checkbox hack with hidden input: -->
+ <input name="checky" type="checkbox" id="checkbox_hack" value="1" />
+ <input name="checky" type="hidden" value="0" />
+ </div>
+
+ <!-- all variations of SELECT controls -->
+ <div id="selects_wrapper">
+ <select name="vu">
+ <option value="1" selected="selected">One</option>
+ <option value="2">Two</option>
+ <option value="3">Three</option>
+ </select>
+ <select id="multiSel1" name="vm[]" multiple="multiple">
+ <option id="multiSel1_opt1" value="1" selected="selected">One</option>
+ <option id="multiSel1_opt2" value="2">Two</option>
+ <option id="multiSel1_opt3" value="3" selected="selected">Three</option>
+ </select>
+ <select name="nvu">
+ <option selected="selected">One</option>
+ <option value="2">Two</option>
+ <option value="3">Three</option>
+ </select>
+
+ <fieldset id="selects_fieldset">
+ <select name="nvm[]" multiple="multiple">
+ <option selected="selected">One</option>
+ <option>Two</option>
+ <option selected="selected">Three</option>
+ </select>
+ <select name="evu">
+ <option value="" selected="selected">One</option>
+ <option value="2">Two</option>
+ <option value="3">Three</option>
+ </select>
+ <select name="evm[]" multiple="multiple">
+ <option value="" selected="selected">One</option>
+ <option>Two</option>
+ <option selected="selected">Three</option>
+ </select>
+ </fieldset>
+ </div>
+
+ <div id="various">
+ <select name="tf_selectOne"><option selected="selected"></option><option>1</option></select>
+ <textarea name="tf_textarea"></textarea>
+ <input type="checkbox" name="tf_checkbox" value="on" />
+ <select name="tf_selectMany" multiple="multiple"></select>
+ <input type="text" name="tf_text" />
+ <div>This is not a form element</div>
+ <input type="radio" name="tf_radio" value="on" />
+ <input type="hidden" name="tf_hidden" />
+ <input type="password" name="tf_password" />
+ </div>
+</form>
+
+<form id="form_focus_hidden" style="display: none">
+ <input type="text" />
+</form>
+
+<form id="form_with_file_input">
+ <input type="file" name="file_name" value="foo" />
+</form>
+
+<!-- tabindexed forms -->
+<div id="tabindex">
+ <form id="ffe">
+ <p><input type="text" disabled="disabled" id="ffe_disabled" /></p>
+ <input type="hidden" id="ffe_hidden" />
+ <input type="checkbox" id="ffe_checkbox" />
+ </form>
+
+ <form id="ffe_ti">
+ <p><input type="text" disabled="disabled" id="ffe_ti_disabled" /></p>
+ <input type="hidden" id="ffe_ti_hidden" />
+ <input type="checkbox" id="ffe_ti_checkbox" />
+ <input type="submit" id="ffe_ti_submit" tabindex="1" />
+ </form>
+
+ <form id="ffe_ti2">
+ <p><input type="text" disabled="disabled" id="ffe_ti2_disabled" /></p>
+ <input type="hidden" id="ffe_ti2_hidden" />
+ <input type="checkbox" id="ffe_ti2_checkbox" tabindex="0" />
+ <input type="submit" id="ffe_ti2_submit" tabindex="1" />
+ </form>
+
+</div>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/hash.js b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/hash.js
new file mode 100644
index 0000000000..be5ccfa7d9
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/hash.js
@@ -0,0 +1,25 @@
+var Fixtures = {
+ one: { a: 'A#' },
+
+ many: {
+ a: 'A',
+ b: 'B',
+ c: 'C',
+ d: 'D#'
+ },
+
+ functions: {
+ quad: function(n) { return n*n },
+ plus: function(n) { return n+n }
+ },
+
+ multiple: { color: $w('r g b') },
+ multiple_nil: { color: ['r', null, 'g', undefined, 0] },
+ multiple_all_nil: { color: [null, undefined] },
+ multiple_empty: { color: [] },
+ multiple_special: { 'stuff[]': $w('$ a ;') },
+
+ value_undefined: { a:"b", c:undefined },
+ value_null: { a:"b", c:null },
+ value_zero: { a:"b", c:0 }
+};
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/hello.js b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/hello.js
new file mode 100644
index 0000000000..63d81117bf
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/hello.js
@@ -0,0 +1 @@
+$("content").update("<H2>Hello world!</H2>");
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/logo.gif b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/logo.gif
new file mode 100644
index 0000000000..71574abd76
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/logo.gif
Binary files differ
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/position.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/position.html
new file mode 100644
index 0000000000..5fd7bdf4b6
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/position.html
@@ -0,0 +1,9 @@
+<div id="ensure_scrollbars" style="width:10000px; height:10000px; position:absolute" > </div>
+
+<div id="body_absolute" style="position: absolute; top: 10px; left: 10px">
+ <div id="absolute_absolute" style="position: absolute; top: 10px; left:10px"> </div>
+ <div id="absolute_relative" style="position: relative; top: 10px; left:10px">
+ <div style="height:10px;font-size:2px">test<span id="inline">test</span></div>
+ <div id="absolute_relative_undefined"> </div>
+ </div>
+</div>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/selector.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/selector.html
new file mode 100644
index 0000000000..d745c8fd55
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/selector.html
@@ -0,0 +1,69 @@
+<div id="fixtures" style="display: none">
+ <h1 class="title">Some title <span>here</span></h1>
+ <p id="p" class="first summary">
+ <strong id="strong">This</strong> is a short blurb
+ <a id="link_1" class="first internal" rel="external nofollow" href="#">with a <em id="em2">link</em></a> or
+ <a id="link_2" class="internal highlight" href="#"><em id="em">two</em></a>.
+ Or <cite id="with_title" title="hello world!">a citation</cite>.
+ </p>
+ <ul id="list">
+ <li id="item_1" class="first"><a id="link_3" href="#" class="external"><span id="span">Another link</span></a></li>
+ <li id="item_2">Some text</li>
+ <li id="item_3" xml:lang="es-us" class="">Otra cosa</li>
+ </ul>
+
+ <!-- this form has a field with the name 'id',
+ therefore its ID property won't be 'troubleForm': -->
+ <form id="troubleForm">
+ <input type="hidden" name="id" id="hidden" />
+ <input type="text" name="disabled_text_field" id="disabled_text_field" disabled="disabled" />
+ <input type="text" name="enabled_text_field" id="enabled_text_field" />
+ <input type="checkbox" name="checkboxes" id="checked_box" checked="checked" value="Checked" />
+ <input type="checkbox" name="checkboxes" id="unchecked_box" value="Unchecked"/>
+ <input type="radio" name="radiobuttons" id="checked_radio" checked="checked" value="Checked" />
+ <input type="radio" name="radiobuttons" id="unchecked_radio" value="Unchecked" />
+ </form>
+
+ <form id="troubleForm2">
+ <input type="checkbox" name="brackets[5][]" id="chk_1" checked="checked" value="1" />
+ <input type="checkbox" name="brackets[5][]" id="chk_2" value="2" />
+ </form>
+
+ <div id="level1">
+ <span id="level2_1">
+ <span id="level3_1"></span>
+ <!-- This comment should be ignored by the adjacent selector -->
+ <span id="level3_2"></span>
+ </span>
+ <span id="level2_2">
+ <em id="level_only_child">
+ </em>
+ </span>
+ <div id="level2_3"></div>
+ </div> <!-- #level1 -->
+
+ <div id="dupContainer">
+ <span id="dupL1" class="span_foo span_bar">
+ <span id="dupL2">
+ <span id="dupL3">
+ <span id="dupL4">
+ <span id="dupL5"></span>
+ </span>
+ </span>
+ </span>
+ </span>
+ </div> <!-- #dupContainer -->
+
+ <div id="grandfather"> grandfather
+ <div id="father" class="brothers men"> father
+ <div id="son"> son </div>
+ </div>
+ <div id="uncle" class="brothers men"> uncle </div>
+ </div>
+
+ <form id="commaParent" title="commas,are,good">
+ <input type="hidden" id="commaChild" name="foo" value="#commaOne,#commaTwo" />
+ <input type="hidden" id="commaTwo" name="foo2" value="oops" />
+ </form>
+ <div id="counted_container"><div class="is_counted"></div></div>
+</div>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/string.js b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/string.js
new file mode 100644
index 0000000000..e4483a5b61
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/string.js
@@ -0,0 +1,8 @@
+var attackTarget;
+var evalScriptsCounter = 0,
+ largeTextEscaped = '&lt;span&gt;test&lt;/span&gt;',
+ largeTextUnescaped = '<span>test</span>';
+(2048).times(function(){
+ largeTextEscaped += ' ABC';
+ largeTextUnescaped += ' ABC';
+});
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/unittest.html b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/unittest.html
new file mode 100644
index 0000000000..15d303aa3d
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/fixtures/unittest.html
@@ -0,0 +1,18 @@
+<div id="testlog_2"> </div>
+
+<!-- Test elements follow -->
+<div id="test_1" class="a bbbbbbbbbbbb cccccccccc dddd"> </div>
+
+<div id="test_2"> <span> </span>
+
+
+
+<div><div></div> </div><span> </span>
+</div>
+
+<ul id="tlist"><li id="tlist_1">x1</li><li id="tlist_2">x2</li></ul>
+<ul id="tlist2"><li class="a" id="tlist2_1">x1</li><li id="tlist2_2">x2</li></ul>
+
+<div id="testmoveby" style="background-color:#333;width:100px;">XXXX</div>
+
+<div id="testcss1">testcss1<span id="testcss1_span" style="display:none;">blah</span></div><div id="testcss2">testcss1</div>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/form_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/form_test.js
new file mode 100644
index 0000000000..4cda87d81b
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/form_test.js
@@ -0,0 +1,384 @@
+// sweet sweet additional assertions
+Object.extend(Test.Unit.Testcase.prototype, {
+ assertEnabled: function() {
+ for (var i = 0, element; element = arguments[i]; i++) {
+ this.assert(!$(element).disabled, Test.Unit.inspect(element) + ' was disabled');
+ }
+ },
+ assertDisabled: function() {
+ for (var i = 0, element; element = arguments[i]; i++) {
+ this.assert($(element).disabled, Test.Unit.inspect(element) + ' was enabled');
+ }
+ }
+});
+
+new Test.Unit.Runner({
+
+ // Make sure to set defaults in the test forms, as some browsers override this
+ // with previously entered values on page reload
+ setup: function(){
+ $$('form').each(function(f){ f.reset() });
+ // hidden value does not reset (for some reason)
+ $('bigform')['tf_hidden'].value = '';
+ },
+
+ testDollarF: function(){
+ this.assertEqual("4", $F("input_enabled"));
+ },
+
+ testFormElementEventObserver: function(){
+ var callbackCounter = 0;
+ var observer = new Form.Element.EventObserver('input_enabled', function(){
+ callbackCounter++;
+ });
+
+ this.assertEqual(0, callbackCounter);
+ $('input_enabled').value = 'boo!';
+ observer.onElementEvent(); // can't test the event directly, simulating
+ this.assertEqual(1, callbackCounter);
+ },
+
+ testFormElementObserver: function(){
+ var timedCounter = 0;
+ // First part: regular field
+ var observer = new Form.Element.Observer('input_enabled', 0.5, function() {
+ ++timedCounter;
+ });
+
+ // Test it's unchanged yet
+ this.assertEqual(0, timedCounter);
+ // Test it doesn't change on first check
+ this.wait(550, function() {
+ this.assertEqual(0, timedCounter);
+ // Change, test it doesn't immediately change
+ $('input_enabled').value = 'yowza!';
+ this.assertEqual(0, timedCounter);
+ // Test it changes on next check, but not again on the next
+ this.wait(550, function() {
+ this.assertEqual(1, timedCounter);
+ this.wait(550, function() {
+ this.assertEqual(1, timedCounter);
+ observer.stop();
+ });
+ });
+ });
+
+ // Second part: multiple-select
+ [1, 2, 3].each(function(index) {
+ $('multiSel1_opt' + index).selected = (1 == index);
+ });
+ timedCounter = 0;
+ observer = new Form.Element.Observer('multiSel1', 0.5, function() {
+ ++timedCounter;
+ });
+
+ // Test it's unchanged yet
+ this.assertEqual(0, timedCounter);
+ // Test it doesn't change on first check
+ this.wait(550, function() {
+ this.assertEqual(0, timedCounter);
+ // Change, test it doesn't immediately change
+ // NOTE: it is important that the 3rd be re-selected, for the
+ // serialize form to obtain the expected value :-)
+ $('multiSel1_opt3').selected = true;
+ this.assertEqual(0, timedCounter);
+ // Test it changes on next check, but not again on the next
+ this.wait(550, function() {
+ this.assertEqual(1, timedCounter);
+ this.wait(550, function() {
+ this.assertEqual(1, timedCounter);
+ observer.stop();
+ });
+ });
+ });
+ },
+
+ testFormObserver: function(){
+ var timedCounter = 0;
+ // should work the same way was Form.Element.Observer
+ var observer = new Form.Observer('form', 0.5, function(form, value) {
+ ++timedCounter;
+ });
+
+ // Test it's unchanged yet
+ this.assertEqual(0, timedCounter);
+ // Test it doesn't change on first check
+ this.wait(550, function() {
+ this.assertEqual(0, timedCounter);
+ // Change, test it doesn't immediately change
+ $('input_enabled').value = 'yowza!';
+ this.assertEqual(0, timedCounter);
+ // Test it changes on next check, but not again on the next
+ this.wait(550, function() {
+ this.assertEqual(1, timedCounter);
+ this.wait(550, function() {
+ this.assertEqual(1, timedCounter);
+ observer.stop();
+ });
+ });
+ });
+ },
+
+ testFormEnabling: function(){
+ var form = $('bigform')
+ var input1 = $('dummy_disabled');
+ var input2 = $('focus_text');
+
+ this.assertDisabled(input1);
+ this.assertEnabled(input2);
+
+ form.disable();
+ this.assertDisabled(input1, input2);
+ form.enable();
+ this.assertEnabled(input1, input2);
+ input1.disable();
+ this.assertDisabled(input1);
+
+ // non-form elements:
+ var fieldset = $('selects_fieldset');
+ var fields = fieldset.immediateDescendants();
+ fields.each(function(select) { this.assertEnabled(select) }, this);
+
+ Form.disable(fieldset)
+ fields.each(function(select) { this.assertDisabled(select) }, this);
+
+ Form.enable(fieldset)
+ fields.each(function(select) { this.assertEnabled(select) }, this);
+ },
+
+ testFormElementEnabling: function(){
+ var field = $('input_disabled');
+ field.enable();
+ this.assertEnabled(field);
+ field.disable();
+ this.assertDisabled(field);
+
+ var field = $('input_enabled');
+ this.assertEnabled(field);
+ field.disable();
+ this.assertDisabled(field);
+ field.enable();
+ this.assertEnabled(field);
+ },
+
+ // due to the lack of a DOM hasFocus() API method,
+ // we're simulating things here a little bit
+ testFormActivating: function(){
+ // Firefox, IE, and Safari 2+
+ function getSelection(element){
+ try {
+ if (typeof element.selectionStart == 'number') {
+ return element.value.substring(element.selectionStart, element.selectionEnd);
+ } else if (document.selection && document.selection.createRange) {
+ return document.selection.createRange().text;
+ }
+ }
+ catch(e){ return null }
+ }
+
+ // Form.focusFirstElement shouldn't focus disabled elements
+ var element = Form.findFirstElement('bigform');
+ this.assertEqual('submit', element.id);
+
+ // Test IE doesn't select text on buttons
+ Form.focusFirstElement('bigform');
+ if (document.selection) this.assertEqual('', getSelection(element));
+
+ // Form.Element.activate shouldn't select text on buttons
+ element = $('focus_text');
+ this.assertEqual('', getSelection(element));
+
+ // Form.Element.activate should select text on text input elements
+ element.activate();
+ this.assertEqual('Hello', getSelection(element));
+
+ // Form.Element.activate shouldn't raise an exception when the form or field is hidden
+ this.assertNothingRaised(function() {
+ $('form_focus_hidden').focusFirstElement();
+ });
+ },
+
+ testFormGetElements: function() {
+ var elements = Form.getElements('various'),
+ names = $w('tf_selectOne tf_textarea tf_checkbox tf_selectMany tf_text tf_radio tf_hidden tf_password');
+ this.assertEnumEqual(names, elements.pluck('name'))
+ },
+
+ testFormGetInputs: function() {
+ var form = $('form');
+ [form.getInputs(), Form.getInputs(form)].each(function(inputs){
+ this.assertEqual(inputs.length, 5);
+ this.assert(inputs instanceof Array);
+ this.assert(inputs.all(function(input) { return (input.tagName == "INPUT"); }));
+ }, this);
+ },
+
+ testFormFindFirstElement: function() {
+ this.assertEqual($('ffe_checkbox'), $('ffe').findFirstElement());
+ this.assertEqual($('ffe_ti_submit'), $('ffe_ti').findFirstElement());
+ this.assertEqual($('ffe_ti2_checkbox'), $('ffe_ti2').findFirstElement());
+ },
+
+ testFormSerialize: function() {
+ // form is initially empty
+ var form = $('bigform');
+ var expected = { tf_selectOne:'', tf_textarea:'', tf_text:'', tf_hidden:'', tf_password:'' };
+ this.assertHashEqual(expected, Form.serialize('various', true));
+
+ // set up some stuff
+ form['tf_selectOne'].selectedIndex = 1;
+ form['tf_textarea'].value = "boo hoo!";
+ form['tf_text'].value = "123öäü";
+ form['tf_hidden'].value = "moo%hoo&test";
+ form['tf_password'].value = 'sekrit code';
+ form['tf_checkbox'].checked = true;
+ form['tf_radio'].checked = true;
+ var expected = { tf_selectOne:1, tf_textarea:"boo hoo!", tf_text:"123öäü",
+ tf_hidden:"moo%hoo&test", tf_password:'sekrit code', tf_checkbox:'on', tf_radio:'on' }
+
+ // return params
+ this.assertHashEqual(expected, Form.serialize('various', true));
+ // return string
+ this.assertEnumEqual(Object.toQueryString(expected).split('&').sort(),
+ Form.serialize('various').split('&').sort());
+ this.assertEqual('string', typeof $('form').serialize({ hash:false }));
+
+ // Checks that disabled element is not included in serialized form.
+ $('input_enabled').enable();
+ this.assertHashEqual({ val1:4, action:'blah', first_submit:'Commit it!' },
+ $('form').serialize(true));
+
+ // should not eat empty values for duplicate names
+ $('checkbox_hack').checked = false;
+ var data = Form.serialize('value_checks', true);
+ this.assertEnumEqual(['', 'siamese'], data['twin']);
+ this.assertEqual('0', data['checky']);
+
+ $('checkbox_hack').checked = true;
+ this.assertEnumEqual($w('1 0'), Form.serialize('value_checks', true)['checky']);
+
+ // all kinds of SELECT controls
+ var params = Form.serialize('selects_fieldset', true);
+ var expected = { 'nvm[]':['One', 'Three'], evu:'', 'evm[]':['', 'Three'] };
+ this.assertHashEqual(expected, params);
+ params = Form.serialize('selects_wrapper', true);
+ this.assertHashEqual(Object.extend(expected, { vu:1, 'vm[]':[1, 3], nvu:'One' }), params);
+
+ // explicit submit button
+ this.assertHashEqual({ val1:4, action:'blah', second_submit:'Delete it!' },
+ $('form').serialize({ submit: 'second_submit' }));
+ this.assertHashEqual({ val1:4, action:'blah' },
+ $('form').serialize({ submit: false }));
+ this.assertHashEqual({ val1:4, action:'blah' },
+ $('form').serialize({ submit: 'inexistent' }));
+
+ // file input should not be serialized
+ this.assertEqual('', $('form_with_file_input').serialize());
+ },
+
+ testFormMethodsOnExtendedElements: function() {
+ var form = $('form');
+ this.assertEqual(Form.serialize('form'), form.serialize());
+ this.assertEqual(Form.Element.serialize('input_enabled'), $('input_enabled').serialize());
+ this.assertNotEqual(form.serialize, $('input_enabled').serialize);
+
+ Element.addMethods('INPUT', { anInputMethod: function(input) { return 'input' } });
+ Element.addMethods('SELECT', { aSelectMethod: function(select) { return 'select' } });
+
+ form = $('bigform');
+ var input = form['tf_text'], select = form['tf_selectOne'];
+ input._extendedByPrototype = select._extendedByPrototype = false;
+
+ this.assert($(input).anInputMethod);
+ this.assert(!input.aSelectMethod);
+ this.assertEqual('input', input.anInputMethod());
+
+ this.assert($(select).aSelectMethod);
+ this.assert(!select.anInputMethod);
+ this.assertEqual('select', select.aSelectMethod());
+ },
+
+ testFormRequest: function() {
+ request = $("form").request();
+ this.assert($("form").hasAttribute("method"));
+ this.assert(request.url.include("fixtures/empty.js?val1=4"));
+ this.assertEqual("get", request.method);
+
+ request = $("form").request({ method: "put", parameters: {val2: "hello"} });
+ var url = request.url;
+
+ this.assert(url.startsWith("fixtures/empty.js"));
+ this.assert(url.endsWith("_method=put") || url.endsWith("_method=put&_="));
+ this.assertEqual(4, request.options.parameters['val1']);
+ this.assertEqual('hello', request.options.parameters['val2']);
+ this.assertEqual("post", request.method);
+ this.assertEqual("put", request.parameters['_method']);
+
+ // with empty action attribute
+ request = $("ffe").request({ method: 'post' });
+ this.assert(request.url.include("unit/tmp/form_test.html"),
+ 'wrong default action for form element with empty action attribute');
+ },
+
+ testFormElementMethodsChaining: function(){
+ var methods = $w('clear activate disable enable'),
+ formElements = $('form').getElements();
+ methods.each(function(method){
+ formElements.each(function(element){
+ var returned = element[method]();
+ this.assertIdentical(element, returned);
+ }, this);
+ }, this);
+ },
+
+ testGetValue: function() {
+ this.assertEqual('Click Me', Form.Element.getValue('button_type_button')); // Button element
+ this.assertEqual(null, Form.Element.getValue('someBorkedId')); // Unknown
+ this.assertEqual(null, Form.Element.getValue('form')); // Unsupported
+ this.assertEqual(null, Form.Element.getValue('form')); // Unsupported
+ },
+
+ testSetValue: function(){
+ // unkown element
+ this.assertEqual(null, Form.Element.setValue('someBorkedId', 'blah')); // Unknown
+
+ // test button element
+ var button = $('button_type_button');
+ button.setValue('I Changed');
+ this.assertEqual('I Changed', button.getValue());
+
+ // text input
+ var input = $('input_enabled'), oldValue = input.getValue();
+ this.assertEqual(input, input.setValue('foo'), 'setValue chaining is broken');
+ this.assertEqual('foo', input.getValue(), 'value improperly set');
+ input.setValue(oldValue);
+ this.assertEqual(oldValue, input.getValue(), 'value improperly restored to original');
+
+ // checkbox
+ input = $('checkbox_hack');
+ input.setValue(false);
+ this.assertEqual(null, input.getValue(), 'checkbox should be unchecked');
+ input.setValue(true);
+ this.assertEqual("1", input.getValue(), 'checkbox should be checked');
+
+ // selectbox
+ input = $('bigform')['vu'];
+ input.setValue('3');
+ this.assertEqual('3', input.getValue(), 'single select option improperly set');
+ input.setValue('1');
+ this.assertEqual('1', input.getValue());
+
+ // multiple select
+ input = $('bigform')['vm[]'];
+ input.setValue(['2', '3']);
+ this.assertEnumEqual(['2', '3'], input.getValue(),
+ 'multiple select options improperly set');
+ input.setValue(['1', '3']);
+ this.assertEnumEqual(['1', '3'], input.getValue());
+
+ // test chainability
+ var input = $('input_enabled');
+ this.assert(Object.isElement(button.setValue('New Value')));
+ this.assert(Object.isElement(input.setValue('New Value')));
+ }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/hash_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/hash_test.js
new file mode 100644
index 0000000000..cc3d083135
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/hash_test.js
@@ -0,0 +1,178 @@
+new Test.Unit.Runner({
+ testSet: function() {
+ var h = $H({a: 'A'})
+
+ this.assertEqual('B', h.set('b', 'B'));
+ this.assertHashEqual({a: 'A', b: 'B'}, h);
+
+ this.assertUndefined(h.set('c'));
+ this.assertHashEqual({a: 'A', b: 'B', c: undefined}, h);
+ },
+
+ testGet: function() {
+ var h = $H({a: 'A'});
+ this.assertEqual('A', h.get('a'));
+ this.assertUndefined(h.a);
+ this.assertUndefined($H({}).get('a'));
+
+ this.assertUndefined($H({}).get('toString'));
+ this.assertUndefined($H({}).get('constructor'));
+ },
+
+ testUnset: function() {
+ var hash = $H(Fixtures.many);
+ this.assertEqual('B', hash.unset('b'));
+ this.assertHashEqual({a:'A', c: 'C', d:'D#'}, hash);
+ this.assertUndefined(hash.unset('z'));
+ this.assertHashEqual({a:'A', c: 'C', d:'D#'}, hash);
+ // not equivalent to Hash#remove
+ this.assertEqual('A', hash.unset('a', 'c'));
+ this.assertHashEqual({c: 'C', d:'D#'}, hash);
+ },
+
+ testToObject: function() {
+ var hash = $H(Fixtures.many), object = hash.toObject();
+ this.assertInstanceOf(Object, object);
+ this.assertHashEqual(Fixtures.many, object);
+ this.assertNotIdentical(Fixtures.many, object);
+ hash.set('foo', 'bar');
+ this.assertHashNotEqual(object, hash.toObject());
+ },
+
+ testConstruct: function() {
+ var object = Object.clone(Fixtures.one);
+ var h = new Hash(object), h2 = $H(object);
+ this.assertInstanceOf(Hash, h);
+ this.assertInstanceOf(Hash, h2);
+
+ this.assertHashEqual({}, new Hash());
+ this.assertHashEqual(object, h);
+ this.assertHashEqual(object, h2);
+
+ h.set('foo', 'bar');
+ this.assertHashNotEqual(object, h);
+
+ var clone = $H(h);
+ this.assertInstanceOf(Hash, clone);
+ this.assertHashEqual(h, clone);
+ h.set('foo', 'foo');
+ this.assertHashNotEqual(h, clone);
+ this.assertIdentical($H, Hash.from);
+ },
+
+ testKeys: function() {
+ this.assertEnumEqual([], $H({}).keys());
+ this.assertEnumEqual(['a'], $H(Fixtures.one).keys());
+ this.assertEnumEqual($w('a b c d'), $H(Fixtures.many).keys().sort());
+ this.assertEnumEqual($w('plus quad'), $H(Fixtures.functions).keys().sort());
+ },
+
+ testValues: function() {
+ this.assertEnumEqual([], $H({}).values());
+ this.assertEnumEqual(['A#'], $H(Fixtures.one).values());
+ this.assertEnumEqual($w('A B C D#'), $H(Fixtures.many).values().sort());
+ this.assertEnumEqual($w('function function'),
+ $H(Fixtures.functions).values().map(function(i){ return typeof i }));
+ this.assertEqual(9, $H(Fixtures.functions).get('quad')(3));
+ this.assertEqual(6, $H(Fixtures.functions).get('plus')(3));
+ },
+
+ testIndex: function() {
+ this.assertUndefined($H().index('foo'));
+
+ this.assert('a', $H(Fixtures.one).index('A#'));
+ this.assert('a', $H(Fixtures.many).index('A'));
+ this.assertUndefined($H(Fixtures.many).index('Z'))
+
+ var hash = $H({a:1,b:'2',c:1});
+ this.assert(['a','c'].include(hash.index(1)));
+ this.assertUndefined(hash.index('1'));
+ },
+
+ testMerge: function() {
+ var h = $H(Fixtures.many);
+ this.assertNotIdentical(h, h.merge());
+ this.assertNotIdentical(h, h.merge({}));
+ this.assertInstanceOf(Hash, h.merge());
+ this.assertInstanceOf(Hash, h.merge({}));
+ this.assertHashEqual(h, h.merge());
+ this.assertHashEqual(h, h.merge({}));
+ this.assertHashEqual(h, h.merge($H()));
+ this.assertHashEqual({a:'A', b:'B', c:'C', d:'D#', aaa:'AAA' }, h.merge({aaa: 'AAA'}));
+ this.assertHashEqual({a:'A#', b:'B', c:'C', d:'D#' }, h.merge(Fixtures.one));
+ },
+
+ testUpdate: function() {
+ var h = $H(Fixtures.many);
+ this.assertIdentical(h, h.update());
+ this.assertIdentical(h, h.update({}));
+ this.assertHashEqual(h, h.update());
+ this.assertHashEqual(h, h.update({}));
+ this.assertHashEqual(h, h.update($H()));
+ this.assertHashEqual({a:'A', b:'B', c:'C', d:'D#', aaa:'AAA' }, h.update({aaa: 'AAA'}));
+ this.assertHashEqual({a:'A#', b:'B', c:'C', d:'D#', aaa:'AAA' }, h.update(Fixtures.one));
+ },
+
+ testToQueryString: function() {
+ this.assertEqual('', $H({}).toQueryString());
+ this.assertEqual('a%23=A', $H({'a#': 'A'}).toQueryString());
+ this.assertEqual('a=A%23', $H(Fixtures.one).toQueryString());
+ this.assertEqual('a=A&b=B&c=C&d=D%23', $H(Fixtures.many).toQueryString());
+ this.assertEqual("a=b&c", $H(Fixtures.value_undefined).toQueryString());
+ this.assertEqual("a=b&c", $H("a=b&c".toQueryParams()).toQueryString());
+ this.assertEqual("a=b&c=", $H(Fixtures.value_null).toQueryString());
+ this.assertEqual("a=b&c=0", $H(Fixtures.value_zero).toQueryString());
+ this.assertEqual("color=r&color=g&color=b", $H(Fixtures.multiple).toQueryString());
+ this.assertEqual("color=r&color=&color=g&color&color=0", $H(Fixtures.multiple_nil).toQueryString());
+ this.assertEqual("color=&color", $H(Fixtures.multiple_all_nil).toQueryString());
+ this.assertEqual("", $H(Fixtures.multiple_empty).toQueryString());
+ this.assertEqual("", $H({foo: {}, bar: {}}).toQueryString());
+ this.assertEqual("stuff%5B%5D=%24&stuff%5B%5D=a&stuff%5B%5D=%3B", $H(Fixtures.multiple_special).toQueryString());
+ this.assertHashEqual(Fixtures.multiple_special, $H(Fixtures.multiple_special).toQueryString().toQueryParams());
+ this.assertIdentical(Object.toQueryString, Hash.toQueryString);
+ },
+
+ testInspect: function() {
+ this.assertEqual('#<Hash:{}>', $H({}).inspect());
+ this.assertEqual("#<Hash:{'a': 'A#'}>", $H(Fixtures.one).inspect());
+ this.assertEqual("#<Hash:{'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D#'}>", $H(Fixtures.many).inspect());
+ },
+
+ testClone: function() {
+ var h = $H(Fixtures.many);
+ this.assertHashEqual(h, h.clone());
+ this.assertInstanceOf(Hash, h.clone());
+ this.assertNotIdentical(h, h.clone());
+ },
+
+ testToJSON: function() {
+ this.assertEqual('{\"b\": [false, true], \"c\": {\"a\": \"hello!\"}}',
+ $H({'b': [undefined, false, true, undefined], c: {a: 'hello!'}}).toJSON());
+ },
+
+ testAbilityToContainAnyKey: function() {
+ var h = $H({ _each: 'E', map: 'M', keys: 'K', pluck: 'P', unset: 'U' });
+ this.assertEnumEqual($w('_each keys map pluck unset'), h.keys().sort());
+ this.assertEqual('U', h.unset('unset'));
+ this.assertHashEqual({ _each: 'E', map: 'M', keys: 'K', pluck: 'P' }, h);
+ },
+
+ testHashToTemplateReplacements: function() {
+ var template = new Template("#{a} #{b}"), hash = $H({ a: "hello", b: "world" });
+ this.assertEqual("hello world", template.evaluate(hash.toObject()));
+ this.assertEqual("hello world", template.evaluate(hash));
+ this.assertEqual("hello", "#{a}".interpolate(hash));
+ },
+
+ testPreventIterationOverShadowedProperties: function() {
+ // redundant now that object is systematically cloned.
+ var FooMaker = function(value) {
+ this.key = value;
+ };
+ FooMaker.prototype.key = 'foo';
+ var foo = new FooMaker('bar');
+ this.assertEqual("key=bar", new Hash(foo).toQueryString());
+ this.assertEqual("key=bar", new Hash(new Hash(foo)).toQueryString());
+ }
+
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/number_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/number_test.js
new file mode 100644
index 0000000000..4e09529b2c
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/number_test.js
@@ -0,0 +1,44 @@
+new Test.Unit.Runner({
+
+ testNumberMathMethods: function() {
+ this.assertEqual(1, (0.9).round());
+ this.assertEqual(-2, (-1.9).floor());
+ this.assertEqual(-1, (-1.9).ceil());
+
+ $w('abs floor round ceil').each(function(method) {
+ this.assertEqual(Math[method](Math.PI), Math.PI[method]());
+ }, this);
+ },
+
+ testNumberToColorPart: function() {
+ this.assertEqual('00', (0).toColorPart());
+ this.assertEqual('0a', (10).toColorPart());
+ this.assertEqual('ff', (255).toColorPart());
+ },
+
+ testNumberToPaddedString: function() {
+ this.assertEqual('00', (0).toPaddedString(2, 16));
+ this.assertEqual('0a', (10).toPaddedString(2, 16));
+ this.assertEqual('ff', (255).toPaddedString(2, 16));
+ this.assertEqual('000', (0).toPaddedString(3));
+ this.assertEqual('010', (10).toPaddedString(3));
+ this.assertEqual('100', (100).toPaddedString(3));
+ this.assertEqual('1000', (1000).toPaddedString(3));
+ },
+
+ testNumberToJSON: function() {
+ this.assertEqual('null', Number.NaN.toJSON());
+ this.assertEqual('0', (0).toJSON());
+ this.assertEqual('-293', (-293).toJSON());
+ },
+
+ testNumberTimes: function() {
+ var results = [];
+ (5).times(function(i) { results.push(i) });
+ this.assertEnumEqual($R(0, 4), results);
+
+ results = [];
+ (5).times(function(i) { results.push(i * this.i) }, { i: 2 });
+ this.assertEnumEqual([0, 2, 4, 6, 8], results);
+ }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/position_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/position_test.js
new file mode 100644
index 0000000000..5cea791b1f
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/position_test.js
@@ -0,0 +1,44 @@
+var testVar = 'to be updated';
+
+new Test.Unit.Runner({
+
+ setup: function() {
+ scrollTo(0,0);
+ Position.prepare();
+ Position.includeScrollOffsets = false;
+ },
+
+ teardown: function() {
+ scrollTo(0,0);
+ Position.prepare();
+ Position.includeScrollOffsets = false;
+ },
+
+ testPrepare: function() {
+ Position.prepare();
+ this.assertEqual(0, Position.deltaX);
+ this.assertEqual(0, Position.deltaY);
+ scrollTo(20,30);
+ Position.prepare();
+ this.assertEqual(20, Position.deltaX);
+ this.assertEqual(30, Position.deltaY);
+ },
+
+ testWithin: function() {
+ [true, false].each(function(withScrollOffsets) {
+ Position.includeScrollOffsets = withScrollOffsets;
+ this.assert(!Position.within($('body_absolute'), 9, 9), 'outside left/top');
+ this.assert(Position.within($('body_absolute'), 10, 10), 'left/top corner');
+ this.assert(Position.within($('body_absolute'), 10, 19), 'left/bottom corner');
+ this.assert(!Position.within($('body_absolute'), 10, 20), 'outside bottom');
+ }, this);
+
+ scrollTo(20,30);
+ Position.prepare();
+ Position.includeScrollOffsets = true;
+ this.assert(!Position.within($('body_absolute'), 9, 9), 'outside left/top');
+ this.assert(Position.within($('body_absolute'), 10, 10), 'left/top corner');
+ this.assert(Position.within($('body_absolute'), 10, 19), 'left/bottom corner');
+ this.assert(!Position.within($('body_absolute'), 10, 20), 'outside bottom');
+ }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/range_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/range_test.js
new file mode 100644
index 0000000000..bcf5acb0b5
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/range_test.js
@@ -0,0 +1,58 @@
+new Test.Unit.Runner({
+
+ testInclude: function() {
+ this.assert(!$R(0, 0, true).include(0));
+ this.assert($R(0, 0, false).include(0));
+
+ this.assert($R(0, 5, true).include(0));
+ this.assert($R(0, 5, true).include(4));
+ this.assert(!$R(0, 5, true).include(5));
+
+ this.assert($R(0, 5, false).include(0));
+ this.assert($R(0, 5, false).include(5));
+ this.assert(!$R(0, 5, false).include(6));
+ },
+
+ testEach: function() {
+ var results = [];
+ $R(0, 0, true).each(function(value) {
+ results.push(value);
+ });
+
+ this.assertEnumEqual([], results);
+
+ results = [];
+ $R(0, 3, false).each(function(value) {
+ results.push(value);
+ });
+
+ this.assertEnumEqual([0, 1, 2, 3], results);
+ },
+
+ testAny: function() {
+ this.assert(!$R(1, 1, true).any());
+ this.assert($R(0, 3, false).any(function(value) {
+ return value == 3;
+ }));
+ },
+
+ testAll: function() {
+ this.assert($R(1, 1, true).all());
+ this.assert($R(0, 3, false).all(function(value) {
+ return value <= 3;
+ }));
+ },
+
+ testToArray: function() {
+ this.assertEnumEqual([], $R(0, 0, true).toArray());
+ this.assertEnumEqual([0], $R(0, 0, false).toArray());
+ this.assertEnumEqual([0], $R(0, 1, true).toArray());
+ this.assertEnumEqual([0, 1], $R(0, 1, false).toArray());
+ this.assertEnumEqual([-3, -2, -1, 0, 1, 2], $R(-3, 3, true).toArray());
+ this.assertEnumEqual([-3, -2, -1, 0, 1, 2, 3], $R(-3, 3, false).toArray());
+ },
+
+ testDefaultsToNotExclusive: function() {
+ this.assertEnumEqual($R(-3,3), $R(-3,3,false));
+ }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/selector_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/selector_test.js
new file mode 100644
index 0000000000..72506fc17d
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/selector_test.js
@@ -0,0 +1,377 @@
+var $RunBenchmarks = false;
+
+new Test.Unit.Runner({
+
+ testSelectorWithTagName: function() {
+ this.assertEnumEqual($A(document.getElementsByTagName('li')), $$('li'));
+ this.assertEnumEqual([$('strong')], $$('strong'));
+ this.assertEnumEqual([], $$('nonexistent'));
+
+ var allNodes = $A(document.getElementsByTagName('*')).select( function(node) {
+ return node.tagName !== '!';
+ });
+ this.assertEnumEqual(allNodes, $$('*'));
+ },
+
+ testSelectorWithId: function() {
+ this.assertEnumEqual([$('fixtures')], $$('#fixtures'));
+ this.assertEnumEqual([], $$('#nonexistent'));
+ this.assertEnumEqual([$('troubleForm')], $$('#troubleForm'));
+ },
+
+ testSelectorWithClassName: function() {
+ this.assertEnumEqual($('p', 'link_1', 'item_1'), $$('.first'));
+ this.assertEnumEqual([], $$('.second'));
+ },
+
+ testSelectorWithTagNameAndId: function() {
+ this.assertEnumEqual([$('strong')], $$('strong#strong'));
+ this.assertEnumEqual([], $$('p#strong'));
+ },
+
+ testSelectorWithTagNameAndClassName: function() {
+ this.assertEnumEqual($('link_1', 'link_2'), $$('a.internal'));
+ this.assertEnumEqual([$('link_2')], $$('a.internal.highlight'));
+ this.assertEnumEqual([$('link_2')], $$('a.highlight.internal'));
+ this.assertEnumEqual([], $$('a.highlight.internal.nonexistent'));
+ },
+
+ testSelectorWithIdAndClassName: function() {
+ this.assertEnumEqual([$('link_2')], $$('#link_2.internal'));
+ this.assertEnumEqual([$('link_2')], $$('.internal#link_2'));
+ this.assertEnumEqual([$('link_2')], $$('#link_2.internal.highlight'));
+ this.assertEnumEqual([], $$('#link_2.internal.nonexistent'));
+ },
+
+ testSelectorWithTagNameAndIdAndClassName: function() {
+ this.assertEnumEqual([$('link_2')], $$('a#link_2.internal'));
+ this.assertEnumEqual([$('link_2')], $$('a.internal#link_2'));
+ this.assertEnumEqual([$('item_1')], $$('li#item_1.first'));
+ this.assertEnumEqual([], $$('li#item_1.nonexistent'));
+ this.assertEnumEqual([], $$('li#item_1.first.nonexistent'));
+ },
+
+ test$$MatchesAncestryWithTokensSeparatedByWhitespace: function() {
+ this.assertEnumEqual($('em2', 'em', 'span'), $$('#fixtures a *'));
+ this.assertEnumEqual([$('p')], $$('div#fixtures p'));
+ },
+
+ test$$CombinesResultsWhenMultipleExpressionsArePassed: function() {
+ this.assertEnumEqual($('link_1', 'link_2', 'item_1', 'item_2', 'item_3'), $$('#p a', ' ul#list li '));
+ },
+
+ testSelectorWithTagNameAndAttributeExistence: function() {
+ this.assertEnumEqual($$('#fixtures h1'), $$('h1[class]'), 'h1[class]');
+ this.assertEnumEqual($$('#fixtures h1'), $$('h1[CLASS]'), 'h1[CLASS]');
+ this.assertEnumEqual([$('item_3')], $$('li#item_3[class]'), 'li#item_3[class]');
+ },
+
+ testSelectorWithTagNameAndSpecificAttributeValue: function() {
+ this.assertEnumEqual($('link_1', 'link_2', 'link_3'), $$('a[href="#"]'));
+ this.assertEnumEqual($('link_1', 'link_2', 'link_3'), $$('a[href=#]'));
+ },
+
+ testSelectorWithTagNameAndWhitespaceTokenizedAttributeValue: function() {
+ this.assertEnumEqual($('link_1', 'link_2'), $$('a[class~="internal"]'), "a[class~=\"internal\"]");
+ this.assertEnumEqual($('link_1', 'link_2'), $$('a[class~=internal]'), "a[class~=internal]");
+ },
+
+ testSelectorWithAttributeAndNoTagName: function() {
+ this.assertEnumEqual($(document.body).select('a[href]'), $(document.body).select('[href]'));
+ this.assertEnumEqual($$('a[class~="internal"]'), $$('[class~=internal]'));
+ this.assertEnumEqual($$('*[id]'), $$('[id]'));
+ this.assertEnumEqual($('checked_radio', 'unchecked_radio'), $$('[type=radio]'));
+ this.assertEnumEqual($$('*[type=checkbox]'), $$('[type=checkbox]'));
+ this.assertEnumEqual($('with_title', 'commaParent'), $$('[title]'));
+ this.assertEnumEqual($$('#troubleForm *[type=radio]'), $$('#troubleForm [type=radio]'));
+ this.assertEnumEqual($$('#troubleForm *[type]'), $$('#troubleForm [type]'));
+ },
+
+ testSelectorWithUniversalAndHyphenTokenizedAttributeValue: function() {
+ this.assertEnumEqual([$('item_3')], $$('*[xml:lang|="es"]'));
+ this.assertEnumEqual([$('item_3')], $$('*[xml:lang|="ES"]'));
+ },
+
+ testSelectorWithTagNameAndNegatedAttributeValue: function() {
+ this.assertEnumEqual([], $$('a[href!="#"]'));
+ },
+
+ testSelectorWithBracketAttributeValue: function() {
+ this.assertEnumEqual($('chk_1', 'chk_2'), $$('#troubleForm2 input[name="brackets[5][]"]'));
+ this.assertEnumEqual([$('chk_1')], $$('#troubleForm2 input[name="brackets[5][]"]:checked'));
+ this.assertEnumEqual([$('chk_2')], $$('#troubleForm2 input[name="brackets[5][]"][value=2]'));
+ this.assertEnumEqual([], $$('#troubleForm2 input[name=brackets[5][]]'));
+ },
+
+ test$$WithNestedAttributeSelectors: function() {
+ this.assertEnumEqual([$('strong')], $$('div[style] p[id] strong'), 'div[style] p[id] strong');
+ },
+
+ testSelectorWithMultipleConditions: function() {
+ this.assertEnumEqual([$('link_3')], $$('a[class~=external][href="#"]'),
+ 'a[class~=external][href="#"]');
+ this.assertEnumEqual([], $$('a[class~=external][href!="#"]'),
+ 'a[class~=external][href!="#"]');
+ },
+
+ testSelectorMatchElements: function() {
+ this.assertElementsMatch(Selector.matchElements($('list').descendants(), 'li'), '#item_1', '#item_2', '#item_3');
+ this.assertElementsMatch(Selector.matchElements($('fixtures').descendants(), 'a.internal'), '#link_1', '#link_2');
+ this.assertEnumEqual([], Selector.matchElements($('fixtures').descendants(), 'p.last'));
+ this.assertElementsMatch(Selector.matchElements($('fixtures').descendants(), '.inexistant, a.internal'), '#link_1', '#link_2');
+ },
+
+ testSelectorFindElement: function() {
+ this.assertElementMatches(Selector.findElement($('list').descendants(), 'li'), 'li#item_1.first');
+ this.assertElementMatches(Selector.findElement($('list').descendants(), 'li', 1), 'li#item_2');
+ this.assertElementMatches(Selector.findElement($('list').descendants(), 'li#item_3'), 'li');
+ this.assertEqual(undefined, Selector.findElement($('list').descendants(), 'em'));
+ },
+
+ testElementMatch: function() {
+ var span = $('dupL1');
+
+ // tests that should pass
+ this.assert(span.match('span'));
+ this.assert(span.match('span#dupL1'));
+ this.assert(span.match('div > span'), 'child combinator');
+ this.assert(span.match('#dupContainer span'), 'descendant combinator');
+ this.assert(span.match('#dupL1'), 'ID only');
+ this.assert(span.match('span.span_foo'), 'class name 1');
+ this.assert(span.match('span.span_bar'), 'class name 2');
+ this.assert(span.match('span:first-child'), 'first-child pseudoclass');
+
+ this.assert(!span.match('span.span_wtf'), 'bogus class name');
+ this.assert(!span.match('#dupL2'), 'different ID');
+ this.assert(!span.match('div'), 'different tag name');
+ this.assert(!span.match('span span'), 'different ancestry');
+ this.assert(!span.match('span > span'), 'different parent');
+ this.assert(!span.match('span:nth-child(5)'), 'different pseudoclass');
+
+ this.assert(!$('link_2').match('a[rel^=external]'));
+ this.assert($('link_1').match('a[rel^=external]'));
+ this.assert($('link_1').match('a[rel^="external"]'));
+ this.assert($('link_1').match("a[rel^='external']"));
+
+ this.assert(span.match({ match: function(element) { return true }}), 'custom selector');
+ this.assert(!span.match({ match: function(element) { return false }}), 'custom selector');
+ },
+
+ testSelectorWithSpaceInAttributeValue: function() {
+ this.assertEnumEqual([$('with_title')], $$('cite[title="hello world!"]'));
+ },
+
+ // AND NOW COME THOSE NEW TESTS AFTER ANDREW'S REWRITE!
+
+ testSelectorWithNamespacedAttributes: function() {
+ if (Prototype.BrowserFeatures.XPath) {
+ this.assertUndefined(new Selector('html[xml:lang]').xpath);
+ this.assertUndefined(new Selector('body p[xml:lang]').xpath);
+ } else
+ this.info("Could not test XPath bypass: no XPath to begin with!");
+
+ this.assertElementsMatch($$('[xml:lang]'), 'html', '#item_3');
+ this.assertElementsMatch($$('*[xml:lang]'), 'html', '#item_3');
+ },
+
+ testSelectorWithChild: function() {
+ this.assertEnumEqual($('link_1', 'link_2'), $$('p.first > a'));
+ this.assertEnumEqual($('father', 'uncle'), $$('div#grandfather > div'));
+ this.assertEnumEqual($('level2_1', 'level2_2'), $$('#level1>span'));
+ this.assertEnumEqual($('level2_1', 'level2_2'), $$('#level1 > span'));
+ this.assertEnumEqual($('level3_1', 'level3_2'), $$('#level2_1 > *'));
+ this.assertEnumEqual([], $$('div > #nonexistent'));
+ $RunBenchmarks && this.wait(500, function() {
+ this.benchmark(function() { $$('#level1 > span') }, 1000);
+ });
+ },
+
+ testSelectorWithAdjacence: function() {
+ this.assertEnumEqual([$('uncle')], $$('div.brothers + div.brothers'));
+ this.assertEnumEqual([$('uncle')], $$('div.brothers + div'));
+ this.assertEqual($('level2_2'), $$('#level2_1+span').reduce());
+ this.assertEqual($('level2_2'), $$('#level2_1 + span').reduce());
+ this.assertEqual($('level2_2'), $$('#level2_1 + *').reduce());
+ this.assertEnumEqual([], $$('#level2_2 + span'));
+ this.assertEqual($('level3_2'), $$('#level3_1 + span').reduce());
+ this.assertEqual($('level3_2'), $$('#level3_1 + *').reduce());
+ this.assertEnumEqual([], $$('#level3_2 + *'));
+ this.assertEnumEqual([], $$('#level3_1 + em'));
+ $RunBenchmarks && this.wait(500, function() {
+ this.benchmark(function() { $$('#level3_1 + span') }, 1000);
+ });
+ },
+
+ testSelectorWithLaterSibling: function() {
+ this.assertEnumEqual([$('list')], $$('h1 ~ ul'));
+ this.assertEqual($('level2_2'), $$('#level2_1 ~ span').reduce());
+ this.assertEnumEqual($('level2_2', 'level2_3'), $$('#level2_1 ~ *').reduce());
+ this.assertEnumEqual([], $$('#level2_2 ~ span'));
+ this.assertEnumEqual([], $$('#level3_2 ~ *'));
+ this.assertEnumEqual([], $$('#level3_1 ~ em'));
+ this.assertEnumEqual([$('level3_2')], $$('#level3_1 ~ #level3_2'));
+ this.assertEnumEqual([$('level3_2')], $$('span ~ #level3_2'));
+ this.assertEnumEqual([], $$('div ~ #level3_2'));
+ this.assertEnumEqual([], $$('div ~ #level2_3'));
+ $RunBenchmarks && this.wait(500, function() {
+ this.benchmark(function() { $$('#level2_1 ~ span') }, 1000);
+ });
+ },
+
+ testSelectorWithNewAttributeOperators: function() {
+ this.assertEnumEqual($('father', 'uncle'), $$('div[class^=bro]'), 'matching beginning of string');
+ this.assertEnumEqual($('father', 'uncle'), $$('div[class$=men]'), 'matching end of string');
+ this.assertEnumEqual($('father', 'uncle'), $$('div[class*="ers m"]'), 'matching substring')
+ this.assertEnumEqual($('level2_1', 'level2_2', 'level2_3'), $$('#level1 *[id^="level2_"]'));
+ this.assertEnumEqual($('level2_1', 'level2_2', 'level2_3'), $$('#level1 *[id^=level2_]'));
+ this.assertEnumEqual($('level2_1', 'level3_1'), $$('#level1 *[id$="_1"]'));
+ this.assertEnumEqual($('level2_1', 'level3_1'), $$('#level1 *[id$=_1]'));
+ this.assertEnumEqual($('level2_1', 'level3_2', 'level2_2', 'level2_3'), $$('#level1 *[id*="2"]'));
+ this.assertEnumEqual($('level2_1', 'level3_2', 'level2_2', 'level2_3'), $$('#level1 *[id*=2]'));
+ $RunBenchmarks && this.wait(500, function() {
+ this.benchmark(function() { $$('#level1 *[id^=level2_]') }, 1000, '[^=]');
+ this.benchmark(function() { $$('#level1 *[id$=_1]') }, 1000, '[$=]');
+ this.benchmark(function() { $$('#level1 *[id*=_2]') }, 1000, '[*=]');
+ });
+ },
+
+ testSelectorWithDuplicates: function() {
+ this.assertEnumEqual($$('div div'), $$('div div').uniq());
+ this.assertEnumEqual($('dupL2', 'dupL3', 'dupL4', 'dupL5'), $$('#dupContainer span span'));
+ $RunBenchmarks && this.wait(500, function() {
+ this.benchmark(function() { $$('#dupContainer span span') }, 1000);
+ });
+ },
+
+ testSelectorWithFirstLastOnlyNthNthLastChild: function() {
+ this.assertEnumEqual([$('level2_1')], $$('#level1>*:first-child'));
+ this.assertEnumEqual($('level2_1', 'level3_1', 'level_only_child'), $$('#level1 *:first-child'));
+ this.assertEnumEqual([$('level2_3')], $$('#level1>*:last-child'));
+ this.assertEnumEqual($('level3_2', 'level_only_child', 'level2_3'), $$('#level1 *:last-child'));
+ this.assertEnumEqual([$('level2_3')], $$('#level1>div:last-child'));
+ this.assertEnumEqual([$('level2_3')], $$('#level1 div:last-child'));
+ this.assertEnumEqual([], $$('#level1>div:first-child'));
+ this.assertEnumEqual([], $$('#level1>span:last-child'));
+ this.assertEnumEqual($('level2_1', 'level3_1'), $$('#level1 span:first-child'));
+ this.assertEnumEqual([], $$('#level1:first-child'));
+ this.assertEnumEqual([], $$('#level1>*:only-child'));
+ this.assertEnumEqual([$('level_only_child')], $$('#level1 *:only-child'));
+ this.assertEnumEqual([], $$('#level1:only-child'));
+ this.assertEnumEqual([$('link_2')], $$('#p *:nth-last-child(2)'), 'nth-last-child');
+ this.assertEnumEqual([$('link_2')], $$('#p *:nth-child(3)'), 'nth-child');
+ this.assertEnumEqual([$('link_2')], $$('#p a:nth-child(3)'), 'nth-child');
+ this.assertEnumEqual($('item_2', 'item_3'), $$('#list > li:nth-child(n+2)'));
+ this.assertEnumEqual($('item_1', 'item_2'), $$('#list > li:nth-child(-n+2)'));
+ $RunBenchmarks && this.wait(500, function() {
+ this.benchmark(function() { $$('#level1 *:first-child') }, 1000, ':first-child');
+ this.benchmark(function() { $$('#level1 *:last-child') }, 1000, ':last-child');
+ this.benchmark(function() { $$('#level1 *:only-child') }, 1000, ':only-child');
+ });
+ },
+
+ testSelectorWithFirstLastNthNthLastOfType: function() {
+ this.assertEnumEqual([$('link_2')], $$('#p a:nth-of-type(2)'), 'nth-of-type');
+ this.assertEnumEqual([$('link_1')], $$('#p a:nth-of-type(1)'), 'nth-of-type');
+ this.assertEnumEqual([$('link_2')], $$('#p a:nth-last-of-type(1)'), 'nth-last-of-type');
+ this.assertEnumEqual([$('link_1')], $$('#p a:first-of-type'), 'first-of-type');
+ this.assertEnumEqual([$('link_2')], $$('#p a:last-of-type'), 'last-of-type');
+ },
+
+ testSelectorWithNot: function() {
+ this.assertEnumEqual([$('link_2')], $$('#p a:not(a:first-of-type)'), 'first-of-type');
+ this.assertEnumEqual([$('link_1')], $$('#p a:not(a:last-of-type)'), 'last-of-type');
+ this.assertEnumEqual([$('link_2')], $$('#p a:not(a:nth-of-type(1))'), 'nth-of-type');
+ this.assertEnumEqual([$('link_1')], $$('#p a:not(a:nth-last-of-type(1))'), 'nth-last-of-type');
+ this.assertEnumEqual([$('link_2')], $$('#p a:not([rel~=nofollow])'), 'attribute 1');
+ this.assertEnumEqual([$('link_2')], $$('#p a:not(a[rel^=external])'), 'attribute 2');
+ this.assertEnumEqual([$('link_2')], $$('#p a:not(a[rel$=nofollow])'), 'attribute 3');
+ this.assertEnumEqual([$('em')], $$('#p a:not(a[rel$="nofollow"]) > em'), 'attribute 4')
+ this.assertEnumEqual([$('item_2')], $$('#list li:not(#item_1):not(#item_3)'), 'adjacent :not clauses');
+ this.assertEnumEqual([$('son')], $$('#grandfather > div:not(#uncle) #son'));
+ this.assertEnumEqual([$('em')], $$('#p a:not(a[rel$="nofollow"]) em'), 'attribute 4 + all descendants');
+ this.assertEnumEqual([$('em')], $$('#p a:not(a[rel$="nofollow"])>em'), 'attribute 4 (without whitespace)');
+ },
+
+ testSelectorWithEnabledDisabledChecked: function() {
+ this.assertEnumEqual([$('disabled_text_field')], $$('#troubleForm > *:disabled'));
+ // bug 452708 this.assertEnumEqual($('troubleForm').getInputs().without($('disabled_text_field'), $('hidden')), $$('#troubleForm > *:enabled'));
+ this.assertEnumEqual($('checked_box', 'checked_radio'), $$('#troubleForm *:checked'));
+ },
+
+ testSelectorWithEmpty: function() {
+ $('level3_1').innerHTML = "";
+ this.assertEnumEqual($('level3_1', 'level3_2', 'level2_3'),
+ $$('#level1 *:empty'), '#level1 *:empty');
+ this.assertEnumEqual([], $$('#level_only_child:empty'), 'newlines count as content!');
+ },
+
+ testIdenticalResultsFromEquivalentSelectors: function() {
+ this.assertEnumEqual($$('div.brothers'), $$('div[class~=brothers]'));
+ this.assertEnumEqual($$('div.brothers'), $$('div[class~=brothers].brothers'));
+ this.assertEnumEqual($$('div:not(.brothers)'), $$('div:not([class~=brothers])'));
+ this.assertEnumEqual($$('li ~ li'), $$('li:not(:first-child)'));
+ this.assertEnumEqual($$('ul > li'), $$('ul > li:nth-child(n)'));
+ this.assertEnumEqual($$('ul > li:nth-child(even)'), $$('ul > li:nth-child(2n)'));
+ this.assertEnumEqual($$('ul > li:nth-child(odd)'), $$('ul > li:nth-child(2n+1)'));
+ this.assertEnumEqual($$('ul > li:first-child'), $$('ul > li:nth-child(1)'));
+ this.assertEnumEqual($$('ul > li:last-child'), $$('ul > li:nth-last-child(1)'));
+ this.assertEnumEqual($$('ul > li:nth-child(n-999)'), $$('ul > li'));
+ this.assertEnumEqual($$('ul>li'), $$('ul > li'));
+ this.assertEnumEqual($$('#p a:not(a[rel$="nofollow"])>em'), $$('#p a:not(a[rel$="nofollow"]) > em'))
+ },
+
+ testSelectorsThatShouldReturnNothing: function() {
+ this.assertEnumEqual([], $$('span:empty > *'));
+ this.assertEnumEqual([], $$('div.brothers:not(.brothers)'));
+ this.assertEnumEqual([], $$('#level2_2 :only-child:not(:last-child)'));
+ this.assertEnumEqual([], $$('#level2_2 :only-child:not(:first-child)'));
+ },
+
+ testCommasFor$$: function() {
+ this.assertEnumEqual($('list', 'p', 'link_1', 'item_1', 'item_3', 'troubleForm'), $$('#list, .first,*[xml:lang="es-us"] , #troubleForm'));
+ this.assertEnumEqual($('list', 'p', 'link_1', 'item_1', 'item_3', 'troubleForm'), $$('#list, .first,', '*[xml:lang="es-us"] , #troubleForm'));
+ this.assertEnumEqual($('commaParent', 'commaChild'), $$('form[title*="commas,"], input[value="#commaOne,#commaTwo"]'));
+ this.assertEnumEqual($('commaParent', 'commaChild'), $$('form[title*="commas,"]', 'input[value="#commaOne,#commaTwo"]'));
+ },
+
+ testSelectorExtendsAllNodes: function(){
+ var element = document.createElement('div');
+ (3).times(function(){
+ element.appendChild(document.createElement('div'));
+ });
+ element.setAttribute('id','scratch_element');
+ $$('body')[0].appendChild(element);
+
+ var results = $$('#scratch_element div');
+ this.assert(typeof results[0].show == 'function');
+ this.assert(typeof results[1].show == 'function');
+ this.assert(typeof results[2].show == 'function');
+ },
+
+ testCountedIsNotAnAttribute: function() {
+ var el = $('list');
+ Selector.handlers.mark([el]);
+ this.assert(!el.innerHTML.include("_counted"));
+ Selector.handlers.unmark([el]);
+ this.assert(!el.innerHTML.include("_counted"));
+ },
+
+ testCopiedNodesGetIncluded: function() {
+ this.assertElementsMatch(
+ Selector.matchElements($('counted_container').descendants(), 'div'),
+ 'div.is_counted'
+ );
+ $('counted_container').innerHTML += $('counted_container').innerHTML;
+ this.assertElementsMatch(
+ Selector.matchElements($('counted_container').descendants(), 'div'), 'div.is_counted',
+ 'div.is_counted'
+ );
+ },
+
+ testElementDown: function() {
+ var a = $('dupL4');
+ var b = $('dupContainer').down('#dupL4');
+
+ this.assertEqual(a, b);
+ }
+});
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/string_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/string_test.js
new file mode 100644
index 0000000000..c4e21f095b
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/string_test.js
@@ -0,0 +1,540 @@
+new Test.Unit.Runner({
+ testInterpret: function(){
+ this.assertIdentical('true', String.interpret(true));
+ this.assertIdentical('123', String.interpret(123));
+ this.assertIdentical('foo bar', String.interpret('foo bar'));
+ this.assertIdentical(
+ 'object string',
+ String.interpret({ toString: function(){ return 'object string' } }));
+
+ this.assertIdentical('0', String.interpret(0));
+ this.assertIdentical('false', String.interpret(false));
+ this.assertIdentical('', String.interpret(undefined));
+ this.assertIdentical('', String.interpret(null));
+ this.assertIdentical('', String.interpret(''));
+ },
+
+ testGsubWithReplacementFunction: function() {
+ var source = 'foo boo boz';
+
+ this.assertEqual('Foo Boo BoZ',
+ source.gsub(/[^o]+/, function(match) {
+ return match[0].toUpperCase()
+ }));
+ this.assertEqual('f2 b2 b1z',
+ source.gsub(/o+/, function(match) {
+ return match[0].length;
+ }));
+ this.assertEqual('f0 b0 b1z',
+ source.gsub(/o+/, function(match) {
+ return match[0].length % 2;
+ }));
+
+ },
+
+ testGsubWithReplacementString: function() {
+ var source = 'foo boo boz';
+
+ this.assertEqual('foobooboz',
+ source.gsub(/\s+/, ''));
+ this.assertEqual(' z',
+ source.gsub(/(.)(o+)/, ''));
+
+ this.assertEqual('ウィメンズ2007<br/>クルーズコレクション',
+ 'ウィメンズ2007\nクルーズコレクション'.gsub(/\n/,'<br/>'));
+ this.assertEqual('ウィメンズ2007<br/>クルーズコレクション',
+ 'ウィメンズ2007\nクルーズコレクション'.gsub('\n','<br/>'));
+ },
+
+ testGsubWithReplacementTemplateString: function() {
+ var source = 'foo boo boz';
+
+ this.assertEqual('-oo-#{1}- -oo-#{1}- -o-#{1}-z',
+ source.gsub(/(.)(o+)/, '-#{2}-\\#{1}-'));
+ this.assertEqual('-foo-f- -boo-b- -bo-b-z',
+ source.gsub(/(.)(o+)/, '-#{0}-#{1}-'));
+ this.assertEqual('-oo-f- -oo-b- -o-b-z',
+ source.gsub(/(.)(o+)/, '-#{2}-#{1}-'));
+ this.assertEqual(' z',
+ source.gsub(/(.)(o+)/, '#{3}'));
+ },
+
+ testSubWithReplacementFunction: function() {
+ var source = 'foo boo boz';
+
+ this.assertEqual('Foo boo boz',
+ source.sub(/[^o]+/, function(match) {
+ return match[0].toUpperCase()
+ }), 1);
+ this.assertEqual('Foo Boo boz',
+ source.sub(/[^o]+/, function(match) {
+ return match[0].toUpperCase()
+ }, 2), 2);
+ this.assertEqual(source,
+ source.sub(/[^o]+/, function(match) {
+ return match[0].toUpperCase()
+ }, 0), 0);
+ this.assertEqual(source,
+ source.sub(/[^o]+/, function(match) {
+ return match[0].toUpperCase()
+ }, -1), -1);
+ },
+
+ testSubWithReplacementString: function() {
+ var source = 'foo boo boz';
+
+ this.assertEqual('oo boo boz',
+ source.sub(/[^o]+/, ''));
+ this.assertEqual('oooo boz',
+ source.sub(/[^o]+/, '', 2));
+ this.assertEqual('-f-oo boo boz',
+ source.sub(/[^o]+/, '-#{0}-'));
+ this.assertEqual('-f-oo- b-oo boz',
+ source.sub(/[^o]+/, '-#{0}-', 2));
+ },
+
+ testScan: function() {
+ var source = 'foo boo boz', results = [];
+ var str = source.scan(/[o]+/, function(match) {
+ results.push(match[0].length);
+ });
+ this.assertEnumEqual([2, 2, 1], results);
+ this.assertEqual(source, source.scan(/x/, this.fail));
+ this.assert(typeof str == 'string');
+ },
+
+ testToArray: function() {
+ this.assertEnumEqual([],''.toArray());
+ this.assertEnumEqual(['a'],'a'.toArray());
+ this.assertEnumEqual(['a','b'],'ab'.toArray());
+ this.assertEnumEqual(['f','o','o'],'foo'.toArray());
+ },
+
+ /*
+ Note that camelize() differs from its Rails counterpart,
+ as it is optimized for dealing with JavaScript object
+ properties in conjunction with CSS property names:
+ - Looks for dashes, not underscores
+ - CamelCases first word if there is a front dash
+ */
+ testCamelize: function() {
+ this.assertEqual('', ''.camelize());
+ this.assertEqual('', '-'.camelize());
+ this.assertEqual('foo', 'foo'.camelize());
+ this.assertEqual('foo_bar', 'foo_bar'.camelize());
+ this.assertEqual('FooBar', '-foo-bar'.camelize());
+ this.assertEqual('FooBar', 'FooBar'.camelize());
+
+ this.assertEqual('fooBar', 'foo-bar'.camelize());
+ this.assertEqual('borderBottomWidth', 'border-bottom-width'.camelize());
+
+ this.assertEqual('classNameTest','class-name-test'.camelize());
+ this.assertEqual('classNameTest','className-test'.camelize());
+ this.assertEqual('classNameTest','class-nameTest'.camelize());
+
+ /* this.benchmark(function(){
+ 'class-name-test'.camelize();
+ },10000); */
+ },
+
+ testCapitalize: function() {
+ this.assertEqual('',''.capitalize());
+ this.assertEqual('Ä','ä'.capitalize());
+ this.assertEqual('A','A'.capitalize());
+ this.assertEqual('Hello','hello'.capitalize());
+ this.assertEqual('Hello','HELLO'.capitalize());
+ this.assertEqual('Hello','Hello'.capitalize());
+ this.assertEqual('Hello world','hello WORLD'.capitalize());
+ },
+
+ testUnderscore: function() {
+ this.assertEqual('', ''.underscore());
+ this.assertEqual('_', '-'.underscore());
+ this.assertEqual('foo', 'foo'.underscore());
+ this.assertEqual('foo', 'Foo'.underscore());
+ this.assertEqual('foo_bar', 'foo_bar'.underscore());
+ this.assertEqual('border_bottom', 'borderBottom'.underscore());
+ this.assertEqual('border_bottom_width', 'borderBottomWidth'.underscore());
+ this.assertEqual('border_bottom_width', 'border-Bottom-Width'.underscore());
+ },
+
+ testDasherize: function() {
+ this.assertEqual('', ''.dasherize());
+ this.assertEqual('foo', 'foo'.dasherize());
+ this.assertEqual('Foo', 'Foo'.dasherize());
+ this.assertEqual('foo-bar', 'foo-bar'.dasherize());
+ this.assertEqual('border-bottom-width', 'border_bottom_width'.dasherize());
+ },
+
+ testTruncate: function() {
+ var source = 'foo boo boz foo boo boz foo boo boz foo boo boz';
+ this.assertEqual(source, source.truncate(source.length));
+ this.assertEqual('foo boo boz foo boo boz foo...', source.truncate(0));
+ this.assertEqual('fo...', source.truncate(5));
+ this.assertEqual('foo b', source.truncate(5, ''));
+
+ this.assert(typeof 'foo'.truncate(5) == 'string');
+ this.assert(typeof 'foo bar baz'.truncate(5) == 'string');
+ },
+
+ testStrip: function() {
+ this.assertEqual('hello world', ' hello world '.strip());
+ this.assertEqual('hello world', 'hello world'.strip());
+ this.assertEqual('hello \n world', ' hello \n world '.strip());
+ this.assertEqual('', ' '.strip());
+ },
+
+ testStripTags: function() {
+ this.assertEqual('hello world', 'hello world'.stripTags());
+ this.assertEqual('hello world', 'hello <span>world</span>'.stripTags());
+ this.assertEqual('hello world', '<a href="#" onclick="moo!">hello</a> world'.stripTags());
+ this.assertEqual('hello world', 'h<b><em>e</em></b>l<i>l</i>o w<span class="moo" id="x"><b>o</b></span>rld'.stripTags());
+ this.assertEqual('1\n2', '1\n2'.stripTags());
+ },
+
+ testStripScripts: function() {
+ this.assertEqual('foo bar', 'foo bar'.stripScripts());
+ this.assertEqual('foo bar', ('foo <script>boo();<'+'/script>bar').stripScripts());
+ this.assertEqual('foo bar', ('foo <script type="text/javascript">boo();\nmoo();<'+'/script>bar').stripScripts());
+ },
+
+ testExtractScripts: function() {
+ this.assertEnumEqual([], 'foo bar'.extractScripts());
+ this.assertEnumEqual(['boo();'], ('foo <script>boo();<'+'/script>bar').extractScripts());
+ this.assertEnumEqual(['boo();','boo();\nmoo();'],
+ ('foo <script>boo();<'+'/script><script type="text/javascript">boo();\nmoo();<'+'/script>bar').extractScripts());
+ this.assertEnumEqual(['boo();','boo();\nmoo();'],
+ ('foo <script>boo();<'+'/script>blub\nblub<script type="text/javascript">boo();\nmoo();<'+'/script>bar').extractScripts());
+
+ var russianChars = '//кПЌеМтарОй\n';
+ var longComment = '//' + Array(7000).join('.') + '\n';
+ var longScript = '\nvar foo = 1;\n' + russianChars + longComment;
+ var longString = '<script type="text/javascript">'+ longScript + '<'+'/script>';
+ this.assertEnumEqual([longScript], longString.extractScripts());
+
+ this.assertEnumEqual([], ('<!--\n<script>boo();<'+'/script>\n-->').extractScripts());
+ },
+
+ testEvalScripts: function() {
+ this.assertEqual(0, evalScriptsCounter);
+
+ ('foo <script>evalScriptsCounter++<'+'/script>bar').evalScripts();
+ this.assertEqual(1, evalScriptsCounter);
+
+ var stringWithScripts = '';
+ (3).times(function(){ stringWithScripts += 'foo <script>evalScriptsCounter++<'+'/script>bar' });
+ stringWithScripts.evalScripts();
+ this.assertEqual(4, evalScriptsCounter);
+ },
+
+ testEscapeHTML: function() {
+ this.assertEqual('foo bar', 'foo bar'.escapeHTML());
+ this.assertEqual('foo &lt;span&gt;bar&lt;/span&gt;', 'foo <span>bar</span>'.escapeHTML());
+ this.assertEqual('foo ß bar', 'foo ß bar'.escapeHTML());
+
+ this.assertEqual('ウィメンズ2007\nクルーズコレクション',
+ 'ウィメンズ2007\nクルーズコレクション'.escapeHTML());
+
+ this.assertEqual('a&lt;a href=&quot;blah&quot;&gt;blub&lt;/a&gt;b&lt;span&gt;&lt;div&gt;&lt;/div&gt;&lt;/span&gt;cdef&lt;strong&gt;!!!!&lt;/strong&gt;g',
+ 'a<a href="blah">blub</a>b<span><div></div></span>cdef<strong>!!!!</strong>g'.escapeHTML());
+
+ this.assertEqual(largeTextEscaped, largeTextUnescaped.escapeHTML());
+
+ this.assertEqual('1\n2', '1\n2'.escapeHTML());
+
+ this.benchmark(function() { largeTextUnescaped.escapeHTML() }, 1000);
+ },
+
+ testUnescapeHTML: function() {
+ this.assertEqual('foo bar', 'foo bar'.unescapeHTML());
+ this.assertEqual('foo <span>bar</span>', 'foo &lt;span&gt;bar&lt;/span&gt;'.unescapeHTML());
+ this.assertEqual('foo ß bar', 'foo ß bar'.unescapeHTML());
+
+ this.assertEqual('a<a href="blah">blub</a>b<span><div></div></span>cdef<strong>!!!!</strong>g',
+ 'a&lt;a href="blah"&gt;blub&lt;/a&gt;b&lt;span&gt;&lt;div&gt;&lt;/div&gt;&lt;/span&gt;cdef&lt;strong&gt;!!!!&lt;/strong&gt;g'.unescapeHTML());
+
+ this.assertEqual(largeTextUnescaped, largeTextEscaped.unescapeHTML());
+
+ this.assertEqual('test \xfa', 'test &uacute;'.unescapeHTML());
+ this.assertEqual('1\n2', '1\n2'.unescapeHTML());
+ this.assertEqual('Pride & Prejudice', '<h1>Pride &amp; Prejudice</h1>'.unescapeHTML());
+
+ var escapedTest = '"&lt;" means "<" in HTML';
+ this.assertEqual(escapedTest, escapedTest.escapeHTML().unescapeHTML());
+
+ this.benchmark(function() { largeTextEscaped.unescapeHTML() }, 1000);
+
+ },
+
+ testTemplateEvaluation: function() {
+ var source = '<tr><td>#{name}</td><td>#{age}</td></tr>';
+ var person = {name: 'Sam', age: 21};
+ var template = new Template(source);
+
+ this.assertEqual('<tr><td>Sam</td><td>21</td></tr>',
+ template.evaluate(person));
+ this.assertEqual('<tr><td></td><td></td></tr>',
+ template.evaluate({}));
+ },
+
+ testTemplateEvaluationWithEmptyReplacement: function() {
+ var template = new Template('##{}');
+ this.assertEqual('#', template.evaluate({}));
+ this.assertEqual('#', template.evaluate({foo: 'bar'}));
+
+ template = new Template('#{}');
+ this.assertEqual('', template.evaluate({}));
+ },
+
+ testTemplateEvaluationWithFalses: function() {
+ var source = '<tr><td>#{zero}</td><td>#{false_}</td><td>#{undef}</td><td>#{null_}</td><td>#{empty}</td></tr>';
+ var falses = {zero:0, false_:false, undef:undefined, null_:null, empty:""};
+ var template = new Template(source);
+
+ this.assertEqual('<tr><td>0</td><td>false</td><td></td><td></td><td></td></tr>',
+ template.evaluate(falses));
+ },
+
+ testTemplateEvaluationWithNested: function() {
+ var source = '#{name} #{manager.name} #{manager.age} #{manager.undef} #{manager.age.undef} #{colleagues.first.name}';
+ var subject = { manager: { name: 'John', age: 29 }, name: 'Stephan', age: 22, colleagues: { first: { name: 'Mark' }} };
+ this.assertEqual('Stephan', new Template('#{name}').evaluate(subject));
+ this.assertEqual('John', new Template('#{manager.name}').evaluate(subject));
+ this.assertEqual('29', new Template('#{manager.age}').evaluate(subject));
+ this.assertEqual('', new Template('#{manager.undef}').evaluate(subject));
+ this.assertEqual('', new Template('#{manager.age.undef}').evaluate(subject));
+ this.assertEqual('Mark', new Template('#{colleagues.first.name}').evaluate(subject));
+ this.assertEqual('Stephan John 29 Mark', new Template(source).evaluate(subject));
+ },
+
+ testTemplateEvaluationWithIndexing: function() {
+ var source = '#{0} = #{[0]} - #{1} = #{[1]} - #{[2][0]} - #{[2].name} - #{first[0]} - #{[first][0]} - #{[\\]]} - #{first[\\]]}';
+ var subject = [ 'zero', 'one', [ 'two-zero' ] ];
+ subject[2].name = 'two-zero-name';
+ subject.first = subject[2];
+ subject[']'] = '\\';
+ subject.first[']'] = 'first\\';
+ this.assertEqual('zero', new Template('#{[0]}').evaluate(subject));
+ this.assertEqual('one', new Template('#{[1]}').evaluate(subject));
+ this.assertEqual('two-zero', new Template('#{[2][0]}').evaluate(subject));
+ this.assertEqual('two-zero-name', new Template('#{[2].name}').evaluate(subject));
+ this.assertEqual('two-zero', new Template('#{first[0]}').evaluate(subject));
+ this.assertEqual('\\', new Template('#{[\\]]}').evaluate(subject));
+ this.assertEqual('first\\', new Template('#{first[\\]]}').evaluate(subject));
+ this.assertEqual('empty - empty2', new Template('#{[]} - #{m[]}').evaluate({ '': 'empty', m: {'': 'empty2'}}));
+ this.assertEqual('zero = zero - one = one - two-zero - two-zero-name - two-zero - two-zero - \\ - first\\', new Template(source).evaluate(subject));
+ },
+
+ testTemplateToTemplateReplacements: function() {
+ var source = 'My name is #{name}, my job is #{job}';
+ var subject = {
+ name: 'Stephan',
+ getJob: function() { return 'Web developer'; },
+ toTemplateReplacements: function() { return { name: this.name, job: this.getJob() } }
+ };
+ this.assertEqual('My name is Stephan, my job is Web developer', new Template(source).evaluate(subject));
+ },
+
+ testTemplateEvaluationCombined: function() {
+ var source = '#{name} is #{age} years old, managed by #{manager.name}, #{manager.age}.\n' +
+ 'Colleagues include #{colleagues[0].name} and #{colleagues[1].name}.';
+ var subject = {
+ name: 'Stephan', age: 22,
+ manager: { name: 'John', age: 29 },
+ colleagues: [ { name: 'Mark' }, { name: 'Indy' } ]
+ };
+ this.assertEqual('Stephan is 22 years old, managed by John, 29.\n' +
+ 'Colleagues include Mark and Indy.',
+ new Template(source).evaluate(subject));
+ },
+
+ testInterpolate: function() {
+ var subject = { name: 'Stephan' };
+ var pattern = /(^|.|\r|\n)(#\((.*?)\))/;
+ this.assertEqual('#{name}: Stephan', '\\#{name}: #{name}'.interpolate(subject));
+ this.assertEqual('#(name): Stephan', '\\#(name): #(name)'.interpolate(subject, pattern));
+ },
+
+ testToQueryParams: function() {
+ // only the query part
+ var result = {a:undefined, b:'c'};
+ this.assertHashEqual({}, ''.toQueryParams(), 'empty query');
+ this.assertHashEqual({}, 'foo?'.toQueryParams(), 'empty query with URL');
+ this.assertHashEqual(result, 'foo?a&b=c'.toQueryParams(), 'query with URL');
+ this.assertHashEqual(result, 'foo?a&b=c#fragment'.toQueryParams(), 'query with URL and fragment');
+ this.assertHashEqual(result, 'a;b=c'.toQueryParams(';'), 'custom delimiter');
+
+ this.assertHashEqual({a:undefined}, 'a'.toQueryParams(), 'key without value');
+ this.assertHashEqual({a:'b'}, 'a=b&=c'.toQueryParams(), 'empty key');
+ this.assertHashEqual({a:'b', c:''}, 'a=b&c='.toQueryParams(), 'empty value');
+
+ this.assertHashEqual({'a b':'c', d:'e f', g:'h'},
+ 'a%20b=c&d=e%20f&g=h'.toQueryParams(), 'proper decoding');
+ this.assertHashEqual({a:'b=c=d'}, 'a=b=c=d'.toQueryParams(), 'multiple equal signs');
+ this.assertHashEqual({a:'b', c:'d'}, '&a=b&&&c=d'.toQueryParams(), 'proper splitting');
+
+ this.assertEnumEqual($w('r g b'), 'col=r&col=g&col=b'.toQueryParams()['col'],
+ 'collection without square brackets');
+ var msg = 'empty values inside collection';
+ this.assertEnumEqual(['r', '', 'b'], 'c=r&c=&c=b'.toQueryParams()['c'], msg);
+ this.assertEnumEqual(['', 'blue'], 'c=&c=blue'.toQueryParams()['c'], msg);
+ this.assertEnumEqual(['blue', ''], 'c=blue&c='.toQueryParams()['c'], msg);
+ },
+
+ testInspect: function() {
+ this.assertEqual('\'\'', ''.inspect());
+ this.assertEqual('\'test\'', 'test'.inspect());
+ this.assertEqual('\'test \\\'test\\\' "test"\'', 'test \'test\' "test"'.inspect());
+ this.assertEqual('\"test \'test\' \\"test\\"\"', 'test \'test\' "test"'.inspect(true));
+ this.assertEqual('\'\\b\\t\\n\\f\\r"\\\\\'', '\b\t\n\f\r"\\'.inspect());
+ this.assertEqual('\"\\b\\t\\n\\f\\r\\"\\\\\"', '\b\t\n\f\r"\\'.inspect(true));
+ this.assertEqual('\'\\b\\t\\n\\f\\r\'', '\x08\x09\x0a\x0c\x0d'.inspect());
+ this.assertEqual('\'\\u001a\'', '\x1a'.inspect());
+ },
+
+ testInclude: function() {
+ this.assert('hello world'.include('h'));
+ this.assert('hello world'.include('hello'));
+ this.assert('hello world'.include('llo w'));
+ this.assert('hello world'.include('world'));
+ this.assert(!'hello world'.include('bye'));
+ this.assert(!''.include('bye'));
+ },
+
+ testStartsWith: function() {
+ this.assert('hello world'.startsWith('h'));
+ this.assert('hello world'.startsWith('hello'));
+ this.assert(!'hello world'.startsWith('bye'));
+ this.assert(!''.startsWith('bye'));
+ this.assert(!'hell'.startsWith('hello'));
+ },
+
+ testEndsWith: function() {
+ this.assert('hello world'.endsWith('d'));
+ this.assert('hello world'.endsWith(' world'));
+ this.assert(!'hello world'.endsWith('planet'));
+ this.assert(!''.endsWith('planet'));
+ this.assert('hello world world'.endsWith(' world'));
+ this.assert(!'z'.endsWith('az'));
+ },
+
+ testBlank: function() {
+ this.assert(''.blank());
+ this.assert(' '.blank());
+ this.assert('\t\r\n '.blank());
+ this.assert(!'a'.blank());
+ this.assert(!'\t y \n'.blank());
+ },
+
+ testEmpty: function() {
+ this.assert(''.empty());
+ this.assert(!' '.empty());
+ this.assert(!'\t\r\n '.empty());
+ this.assert(!'a'.empty());
+ this.assert(!'\t y \n'.empty());
+ },
+
+ testSucc: function() {
+ this.assertEqual('b', 'a'.succ());
+ this.assertEqual('B', 'A'.succ());
+ this.assertEqual('1', '0'.succ());
+ this.assertEqual('abce', 'abcd'.succ());
+ this.assertEqual('{', 'z'.succ());
+ this.assertEqual(':', '9'.succ());
+ },
+
+ testTimes: function() {
+
+ this.assertEqual('', ''.times(0));
+ this.assertEqual('', ''.times(5));
+ this.assertEqual('', 'a'.times(-1));
+ this.assertEqual('', 'a'.times(0));
+ this.assertEqual('a', 'a'.times(1));
+ this.assertEqual('aa', 'a'.times(2));
+ this.assertEqual('aaaaa', 'a'.times(5));
+ this.assertEqual('foofoofoofoofoo', 'foo'.times(5));
+ this.assertEqual('', 'foo'.times(-5));
+
+ /*window.String.prototype.oldTimes = function(count) {
+ var result = '';
+ for (var i = 0; i < count; i++) result += this;
+ return result;
+ };
+
+ this.benchmark(function() {
+ 'foo'.times(15);
+ }, 1000, 'new: ');
+
+ this.benchmark(function() {
+ 'foo'.oldTimes(15);
+ }, 1000, 'previous: ');*/
+ },
+
+ testToJSON: function() {
+ this.assertEqual('\"\"', ''.toJSON());
+ this.assertEqual('\"test\"', 'test'.toJSON());
+ },
+
+ testIsJSON: function() {
+ this.assert(!''.isJSON());
+ this.assert(!' '.isJSON());
+ this.assert('""'.isJSON());
+ this.assert('"foo"'.isJSON());
+ this.assert('{}'.isJSON());
+ this.assert('[]'.isJSON());
+ this.assert('null'.isJSON());
+ this.assert('123'.isJSON());
+ this.assert('true'.isJSON());
+ this.assert('false'.isJSON());
+ this.assert('"\\""'.isJSON());
+ this.assert(!'\\"'.isJSON());
+ this.assert(!'new'.isJSON());
+ this.assert(!'\u0028\u0029'.isJSON());
+ // we use '@' as a placeholder for characters authorized only inside brackets,
+ // so this tests make sure it is not considered authorized elsewhere.
+ this.assert(!'@'.isJSON());
+ },
+
+ testEvalJSON: function() {
+ var valid = '{"test": \n\r"hello world!"}';
+ var invalid = '{"test": "hello world!"';
+ var dangerous = '{});attackTarget = "attack succeeded!";({}';
+
+ // use smaller huge string size for KHTML
+ var size = navigator.userAgent.include('KHTML') ? 20 : 100;
+ var longString = '"' + '123456789\\"'.times(size * 10) + '"';
+ var object = '{' + longString + ': ' + longString + '},';
+ var huge = '[' + object.times(size) + '{"test": 123}]';
+
+ this.assertEqual('hello world!', valid.evalJSON().test);
+ this.assertEqual('hello world!', valid.evalJSON(true).test);
+ this.assertRaise('SyntaxError', function() { invalid.evalJSON() });
+ this.assertRaise('SyntaxError', function() { invalid.evalJSON(true) });
+
+ attackTarget = "scared";
+ dangerous.evalJSON();
+ this.assertEqual("attack succeeded!", attackTarget);
+
+ attackTarget = "Not scared!";
+ this.assertRaise('SyntaxError', function(){dangerous.evalJSON(true)});
+ this.assertEqual("Not scared!", attackTarget);
+
+ this.assertEqual('hello world!', ('/*-secure- \r \n ' + valid + ' \n */').evalJSON().test);
+ var temp = Prototype.JSONFilter;
+ Prototype.JSONFilter = /^\/\*([\s\S]*)\*\/$/; // test custom delimiters.
+ this.assertEqual('hello world!', ('/*' + valid + '*/').evalJSON().test);
+ Prototype.JSONFilter = temp;
+
+ this.assertMatch(123, huge.evalJSON(true).last().test);
+
+ this.assertEqual('', '""'.evalJSON());
+ this.assertEqual('foo', '"foo"'.evalJSON());
+ this.assert('object', typeof '{}'.evalJSON());
+ this.assert(Object.isArray('[]'.evalJSON()));
+ this.assertNull('null'.evalJSON());
+ this.assert(123, '123'.evalJSON());
+ this.assertIdentical(true, 'true'.evalJSON());
+ this.assertIdentical(false, 'false'.evalJSON());
+ this.assertEqual('"', '"\\""'.evalJSON());
+ }
+}); \ No newline at end of file
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/ajax_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/ajax_test.html
new file mode 100644
index 0000000000..b38fd306ca
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/ajax_test.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Ajax</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+ <script src="../fixtures/ajax.js" type="text/javascript" charset="utf-8"></script>
+
+
+ <script src="../ajax_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Ajax</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<div id="content"></div>
+<div id="content2" style="color:red"></div>
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/array_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/array_test.html
new file mode 100644
index 0000000000..cc3b9ef629
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/array_test.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Array</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+
+ <script src="../array_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Array</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<div id="test_node">22<span id="span_1"></span><span id="span_2"></span></div>
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/base_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/base_test.html
new file mode 100644
index 0000000000..bcd29f91df
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/base_test.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Base</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+ <script src="../fixtures/base.js" type="text/javascript" charset="utf-8"></script>
+
+
+ <script src="../base_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Base</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<div id="test"></div>
+<ul id="list">
+ <li></li>
+ <li></li>
+ <li></li>
+</ul>
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/dom_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/dom_test.html
new file mode 100644
index 0000000000..c1ffb7536f
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/dom_test.html
@@ -0,0 +1,326 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Dom</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+ <link rel="stylesheet" href="../fixtures/dom.css" type="text/css" charset="utf-8" />
+
+
+
+ <script src="../fixtures/dom.js" type="text/javascript" charset="utf-8"></script>
+
+
+ <script src="../dom_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Dom</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<div id="scroll_test_1">
+ <p id="scroll_test_2">Scroll test</p>
+</div>
+
+<div id="test-visible">visible</div>
+<div id="test-hidden" style="display:none;">hidden</div>
+<div id="test-toggle-visible">visible</div>
+<div id="test-toggle-hidden" style="display:none;">hidden</div>
+<div id="test-hide-visible">visible</div>
+<div id="test-hide-hidden" style="display:none;">hidden</div>
+<div id="test-show-visible">visible</div>
+<div id="test-show-hidden" style="display:none;">hidden</div>
+<div id="removable-container"><div id="removable"></div></div>
+
+<div>
+ <table>
+ <tbody id="table">
+ <tr>
+ <td>Data</td>
+ </tr>
+ <tr>
+ <td id="a_cell">First Row</td>
+ </tr>
+ <tr id="second_row">
+ <td>Second Row</td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+
+<div id="table-container-to-replace">
+ <table>
+ <tbody id="table-to-replace">
+ <tr>
+ <td>Data</td>
+ </tr>
+ <tr>
+ <td id="a_cell-to-replace">First Row</td>
+ </tr>
+ <tr id="second_row-to-replace">
+ <td>Second Row</td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+
+<p class="test">Test paragraph outside of container</p>
+
+<div id="container">
+ <p class="test" id="intended">Test paragraph 1 inside of container</p>
+ <p class="test">Test paragraph 2 inside of container</p>
+ <p class="test">Test paragraph 3 inside of container</p>
+ <p class="test">Test paragraph 4 inside of container</p>
+</div>
+
+<div id="testdiv">to be updated</div>
+<div id="testdiv-replace-container-1"><div id="testdiv-replace-1"></div></div>
+<div id="testdiv-replace-container-2"><div id="testdiv-replace-2"></div></div>
+<div id="testdiv-replace-container-3"><div id="testdiv-replace-3"></div></div>
+<div id="testdiv-replace-container-4"><div id="testdiv-replace-4"></div></div>
+<div id="testdiv-replace-container-5"><div id="testdiv-replace-5"></div></div>
+<div id="testdiv-replace-container-element"><div id="testdiv-replace-element"></div></div>
+<div id="testdiv-replace-container-toelement"><div id="testdiv-replace-toelement"></div></div>
+<div id="testdiv-replace-container-tohtml"><div id="testdiv-replace-tohtml"></div></div>
+<div id="testtable-replace-container"><table id="testtable-replace"></table></div>
+<table id="testrow-replace-container"><tr id="testrow-replace"></tr></table>
+<select id="testoption-replace-container"><option id="testoption-replace"></option><option>stays</option></select>
+<div id="testform-replace-container"><p>some text</p><form id="testform-replace"><input id="testinput-replace" type="text" /></form><p>some text</p></div>
+
+<div id="element_with_visible_overflow" style="overflow:visible">V</div>
+<div id="element_with_hidden_overflow" style="overflow:hidden">H</div>
+<div id="element_with_scroll_overflow" style="overflow:scroll">S</div>
+
+<div id="element_extend_test"> </div>
+
+<div id="element_reextend_test"><div id="discard_1"></div></div>
+
+<div id="test_whitespace"> <span> </span>
+
+
+<div><div></div> </div><span> </span>
+</div>
+
+
+<div id="nav_tests_isolator">
+ <div id="nav_test_first_sibling"></div>
+ <div></div>
+ <p id="nav_test_p" class="test"></p>
+ <span id="nav_test_prev_sibling"></span>
+
+ <ul id="navigation_test" style="display: none">
+ <!-- comment node to screw things up -->
+ <li class="first"><em>A</em></li>
+ <li><em class="dim">B</em></li>
+ <li id="navigation_test_c">
+ <em>C</em>
+ <ul>
+ <li><em class="dim">E</em></li>
+ <li id="navigation_test_f"><em>F</em></li>
+ </ul>
+ </li>
+ <li class="last"><em>D</em></li>
+ </ul>
+
+ <div id="navigation_test_next_sibling">
+ <!-- -->
+ </div>
+
+ <p></p>
+</div>
+
+<div id="class_names">
+ <p class="A"></p>
+ <ul class="A B" id="class_names_ul">
+ <li class="C"></li>
+ <li class="A C"></li>
+ <li class="1"></li>
+ </ul>
+ <div class="B C D"></div>
+ <div id="unextended"></div>
+</div>
+
+<div id="style_test_1" style="display:none;"></div>
+<div id="style_test_2" class="style-test" style="font-size:11px;"></div>
+
+<div id="style_test_3">blah</div>
+<span id="style_test_4">blah</span>
+<span id="style_test_5">blah</span>
+
+<div id="style_test_dimensions_container">
+ <div id="style_test_dimensions" style="background:#ddd;padding:1px;margin:1px;border:1px solid #00f"><div style="height:5px;background:#eee;width:5px;padding:2px;margin:2px;border:2px solid #0f0"> </div>
+ </div>
+</div>
+
+<div id="test_csstext_1">test_csstext_1</div>
+<div id="test_csstext_2">test_csstext_2</div>
+<div id="test_csstext_3" style="border: 1px solid red">test_csstext_3</div>
+<div id="test_csstext_4" style="font-size: 20px">test_csstext_4</div>
+<div id="test_csstext_5">test_csstext_5</div>
+
+<div id="custom_attributes">
+ <div foo="1" bar="2"></div>
+ <div foo="2"></div>
+</div>
+
+<div id="cloned_element_attributes_issue" foo="original"></div>
+<a id="attributes_with_issues_1" href="test.html" accesskey="L" tabindex="50" title="a link" onclick="alert('hello world');"></a>
+<a id="attributes_with_issues_2" href="" accesskey="" tabindex="" title=""></a>
+<a id="attributes_with_issues_3"></a>
+<form id="attributes_with_issues_form" method="post" action="blah" class="blah-class">
+ <input type="hidden" id="id" />
+ <input type="hidden" name="id" />
+ <input type="checkbox" id="action" />
+ <input type="checkbox" name="action" />
+ <input type="text" id="method" />
+ <input type="hidden" name="class" />
+ <input type="checkbox" id="attributes_with_issues_checked" name="a" checked="checked"/>
+ <input type="checkbox" id="attributes_with_issues_disabled" name="b" checked="checked" disabled="disabled"/>
+ <input type="text" id="attributes_with_issues_readonly" name="c" readonly="readonly" value="blech"/>
+ <input type="text" id="attributes_with_issues_regular" name="d" value="0"/>
+ <input type="date" id="attributes_with_issues_type" value="blech" />
+ <select id="attributes_with_issues_multiple" name="e" multiple="multiple">
+ <option>blech</option>
+ <option>blah</option>
+ </select>
+</form>
+
+<!-- writeAttributes -->
+<p id="write_attribute_para"></p>
+<a id="write_attribute_link" href="test.html"></a>
+<form action="/dev/null" id="write_attribute_form" method="get" accept-charset="utf-8">
+ <label id="write_attribute_label"></label>
+ <input type="checkbox" name="write_attribute_checkbox" value="" id="write_attribute_checkbox">
+ <input type="checkbox" checked="checked" name="write_attribute_checked_checkbox" value="" id="write_attribute_checked_checkbox">
+ <input type="text" name="write_attribute_input" value="" id="write_attribute_input">
+ <select id="write_attribute_select">
+ <option>Cat</option>
+ <option>Dog</option>
+ </select>
+</form>
+
+<table id="write_attribute_table" cellpadding="6" cellspacing="4">
+ <tr><td id="write_attribute_td">A</td><td>B</td></tr>
+ <tr><td>C</td></tr>
+ <tr><td>D</td><td>E</td><td>F</td></tr>
+</table>
+
+<div id="dom_attribute_precedence">
+ <form action="blech" method="post">
+ <input type="submit" id="update" />
+ </form>
+</div>
+
+<div id="not_floating_none">NFN</div>
+<div id="not_floating_inline" style="float:none">NFI</div>
+<div id="not_floating_style">NFS</div>
+
+<div id="floating_inline" style="float:left">FI</div>
+<div id="floating_style">FS</div>
+<!-- Test Element opacity functions -->
+<img id="op1" alt="op2" src="fixtures/logo.gif" style="opacity:0.5;filter:alpha(opacity=50)" />
+<img id="op2" alt="op2" src="fixtures/logo.gif"/>
+<img id="op3" alt="op3" src="fixtures/logo.gif"/>
+<img id="op4-ie" alt="op3" src="fixtures/logo.gif" style="filter:alpha(opacity=30)" />
+<div id="dimensions-visible"></div>
+<div id="dimensions-display-none"></div>
+<div id="dimensions-visible-pos-rel"></div>
+<div id="dimensions-display-none-pos-rel"></div>
+<div id="dimensions-visible-pos-abs"></div>
+<div id="dimensions-display-none-pos-abs"></div>
+<table border="0" cellspacing="0" cellpadding="0" id="dimensions-table">
+ <tbody id="dimensions-tbody">
+ <tr id="dimensions-tr">
+ <td id="dimensions-td">Data</td>
+ </tr>
+ </tbody>
+</table>
+
+<div id="dimensions-nester" style="width: 500px;">
+ <div id="dimensions-nestee" style="display: none">This is a nested DIV. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
+</div>
+
+
+<p id="test-empty"></p>
+<p id="test-empty-but-contains-whitespace">
+
+
+</p>
+<p id="test-full">content</p>
+<div id="ancestor">
+ <div id="child">
+ <div id="grand-child">
+ <div id="great-grand-child"></div>
+ </div></div><!-- intentional formatting; don't change this line -->
+ <div id="sibling"><div id="grand-sibling"></div></div>
+</div>
+<div id="not-in-the-family"></div>
+
+<div id="insertions-container"><div id="insertions-main"><p>some content.</p></div></div>
+<div id="insertions-node-container"><div id="insertions-node-main"><p>some content.</p></div></div>
+<div id="element-insertions-container"><div id="element-insertions-main"><p>some content.</p></div></div>
+<div id="element-insertions-multiple-container"><div id="element-insertions-multiple-main"><p>some content.</p></div></div>
+<table id="table_for_insertions"></table>
+<table id="table_for_row_insertions"><tr id="row_1"></tr></table>
+<form method="post" action="blah">
+ <select id="select_for_update" name="select_for_update">
+ <option>option 1</option>
+ <option>option 2</option>
+ </select>
+ <select id="select_for_insert_bottom" name="select_for_insert_bottom">
+ <option>option 1</option>
+ <option>option 2</option>
+ </select>
+ <select id="select_for_insert_top" name="select_for_insert_top">
+ <option>option 1</option>
+ <option>option 2</option>
+ </select>
+</form>
+<div id="wrap-container"><p id="wrap"></p></div>
+
+<!-- Positioning methods bench -->
+<div id="body_absolute" style="position: absolute; top: 10px; left: 10px">
+ <div id="absolute_absolute" style="position: absolute; top: 10px; left:10px"> </div>
+ <div id="absolute_relative" style="position: relative; top: 10px; left:10px">
+ <div style="height:10px;font-size:2px">test<span id="inline">test</span></div>
+ <div id="absolute_relative_undefined">XYZ</div>
+ </div>
+ <div id="absolute_fixed" style="position: fixed; top: 10px; left: 10px">
+ <span id="absolute_fixed_absolute" style="position: absolute; top: 10px; left: 10px">foo</span>
+ <span id="absolute_fixed_undefined" style="display:block">bar</span>
+ </div></div>
+<div id="notInlineAbsoluted"></div>
+<div id="inlineAbsoluted" style="position: absolute"></div>
+
+<div id="unextended"></div>
+<div id="identification">
+ <div id="predefined_id"></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div id="anonymous_element_3"></div>
+</div>
+
+<div id='elementToViewportDimensions' style='display: none'></div>
+<div id="auto_dimensions" style="height:auto"></div>
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/element_mixins_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/element_mixins_test.html
new file mode 100644
index 0000000000..51a789e79b
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/element_mixins_test.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Element mixins</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+ <script src="../fixtures/element_mixins.js" type="text/javascript" charset="utf-8"></script>
+
+
+ <script src="../element_mixins_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Element mixins</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<form id="form">
+ <input type="text" id="input" value="4" />
+ <input type="submit" />
+</form>
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/enumerable_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/enumerable_test.html
new file mode 100644
index 0000000000..8f462b6395
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/enumerable_test.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Enumerable</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+ <script src="../fixtures/enumerable.js" type="text/javascript" charset="utf-8"></script>
+
+
+ <script src="../enumerable_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Enumerable</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<table id="grepTable">
+<tbody id="grepTBody">
+ <tr id="grepRow">
+ <th id="grepHeader" class="cell"></th>
+ <td id="grepCell" class="cell"></td>
+ </tr>
+</tbody>
+</table>
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/event_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/event_test.html
new file mode 100644
index 0000000000..12accf239f
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/event_test.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Event</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+
+ <script src="../event_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Event</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<div id="outer" style="display: none">
+ <p id="inner">One two three <span id="span">four</span></p>
+</div>
+<div id="container"><div></div></div>
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/form_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/form_test.html
new file mode 100644
index 0000000000..14349eb511
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/form_test.html
@@ -0,0 +1,150 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Form</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+
+ <script src="../form_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Form</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<form id="form" method="get" action="fixtures/empty.js">
+ <input type="text" name="val1" id="input_enabled" value="4" />
+ <div>This is not a form element</div>
+ <input type="text" name="val2" id="input_disabled" disabled="disabled" value="5" />
+ <input type="submit" name="first_submit" value="Commit it!" />
+ <input type="submit" name="second_submit" value="Delete it!" />
+ <input type="text" name="action" value="blah" />
+</form>
+
+<form id="bigform" method="get" action="fixtures/empty.js">
+ <div id="inputs">
+ <input type="text" name="dummy" id="dummy_disabled" disabled="disabled"/>
+ <input type="submit" name="commit" id="submit" />
+ <input type="button" name="clicky" value="click me" />
+ <input type="reset" name="revert" />
+ <input type="text" name="greeting" id="focus_text" value="Hello" />
+ </div>
+
+ <div id="buttons">
+ <button type="button" id="button_type_button" name="button">Click Me</button>
+ </div>div>
+
+ <!-- some edge cases in serialization -->
+ <div id="value_checks">
+ <input name="twin" type="text" value="" />
+ <input name="twin" type="text" value="siamese" />
+ <!-- Rails checkbox hack with hidden input: -->
+ <input name="checky" type="checkbox" id="checkbox_hack" value="1" />
+ <input name="checky" type="hidden" value="0" />
+ </div>
+
+ <!-- all variations of SELECT controls -->
+ <div id="selects_wrapper">
+ <select name="vu">
+ <option value="1" selected="selected">One</option>
+ <option value="2">Two</option>
+ <option value="3">Three</option>
+ </select>
+ <select id="multiSel1" name="vm[]" multiple="multiple">
+ <option id="multiSel1_opt1" value="1" selected="selected">One</option>
+ <option id="multiSel1_opt2" value="2">Two</option>
+ <option id="multiSel1_opt3" value="3" selected="selected">Three</option>
+ </select>
+ <select name="nvu">
+ <option selected="selected">One</option>
+ <option value="2">Two</option>
+ <option value="3">Three</option>
+ </select>
+
+ <fieldset id="selects_fieldset">
+ <select name="nvm[]" multiple="multiple">
+ <option selected="selected">One</option>
+ <option>Two</option>
+ <option selected="selected">Three</option>
+ </select>
+ <select name="evu">
+ <option value="" selected="selected">One</option>
+ <option value="2">Two</option>
+ <option value="3">Three</option>
+ </select>
+ <select name="evm[]" multiple="multiple">
+ <option value="" selected="selected">One</option>
+ <option>Two</option>
+ <option selected="selected">Three</option>
+ </select>
+ </fieldset>
+ </div>
+
+ <div id="various">
+ <select name="tf_selectOne"><option selected="selected"></option><option>1</option></select>
+ <textarea name="tf_textarea"></textarea>
+ <input type="checkbox" name="tf_checkbox" value="on" />
+ <select name="tf_selectMany" multiple="multiple"></select>
+ <input type="text" name="tf_text" />
+ <div>This is not a form element</div>
+ <input type="radio" name="tf_radio" value="on" />
+ <input type="hidden" name="tf_hidden" />
+ <input type="password" name="tf_password" />
+ </div>
+</form>
+
+<form id="form_focus_hidden" style="display: none">
+ <input type="text" />
+</form>
+
+<form id="form_with_file_input">
+ <input type="file" name="file_name" value="foo" />
+</form>
+
+<!-- tabindexed forms -->
+<div id="tabindex">
+ <form id="ffe">
+ <p><input type="text" disabled="disabled" id="ffe_disabled" /></p>
+ <input type="hidden" id="ffe_hidden" />
+ <input type="checkbox" id="ffe_checkbox" />
+ </form>
+
+ <form id="ffe_ti">
+ <p><input type="text" disabled="disabled" id="ffe_ti_disabled" /></p>
+ <input type="hidden" id="ffe_ti_hidden" />
+ <input type="checkbox" id="ffe_ti_checkbox" />
+ <input type="submit" id="ffe_ti_submit" tabindex="1" />
+ </form>
+
+ <form id="ffe_ti2">
+ <p><input type="text" disabled="disabled" id="ffe_ti2_disabled" /></p>
+ <input type="hidden" id="ffe_ti2_hidden" />
+ <input type="checkbox" id="ffe_ti2_checkbox" tabindex="0" />
+ <input type="submit" id="ffe_ti2_submit" tabindex="1" />
+ </form>
+
+</div>
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/hash_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/hash_test.html
new file mode 100644
index 0000000000..4e4f0be75d
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/hash_test.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Hash</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+ <script src="../fixtures/hash.js" type="text/javascript" charset="utf-8"></script>
+
+
+ <script src="../hash_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Hash</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/number_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/number_test.html
new file mode 100644
index 0000000000..85eed3191b
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/number_test.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Number</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+
+ <script src="../number_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Number</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/position_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/position_test.html
new file mode 100644
index 0000000000..78ed551d0e
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/position_test.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Position</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+
+ <script src="../position_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Position</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<div id="ensure_scrollbars" style="width:10000px; height:10000px; position:absolute" > </div>
+
+<div id="body_absolute" style="position: absolute; top: 10px; left: 10px">
+ <div id="absolute_absolute" style="position: absolute; top: 10px; left:10px"> </div>
+ <div id="absolute_relative" style="position: relative; top: 10px; left:10px">
+ <div style="height:10px;font-size:2px">test<span id="inline">test</span></div>
+ <div id="absolute_relative_undefined"> </div>
+ </div>
+</div>
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/range_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/range_test.html
new file mode 100644
index 0000000000..cbc6f828b6
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/range_test.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Range</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+
+ <script src="../range_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Range</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/selector_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/selector_test.html
new file mode 100644
index 0000000000..84bde55e50
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/selector_test.html
@@ -0,0 +1,107 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Selector</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+
+ <script src="../selector_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Selector</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<div id="fixtures" style="display: none">
+ <h1 class="title">Some title <span>here</span></h1>
+ <p id="p" class="first summary">
+ <strong id="strong">This</strong> is a short blurb
+ <a id="link_1" class="first internal" rel="external nofollow" href="#">with a <em id="em2">link</em></a> or
+ <a id="link_2" class="internal highlight" href="#"><em id="em">two</em></a>.
+ Or <cite id="with_title" title="hello world!">a citation</cite>.
+ </p>
+ <ul id="list">
+ <li id="item_1" class="first"><a id="link_3" href="#" class="external"><span id="span">Another link</span></a></li>
+ <li id="item_2">Some text</li>
+ <li id="item_3" xml:lang="es-us" class="">Otra cosa</li>
+ </ul>
+
+ <!-- this form has a field with the name 'id',
+ therefore its ID property won't be 'troubleForm': -->
+ <form id="troubleForm">
+ <input type="hidden" name="id" id="hidden" />
+ <input type="text" name="disabled_text_field" id="disabled_text_field" disabled="disabled" />
+ <input type="text" name="enabled_text_field" id="enabled_text_field" />
+ <input type="checkbox" name="checkboxes" id="checked_box" checked="checked" value="Checked" />
+ <input type="checkbox" name="checkboxes" id="unchecked_box" value="Unchecked"/>
+ <input type="radio" name="radiobuttons" id="checked_radio" checked="checked" value="Checked" />
+ <input type="radio" name="radiobuttons" id="unchecked_radio" value="Unchecked" />
+ </form>
+
+ <form id="troubleForm2">
+ <input type="checkbox" name="brackets[5][]" id="chk_1" checked="checked" value="1" />
+ <input type="checkbox" name="brackets[5][]" id="chk_2" value="2" />
+ </form>
+
+ <div id="level1">
+ <span id="level2_1">
+ <span id="level3_1"></span>
+ <!-- This comment should be ignored by the adjacent selector -->
+ <span id="level3_2"></span>
+ </span>
+ <span id="level2_2">
+ <em id="level_only_child">
+ </em>
+ </span>
+ <div id="level2_3"></div>
+ </div> <!-- #level1 -->
+
+ <div id="dupContainer">
+ <span id="dupL1" class="span_foo span_bar">
+ <span id="dupL2">
+ <span id="dupL3">
+ <span id="dupL4">
+ <span id="dupL5"></span>
+ </span>
+ </span>
+ </span>
+ </span>
+ </div> <!-- #dupContainer -->
+
+ <div id="grandfather"> grandfather
+ <div id="father" class="brothers men"> father
+ <div id="son"> son </div>
+ </div>
+ <div id="uncle" class="brothers men"> uncle </div>
+ </div>
+
+ <form id="commaParent" title="commas,are,good">
+ <input type="hidden" id="commaChild" name="foo" value="#commaOne,#commaTwo" />
+ <input type="hidden" id="commaTwo" name="foo2" value="oops" />
+ </form>
+ <div id="counted_container"><div class="is_counted"></div></div>
+</div>
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/string_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/string_test.html
new file mode 100644
index 0000000000..74564fc0ce
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/string_test.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | String</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+ <script src="../fixtures/string.js" type="text/javascript" charset="utf-8"></script>
+
+
+ <script src="../string_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>String</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/tmp/unit_test.html b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/unit_test.html
new file mode 100644
index 0000000000..b684225ba5
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/tmp/unit_test.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>Prototype Unit test file | Unittest</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <script type="text/javascript" charset="utf-8">
+ var eventResults = {};
+ var originalElement = window.Element;
+ </script>
+ <script src="../../../dist/prototype.js" type="text/javascript"></script>
+ <script src="../../lib/unittest.js" type="text/javascript"></script>
+ <link rel="stylesheet" href="../../test.css" type="text/css" />
+
+
+
+
+
+ <script src="../unittest_test.js" type="text/javascript"></script>
+</head>
+<body>
+<h1>Prototype Unit test file</h1>
+<h2>Unittest</h2>
+
+<!-- This file is programmatically generated. Do not attempt to modify it. Instead, modify -->
+
+<!-- Log output start -->
+<div id="testlog"></div>
+<!-- Log output end -->
+
+<!-- HTML Fixtures start -->
+<div id="testlog_2"> </div>
+
+<!-- Test elements follow -->
+<div id="test_1" class="a bbbbbbbbbbbb cccccccccc dddd"> </div>
+
+<div id="test_2"> <span> </span>
+
+
+
+<div><div></div> </div><span> </span>
+</div>
+
+<ul id="tlist"><li id="tlist_1">x1</li><li id="tlist_2">x2</li></ul>
+<ul id="tlist2"><li class="a" id="tlist2_1">x1</li><li id="tlist2_2">x2</li></ul>
+
+<div id="testmoveby" style="background-color:#333;width:100px;">XXXX</div>
+
+<div id="testcss1">testcss1<span id="testcss1_span" style="display:none;">blah</span></div><div id="testcss2">testcss1</div>
+
+<!-- HTML Fixtures end -->
+</body>
+</html>
+<script type="text/javascript" charset="utf-8">
+ eventResults.endOfDocument = true;
+</script>
diff --git a/dom/tests/mochitest/ajax/prototype/test/unit/unittest_test.js b/dom/tests/mochitest/ajax/prototype/test/unit/unittest_test.js
new file mode 100644
index 0000000000..e7afdd60bf
--- /dev/null
+++ b/dom/tests/mochitest/ajax/prototype/test/unit/unittest_test.js
@@ -0,0 +1,143 @@
+var testObj = {
+ isNice: function() {
+ return true;
+ },
+ isBroken: function() {
+ return false;
+ }
+}
+
+new Test.Unit.Runner({
+
+ testBuildMessage: function() {
+ this.assertEqual("'foo' 'bar'", this.buildMessage('', '? ?', 'foo', 'bar'))
+ },
+
+ testAssertEqual: function() {
+ this.assertEqual(0, 0);
+ this.assertEqual(0, 0, "test");
+
+ this.assertEqual(0,'0');
+ this.assertEqual(65.0, 65);
+
+ this.assertEqual("a", "a");
+ this.assertEqual("a", "a", "test");
+
+ this.assertNotEqual(0, 1);
+ this.assertNotEqual("a","b");
+ this.assertNotEqual({},{});
+ this.assertNotEqual([],[]);
+ this.assertNotEqual([],{});
+ },
+
+ testAssertEnumEqual: function() {
+ this.assertEnumEqual([], []);
+ this.assertEnumEqual(['a', 'b'], ['a', 'b']);
+ this.assertEnumEqual(['1', '2'], [1, 2]);
+ this.assertEnumNotEqual(['1', '2'], [1, 2, 3]);
+ },
+
+ testAssertHashEqual: function() {
+ this.assertHashEqual({}, {});
+ this.assertHashEqual({a:'b'}, {a:'b'});
+ this.assertHashEqual({a:'b', c:'d'}, {c:'d', a:'b'});
+ this.assertHashNotEqual({a:'b', c:'d'}, {c:'d', a:'boo!'});
+ },
+
+ testAssertRespondsTo: function() {
+ this.assertRespondsTo('isNice', testObj);
+ this.assertRespondsTo('isBroken', testObj);
+ },
+
+ testAssertIdentical: function() {
+ this.assertIdentical(0, 0);
+ this.assertIdentical(0, 0, "test");
+ this.assertIdentical(1, 1);
+ this.assertIdentical('a', 'a');
+ this.assertIdentical('a', 'a', "test");
+ this.assertIdentical('', '');
+ this.assertIdentical(undefined, undefined);
+ this.assertIdentical(null, null);
+ this.assertIdentical(true, true);
+ this.assertIdentical(false, false);
+
+ var obj = {a:'b'};
+ this.assertIdentical(obj, obj);
+
+ this.assertNotIdentical({1:2,3:4},{1:2,3:4});
+
+ this.assertIdentical(1, 1.0); // both are typeof == 'number'
+
+ this.assertNotIdentical(1, '1');
+ this.assertNotIdentical(1, '1.0');
+ },
+
+ testAssertNullAndAssertUndefined: function() {
+ this.assertNull(null);
+ this.assertNotNull(undefined);
+ this.assertNotNull(0);
+ this.assertNotNull('');
+ this.assertNotUndefined(null);
+ this.assertUndefined(undefined);
+ this.assertNotUndefined(0);
+ this.assertNotUndefined('');
+ this.assertNullOrUndefined(null);
+ this.assertNullOrUndefined(undefined);
+ this.assertNotNullOrUndefined(0);
+ this.assertNotNullOrUndefined('');
+ },
+
+ testAssertMatch: function() {
+ this.assertMatch(/knowmad.jpg$/, 'http://script.aculo.us/images/knowmad.jpg');
+ this.assertMatch(/Fuc/, 'Thomas Fuchs');
+ this.assertMatch(/^\$(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/, '$19.95');
+ this.assertMatch(/(\d{3}\) ?)|(\d{3}[- \.])?\d{3}[- \.]\d{4}(\s(x\d+)?){0,1}$/, '704-343-9330');
+ this.assertMatch(/^(?:(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\/|-|\.)(?:0?2\1(?:29)))|(?:(?:(?:1[6-9]|[2-9]\d)?\d{2})(\/|-|\.)(?:(?:(?:0?[13578]|1[02])\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\2(?:0?[1-9]|1\d|2[0-8]))))$/, '2001-06-16');
+ this.assertMatch(/^((0?[123456789])|(1[012]))\s*:\s*([012345]\d)(\s*:\s*([012345]\d))?\s*[ap]m\s*-\s*((0?[123456789])|(1[012]))\s*:\s*([012345]\d)(\s*:\s*([012345]\d))?\s*[ap]m$/i, '2:00PM-2:15PM');
+ this.assertNoMatch(/zubar/, 'foo bar');
+ },
+
+ testAssertInstanceOf: function() {
+ this.assertInstanceOf(String, new String);
+ this.assertInstanceOf(RegExp, /foo/);
+ this.assertNotInstanceOf(String, {});
+ },
+
+ testAssertVisible: function() {
+ this.assertVisible('testcss1');
+ this.assertNotVisible('testcss1_span');
+ //this.assertNotVisible('testcss2', "Due to a Safari bug, this test fails in Safari.");
+
+ Element.hide('testcss1');
+ this.assertNotVisible('testcss1');
+ this.assertNotVisible('testcss1_span');
+ Element.show('testcss1');
+ this.assertVisible('testcss1');
+ this.assertNotVisible('testcss1_span');
+
+ Element.show('testcss1_span');
+ this.assertVisible('testcss1_span');
+ Element.hide('testcss1');
+ this.assertNotVisible('testcss1_span'); // hidden by parent
+ },
+
+ testAssertElementsMatch: function() {
+ this.assertElementsMatch($$('#tlist'), '#tlist');
+ this.assertElementMatches($('tlist'), '#tlist');
+ }
+});
+
+/* This test was disabled in bug 486256, because we don't support having two
+ * Runners in one file.
+ */
+/*
+new Test.Unit.Runner({
+ testDummy: function() {
+ this.assert(true);
+ },
+
+ testMultipleTestRunner: function() {
+ this.assertEqual('passed', $('testlog_2').down('td', 1).innerHTML);
+ }
+}, {testLog: 'testlog_2'});
+*/