From b9d78efa7edf42cbeb0bdc9489047bb556965f9d Mon Sep 17 00:00:00 2001 From: Nick Galbreath Date: Sun, 25 Apr 2010 17:13:35 +0000 Subject: [PATCH] massive form cleanup, hundreds of new unit tests. runs in FF. --- specs/html/spec.js | 145 +++++++++++++++++++-- specs/parser/boot.js | 1 + specs/parser/spec.js | 253 ++++++++++++++++++++++++++++++++++++- src/html/area.js | 2 +- src/html/button.js | 8 +- src/html/collection.js | 35 +++-- src/html/document.js | 22 ++-- src/html/form.js | 13 +- src/html/input-elements.js | 12 -- src/html/input.js | 43 ++++++- src/html/option.js | 119 ++++++++++------- src/html/select.js | 115 +++++++++-------- src/html/textarea.js | 33 +++-- src/parser/htmldocument.js | 3 + 14 files changed, 625 insertions(+), 179 deletions(-) diff --git a/specs/html/spec.js b/specs/html/spec.js index d01141e4..4e7fcaca 100644 --- a/specs/html/spec.js +++ b/specs/html/spec.js @@ -47,7 +47,7 @@ test('HTML Interfaces Available', function(){ ok(HTMLParamElement, 'HTMLParamElement defined'); ok(HTMLScriptElement, 'HTMLScriptElement defined'); ok(HTMLSelectElement, 'HTMLSelectElement defined'); - ok(HTMLSpanElement, 'HTMLSpanElement defined'); + ok(HTMLSpanElement, 'HTMLSpanElement defined'); ok(HTMLStyleElement, 'HTMLStyleElement defined'); ok(HTMLTableElement, 'HTMLTableElement defined'); ok(HTMLTableSectionElement, 'HTMLTableSectionElement defined'); @@ -299,6 +299,9 @@ test('HTMLAreaElement', function(){ equals(element.parentNode, null, '.parentNode'); equals(element.prefix, null, '.prefix'); equals(xmlserializer.serializeToString(element), '', 'xmlserializer'); + equals(element.alt, '', 'alt'); + element.alt = 'foo'; + equals(element.alt, 'foo', 'set alt'); equals(element.toString(), '', 'toString returns href'); element.href = 'http://envjs.com/'; @@ -332,6 +335,7 @@ test('HTMLDocument.createElement(frame)', function(){ equals(element.scrolling, "", '.scrolling'); equals(element.src, "", '.src'); equals(element.tagName, 'FRAME', '.name'); + equals(element.toString(), '[object HTMLFrameElement]', 'toString'); equals(xmlserializer.serializeToString(element), '', 'xmlserializer'); }); @@ -391,6 +395,20 @@ test('HTMLBRElement', function() { equals(a.toString(), '[object HTMLBRElement]'); }); +test('HTMLButtonElement', function() { + var e; + e = document.createElement('button'); + ok(e, 'element created'); + equals(e.toString(), '[object HTMLButtonElement]', 'toString'); + + equals(e.type, 'submit', 'type'); + equals(e.value, '', 'empty button value'); + equals(typeof e.value, 'string', 'empty button value is string'); + + e.value = 'foo'; + equals(e.value, 'foo', 'set value'); +}); + test('HTMLDivElement', function() { var a = document.createElement('div'); ok(a, 'element created'); @@ -428,12 +446,37 @@ test('HTMLInputElement', function() { equals(a.alt, '', 'empty alt is string'); a.alt = 'foo'; equals(a.alt, 'foo', 'set alt'); - + equals(a.type, 'text', 'type'); equals(a.src, '', 'empty src is string'); a.src = 'http://envjs.com/'; equals(a.src, 'http://envjs.com/', 'set src'); // TODO, src should make absolute any relative links + /** + * 'value' is a virtual state, NOT an attribute + * + */ + // relationship between defaultValue and Value + equals(a.value, '', 'default value'); + equals(a.defaultValue, '', 'default defaultValue'); + + a.defaultValue = 'bar'; + equals(a.defaultValue, 'bar', 'set defaultValue'); + equals(a.value, 'bar', 'value is initially set by defaultValue'); + + a.value = 'foo'; + equals(a.value, 'foo', 'set value'); + equals(a.defaultValue, 'bar', 'defaultValue is unchanged'); + + a.defaultValue = 'dingbat'; + equals(a.defaultValue, 'dingbat', 'set defaultValue'); + equals(a.value, 'foo', 'value is unchanged'); + + // test with DOMAPI + a.setAttribute('value', 'foobar'); + equals(a.defaultValue, 'foobar', 'set defaultValue via DOMAPI'); + equals(a.value, 'foo', 'value is unchanged'); + /** * Checked is a virtual state, NOT an attribute * @@ -463,6 +506,7 @@ test('HTMLInputElement', function() { equals(a.useMap, '', 'useMap is false'); equals(typeof a.useMap, 'string', 'default useMap value is boolean'); + /** * Numeric-like things */ @@ -542,6 +586,22 @@ test('HTMLMetaElement', function() { equals(element.getAttribute('content'), 'foo', 'get content via attribute'); }); +test('HTMLModElement', function() { + var a = document.createElement('del'); + ok(a, 'element created'); + //equals(a.toString(), '[object HTMLModElement]'); + + a = document.createElement('ins'); + ok(a, 'element created'); + //equals(a.toString(), '[object HTMLModElement]'); +}); + +test('HTMLObjectElement', function() { + var a = document.createElement('object'); + ok(a, 'element created'); + equals(a.toString(), '[object HTMLObjectElement]'); +}); + test('HTMLOListElement', function() { var a = document.createElement('ol'); ok(a, 'element created'); @@ -578,6 +638,26 @@ test('HTMLQuoteElement', function() { // See http://dev.w3.org/html5/spec/Overview.html#dom-quote-cite }); +test('HTMLSelectElement', function() { + var a = document.createElement('select'); + ok(a, 'element created'); + equals(a.toString(), '[object HTMLSelectElement]'); + + equals(a.value, '', 'value'); + equals(a.length, 0, 'length'); + equals(a.selectedIndex, -1, 'selectedIndex'); + equals(a.type, 'select-one', 'type'); + + equals(a.multiple, false, 'multiple'); + a.multiple = true; + equals(a.multiple, true, 'set multiple'); + equals(a.hasAttribute('multiple'), true, 'set multiple has attribute'); + equals(a.getAttribute('multiple'), '', 'set multiple set attribute'); + a.multiple = false; + equals(a.hasAttribute('multiple'), false, + 'set multiple removes attribute'); +}); + test('HTMLSpanElement', function() { var a = document.createElement('span'); ok(a, 'element created'); @@ -604,8 +684,8 @@ test('HTMLTableDataCellElement', function() { ok(element, 'element created'); if (runningUnderEnvjs()) equals(element.toString(), '[object HTMLTableDataCellElement]', - 'toString'); - // don't run in-browser, FF uses HTMLTableCellElement + 'toString'); + // don't run in-browser, FF uses HTMLTableCellElement }); test('HTMLTableHeaderCellElement', function() { @@ -614,8 +694,8 @@ test('HTMLTableHeaderCellElement', function() { ok(element, 'element created'); if (runningUnderEnvjs()) equals(element.toString(), '[object HTMLTableHeaderCellElement]', - 'toString'); - // don't run in-browser, FF uses HTMLTableCellElement + 'toString'); + // don't run in-browser, FF uses HTMLTableCellElement }); test('HTMLTableRowElement', function() { @@ -638,6 +718,7 @@ test('HTMLTextArea', function() { ok(e, 'element created'); equals(e.toString(), '[object HTMLTextAreaElement]', 'toString'); + equals(e.type, 'textarea', 'type'); equals(e.cols, -1, 'default cols is -1'); e.cols = '10'; equals(e.cols, 10, 'set cols'); @@ -648,6 +729,41 @@ test('HTMLTextArea', function() { equals(e.rows, 11, 'set row'); equals(typeof e.rows, 'number', 'rows is a number'); + // relationship between defaultValue and Value + equals(e.value, '', 'default value'); + equals(e.defaultValue, '', 'default defaultValue'); + + e.defaultValue = 'bar'; + equals(e.defaultValue, 'bar', 'set defaultValue'); + equals(e.value, 'bar', 'value is initially set by defaultValue'); + + e.value = 'foo'; + equals(e.value, 'foo', 'set value'); + equals(e.defaultValue, 'bar', 'defaultValue is unchanged'); + + e.defaultValue = 'dingbat'; + equals(e.defaultValue, 'dingbat', 'set defaultValue'); + equals(e.value, 'foo', 'value is unchanged'); + + // change 'value' via DOMAPI setAttribute + e.value = 'foo'; + e.defaultValue = 'bar'; + + // "setAttribute(value)" does nothing since the value of textarea is + // really in it's textContent child + e.setAttribute('value', 'dingbat'); + equals(e.value, 'foo', 'value is NOT set via DOMAPI'); + equals(e.defaultValue, 'bar', 'defaultValue is NOT set via setattr'); + equals(e.textContent, 'bar', 'textContent is NOT set via setattr'); + + e.textContent = 'dingbat'; + equals(e.textContent, 'dingbat', 'set textContent'); + equals(e.value, 'foo', 'value is NOT set via textContent'); + equals(e.defaultValue, 'dingbat', 'defaultValue is set via textContent'); + + + // TODO: normalization of rawvalue + }); test('HTMLTitleElement', function() { @@ -710,6 +826,7 @@ test("Option", function() { equals(x.tagName, 'OPTION', 'constructor sets tagName'); equals(x.form, null, 'get form is null'); equals(x.selected, false, 'selected is false'); + equals(typeof x.type, 'undefined', 'type is undefined'); x = new Option('text'); equals(x.text, 'text', 'text content'); @@ -719,11 +836,19 @@ test("Option", function() { x = new Option('text', 'value'); equals(x.text, 'text', 'text content'); equals(x.value, 'value', 'value attribute'); + equals(x.index, -1, 'index'); + equals(x.form, null, 'form'); + equals(x.selected, false, 'selected is false'); + x.selected = true; + equals(x.selected, true, 'set selected'); - // TODO: defaultSelect, and selected arguments - // Missing since logic to compute 'selectedness' is busted. - x = new Option('text', 'value', true); - x = new Option('text', 'value', true, true); + equals(x.defaultSelected, false, 'defaultselected'); + x.defaultSelected = true; + equals(x.defaultSelected, true, 'set defaultselected'); + x.defaultSelected = false; + equals(x.defaultSelected, false, 'set defaultselected'); + x = new Option('text1', 'value1'); + x = new Option('text2', 'value2', true, true); }); diff --git a/specs/parser/boot.js b/specs/parser/boot.js index e2259808..7a7a0fc1 100644 --- a/specs/parser/boot.js +++ b/specs/parser/boot.js @@ -5,6 +5,7 @@ load('specs/qunit.js'); load('specs/env.qunit.js'); +load('specs/helpers.js'); QUnit.init(); load('dist/platform/core.js'); diff --git a/specs/parser/spec.js b/specs/parser/spec.js index 11497678..e678d1df 100644 --- a/specs/parser/spec.js +++ b/specs/parser/spec.js @@ -1,5 +1,12 @@ QUnit.module('parser'); +var isenvjs; +try { + isenvjs = runningUnderEnvjs(); +} catch (e) { + isenvjs= false; +} + test('Parser Interfaces Available', function(){ expect(1); @@ -390,7 +397,7 @@ test('Form Named Element Lookup', function(){ // let's change the name var node = form.input1; node.name = 'input2'; - ok(elements.input1 instanceof HTMLInputElement, 'is HTMLInputElement'); + ok(form.input2 instanceof HTMLInputElement, 'is HTMLInputElement'); ok(form.input1 instanceof HTMLInputElement, 'is HTMLInputElement'); /* @@ -407,3 +414,247 @@ test('Form Named Element Lookup', function(){ doc.close(); stop(); }); + + +function testForm(doc, isenvjs) { + var form = doc.foo; + var elements = form.elements; + ok(elements instanceof HTMLCollection, + "form.elements is an HTMLCollection"); + equals(elements.length, 6, "form.elements.length"); + equals(form.length, 6, "form.length"); + + + // not yet supported by FF 3.6 + //equals(form.namedItem('e1').value, 'v1', 'form.namedItem(e1).value'); + //equals(form.item(0).value, 'v1', 'form.item(0).value'); + + equals(form.e1.value, 'v1', 'form.e1.value'); + equals(form.e2.value, 'v2', 'form.e2.value'); + equals(form.e3.value, 'v3', 'form.e3.value'); + equals(form.e4.value, 'v4', 'form.e4.value'); + equals(form.e5.value, 'v5', 'form.e5.value'); + equals(form.e6.value, 'v6', 'form.e6.value'); + + // quick tests of HTMLCollection + equals(form.elements.toString(), '[object HTMLCollection]', + 'form.elements.toString()'); + equals(form.elements[1234], null, 'form.elements[12340]'); + equals(form.elements.item(1234), null, 'form.elements.item(12340)'); + equals(form.elements.namedItem('foo'), null, 'form.elements.namedItem(foo)'); + + equals(form.elements.e1.value, 'v1', 'form.elements.e1.value'); + equals(form.elements.e2.value, 'v2', 'form.elements.e2.value'); + equals(form.elements.e3.value, 'v3', 'form.elements.e3.value'); + equals(form.elements.e4.value, 'v4', 'form.elements.e4.value'); + equals(form.elements.e5.value, 'v5', 'form.elements.e5.value'); + equals(form.elements.e6.value, 'v6', 'form.elements.e6.value'); + + // direct array lookup + equals(form.elements[0].value, 'v1', 'form.elements[0].value'); + equals(form.elements[1].value, 'v2', 'form.elements[1].value'); + equals(form.elements[2].value, 'v3', 'form.elements[2].value'); + equals(form.elements[3].value, 'v4', 'form.elements[3].value'); + equals(form.elements[4].value, 'v5', 'form.elements[4].value'); + equals(form.elements[5].value, 'v6', 'form.elements[5].value'); + + // namedItems + equals(form.elements.namedItem('e1').value, 'v1', + 'form.elements.namedItem(e1).value'); + equals(form.elements.namedItem('e2').value, 'v2', + 'form.elements.namedItem(e2).value'); + equals(form.elements.namedItem('e3').value, 'v3', + 'form.elements.namedItem(e3).value'); + equals(form.elements.namedItem('e4').value, 'v4', + 'form.elements.namedItem(e4).value'); + equals(form.elements.namedItem('e5').value, 'v5', + 'form.elements.namedItem(e5).value'); + equals(form.elements.namedItem('e6').value, 'v6', + 'form.elements.namedItem(e6).value'); + + + // items + equals(form.elements.item(0).value, 'v1', + 'form.elements.item(e1).value'); + equals(form.elements.item(1).value, 'v2', + 'form.elements.item(e2).value'); + equals(form.elements.item(2).value, 'v3', + 'form.elements.item(e3).value'); + equals(form.elements.item(3).value, 'v4', + 'form.elements.item(e4).value'); + equals(form.elements.item(4).value, 'v5', + 'form.elements.item(e5).value'); + equals(form.elements.item(5).value, 'v6', + 'form.elements.item(e6).value'); + + // Options + equals(form.e5[0].value, 'v5', 'form.e5[0]'); + equals(form.e5[1].value, 'opt2', 'form.e5[1]'); + + + equals(form.e5.item(0).value, 'v5', 'form.e5.item(0)'); + equals(form.e5.item(1).value, 'opt2', 'form.e5.item(1)'); + + + equals(form.e5.options.length, 2, 'form.e5.options.length'); + equals(form.e5.options[0].value, 'v5', 'form.e5.options[0].value'); + equals(form.e5.options[1].value, 'opt2', 'form.e5.options[1].value'); + equals(form.e5.options.item(0).value, 'v5', 'form.e5.options[0].value'); + equals(form.e5.options.item(1).value, 'opt2', 'form.e5.options[1].value'); + + // firefox bugs or incomplete behavior + // some of these run under the doc and innerHTML tests, but + // don't work under the DOMAPI test + if (isenvjs) { + equals(form.e5.options.namedItem('o1').value, 'v5', 'form.e5.options[0].value'); + equals(form.e5.options.namedItem('o2').value, 'opt2', 'form.e5.options[1].value'); + equals(form.e5['o1'].value, 'v5', 'form.e5[0]'); + equals(form.e5['o2'].value, 'opt2', 'form.e5[1]'); + + equals(form.e5.namedItem('o1').value, 'v5', 'form.e5.namedItem(o1)'); + equals(form.e5.namedItem('o2').value, 'opt2', 'form.e5.namedItem(o2)'); + } + + +} + + + +test('Form Named Elements via parser', function() { + if ((typeof Envjs == 'undefined') || !Envjs) { + Envjs = {}; + } + + // need to do this at top level since under FF, + // frames have different scope and this function isn't defined. + var iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + + iframe.addEventListener('load', function() { + var doc = iframe.contentDocument; + ok(true, 'frame loaded'); + testForm(doc, isenvjs); + document.body.removeChild(iframe); + start(); + }, false); + + var doc = iframe.contentDocument; + doc.write('
' + + '
' + // non-form element + '' + // input element + '' + // input element + '' + // text area + '' + // text area + '' + + '