diff default/node_modules/shoestring/test/unit/extensions.js @ 0:1d038bc9b3d2 default tip

Up:default
author Liny <dev@neowd.com>
date Sat, 31 May 2025 09:21:51 +0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/default/node_modules/shoestring/test/unit/extensions.js	Sat May 31 09:21:51 2025 +0800
@@ -0,0 +1,1929 @@
+(function(undefined){
+  var config, ss = shoestring;
+	var $fixture = shoestring( '#qunit-fixture' );
+
+	module( 'dom', config = {
+		setup: function() {
+			$fixture = shoestring( '#qunit-fixture' );
+		},
+
+		teardown: function() {
+			$fixture.unbind("foo");
+			$(document).unbind("foo");
+		}
+	});
+
+	test( '`.add()` adds selected elements to the set', function(){
+		var length, count;
+
+		length = $fixture.length;
+		count = shoestring( '.add' ).length;
+		$fixture = $fixture.add( '.add' );
+
+		ok( count > 0 );
+		equal( $fixture.length, length + count );
+	});
+
+	test( '`.addClass()` adds a classes when they doesnt exit', function(){
+		var $element = $fixture.find( '.add-class' );
+
+		$element.addClass( 'foo bar baz' );
+		equal( $element.attr( "class" ), "add-class foo bar baz" );
+	});
+
+	test( '`.addClass()` doesnt duplicate classes', function(){
+		var $element = $fixture.find( '.add-class' );
+
+		$element.addClass( 'add-class' );
+		equal( $element.attr( "class" ), "add-class" );
+	});
+
+	test( '`.after()` inserts a sibling after the current obj element', function(){
+		expect( 3 );
+		var $element = $fixture.find( '.after' );
+
+		equal( $fixture.find( '.foo-after' ).length, 0 );
+		$element.after( "<div class='foo-after'></div> ");
+		equal( $fixture.find( '.foo-after' ).length, 1 );
+
+		// sibling to .foo-after
+		$fixture.children().each(function(i) {
+			if( shoestring( this ).is( '.after' ) ){
+				equal( $fixture.children()[i+1].className, "foo-after" );
+			}
+		});
+	});
+
+	test( '`.after()` inserts siblings after the current obj element in the correct order', function(){
+		expect( 6 );
+		var $element = $fixture.find( '.after' );
+
+		equal( $fixture.find( '.foo-after' ).length, 0 );
+		equal( $fixture.find( '.foo-after2' ).length, 0 );
+		$element.after( "<div class='foo-after'></div><div class='foo-after2'></div> ");
+		equal( $fixture.find( '.foo-after' ).length, 1 );
+		equal( $fixture.find( '.foo-after2' ).length, 1 );
+
+		// sibling to .foo-after
+		$fixture.children().each(function(i) {
+			if( shoestring( this ).is( '.after' ) ){
+				equal( $fixture.children()[i+1].className, "foo-after" );
+				equal( $fixture.children()[i+2].className, "foo-after2" );
+			}
+		});
+	});
+
+	test( '`.insertAfter()` inserts after the selector', function(){
+		expect( 3 );
+
+		equal( $fixture.find( '.foo-after' ).length, 0 );
+		shoestring( "<div class='foo-after'></div> ").insertAfter( '.after' );
+		equal( $fixture.find( '.foo-after' ).length, 1 );
+
+		// sibling to .foo-after
+		$fixture.children().each(function(i) {
+			if( shoestring( this ).is( '.after' ) ){
+				equal( $fixture.children()[i+1].className, "foo-after" );
+			}
+		});
+	});
+
+	test( '`.append()` inserts a child in the current obj element', function(){
+		var $element = $fixture.find( '.append' );
+
+		equal( $element.find( '.foo-append' ).length, 0 );
+		$element.append( "<div class='foo-append'></div> ");
+		equal( $element.find( '.foo-append' ).length, 1 );
+	});
+
+	test( '`.insertAfter()` inserts after the selector', function(){
+		var $element = $fixture.find( '.append' );
+
+		equal( $element.find( '.foo-append' ).length, 0 );
+		shoestring( "<div class='foo-append'></div> ").appendTo( $element );
+		equal( $element.find( '.foo-append' ).length, 1 );
+	});
+
+	test( '`.attr()` returns undefined on empty set', function(){
+		var $element = $( '#this_will_not_match' );
+
+		equal( $element.attr( 'class' ), undefined );
+	});
+
+	test( '`.attr()` gets the attribute', function(){
+		var $element = $fixture.find( '.attr' );
+
+		equal( $element.attr( 'class' ), "attr" );
+	});
+
+	test( '`.attr()` sets the attribute', function(){
+		var $element = $fixture.find( '.attr' );
+
+		equal( $element.attr( 'class', "foo" ).attr( 'class' ), "foo" );
+	});
+
+	test( '`.before()` inserts a sibling before the current obj element', function(){
+		expect( 3 );
+		var $element = $fixture.find( '.before' );
+
+		equal( $fixture.find( '.foo-before' ).length, 0 );
+		$element.before( "<div class='foo-before'></div> ");
+		equal( $fixture.find( '.foo-before' ).length, 1 );
+
+		// sibling to .foo-before
+		$fixture.children().each(function(i) {
+			if( shoestring( this ).is( '.before' ) ){
+				equal( $fixture.children()[i-1].className, "foo-before" );
+			}
+		});
+	});
+
+	test( '`.data` and falsy values', function() {
+		var $fixture = shoestring( '#qunit-fixture' ),
+			$el;
+
+		$fixture.html( '<div id="el"></div>' );
+		$el = $( "#el" );
+
+		$el.data( "val-false", false );
+		strictEqual( $( '#el' ).data( "val-false" ), false );
+
+		$el.data( "val-zero", 0 );
+		strictEqual( $( '#el' ).data( "val-zero" ), 0 );
+
+		$el.data( "val-undefined", undefined );
+		strictEqual( $( '#el' ).data( "val-undefined" ), undefined );
+	});
+
+	test( '`.data` works on empty nodelists', function() {
+		var $fixture = shoestring( '#qunit-fixture' ),
+			$el;
+
+		$fixture.html( '<div id="el"></div>' );
+		$el = $( "#el" );
+
+		strictEqual( $( '#thiswontmatch' ).data(), undefined, 'should be undefined on an empty result set.' );
+		strictEqual( $( '#thiswontmatch' ).data( "somekey" ), undefined, 'should be undefined on an empty result set with a key passed in.' );
+
+		deepEqual( $( '#el' ).data(), {}, 'should be an empty object on an nonempty result set.' );
+		strictEqual( $( '#el' ).data( "somekey" ), undefined, 'should be undefined on an nonempty result set with a key passed in.' );
+	});
+
+	test( '`.data` does not alias to `data-` attributes', function() {
+		expect( 3 );
+		var $fixture = shoestring( '#qunit-fixture' ),
+			$el;
+
+		$fixture.html( '<div id="el" data-attr1 data-attr2="test"></div>' );
+		$el = $( "#el" );
+
+		strictEqual( $( '#el' ).data( "attr0" ), undefined, 'attribute does not exist, should not throw an error.' );
+
+		throws(function() {
+			$( '#el' ).data( "attr1" );
+		}, 'attribute exists but has no value, should have thrown a dev error.' );
+
+		throws(function() {
+			$( '#el' ).data( "attr2" );
+		}, 'attribute exists and has a value, should have thrown a dev error.' );
+	});
+
+	test( '`.insertBefore()` inserts before the selector', function(){
+		expect( 3 );
+
+		equal( $fixture.find( '.foo-before' ).length, 0 );
+		shoestring( "<div class='foo-before'></div> ").insertBefore( '.before' );
+		equal( $fixture.find( '.foo-before' ).length, 1 );
+
+		// sibling to .foo-before
+		$fixture.children().each(function(i) {
+			if( shoestring( this ).is( '.before' ) ){
+				equal( $fixture.children()[i-1].className, "foo-before" );
+			}
+		});
+	});
+
+	test( '`.clone()` prevents alteration of original', function() {
+		var $clone, $element;
+
+		$element = $fixture.find( ".clone" );
+		$clone = $element.clone();
+
+		equal( $element.attr( "class" ), "clone" );
+		equal( $clone.attr( "class" ), "clone" );
+		$clone.attr( "class", "foo" );
+		equal( $element.attr( "class" ), "clone" );
+		equal( $clone.attr( "class" ), "foo" );
+	});
+
+	test( '`.closest()`', function() {
+		var $fixture = shoestring( '#qunit-fixture' );
+
+		var $child = $fixture.find( '.closest .child' );
+
+		equal( $child[0], $child.closest( '.child' )[0], 'Closest returns current element on match' );
+
+		equal( $child.closest( '.parent' ).length, 1, 'Closest returns only one element when original nodelist has one element.' );
+
+		var $children = $fixture.find( '.closest .second-child' ).add( $child );
+
+		equal( $children.closest( '.parent' ).length, 2, 'Closest returns only two elements when original nodelist has two element.' );
+
+		ok( $child.closest( '.parent' ).is( '.first' ), 'Closest returns from the bottom up.' );
+
+		ok( $child.closest( '.parent.second' ).is( '.second' ), 'Closest will traverse at least two parents correctly.' );
+	});
+
+	test('`.css()`', function() {
+		var $css = $fixture.find( ".css" ),
+			$otherCss = $fixture.find( ".othercss" );
+
+		$css.css({
+			foo: "bar",
+			baz: "bak",
+			"float": "left",
+			"margin-right": "1px",
+			"transform": "rotateX(0)",
+			"WebkitTransform": "rotateX(0)",
+			"box-sizing": "border-box",
+			"WebkitBoxSizing": "border-box"
+		});
+
+		$css.css( 'margin-left', "2px" );
+
+		// computed style should ignore spurious styles
+		equal( ss._getStyle($css[0], 'baz'), undefined );
+
+		// width is defined in the page
+		equal( ss._getStyle($css[0], 'width'), "200px", "width should show value set from <style> tag." );
+
+		// margin-right is defined in the object assignment above
+		equal( ss._getStyle($css[0], 'margin-right'), "1px", "margin-right should be set" );
+
+		// margin-left is defined in the property assignment above
+		equal( ss._getStyle($css[0], 'margin-left'), "2px", "margin-left should be set" );
+
+		equal( ss._getStyle($css[0], "float"), "left", "float is a special case (cssFloat in JS)." );
+
+		equal(	ss._getStyle($css[0], 'box-sizing'), 'border-box', 'Box-sizing should default to content-box.' );
+
+		if( document.defaultView ) { // CTM for this vendor prefix test.
+			notEqual( ss._getStyle($css[0], 'transform'), undefined, 'transform should **NOT** be undefined (get vendor prefixes correctly).' );
+		}
+
+		notEqual( ss._getStyle($otherCss[0], 'width'), undefined, 'Width should **NOT** have a value because it’s not set.' );
+	});
+
+	test('`.eq()`', function() {
+		equal( $fixture.eq( 0 )[0], $fixture[0] );
+		equal( $fixture.eq( 1000000 )[0], undefined );
+	});
+
+	test('`.filter( selector )`', function() {
+		var $divs = $fixture.find( "div" );
+
+		equal( $divs.filter( ".filter" ).length, 1 );
+		equal( $divs.filter( ".filter" )[0], $fixture.find( ".filter" )[0] );
+
+		var $withoutParent = $( "<div class='filter'></div><div></div>" );
+
+		equal( $withoutParent.filter( ".filter" ).length, 1 );
+		equal( $withoutParent.filter( ".filter" )[0], $withoutParent[0] );
+	});
+
+	test('`.add( document ).filter( selector )`', function() {
+		var $divs = $fixture.find( "div" );
+		var $addDoc = $divs.add( document );
+		equal( $addDoc.filter( ".filter" ).length, 1 );
+
+		var $doc = $( document );
+		equal( $doc.filter( document ).length, 1 );
+	});
+
+	test('`.filter( function )`', function() {
+		var $divs = $fixture.find( ".filter" );
+
+		equal( $divs.length, 1 );
+		equal( $divs.filter(function() { return false; }).length, 0 );
+		equal( $divs.filter(function() { return true; }).length, 1 );
+	});
+
+	test('`.first()`', function() {
+		equal( $fixture.eq( 0 )[0], $fixture.first()[0] );
+	});
+
+	test('`.get()`', function() {
+		equal( $fixture[0], $fixture.get(0) );
+	});
+
+	test('`.height()`', function() {
+		var $height = $fixture.find( ".height" );
+
+		// returns the value without param
+		equal( $height.height(), 200 );
+
+		// works with integers
+		$height.height( 300 );
+		equal( $height.height(), 300 );
+
+		// works with strings
+		$height.height( "400px" );
+		equal( $height.height(), 400 );
+	});
+
+	test( '`.html()`', function() {
+		var $old = shoestring( '.html .old' ),
+			$new = shoestring( '.html .new' ),
+			htmlStr = '<div id="sibling"></div>';
+
+		$old[0].innerHTML = htmlStr;
+		$new.html( htmlStr );
+
+		ok( !!$old[0].innerHTML );
+		equal( $new[0].innerHTML, $old[0].innerHTML, '.html(str) set properly.' );
+		equal( $new.html(), $old[0].innerHTML, '.html() get str properly.' );
+	});
+
+	test( '`.html(Number)`', function() {
+		var $old = shoestring( '.html .old' ),
+			$new = shoestring( '.html .new' ),
+			htmlStr = 2;
+
+		$old[0].innerHTML = htmlStr;
+		$new.html( htmlStr );
+
+		ok( !!$old[0].innerHTML );
+		equal( $new[0].innerHTML, $old[0].innerHTML, '.html(number) set a number properly.' );
+		equal( $new.html(), $old[0].innerHTML, '.html() get number properly.' );
+	});
+
+	test( '`.html(HTML Object)`', function() {
+		var $old = shoestring( '.html .old' ),
+			$new = shoestring( '.html .new' );
+
+		var div = document.createElement( "div" );
+		div.id = "sibling";
+
+		$old[0].innerHTML = "<div id='sibling'></div>";
+		$new.html( div );
+
+		ok( !!$old[0].innerHTML );
+		equal( $new[0].innerHTML, $old[0].innerHTML, '.html(obj) set properly.' );
+		equal( $new.html(), $old[0].innerHTML, '.html() get obj properly.' );
+	});
+
+	test( '`.html(HTML Object)`', function() {
+		var $old = shoestring( '.html .old' ),
+			$new = shoestring( '.html .new' );
+
+		var div = document.createElement( "div" );
+		div.id = "sibling";
+
+		$old[0].innerHTML = "<div id='sibling'></div>";
+		$new.html( div );
+
+		ok( !!$old[0].innerHTML );
+		equal( $new[0].innerHTML, $old[0].innerHTML, '.html(obj) set properly.' );
+		equal( $new.html(), $old[0].innerHTML, '.html() get properly.' );
+	});
+
+	test( '`.html(Array)`', function() {
+		var $old = shoestring( '.html .old' ),
+			$new = shoestring( '.html .new' );
+
+		var arr = [];
+
+		var div = document.createElement( "div" );
+		div.id = "sibling";
+		var div2 = document.createElement( "div" );
+		div2.id = "sibling2";
+
+		arr.push( div );
+		arr.push( div2 );
+
+		$old[0].innerHTML = "<div id='sibling'></div><div id='sibling2'></div>";
+		$new.html( arr );
+
+		ok( !!$old[0].innerHTML );
+		equal( $new[0].innerHTML, $old[0].innerHTML, '.html(Array) set properly.' );
+		equal( $new.html(), $old[0].innerHTML, '.html() get properly.' );
+	});
+
+	test('`.index()`', function() {
+		var $indexed = $fixture.find( ".index div" );
+		equal( $indexed.index( ".first" ), 0 );
+		equal( $indexed.index( ".second" ), 1 );
+
+		var $second = $fixture.find( ".index .second" );
+		equal( $second.index(), 1 );
+		equal( $indexed.index( $second.get( 0 ) ), 1, "index() DOM element argument" );
+
+		throws(function() {
+			equal( $indexed.index( $second ), 1, "index() shoestring argument" );
+		}, 'index(shoestring()) should throw a dev error.' );
+
+	});
+
+	test('empty set `.index()`', function() {
+		equal( $( ".this-set-will-be-empty" ).index(), -1 );
+	});
+
+	test('`.is()`', function() {
+		ok( $fixture.is("#qunit-fixture") );
+		ok( !$fixture.is(".jacky-jormp-jomp") );
+		ok( $("html").is("html") );
+		ok( $("body").is("body") );
+		ok( $("body").is(document.body), "body is document.body" );
+
+		// For some reason in IE8, document[0] returns the first form.
+		ok( !$("form[name=abc]").is( document ), "a form is not document" );
+
+		// element checks permitted, works at parent level
+		ok( $( document ).is( document ), "document should be document" );
+
+		ok( $fixture.is( $fixture ) );
+
+		// correctly matches the child/descendant selector combinators
+		ok( $fixture.find( ".is .child" ).is( ".is > .child" ) );
+		ok( $fixture.find( ".is .child" ).is( "body .child" ) );
+	});
+
+	test('`.last()`', function() {
+		equal( $fixture.eq( $fixture.length - 1 )[0], $fixture.last()[0] );
+	});
+
+	test( '`.next()`', function() {
+		var $first, $all;
+
+		$first = $fixture.find( ".next .first" );
+		$all = $fixture.find( ".next > div" );
+
+
+		equal( $first.next().length, 1 );
+		equal( $first.next()[0], $fixture.find(".next .second")[0]);
+
+		equal( $all.next().length, 2 );
+		equal( $all.next()[0], $fixture.find(".next .second")[0]);
+		equal( $all.next()[1], $fixture.find(".next .third")[0]);
+		equal( $all.next()[2], undefined );
+	});
+
+	test( '`.not()`', function() {
+		var $divs = $fixture.find( ".not div" );
+
+		equal( $divs.not( ".is-not" ).length, 1 );
+		equal( $divs.not( ".is-so" ).length, $divs.length - 1 );
+	});
+
+	test( '`.parent()`', function() {
+		var $children, $parent;
+
+		$parent = $( "#qunit-fixture > .parent" );
+		$children = $parent.find( ".child" );
+
+		// double parent
+		equal( $children.parent()[0],	 $parent[0] );
+		equal( $children.parent()[1],	 $parent[0] );
+
+		// default to document element
+		// NOTE: this behavior is to match the jQuery semantics
+		equal( $( "html" ).parent()[0], document );
+
+		$children.remove();
+
+		equal( $children.eq(0).parent().length, 0);
+	});
+
+	test( '`.parents()` ... with an s', function() {
+		var $children, $parent;
+
+		$parent = $( "#qunit-fixture > .parents" );
+		$children = $parent.find( ".child" );
+
+		// the shared parents of the first and second child
+		// +1 for the second parent which is unique
+		equal( $children.parents().length, 6);
+		equal( $children.parents()[0], $(".parents > .first-parent")[0] );
+		equal( $children.parents()[2], $("#qunit-fixture")[0] );
+		equal( $children.parents()[4], $("html")[0] );
+		equal( $children.parents()[5], $(".parents > .second-parent")[0] );
+	});
+
+	test( '`.prepend() adds a first child element', function() {
+		var tmp, $prepend = $fixture.find( ".prepend" );
+
+		tmp = $(	"<div class='first'></div>" );
+		$prepend.append( tmp[0] );
+		$prepend.append( "<div class='second'></div>" );
+		$prepend.append( ".testel" );
+
+		equal( $prepend.find( ".first" )[0], tmp[0] );
+		equal( $prepend.find( ".second" ).length, 1 );
+		equal( $prepend.find( ".testel" ).length, 1 );
+	});
+
+	test( '`.prependTo() adds the all elements to the selected element` ', function() {
+		var tmp, $prepend = $fixture.find( ".prepend" );
+
+		tmp = $(	"<div class='first'></div>" );
+
+		tmp.appendTo( "#qunit-fixture > .prepend" );
+
+		equal( $prepend.find( ".first" )[0], tmp[0] );
+	});
+
+	test( '`.prev()`', function() {
+		var $last, $all;
+
+		$last = $fixture.find( ".prev div.third" );
+		$all = $fixture.find( ".prev > div" );
+
+		equal( $last.prev().length, 1 );
+		equal( $last.prev()[0], $fixture.find(".prev .second")[0]);
+
+		// ordering correct according to jquery api
+		// http://api.jquery.com/prev/
+		equal( $all.prev().length, 2 );
+		equal( $all.prev()[0], $fixture.find(".prev .first")[0]);
+		equal( $all.prev()[1], $fixture.find(".prev .second")[0]);
+		equal( $all.prev()[2], undefined );
+	});
+
+	test( '`.prevAll()`', function() {
+		var $last;
+
+		$last = $fixture.find( ".prevall div.third" );
+
+		equal( $last.prevAll().length, 2 );
+
+		// ordering correct according to jquery api
+		// http://api.jquery.com/prevall/
+		equal( $last.prevAll()[0], $fixture.find(".prevall .second")[0]);
+		equal( $last.prevAll()[1], $fixture.find(".prevall .first")[0]);
+		equal( $last.prevAll()[2], undefined );
+	});
+
+	test( '`.prop()` returns undefined on empty set', function(){
+		var $element = $( '#this_will_not_match' );
+
+		equal( $element.prop( 'class' ), undefined );
+	});
+
+	test( '`.prop()` gets the attribute', function(){
+		var $element = $fixture.find( '.prop' );
+
+		equal( $element.prop( 'class' ), "prop" );
+	});
+
+	test( '`.prop()` sets the attribute', function(){
+		var $element = $fixture.find( '.prop' );
+
+		equal( $element.prop( 'class', "bar" )[0].className, "bar" );
+	});
+
+	test( '`.remove()`', function(){
+		var $el, $fixture;
+
+		$fixture = shoestring( '#qunit-fixture' );
+		$fixture.html( '<div id="el"></div>' );
+		$el = $( "#el" );
+
+		equal( $fixture.children().length, 1 );
+		$el.remove();
+
+		equal( $fixture.children().length, 0 );
+	});
+
+	test( '`.remove()` on unattached nodes', function(){
+		var $el;
+		$el = $( document.createElement( "div" ) );
+
+		$el.remove();
+		ok( true );
+	});
+
+	// here to test for ie8
+	test( '`.removeAttr()`', function() {
+		var $removeAttr = $fixture.find( ".remove-attr" );
+
+		equal( $removeAttr.attr( "data-foo" ), "bar" );
+		$removeAttr.removeAttr( "data-foo" );
+		equal( $removeAttr.attr( "data-foo" ), undefined );
+	});
+
+	test( '`.removeClass()` removes the class', function() {
+		var $removeClass = $fixture.find( ".remove-class" );
+
+		ok( $removeClass.is( ".foo" ) );
+		$removeClass.removeClass( "foo" );
+		ok( !$removeClass.is( ".foo" ) );
+	});
+
+	test( '`.removeClass()` leaves no extra whitespace', function() {
+		var $removeClass = $fixture.find( ".remove-class" );
+
+		$removeClass.addClass( "foo" );
+		$removeClass.removeClass( "foo" );
+		$removeClass.addClass( "foo" );
+		$removeClass.removeClass( "foo" );
+
+		equal( $removeClass[0].className, "remove-class" );
+	});
+
+	test( '`.removeProp()`', function() {
+		var $removeProp = $fixture.find( ".remove-prop" );
+
+		equal( $removeProp.attr( "class" ), "remove-prop" );
+		$removeProp.removeProp( "class" );
+
+		// NOTE this is bullshit, unquoted undefined works in everything but phantom
+		equal( $removeProp.attr( "class"), "undefined" );
+	});
+
+	test( '`.replaceWith()`', function() {
+		var $replaceWith = $fixture.find( ".replace-with" );
+
+		equal( $fixture.find( ".replace-with" ).length, 1 );
+
+		var old = $replaceWith.replaceWith( "<div class='replacement'></div>" );
+
+		equal( $fixture.find( ".replace-with" ).length, 0 );
+		equal( $fixture.find( ".replacement" ).length, 1 );
+		ok( old[0].className === "replace-with", "Returned element should be the original element copied" );
+	});
+
+	test( '`.replaceWith()` with multiple pieces', function() {
+		var $replaceWith = $fixture.find( ".replace-with-multiple" );
+
+		equal( $fixture.find( ".replace-with-multiple" ).length, 1 );
+
+		var old = $replaceWith.replaceWith( "<div class='replacement1'></div><div class='replacement2'></div>" );
+
+		equal( $fixture.find( ".replace-with-multiple" ).length, 0 );
+		equal( $fixture.find( ".replacement1" ).length, 1 );
+		equal( $fixture.find( ".replacement2" ).length, 1 );
+		ok( old[0].className === "replace-with-multiple", "Returned element should be the original element copied" );
+
+		$fixture.children().each(function(i) {
+			if( shoestring( this ).is( '.replacement1' ) ){
+				equal( $fixture.children()[i+1].className, "replacement2", "Elements should be in order" );
+			}
+		});
+	});
+
+	test( '`.replaceWith()` with no dom piece/missing parentNode', function() {
+		var $replaceWith = $( "<div class='replace-missing'></div>" );
+
+		equal( $replaceWith.length, 1 );
+
+		var old = $replaceWith.replaceWith( "<div class='replace-it'></div>" );
+
+		equal( $fixture.find( ".replace-it" ).length, 0 );
+		ok( old[0].className === "replace-missing", "Returned element should be the original element copied" );
+
+	});
+
+  // TODO make this suck less
+	test( '`.serialize()`', function() {
+		var data, input, type, $serialize = $fixture.find( ".serialize" );
+
+		for( var i = 0; i < shoestring.inputTypes.length; i++ ) {
+			type = shoestring.inputTypes[i];
+			input = "<input type='" + type + "'" +
+				"name='" + type + "'" +
+				"value='" + type + "'></input>";
+
+			$serialize.append( input );
+		}
+
+		data = $serialize.serialize();
+
+		for( var val in data ) {
+			ok( data[ val ] || data[ val ] === "" );
+		}
+	});
+
+	test( '`.siblings()`', function() {
+		var $fixture = shoestring( '#qunit-fixture' );
+		$fixture.html( '<div></div><div id="sibling"></div><div></div>' );
+
+		strictEqual( $( '#imaginary_element' ).siblings().length, 0, '.siblings runs on an empty set.' );
+		equal( $( '#sibling' ).siblings().length, 2, '.siblings returns non-empty set.' );
+	});
+
+	test( '`.text()` returns content properly', function(){
+		var container = $( "<div class='text-test'><div class='demo-box'>Demonstration Box</div><ul><li>list item 1</li><li>list <strong>item</strong> 2</li></ul></div></div>" );
+		var content = "Demonstration Boxlist item 1list item 2";
+
+		equal( container.text(), content, "should return nested text properly" );
+	});
+
+	test( '`.val()` returns correct value of element', function(){
+		var value = "happy";
+		var input = document.createElement( "input" );
+		input.type = "text";
+		input.value = value;
+
+		equal( $( input ).val(), value, ".val should return the equivalent of the input's value" );
+	});
+
+	test( '`.val()` returns correct value of select element', function(){
+		var select = document.createElement( "select" );
+		var option1 = document.createElement( "option" );
+		var option2 = document.createElement( "option" );
+
+		option1.value = "1";
+		option2.value = "2";
+
+		option2.selected = "selected";
+
+		select.appendChild( option1 );
+		select.appendChild( option2 );
+
+		equal( $( select ).val(), "2", ".val should return the equivalent of the select's selected option's value" );
+	});
+
+	test( '`.val()` returns correct value of select element', function(){
+		var select = document.createElement( "select" );
+		var option1 = document.createElement( "option" );
+		var option2 = document.createElement( "option" );
+
+		option1.value = "1";
+		option2.value = "2";
+
+
+		select.appendChild( option1 );
+		select.appendChild( option2 );
+
+		select.selectedIndex = -1;
+
+		equal( $( select ).val(), "", ".val should return empty string if nothing is selected" );
+	});
+
+	test( '`$( input ).val(value)` inserts value into input', function(){
+		var value = "happy";
+		var input = document.createElement( "input" );
+		input.type = "text";
+		$( input ).val( value );
+
+		equal( input.value, value, ".val should be the equivalent of setting the input's value" );
+	});
+
+	test( '`$( select ).val(value)` selects the option that matches the value', function(){
+		var select = document.createElement( "select" );
+		var option1 = document.createElement( "option" );
+		var option2 = document.createElement( "option" );
+		var option3 = document.createElement( "option" );
+
+		option1.value = "1";
+		option2.value = "2";
+		option3.value = "3";
+
+		option2.selected = "selected";
+
+		select.appendChild( option1 );
+		select.appendChild( option2 );
+		select.appendChild( option3 );
+
+		$( select ).val( "3" );
+
+
+		equal( $( select ).val(), "3", ".val should set the correct option" );
+	});
+
+	test('`.width()`', function() {
+		var $width = $fixture.find( ".width" );
+
+		// returns the value without param
+		equal( $width.width(), 200 );
+
+		// works with integers
+		$width.width( 300 );
+		equal( $width.width(), 300 );
+
+		// works with strings
+		$width.width( "400px" );
+		equal( $width.width(), 400 );
+	});
+
+	test('`.wrapInner()`', function() {
+		var $wrapInner = $fixture.find( ".wrap-inner" );
+
+		$wrapInner.wrapInner( "<div class='wrapper'></div>" );
+		equal( $wrapInner.find( ".wrapper > .inner" ).length, 1 );
+		equal( $wrapInner.find( ".wrapper" ).length, 1 );
+	});
+
+	module( 'events', config );
+
+	asyncTest( '`.bind()` and `.trigger()`', function() {
+		expect( 2 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "click", function( e ) {
+			ok( true, 'event callback should execute.' );
+			ok( e.target, 'event.target should exist.' );
+			start();
+		}).trigger( "click" );
+	});
+
+	test( '`.trigger("click")` checks a checkbox', function() {
+		expect( 2 );
+		shoestring( '#qunit-fixture' ).html( '<input id="cbx" type="checkbox" />' );
+
+		ok( !$( "#cbx" )[0].checked, "Checkbox shouldn't be checked" );
+		$( "#cbx" ).trigger( "click" );
+		ok( !!$( "#cbx" )[0].checked, "Checkbox should be checked" );
+	});
+
+	asyncTest( "custom event bindings get the right target", function() {
+		expect( 1 );
+
+		var $div = $fixture.find( "div" ).first();
+
+		$fixture.one( "foo", function( event ) {
+			equal( $div[0], event.target );
+			start();
+		});
+
+		$div.trigger( "foo" );
+	});
+
+	asyncTest( "custom event bindings get the right context (`this`)", function() {
+		expect( 1 );
+
+		var $div = $fixture.find( "div" ).first();
+
+		$fixture.one( "foo", function( event ) {
+			equal( this, $fixture[0] );
+			start();
+		});
+
+		$div.trigger( "foo" );
+	});
+
+	asyncTest( "`document` bindings get events triggered on `documentElement` children", function() {
+		expect( 1 );
+
+		$(document).one( "foo", function() {
+			ok( true );
+			start();
+		});
+
+		$fixture.trigger( "foo" );
+	});
+
+	asyncTest( "`document` bindings get events triggered on `document`", function() {
+		expect( 1 );
+
+		$(document).one( "foo", function() {
+			ok( true );
+			start();
+		});
+
+		$( document ).trigger( "foo" );
+	});
+
+	asyncTest( 'DOM Event `.bind()` and `.trigger()` with arguments', function() {
+		expect( 1 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "click", function( e, myArgument ) {
+			equal( myArgument, "Argument", 'a custom argument should exist.' );
+			start();
+		}).trigger( "click", [ "Argument" ] );
+	});
+
+	asyncTest( 'Custom Event `.bind()` and `.trigger()` with arguments', function() {
+		expect( 1 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "myCustomEvent", function( e, myArgument ) {
+			equal( myArgument, "Argument", 'a custom argument should exist.' );
+			start();
+		}).trigger( "myCustomEvent", [ "Argument" ] );
+	});
+
+	asyncTest( '`.bind()` and `.trigger()` with data', function() {
+		expect( 2 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "click", { key: "test-value" }, function( e ) {
+			ok( true, 'event callback should execute.' );
+			equal( e.data.key, "test-value", "Data should be present on event object" );
+			start();
+		}).trigger( "click" );
+	});
+
+	asyncTest( '`.on()` and click event bubbles to parent', function() {
+		expect( 1 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="parent"><div id="child"></div></div>' );
+
+		$( '#parent' ).on( "click", function() {
+			ok( true, 'event callback should execute.' );
+			start();
+		});
+
+		$( '#child' ).trigger( "click" );
+	});
+
+	asyncTest( '`.bind()` and `.trigger()` with custom events', function() {
+		expect( 1 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "aCustomEvent", function() {
+			ok( true, 'event callback should execute.' );
+			start();
+		}).trigger( "aCustomEvent" );
+
+		$( "#el" ).unbind( "aCustomEvent" );
+	});
+
+	asyncTest( '`.bind()` and `.trigger()` with custom events and data', function() {
+		expect( 2 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "aCustomEvent", { key: "custom" }, function(e) {
+			ok( true, 'event callback should execute.' );
+			equal( e.data.key, "custom" );
+			start();
+		}).trigger( "aCustomEvent" );
+
+		$( "#el" ).unbind( "aCustomEvent" );
+	});
+
+	asyncTest( '`.bind()` doesn’t execute callback without `.trigger()` with custom events', function() {
+		expect( 1 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "aCustomEvent", function() {
+			ok( false, "Should not execute without being triggered." );
+		}).bind( "anotherCustomEvent", function() {
+			ok( false, "Should not execute without being triggered." );
+		});
+
+		setTimeout(function() {
+			ok( true );
+
+			$( "#el" ).unbind( "aCustomEvent anotherCustomEvent" );
+
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`.on()` and custom events bubble to parent', function() {
+		expect( 1 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="parent"><div id="child"></div></div>' );
+
+		$( '#parent' ).on( "aCustomEvent", function() {
+			ok( true, 'event callback should execute.' );
+
+			start();
+		});
+
+		$( '#child' ).trigger( "aCustomEvent" );
+		$( "#parent" ).unbind( "aCustomEvent" );
+	});
+
+	asyncTest( '`.bind()` and `.trigger()` with multiple of the same event on a single element', function() {
+		expect( 3 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "click", function() {
+			counter++;
+			equal( counter, 1, 'event callback should execute first.' );
+		}).bind( "click", function() {
+			counter++;
+			equal( counter, 2, 'event callback should execute second.' );
+		}).bind( "click", function() {
+			counter++;
+			equal( counter, 3, 'event callback should execute third.' );
+			start();
+		}).trigger( "click" );
+	});
+
+	asyncTest( '`.bind()` and `.trigger()` with multiple of the same event on a single element, bubbles to parent', function() {
+		expect( 3 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="parent"><div id="child"></div></div>' );
+
+		$( "#parent" ).bind( "click", function() {
+			counter++;
+			equal( counter, 1, 'event callback should execute first.' );
+		}).bind( "click", function() {
+			counter++;
+			equal( counter, 2, 'event callback should execute second.' );
+		}).bind( "click", function() {
+			counter++;
+			equal( counter, 3, 'event callback should execute third.' );
+			start();
+		});
+
+		$( "#child" ).trigger( "click" );
+	});
+
+	asyncTest( '`.bind()` and `.trigger()` with multiple of the same event on different elements', function() {
+		expect( 2 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el1"></div><div id="el2"></div>' );
+
+		$( "#el1" ).bind( "click", function() {
+			counter++;
+			equal( counter, 1, 'event callback should execute first.' );
+		});
+		$( "#el2" ).bind( "click", function() {
+			counter++;
+			equal( counter, 2, 'event callback should execute second.' );
+			start();
+		});
+		$( "#el1" ).trigger( "click" );
+		$( "#el2" ).trigger( "click" );
+	});
+
+	asyncTest( '`.bind()` and `.trigger()` with multiple of the same custom event on a single element', function() {
+		expect( 4 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 1, 'event callback should execute first.' );
+		}).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 2, 'event callback should execute second.' );
+		}).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 3, 'event callback should execute third.' );
+		}).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 4, 'event callback should execute fourth.' );
+			start();
+		}).trigger( "aCustomEvent" );
+
+		$( "#el" ).unbind( "aCustomEvent" );
+	});
+
+	asyncTest( '`.bind()` and `.trigger()` with multiple of the same custom event on a single element, bubbles to parent', function() {
+		expect( 2 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="parent"><div id="child"></div></div>' );
+
+		$( "#parent" ).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 1, 'event callback should execute first.' );
+		}).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 2, 'event callback should execute second.' );
+			start();
+		});
+
+		$( "#child" ).trigger( "aCustomEvent" );
+
+		$( "#parent" ).unbind( "aCustomEvent" );
+	});
+
+	asyncTest( '`.bind()` and `.trigger()` with multiple of the same custom event on different elements', function() {
+		expect( 2 );
+
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el1"></div><div id="el2"></div>' );
+
+		$( "#el1" ).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 1, 'event callback should execute first.' );
+		});
+		$( "#el2" ).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 2, 'event callback should execute second.' );
+			start();
+		});
+		$( "#el1" ).trigger( "aCustomEvent" );
+		$( "#el2" ).trigger( "aCustomEvent" );
+
+		$( "#el1" ).unbind( "aCustomEvent" );
+		$( "#el2" ).unbind( "aCustomEvent" );
+	});
+
+	asyncTest( '`.bind()` should not execute without trigger', function() {
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( '#el' )
+			.bind( "dragmove.carousel", function( e, data ){
+				ok( false, "Should not execute without being triggered.");
+			});
+
+		setTimeout(function() {
+			ok( true );
+
+			$( "#el" ).unbind( "dragmove.carousel" );
+
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`.unbind("click", function)`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "click", f )
+			.trigger( "click" )
+			.unbind( "click", f )
+			.trigger( "click" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`.unbind("mouseup mousedown", function) multiple dom events`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "mouseup", f )
+			.bind( "mousedown", f )
+			.unbind( "mouseup mousedown", f )
+			.trigger( "mouseup" )
+			.trigger( "mousedown" );
+
+		setTimeout(function() {
+			strictEqual( counter, 0, "callback should not have fired." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`.unbind("aCustomEvent anotherCustomEvent", function)`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "aCustomEvent", f )
+			.bind( "anotherCustomEvent", f )
+			.unbind( "aCustomEvent anotherCustomEvent", f )
+			.trigger( "aCustomEvent" )
+			.trigger( "anotherCustomEvent" );
+
+		setTimeout(function() {
+			strictEqual( counter, 0, "callback should not have fired." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`.unbind("click")`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "click", f )
+			.trigger( "click" )
+			.unbind( "click" )
+			.trigger( "click" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`.unbind("aCustomEvent", function)`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "aCustomEvent", f )
+			.trigger( "aCustomEvent" )
+			.unbind( "aCustomEvent", f )
+			.trigger( "aCustomEvent" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`.unbind("aCustomEvent")`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "aCustomEvent", f )
+			.trigger( "aCustomEvent" )
+			.unbind( "aCustomEvent" )
+			.trigger( "aCustomEvent" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`.unbind()` all', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "aCustomEvent", f )
+			.trigger( "aCustomEvent" )
+			.unbind()
+			.trigger( "aCustomEvent" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`.unbind("aCustomEvent", function)` in a `.bind()` callback', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+			$( this ).unbind( "aCustomEvent", f );
+		};
+
+		$( "#el" ).bind( "aCustomEvent", f )
+			.trigger( "aCustomEvent" )
+			.trigger( "aCustomEvent" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`.unbind("eventThatDoesntExist", function)` doesn\'t throw error, does nothing', function() {
+		expect( 1 );
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		$( "#el" ).unbind( "eventThatDoesntExist" );
+		setTimeout(function() {
+			ok( true, "No error thrown, nothing happened" );
+			start();
+		}, 30);
+
+	});
+
+	test( '`.one()` with multiple events (see #13)', function() {
+		var $fixture = shoestring( '#qunit-fixture' ),
+			triggerCount = 0,
+			$el;
+
+		$fixture.html( '<div id="el"></div>' );
+		$el = $( "#el" );
+
+		$el.one( "hover mousedown", function() {
+			triggerCount++;
+		});
+
+		$el.trigger( "hover" );
+		$el.trigger( "mousedown" );
+
+		strictEqual( triggerCount, 1, 'only one event callback should execute.' );
+	});
+
+	asyncTest( '`.one()` with multiple custom events', function() {
+		expect( 1 );
+		var $fixture = shoestring( '#qunit-fixture' ),
+			triggerCount = 0,
+			$el;
+
+		$fixture.html( '<div id="el"></div>' );
+		$el = $( "#el" );
+
+		$el.one( "aCustomEvent anotherCustomEvent yetAnotherCustomEvent", function() {
+			triggerCount++;
+		});
+
+		$el.trigger( "aCustomEvent" );
+		$el.trigger( "anotherCustomEvent" );
+
+		window.setTimeout(function() {
+			strictEqual( triggerCount, 1, 'only one event callback should execute.' );
+			start();
+		}, 15);
+	});
+
+	asyncTest( '`.bind()` bubbling event order', function() {
+		expect( 2 );
+
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="parent"><div id="child"></div></div>' );
+
+		$( '#parent' ).bind( "click", function() {
+			counter++;
+			equal( counter, 2, 'event callback should execute second.' );
+		});
+
+		$( '#child' ).bind( "click", function() {
+			counter++;
+			equal( counter, 1, 'event callback should execute first.' );
+		}).trigger( "click" );
+
+		setTimeout(function() {
+			start();
+		}, 15);
+	});
+
+
+	asyncTest( '`.bind()` bubbling custom event order (parent first)', function() {
+		expect( 2 );
+
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="parent"><div id="child"></div></div>' );
+
+		$( '#parent' ).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 2, 'parent event callback should execute second.' );
+		});
+
+		$( '#child' ).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 1, 'child event callback should execute first.' );
+		}).trigger( "aCustomEvent" );
+
+		setTimeout(function() {
+			start();
+		}, 15);
+	});
+
+	asyncTest( '`.bind()` bubbling custom event order (child first)', function() {
+		expect( 2 );
+
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="parent"><div id="child"></div></div>' );
+
+		$( '#child' ).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 1, 'child event callback should execute first.' );
+		});
+
+		$( '#parent' ).bind( "aCustomEvent", function() {
+			counter++;
+			equal( counter, 2, 'parent event callback should execute second.' );
+		});
+
+		$( '#child' ).trigger( "aCustomEvent" );
+
+		setTimeout(function() {
+			start();
+		}, 15);
+	});
+
+	asyncTest( 'trigger click executes a native click', function() {
+		var hash = location.hash;
+
+		expect( 1 );
+		shoestring( '#qunit-fixture' ).html( '<a href="#test" id="el">Link</a>' );
+
+		$( '#el' ).trigger( "click" );
+
+		setTimeout(function() {
+			notEqual( location.hash, hash, 'hash should have changed, link should have been clicked.' );
+
+			location.hash = "";
+			start();
+		}, 15);
+	});
+
+	asyncTest( 'preventDefault on dom event', function() {
+		var hash = location.hash;
+
+		expect( 1 );
+		shoestring( '#qunit-fixture' ).html( '<a href="#test" id="el">Link</a>' );
+
+		$( '#el' ).bind( "click", function( e ) {
+			e.preventDefault();
+		}).trigger( "click" );
+
+		setTimeout(function() {
+			equal( location.hash, hash, 'hash should not have changed, event should preventDefault' );
+
+			location.hash = "";
+			start();
+		}, 15);
+	});
+
+	asyncTest( '`.isDefaultPrevented()`', function(){
+		expect(1);
+		var fn = function(e){
+			e.preventDefault();
+			ok(e.isDefaultPrevented());
+		};
+
+		shoestring( '#qunit-fixture' ).html( '<div id="preventdefault"></div>' );
+
+		$( "#preventdefault" ).bind( "click", fn )
+			.trigger( "click" );
+
+		setTimeout(function() {
+			start();
+		}, 15);
+
+	});
+
+	asyncTest( '`.isDefaultPrevented()` without `.preventDefault()`', function(){
+		expect(1);
+		var fn = function(e){
+			ok(!e.isDefaultPrevented());
+		};
+
+		shoestring( '#qunit-fixture' ).html( '<div id="preventdefault2"></div>' );
+
+		$( "#preventdefault2" ).bind( "click", fn )
+			.trigger( "click" );
+
+		setTimeout(function() {
+			start();
+		}, 15);
+
+	});
+
+	asyncTest( 'return false prevents propagation', function() {
+		expect( 1 ) ;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="parent"><div id="child"></div></div>' );
+
+		$( "#child" ).one( "click", function() {
+			ok( true, "one runs" );
+
+			setTimeout(function() {
+				start();
+			});
+
+			return false;
+		});
+
+		$( "#parent" ).one( "click", function() {
+			ok( false, "never runs" );
+		});
+
+		$( "#child" ).trigger( "click" );
+	});
+
+	asyncTest( 'stopPropagation prevents propagation', function() {
+		expect( 1 ) ;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="parent"><div id="child"></div></div>' );
+
+		$( "#child" ).one( "click", function(e) {
+			e.stopPropagation();
+			ok( true, "one runs" );
+
+			setTimeout(function() {
+				start();
+			});
+
+		});
+
+		$( "#parent" ).one( "click", function() {
+			ok( false, "never runs" );
+		});
+
+		$( "#child" ).trigger( "click" );
+	});
+
+	asyncTest( 'no stopPropagation allows propagation', function() {
+		expect( 2 ) ;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="parent"><div id="child"></div></div>' );
+
+		$( "#child" ).one( "click", function(e) {
+			ok( true, "one runs" );
+
+			setTimeout(function() {
+				start();
+			});
+
+		});
+
+		$( "#parent" ).one( "click", function() {
+			ok( true, "also runs" );
+		});
+
+		$( "#child" ).trigger( "click" );
+	});
+
+	asyncTest( 'Custom Events: namespaced bind, namespaced trigger', function() {
+		expect( 2 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "customEvent.myNamespace", function( e ) {
+			ok( true, 'event callback should execute.' );
+			ok( e.namespace, 'namespace property should exist.' );
+		})
+		.trigger( "customEvent.myNamespace" );
+
+		setTimeout(function() {
+			start();
+		}, 15);
+	});
+
+	asyncTest( 'Custom Events: namespaced bind, unnamespaced trigger', function() {
+		expect( 2 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "customEvent.myNamespace", function( e ) {
+			ok( true, 'event callback should execute.' );
+			ok( !e.namespace, 'namespace property should not exist.' );
+		})
+		.trigger( "customEvent" );
+
+		setTimeout(function() {
+			start();
+		}, 15);
+	});
+
+	asyncTest( 'DOM Events: namespaced bind, namespaced trigger', function() {
+		expect( 2 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "click.myNamespace", function( e ) {
+			ok( true, 'event callback should execute.' );
+			ok( e.namespace, 'namespace property should exist.' );
+		})
+		.trigger( "click.myNamespace" );
+
+		setTimeout(function() {
+			start();
+		}, 15);
+	});
+
+	asyncTest( 'DOM Events: namespaced bind, unnamespaced trigger', function() {
+		expect( 2 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el2"></div>' );
+
+		$( "#el2" ).bind( "click.myNamespace", function( e ) {
+			ok( true, 'event callback should execute.' );
+			ok( !e.namespace, 'namespace property should not exist.' );
+		})
+		.trigger( "click" );
+
+		setTimeout(function() {
+			start();
+		}, 15);
+	});
+
+	asyncTest( 'DOM Events: unnamespaced bind, namespaced trigger', function() {
+		expect( 0 );
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+
+		$( "#el" ).bind( "click", function( e ) {
+			ok( true, 'event callback should not execute.' );
+		}).trigger( "click.myNamespace" );
+
+		setTimeout(function() {
+			start();
+		}, 15);
+	});
+
+asyncTest( '`Custom Events: .bind("myCustomEvent.myNamespace") .unbind("myCustomEvent.myNamespace")`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "myCustomEvent.myNamespace", f )
+			.trigger( "myCustomEvent.myNamespace" )
+			.unbind( "myCustomEvent.myNamespace" )
+			.trigger( "myCustomEvent.myNamespace" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`Custom Events: .bind("myCustomEvent.myNamespace") .unbind("myCustomEvent.myNamespace", function)`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "myCustomEvent.myNamespace", f )
+			.trigger( "myCustomEvent.myNamespace" )
+			.unbind( "myCustomEvent.myNamespace", f )
+			.trigger( "myCustomEvent.myNamespace" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`Custom Events: .bind("myCustomEvent.myNamespace") .unbind("myCustomEvent")`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "myCustomEvent.myNamespace", f )
+			.trigger( "myCustomEvent.myNamespace" )
+			.unbind( "myCustomEvent" )
+			.trigger( "myCustomEvent.myNamespace" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`Custom Events: .bind("myCustomEvent") .unbind("myCustomEvent.myNamespace", function)`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "myCustomEvent", f )
+			.trigger( "myCustomEvent" )
+			.unbind( "myCustomEvent.myNamespace", f )
+			.trigger( "myCustomEvent" );
+
+		setTimeout(function() {
+			equal( counter, 2, "callback should fire twice. unbind should have not matched anything." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`DOM Events: .bind("click.myNamespace") .unbind("click.myNamespace")`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "click.myNamespace", f )
+			.trigger( "click.myNamespace" )
+			.unbind( "click.myNamespace" )
+			.trigger( "click.myNamespace" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`DOM Events: .bind("click.myNamespace") .unbind("click.myNamespace", function)`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "click.myNamespace", f )
+			.trigger( "click.myNamespace" )
+			.unbind( "click.myNamespace", f )
+			.trigger( "click.myNamespace" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`DOM Events: .bind("click.myNamespace") .unbind("click")`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "click.myNamespace", f )
+			.trigger( "click.myNamespace" )
+			.unbind( "click" )
+			.trigger( "click.myNamespace" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should have fired once." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`DOM Events: .bind("click") .unbind("click.myNamespace", function)`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "click", f )
+			.trigger( "click" )
+			.unbind( "click.myNamespace", f )
+			.trigger( "click" );
+
+		setTimeout(function() {
+			equal( counter, 2, "callback should fire twice. unbind should have not matched anything." );
+			start();
+		}, 30);
+	});
+
+	asyncTest( '`DOM Events: .unbind(".myNamespace")`', function() {
+		expect( 1 );
+		var counter = 0;
+
+		shoestring( '#qunit-fixture' ).html( '<div id="el"></div>' );
+		var f = function() {
+			counter++;
+		};
+
+		$( "#el" ).bind( "click.myNamespace", f )
+			.trigger( "click.myNamespace" )
+			.unbind( ".myNamespace", f )
+			.trigger( "click.myNamespace" );
+
+		setTimeout(function() {
+			equal( counter, 1, "callback should fire once." );
+			start();
+		}, 30);
+	});
+
+	if( window.JSON && 'localStorage' in window ) {
+		module( "util", config );
+
+		test( "when a shoestring.fn method is called it gets tracked", function() {
+			var tracked;
+
+			window.localStorage.setItem( shoestring.trackedMethodsKey,	"{}" );
+
+			$fixture.find( "div" ).remove();
+
+			tracked = JSON.parse( window.localStorage.getItem(shoestring.trackedMethodsKey) );
+
+			ok( tracked.find );
+			ok( tracked.remove );
+		});
+	}
+
+	module( 'ajax', config );
+
+	test( "ajax doesn't override default options", function() {
+		equal( shoestring.ajax.settings.method, "GET" );
+		shoestring.ajax( "foo", { method: "POST" } );
+		equal( shoestring.ajax.settings.method, "GET" );
+	});
+
+	var mockXHR = function() {
+		var fakeXHR = sinon.useFakeXMLHttpRequest();
+		var requests = sinon.requests = [];
+
+		fakeXHR.onCreate = function ( request ) {
+			requests.push( request );
+		};
+
+		return requests;
+	};
+
+	test( ".ajax throws exception with data and url with params", function(){
+		mockXHR();
+
+		throws(function() {
+			shoestring.ajax( "/some/url?foo=bar", {
+				data: { bar: 'baz' }
+			});
+		});
+	});
+
+	test( ".ajax defaul headers", function(){
+		var requests = mockXHR();
+
+		// call ajax method
+		shoestring.ajax( "/some/url", {	success: function() {} });
+
+		equal(requests[0].requestHeaders['X-Requested-With'], "XMLHttpRequest");
+	});
+
+	test( ".ajax includes headers", function(){
+		var requests = mockXHR();
+
+		// call ajax method
+		shoestring.ajax( "/some/url", {
+			data: { param1: "one", param2: "two" },
+			headers: { foo: 'bar' },
+			success: function() {}
+		});
+
+		equal(requests[0].requestHeaders.foo, 'bar');
+	});
+
+	test( ".ajax sends request with method GET and appends data elements to url", function(){
+		var requests = mockXHR();
+		var callback = sinon.spy();
+
+		// call ajax method
+		shoestring.ajax( "/some/url", {
+			data: { param1: "one", param2: "two" },
+			success: callback
+		});
+
+		// check that only one request is sent
+		equal( sinon.requests.length, 1 );
+		// check correct method is used
+		equal( sinon.requests[0].method, "GET" );
+		// check that parameter string was appended to url
+		equal( sinon.requests[0].url, "/some/url?param1=one&param2=two" );
+
+		// mock response to test callback
+		requests[0].respond( 200, { "Content-Type": "application/json" }, '{}' );
+		// check that callback was called
+		ok( callback.called );
+	});
+
+	test( ".post sends request with method POST, send data in request body", function(){
+		var requests = mockXHR();
+
+		var url = "/some/url";
+		var callback = sinon.spy();
+
+		// call post method
+		shoestring.post( url, { param1: "one", param2: "two" }, callback );
+
+		// check that only one request is sent
+		equal( sinon.requests.length, 1 );
+		// check correct method is used
+		equal( sinon.requests[0].method, "POST" );
+		// check that url has not been changed
+		equal( sinon.requests[0].url, url );
+		// check data elements are sent in request body
+		equal( sinon.requests[0].requestBody, "param1=one&param2=two" );
+		// check that only one request is sent
+		ok( sinon.requests[0].requestHeaders['Content-type'].indexOf("application/x-www-form-urlencode") >= 0);
+
+		requests[0].respond( 200, { "Content-Type": "application/json" }, '[]' );
+
+		ok( callback.called );
+	});
+})();