1 | # Dependency injection
|
2 |
|
3 | We have built our own super simple DI.
|
4 |
|
5 | ## Install
|
6 |
|
7 | `npm install @mindhive/di`
|
8 |
|
9 | ## Motivations and benefits
|
10 |
|
11 | - Prefer pure functions
|
12 | - Avoid ES6 imports as they are difficult to test
|
13 | - Especially avoid Meteor package imports as most test runners don't understand Meteor's packaging
|
14 | (they can be accessed through Meteor globals but that's not a great idea either)
|
15 |
|
16 | ## Lifecycle
|
17 |
|
18 | 1. Main file for the app should import all of it's modules using `initModules()`
|
19 |
|
20 | 2. Modules should export a default function
|
21 |
|
22 | - For example: `export default () => { ...; return { serviceName: new Service(), ... } }`
|
23 | - Return an object where the keys map service names to the service objects/functions to be
|
24 | put into the app context
|
25 | - Modules further down thru the array passed to `initModules()` can use services added to the
|
26 | appContext by earlier modules. The module function is passed the current appContext
|
27 | (destructing works a treat), for example:
|
28 | `export default ({ Meteor, Mongo }) => { ... }`
|
29 | - Modules don't have to return anything, you can use them to perform other initialization
|
30 | - Modules are called inside `Meteor.startup` so there is no need to manage that yourself
|
31 |
|
32 | 3. To access services in the appContext call `app()` to get the appContext
|
33 |
|
34 | ## Testing
|
35 |
|
36 | In the example below `service` will be the only object in the appContext and available to any
|
37 | code that calls `app()`.
|
38 |
|
39 | ```javascript
|
40 | import { mockAppContext } from '@mindhive/di'
|
41 | const modules = () => ({
|
42 | service: { foo: sinon.spy() }
|
43 | })
|
44 | it('should call service.foo()',
|
45 | mockAppContext(modules, () => {
|
46 | funcUnderTest()
|
47 | service.foo.should.have.been.calledOnce
|
48 | })
|
49 | )
|
50 | ````
|
51 |
|
52 | `modules` is a function so that the spys and dummy values used in it
|
53 | are recreated every test, avoiding any contamination to the next test.
|
54 |
|
55 | However, if your test runner doesn't teardown the tests properly it
|
56 | may be necessary to use `resetAppContext`.
|
57 |
|
58 | You can also use `initModules` within the 'modules' function, it operates
|
59 | exactly as it would in production code.
|
60 |
|
\ | No newline at end of file |