mirror of
https://github.com/bigskysoftware/htmx.git
synced 2026-01-05 08:12:03 +00:00
313 lines
11 KiB
JavaScript
313 lines
11 KiB
JavaScript
describe('ajax() unit Tests', function() {
|
|
|
|
beforeEach(function() {
|
|
setupTest();
|
|
});
|
|
|
|
afterEach(function() {
|
|
cleanupTest();
|
|
});
|
|
|
|
it('ajax works with element target', async function() {
|
|
mockResponse('GET', '/test', 'foo!');
|
|
const div = createProcessedHTML('<div></div>');
|
|
await htmx.ajax('GET', '/test', {target: div, swap: 'innerHTML'});
|
|
assert.equal(div.innerHTML, 'foo!');
|
|
});
|
|
|
|
it('ajax works with selector target', async function() {
|
|
mockResponse('GET', '/test', 'foo!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
await htmx.ajax('GET', '/test', {target: '#d1', swap: 'innerHTML'});
|
|
assert.equal(div.innerHTML, 'foo!');
|
|
});
|
|
|
|
it('ajax rejects when target selector invalid', async function() {
|
|
mockResponse('GET', '/test', 'foo!');
|
|
createProcessedHTML('<div id="d1"></div>');
|
|
try {
|
|
await htmx.ajax('GET', '/test', '#d2');
|
|
assert.fail('Should have rejected');
|
|
} catch (e) {
|
|
assert.include(e.message, 'Target not found');
|
|
}
|
|
});
|
|
|
|
it('ajax rejects when target invalid even if source set', async function() {
|
|
mockResponse('GET', '/test', 'foo!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
try {
|
|
await htmx.ajax('GET', '/test', {
|
|
source: div,
|
|
target: '#d2'
|
|
});
|
|
assert.fail('Should have rejected');
|
|
} catch (e) {
|
|
assert.include(e.message, 'Target not found');
|
|
}
|
|
});
|
|
|
|
it('ajax rejects when source selector invalid', async function() {
|
|
mockResponse('GET', '/test', 'foo!');
|
|
createProcessedHTML('<div id="d1"></div>');
|
|
try {
|
|
await htmx.ajax('GET', '/test', {
|
|
source: '#d2'
|
|
});
|
|
assert.fail('Should have rejected');
|
|
} catch (e) {
|
|
assert.include(e.message, 'Source not found');
|
|
}
|
|
});
|
|
|
|
it('ajax targets source if target not set', async function() {
|
|
mockResponse('GET', '/test', 'foo!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
await htmx.ajax('GET', '/test', {
|
|
source: div,
|
|
swap: 'innerHTML'
|
|
});
|
|
assert.equal(div.innerHTML, 'foo!');
|
|
});
|
|
|
|
it('ajax works with swap option', async function() {
|
|
mockResponse('GET', '/test', '<p class="test">foo!</p>');
|
|
const container = createProcessedHTML('<div><div id="target"></div></div>');
|
|
await htmx.ajax('GET', '/test', {
|
|
target: '#target',
|
|
swap: 'outerHTML'
|
|
});
|
|
assert.equal(container.innerHTML, '<p class="test">foo!</p>');
|
|
});
|
|
|
|
it('ajax works with select option', async function() {
|
|
mockResponse('GET', '/test', '<div id="d1">foo</div><div id="d2">bar</div>');
|
|
const div = createProcessedHTML('<div id="target"></div>');
|
|
await htmx.ajax('GET', '/test', {
|
|
target: '#target',
|
|
swap: 'innerHTML',
|
|
select: '#d2'
|
|
});
|
|
assert.include(div.innerHTML, 'bar');
|
|
assert.notInclude(div.innerHTML, 'foo');
|
|
});
|
|
|
|
it('ajax returns a promise', async function() {
|
|
mockResponse('GET', '/test', 'foo!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
const promise = htmx.ajax('GET', '/test', {target: '#d1', swap: 'innerHTML'});
|
|
assert.instanceOf(promise, Promise);
|
|
await promise;
|
|
assert.equal(div.innerHTML, 'foo!');
|
|
});
|
|
|
|
it('ajax can pass values', async function() {
|
|
mockResponse('POST', '/test', 'Clicked!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
await htmx.ajax('POST', '/test', {
|
|
target: '#d1',
|
|
swap: 'innerHTML',
|
|
values: { i1: 'test' }
|
|
});
|
|
assert.equal(div.innerHTML, 'Clicked!');
|
|
const lastCall = lastFetch();
|
|
const params = new URLSearchParams(lastCall.request.body);
|
|
assert.equal(params.get('i1'), 'test');
|
|
});
|
|
|
|
it('ajax can pass custom headers', async function() {
|
|
mockResponse('POST', '/test', 'Clicked!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
await htmx.ajax('POST', '/test', {
|
|
target: '#d1',
|
|
swap: 'innerHTML',
|
|
headers: {
|
|
'X-Custom': 'test-value'
|
|
},
|
|
values: { i1: 'test' }
|
|
});
|
|
assert.equal(div.innerHTML, 'Clicked!');
|
|
const lastCall = lastFetch();
|
|
assert.equal(lastCall.request.headers['X-Custom'], 'test-value');
|
|
});
|
|
|
|
it('ajax collects form data from source element', async function() {
|
|
mockResponse('POST', '/test', 'Submitted!');
|
|
createProcessedHTML('<form id="myForm"><input name="field1" value="value1"/></form><div id="result"></div>');
|
|
const form = find('#myForm');
|
|
const div = find('#result');
|
|
await htmx.ajax('POST', '/test', {
|
|
source: form,
|
|
target: '#result',
|
|
swap: 'innerHTML'
|
|
});
|
|
assert.equal(div.innerHTML, 'Submitted!');
|
|
const lastCall = lastFetch();
|
|
const params = new URLSearchParams(lastCall.request.body);
|
|
assert.equal(params.get('field1'), 'value1');
|
|
});
|
|
|
|
it('ajax values override form data', async function() {
|
|
mockResponse('POST', '/test', 'Submitted!');
|
|
createProcessedHTML('<form id="myForm"><input name="field1" value="original"/></form><div id="result"></div>');
|
|
const form = find('#myForm');
|
|
const div = find('#result');
|
|
await htmx.ajax('POST', '/test', {
|
|
source: form,
|
|
target: '#result',
|
|
swap: 'innerHTML',
|
|
values: { field1: 'override' }
|
|
});
|
|
assert.equal(div.innerHTML, 'Submitted!');
|
|
const lastCall = lastFetch();
|
|
const params = new URLSearchParams(lastCall.request.body);
|
|
assert.equal(params.get('field1'), 'override');
|
|
});
|
|
|
|
it('ajax works with GET and query parameters', async function() {
|
|
mockResponse('GET', /\/test\?.*/, 'Got it!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
await htmx.ajax('GET', '/test', {
|
|
target: '#d1',
|
|
swap: 'innerHTML',
|
|
values: { param1: 'value1', param2: 'value2' }
|
|
});
|
|
assert.equal(div.innerHTML, 'Got it!');
|
|
const lastCall = lastFetch();
|
|
assert.include(lastCall.url, 'param1=value1');
|
|
assert.include(lastCall.url, 'param2=value2');
|
|
});
|
|
|
|
it('ajax works with optimistic UI', async function() {
|
|
mockResponse('POST', '/test', 'final!');
|
|
createProcessedHTML('<div id="loading">Loading...</div><div id="target">initial</div>');
|
|
const div = find('#target');
|
|
|
|
// Just verify optimistic option doesn't break the request
|
|
await htmx.ajax('POST', '/test', {
|
|
target: '#target',
|
|
swap: 'innerHTML',
|
|
optimistic: '#loading'
|
|
});
|
|
|
|
assert.equal(div.innerHTML, 'final!');
|
|
});
|
|
|
|
it('ajax respects transition option', async function() {
|
|
mockResponse('GET', '/test', 'content!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
await htmx.ajax('GET', '/test', {
|
|
target: '#d1',
|
|
swap: 'innerHTML',
|
|
transition: false
|
|
});
|
|
assert.equal(div.innerHTML, 'content!');
|
|
});
|
|
|
|
it('ajax works with no context (defaults to body)', async function() {
|
|
this.skip() // We can't test this as it will replace the body and nuke the test UI lol
|
|
return;
|
|
mockResponse('GET', '/test', '<div id="ajax-result">body content</div>');
|
|
await htmx.ajax('GET', '/test', {swap: 'beforeend'});
|
|
// Verify content was added to body
|
|
const result = document.getElementById('ajax-result');
|
|
assert.isNotNull(result);
|
|
assert.equal(result.textContent, 'body content');
|
|
// Clean up
|
|
result.remove();
|
|
});
|
|
|
|
it('ajax case insensitive verb', async function() {
|
|
mockResponse('POST', '/test', 'posted!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
await htmx.ajax('post', '/test', {
|
|
target: '#d1',
|
|
swap: 'innerHTML',
|
|
values: {test: 'value'}
|
|
});
|
|
assert.equal(div.innerHTML, 'posted!');
|
|
});
|
|
|
|
it('ajax uppercase verb', async function() {
|
|
mockResponse('DELETE', '/test', 'deleted!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
await htmx.ajax('DELETE', '/test', {target: '#d1', swap: 'innerHTML'});
|
|
assert.equal(div.innerHTML, 'deleted!');
|
|
});
|
|
|
|
it('ajax with event context', async function() {
|
|
mockResponse('POST', '/test', 'clicked!');
|
|
createProcessedHTML('<button id="btn">Click</button><div id="result"></div>');
|
|
const div = find('#result');
|
|
const clickEvent = new MouseEvent('click', { bubbles: true });
|
|
|
|
await htmx.ajax('POST', '/test', {
|
|
target: '#result',
|
|
swap: 'innerHTML',
|
|
event: clickEvent
|
|
});
|
|
assert.equal(div.innerHTML, 'clicked!');
|
|
});
|
|
|
|
it('ajax triggers htmx events', async function() {
|
|
mockResponse('GET', '/test', 'content!');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
|
|
let beforeRequestFired = false;
|
|
let afterRequestFired = false;
|
|
|
|
div.addEventListener('htmx:before:request', () => {
|
|
beforeRequestFired = true;
|
|
});
|
|
|
|
div.addEventListener('htmx:after:request', () => {
|
|
afterRequestFired = true;
|
|
});
|
|
|
|
await htmx.ajax('GET', '/test', {target: div, swap: 'innerHTML'});
|
|
|
|
assert.isTrue(beforeRequestFired);
|
|
assert.isTrue(afterRequestFired);
|
|
});
|
|
|
|
it('ajax with multiple values', async function() {
|
|
mockResponse('POST', '/test', 'OK');
|
|
const div = createProcessedHTML('<div id="d1"></div>');
|
|
await htmx.ajax('POST', '/test', {
|
|
target: '#d1',
|
|
swap: 'innerHTML',
|
|
values: {
|
|
field1: 'value1',
|
|
field2: 'value2',
|
|
field3: 'value3'
|
|
}
|
|
});
|
|
const lastCall = lastFetch();
|
|
const params = new URLSearchParams(lastCall.request.body);
|
|
assert.equal(params.get('field1'), 'value1');
|
|
assert.equal(params.get('field2'), 'value2');
|
|
assert.equal(params.get('field3'), 'value3');
|
|
});
|
|
|
|
it('ajax with swap innerHTML', async function() {
|
|
mockResponse('GET', '/test', '<span>inner</span>');
|
|
const div = createProcessedHTML('<div id="target"><p>old</p></div>');
|
|
await htmx.ajax('GET', '/test', {
|
|
target: '#target',
|
|
swap: 'innerHTML'
|
|
});
|
|
assert.equal(div.innerHTML, '<span class="">inner</span>');
|
|
});
|
|
|
|
it('ajax with swap beforeend', async function() {
|
|
mockResponse('GET', '/test', '<span>new</span>');
|
|
const div = createProcessedHTML('<div id="target"><p>old</p></div>');
|
|
await htmx.ajax('GET', '/test', {
|
|
target: '#target',
|
|
swap: 'beforeend'
|
|
});
|
|
assert.include(div.innerHTML, '<p>old</p>');
|
|
assert.include(div.innerHTML, '<span class="">new</span>');
|
|
});
|
|
});
|