1 | # ineeda
|
2 |
|
3 | [![npm version](https://img.shields.io/npm/v/ineeda.svg)](https://img.shields.io/npm/v/ineeda.svg)
|
4 |
|
5 | Auto-mocking with [Proxies](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy)! Works best with TypeScript, but works just as well with JavaScript!
|
6 |
|
7 | # Installation:
|
8 |
|
9 | ```
|
10 | npm install ineeda --save-dev
|
11 | ```
|
12 | or
|
13 | ```
|
14 | yarn add ineeda --dev
|
15 | ```
|
16 |
|
17 | # Mocking:
|
18 |
|
19 | ### To get a mock of a concrete class:
|
20 |
|
21 | ```typescript
|
22 | import { Hero } from './Hero';
|
23 |
|
24 | import { ineeda } from 'ineeda';
|
25 |
|
26 | let hero: Hero = ineeda<Hero>();
|
27 | console.log(hero.age); // [IneedaProxy] (truthy!)
|
28 | console.log(hero.weapon.isMagic); // [IneedaProxy] (truthy!)
|
29 | console.log(hero.weapon.sharpen()); // Error('"sharpen" is not implemented.');
|
30 |
|
31 | let bonnie: Hero = ineeda<Hero>({ name: 'Bonnie' });
|
32 | console.log(bonnie.name); // 'Bonnie'
|
33 | ```
|
34 |
|
35 | ### To get a mock of an interface:
|
36 |
|
37 | ```typescript
|
38 | import { IHorse } from './IHorse';
|
39 |
|
40 | import { ineeda } from 'ineeda';
|
41 |
|
42 | let horse: IHorse = ineeda<IHorse>();
|
43 | horse.hero.weapon.sharpen(); // Error('"sharpen" is not implemented.');
|
44 | ```
|
45 |
|
46 | ### To get a mock of a concrete class that is an actual instance of that class:
|
47 |
|
48 | ```typescript
|
49 | import { Hero } from './Hero';
|
50 |
|
51 | import { ineeda } from 'ineeda';
|
52 |
|
53 | let realHero: Hero = ineeda.instanceof<Hero>(Hero);
|
54 | console.log(realHero instanceof Hero); // true;
|
55 | ```
|
56 |
|
57 | ### To get a factory that produces mocks of a concrete class:
|
58 |
|
59 | ```typescript
|
60 | import { Hero } from './Hero';
|
61 |
|
62 | import { ineeda, IneedaFactory } from 'ineeda';
|
63 |
|
64 | let heroFactory: IneedaFactory<Hero> = ineeda.factory<Hero>();
|
65 | let heroMock: Hero = heroFactory();
|
66 | ```
|
67 |
|
68 | # Intercepting:
|
69 |
|
70 | ### Overriding proxied values:
|
71 |
|
72 | Since the result of a call to `ineeda` is a proxy, it will happily pretend to be any kind of object you ask it to be! That can cause some issues, such as when dealing with `Promises` or `Observables`. To get around that, you can use `intercept`.
|
73 |
|
74 | When you need a fake `Promise` or `Observable`:
|
75 |
|
76 | ```typescript
|
77 | let mockObject = ineeda<MyObject>();
|
78 |
|
79 | function looksLikePromise (obj) {
|
80 | return !!obj.then;
|
81 | }
|
82 |
|
83 | looksLikePromise(mockObject); // true;
|
84 | looksLikePromise(mockObject.intercept({ then: null })); // false;
|
85 |
|
86 | let mockObject = ineeda<MyObject>();
|
87 | let myObservable$ = Observable.of(mockObject.intercept({ schedule: null }));
|
88 | ```
|
89 |
|
90 | Remembering which properties need to be intercepted can be a pain, and rather error prone. Alternatively, you can assign a `key`, which you can use to set up specific values that should be intercepted. In your test config you might do something like the following:
|
91 |
|
92 | ```typescript
|
93 | // Prevent Bluebird from thinking ineeda mocks are Promises:
|
94 | ineeda.intercept<Promise<any>>(Promise, { then: null });
|
95 |
|
96 | // Prevent RxJS from thinking ineeda mocks are Schedulers:
|
97 | ineeda.intercept<Scheduler>(Observable, { schedule: null });
|
98 | ```
|
99 |
|
100 | Then later, in your tests, you could do the following:
|
101 |
|
102 | ```typescript
|
103 | let mockObject = ineeda<MyObject>();
|
104 |
|
105 | function looksLikePromise (obj) {
|
106 | return !!obj.then;
|
107 | }
|
108 |
|
109 | looksLikePromise(mockObject); // true;
|
110 | looksLikePromise(mockObject.intercept(Promise)); // false;
|
111 |
|
112 | let mockObject = ineeda<MyObject>();
|
113 | let myObservable$ = Observable.of(mockObject.intercept(Observable));
|
114 | ```
|
115 |
|
116 | You can also *globally* intercept something on all objects, by using the `intercept` method without the `key`:
|
117 |
|
118 | ```typeScript
|
119 | ineeda.intercept({
|
120 | // Prevent zone.js from thinking ineeda mocks are unconfigurable:
|
121 | __zone_symbol__unconfigurables: null
|
122 | });
|
123 | ```
|
124 |
|
125 | ### Adding behaviour to proxied values:
|
126 |
|
127 | `intercept` can also be used to augment the behaviour of all mocks. One example might be to make every mocked function a `spy`.
|
128 |
|
129 | ```typescript
|
130 | // Prevent sinon from thinking ineeda mocks are already spies:
|
131 | ineeda.intercept({
|
132 | restore: null,
|
133 | calledBefore: null
|
134 | });
|
135 |
|
136 | // Intercept all values that are functions and turn it into a stub:
|
137 | ineeda.intercept((value, key: string, values, target) => {
|
138 | if (value instanceof Function) {
|
139 | target[key] = () => { };
|
140 | return sinon.stub(target, key, values[key]);
|
141 | }
|
142 | return value;
|
143 | });
|
144 |
|
145 | let mockObject = ineeda<MyObject>();
|
146 | mockObject.someMethod(1, 2, 3);
|
147 |
|
148 | // Using sinon-chai:
|
149 | expect(mockObject.someMethod).to.have.been.calledWith(1, 2, 3);
|
150 | ```
|