Testing Angular components
I am having a hard time testing some GUI code. Part of this feels like a problem of organization. The way this code uses Angular, components frequently mix "how" with "when." They handle the details of interacting with [important Service], plus internal state, plus when to interact — on what button click or UI interaction.
One piece of advice I came across recently is to split out the how. Stick the details of state and talking-to-the-service in another object, inject an instance into your component, and test the object rather than the component. It goes against the grain of the codebase and an awful lot of work. But it might be a good idea.
Another idea is to directly depend on the templates. This is what the tutorials do and I know it happens in other contexts. It seems to violate the principle that tests should be resistant to refactoring, though. On the other hand — does a UI change count as refactoring, given it's usually a user-observable change? In theory, no it shouldn't. In practice — this UI may not be so stable yet that we want to fix or replace five tests every time we change the UI. (Or maybe it is stable enough! It seems pretty stable to me, overall...) If the UI changes frequently, it's probably not useful to write a test that depends on the details of how the UI works.
But I still want to know that mashing buttons in the UI won't screw up the application state. How can I test that?
Well — I could just test that the component's methods do what they are supposed to. That's an option. It makes sense if the HTML template is just calling semantically meaningful "event" methods on the component, similar to a humble object or humble dialog box.
The tricky part is that these methods use the HappyService
, which — if I recall correctly — both tracks state and makes HTTP API calls by directly calling bare functions. To test just the state handling, I'd want to fake out the API calls. That should be doable, though... just inject the API functions into the HappyService
.
Some of the components may be a bit too complicated for that to work. They might try to do things with the HTML that won't work if it's not rendered. But this might work for some things. Worth considering.