mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-10-02 15:25:26 +00:00

* Update parseInterval to handle "0" correctly When a parameter like "0ms" is passed in to parseInterval it gets parsed to 0. Previously this would result in a return value of "undefined" because 0 is falsy and thus the `return 0 || undefined` statements return undefined. The purpose of the form `parseFloat(str) || undefined` was to return "undefined" if parseFloat failed (parseFloat returns NaN, a falsy value, if it can't parse its argument). Unfortunately, as mentioned, parseFloat can also succeed and return a falsy value -- when the argument is "0" (or "0.0", etc.). So the new code, rather than depending on the falsiness of the result of parseFloat, explicitly checks for a NaN. * Adds some semicolons Adds some semicolons to parseInterval (and tests) for consistency. * Add one more parseInterval test for "0" Adds test test to make sure parseInterval works on "0". * Adds functional tests for every, swap, settle, throttle, and delay * Explcitly check that setTimeout values are > 0 These values come from user settings that are read from parseInterval, so they could be a number or undefined. If the value being checked is > 0 setTimeout will be called with some associated function. If the value is 0 or 'undefined' the associated function will be called immediately ('undefined' is not greater than 0). * Change '!== undefined' to '> 0' `pollInterval !== undefined` is a subtly different conditional than just `pollInterval` or `pollInterval > 0` (which are equivalent). Changes the conditional to `pollInterval > 0` so as to not change the behavior but also be more explicit in the test.
149 lines
6.3 KiB
JavaScript
149 lines
6.3 KiB
JavaScript
describe("Core htmx internals Tests", function() {
|
|
|
|
beforeEach(function () {
|
|
this.server = makeServer();
|
|
clearWorkArea();
|
|
});
|
|
afterEach(function () {
|
|
this.server.restore();
|
|
clearWorkArea();
|
|
});
|
|
|
|
it("makeFragment works with janky stuff", function(){
|
|
htmx._("makeFragment")("<html></html>").tagName.should.equal("BODY");
|
|
htmx._("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
|
|
htmx._("makeFragment")("<td></td>").tagName.should.equal("TR");
|
|
htmx._("makeFragment")("<thead></thead>").tagName.should.equal("TABLE");
|
|
htmx._("makeFragment")("<col></col>").tagName.should.equal("COLGROUP");
|
|
htmx._("makeFragment")("<tr></tr>").tagName.should.equal("TBODY");
|
|
})
|
|
|
|
it("makeFragment works with template wrapping", function(){
|
|
if (!supportsTemplates()) {
|
|
this._runnable.title += " - Skipped as IE11 doesn't support templates"
|
|
this.skip()
|
|
return
|
|
}
|
|
try {
|
|
htmx._("makeFragment")("<html></html>").children.length.should.equal(0);
|
|
htmx._("makeFragment")("<html><body></body></html>").children.length.should.equal(0);
|
|
|
|
var fragment = htmx._("makeFragment")("<td></td>");
|
|
fragment.firstElementChild.tagName.should.equal("TD");
|
|
|
|
fragment = htmx._("makeFragment")("<thead></thead>");
|
|
fragment.firstElementChild.tagName.should.equal("THEAD");
|
|
|
|
fragment = htmx._("makeFragment")("<col></col>");
|
|
fragment.firstElementChild.tagName.should.equal("COL");
|
|
|
|
fragment = htmx._("makeFragment")("<tr></tr>");
|
|
fragment.firstElementChild.tagName.should.equal("TR");
|
|
|
|
} finally {
|
|
htmx.config.useTemplateFragments = false;
|
|
}
|
|
})
|
|
|
|
|
|
it("makeFragment works with template wrapping and funky combos", function(){
|
|
if (!supportsTemplates()) {
|
|
this._runnable.title += " - Skipped as IE11 doesn't support templates"
|
|
this.skip()
|
|
return
|
|
}
|
|
htmx.config.useTemplateFragments = true;
|
|
try {
|
|
var fragment = htmx._("makeFragment")("<td></td><div></div>");
|
|
fragment.children[0].tagName.should.equal("TD");
|
|
fragment.children[1].tagName.should.equal("DIV");
|
|
} finally {
|
|
htmx.config.useTemplateFragments = false;
|
|
}
|
|
})
|
|
|
|
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
|
|
})
|
|
|
|
it("handles parseInterval correctly", function() {
|
|
chai.expect(htmx.parseInterval("1ms")).to.be.equal(1);
|
|
chai.expect(htmx.parseInterval("300ms")).to.be.equal(300);
|
|
chai.expect(htmx.parseInterval("1s")).to.be.equal(1000);
|
|
chai.expect(htmx.parseInterval("1.5s")).to.be.equal(1500);
|
|
chai.expect(htmx.parseInterval("2s")).to.be.equal(2000);
|
|
chai.expect(htmx.parseInterval("0ms")).to.be.equal(0);
|
|
chai.expect(htmx.parseInterval("0s")).to.be.equal(0);
|
|
chai.expect(htmx.parseInterval("0m")).to.be.equal(0);
|
|
chai.expect(htmx.parseInterval("0")).to.be.equal(0);
|
|
chai.expect(htmx.parseInterval("5")).to.be.equal(5);
|
|
|
|
chai.expect(htmx.parseInterval(null)).to.be.undefined
|
|
chai.expect(htmx.parseInterval("")).to.be.undefined
|
|
chai.expect(htmx.parseInterval("undefined")).to.be.undefined
|
|
chai.expect(htmx.parseInterval("true")).to.be.undefined
|
|
chai.expect(htmx.parseInterval("false")).to.be.undefined
|
|
})
|
|
|
|
it("tokenizes correctly", function() {
|
|
chai.expect(htmx._("tokenizeString")("a,")).to.be.deep.equal(['a', ',']);
|
|
chai.expect(htmx._("tokenizeString")("aa,")).to.be.deep.equal(['aa', ',']);
|
|
chai.expect(htmx._("tokenizeString")("aa,aa")).to.be.deep.equal(['aa', ',', 'aa']);
|
|
chai.expect(htmx._("tokenizeString")("aa.aa")).to.be.deep.equal(['aa', '.', 'aa']);
|
|
})
|
|
|
|
it("tags respond correctly to shouldCancel", function() {
|
|
var anchorThatShouldCancel = make("<a href='/foo'></a>");
|
|
htmx._("shouldCancel")({type:'click'}, anchorThatShouldCancel).should.equal(true);
|
|
|
|
var anchorThatShouldCancel = make("<a href='#'></a>");
|
|
htmx._("shouldCancel")({type:'click'}, anchorThatShouldCancel).should.equal(true);
|
|
|
|
var anchorThatShouldNotCancel = make("<a href='#foo'></a>");
|
|
htmx._("shouldCancel")({type:'click'}, anchorThatShouldNotCancel).should.equal(false);
|
|
|
|
var form = make("<form></form>");
|
|
htmx._("shouldCancel")({type:'submit'}, form).should.equal(true);
|
|
|
|
var form = make("<form><input id='i1' type='submit'></form>");
|
|
var input = byId("i1");
|
|
htmx._("shouldCancel")({type:'click'}, input).should.equal(true);
|
|
|
|
var form = make("<form><button id='b1' type='submit'></form>");
|
|
var button = byId("b1");
|
|
htmx._("shouldCancel")({type:'click'}, button).should.equal(true);
|
|
|
|
})
|
|
|
|
it("unset properly unsets a given attribute", function(){
|
|
make("<div foo='1'><div foo='2'><div foo='unset' id='d1'></div></div></div>");
|
|
var div = byId("d1");
|
|
should.equal(undefined, htmx._("getClosestAttributeValue")(div, "foo"));
|
|
})
|
|
|
|
it("unset properly unsets a given attribute on a parent", function(){
|
|
make("<div foo='1'><div foo='unset'><div id='d1'></div></div></div>");
|
|
var div = byId("d1");
|
|
should.equal(undefined, htmx._("getClosestAttributeValue")(div, "foo"));
|
|
})
|
|
|
|
it("unset does not unset a value below it in the hierarchy", function(){
|
|
make("<div foo='unset'><div foo='2'><div id='d1'></div></div></div>");
|
|
var div = byId("d1");
|
|
should.equal("2", htmx._("getClosestAttributeValue")(div, "foo"));
|
|
})
|
|
|
|
it("encoding values respects enctype on forms", function(){
|
|
var form = make("<form enctype='multipart/form-data'></form>");
|
|
var value = htmx._("encodeParamsForBody")(null, form, {});
|
|
(value instanceof FormData).should.equal(true);
|
|
})
|
|
|
|
}); |