Search code examples
angulararchitecturenrwl-nxmicro-frontend

In Nx + Angular monorepo architecture, where should I put testing helpers that are specific to just one library?


For context, we have an Angular + Nx monorepo with just one main app currently, but we plan to split it to a few separate microfrontends soon.

We currently have just one main module, util-models, that contains all the interfaces describing all the API interactions, and also all the stubs we use in tests to mock data.

Now let's say I have a library my-feature that contains some feature that I'll want to build and deploy (as a lazily-loaded route or as a part of the main bundle). This library already depends on util-models, because it deals with some standardized data, but we also have there a separate my-model.model.ts file that only describes interfaces specific to this one feature.


Some visual representation:

\my-feature
  \lib
    - my-models.model.ts
    - my-component.component.ts
    - my-component.component.spec.ts

\util-models
  \lib
    - shared-model.model.ts
    \test
      - shared-model.stub.ts

So the question is, where should I put my my-models.stub.ts file that contains all of the library-specific stubs?

1. The first obvious answer would seem to be "put your library-specific code in the library". But does that mean that all of my libraries should actually aim to have a separate test directory for all stubs or test utils that are specific to them? Does that apply to models too (which aren't even compilable code, just interfaces)? Doesn't that reduce the discoverability of these tools that are supposed to assist devs, in case some other library in the future was also actually dealing with the same data structures?

Also, will this code get automatically dropped from the prod build alongside the regular .spec.ts files? Is it enough to just not import it in the module?

2. Another option would be putting it in the already existing util-models library, which my-feature will probably keep depending on, but obviously I'm worried that just makes it less separated in the long run. On the other hand, if this is just testing code that will never go to production anyway, then maybe that's actually fine, or even desirable for some reason?


I'm mostly interested in how both options would potentially affect things like build/test build times, tree shaking, lazy loading, and migration to microfrontends. I'd appreciate any tips!


Solution

  • I haven't found any official document that would clear this up, but after spending more time with Nx, and especially after learning more about DDD (Domain Driven Development), I grew more of an intuition.

    My current intuition is that "discoverability" of code between libraries that are actually unrelated is not a feature, it's a problem. All code should belong to its own specific domain, not get centralized in some large generic library - it doesn't matter if it's only interfaces or testing code.

    Each "shared" library, if we allow it to exist in our dependency tree, has to have a purpose specific to at most one domain.

    Therefore I now feel confident with the following decisions:

    1. We should aim to disband the central util-models library. Models describing API responses all can be assigned to more specific domains.
    2. If we want to reuse models between feature libraries, because we are certain they actually do belong to the same business domain, then we will create a separate util library only for sharing those specific models for this specific domain.
    3. As logically follows, we should start including separate test directories in any libraries that own models, in order to have model stubs ready when we want to test our components/services/etc. in that library.