1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
describe('bootstrap unit tests', function() {
it("Test that fragment parsing works as expected", function() {
var result = htmx.__makeFragment("foo");
var temp = document.createElement('div');
temp.appendChild(result.fragment.cloneNode(true));
assert.equal("foo", temp.textContent.trim())
// Test that template partials are preserved in fragment
result = htmx.__makeFragment(`<template partial hx-target="#test">foo</template>`);
temp = document.createElement('div');
temp.appendChild(result.fragment.cloneNode(true));
assert.include(temp.innerHTML, 'template')
})
it("__makeFragment handles multiple partials", function() {
var result = htmx.__makeFragment(`
<div>Main content</div>
<template partial hx-target="#test1">Partial 1</template>
<template partial hx-target="#test2" hx-swap="innerHTML">Partial 2</template>
`);
var temp = document.createElement('div');
temp.appendChild(result.fragment.cloneNode(true));
assert.include(temp.innerHTML, "Main content")
assert.include(temp.innerHTML, "template")
})
it("__makeFragment extracts title from HTML", function() {
var result = htmx.__makeFragment(`
<html><head><title>Test Title</title></head><body>Content</body></html>
`);
assert.equal("Test Title", result.title)
})
it("__makeFragment handles body tag response", function() {
var result = htmx.__makeFragment(`<body><div>Content</div></body>`);
var temp = document.createElement('div');
temp.appendChild(result.fragment.cloneNode(true));
assert.include(temp.innerHTML, "Content")
})
it("__makeFragment handles fragment response", function() {
var result = htmx.__makeFragment(`<div>Fragment</div><span>More</span>`);
var temp = document.createElement('div');
temp.appendChild(result.fragment.cloneNode(true));
assert.include(temp.innerHTML, "Fragment")
assert.include(temp.innerHTML, "More")
})
it("__attributeValue returns direct attribute value", function() {
const div = createDisconnectedHTML('<div hx-get="/test"></div>');
const result = htmx.__attributeValue(div, 'hx-get', 'default');
assert.equal(result, '/test');
})
it("__attributeValue returns inherited attribute from element", function() {
const div = createDisconnectedHTML('<div hx-get:inherited="/inherited"></div>');
const result = htmx.__attributeValue(div, 'hx-get', 'default');
assert.equal(result, '/inherited');
})
it("__attributeValue prefers direct attribute over inherited", function() {
const div = createDisconnectedHTML('<div hx-get="/direct" hx-get:inherited="/inherited"></div>');
const result = htmx.__attributeValue(div, 'hx-get', 'default');
assert.equal(result, '/direct');
})
it("__attributeValue finds inherited attribute on parent", function() {
const parent = createDisconnectedHTML('<div hx-get:inherited="/parent"><div></div></div>');
const child = parent.firstElementChild;
const result = htmx.__attributeValue(child, 'hx-get', 'default');
assert.equal(result, '/parent');
})
it("__attributeValue returns default when attribute not found", function() {
const div = createDisconnectedHTML('<div></div>');
const result = htmx.__attributeValue(div, 'hx-get', 'default');
assert.equal(result, 'default');
})
it("__parseTriggerSpecs parses simple event", function() {
const result = htmx.__parseTriggerSpecs('click');
assert.equal(result.length, 1);
assert.equal(result[0].name, 'click');
})
it("__parseTriggerSpecs parses event with option", function() {
const result = htmx.__parseTriggerSpecs('click delay:500');
assert.equal(result.length, 1);
assert.equal(result[0].name, 'click');
assert.equal(result[0].delay, '500');
})
it("__parseTriggerSpecs parses event with multiple options", function() {
const result = htmx.__parseTriggerSpecs('click delay:500 throttle:100');
assert.equal(result.length, 1);
assert.equal(result[0].name, 'click');
assert.equal(result[0].delay, '500');
assert.equal(result[0].throttle, '100');
})
it("__parseTriggerSpecs parses event with boolean opts", function() {
const result = htmx.__parseTriggerSpecs('click once changed');
assert.equal(result.length, 1);
assert.equal(result[0].name, 'click');
assert.equal(result[0].once, true);
assert.equal(result[0].changed, true);
})
it("__parseTriggerSpecs parses event with options and boolean opts", function() {
const result = htmx.__parseTriggerSpecs('click delay:1s once changed');
assert.equal(result.length, 1);
assert.equal(result[0].name, 'click');
assert.equal(result[0].delay, '1s');
assert.equal(result[0].once, true);
assert.equal(result[0].changed, true);
})
it("__parseTriggerSpecs parses multiple events", function() {
const result = htmx.__parseTriggerSpecs('click, submit');
assert.equal(result.length, 2);
assert.equal(result[0].name, 'click');
assert.equal(result[1].name, 'submit');
})
it("__parseTriggerSpecs parses multiple events with options", function() {
const result = htmx.__parseTriggerSpecs('click delay:500, keyup changed');
assert.equal(result.length, 2);
assert.equal(result[0].name, 'click');
assert.equal(result[0].delay, '500');
assert.equal(result[1].name, 'keyup');
assert.equal(result[1].changed, true);
})
it("__parseTriggerSpecs parses event filter", function() {
const result = htmx.__parseTriggerSpecs('click[ctrlKey]');
assert.equal(result.length, 1);
assert.equal(result[0].name, 'click[ctrlKey]');
})
it("__parseTriggerSpecs parses event filter with spaces", function() {
const result = htmx.__parseTriggerSpecs('click[target.value == "test"]');
assert.equal(result.length, 1);
assert.equal(result[0].name, 'click[target.value == "test"]');
})
it("__parseTriggerSpecs parses event with from option", function() {
const result = htmx.__parseTriggerSpecs('click from:body');
assert.equal(result.length, 1);
assert.equal(result[0].name, 'click');
assert.equal(result[0].from, 'body');
})
it("__parseTriggerSpecs throws on unterminated filter", function() {
assert.throws(() => {
htmx.__parseTriggerSpecs('click[ctrlKey');
}, /unterminated/);
})
it("__parseTriggerSpecs handles complex real-world spec", function() {
const result = htmx.__parseTriggerSpecs('keyup[target.value.length > 3] changed delay:500ms from:input');
assert.equal(result.length, 1);
assert.equal(result[0].name, 'keyup[target.value.length > 3]');
assert.equal(result[0].changed, true);
assert.equal(result[0].delay, '500ms');
assert.equal(result[0].from, 'input');
})
it("__parseTriggerSpecs handles complex real-world spec w string and preserves spaces in string", function() {
const result = htmx.__parseTriggerSpecs('keyup[target.value == "hello world"] changed delay:500ms from:input');
assert.equal(result.length, 1);
assert.equal(result[0].name, 'keyup[target.value == "hello world"]');
assert.equal(result[0].changed, true);
assert.equal(result[0].delay, '500ms');
assert.equal(result[0].from, 'input');
})
it("public API surface remains stable", function() {
// This test ensures the public API doesn't accidentally change
const expectedPublicMethods = [
'ajax',
'find',
'findAll',
'forEvent',
'on',
'onLoad',
'parseInterval',
'process',
'swap',
'takeClass',
'timeout',
'registerExtension',
'trigger',
].sort();
const expectedPublicProperties = [
'config'
].sort();
// Get own properties (like config, eventSource)
const ownProperties = Object.keys(htmx).filter(name => !name.startsWith("_") && typeof htmx[name] !== 'function').sort();
// Get methods from the prototype
const proto = Object.getPrototypeOf(htmx);
const protoMethods = Object.getOwnPropertyNames(proto)
.filter(name => !name.startsWith("_") && name !== 'constructor' && typeof htmx[name] === 'function')
.sort();
// Check methods
assert.deepEqual(protoMethods, expectedPublicMethods,
'Public methods have changed. Expected: ' + JSON.stringify(expectedPublicMethods) +
', Got: ' + JSON.stringify(protoMethods));
// Check properties
assert.deepEqual(ownProperties, expectedPublicProperties,
'Public properties have changed. Expected: ' + JSON.stringify(expectedPublicProperties) +
', Got: ' + JSON.stringify(ownProperties));
})
})
|