squint

lread 2025-11-20T17:01:27.149049Z

Probably not really a squint question... more of a newbie question... I've not got any unit tests around cljdoc's front-end (which is written in squint)... I might like to add some. The current implementation is coupled to the dom. What do folks use in these cases? https://github.com/capricorn86/happy-dom/?

borkdude 2025-11-20T17:22:08.253589Z

You can check reagamis tests

borkdude 2025-11-20T17:22:50.191639Z

I happened to land in JSDom. Eucalypt uses happydom. Don’t have much experience with both

lread 2025-11-20T17:28:30.999059Z

Thanks! Will take a peek.

cjohansen 2025-11-20T21:53:48.614869Z

Hot take: Don't couple code to the DOM πŸ˜…

borkdude 2025-11-20T21:54:47.106099Z

except when you're creating a DOM patching library, then it might be handy to check if it works

cjohansen 2025-11-20T21:56:00.167049Z

Sure, but you don't want to be in a situation where you can only check if things work by going through the DOM

cjohansen 2025-11-20T21:57:14.125069Z

Replicant uses a protocol in front of the DOM to spare me the suffering of needing to run tests through a DOM

borkdude 2025-11-20T21:57:31.613409Z

then you're testing the protocol. I want to test if things actually work in the real world

cjohansen 2025-11-20T21:57:43.562329Z

With a protocol you can do that as well

borkdude 2025-11-20T21:58:04.308289Z

for example the input range min/max/value thing, you wouldn't catch that if you just test a protocol or instrument your code

cjohansen 2025-11-20T21:58:35.524079Z

No, but you can still write a test for the situation

cjohansen 2025-11-20T21:59:21.234829Z

I don't think you'll ever unit test yourself into such a case. You'll discover the problem through real usage. The question is: can you write a test that ensures you don't have that problem again? I can, even if I test against a protocol.

cjohansen 2025-11-20T22:00:04.389889Z

In any case, you could make an argument for coupling your tests to the DOM, but it still isn't a good argument for coupling the implementation to the DOM πŸ™‚

borkdude 2025-11-20T22:00:18.304689Z

I'm sure you can, but why test something fake if you can test the real thing. it's like testing a mock. I try to avoid mocks. I try to avoid unit tests as well. I tend to test systems, not just parts

cjohansen 2025-11-20T22:00:54.630959Z

I mostly agree with you. But I don't think this is a good reason to couple your implementation to a browser.

borkdude 2025-11-20T22:01:18.906919Z

what do you mean with "implementation and browser". what's your problem man

borkdude 2025-11-20T22:01:24.333459Z

:P

borkdude 2025-11-20T22:01:44.389219Z

I don't even know what you're accusing me of

2025-11-20T22:02:13.358419Z

hey cjohansen, this is a question about a dom library. i'm not sure what purpose you have for saying that a dom library shouldn't be used.

cjohansen 2025-11-20T22:02:40.468629Z

I am obviously not expressing myself well. Sorry for that!

2025-11-20T22:02:43.439799Z

there's a question and potential answers. i think if you have strong feelings about not using dom libraries, those would be better suited for a different thread

2025-11-20T22:02:55.304619Z

to be clear, i'm not a mod, just wondering what the goal here is

borkdude 2025-11-20T22:03:36.054149Z

it's fine. let him speak. :P

cjohansen 2025-11-20T22:04:09.809839Z

The way I read this thread: My code is coupled to the DOM, how can I test it? My hot take answer is: don't couple your code to the DOM and test it the conventional way. If the question instead was "how do I integration test with the DOM" then I am misguided, and apologize.

πŸ‘ 1
cjohansen 2025-11-20T22:05:08.035679Z

I haven't tried to accuse anyone of anything, and certainly did not mean to suggest someone shouldn't use "dom libraries". I just think coupling code to the DOM is a bad idea, but I understand my hot take is not appreciated, and will shut up now πŸ˜…

πŸ‘ 1
2025-11-20T22:07:26.311649Z

no worries, glad we could clear it up!

borkdude 2025-11-20T22:08:14.994539Z

it's fine. I appreciate it. I was just joking around while disagreeing on some things you said, because my reference is reagami, which is a DOM patching library. There I want to know if it actually mutates the DOM in the way I'd expect, e.g. is the node rendered the same reference. When testing applications, you're probably in a different game

cjohansen 2025-11-20T22:10:02.063949Z

I still think "I want to know if it actually mutates the DOM in the way I expect" is orthogonal to whether or not the code (specifically the implementation, not the tests) is directly coupled to the DOM. That was the point I was trying to make.

cjohansen 2025-11-20T22:11:25.634709Z

Example: Let's say your DOM morphing library can manipulate CSS properties. You might want to write several tests for how the library interprets Clojure datastructures into CSS. You need at least one test to make sure the style property of the DOM node is manipulated, but the bulk of tests could be written for how the library manipulates data.

lread 2025-11-20T22:11:36.182629Z

I was out raking leaves. I filled 11 bags. My word!

πŸ‚ 1
πŸ˜‚ 3
lread 2025-11-20T22:11:42.090129Z

Hot takes are welcome!

borkdude 2025-11-20T22:12:14.302789Z

That's where I think we differ. I've seen enough breaking tests where the ideal platonic world survives a "unit test" until it hits the real world. I want to see the system working, not just a part.

lread 2025-11-20T22:13:52.290399Z

So yeah, my first cljs go at the cljdoc front end was to simply transcribe it from TypeScript to squint cljs. That's where I'm at. I am wholly unsophisticated. simple_smile

cjohansen 2025-11-20T22:15:25.855209Z

I'm not necessarily talking about a part of a system. I'm saying that you can test that one aspect of the system works in the intended runtime, and then add a hell of a lot of more examples of that same behavior that runs faster by leaning on that one full example. This is not really a unit vs integration test thing. Besides: by not making the code directly coupled to the DOM, you open up for the ability for the code to work against targets that are not the DOM.

lread 2025-11-20T22:15:52.063219Z

I can now at least understand it and maintain it!

πŸ‘ 1
lread 2025-11-20T22:18:01.626909Z

The idea of localizing code that mutates the DOM makes sense to me. That's not what cljdoc code does. But it makes sense to me.

borkdude 2025-11-20T22:19:38.450959Z

It all makes sense to me but there's always different trade-offs. It's not like protocols are totally free in terms of performance either.

lread 2025-11-20T22:20:24.850979Z

But then again, cljdoc has a relatively teeny weeny front-end. So I might leave it as is unless it causes me problems.

borkdude 2025-11-20T22:20:53.259479Z

@lee what are you actually testing? aren't you maintaining a library called #etaoin that can help you with that? ;)

cjohansen 2025-11-20T22:21:01.743789Z

They're not. But I think (hope?) that their cost is low relative to updating the DOM, and not really a bottle neck. I think I may even have tested this, but I'm not sure.

lread 2025-11-20T22:22:23.916639Z

Ha! Yeah, I could use etaoin, but I've been traumatized by flaky webdriver tests while maintaining it!

πŸ˜… 1
borkdude 2025-11-20T22:22:28.838639Z

just for the record, @lee is just using squint + preact (comes down to as if you just wrote JS + React basically in terms of testing).

cjohansen 2025-11-20T22:23:05.590799Z

Yes, my hot take may have been entirely misplaced. Sorry!

lread 2025-11-20T22:27:14.570789Z

I could reconsider etaoin @borkdude. It is pretty reliable on Linux. I really just go through a short manual checklist. Or I could just keep going through my short checklist manually. simple_smile

lread 2025-11-20T22:27:52.452039Z

@christian767 nice, to see you so fired up and passionate!

borkdude 2025-11-20T22:28:10.793679Z

if your take is: you should just test the hiccup that's generated like in replicant: my feeling is that you don't even need to write a test for that - hiccup is just data. you may want to just skip that stuff entirely and not even include a rendering library for testing. unfortunately my experience with browser testing is that it sucks and is brittle almost always.

borkdude 2025-11-20T22:29:00.984779Z

people have had good experience with playwright: you can record your clicking around and stuff (and then also generate JS from that). haven't really tried it.

borkdude 2025-11-20T22:30:56.632219Z

my worry is more that there's something not working in the browser than the front-end logic and if you skip testing that part, you may just be fooling yourself

borkdude 2025-11-20T22:32:21.988009Z

it's like testing stuff with databases. it's all nice testing isolated functions that emit events and stuff, until you discover that the database is dropping data for some crazy reason

cjohansen 2025-11-20T22:35:56.055729Z

@borkdude The goal with Replicant certainly is that its user should be able to adopt such a naive approach to testing. From my own experience as an application developer I would say it's quite successful at this. As for Replicant's own tests, most of them are about which operations Replicant will perform in certain scenarios. They have helped me a lot, but surely also left some holes. But I don't think you can blame the testing strategy for that. Sure, Replicant had a bug with input ranges, but it also didn't have a single input range test - it hadn't occurred to me. It now has several, and none of them touch the DOM. They're probably not as good as the real thing, but by how much? And what do they gain from this disparity? I can make sure that it generates the right HTML string for server-rendering with the same test. That's something.

borkdude 2025-11-20T22:39:32.972539Z

I think it's telling that I ran into these bugs by just re-creating some reagent examples in my from-scratch reagent-clone in a few days and was able to fix them pretty quickly. The test may not look as nice as a pure-data test, but the writing the test wasn't my bottleneck at all.

borkdude 2025-11-20T22:41:50.830559Z

I want a test where I don't have to encode "this should be done before that" but "this will fail because the browser behaves like this". The this before that thing is just a way of preventing the failure. If you are testing that, then you are testing an implementation.

cjohansen 2025-11-20T22:46:34.429999Z

It's telling that you ran into the bug by recreating the examples. But it's not telling a lot about automated test strategy 😊 it does tell that you're very meticulous and methodical in how you approach things. I mostly make shit for myself. That affects my focus and horizon. This definitely reflects well on you, but I don't think the approach to automated testing has any bearing on this issue.

lread 2025-11-20T22:47:10.425509Z

Well, my innocent question triggered a very interesting discussion! I think borkdude is saying that without integration tests, he can't trust that his code works. And that he favours integration tests over unit tests. And cjohansen is saying that with solid very well tested dom abstractions, he can trust his unit tests enough to tell him his code is working. Is that a good summary?

borkdude 2025-11-20T22:48:59.304719Z

the approach to automated testing reflects on this issue exactly the way I wrote it: I want to test actual browser behavior because browsers are messy. I don't just want to test the platonic data-world stuff. 99% of clj-kondo's tests are written in this way too. real world scenario's going through the file system. not just "test this tiny function to see if it finds this particular case in this re-write-clj node"

borkdude 2025-11-20T22:49:27.915579Z

yeah, good summary

lread 2025-11-20T22:49:50.948889Z

Yes, I've very much noticed this is your preference when working with you over the years, borkdude.

borkdude 2025-11-20T22:50:45.531829Z

if you are the user of a library like replicant or something else, that's a different game. you shouldn't have to re-test that library. I agree with that

borkdude 2025-11-20T22:51:06.353809Z

but I'm talking about testing the library here

borkdude 2025-11-20T22:51:27.037059Z

well maybe for applications, I wouldn't blindly trust the library either

borkdude 2025-11-20T22:51:37.694029Z

anyway

borkdude 2025-11-20T22:51:51.306119Z

I still love you @christian767

❀️ 1
πŸ’– 1
cjohansen 2025-11-20T22:52:10.873109Z

It's a roughly accurate summary of where we ended up, but not really my initial point. I'm of the opinion that what you include in your tests is orthogonal to what you couple your code to. I agree that unit tests can fail by focusing too much on details, but I don't agree that this means every test should be an integration test.

borkdude 2025-11-20T22:52:45.367569Z

orthogonal is such an overloaded and overused word

lread 2025-11-20T22:54:31.122289Z

I've tended to like both. Unit tests can help me write and verify my code. And integration tests tell me my app/lib is working as a whole.

borkdude 2025-11-20T22:55:29.384659Z

> I agree that unit tests can fail by focusing too much on details Detail isn't my point at all. The point is that the unit test doesn't hit the stuff that is most often where the problems are. Detail is the wrong word: it's just not testing the most likely point of failure. It's not about detail

borkdude 2025-11-20T22:56:13.645899Z

I'm also not against unit tests. I don't force integration tests on everything. There are functions that are purely data and I write unit tests for those as well (e.g. in clj-kondo's type system for example)

cjohansen 2025-11-20T22:56:54.342989Z

That's roughly what I meant by "detail". I think we agree on this 😊

borkdude 2025-11-20T22:58:31.904129Z

well yeah, unit tests can focus on implementation details too much. and they are a pain to change when your internal implementation changes

borkdude 2025-11-20T22:58:58.250309Z

I think we all know this, it's not like we're discovering new ideas here

cjohansen 2025-11-20T23:00:09.209699Z

Maybe orthogonal is overused. But still, wanting to test everything through the DOM is a separate decision from whether the implementation should be hard coupled to the DOM. Coupling the implementation to the DOM means tests must involve the DOM. Not coupling the implementation means you can choose to involve the DOM or not.

lread 2025-11-20T23:00:11.102289Z

But do you know what we did discover? That you love @christian767, and that's nice.

cjohansen 2025-11-20T23:00:20.548999Z

Hehe

lread 2025-11-20T23:00:33.560479Z

Mission accomplished

borkdude 2025-11-20T23:01:11.711709Z

I still don't know what you are referring to with "the implementation".

cjohansen 2025-11-20T23:01:25.409539Z

The code that isn't the tests

borkdude 2025-11-20T23:02:07.109449Z

at some point some code somewhere needs to deal with the DOM. so what code are we talking about here.

lread 2025-11-20T23:03:48.670619Z

I've watched @christian767's video series on Replicant. I think it illustrates what he is talking about. And maybe goes back to my summary point.

borkdude 2025-11-20T23:05:08.965359Z

are you referring to "implementation" from the original post maybe?

cjohansen 2025-11-20T23:06:59.667919Z

I'm talking about what the code assumes and what is pluggable. If the code calls directly on the DOM, I'd say it's hard coupled because it assumes it's the only way to achieve its goal. If the DOM is behind some sort of abstraction, I'd say it isn't hard coupled. By "the implementation" I'm really talking about all the decisions the code makes around the DOM operations it needs to perform. But I don't think we'll agree on this on Slack, so maybe we've come as far as we'll come. I'll be at Dutch Clojure days 😊

borkdude 2025-11-20T23:07:45.099209Z

I think I'm still confused by what you mean with "the implementation" and "the code".

borkdude 2025-11-20T23:08:07.359139Z

you can't keep inventing layers of abstractions to hide away a problem, at some point you need to hit something in the real world

borkdude 2025-11-20T23:09:17.611339Z

but sure, let's talk at DCD. Are you coming to Babashka Conf too, the day before? https://www.meetup.com/the-dutch-clojure-meetup/events/312079164/?slug=the-dutch-clojure-meetup&eventId=312079164

borkdude 2025-11-20T23:09:32.451549Z

(there's only 10 out of 50 places left... after 1 day)

cjohansen 2025-11-20T23:10:17.033029Z

Just signed up!

πŸŽ‰ 1
borkdude 2025-11-20T23:10:46.238639Z

Are you sending something in for the CfP for DCD?

borkdude 2025-11-20T23:13:43.194579Z

you have more experience with writing front ends than me obviously. if you say that testing an abstraction works 90% of the time and for the remaining 10% you maybe write some more gnarly tests that might involve the DOM if you really have to, I believe you. it's great that this is working out for you. I'm really sceptical when it comes to computers working. Maybe I should start trusting browsers more.

πŸ˜‚ 1
cjohansen 2025-11-20T23:17:37.322849Z

I'm planning to send something to the CfP yes!

borkdude 2025-11-20T23:17:46.960599Z

can we guess which project it will be about?

cjohansen 2025-11-20T23:20:22.876749Z

I haven't decided yet, otherwise it would already be in 😊

lread 2025-11-20T23:22:33.638009Z

So to answer my original question: It depends, there are many different schools of thought and preferences.

borkdude 2025-11-20T23:22:57.382829Z

don't trust me, trust browsers

1
borkdude 2025-11-20T23:23:13.318379Z

gotta do some πŸ’€ now

lread 2025-11-20T23:24:47.815619Z

Good night, folks. Thanks for this thread. It was interesting, fun, and also Clojurely in its spirited yet diplomatic tone.

Chris McCormick 2025-11-21T04:40:43.771969Z

Plot twist: writing Eucalypt tests I discovered that happy-dom diverges from the browser behaviour more frequently than I would like. laughcry

πŸ˜… 4