0.0.1 update

This commit is contained in:
carson 2020-05-15 07:11:00 -07:00
parent 077ad83327
commit 1be6e3cfef
37 changed files with 49444 additions and 1 deletions

BIN
dist/kutty.min.js.gz vendored

Binary file not shown.

View File

@ -5,7 +5,7 @@
"AJAX",
"HTML"
],
"version": "0.0.1-alpha.3",
"version": "0.0.1",
"homepage": "https://kutty.org/",
"bugs": {
"url": "https://github.com/bigskysoftware/kutty/issues"

10854
www/test/0.0.1/node_modules/chai/chai.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

325
www/test/0.0.1/node_modules/mocha/mocha.css generated vendored Normal file
View File

@ -0,0 +1,325 @@
@charset "utf-8";
body {
margin:0;
}
#mocha {
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 60px 50px;
}
#mocha ul,
#mocha li {
margin: 0;
padding: 0;
}
#mocha ul {
list-style: none;
}
#mocha h1,
#mocha h2 {
margin: 0;
}
#mocha h1 {
margin-top: 15px;
font-size: 1em;
font-weight: 200;
}
#mocha h1 a {
text-decoration: none;
color: inherit;
}
#mocha h1 a:hover {
text-decoration: underline;
}
#mocha .suite .suite h1 {
margin-top: 0;
font-size: .8em;
}
#mocha .hidden {
display: none;
}
#mocha h2 {
font-size: 12px;
font-weight: normal;
cursor: pointer;
}
#mocha .suite {
margin-left: 15px;
}
#mocha .test {
margin-left: 15px;
overflow: hidden;
}
#mocha .test.pending:hover h2::after {
content: '(pending)';
font-family: arial, sans-serif;
}
#mocha .test.pass.medium .duration {
background: #c09853;
}
#mocha .test.pass.slow .duration {
background: #b94a48;
}
#mocha .test.pass::before {
content: '✓';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #00d6b2;
}
#mocha .test.pass .duration {
font-size: 9px;
margin-left: 5px;
padding: 2px 5px;
color: #fff;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
}
#mocha .test.pass.fast .duration {
display: none;
}
#mocha .test.pending {
color: #0b97c4;
}
#mocha .test.pending::before {
content: '◦';
color: #0b97c4;
}
#mocha .test.fail {
color: #c00;
}
#mocha .test.fail pre {
color: black;
}
#mocha .test.fail::before {
content: '✖';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #c00;
}
#mocha .test pre.error {
color: #c00;
max-height: 300px;
overflow: auto;
}
#mocha .test .html-error {
overflow: auto;
color: black;
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: -webkit-calc(100% - 42px);
max-width: -moz-calc(100% - 42px);
max-width: calc(100% - 42px); /*(2)*/
max-height: 300px;
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-box-shadow: 0 1px 3px #eee;
box-shadow: 0 1px 3px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
#mocha .test .html-error pre.error {
border: none;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: 0;
-moz-box-shadow: 0;
box-shadow: 0;
padding: 0;
margin: 0;
margin-top: 18px;
max-height: none;
}
/**
* (1): approximate for browsers not supporting calc
* (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
* ^^ seriously
*/
#mocha .test pre {
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: -webkit-calc(100% - 42px);
max-width: -moz-calc(100% - 42px);
max-width: calc(100% - 42px); /*(2)*/
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-box-shadow: 0 1px 3px #eee;
box-shadow: 0 1px 3px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
#mocha .test h2 {
position: relative;
}
#mocha .test a.replay {
position: absolute;
top: 3px;
right: 0;
text-decoration: none;
vertical-align: middle;
display: block;
width: 15px;
height: 15px;
line-height: 15px;
text-align: center;
background: #eee;
font-size: 15px;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
-webkit-transition:opacity 200ms;
-moz-transition:opacity 200ms;
-o-transition:opacity 200ms;
transition: opacity 200ms;
opacity: 0.3;
color: #888;
}
#mocha .test:hover a.replay {
opacity: 1;
}
#mocha-report.pass .test.fail {
display: none;
}
#mocha-report.fail .test.pass {
display: none;
}
#mocha-report.pending .test.pass,
#mocha-report.pending .test.fail {
display: none;
}
#mocha-report.pending .test.pass.pending {
display: block;
}
#mocha-error {
color: #c00;
font-size: 1.5em;
font-weight: 100;
letter-spacing: 1px;
}
#mocha-stats {
position: fixed;
top: 15px;
right: 10px;
font-size: 12px;
margin: 0;
color: #888;
z-index: 1;
}
#mocha-stats .progress {
float: right;
padding-top: 0;
/**
* Set safe initial values, so mochas .progress does not inherit these
* properties from Bootstrap .progress (which causes .progress height to
* equal line height set in Bootstrap).
*/
height: auto;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
background-color: initial;
}
#mocha-stats em {
color: black;
}
#mocha-stats a {
text-decoration: none;
color: inherit;
}
#mocha-stats a:hover {
border-bottom: 1px solid #eee;
}
#mocha-stats li {
display: inline-block;
margin: 0 5px;
list-style: none;
padding-top: 11px;
}
#mocha-stats canvas {
width: 40px;
height: 40px;
}
#mocha code .comment { color: #ddd; }
#mocha code .init { color: #2f6fad; }
#mocha code .string { color: #5890ad; }
#mocha code .keyword { color: #8a6343; }
#mocha code .number { color: #2f6fad; }
@media screen and (max-device-width: 480px) {
#mocha {
margin: 60px 0px;
}
#mocha #stats {
position: absolute;
}
}

18178
www/test/0.0.1/node_modules/mocha/mocha.js generated vendored Normal file

File diff suppressed because one or more lines are too long

16430
www/test/0.0.1/node_modules/sinon/pkg/sinon.js generated vendored Normal file

File diff suppressed because one or more lines are too long

1306
www/test/0.0.1/src/kutty.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
describe("kt-boost attribute", function() {
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
});
afterEach(function () {
this.server.restore();
clearWorkArea();
});
it('handles basic anchor properly', function () {
this.server.respondWith("GET", "/test", "Boosted");
var div = make('<div kt-target="this" kt-boost="true"><a id="a1" href="/test">Foo</a></div>');
var a = byId('a1');
a.click();
this.server.respond();
div.innerHTML.should.equal("Boosted");
})
it('handles basic form post properly', function () {
this.server.respondWith("POST", "/test", "Boosted");
this.server.respondWith("POST", "/test", "Boosted");
var div = make('<div kt-target="this" kt-boost="true"><form id="f1" action="/test" method="post"><button id="b1">Submit</button></form></div>');
var btn = byId('b1');
btn.click();
this.server.respond();
div.innerHTML.should.equal("Boosted");
})
it('handles basic form get properly', function () {
this.server.respondWith("GET", "/test", "Boosted");
var div = make('<div kt-target="this" kt-boost="true"><form id="f1" action="/test" method="get"><button id="b1">Submit</button></form></div>');
var btn = byId('b1');
btn.click();
this.server.respond();
div.innerHTML.should.equal("Boosted");
})
it('handles basic form with no explicit method property', function () {
this.server.respondWith("GET", "/test", "Boosted");
var div = make('<div kt-target="this" kt-boost="true"><form id="f1" action="/test"><button id="b1">Submit</button></form></div>');
var btn = byId('b1');
btn.click();
this.server.respond();
div.innerHTML.should.equal("Boosted");
})
});

View File

@ -0,0 +1,32 @@
describe("kt-classes attribute", function(){
beforeEach(function() {
this.server = makeServer();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('adds classes properly', function(done)
{
var div = make('<div kt-classes="add c1">Click Me!</div>')
should.equal(div.classList.length, 0);
setTimeout(function(){
should.equal(div.classList.contains("c1"), true);
done();
}, 100);
});
it('removes classes properly', function(done)
{
var div = make('<div class="foo bar" kt-classes="remove bar">Click Me!</div>')
should.equal(div.classList.contains("foo"), true);
should.equal(div.classList.contains("bar"), true);
setTimeout(function(){
should.equal(div.classList.contains("foo"), true);
should.equal(div.classList.contains("bar"), false);
done();
}, 100);
});
})

View File

@ -0,0 +1,23 @@
describe("kt-delete attribute", function(){
beforeEach(function() {
this.server = makeServer();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('issues a DELETE request with proper headers', function()
{
this.server.respondWith("DELETE", "/test", function(xhr){
xhr.requestHeaders['X-HTTP-Method-Override'].should.equal('DELETE');
xhr.respond(200, {}, "Deleted!");
});
var btn = make('<button kt-delete="/test">Click Me!</button>')
btn.click();
this.server.respond();
btn.innerHTML.should.equal("Deleted!");
});
})

View File

@ -0,0 +1,21 @@
describe("kt-error-url attribute", function(){
beforeEach(function() {
this.server = makeServer();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('Submits a POST with error content on bad request', function()
{
this.server.respondWith("POST", "/error", function(xhr){
should.equal(JSON.parse(xhr.requestBody).detail.xhr.status, 404);
});
var btn = make('<button kt-error-url="/error" kt-get="/bad">Click Me!</button>')
btn.click();
this.server.respond();
this.server.respond();
});
})

View File

@ -0,0 +1,30 @@
describe("kt-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('<button kt-get="/test">Click Me!</button>')
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) {
xhr.respond(200, {}, "Clicked!");
});
make('<form><input name="i1" value="value"/><button id="b1" kt-get="/test">Click Me!</inputbutton></form>')
var btn = byId("b1");
btn.click();
this.server.respond();
btn.innerHTML.should.equal("Clicked!");
});
});

View File

@ -0,0 +1,139 @@
describe("kt-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 = parseParams(xhr.requestBody);
params['i1'].should.equal("test");
xhr.respond(200, {}, "Clicked!")
});
var div = make('<div kt-target="this"><input kt-post="/include" kt-trigger="click" id="i1" name="i1" value="test"/></div>')
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 = parseParams(xhr.requestBody);
params['i1'].should.equal("test");
xhr.respond(200, {}, "Clicked!")
});
var div = make('<form kt-target="this"><div id="d1" kt-post="/include"></div><input name="i1" value="test"/></form>')
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 = parseParams(xhr.requestBody);
should.equal(params['i1'], undefined);
xhr.respond(200, {}, "Clicked!")
});
var div = make('<form kt-target="this"><div id="d1" kt-get="/include"></div><input name="i1" value="test"/></form>')
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 = parseParams(xhr.requestBody);
params['i1'].should.equal("test");
xhr.respond(200, {}, "Clicked!")
});
var div = make('<form kt-target="this"><input kt-post="/include" kt-trigger="click" id="i1" name="i1" value="test"/></form>')
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 = parseParams(xhr.requestBody);
params['i1'].should.deep.equal(["test", "test2"]);
xhr.respond(200, {}, "Clicked!")
});
var div = make('<form kt-target="this">' +
'<input kt-post="/include" kt-trigger="click" id="i1" name="i1" value="test"/>' +
'<input name="i1" value="test2"/>' +
'</form>')
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 = parseParams(xhr.requestBody);
params['i1'].should.equal("test");
xhr.respond(200, {}, "Clicked!")
});
var div = make('<form id="f1" kt-target="this">' +
'<input kt-include="#f1" kt-post="/include" kt-trigger="click" id="i1" name="i1" value="test"/>' +
'</form>')
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 = parseParams(xhr.requestBody);
params['i1'].should.equal("test");
xhr.respond(200, {}, "Clicked!")
});
make('<input id="i1" name="i1" value="test"/>');
var div = make('<div kt-post="/include" kt-include="#i1"></div>')
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 = parseParams(xhr.requestBody);
params['i1'].should.equal("test");
params['i2'].should.equal("test");
xhr.respond(200, {}, "Clicked!")
});
make('<input id="i1" name="i1" value="test"/>');
make('<input id="i2" name="i2" value="test"/>');
var div = make('<div kt-post="/include" kt-include="#i1, #i2"></div>')
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 = parseParams(xhr.requestBody);
params['i1'].should.equal("test");
params['i2'].should.equal("test");
xhr.respond(200, {}, "Clicked!")
});
make('<form id="f1">' +
'<input name="i1" value="test"/>' +
'<input name="i2" value="test"/>' +
'</form> ');
var div = make('<div kt-post="/include" kt-include="#f1"></div>')
div.click();
this.server.respond();
div.innerHTML.should.equal("Clicked!");
});
});

View File

@ -0,0 +1,36 @@
describe("kt-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('<button kt-get="/test">Click Me!</button>')
btn.click();
btn.classList.contains("kutty-request").should.equal(true);
this.server.respond();
btn.classList.contains("kutty-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('<button kt-get="/test" kt-indicator="#a1, #a2">Click Me!</button>')
var a1 = make('<a id="a1"></a>')
var a2 = make('<a id="a2"></a>')
btn.click();
btn.classList.contains("kutty-request").should.equal(false);
a1.classList.contains("kutty-request").should.equal(true);
a2.classList.contains("kutty-request").should.equal(true);
this.server.respond();
btn.classList.contains("kutty-request").should.equal(false);
a1.classList.contains("kutty-request").should.equal(false);
a2.classList.contains("kutty-request").should.equal(false);
});
})

View File

@ -0,0 +1,83 @@
describe("kt-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 = parseParams(xhr.requestBody);
should.equal(params['i1'], undefined);
should.equal(params['i2'], undefined);
should.equal(params['i3'], undefined);
xhr.respond(200, {}, "Clicked!")
});
var form = make('<form kt-trigger="click" kt-post="/params" kt-params="none">' +
'<input name="i1" value="test"/>' +
'<input name="i2" value="test"/>' +
'<input name="i3" value="test"/>' +
'</form> ');
form.click();
this.server.respond();
form.innerHTML.should.equal("Clicked!");
});
it('"*" includes all params', function () {
this.server.respondWith("POST", "/params", function (xhr) {
var params = parseParams(xhr.requestBody);
should.equal(params['i1'], "test");
should.equal(params['i2'], "test");
should.equal(params['i3'], "test");
xhr.respond(200, {}, "Clicked!")
});
var form = make('<form kt-trigger="click" kt-post="/params" kt-params="*">' +
'<input name="i1" value="test"/>' +
'<input name="i2" value="test"/>' +
'<input name="i3" value="test"/>' +
'</form> ');
form.click();
this.server.respond();
form.innerHTML.should.equal("Clicked!");
});
it('named includes works', function () {
this.server.respondWith("POST", "/params", function (xhr) {
var params = parseParams(xhr.requestBody);
should.equal(params['i1'], "test");
should.equal(params['i2'], undefined);
should.equal(params['i3'], "test");
xhr.respond(200, {}, "Clicked!")
});
var form = make('<form kt-trigger="click" kt-post="/params" kt-params="i1, i3">' +
'<input name="i1" value="test"/>' +
'<input name="i2" value="test"/>' +
'<input name="i3" value="test"/>' +
'</form> ');
form.click();
this.server.respond();
form.innerHTML.should.equal("Clicked!");
});
it('named exclude works', function () {
this.server.respondWith("POST", "/params", function (xhr) {
var params = parseParams(xhr.requestBody);
should.equal(params['i1'], undefined);
should.equal(params['i2'], "test");
should.equal(params['i3'], undefined);
xhr.respond(200, {}, "Clicked!")
});
var form = make('<form kt-trigger="click" kt-post="/params" kt-params="not i1, i3">' +
'<input name="i1" value="test"/>' +
'<input name="i2" value="test"/>' +
'<input name="i3" value="test"/>' +
'</form> ');
form.click();
this.server.respond();
form.innerHTML.should.equal("Clicked!");
});
});

View File

@ -0,0 +1,23 @@
describe("kt-patch attribute", function(){
beforeEach(function() {
this.server = makeServer();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('issues a PATCH request with proper headers', function()
{
this.server.respondWith("PATCH", "/test", function(xhr){
xhr.requestHeaders['X-HTTP-Method-Override'].should.equal('PATCH');
xhr.respond(200, {}, "Patched!");
});
var btn = make('<button kt-patch="/test">Click Me!</button>')
btn.click();
this.server.respond();
btn.innerHTML.should.equal("Patched!");
});
})

View File

@ -0,0 +1,23 @@
describe("kt-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('<button kt-post="/test">Click Me!</button>')
btn.click();
this.server.respond();
btn.innerHTML.should.equal("Posted!");
});
})

View File

@ -0,0 +1,123 @@
describe("kt-push-url attribute", function() {
var KUTTY_HISTORY_CACHE = "kutty-history-cache";
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
localStorage.removeItem(KUTTY_HISTORY_CACHE);
});
afterEach(function () {
this.server.restore();
clearWorkArea();
localStorage.removeItem(KUTTY_HISTORY_CACHE);
});
it("navigation should push an element into the cache ", function () {
this.server.respondWith("GET", "/test", "second");
getWorkArea().innerHTML.should.be.equal("");
var div = make('<div kt-push-url="true" kt-get="/test">first</div>');
div.click();
this.server.respond();
getWorkArea().textContent.should.equal("second")
var cache = JSON.parse(localStorage.getItem(KUTTY_HISTORY_CACHE));
cache.length.should.equal(1);
});
it("restore should return old value", function () {
this.server.respondWith("GET", "/test1", '<div id="d2" kt-push-url="true" kt-get="/test2" kt-swap="outerHTML settle:0">test1</div>');
this.server.respondWith("GET", "/test2", '<div id="d3" kt-push-url="true" kt-get="/test3" kt-swap="outerHTML settle:0">test2</div>');
make('<div id="d1" kt-push-url="true" kt-get="/test1" kt-swap="outerHTML settle:0">init</div>');
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(KUTTY_HISTORY_CACHE));
cache.length.should.equal(2);
kutty._('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, {}, '<div id="d1" kt-push-url="true" kt-get="/test' + x + '" kt-swap="outerHTML settle:0"></div>')
});
getWorkArea().innerHTML.should.be.equal("");
make('<div id="d1" kt-push-url="true" kt-get="/test" kt-swap="outerHTML settle:0"></div>');
for (var i = 0; i < 20; i++) { // issue 20 requests
byId("d1").click();
this.server.respond();
}
var cache = JSON.parse(localStorage.getItem(KUTTY_HISTORY_CACHE));
cache.length.should.equal(10); // should only be 10 elements
});
it("cache miss should issue another GET", function () {
this.server.respondWith("GET", "/test1", '<div id="d2" kt-push-url="true" kt-get="/test2" kt-swap="outerHTML settle:0">test1</div>');
this.server.respondWith("GET", "/test2", '<div id="d3" kt-push-url="true" kt-get="/test3" kt-swap="outerHTML settle:0">test2</div>');
make('<div id="d1" kt-push-url="true" kt-get="/test1" kt-swap="outerHTML settle:0">init</div>');
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(KUTTY_HISTORY_CACHE));
cache.length.should.equal(2);
localStorage.removeItem(KUTTY_HISTORY_CACHE); // clear cache
kutty._('restoreHistory')("/test1")
this.server.respond();
getWorkArea().textContent.should.equal("test1")
});
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("implementation details 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(KUTTY_HISTORY_CACHE, string);
var reReadString = localStorage.getItem(KUTTY_HISTORY_CACHE);
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");
})
});

View File

@ -0,0 +1,23 @@
describe("kt-put attribute", function(){
beforeEach(function() {
this.server = makeServer();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('issues a PUT request with proper headers', function()
{
this.server.respondWith("PUT", "/test", function(xhr){
xhr.requestHeaders['X-HTTP-Method-Override'].should.equal('PUT');
xhr.respond(200, {}, "Putted!");
});
var btn = make('<button kt-put="/test">Click Me!</button>')
btn.click();
this.server.respond();
btn.innerHTML.should.equal("Putted!");
});
})

View File

@ -0,0 +1,30 @@
describe("BOOTSTRAP - kutty 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", "<div id='d1'>foo</div><div id='d2'>bar</div>");
var div = make('<div kt-get="/test" kt-select="#d1"></div>');
div.click();
this.server.respond();
div.innerHTML.should.equal("<div id=\"d1\">foo</div>");
});
it('properly handles a full HTML document', function()
{
var i = 1;
this.server.respondWith("GET", "/test", "<html><body><div id='d1'>foo</div><div id='d2'>bar</div></body></html>");
var div = make('<div kt-get="/test" kt-select="#d1"></div>');
div.click();
this.server.respond();
div.innerHTML.should.equal("<div id=\"d1\">foo</div>");
});
})

View File

@ -0,0 +1,30 @@
describe("kt-swap-oob attribute", function () {
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
});
afterEach(function () {
this.server.restore();
clearWorkArea();
});
it('handles basic response properly', function () {
this.server.respondWith("GET", "/test", "Clicked<div id='d1' kt-swap-oob='true'>Swapped</div>");
var div = make('<div kt-get="/test">click me</div>');
make('<div id="d1"></div>');
div.click();
this.server.respond();
div.innerHTML.should.equal("Clicked");
byId("d1").innerHTML.should.equal("Swapped");
})
it('handles no id match properly', function () {
this.server.respondWith("GET", "/test", "Clicked<div id='d1' kt-swap-oob='true'>Swapped</div>");
var div = make('<div kt-get="/test">click me</div>');
div.click();
this.server.respond();
div.innerText.should.equal("Clicked");
})
});

View File

@ -0,0 +1,249 @@
describe("kt-swap attribute", function(){
beforeEach(function() {
this.server = makeServer();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('swap innerHTML properly', function()
{
this.server.respondWith("GET", "/test", '<a kt-get="/test2">Click Me</a>');
this.server.respondWith("GET", "/test2", "Clicked!");
var div = make('<div kt-get="/test"></div>')
div.click();
this.server.respond();
div.innerHTML.should.equal('<a kt-get="/test2">Click Me</a>');
var a = div.querySelector('a');
a.click();
this.server.respond();
a.innerHTML.should.equal('Clicked!');
});
it('swap outerHTML properly', function()
{
this.server.respondWith("GET", "/test", '<a id="a1" kt-get="/test2">Click Me</a>');
this.server.respondWith("GET", "/test2", "Clicked!");
var div = make('<div id="d1" kt-get="/test" kt-swap="outerHTML"></div>')
div.click();
should.equal(byId("d1"), div);
this.server.respond();
should.equal(byId("d1"), null);
byId("a1").click();
this.server.respond();
byId("a1").innerHTML.should.equal('Clicked!');
});
it('swap beforebegin properly', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="beforebegin">*</div>')
var parent = div.parentElement;
div.click();
this.server.respond();
div.innerText.should.equal("*");
removeWhiteSpace(parent.innerText).should.equal("1*");
byId("a1").click();
this.server.respond();
removeWhiteSpace(parent.innerText).should.equal("**");
div.click();
this.server.respond();
div.innerText.should.equal("*");
removeWhiteSpace(parent.innerText).should.equal("*2*");
byId("a2").click();
this.server.respond();
removeWhiteSpace(parent.innerText).should.equal("***");
});
it('swap afterbegin properly', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="afterbegin">*</div>')
div.click();
this.server.respond();
div.innerText.should.equal("1*");
byId("a1").click();
this.server.respond();
div.innerText.should.equal("**");
div.click();
this.server.respond();
div.innerText.should.equal("2**");
byId("a2").click();
this.server.respond();
div.innerText.should.equal("***");
});
it('swap afterbegin properly with no initial content', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="afterbegin"></div>')
div.click();
this.server.respond();
div.innerText.should.equal("1");
byId("a1").click();
this.server.respond();
div.innerText.should.equal("*");
div.click();
this.server.respond();
div.innerText.should.equal("2*");
byId("a2").click();
this.server.respond();
div.innerText.should.equal("**");
});
it('swap afterend properly', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="afterend">*</div>')
var parent = div.parentElement;
div.click();
this.server.respond();
div.innerText.should.equal("*");
removeWhiteSpace(parent.innerText).should.equal("*1");
byId("a1").click();
this.server.respond();
removeWhiteSpace(parent.innerText).should.equal("**");
div.click();
this.server.respond();
div.innerText.should.equal("*");
removeWhiteSpace(parent.innerText).should.equal("*2*");
byId("a2").click();
this.server.respond();
removeWhiteSpace(parent.innerText).should.equal("***");
});
it('swap beforeend properly', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="beforeend">*</div>')
div.click();
this.server.respond();
div.innerText.should.equal("*1");
byId("a1").click();
this.server.respond();
div.innerText.should.equal("**");
div.click();
this.server.respond();
div.innerText.should.equal("**2");
byId("a2").click();
this.server.respond();
div.innerText.should.equal("***");
});
it('swap beforeend properly with no initial content', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="beforeend"></div>')
div.click();
this.server.respond();
div.innerText.should.equal("1");
byId("a1").click();
this.server.respond();
div.innerText.should.equal("*");
div.click();
this.server.respond();
div.innerText.should.equal("*2");
byId("a2").click();
this.server.respond();
div.innerText.should.equal("**");
});
it('properly parses various swap specifications', function(){
var swapSpec = kutty._("getSwapSpecification"); // internal function for swap spec
swapSpec(make("<div/>")).swapStyle.should.equal("innerHTML")
swapSpec(make("<div kt-swap='innerHTML'/>")).swapStyle.should.equal("innerHTML")
swapSpec(make("<div kt-swap='innerHTML'/>")).swapDelay.should.equal(0)
swapSpec(make("<div kt-swap='innerHTML'/>")).settleDelay.should.equal(100)
swapSpec(make("<div kt-swap='innerHTML swap:10'/>")).swapDelay.should.equal(10)
swapSpec(make("<div kt-swap='innerHTML settle:10'/>")).settleDelay.should.equal(10)
swapSpec(make("<div kt-swap='innerHTML swap:10 settle:11'/>")).swapDelay.should.equal(10)
swapSpec(make("<div kt-swap='innerHTML swap:10 settle:11'/>")).settleDelay.should.equal(11)
swapSpec(make("<div kt-swap='innerHTML settle:11 swap:10'/>")).swapDelay.should.equal(10)
swapSpec(make("<div kt-swap='innerHTML settle:11 swap:10'/>")).settleDelay.should.equal(11)
swapSpec(make("<div kt-swap='innerHTML nonsense settle:11 swap:10'/>")).settleDelay.should.equal(11)
swapSpec(make("<div kt-swap='innerHTML nonsense settle:11 swap:10 '/>")).settleDelay.should.equal(11)
})
it('works with a swap delay', function(done) {
this.server.respondWith("GET", "/test", "Clicked!");
var div = make("<div kt-get='/test' kt-swap='innerHTML swap:10ms'></div>");
div.click();
this.server.respond();
div.innerText.should.equal("");
setTimeout(function () {
div.innerText.should.equal("Clicked!");
done();
}, 30);
});
it('works with a settle delay', function(done) {
this.server.respondWith("GET", "/test", "<div id='d1' class='foo' kt-get='/test' kt-swap='outerHTML settle:10ms'></div>");
var div = make("<div id='d1' kt-get='/test' kt-swap='outerHTML settle:10ms'></div>");
div.click();
this.server.respond();
div.classList.contains('foo').should.equal(false);
setTimeout(function () {
byId('d1').classList.contains('foo').should.equal(true);
done();
}, 30);
});
})

View File

@ -0,0 +1,71 @@
describe("kt-target attribute", function(){
beforeEach(function() {
this.server = sinon.fakeServer.create();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('targets an adjacent element properly', function()
{
this.server.respondWith("GET", "/test", "Clicked!");
var btn = make('<button kt-target="#d1" kt-get="/test">Click Me!</button>')
var div1 = make('<div id="d1"></div>')
btn.click();
this.server.respond();
div1.innerHTML.should.equal("Clicked!");
});
it('targets a parent element properly', function()
{
this.server.respondWith("GET", "/test", "Clicked!");
var div1 = make('<div id="d1"><button id="b1" kt-target="#d1" kt-get="/test">Click Me!</button></div>')
var btn = byId("b1")
btn.click();
this.server.respond();
div1.innerHTML.should.equal("Clicked!");
});
it('targets a `this` element properly', function()
{
this.server.respondWith("GET", "/test", "Clicked!");
var div1 = make('<div kt-target="this"><button id="b1" kt-get="/test">Click Me!</button></div>')
var btn = byId("b1")
btn.click();
this.server.respond();
div1.innerHTML.should.equal("Clicked!");
});
it('targets a `closest` element properly', function()
{
this.server.respondWith("GET", "/test", "Clicked!");
var div1 = make('<div><p><i><button id="b1" kt-target="closest div" kt-get="/test">Click Me!</button></i></p></div>')
var btn = byId("b1")
btn.click();
this.server.respond();
div1.innerHTML.should.equal("Clicked!");
});
it('targets an inner element properly', function()
{
this.server.respondWith("GET", "/test", "Clicked!");
var btn = make('<button kt-target="#d1" kt-get="/test">Click Me!<div id="d1"></div></button>')
var div1 = byId("d1")
btn.click();
this.server.respond();
div1.innerHTML.should.equal("Clicked!");
});
it('handles bad target gracefully', function()
{
this.server.respondWith("GET", "/test", "Clicked!");
var btn = make('<button kt-target="bad" kt-get="/test">Click Me!</button>')
btn.click();
this.server.respond();
btn.innerHTML.should.equal("Click Me!");
});
})

View File

@ -0,0 +1,89 @@
describe("kt-trigger attribute", function(){
beforeEach(function() {
this.server = sinon.fakeServer.create();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('non-default value works', function()
{
this.server.respondWith("GET", "/test", "Clicked!");
var form = make('<form kt-get="/test" kt-trigger="click">Click Me!</form>');
form.click();
form.innerHTML.should.equal("Click Me!");
this.server.respond();
form.innerHTML.should.equal("Clicked!");
});
it('changed modifier works', function()
{
var requests = 0;
this.server.respondWith("GET", "/test", function (xhr) {
requests++;
xhr.respond(200, {}, "Requests: " + requests);
});
var input = make('<input kt-trigger="click changed" kt-target="#d1" kt-get="/test" value="foo"/>');
var div = make('<div id="d1"></div>');
input.click();
this.server.respond();
div.innerHTML.should.equal("Requests: 1");
input.click();
this.server.respond();
div.innerHTML.should.equal("Requests: 1");
input.value = "bar";
input.click();
this.server.respond();
div.innerHTML.should.equal("Requests: 2");
input.click();
this.server.respond();
div.innerHTML.should.equal("Requests: 2");
});
it('once modifier works', function()
{
var requests = 0;
this.server.respondWith("GET", "/test", function (xhr) {
requests++;
xhr.respond(200, {}, "Requests: " + requests);
});
var input = make('<input kt-trigger="click once" kt-target="#d1" kt-get="/test" value="foo"/>');
var div = make('<div id="d1"></div>');
input.click();
this.server.respond();
div.innerHTML.should.equal("Requests: 1");
input.click();
this.server.respond();
div.innerHTML.should.equal("Requests: 1");
input.value = "bar";
input.click();
this.server.respond();
div.innerHTML.should.equal("Requests: 1");
input.click();
this.server.respond();
div.innerHTML.should.equal("Requests: 1");
});
it('polling works', function(complete)
{
var requests = 0;
this.server.respondWith("GET", "/test", function (xhr) {
requests++;
if (requests > 5) {
complete();
// cancel polling with a
xhr.respond(286, {}, "Requests: " + requests);
} else {
xhr.respond(200, {}, "Requests: " + requests);
}
});
this.server.autoRespond = true;
this.server.autoRespondAfter = 0;
make('<div kt-trigger="every 10ms" kt-get="/test"/>');
});
})

View File

@ -0,0 +1,110 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Mocha Tests</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="../node_modules/chai/chai.js"></script>
<script src="../node_modules/mocha/mocha.js"></script>
<script src="../node_modules/sinon/pkg/sinon.js"></script>
<script src="../src/kutty.js"></script>
<script class="mocha-init">
mocha.setup('bdd');
mocha.checkLeaks();
should = chai.should();
</script>
<script src="util/util.js"></script>
<script>
describe("Browser Only Tests", function() {
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
});
afterEach(function () {
this.server.restore();
clearWorkArea();
});
it("should handle a basic back button click", function (done) {
this.server.respondWith("GET", "/test", "second");
getWorkArea().innerHTML.should.be.equal("");
var div = make('<div kt-push-url="true" kt-get="/test">first</div>');
div.click();
this.server.respond();
getWorkArea().textContent.should.equal("second")
history.back();
setTimeout(function(){
getWorkArea().textContent.should.equal("first");
done();
}, 20);
});
it("should handle two forward clicks then back twice", function (done) {
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, "" + i);
});
getWorkArea().innerHTML.should.equal("");
var div = make('<div kt-push-url="true" kt-get="/test" class="">0</div>');
div.click();
this.server.respond();
getWorkArea().textContent.should.equal("1")
div.click();
this.server.respond();
getWorkArea().textContent.should.equal("2")
history.back();
setTimeout(function(){
getWorkArea().textContent.should.equal("1");
history.back();
setTimeout(function(){
getWorkArea().textContent.should.equal("0");
done();
}, 20);
}, 20);
})
it("should handle a back, forward, back button click", function (done) {
this.server.respondWith("GET", "/test", "second");
getWorkArea().innerHTML.should.equal("");
var div = make('<div kt-push-url="true" kt-get="/test" class="">first</div>');
div.click();
this.server.respond();
getWorkArea().textContent.should.equal("second")
history.back();
setTimeout(function(){
getWorkArea().textContent.should.equal("first");
history.forward();
setTimeout(function() {
getWorkArea().textContent.should.equal("second");
history.back();
setTimeout(function() {
getWorkArea().textContent.should.equal("first");
done();
}, 20);
}, 20);
}, 20);
})
});
</script>
<script class="mocha-exec">
mocha.run();
</script>
<em>Work Area</em>
<hr/>
<div id="work-area" kt-history-elt>
</div>
</body>
</html>

View File

@ -0,0 +1,388 @@
describe("Core kutty AJAX Tests", function(){
beforeEach(function() {
this.server = makeServer();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
// bootstrap test
it('issues a GET request on click and swaps content', function()
{
this.server.respondWith("GET", "/test", "Clicked!");
var btn = make('<button kt-get="/test">Click Me!</button>')
btn.click();
this.server.respond();
btn.innerHTML.should.equal("Clicked!");
});
it('processes inner content properly', function()
{
this.server.respondWith("GET", "/test", '<a kt-get="/test2">Click Me</a>');
this.server.respondWith("GET", "/test2", "Clicked!");
var div = make('<div kt-get="/test"></div>')
div.click();
this.server.respond();
div.innerHTML.should.equal('<a kt-get="/test2">Click Me</a>');
var a = div.querySelector('a');
a.click();
this.server.respond();
a.innerHTML.should.equal('Clicked!');
});
it('handles swap outerHTML properly', function()
{
this.server.respondWith("GET", "/test", '<a id="a1" kt-get="/test2">Click Me</a>');
this.server.respondWith("GET", "/test2", "Clicked!");
var div = make('<div id="d1" kt-get="/test" kt-swap="outerHTML"></div>')
div.click();
should.equal(byId("d1"), div);
this.server.respond();
should.equal(byId("d1"), null);
byId("a1").click();
this.server.respond();
byId("a1").innerHTML.should.equal('Clicked!');
});
it('handles beforebegin properly', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="beforebegin">*</div>')
var parent = div.parentElement;
div.click();
this.server.respond();
div.innerText.should.equal("*");
removeWhiteSpace(parent.innerText).should.equal("1*");
byId("a1").click();
this.server.respond();
removeWhiteSpace(parent.innerText).should.equal("**");
div.click();
this.server.respond();
div.innerText.should.equal("*");
removeWhiteSpace(parent.innerText).should.equal("*2*");
byId("a2").click();
this.server.respond();
removeWhiteSpace(parent.innerText).should.equal("***");
});
it('handles afterbegin properly', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="afterbegin">*</div>')
div.click();
this.server.respond();
div.innerText.should.equal("1*");
byId("a1").click();
this.server.respond();
div.innerText.should.equal("**");
div.click();
this.server.respond();
div.innerText.should.equal("2**");
byId("a2").click();
this.server.respond();
div.innerText.should.equal("***");
});
it('handles afterbegin properly with no initial content', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="afterbegin"></div>')
div.click();
this.server.respond();
div.innerText.should.equal("1");
byId("a1").click();
this.server.respond();
div.innerText.should.equal("*");
div.click();
this.server.respond();
div.innerText.should.equal("2*");
byId("a2").click();
this.server.respond();
div.innerText.should.equal("**");
});
it('handles afterend properly', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="afterend">*</div>')
var parent = div.parentElement;
div.click();
this.server.respond();
div.innerText.should.equal("*");
removeWhiteSpace(parent.innerText).should.equal("*1");
byId("a1").click();
this.server.respond();
removeWhiteSpace(parent.innerText).should.equal("**");
div.click();
this.server.respond();
div.innerText.should.equal("*");
removeWhiteSpace(parent.innerText).should.equal("*2*");
byId("a2").click();
this.server.respond();
removeWhiteSpace(parent.innerText).should.equal("***");
});
it('handles beforeend properly', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="beforeend">*</div>')
div.click();
this.server.respond();
div.innerText.should.equal("*1");
byId("a1").click();
this.server.respond();
div.innerText.should.equal("**");
div.click();
this.server.respond();
div.innerText.should.equal("**2");
byId("a2").click();
this.server.respond();
div.innerText.should.equal("***");
});
it('handles beforeend properly with no initial content', function()
{
var i = 0;
this.server.respondWith("GET", "/test", function(xhr){
i++;
xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>');
});
this.server.respondWith("GET", "/test2", "*");
var div = make('<div kt-get="/test" kt-swap="beforeend"></div>')
div.click();
this.server.respond();
div.innerText.should.equal("1");
byId("a1").click();
this.server.respond();
div.innerText.should.equal("*");
div.click();
this.server.respond();
div.innerText.should.equal("*2");
byId("a2").click();
this.server.respond();
div.innerText.should.equal("**");
});
it('handles kt-target properly', function()
{
this.server.respondWith("GET", "/test", "Clicked!");
var btn = make('<button kt-get="/test" kt-target="#s1">Click Me!</button>');
var target = make('<span id="s1">Initial</span>');
btn.click();
target.innerHTML.should.equal("Initial");
this.server.respond();
target.innerHTML.should.equal("Clicked!");
});
it('handles 204 NO CONTENT responses properly', function()
{
this.server.respondWith("GET", "/test", [204, {}, "No Content!"]);
var btn = make('<button kt-get="/test">Click Me!</button>');
btn.click();
btn.innerHTML.should.equal("Click Me!");
this.server.respond();
btn.innerHTML.should.equal("Click Me!");
});
it('handles kt-trigger with non-default value', function()
{
this.server.respondWith("GET", "/test", "Clicked!");
var form = make('<form kt-get="/test" kt-trigger="click">Click Me!</form>');
form.click();
form.innerHTML.should.equal("Click Me!");
this.server.respond();
form.innerHTML.should.equal("Clicked!");
});
it('handles kt-trigger with load event', function()
{
this.server.respondWith("GET", "/test", "Loaded!");
var div = make('<div kt-get="/test" kt-trigger="load">Load Me!</div>');
div.innerHTML.should.equal("Load Me!");
this.server.respond();
div.innerHTML.should.equal("Loaded!");
});
it('sets the content type of the request properly', function (done) {
this.server.respondWith("GET", "/test", function(xhr){
xhr.respond(200, {}, "done");
xhr.overriddenMimeType.should.equal("text/html");
done();
});
var div = make('<div kt-get="/test">Click Me!</div>');
div.click();
this.server.respond();
});
it('doesnt issue two requests when clicked twice before response', function()
{
var i = 1;
this.server.respondWith("GET", "/test", function (xhr) {
xhr.respond(200, {}, "click " + i);
i++
});
var div = make('<div kt-get="/test"></div>');
div.click();
div.click();
this.server.respond();
div.innerHTML.should.equal("click 1");
});
it('properly handles kt-select for basic situation', function()
{
var i = 1;
this.server.respondWith("GET", "/test", "<div id='d1'>foo</div><div id='d2'>bar</div>");
var div = make('<div kt-get="/test" kt-select="#d1"></div>');
div.click();
this.server.respond();
div.innerHTML.should.equal("<div id=\"d1\">foo</div>");
});
it('properly handles kt-select for full html document situation', function()
{
var i = 1;
this.server.respondWith("GET", "/test", "<html><body><div id='d1'>foo</div><div id='d2'>bar</div></body></html>");
var div = make('<div kt-get="/test" kt-select="#d1"></div>');
div.click();
this.server.respond();
div.innerHTML.should.equal("<div id=\"d1\">foo</div>");
});
it('properly handles checkbox inputs', function()
{
var values;
this.server.respondWith("Post", "/test", function (xhr) {
values = parseParams(xhr.requestBody);
xhr.respond(204, {}, "");
});
var form = make('<form kt-post="/test" kt-trigger="click">' +
'<input id="cb1" name="c1" value="cb1" type="checkbox">'+
'<input id="cb2" name="c1" value="cb2" type="checkbox">'+
'<input id="cb3" name="c1" value="cb3" type="checkbox">'+
'<input id="cb4" name="c2" value="cb4" type="checkbox">'+
'<input id="cb5" name="c2" value="cb5" type="checkbox">'+
'<input id="cb6" name="c3" value="cb6" type="checkbox">'+
'</form>');
form.click();
this.server.respond();
values.should.deep.equal({});
byId("cb1").checked = true;
form.click();
this.server.respond();
values.should.deep.equal({c1:"cb1"});
byId("cb1").checked = true;
byId("cb2").checked = true;
form.click();
this.server.respond();
values.should.deep.equal({c1:["cb1", "cb2"]});
byId("cb1").checked = true;
byId("cb2").checked = true;
byId("cb3").checked = true;
form.click();
this.server.respond();
values.should.deep.equal({c1:["cb1", "cb2", "cb3"]});
byId("cb1").checked = true;
byId("cb2").checked = true;
byId("cb3").checked = true;
byId("cb4").checked = true;
form.click();
this.server.respond();
values.should.deep.equal({c1:["cb1", "cb2", "cb3"], c2:"cb4"});
byId("cb1").checked = true;
byId("cb2").checked = true;
byId("cb3").checked = true;
byId("cb4").checked = true;
byId("cb5").checked = true;
form.click();
this.server.respond();
values.should.deep.equal({c1:["cb1", "cb2", "cb3"], c2:["cb4", "cb5"]});
byId("cb1").checked = true;
byId("cb2").checked = true;
byId("cb3").checked = true;
byId("cb4").checked = true;
byId("cb5").checked = true;
byId("cb6").checked = true;
form.click();
this.server.respond();
values.should.deep.equal({c1:["cb1", "cb2", "cb3"], c2:["cb4", "cb5"], c3:"cb6"});
byId("cb1").checked = true;
byId("cb2").checked = false;
byId("cb3").checked = true;
byId("cb4").checked = false;
byId("cb5").checked = true;
byId("cb6").checked = true;
form.click();
this.server.respond();
values.should.deep.equal({c1:["cb1", "cb3"], c2:"cb5", c3:"cb6"});
});
})

View File

@ -0,0 +1,161 @@
describe("Core kutty API test", function(){
beforeEach(function() {
this.server = makeServer();
clearWorkArea();
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('version is correct', function(){
kutty.version.should.equal("0.0.1");
});
it('onLoad is called... onLoad', function(){
// also tests on/off
this.server.respondWith("GET", "/test", "<div id='d1' kt-get='/test'></div>")
var helper = kutty.onLoad(function (elt) {
elt.setAttribute("foo", "bar");
});
try {
var div = make("<div id='d1' kt-get='/test' kt-swap='outerHTML'></div>");
div.click();
this.server.respond();
byId("d1").getAttribute("foo").should.equal("bar");
} finally {
kutty.off("load.kutty", helper);
}
});
it('triggers properly', function () {
var div = make("<div/>");
var myEventCalled = false;
var detailStr = "";
kutty.on("myEvent", function(evt){
myEventCalled = true;
detailStr = evt.detail.str;
})
kutty.trigger(div, "myEvent", {str:"foo"})
myEventCalled.should.equal(true);
detailStr.should.equal("foo");
});
it('should find properly', function(){
var div = make("<div id='d1' class='c1 c2'>");
div.should.equal(kutty.find("#d1"));
div.should.equal(kutty.find(".c1"));
div.should.equal(kutty.find(".c2"));
div.should.equal(kutty.find(".c1.c2"));
});
it('should find properly from elt', function(){
var div = make("<div><a id='a1'></a><a id='a2'></a></div>");
kutty.find(div, "a").id.should.equal('a1');
});
it('should find all properly', function(){
var div = make("<div class='c1 c2 c3'><div class='c1 c2'><div class='c1'>");
kutty.findAll(".c1").length.should.equal(3);
kutty.findAll(".c2").length.should.equal(2);
kutty.findAll(".c3").length.should.equal(1);
});
it('should find all properly from elt', function(){
var div = make("<div><div class='c1 c2 c3'><div class='c1 c2'><div class='c1'></div>");
kutty.findAll(div, ".c1").length.should.equal(3);
kutty.findAll(div, ".c2").length.should.equal(2);
kutty.findAll(div,".c3").length.should.equal(1);
});
it('should find closest element properly', function () {
var div = make("<div><a id='a1'></a><a id='a2'></a></div>");
var a = kutty.find(div, "a");
kutty.closest(a, "div").should.equal(div);
});
it('should remove element properly', function () {
var div = make("<div><a></a></div>");
var a = kutty.find(div, "a");
kutty.remove(a);
div.innerHTML.should.equal("");
});
it('should add class properly', function () {
var div = make("<div></div>");
div.classList.contains("foo").should.equal(false);
kutty.addClass(div, "foo");
div.classList.contains("foo").should.equal(true);
});
it('should add class properly after delay', function (done) {
var div = make("<div></div>");
div.classList.contains("foo").should.equal(false);
kutty.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("<div></div>");
kutty.addClass(div, "foo");
div.classList.contains("foo").should.equal(true);
kutty.removeClass(div, "foo");
div.classList.contains("foo").should.equal(false);
});
it('should add class properly after delay', function (done) {
var div = make("<div></div>");
kutty.addClass(div, "foo");
div.classList.contains("foo").should.equal(true);
kutty.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></div>");
div.classList.contains("foo").should.equal(false);
kutty.toggleClass(div, "foo");
div.classList.contains("foo").should.equal(true);
kutty.toggleClass(div, "foo");
div.classList.contains("foo").should.equal(false);
});
it('should take class properly', function () {
var div1 = make("<div></div>");
var div2 = make("<div></div>");
var div3 = make("<div></div>");
div1.classList.contains("foo").should.equal(false);
div2.classList.contains("foo").should.equal(false);
div3.classList.contains("foo").should.equal(false);
kutty.takeClass(div1, "foo");
div1.classList.contains("foo").should.equal(true);
div2.classList.contains("foo").should.equal(false);
div3.classList.contains("foo").should.equal(false);
kutty.takeClass(div2, "foo");
div1.classList.contains("foo").should.equal(false);
div2.classList.contains("foo").should.equal(true);
div3.classList.contains("foo").should.equal(false);
kutty.takeClass(div3, "foo");
div1.classList.contains("foo").should.equal(false);
div2.classList.contains("foo").should.equal(false);
div3.classList.contains("foo").should.equal(true);
});
})

View File

@ -0,0 +1,82 @@
describe("Core kutty Events", function() {
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
});
afterEach(function () {
this.server.restore();
clearWorkArea();
});
it("load.kutty fires properly", function () {
var handler = kutty.on("load.kutty", function (evt) {
called = true;
});
try {
this.server.respondWith("GET", "/test", "<div></div>");
var called = false;
var div = make("<div kt-get='/test'></div>");
div.click();
this.server.respond();
should.equal(called, true);
} finally {
kutty.off("load.kutty", handler);
}
});
it("configRequest.kutty allows attribute addition", function () {
var handler = kutty.on("configRequest.kutty", function (evt) {
evt.detail.parameters['param'] = "true";
});
try {
var param = null;
this.server.respondWith("POST", "/test", function (xhr) {
param = parseParams(xhr.requestBody)['param'];
});
var div = make("<div kt-post='/test'></div>");
div.click();
this.server.respond();
param.should.equal("true");
} finally {
kutty.off("configRequest.kutty", handler);
}
});
it("configRequest.kutty allows attribute removal", function () {
var param = "foo";
var handler = kutty.on("configRequest.kutty", function (evt) {
delete evt.detail.parameters['param'];
});
try {
this.server.respondWith("POST", "/test", function (xhr) {
param = parseParams(xhr.requestBody)['param'];
});
var div = make("<form kt-trigger='click' kt-post='/test'><input name='param' value='foo'></form>");
div.click();
this.server.respond();
should.equal(param, undefined);
} finally {
kutty.off("configRequest.kutty", handler);
}
});
it("configRequest.kutty allows header tweaking", function () {
var header = "foo";
var handler = kutty.on("configRequest.kutty", function (evt) {
evt.detail.headers['X-My-Header'] = "bar";
});
try {
this.server.respondWith("POST", "/test", function (xhr) {
header = xhr.requestHeaders['X-My-Header'];
});
var div = make("<form kt-trigger='click' kt-post='/test'><input name='param' value='foo'></form>");
div.click();
this.server.respond();
should.equal(header, "bar");
} finally {
kutty.off("configRequest.kutty", handler);
}
});
});

View File

@ -0,0 +1,110 @@
describe("Core kutty AJAX headers", function() {
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
});
afterEach(function () {
this.server.restore();
clearWorkArea();
});
it("should include the X-KT-Request header", function(){
this.server.respondWith("GET", "/test", function(xhr){
xhr.requestHeaders['X-KT-Request'].should.be.equal('true');
xhr.respond(200, {}, "");
});
var div = make('<div kt-get="/test"></div>');
div.click();
this.server.respond();
})
it("should include the X-KT-Trigger header", function(){
this.server.respondWith("GET", "/test", function(xhr){
xhr.requestHeaders['X-KT-Trigger'].should.equal('d1');
xhr.respond(200, {}, "");
});
var div = make('<div id="d1" kt-get="/test"></div>');
div.click();
this.server.respond();
})
it("should include the X-KT-Trigger-Name header", function(){
this.server.respondWith("GET", "/test", function(xhr){
xhr.requestHeaders['X-KT-Trigger-Name'].should.equal('n1');
xhr.respond(200, {}, "");
});
var div = make('<button name="n1" kt-get="/test"></button>');
div.click();
this.server.respond();
})
it("should include the X-KT-Target header", function(){
this.server.respondWith("GET", "/test", function(xhr){
xhr.requestHeaders['X-KT-Target'].should.equal('d1');
xhr.respond(200, {}, "");
});
var div = make('<div kt-target="#d1" kt-get="/test"></div><div id="d1" ></div>');
div.click();
this.server.respond();
})
it("should handle simple string X-KT-Trigger response header properly", function(){
this.server.respondWith("GET", "/test", [200, {"X-KT-Trigger" : "foo"}, ""]);
var div = make('<div kt-get="/test"></div>');
var invokedEvent = false;
div.addEventListener("foo", function (evt) {
invokedEvent = true;
});
div.click();
this.server.respond();
invokedEvent.should.equal(true);
})
it("should handle basic JSON X-KT-Trigger response header properly", function(){
this.server.respondWith("GET", "/test", [200, {"X-KT-Trigger" : "{\"foo\":null}"}, ""]);
var div = make('<div kt-get="/test"></div>');
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 X-KT-Trigger response header properly", function(){
this.server.respondWith("GET", "/test", [200, {"X-KT-Trigger" : "{\"foo\":[1, 2, 3]}"}, ""]);
var div = make('<div kt-get="/test"></div>');
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 X-KT-Trigger response header properly", function(){
this.server.respondWith("GET", "/test", [200, {"X-KT-Trigger" : "{\"foo\":{\"a\":1, \"b\":2}}"}, ""]);
var div = make('<div kt-get="/test"></div>');
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);
})
});

View File

@ -0,0 +1,23 @@
describe("Core kutty internals Tests", function() {
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
});
afterEach(function () {
this.server.restore();
clearWorkArea();
});
it("makeFragment works with janky stuff", function(){
kutty._("makeFragment")("<html></html>").tagName.should.equal("BODY");
kutty._("makeFragment")("<html><body></body></html>").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
kutty._("makeFragment")("<td></td>").tagName.should.equal("TR");
kutty._("makeFragment")("<thead></thead>").tagName.should.equal("TABLE");
kutty._("makeFragment")("<col></col>").tagName.should.equal("COLGROUP");
kutty._("makeFragment")("<tr></tr>").tagName.should.equal("TBODY");
})
});

View File

@ -0,0 +1,114 @@
describe("Core kutty Parameter Handling", function() {
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
});
afterEach(function () {
this.server.restore();
clearWorkArea();
});
it('Input includes value', function () {
var input = make('<input name="foo" value="bar"/>');
var vals = kutty._('getInputValues')(input);
vals['foo'].should.equal('bar');
})
it('Input includes value on get', function () {
var input = make('<input name="foo" value="bar"/>');
var vals = kutty._('getInputValues')(input, "get");
vals['foo'].should.equal('bar');
})
it('Input includes form', function () {
var form = make('<form><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/></form>');
var input = byId('i1');
var vals = kutty._('getInputValues')(input);
vals['foo'].should.equal('bar');
vals['do'].should.equal('rey');
})
it('Input doesnt include form on get', function () {
var form = make('<form><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/></form>');
var input = byId('i1');
var vals = kutty._('getInputValues')(input, 'get');
vals['foo'].should.equal('bar');
should.equal(vals['do'], undefined);
})
it('non-input includes form', function () {
var form = make('<form><div id="d1"/><input id="i2" name="do" value="rey"/></form>');
var div = byId('d1');
var vals = kutty._('getInputValues')(div, "post");
vals['do'].should.equal('rey');
})
it('non-input doesnt include form on get', function () {
var form = make('<form><div id="d1"/><input id="i2" name="do" value="rey"/></form>');
var div = byId('d1');
var vals = kutty._('getInputValues')(div, "get");
should.equal(vals['do'], undefined);
})
it('Basic form works on get', function () {
var form = make('<form><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/></form>');
var vals = kutty._('getInputValues')(form, 'get');
vals['foo'].should.equal('bar');
vals['do'].should.equal('rey');
})
it('Basic form works on non-get', function () {
var form = make('<form><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/></form>');
var vals = kutty._('getInputValues')(form, 'post');
vals['foo'].should.equal('bar');
vals['do'].should.equal('rey');
})
it('Double values are included as array', function () {
var form = make('<form><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/><input id="i2" name="do" value="rey"/></form>');
var vals = kutty._('getInputValues')(form);
vals['foo'].should.equal('bar');
vals['do'].should.deep.equal(['rey', 'rey']);
})
it('kt-include works with form', function () {
var form = make('<form id="f1"><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/><input id="i2" name="do" value="rey"/></form>');
var div = make('<div kt-include="#f1"></div>');
var vals = kutty._('getInputValues')(div);
vals['foo'].should.equal('bar');
vals['do'].should.deep.equal(['rey', 'rey']);
})
it('kt-include works with input', function () {
var form = make('<form id="f1"><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/><input id="i2" name="do" value="rey"/></form>');
var div = make('<div kt-include="#i1"></div>');
var vals = kutty._('getInputValues')(div);
vals['foo'].should.equal('bar');
should.equal(vals['do'], undefined);
})
it('kt-include works with two inputs', function () {
var form = make('<form id="f1"><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/><input id="i2" name="do" value="rey"/></form>');
var div = make('<div kt-include="#i1, #i2"></div>');
var vals = kutty._('getInputValues')(div);
vals['foo'].should.equal('bar');
vals['do'].should.deep.equal(['rey', 'rey']);
})
it('kt-include works with two inputs, plus form', function () {
var form = make('<form id="f1"><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/><input id="i2" name="do" value="rey"/></form>');
var div = make('<div kt-include="#i1, #i2, #f1"></div>');
var vals = kutty._('getInputValues')(div);
vals['foo'].should.equal('bar');
vals['do'].should.deep.equal(['rey', 'rey']);
})
it('correctly URL escapes values', function () {
kutty._("urlEncode")({}).should.equal("");
kutty._("urlEncode")({"foo": "bar"}).should.equal("foo=bar");
kutty._("urlEncode")({"foo": "bar", "do" : "rey"}).should.equal("foo=bar&do=rey");
kutty._("urlEncode")({"foo": "bar", "do" : ["rey", "blah"]}).should.equal("foo=bar&do=rey&do=blah");
});
});

View File

@ -0,0 +1,22 @@
describe("Core kutty 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('<svg onclick="document.getElementById(\'contents\').classList.toggle(\'show\')" class="hamburger" viewBox="0 0 100 80" width="25" height="25" style="margin-bottom:-5px">\n' +
'<rect width="100" height="20" style="fill:rgb(52, 101, 164)" rx="10"></rect>\n' +
'<rect y="30" width="100" height="20" style="fill:rgb(52, 101, 164)" rx="10"></rect>\n' +
'<rect y="60" width="100" height="20" style="fill:rgb(52, 101, 164)" rx="10"></rect>\n' +
'</svg>')
});
})

View File

@ -0,0 +1,44 @@
describe("Core kutty AJAX Verbs", function() {
beforeEach(function () {
this.server = makeServer();
clearWorkArea();
});
afterEach(function () {
this.server.restore();
clearWorkArea();
});
it('handles basic posts properly', function () {
this.server.respondWith("POST", "/test", "post");
var div = make('<div kt-post="/test">click me</div>');
div.click();
this.server.respond();
div.innerHTML.should.equal("post");
})
it('handles basic put properly', function () {
this.server.respondWith("PUT", "/test", "put");
var div = make('<div kt-put="/test">click me</div>');
div.click();
this.server.respond();
div.innerHTML.should.equal("put");
})
it('handles basic patch properly', function () {
this.server.respondWith("PATCH", "/test", "patch");
var div = make('<div kt-patch="/test">click me</div>');
div.click();
this.server.respond();
div.innerHTML.should.equal("patch");
})
it('handles basic delete properly', function () {
this.server.respondWith("DELETE", "/test", "delete");
var div = make('<div kt-delete="/test">click me</div>');
div.click();
this.server.respond();
div.innerHTML.should.equal("delete");
})
});

View File

@ -0,0 +1,70 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Mocha Tests</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
<meta http-equiv="cache-control" content="no-cache, must-revalidate, post-check=0, pre-check=0" />
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
<meta name="kutty-config" content='{"historyEnabled":false}'>
</head>
<body>
<div id="mocha"></div>
<script src="../node_modules/chai/chai.js"></script>
<script src="../node_modules/mocha/mocha.js"></script>
<script src="../node_modules/sinon/pkg/sinon.js"></script>
<script src="../src/kutty.js"></script>
<script class="mocha-init">
mocha.setup('bdd');
mocha.checkLeaks();
should = chai.should();
</script>
<script src="util/util.js"></script>
<!-- core tests -->
<script src="core/internals.js"></script>
<script src="core/api.js"></script>
<script src="core/ajax.js"></script>
<script src="core/verbs.js"></script>
<script src="core/parameters.js"></script>
<script src="core/headers.js"></script>
<script src="core/regressions.js"></script>
<!-- attribute tests -->
<script src="attributes/kt-boost.js"></script>
<script src="attributes/kt-classes.js"></script>
<script src="attributes/kt-delete.js"></script>
<script src="attributes/kt-error-url.js"></script>
<script src="attributes/kt-get.js"></script>
<script src="attributes/kt-include.js"></script>
<script src="attributes/kt-indicator.js"></script>
<script src="attributes/kt-params.js"></script>
<script src="attributes/kt-patch.js"></script>
<script src="attributes/kt-post.js"></script>
<script src="attributes/kt-push-url.js"></script>
<script src="attributes/kt-put.js"></script>
<script src="attributes/kt-swap-oob.js"></script>
<script src="attributes/kt-swap.js"></script>
<script src="attributes/kt-target.js"></script>
<script src="attributes/kt-trigger.js"></script>
<!-- events last so they don't screw up other tests -->
<script src="core/events.js"></script>
<a href="browser-only-tests.html">Run Browser-Only Tests</a>
<script class="mocha-exec">
mocha.run();
</script>
<em>Work Area</em>
<hr/>
<div id="work-area" kt-history-elt>
</div>
</body>
</html>

View File

@ -0,0 +1,51 @@
<html lang="en">
<head>
<style>
div {
transition: all 1000ms ease-in;
}
.indicator {
opacity: 0;
}
.kt-show-indicator .indicator {
opacity: 100%;
}
</style>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
</head>
<body>
<script src="../node_modules/sinon/pkg/sinon.js"></script>
<script src="../src/kutty.js"></script>
<script src="util/util.js"></script>
<script src="util/scratch_server.js"></script>
<script>
// this.server.respondWith("GET", "/test", '<a kt-get="/test2">Click Me</a>');
// this.server.respondWith("GET", "/test2", "Clicked!");
//
// make('<div kt-get="/test">dd</div>')
this.server.respondWith("GET", "/test", '<div id="d1" style="color: red; margin: 100px">Foo</div>');
make('<div kt-swap="outerHTML" kt-get="/test" kt-push-url="true" id="d1">Foo</div>');
</script>
<h2>Server Options</h2>
<button onclick="server.respond()">Server Respond</button>
<br/>
Autorespond: <input id="autorespond" type="checkbox" onclick="toggleAutoRespond()">
<br/>
<br/>
<em>Work Area</em>
<hr/>
<div id="work-area" kt-history-elt>
</div>
</body>
</html>

View File

@ -0,0 +1,17 @@
var server = makeServer();
var autoRespond = localStorage.getItem('kt-scratch-autorespond') == "true";
server.autoRespond = autoRespond;
ready(function () {
if (autoRespond) {
byId("autorespond").setAttribute("checked", "true");
}
})
function toggleAutoRespond() {
if (server.autoRespond) {
localStorage.removeItem('kt-scratch-autorespond');
server.autoRespond = false;
} else {
localStorage.setItem('kt-scratch-autorespond', 'true');
server.autoRespond = true;
}
}

View File

@ -0,0 +1,81 @@
/* Test Utilities */
kutty.logAll();
function byId(id) {
return document.getElementById(id);
}
function make(htmlStr) {
var makeFn = function(){
var range = document.createRange();
var fragment = range.createContextualFragment(htmlStr);
var wa = getWorkArea();
for (var i = fragment.childNodes.length - 1; i >= 0; i--) {
var child = fragment.childNodes[i];
kutty.process(child);
wa.appendChild(child);
}
return wa.lastChild;
}
if (getWorkArea()) {
return makeFn();
} else {
ready(makeFn);
}
}
function ready(fn) {
if (document.readyState !== 'loading') {
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
function getWorkArea() {
return byId("work-area");
}
function clearWorkArea() {
getWorkArea().innerHTML = "";
}
function removeWhiteSpace(str) {
return str.replace(/\s/g, "");
}
function makeServer(){
var server = sinon.fakeServer.create();
server.fakeHTTPMethods = true;
server.getHTTPMethod = function(xhr) {
return xhr.requestHeaders['X-HTTP-Method-Override'] || xhr.method;
}
return server;
}
function parseParams(str) {
var re = /([^&=]+)=?([^&]*)/g;
var decode = function (str) {
return decodeURIComponent(str.replace(/\+/g, ' '));
};
var params = {}, e;
if (str) {
if (str.substr(0, 1) == '?') {
str = str.substr(1);
}
while (e = re.exec(str)) {
var k = decode(e[1]);
var v = decode(e[2]);
if (params[k] !== undefined) {
if (!Array.isArray(params[k])) {
params[k] = [params[k]];
}
params[k].push(v);
} else {
params[k] = v;
}
}
}
return params;
}