Untangled server 0.7.0 released. NOTE: This was a major refactoring, which is why it was delayed. Should be 100% backward compatible, but adds a new more modular way to build servers, including API composition, and easy custom Ring middleware stacks.
We're using the modular stuff internally, but not the classic build server function.
This branch: https://github.com/untangled-web/untangled-template/tree/modular-server
is a template using the new modular server support
Custom Ring, composable API modules, and parser injections as component injections
@tony.kay congrats
I’m trying to write some tests using untangled.server.protocol-support/check-response-to-client, but I’ve hit some problems with tempids. I tried to use the :om.tempid/my-temp-id form, but there’s some translation to an om.tempid.TempId form somewhere along the way and it all goes wrong. I added a hack to treat om.tempid.TempIds as tempids in that code, and it worked fine with an om generated tempid
That issue aside, is there a way to apply a series of mutations to the system, in a similar way to check-response-to-client, or is there a better testing strategy for that.
@lucasbradstreet We're kind of on the fence abt protocol support. It was an experiment that had some merit in the idea department, but in our experience it hasn't really given us good overall velocity in testing. The client-side stuff is OK, but I'm leaning much more towards operations on db objects that are easy to reason about (and test, if necessary). The composition of said functions into a mutation is also trivial to test. Integration testing mutations really should not involve as much of the stack as protocol support pushes you towards. In the small, it sounded great. In the large, I lean towards it being too heavy.
The approach we take that is working well:
1. We have the database components set up with seeding (using keyword type seeding)
2. We write small integration tests around just the database operation
3. If there is logic around the IO, then that is possibly unit tested (e.g. db op tested in (2) mocked out. THis might be, for example, the security step.
4. Anything else that is tested is more pure code (e.g. client-side mutations are just compositions of functions (f state-map) => state-map
or (f table-obj) => table-obj
.
usually the state-map transforms are just (swap! state (fn [m] (-> (update-in (obj-ident x) do-something-to-x) ...)))
e.g. a composition of focusing on tables and table-local operations
along with helper functions that encapsulate the swap/update-in (I'm making this up on the spot): (evolve! state (object-ident x) do-something-to-x)
or a compositional form (swap! state evolve (object-ident x) do-something-to-x do-something-else)
then the vast majority of the code is so stinkin simple you might not choose to write tests for it, and the rest is still quite easy to test.
because the ops (except for evolve) are against component-local table maps instead of the app state
this also helps with local reasoning
So, loooong-answer for a short question. The short answer is "protocol support is a mostly-failed experiment"
I would love to delete it, but don't want to break people's existing test suites. I might try moving it out to a deprecated library, so a deps change could suffice for breakage avoidance.
@tony.kay thanks for the explanation. I'll stay away from protocol support style tests then. I'm looking forward to your Clojurewest talk
Is anyone using core.spec with untangled? Is the testing library that comes with untangled complementary to it, or a replacement?
Hey @tony.kay i'm happy to see you on the speakers' list as well 😃
So for a UI child to gain access to a top-level table, its parent has to have access to it?
Or is there a way for a deeply nested child to reach up for an arbitrary database entry?
http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.D_Queries under query-example-links I can see that you can reach use links [:entities/by-id _]
however, I'm having trouble with a specific use-case that I'm not sure this covers
So basically I have a component that gets a bunch of items from the database. A list of idents and some other fields
This components needs the ability to edit the entites, so I've defined a field in the database that can be changed from this component