')
+ var btn1 = byId("btn-1");
+ var btn2 = byId("btn-2");
+
+ btn1.click();
+ this.server.respond();
+ ext1Calls.should.equal(1);
+ ext2Calls.should.equal(1);
+ ext3Calls.should.equal(0);
+
+ btn2.click();
+ this.server.respond();
+ ext1Calls.should.equal(2);
+ ext2Calls.should.equal(1);
+ ext3Calls.should.equal(1);
+ });
+
+ it('supports comma separated lists', function () {
+ this.server.respondWith("GET", "/test", "Clicked!");
+
+ make('')
+ var btn1 = byId("btn-1");
+ var btn2 = byId("btn-2");
+
+ btn1.click();
+ this.server.respond();
+ ext1Calls.should.equal(1);
+ ext2Calls.should.equal(1);
+ ext3Calls.should.equal(1);
+ });
+
+ it('A simple extension is invoked properly w/ data-* prefix', function () {
+ this.server.respondWith("GET", "/test", "Clicked!");
+
+ var btn = make('')
+ btn.click();
+ this.server.respond();
+ ext1Calls.should.equal(1);
+ ext2Calls.should.equal(0);
+ ext3Calls.should.equal(0);
+ });
+
+
+});
\ No newline at end of file
diff --git a/www/test/0.1.1/test/attributes/hx-get.js b/www/test/0.1.1/test/attributes/hx-get.js
new file mode 100644
index 00000000..7326c39e
--- /dev/null
+++ b/www/test/0.1.1/test/attributes/hx-get.js
@@ -0,0 +1,76 @@
+describe("hx-get attribute", function() {
+ beforeEach(function () {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function () {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('issues a GET request on click and swaps content', function () {
+ this.server.respondWith("GET", "/test", "Clicked!");
+
+ var btn = make('')
+ btn.click();
+ this.server.respond();
+ btn.innerHTML.should.equal("Clicked!");
+ });
+
+ it('GET does not include surrounding data by default', function () {
+ this.server.respondWith("GET", "/test", function (xhr) {
+ should.equal(getParameters(xhr)["i1"], undefined);
+ xhr.respond(200, {}, "Clicked!");
+ });
+ make('')
+ var btn = byId("b1");
+ btn.click();
+ this.server.respond();
+ btn.innerHTML.should.equal("Clicked!");
+ });
+
+ it('GET on form includes its own data by default', function () {
+ this.server.respondWith("GET", /\/test.*/, function (xhr) {
+ getParameters(xhr)["i1"].should.equal("value");
+ xhr.respond(200, {}, "Clicked!");
+ });
+ var form = make('');
+ form.click();
+ this.server.respond();
+ form.innerHTML.should.equal("Clicked!");
+ });
+
+ it('GET on form with existing parameters works properly', function () {
+ this.server.respondWith("GET", /\/test.*/, function (xhr) {
+ getParameters(xhr)["foo"].should.equal("bar");
+ getParameters(xhr)["i1"].should.equal("value");
+ xhr.respond(200, {}, "Clicked!");
+ });
+ var form = make('');
+ form.click();
+ this.server.respond();
+ form.innerHTML.should.equal("Clicked!");
+ });
+
+ it('GET on form with anchor works properly', function () {
+ this.server.respondWith("GET", /\/test.*/, function (xhr) {
+ getParameters(xhr)["foo"].should.equal("bar");
+ getParameters(xhr)["i1"].should.equal("value");
+ xhr.respond(200, {}, "Clicked!");
+ });
+ var form = make('');
+ form.click();
+ this.server.respond();
+ form.innerHTML.should.equal("Clicked!");
+ });
+
+
+ it('issues a GET request on click and swaps content w/ data-* prefix', function () {
+ this.server.respondWith("GET", "/test", "Clicked!");
+
+ var btn = make('')
+ btn.click();
+ this.server.respond();
+ btn.innerHTML.should.equal("Clicked!");
+ });
+});
\ No newline at end of file
diff --git a/www/test/0.1.1/test/attributes/hx-include.js b/www/test/0.1.1/test/attributes/hx-include.js
new file mode 100644
index 00000000..1d00f25d
--- /dev/null
+++ b/www/test/0.1.1/test/attributes/hx-include.js
@@ -0,0 +1,153 @@
+describe("hx-include attribute", function() {
+ beforeEach(function () {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function () {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('By default an input includes itself', function () {
+ this.server.respondWith("POST", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.equal("test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var div = make('')
+ var input = byId("i1")
+ input.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('non-GET includes closest form', function () {
+ this.server.respondWith("POST", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.equal("test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var div = make('')
+ var input = byId("d1")
+ input.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('GET does not include closest form by default', function () {
+ this.server.respondWith("GET", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ should.equal(params['i1'], undefined);
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var div = make('')
+ var input = byId("d1")
+ input.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('Input not included twice when in form', function () {
+ this.server.respondWith("POST", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.equal("test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var div = make('')
+ var input = byId("i1")
+ input.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('Two inputs are included twice when they have the same name', function () {
+ this.server.respondWith("POST", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.deep.equal(["test", "test2"]);
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var div = make('')
+ var input = byId("i1")
+ input.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('Input not included twice when it explicitly refers to parent form', function () {
+ this.server.respondWith("POST", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.equal("test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var div = make('')
+ var input = byId("i1")
+ input.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('Input can be referred to externally', function () {
+ this.server.respondWith("POST", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.equal("test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ make('');
+ var div = make('')
+ div.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('Two inputs can be referred to externally', function () {
+ this.server.respondWith("POST", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.equal("test");
+ params['i2'].should.equal("test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ make('');
+ make('');
+ var div = make('')
+ div.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('A form can be referred to externally', function () {
+ this.server.respondWith("POST", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.equal("test");
+ params['i2'].should.equal("test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ make(' ');
+ var div = make('')
+ div.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('By default an input includes itself w/ data-* prefix', function () {
+ this.server.respondWith("POST", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.equal("test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var div = make('')
+ var input = byId("i1")
+ input.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+
+});
\ No newline at end of file
diff --git a/www/test/0.1.1/test/attributes/hx-indicator.js b/www/test/0.1.1/test/attributes/hx-indicator.js
new file mode 100644
index 00000000..1385eb42
--- /dev/null
+++ b/www/test/0.1.1/test/attributes/hx-indicator.js
@@ -0,0 +1,52 @@
+describe("hx-indicator attribute", function(){
+ beforeEach(function() {
+ this.server = sinon.fakeServer.create();
+ clearWorkArea();
+ });
+ afterEach(function() {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('Indicator classes are properly put on element with no explicit indicator', function()
+ {
+ this.server.respondWith("GET", "/test", "Clicked!");
+ var btn = make('')
+ btn.click();
+ btn.classList.contains("htmx-request").should.equal(true);
+ this.server.respond();
+ btn.classList.contains("htmx-request").should.equal(false);
+ });
+
+ it('Indicator classes are properly put on element with explicit indicator', function()
+ {
+ this.server.respondWith("GET", "/test", "Clicked!");
+ var btn = make('')
+ var a1 = make('')
+ var a2 = make('')
+ btn.click();
+ btn.classList.contains("htmx-request").should.equal(false);
+ a1.classList.contains("htmx-request").should.equal(true);
+ a2.classList.contains("htmx-request").should.equal(true);
+ this.server.respond();
+ btn.classList.contains("htmx-request").should.equal(false);
+ a1.classList.contains("htmx-request").should.equal(false);
+ a2.classList.contains("htmx-request").should.equal(false);
+ });
+
+ it('Indicator classes are properly put on element with explicit indicator w/ data-* prefix', function()
+ {
+ this.server.respondWith("GET", "/test", "Clicked!");
+ var btn = make('')
+ var a1 = make('')
+ var a2 = make('')
+ btn.click();
+ btn.classList.contains("htmx-request").should.equal(false);
+ a1.classList.contains("htmx-request").should.equal(true);
+ a2.classList.contains("htmx-request").should.equal(true);
+ this.server.respond();
+ btn.classList.contains("htmx-request").should.equal(false);
+ a1.classList.contains("htmx-request").should.equal(false);
+ a2.classList.contains("htmx-request").should.equal(false);
+ });
+})
diff --git a/www/test/0.1.1/test/attributes/hx-params.js b/www/test/0.1.1/test/attributes/hx-params.js
new file mode 100644
index 00000000..b2b19ca2
--- /dev/null
+++ b/www/test/0.1.1/test/attributes/hx-params.js
@@ -0,0 +1,101 @@
+describe("hx-params attribute", function() {
+ beforeEach(function () {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function () {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('none excludes all params', function () {
+ this.server.respondWith("POST", "/params", function (xhr) {
+ var params = getParameters(xhr);
+ should.equal(params['i1'], undefined);
+ should.equal(params['i2'], undefined);
+ should.equal(params['i3'], undefined);
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var form = make(' ');
+ form.click();
+ this.server.respond();
+ form.innerHTML.should.equal("Clicked!");
+ });
+
+ it('"*" includes all params', function () {
+ this.server.respondWith("POST", "/params", function (xhr) {
+ var params = getParameters(xhr);
+ should.equal(params['i1'], "test");
+ should.equal(params['i2'], "test");
+ should.equal(params['i3'], "test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var form = make(' ');
+ form.click();
+ this.server.respond();
+ form.innerHTML.should.equal("Clicked!");
+ });
+
+ it('named includes works', function () {
+ this.server.respondWith("POST", "/params", function (xhr) {
+ var params = getParameters(xhr);
+ should.equal(params['i1'], "test");
+ should.equal(params['i2'], undefined);
+ should.equal(params['i3'], "test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var form = make(' ');
+ form.click();
+ this.server.respond();
+ form.innerHTML.should.equal("Clicked!");
+ });
+
+ it('named exclude works', function () {
+ this.server.respondWith("POST", "/params", function (xhr) {
+ var params = getParameters(xhr);
+ should.equal(params['i1'], undefined);
+ should.equal(params['i2'], "test");
+ should.equal(params['i3'], undefined);
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var form = make(' ');
+ form.click();
+ this.server.respond();
+ form.innerHTML.should.equal("Clicked!");
+ });
+
+ it('named exclude works w/ data-* prefix', function () {
+ this.server.respondWith("POST", "/params", function (xhr) {
+ var params = getParameters(xhr);
+ should.equal(params['i1'], undefined);
+ should.equal(params['i2'], "test");
+ should.equal(params['i3'], undefined);
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var form = make(' ');
+ form.click();
+ this.server.respond();
+ form.innerHTML.should.equal("Clicked!");
+ });
+
+});
\ No newline at end of file
diff --git a/www/test/0.1.1/test/attributes/hx-patch.js b/www/test/0.1.1/test/attributes/hx-patch.js
new file mode 100644
index 00000000..a3c51984
--- /dev/null
+++ b/www/test/0.1.1/test/attributes/hx-patch.js
@@ -0,0 +1,34 @@
+describe("hx-patch attribute", function(){
+ beforeEach(function() {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function() {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('issues a PATCH request', function()
+ {
+ this.server.respondWith("PATCH", "/test", function(xhr){
+ xhr.respond(200, {}, "Patched!");
+ });
+
+ var btn = make('')
+ btn.click();
+ this.server.respond();
+ btn.innerHTML.should.equal("Patched!");
+ });
+
+ it('issues a PATCH request w/ data-* prefix', function()
+ {
+ this.server.respondWith("PATCH", "/test", function(xhr){
+ xhr.respond(200, {}, "Patched!");
+ });
+
+ var btn = make('')
+ btn.click();
+ this.server.respond();
+ btn.innerHTML.should.equal("Patched!");
+ });
+})
diff --git a/www/test/0.1.1/test/attributes/hx-post.js b/www/test/0.1.1/test/attributes/hx-post.js
new file mode 100644
index 00000000..6734e30d
--- /dev/null
+++ b/www/test/0.1.1/test/attributes/hx-post.js
@@ -0,0 +1,36 @@
+describe("hx-post attribute", function(){
+ beforeEach(function() {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function() {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('issues a POST request with proper headers', function()
+ {
+ this.server.respondWith("POST", "/test", function(xhr){
+ should.equal(xhr.requestHeaders['X-HTTP-Method-Override'], undefined);
+ xhr.respond(200, {}, "Posted!");
+ });
+
+ var btn = make('')
+ btn.click();
+ this.server.respond();
+ btn.innerHTML.should.equal("Posted!");
+ });
+
+ it('issues a POST request with proper headers w/ data-* prefix', function()
+ {
+ this.server.respondWith("POST", "/test", function(xhr){
+ should.equal(xhr.requestHeaders['X-HTTP-Method-Override'], undefined);
+ xhr.respond(200, {}, "Posted!");
+ });
+
+ var btn = make('')
+ btn.click();
+ this.server.respond();
+ btn.innerHTML.should.equal("Posted!");
+ });
+})
diff --git a/www/test/0.1.1/test/attributes/hx-push-url.js b/www/test/0.1.1/test/attributes/hx-push-url.js
new file mode 100644
index 00000000..206fe934
--- /dev/null
+++ b/www/test/0.1.1/test/attributes/hx-push-url.js
@@ -0,0 +1,170 @@
+describe("hx-push-url attribute", function() {
+
+ var HTMX_HISTORY_CACHE_NAME = "htmx-history-cache";
+
+ beforeEach(function () {
+ this.server = makeServer();
+ clearWorkArea();
+ localStorage.removeItem(HTMX_HISTORY_CACHE_NAME);
+ });
+ afterEach(function () {
+ this.server.restore();
+ clearWorkArea();
+ localStorage.removeItem(HTMX_HISTORY_CACHE_NAME);
+ });
+
+ it("navigation should push an element into the cache when true", function () {
+ this.server.respondWith("GET", "/test", "second");
+ getWorkArea().innerHTML.should.be.equal("");
+ var div = make('
first
');
+ div.click();
+ this.server.respond();
+ div.click();
+ this.server.respond();
+ getWorkArea().textContent.should.equal("second")
+ var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME));
+ cache.length.should.equal(2);
+ cache[1].url.should.equal("/test");
+ });
+
+ it("navigation should push an element into the cache when string", function () {
+ this.server.respondWith("GET", "/test", "second");
+ getWorkArea().innerHTML.should.be.equal("");
+ var div = make('
first
');
+ div.click();
+ this.server.respond();
+ div.click();
+ this.server.respond();
+ getWorkArea().textContent.should.equal("second")
+ var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME));
+ console.log(cache);
+ cache.length.should.equal(2);
+ cache[1].url.should.equal("/abc123");
+ });
+
+ it("restore should return old value", function () {
+ this.server.respondWith("GET", "/test1", '
test1
');
+ this.server.respondWith("GET", "/test2", '
test2
');
+
+ make('
init
');
+
+ byId("d1").click();
+ this.server.respond();
+ var workArea = getWorkArea();
+ workArea.textContent.should.equal("test1")
+
+ byId("d2").click();
+ this.server.respond();
+ workArea.textContent.should.equal("test2")
+
+ var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME));
+
+ cache.length.should.equal(2);
+ htmx._('restoreHistory')("/test1")
+ this.server.respond();
+ getWorkArea().textContent.should.equal("test1")
+ });
+
+ it("cache should only store 10 entries", function () {
+ var x = 0;
+ this.server.respondWith("GET", /test.*/, function(xhr){
+ x++;
+ xhr.respond(200, {}, '')
+ });
+ getWorkArea().innerHTML.should.be.equal("");
+ make('');
+ for (var i = 0; i < 20; i++) { // issue 20 requests
+ byId("d1").click();
+ this.server.respond();
+ }
+ var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME));
+ cache.length.should.equal(10); // should only be 10 elements
+ });
+
+ it("cache miss should issue another GET", function () {
+ this.server.respondWith("GET", "/test1", '
test1
');
+ this.server.respondWith("GET", "/test2", '
test2
');
+
+ make('
init
');
+
+ byId("d1").click();
+ this.server.respond();
+ var workArea = getWorkArea();
+ workArea.textContent.should.equal("test1")
+
+ byId("d2").click();
+ this.server.respond();
+ workArea.textContent.should.equal("test2")
+
+ var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME));
+
+ cache.length.should.equal(2);
+ localStorage.removeItem(HTMX_HISTORY_CACHE_NAME); // clear cache
+ htmx._('restoreHistory')("/test1")
+ this.server.respond();
+ getWorkArea().textContent.should.equal("test1")
+ });
+
+ it("navigation should push an element into the cache w/ data-* prefix", function () {
+ this.server.respondWith("GET", "/test", "second");
+ getWorkArea().innerHTML.should.be.equal("");
+ var div = make('
first
');
+ div.click();
+ this.server.respond();
+ getWorkArea().textContent.should.equal("second")
+ var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME));
+ cache.length.should.equal(1);
+ });
+
+ it("deals with malformed JSON in history cache when getting", function () {
+ localStorage.setItem(HTMX_HISTORY_CACHE_NAME, "Invalid JSON");
+ var history = htmx._('getCachedHistory')('url');
+ should.equal(history, null);
+ });
+
+ it("deals with malformed JSON in history cache when saving", function () {
+ localStorage.setItem(HTMX_HISTORY_CACHE_NAME, "Invalid JSON");
+ htmx._('saveToHistoryCache')('url', 'content', 'title', 'scroll');
+ var cache = JSON.parse(localStorage.getItem(HTMX_HISTORY_CACHE_NAME));
+ cache.length.should.equal(1);
+ });
+
+
+ it("htmx:afterSettle is called when replacing outerHTML", function () {
+ var called = false;
+ var handler = htmx.on("htmx:afterSettle", function (evt) {
+ called = true;
+ });
+ try {
+ this.server.respondWith("POST", "/test", function (xhr) {
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(called, true);
+ } finally {
+ htmx.off("htmx:afterSettle", handler);
+ }
+ });
+
+ it("should include parameters on a get", function () {
+ var path = "";
+ var handler = htmx.on("htmx:pushedIntoHistory", function (evt) {
+ path = evt.detail.path;
+ });
+ try {
+ this.server.respondWith("GET", /test.*/, function (xhr) {
+ xhr.respond(200, {}, "second")
+ });
+ var form = make('');
+ form.click();
+ this.server.respond();
+ form.textContent.should.equal("second")
+ path.should.equal("/test?foo=bar")
+ } finally {
+ htmx.off("htmx:pushedIntoHistory", handler);
+ }
+ });
+
+});
diff --git a/www/test/0.1.1/test/attributes/hx-put.js b/www/test/0.1.1/test/attributes/hx-put.js
new file mode 100644
index 00000000..589ec199
--- /dev/null
+++ b/www/test/0.1.1/test/attributes/hx-put.js
@@ -0,0 +1,34 @@
+describe("hx-put attribute", function(){
+ beforeEach(function() {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function() {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('issues a PUT request', function()
+ {
+ this.server.respondWith("PUT", "/test", function(xhr){
+ xhr.respond(200, {}, "Putted!");
+ });
+
+ var btn = make('')
+ btn.click();
+ this.server.respond();
+ btn.innerHTML.should.equal("Putted!");
+ });
+
+ it('issues a PUT request w/ data-* prefix', function()
+ {
+ this.server.respondWith("PUT", "/test", function(xhr){
+ xhr.respond(200, {}, "Putted!");
+ });
+
+ var btn = make('')
+ btn.click();
+ this.server.respond();
+ btn.innerHTML.should.equal("Putted!");
+ });
+})
diff --git a/www/test/0.1.1/test/attributes/hx-select.js b/www/test/0.1.1/test/attributes/hx-select.js
new file mode 100644
index 00000000..c5868430
--- /dev/null
+++ b/www/test/0.1.1/test/attributes/hx-select.js
@@ -0,0 +1,40 @@
+describe("BOOTSTRAP - htmx AJAX Tests", function(){
+ beforeEach(function() {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function() {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('properly handles a partial of HTML', function()
+ {
+ var i = 1;
+ this.server.respondWith("GET", "/test", "
foo
bar
");
+ var div = make('');
+ div.click();
+ this.server.respond();
+ div.innerHTML.should.equal("
foo
");
+ });
+
+ it('properly handles a full HTML document', function()
+ {
+ var i = 1;
+ this.server.respondWith("GET", "/test", "
foo
bar
");
+ var div = make('');
+ div.click();
+ this.server.respond();
+ div.innerHTML.should.equal("
foo
");
+ });
+
+ it('properly handles a full HTML document w/ data-* prefix', function()
+ {
+ var i = 1;
+ this.server.respondWith("GET", "/test", "
foo
bar
");
+ var div = make('');
+ div.click();
+ this.server.respond();
+ div.innerHTML.should.equal("
');
+ div.click();
+ this.server.respond();
+ this.eventSource.wasClosed().should.equal(true)
+ })
+
+ it('is closed after removal with no close and activity', function () {
+ var div = make('
')
+ var div = byId("d1");
+ div.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('hx-vars can override parents', function () {
+ this.server.respondWith("POST", "/vars", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.equal("best");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ make('
')
+ var div = byId("d1");
+ div.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+ it('hx-vars do not override inputs', function () {
+ this.server.respondWith("POST", "/include", function (xhr) {
+ var params = getParameters(xhr);
+ params['i1'].should.equal("test");
+ xhr.respond(200, {}, "Clicked!")
+ });
+ var div = make('')
+ var input = byId("i1")
+ input.click();
+ this.server.respond();
+ div.innerHTML.should.equal("Clicked!");
+ });
+
+});
\ No newline at end of file
diff --git a/www/test/0.1.1/test/attributes/hx-ws.js b/www/test/0.1.1/test/attributes/hx-ws.js
new file mode 100644
index 00000000..de47075e
--- /dev/null
+++ b/www/test/0.1.1/test/attributes/hx-ws.js
@@ -0,0 +1,73 @@
+describe("hx-ws attribute", function() {
+
+ function mockWebsocket() {
+ var listener;
+ var lastSent;
+ var wasClosed = false;
+ var mockSocket = {
+ addEventListener : function(message, l) {
+ listener = l;
+ },
+ write : function(content) {
+ return listener({data:content});
+ },
+ send : function(data) {
+ lastSent = data;
+ },
+ getLastSent : function() {
+ return lastSent;
+ },
+ close : function() {
+ wasClosed = true;
+ },
+ wasClosed : function () {
+ return wasClosed;
+ }
+ };
+ return mockSocket;
+ }
+
+ beforeEach(function () {
+ this.server = makeServer();
+ var socket = mockWebsocket();
+ this.socket = socket;
+ clearWorkArea();
+ htmx.createWebSocket = function(){ return socket };
+ });
+ afterEach(function () {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('handles a basic call back', function () {
+ var div = make('
div1
div2
');
+ this.socket.write("
replaced
")
+ byId("d1").innerHTML.should.equal("replaced");
+ byId("d2").innerHTML.should.equal("div2");
+ })
+
+ it('handles a basic send', function () {
+ var div = make('
div1
');
+ byId("d1").click();
+ var lastSent = this.socket.getLastSent();
+ var data = JSON.parse(lastSent);
+ data.HEADERS["HX-Request"].should.equal("true");
+ })
+
+ it('is closed after removal', function () {
+ this.server.respondWith("GET", "/test", "Clicked!");
+ var div = make('');
+ div.click();
+ this.server.respond();
+ this.socket.wasClosed().should.equal(true)
+ })
+
+ it('is closed after removal with no close and activity', function () {
+ var div = make('');
+ div.parentElement.removeChild(div);
+ this.socket.write("
");
+ div.should.equal(htmx.find("#d1"));
+ div.should.equal(htmx.find(".c1"));
+ div.should.equal(htmx.find(".c2"));
+ div.should.equal(htmx.find(".c1.c2"));
+ });
+
+ it('should find properly from elt', function(){
+ var div = make("
");
+ htmx.find(div, "a").id.should.equal('a1');
+ });
+
+ it('should find all properly', function(){
+ var div = make("
");
+ htmx.findAll(".c1").length.should.equal(3);
+ htmx.findAll(".c2").length.should.equal(2);
+ htmx.findAll(".c3").length.should.equal(1);
+ });
+
+ it('should find all properly from elt', function(){
+ var div = make("
");
+ htmx.findAll(div, ".c1").length.should.equal(3);
+ htmx.findAll(div, ".c2").length.should.equal(2);
+ htmx.findAll(div,".c3").length.should.equal(1);
+ });
+
+ it('should find closest element properly', function () {
+ var div = make("
");
+ var a = htmx.find(div, "a");
+ htmx.closest(a, "div").should.equal(div);
+ });
+
+ it('should remove element properly', function () {
+ var div = make("
");
+ var a = htmx.find(div, "a");
+ htmx.remove(a);
+ div.innerHTML.should.equal("");
+ });
+
+ it('should add class properly', function () {
+ var div = make("");
+ div.classList.contains("foo").should.equal(false);
+ htmx.addClass(div, "foo");
+ div.classList.contains("foo").should.equal(true);
+ });
+
+ it('should add class properly after delay', function (done) {
+ var div = make("");
+ div.classList.contains("foo").should.equal(false);
+ htmx.addClass(div, "foo", 10);
+ div.classList.contains("foo").should.equal(false);
+ setTimeout(function () {
+ div.classList.contains("foo").should.equal(true);
+ done();
+ }, 20);
+ });
+
+ it('should remove class properly', function () {
+ var div = make("");
+ htmx.addClass(div, "foo");
+ div.classList.contains("foo").should.equal(true);
+ htmx.removeClass(div, "foo");
+ div.classList.contains("foo").should.equal(false);
+ });
+
+ it('should add class properly after delay', function (done) {
+ var div = make("");
+ htmx.addClass(div, "foo");
+ div.classList.contains("foo").should.equal(true);
+ htmx.removeClass(div, "foo", 10);
+ div.classList.contains("foo").should.equal(true);
+ setTimeout(function () {
+ div.classList.contains("foo").should.equal(false);
+ done();
+ }, 20);
+ });
+
+ it('should toggle class properly', function () {
+ var div = make("");
+ div.classList.contains("foo").should.equal(false);
+ htmx.toggleClass(div, "foo");
+ div.classList.contains("foo").should.equal(true);
+ htmx.toggleClass(div, "foo");
+ div.classList.contains("foo").should.equal(false);
+ });
+
+ it('should take class properly', function () {
+ var div1 = make("");
+ var div2 = make("");
+ var div3 = make("");
+
+ div1.classList.contains("foo").should.equal(false);
+ div2.classList.contains("foo").should.equal(false);
+ div3.classList.contains("foo").should.equal(false);
+
+ htmx.takeClass(div1, "foo");
+
+ div1.classList.contains("foo").should.equal(true);
+ div2.classList.contains("foo").should.equal(false);
+ div3.classList.contains("foo").should.equal(false);
+
+ htmx.takeClass(div2, "foo");
+
+ div1.classList.contains("foo").should.equal(false);
+ div2.classList.contains("foo").should.equal(true);
+ div3.classList.contains("foo").should.equal(false);
+
+ htmx.takeClass(div3, "foo");
+
+ div1.classList.contains("foo").should.equal(false);
+ div2.classList.contains("foo").should.equal(false);
+ div3.classList.contains("foo").should.equal(true);
+ });
+
+
+})
diff --git a/www/test/0.1.1/test/core/events.js b/www/test/0.1.1/test/core/events.js
new file mode 100644
index 00000000..4bb1674d
--- /dev/null
+++ b/www/test/0.1.1/test/core/events.js
@@ -0,0 +1,260 @@
+describe("Core htmx Events", function() {
+ beforeEach(function () {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function () {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it("htmx:load fires properly", function () {
+ var called = false;
+ var handler = htmx.on("htmx:load", function (evt) {
+ called = true;
+ });
+ try {
+ this.server.respondWith("GET", "/test", "");
+ this.server.respondWith("GET", "/test", "");
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(called, true);
+ } finally {
+ htmx.off("htmx:load", handler);
+ }
+ });
+
+ it("htmx:configRequest allows attribute addition", function () {
+ var handler = htmx.on("htmx:configRequest", function (evt) {
+ evt.detail.parameters['param'] = "true";
+ });
+ try {
+ var param = null;
+ this.server.respondWith("POST", "/test", function (xhr) {
+ param = getParameters(xhr)['param'];
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ param.should.equal("true");
+ } finally {
+ htmx.off("htmx:configRequest", handler);
+ }
+ });
+
+ it("htmx:configRequest is also dispatched in kebab-case", function () {
+ var handler = htmx.on("htmx:config-request", function (evt) {
+ evt.detail.parameters['param'] = "true";
+ });
+ try {
+ var param = null;
+ this.server.respondWith("POST", "/test", function (xhr) {
+ param = getParameters(xhr)['param'];
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ param.should.equal("true");
+ } finally {
+ htmx.off("htmx:config-request", handler);
+ }
+ });
+
+ it("events are only dispatched once if kebab and camel case match", function () {
+ var invoked = 0;
+ var handler = htmx.on("custom", function () {
+ invoked = invoked + 1
+ });
+ try {
+ var div = make("");
+ htmx.trigger(div, "custom");
+ invoked.should.equal(1);
+ } finally {
+ htmx.off("custom", handler);
+ }
+ });
+
+ it("htmx:configRequest allows attribute removal", function () {
+ var param = "foo";
+ var handler = htmx.on("htmx:configRequest", function (evt) {
+ delete evt.detail.parameters['param'];
+ });
+ try {
+ this.server.respondWith("POST", "/test", function (xhr) {
+ param = getParameters(xhr)['param'];
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(param, undefined);
+ } finally {
+ htmx.off("htmx:configRequest", handler);
+ }
+ });
+
+ it("htmx:configRequest allows header tweaking", function () {
+ var header = "foo";
+ var handler = htmx.on("htmx:configRequest", function (evt) {
+ evt.detail.headers['X-My-Header'] = "bar";
+ });
+ try {
+ this.server.respondWith("POST", "/test", function (xhr) {
+ header = xhr.requestHeaders['X-My-Header'];
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(header, "bar");
+ } finally {
+ htmx.off("htmx:configRequest", handler);
+ }
+ });
+
+ it("htmx:afterSwap is called when replacing outerHTML", function () {
+ var called = false;
+ var handler = htmx.on("htmx:afterSwap", function (evt) {
+ called = true;
+ });
+ try {
+ this.server.respondWith("POST", "/test", function (xhr) {
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(called, true);
+ } finally {
+ htmx.off("htmx:afterSwap", handler);
+ }
+ });
+
+ it("htmx:afterSettle is called when replacing outerHTML", function () {
+ var called = false;
+ var handler = htmx.on("htmx:afterSettle", function (evt) {
+ called = true;
+ });
+ try {
+ this.server.respondWith("POST", "/test", function (xhr) {
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(called, true);
+ } finally {
+ htmx.off("htmx:afterSettle", handler);
+ }
+ });
+
+ it("htmx:afterRequest is called after a successful request", function () {
+ var called = false;
+ var handler = htmx.on("htmx:afterRequest", function (evt) {
+ called = true;
+ });
+ try {
+ this.server.respondWith("POST", "/test", function (xhr) {
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(called, true);
+ } finally {
+ htmx.off("htmx:afterRequest", handler);
+ }
+ });
+
+ it("htmx:afterOnLoad is called after a successful request", function () {
+ var called = false;
+ var handler = htmx.on("htmx:afterOnLoad", function (evt) {
+ called = true;
+ });
+ try {
+ this.server.respondWith("POST", "/test", function (xhr) {
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(called, true);
+ } finally {
+ htmx.off("htmx:afterOnLoad", handler);
+ }
+ });
+
+ it("htmx:afterRequest is called after a failed request", function () {
+ var called = false;
+ var handler = htmx.on("htmx:afterRequest", function (evt) {
+ called = true;
+ });
+ try {
+ this.server.respondWith("POST", "/test", function (xhr) {
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(called, true);
+ } finally {
+ htmx.off("htmx:afterRequest", handler);
+ }
+ });
+
+ it("htmx:sendError is called after a failed request", function (done) {
+ var called = false;
+ var handler = htmx.on("htmx:sendError", function (evt) {
+ called = true;
+ });
+ this.server.restore(); // turn off server mock so connection doesn't work
+ var div = make("");
+ div.click();
+ setTimeout(function () {
+ htmx.off("htmx:sendError", handler);
+ should.equal(called, true);
+ done();
+ }, 30);
+ });
+
+ it("htmx:afterRequest is called when replacing outerHTML", function () {
+ var called = false;
+ var handler = htmx.on("htmx:afterRequest", function (evt) {
+ called = true;
+ });
+ try {
+ this.server.respondWith("POST", "/test", function (xhr) {
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(called, true);
+ } finally {
+ htmx.off("htmx:afterRequest", handler);
+ }
+ });
+
+ it("htmx:afterOnLoad is called when replacing outerHTML", function () {
+ var called = false;
+ var handler = htmx.on("htmx:afterOnLoad", function (evt) {
+ called = true;
+ });
+ try {
+ this.server.respondWith("POST", "/test", function (xhr) {
+ xhr.respond(200, {}, "");
+ });
+ var div = make("");
+ div.click();
+ this.server.respond();
+ should.equal(called, true);
+ } finally {
+ htmx.off("htmx:afterOnLoad", handler);
+ }
+ });
+
+});
+
diff --git a/www/test/0.1.1/test/core/headers.js b/www/test/0.1.1/test/core/headers.js
new file mode 100644
index 00000000..ab59f992
--- /dev/null
+++ b/www/test/0.1.1/test/core/headers.js
@@ -0,0 +1,118 @@
+describe("Core htmx AJAX headers", function() {
+ beforeEach(function () {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function () {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it("should include the HX-Request header", function(){
+ this.server.respondWith("GET", "/test", function(xhr){
+ xhr.requestHeaders['HX-Request'].should.be.equal('true');
+ xhr.respond(200, {}, "");
+ });
+ var div = make('');
+ div.click();
+ this.server.respond();
+ })
+
+ it("should include the HX-Trigger header", function(){
+ this.server.respondWith("GET", "/test", function(xhr){
+ xhr.requestHeaders['HX-Trigger'].should.equal('d1');
+ xhr.respond(200, {}, "");
+ });
+ var div = make('');
+ div.click();
+ this.server.respond();
+ })
+
+ it("should include the HX-Trigger-Name header", function(){
+ this.server.respondWith("GET", "/test", function(xhr){
+ xhr.requestHeaders['HX-Trigger-Name'].should.equal('n1');
+ xhr.respond(200, {}, "");
+ });
+ var div = make('');
+ div.click();
+ this.server.respond();
+ })
+
+ it("should include the HX-Target header", function(){
+ this.server.respondWith("GET", "/test", function(xhr){
+ xhr.requestHeaders['HX-Target'].should.equal('d1');
+ xhr.respond(200, {}, "");
+ });
+ var div = make('');
+ div.click();
+ this.server.respond();
+ })
+
+ it("should handle simple string HX-Trigger response header properly", function(){
+ this.server.respondWith("GET", "/test", [200, {"HX-Trigger" : "foo"}, ""]);
+
+ var div = make('');
+ var invokedEvent = false;
+ div.addEventListener("foo", function (evt) {
+ invokedEvent = true;
+ });
+ div.click();
+ this.server.respond();
+ invokedEvent.should.equal(true);
+ })
+
+ it("should handle basic JSON HX-Trigger response header properly", function(){
+ this.server.respondWith("GET", "/test", [200, {"HX-Trigger" : "{\"foo\":null}"}, ""]);
+
+ var div = make('');
+ var invokedEvent = false;
+ div.addEventListener("foo", function (evt) {
+ invokedEvent = true;
+ should.equal(null, evt.detail.value);
+ evt.detail.elt.should.equal(div);
+ });
+ div.click();
+ this.server.respond();
+ invokedEvent.should.equal(true);
+ })
+
+ it("should handle JSON with array arg HX-Trigger response header properly", function(){
+ this.server.respondWith("GET", "/test", [200, {"HX-Trigger" : "{\"foo\":[1, 2, 3]}"}, ""]);
+
+ var div = make('');
+ var invokedEvent = false;
+ div.addEventListener("foo", function (evt) {
+ invokedEvent = true;
+ evt.detail.elt.should.equal(div);
+ evt.detail.value.should.deep.equal([1, 2, 3]);
+ });
+ div.click();
+ this.server.respond();
+ invokedEvent.should.equal(true);
+ })
+
+ it("should handle JSON with array arg HX-Trigger response header properly", function(){
+ this.server.respondWith("GET", "/test", [200, {"HX-Trigger" : "{\"foo\":{\"a\":1, \"b\":2}}"}, ""]);
+
+ var div = make('');
+ var invokedEvent = false;
+ div.addEventListener("foo", function (evt) {
+ invokedEvent = true;
+ evt.detail.elt.should.equal(div);
+ evt.detail.a.should.equal(1);
+ evt.detail.b.should.equal(2);
+ });
+ div.click();
+ this.server.respond();
+ invokedEvent.should.equal(true);
+ })
+
+ it("should survive malformed JSON in HX-Trigger response header", function(){
+ this.server.respondWith("GET", "/test", [200, {"HX-Trigger" : "{not: valid}"}, ""]);
+
+ var div = make('');
+ div.click();
+ this.server.respond();
+ })
+
+});
diff --git a/www/test/0.1.1/test/core/internals.js b/www/test/0.1.1/test/core/internals.js
new file mode 100644
index 00000000..5089daf5
--- /dev/null
+++ b/www/test/0.1.1/test/core/internals.js
@@ -0,0 +1,23 @@
+describe("Core htmx internals Tests", function() {
+
+ it("makeFragment works with janky stuff", function(){
+ htmx._("makeFragment")("").tagName.should.equal("BODY");
+ htmx._("makeFragment")("").tagName.should.equal("BODY");
+
+ //NB - the tag name should be the *parent* element hosting the HTML since we use the fragment children
+ // for the swap
+ htmx._("makeFragment")("
").tagName.should.equal("TBODY");
+ })
+
+ it("set header works with non-ASCII values", function(){
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "/dummy");
+ htmx._("safelySetHeaderValue")(xhr, "Example", "привет");
+ // unfortunately I can't test the value :/
+ // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
+ })
+
+});
\ No newline at end of file
diff --git a/www/test/0.1.1/test/core/parameters.js b/www/test/0.1.1/test/core/parameters.js
new file mode 100644
index 00000000..f6b71a35
--- /dev/null
+++ b/www/test/0.1.1/test/core/parameters.js
@@ -0,0 +1,121 @@
+describe("Core htmx Parameter Handling", function() {
+ beforeEach(function () {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function () {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('Input includes value', function () {
+ var input = make('');
+ var vals = htmx._('getInputValues')(input);
+ vals['foo'].should.equal('bar');
+ })
+
+ it('Input includes value on get', function () {
+ var input = make('');
+ var vals = htmx._('getInputValues')(input, "get");
+ vals['foo'].should.equal('bar');
+ })
+
+ it('Input includes form', function () {
+ var form = make('');
+ var input = byId('i1');
+ var vals = htmx._('getInputValues')(input);
+ vals['foo'].should.equal('bar');
+ vals['do'].should.equal('rey');
+ })
+
+ it('Input doesnt include form on get', function () {
+ var form = make('');
+ var input = byId('i1');
+ var vals = htmx._('getInputValues')(input, 'get');
+ vals['foo'].should.equal('bar');
+ should.equal(vals['do'], undefined);
+ })
+
+ it('non-input includes form', function () {
+ var form = make('');
+ var div = byId('d1');
+ var vals = htmx._('getInputValues')(div, "post");
+ vals['do'].should.equal('rey');
+ })
+
+ it('non-input doesnt include form on get', function () {
+ var form = make('');
+ var div = byId('d1');
+ var vals = htmx._('getInputValues')(div, "get");
+ should.equal(vals['do'], undefined);
+ })
+
+ it('Basic form works on get', function () {
+ var form = make('');
+ var vals = htmx._('getInputValues')(form, 'get');
+ vals['foo'].should.equal('bar');
+ vals['do'].should.equal('rey');
+ })
+
+ it('Basic form works on non-get', function () {
+ var form = make('');
+ var vals = htmx._('getInputValues')(form, 'post');
+ vals['foo'].should.equal('bar');
+ vals['do'].should.equal('rey');
+ })
+
+ it('Double values are included as array', function () {
+ var form = make('');
+ var vals = htmx._('getInputValues')(form);
+ vals['foo'].should.equal('bar');
+ vals['do'].should.deep.equal(['rey', 'rey']);
+ })
+
+ it('Double values are included as array in correct order', function () {
+ var form = make('');
+ var vals = htmx._('getInputValues')(byId("i3"));
+ vals['foo'].should.equal('bar');
+ vals['do'].should.deep.equal(['rey1', 'rey2']);
+ })
+
+ it('hx-include works with form', function () {
+ var form = make('');
+ var div = make('');
+ var vals = htmx._('getInputValues')(div);
+ vals['foo'].should.equal('bar');
+ vals['do'].should.deep.equal(['rey', 'rey']);
+ })
+
+ it('hx-include works with input', function () {
+ var form = make('');
+ var div = make('');
+ var vals = htmx._('getInputValues')(div);
+ vals['foo'].should.equal('bar');
+ should.equal(vals['do'], undefined);
+ })
+
+ it('hx-include works with two inputs', function () {
+ var form = make('');
+ var div = make('');
+ var vals = htmx._('getInputValues')(div);
+ vals['foo'].should.equal('bar');
+ vals['do'].should.deep.equal(['rey', 'rey']);
+ })
+
+ it('hx-include works with two inputs, plus form', function () {
+ var form = make('');
+ var div = make('');
+ var vals = htmx._('getInputValues')(div);
+ vals['foo'].should.equal('bar');
+ vals['do'].should.deep.equal(['rey', 'rey']);
+ })
+
+ it('correctly URL escapes values', function () {
+ htmx._("urlEncode")({}).should.equal("");
+ htmx._("urlEncode")({"foo": "bar"}).should.equal("foo=bar");
+ htmx._("urlEncode")({"foo": "bar", "do" : "rey"}).should.equal("foo=bar&do=rey");
+ htmx._("urlEncode")({"foo": "bar", "do" : ["rey", "blah"]}).should.equal("foo=bar&do=rey&do=blah");
+ });
+
+});
+
diff --git a/www/test/0.1.1/test/core/perf.js b/www/test/0.1.1/test/core/perf.js
new file mode 100644
index 00000000..6fdbbbea
--- /dev/null
+++ b/www/test/0.1.1/test/core/perf.js
@@ -0,0 +1,70 @@
+describe("Core htmx perf Tests", function() {
+
+ var HTMX_HISTORY_CACHE_NAME = "htmx-history-cache";
+
+ beforeEach(function () {
+ this.server = makeServer();
+ clearWorkArea();
+ localStorage.removeItem(HTMX_HISTORY_CACHE_NAME);
+ });
+ afterEach(function () {
+ this.server.restore();
+ clearWorkArea();
+ localStorage.removeItem(HTMX_HISTORY_CACHE_NAME);
+ });
+
+ function stringRepeat(str, num) {
+ num = Number(num);
+
+ var result = '';
+ while (true) {
+ if (num & 1) { // (1)
+ result += str;
+ }
+ num >>>= 1; // (2)
+ if (num <= 0) break;
+ str += str;
+ }
+
+ return result;
+ }
+
+ it("DOM processing should be fast", function(){
+ this.server.respondWith("GET", "/test", "Clicked!");
+
+ // create an entry with a large content string (256k) and see how fast we can write and read it
+ // to local storage as a single entry
+ var str = stringRepeat("
", 30) + stringRepeat("
\n", 1000) + stringRepeat("
", 30);
+ var start = performance.now();
+ var stuff = make(str);
+ var end = performance.now();
+ var timeInMs = end - start;
+
+ // make sure the DOM actually processed
+ var firstBtn = stuff.querySelector("button");
+ firstBtn.click();
+ this.server.respond();
+ firstBtn.innerHTML.should.equal("Clicked!");
+
+ chai.assert(timeInMs < 100, "Should take less than 100ms on most platforms, took: " + timeInMs + "ms");
+ })
+
+ it("history implementation should be fast", function(){
+ // create an entry with a large content string (256k) and see how fast we can write and read it
+ // to local storage as a single entry
+ var entry = {url: stringRepeat("x", 32), content:stringRepeat("x", 256*1024)}
+ var array = [];
+ for (var i = 0; i < 10; i++) {
+ array.push(entry);
+ }
+ var start = performance.now();
+ var string = JSON.stringify(array);
+ localStorage.setItem(HTMX_HISTORY_CACHE_NAME, string);
+ var reReadString = localStorage.getItem(HTMX_HISTORY_CACHE_NAME);
+ var finalJson = JSON.parse(reReadString);
+ var end = performance.now();
+ var timeInMs = end - start;
+ chai.assert(timeInMs < 300, "Should take less than 300ms on most platforms");
+ })
+
+})
\ No newline at end of file
diff --git a/www/test/0.1.1/test/core/regressions.js b/www/test/0.1.1/test/core/regressions.js
new file mode 100644
index 00000000..ff36a937
--- /dev/null
+++ b/www/test/0.1.1/test/core/regressions.js
@@ -0,0 +1,92 @@
+describe("Core htmx Regression Tests", function(){
+
+ beforeEach(function() {
+ this.server = makeServer();
+ clearWorkArea();
+ });
+ afterEach(function() {
+ this.server.restore();
+ clearWorkArea();
+ });
+
+ it('SVGs process properly in IE11', function()
+ {
+ var btn = make('')
+ });
+
+ it ('Handles https://github.com/bigskysoftware/htmx/issues/4 properly', function() {
+ this.server.respondWith("GET", "/index2a.php",
+ "
I came from message oob swap I should be second
" +
+ "
I came from a message2 oob swap I should be third but I am in the wrong spot
" +
+ "I'm page2 content (non-swap) I should be first")
+
+ var h1 = make("
Kutty CLICK ME
" +
+ "" +
+ "" +
+ "")
+ h1.click();
+ this.server.respond();
+ htmx.find("#page2").innerHTML.should.equal("I'm page2 content (non-swap) I should be first")
+ htmx.find("#message").innerHTML.should.equal("I came from message oob swap I should be second")
+ htmx.find("#message2").innerHTML.should.equal("I came from a message2 oob swap I should be third but I am in the wrong spot")
+ });
+
+ it ('Handles https://github.com/bigskysoftware/htmx/issues/33 "empty values" properly', function() {
+ this.server.respondWith("POST", "/htmx.php", function (xhr) {
+ xhr.respond(200, {}, xhr.requestBody);
+ });
+
+ var form = make('')
+ form.click();
+ this.server.respond();
+ form.innerHTML.should.equal("variable=")
+ });
+
+ it ('name=id doesnt cause an error', function(){
+ this.server.respondWith("GET", "/test", "Foo")
+ var div = make('
Get It
')
+ div.click();
+ this.server.respond();
+ div.innerText.should.contain("Foo")
+ });
+
+ it ('empty id doesnt cause an error', function(){
+ this.server.respondWith("GET", "/test", "Foo\n")
+ var div = make('
Get It
')
+ div.click();
+ this.server.respond();
+ div.innerText.should.contain("Foo")
+ });
+
+ it ('id with dot in value doesnt cause an error', function(){
+ this.server.respondWith("GET", "/test", "Foo ");
+ var div = make('
Get It
');
+ div.click();
+ this.server.respond();
+ div.innerText.should.contain("Foo");
+ });
+
+ it ('@ symbol in attributes does not break requests', function(){
+ this.server.respondWith("GET", "/test", "
Foo
");
+ var div = make('
Get It
');
+ div.click();
+ this.server.respond();
+ byId("d1").getAttribute('@foo').should.equal('bar');
+ });
+
+ it ('@ symbol in attributes does not break attribute swizzling requests', function(){
+ this.server.respondWith("GET", "/test", "