Hacker News new | ask | show | jobs
by jilles 521 days ago
I've created a Django application using HTMX. Usually I'd jump to React or Vue. It was a great exercise and I can see where HTMX would be a great fit.

1. If you consider yourself a "backend developer" only and want to write the minimum amount of JS/TS.

2. If your application is simple. Yes you can do more complicated interactivity with oob swaps, but you end up with more complexity than you chose HTMX for.

For my next projects, I will still use Django but with React/Vue for pieces that need interactivity. As an example in my HTMX app, I wanted to add a profile image uploader. Lots of great frontend libraries exist to resize / modify your image before even uploading it to your server.

Finally, HTMX is just not testable the same way modern frontend libraries are. I've managed to write some decent tests using beautifulsoup, but it's night and day compared to vitest or jest.

8 comments

This was my exact experience - loved it as a backend developer wanting to build simple frontends with minimal JavaScript (and I still recommend it for many use cases) but when I then tried HTMX to build a more complex application I found that the complexity that would normally be handled by a JavaScript framework ultimately grew and shifted to the HTML and, surprisingly, the backend as well.

For example, error handling in complex forms. When you have React handling errors you simply return a 400 JSON response with fields and reasons, or some other error message, and React decides what to do depending on the context, which it knows. When this responsibility is moved to the backend you now need to track the request location, state etc. and find the right fragment, which very quickly turned the code into a mess.

I think the choice of backend is also important. I suspect that Java (Spring Boot) made using HTMX much less pleasant than it would have been with something else, especially when it comes to templates and routing. Using Java for HTML templates (Thymeleaf or any of the other popular libraries) is something I will never do again.

Edit:

The analogy with jQuery is interesting. I feel the same way about HTMX now as I did about jQuery ten years ago. I used to plug jQuery into every project even if it was just to select elements or whatever, but whenever I used jQuery entirely over the frameworks that were popular at the time (Ember, Angular) I ended up with way messier code.

> When this responsibility is moved to the backend you now need to track the request location, state etc. and find the right fragment,

Maybe not? I'm just returning a 422 JSON response with fields and reasons and I have a tiny bit of JavaScript in the frontend that just plugs them in to the form with the built-in Constraint Validation API.

https://dev.to/yawaramin/handling-form-errors-in-htmx-3ncg

> I suspect that Java (Spring Boot) made using HTMX much less pleasant than it would have been with something else, especially when it comes to templates and routing.

I strongly agree with that and created a library to help with those aspects: https://github.com/yawaramin/dream-html?tab=readme-ov-file#f...

IMHO one of the biggest advantages of using HTMX is not having to maintain three layers of test suites (backend, frontend, end-to-end). You just need to test that your endpoints return the right HTML piece. You don't need unit testing the frontend since you don't have that much logic there. Just rely on end-to-end tests as a complementary tool to check small pieces of logic on the HTMX code.
I’m not sure I’d agree. The HX attributes encode a lot of functionality and you want to check that they do the right thing together. You can test you get the right attributes in a response, but that’s only a proxy for the application doing the right thing, so you most likely still need the end to end tests.

The problem is that end to end tests are the hardest kind to write. At least if you have a frontend code base you can have some tests there and get some confidence about things working at a lower level.

> You just need to test that your endpoints return the right HTML piece. You don't need unit testing the frontend since you don't have that much logic there.

Only using the standard Django test client? I don't find this myself when I've had to work with HTMX code e.g. if you're using HTMX for your sign up form, it can be completely broken on the happy path and on form errors if the HTMX attributes are wrong, and the standard Django test client won't let you know, so you lose a lot of confidence when making refactors/changes.

That honestly sounds like a downside. Having to verify HTML as an output (in comparison to e.g. JSON) is brittle since it will often change just for presentation reasons. Having a clear and somewhat stable API (which is a boon for testing) is IMHO a strong reason for the SPA model.
> Having to verify HTML as an output (in comparison to e.g. JSON) is brittle since it will often change just for presentation reasons.

For HTML tests, if you target elements by their ARIA role, semantic tag, or by matching against the text/label/title the user would see, it should be robust to a lot of presentation changes (and does some accessibility checks too). It's much more robust than e.g. `body > div > div .card > h2` which are sure to break in tests and slow you down when you make changes later.

See Playwright locators for example:

https://playwright.dev/docs/locators

Not sure if this is what you meant, but you can't rely on only the JSON because you can't assume it's been properly transformed into the expected HTML.

htmx moves the data -> html transformation to the server side and thus should be more testable
It's standard practice in the frontend world https://jestjs.io/docs/snapshot-testing
In my experience snapshots have largely fallen out of vogue, at least as far as them blocking deploys goes. They're usually flaky, change often, are slow to test and it's way too easy to have false positives which lulls people into complacency and just regenerating the snapshots as soon as they reach a failure. I'm guilty of that myself, unless I can spot the breakage immediately I pretty much just regen the snapshot by default subconsciously because of how often I've had to do that for false positives
Then what's to stop you from making any unit test pass by just changing the expectations? The best testing technique in the world can't save us from developer error.
The problem with snapshot tests is that they tend to fail when something is changed.

One property of good tests is that they only fail when something is broken.

Snapshot tests aren't really automated tests, because you have to manually check the outputs to see if failures are genuine. It's a reminder to do manual checking but it's still not an automated process.

> The best testing technique in the world can't save us from developer error.

Sure, but using a testing technique that increases developer error is unwise, and snapshot testing has done that every time I've seen it used, so I don't use it anymore.

Not really unstable since you generate it and there's no browser modifying it. However you'd still lack client functionality testing.
> 1. If you consider yourself a "backend developer" only and want to write the minimum amount of JS/TS.

This is a great point and should be underscored more. I think generally the HTMX vs React/Vue/Svelte argument gets undercut when people don't express their innate bias on which part of the stack they want to give more control to. HTMX is great if you're pro-expanding the server; JS Frameworks if you're trying to expand it from the application layer.

You don't have to write your own using beautifulsoup. There are test frameworks like https://www.cypress.io/ and https://playwright.dev/ that work great there.
With the BeautifulSoup tests I can run 1000s of tests in seconds. Cypress/Playwright are wonderful for e2e tests, but not comparable to simple unit tests you'd have in React/Vue. I find that the BeautifulSoup tests are a decent middle ground.
But with beautifulsoup you don't test the interactions at all. You only test the rendered template which is nice, but doesn't tell you if any button actually works the way you expect.
Why is that a good thing when testing a web app? You want to see if the browser is executing your code with the correct intent.

Seems very brittle and may not catch actual regressions browsers introduce.

I've successfully used (for 3+ years in multiple projects) an approach similar to BeautifulSoup's get_text() function to assert the whole visible text of a component. You can implement it in other languages with a few regexes.

One addition makes it an order of magnitude more versatile: a way to visualize non-textual information as text in the tests. For example add a data-test-icon attribute which contains the replacement text that should be shown in tests. Another method is to parse the HTML and write custom visualization for some elements, so that you get useful default visualization for at least form elements and such, without having to repeat the data-test-icon attribute every time.

See https://martinfowler.com/articles/tdd-html-templates.html#Bo...

I’ve done something similar, but using pandoc to convert the html to text, so tables and bullet points are rendered appropriately.
I'm all in on Hotwire, which is pretty similar.

They're both fantastic expansions of what server-side rendering can do. They can't really do work as nice as what React can, but you can get perhaps 85% of React for 5-10% of the development time. And a big increase in usability of your app.

As I dont do frontend work, how do you "test" anything without an insane amount of browsers/hardware realistically ?

If I was to write tests, it'd be basically http get/post/put/delete requests and measuring the responses are what I expect.. how can HTMX be any different here ?

How do you "test" a button works without a browser engine ? Every browser engine ?

We do have pseudo-browsers written in pure js that you can theoretically use:

https://github.com/jsdom/jsdom

https://github.com/capricorn86/happy-dom

but they're about as reliable as you can expect: it's difficult to keep up the pace with the big three (or two) on standards compliance, and they usually don't even try.

So the only reliable solution is a headless Chromium, Firefox, and/or WebKit-based noname browser like the sibling says.

https://pptr.dev/guides/what-is-puppeteer

https://playwright.dev/

https://www.selenium.dev/documentation/

You throw headless browsers into your CI/CD pipeline and try not to think about how many resources you're burning.
Might work for a small project, but a nightmare for medium to large projects. Imagine Microsoft tests their Outlook (web app) like that.
Microsoft tests Outlook?
> For my next projects, I will still use Django but with React/Vue for pieces that need interactivity

What's your plan for "plugging" these into your HTML? Web components?

Does Django have some kind of integration with Vite for hot reload during dev?

Check out my project, built exactly for this: https://www.reactivated.io