const { assert } = require("chai");
describe("sse extension", function() {
function mockEventSource() {
var listeners = {};
var wasClosed = false;
var url;
var mockEventSource = {
removeEventListener: function(name, l) {
listeners[name] = listeners[name].filter(function(elt, idx, arr) {
if (arr[idx] === l) {
return false;
}
return true;
})
},
addEventListener: function(message, l) {
if (listeners == undefined) {
listeners[message] = [];
}
listeners[message].push(l)
},
sendEvent: function(eventName, data) {
var listeners = listeners[eventName];
if (listeners) {
listeners.forEach(function(listener) {
var event = htmx._("makeEvent")(eventName);
event.data = data;
listener(event);
}
}
},
close: function() {
wasClosed = true;
},
wasClosed: function() {
return wasClosed;
},
connect: function(url) {
this.url = url
}
};
return mockEventSource;
}
beforeEach(function() {
this.server = makeServer();
var eventSource = mockEventSource();
this.eventSource = eventSource;
clearWorkArea();
htmx.createEventSource = function(url) {
eventSource.connect(url);
return eventSource;
};
});
afterEach(function() {
this.server.restore();
clearWorkArea();
});
it('handles basic sse triggering', function() {
this.server.respondWith("GET", "/d1", "div1 updated");
this.server.respondWith("GET", "/d2", "div2 updated");
var div = make('
');
this.eventSource.sendEvent("e1");
this.server.respond();
byId("d1").innerHTML.should.equal("div1 updated");
byId("d2").innerHTML.should.equal("div2");
this.eventSource.sendEvent("e2");
this.server.respond();
byId("d1").innerHTML.should.equal("div1 updated");
byId("d2").innerHTML.should.equal("div2 updated");
})
it('does not trigger events that arent named', function() {
this.server.respondWith("GET", "/d1", "div1 updated");
var div = make('');
this.eventSource.sendEvent("foo");
this.server.respond();
byId("d1").innerHTML.should.equal("div1");
this.eventSource.sendEvent("e2");
this.server.respond();
byId("d1").innerHTML.should.equal("div1");
this.eventSource.sendEvent("e1");
this.server.respond();
byId("d1").innerHTML.should.equal("div1 updated");
})
it('does not trigger events not on descendents', function() {
this.server.respondWith("GET", "/d1", "div1 updated");
var div = make('' +
'div1
');
this.eventSource.sendEvent("foo");
this.server.respond();
byId("d1").innerHTML.should.equal("div1");
this.eventSource.sendEvent("e2");
this.server.respond();
byId("d1").innerHTML.should.equal("div1");
this.eventSource.sendEvent("e1");
this.server.respond();
byId("d1").innerHTML.should.equal("div1");
})
it('is closed after removal, hx-trigger', function() {
this.server.respondWith("GET", "/test", "Clicked!");
var div = make('');
div.click();
this.server.respond();
this.eventSource.wasClosed().should.equal(true)
})
it('is closed after removal, hx-swap', function() {
this.server.respondWith("GET", "/test", "Clicked!");
var div = make('');
div.click();
this.server.respond();
this.eventSource.wasClosed().should.equal(true)
})
it('is closed after removal with no close and activity, hx-trigger', function() {
var div = make('');
div.parentElement.removeChild(div);
this.eventSource.sendEvent("e1")
this.eventSource.wasClosed().should.equal(true)
})
// sse and hx-trigger handlers are distinct
it('is closed after removal with no close and activity, sse-swap', function() {
var div = make('');
div.parentElement.removeChild(div);
this.eventSource.sendEvent("e1")
this.eventSource.wasClosed().should.equal(true)
})
it('swaps content properly on SSE swap', function() {
var div = make('\n');
byId("d1").innerText.should.equal("")
byId("d2").innerText.should.equal("")
this.eventSource.sendEvent("e1", "Event 1")
byId("d1").innerText.should.equal("Event 1")
byId("d2").innerText.should.equal("")
this.eventSource.sendEvent("e2", "Event 2")
byId("d1").innerText.should.equal("Event 1")
byId("d2").innerText.should.equal("Event 2")
})
it('swaps swapped in content', function() {
var div = make('\n'
)
this.eventSource.sendEvent("e1", '')
this.eventSource.sendEvent("e2", 'Event 2')
byId("d2").innerText.should.equal("Event 2")
})
it('works in a child of an hx-ext="sse" element', function() {
var div = make('\n'
)
this.eventSource.url = "/event_stream"
})
it('only adds sseEventSource to elements with sse-connect', function() {
var div = make('');
(byId('d1')["htmx-internal-data"].sseEventSource == undefined).should.be.true
// Even when content is swapped in
this.eventSource.sendEvent("e1", '');
(byId('d2')["htmx-internal-data"].sseEventSource == undefined).should.be.true
})
it('initializes connections in swapped content', function() {
this.server.respondWith("GET", "/d1", '');
this.server.respondWith("GET", "/d2", "div2 updated");
var div = make('');
div.click();
this.server.respond();
this.eventSource.sendEvent("e2");
this.server.respond();
byId("d2").innerHTML.should.equal("div2 updated");
})
it('creates an eventsource on elements with sse-connect', function() {
var div = make('');
(byId("d1")['htmx-internal-data'].sseEventSource == undefined).should.be.false;
})
});