1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | var expect = require("expect.js"),
|
11 | rewire = require("rewire"),
|
12 | __set__Src = require("../lib/__set__.js").toString(),
|
13 | __get__Src = require("../lib/__get__.js").toString(),
|
14 | __with__Src = require("../lib/__with__.js").toString();
|
15 |
|
16 | var supportsObjectSpread = (function () {
|
17 | try {
|
18 | eval("({...{}})");
|
19 | return true;
|
20 | } catch (err) {
|
21 | return false;
|
22 | }
|
23 | })();
|
24 | var supportsObjectRest = (function () {
|
25 | try {
|
26 | eval("const {...a} = {}");
|
27 | return true;
|
28 | } catch (err) {
|
29 | return false;
|
30 | }
|
31 | })();
|
32 |
|
33 | function checkForTypeError(err) {
|
34 | expect(err.constructor).to.be(TypeError);
|
35 | }
|
36 |
|
37 | module.exports = function () {
|
38 |
|
39 | it("should work like require()", function () {
|
40 | rewire("./moduleA.js").getFilename();
|
41 | require("./moduleA.js").getFilename();
|
42 | expect(rewire("./moduleA.js").getFilename()).to.eql(require("./moduleA.js").getFilename());
|
43 | expect(rewire("../testLib/someOtherModule.js").filename).to.eql(require("../testLib/someOtherModule.js").filename);
|
44 | });
|
45 |
|
46 | it("should return a fresh instance of the module", function () {
|
47 | var someOtherModule = require("./someOtherModule.js"),
|
48 | rewiredSomeOtherModule;
|
49 |
|
50 | someOtherModule.fs = "This has been modified";
|
51 | rewiredSomeOtherModule = rewire("./someOtherModule.js");
|
52 | expect(rewiredSomeOtherModule.fs).not.to.be("This has been modified");
|
53 | });
|
54 |
|
55 | it("should not cache the rewired module", function () {
|
56 | var rewired,
|
57 | someOtherModule = require("./someOtherModule.js");
|
58 |
|
59 | someOtherModule.fs = "This has been changed";
|
60 |
|
61 | rewired = rewire("./someOtherModule.js");
|
62 | expect(someOtherModule).not.to.be(rewired);
|
63 | expect(require("./moduleA.js").someOtherModule).not.to.be(rewired);
|
64 | expect(require("./moduleA.js").someOtherModule).to.be(someOtherModule);
|
65 | expect(require("./moduleA.js").someOtherModule.fs).to.be("This has been changed");
|
66 | });
|
67 |
|
68 |
|
69 | it("should modify the module so it provides the __set__ - function", function () {
|
70 | expect(rewire("./moduleA.js").__set__.toString()).to.be(__set__Src);
|
71 | expect(rewire("./moduleB.js").__set__.toString()).to.be(__set__Src);
|
72 | });
|
73 |
|
74 |
|
75 | it("should modify the module so it provides the __get__ - function", function () {
|
76 | expect(rewire("./moduleA.js").__get__.toString()).to.be(__get__Src);
|
77 | expect(rewire("./moduleB.js").__get__.toString()).to.be(__get__Src);
|
78 | });
|
79 |
|
80 |
|
81 | it("should modify the module so it provides the __with__ - function", function () {
|
82 | expect(rewire("./moduleA.js").__with__.toString()).to.be(__with__Src);
|
83 | expect(rewire("./moduleB.js").__with__.toString()).to.be(__with__Src);
|
84 | });
|
85 |
|
86 |
|
87 | ["__get__", "__set__", "__with__"].forEach(function(funcName) {
|
88 | it("should provide " + funcName + " as a non-enumerable property", function () {
|
89 | expect(Object.keys(rewire("./moduleA.js")).indexOf(funcName)).to.be(-1);
|
90 | });
|
91 |
|
92 | it("should provide " + funcName + " as a writable property", function () {
|
93 | var obj = rewire("./moduleA.js");
|
94 | var desc = Object.getOwnPropertyDescriptor(obj, funcName);
|
95 | expect(desc.writable).to.be(true);
|
96 | });
|
97 | });
|
98 |
|
99 | it("should not influence other modules", function () {
|
100 | rewire("./moduleA.js");
|
101 |
|
102 | expect(require("./someOtherModule.js").__set__).to.be(undefined);
|
103 | expect(require("./someOtherModule.js").__get__).to.be(undefined);
|
104 | expect(require("./someOtherModule.js").__with__).to.be(undefined);
|
105 | });
|
106 |
|
107 | it("should not override/influence global objects by default", function () {
|
108 |
|
109 | rewire("./moduleA.js").checkSomeGlobals();
|
110 | rewire("./moduleB.js").checkSomeGlobals();
|
111 | });
|
112 |
|
113 |
|
114 |
|
115 | it("should provide a working __set__ method", function () {
|
116 | var rewiredModuleA = rewire("./moduleA.js"),
|
117 | newObj = {};
|
118 |
|
119 | expect(rewiredModuleA.getMyNumber()).to.be(0);
|
120 | rewiredModuleA.__set__("myNumber", 2);
|
121 | expect(rewiredModuleA.getMyNumber()).to.be(2);
|
122 | rewiredModuleA.__set__("myObj", newObj);
|
123 | expect(rewiredModuleA.getMyObj()).to.be(newObj);
|
124 | rewiredModuleA.__set__("env", "ENVENV");
|
125 | });
|
126 |
|
127 |
|
128 |
|
129 | it("should provide a working __get__ method", function () {
|
130 | var rewiredModuleA = rewire("./moduleA.js");
|
131 |
|
132 | expect(rewiredModuleA.__get__("myNumber")).to.be(rewiredModuleA.getMyNumber());
|
133 | expect(rewiredModuleA.__get__("myObj")).to.be(rewiredModuleA.getMyObj());
|
134 | });
|
135 |
|
136 |
|
137 |
|
138 | it("should provide a working __with__ method", function () {
|
139 | var rewiredModuleA = rewire("./moduleA.js"),
|
140 | newObj = {};
|
141 |
|
142 | expect(rewiredModuleA.getMyNumber()).to.be(0);
|
143 | expect(rewiredModuleA.getMyObj()).to.not.be(newObj);
|
144 |
|
145 | rewiredModuleA.__with__({
|
146 | myNumber: 2,
|
147 | myObj: newObj
|
148 | })(function () {
|
149 | expect(rewiredModuleA.getMyNumber()).to.be(2);
|
150 | expect(rewiredModuleA.getMyObj()).to.be(newObj);
|
151 | });
|
152 |
|
153 | expect(rewiredModuleA.getMyNumber()).to.be(0);
|
154 | expect(rewiredModuleA.getMyObj()).to.not.be(newObj);
|
155 | });
|
156 |
|
157 | it("should provide the ability to inject mocks", function (done) {
|
158 | var rewiredModuleA = rewire("./moduleA.js"),
|
159 | mockedFs = {
|
160 | readFileSync: function (file) {
|
161 | expect(file).to.be("bla.txt");
|
162 | done();
|
163 | }
|
164 | };
|
165 |
|
166 | rewiredModuleA.__set__("fs", mockedFs);
|
167 | rewiredModuleA.readFileSync();
|
168 | });
|
169 |
|
170 | it("should not influence other modules when injecting mocks", function () {
|
171 | var rewiredModuleA = rewire("./moduleA.js"),
|
172 | someOtherModule,
|
173 | mockedFs = {};
|
174 |
|
175 | rewiredModuleA.__set__("fs", mockedFs);
|
176 | someOtherModule = require("./someOtherModule.js");
|
177 | expect(someOtherModule.fs).not.to.be(mockedFs);
|
178 | });
|
179 |
|
180 | it("should provide the ability to mock global objects just within the module", function () {
|
181 | var rewiredModuleA = rewire("./moduleA.js"),
|
182 | rewiredModuleB = rewire("./moduleB.js"),
|
183 | consoleMock = {},
|
184 | bufferMock = {},
|
185 | documentMock = {},
|
186 | newFilename = "myFile.js";
|
187 |
|
188 | rewiredModuleA.__set__({
|
189 | console: consoleMock,
|
190 | __filename: newFilename
|
191 | });
|
192 | expect(rewiredModuleA.getConsole()).to.be(consoleMock);
|
193 | expect(rewiredModuleB.getConsole()).not.to.be(consoleMock);
|
194 | expect(console).not.to.be(consoleMock);
|
195 | expect(rewiredModuleA.getFilename()).to.be(newFilename);
|
196 | expect(rewiredModuleB.getFilename()).not.to.be(newFilename);
|
197 | expect(console).not.to.be(newFilename);
|
198 | if (typeof window === "undefined") {
|
199 | rewiredModuleA.__set__("Buffer", bufferMock);
|
200 | expect(rewiredModuleA.getBuffer()).to.be(bufferMock);
|
201 | expect(rewiredModuleB.getBuffer()).not.to.be(bufferMock);
|
202 | expect(Buffer).not.to.be(bufferMock);
|
203 | } else {
|
204 | rewiredModuleA.__set__("document", documentMock);
|
205 | expect(rewiredModuleA.getDocument()).to.be(documentMock);
|
206 | expect(rewiredModuleB.getDocument() === documentMock).to.be(false);
|
207 | expect(document === documentMock).to.be(false);
|
208 | }
|
209 | });
|
210 |
|
211 | it("should be possible to mock global objects that are added on runtime", function () {
|
212 | var rewiredModule;
|
213 |
|
214 | if (typeof window === "undefined") {
|
215 | global.someGlobalVar = "test";
|
216 | rewiredModule = rewire("./moduleA.js");
|
217 | rewiredModule.__set__("someGlobalVar", "other value");
|
218 | expect(global.someGlobalVar).to.be("test");
|
219 | expect(rewiredModule.__get__("someGlobalVar")).to.be("other value");
|
220 | delete global.someGlobalVar;
|
221 | } else {
|
222 | window.someGlobalVar = "test";
|
223 | rewiredModule = rewire("./moduleA.js");
|
224 | rewiredModule.__set__("someGlobalVar", "other value");
|
225 | expect(window.someGlobalVar).to.be("test");
|
226 | expect(rewiredModule.__get__("someGlobalVar")).to.be("other value");
|
227 | if (typeof navigator !== "undefined" && /MSIE [6-8]\.[0-9]/g.test(navigator.userAgent) === false) {
|
228 | delete window.someGlobalVar;
|
229 | }
|
230 | }
|
231 | });
|
232 |
|
233 | it("should not be a problem to have a comment on file end", function () {
|
234 | var rewired = rewire("./emptyModule.js");
|
235 |
|
236 | rewired.__set__("someVar", "hello");
|
237 | expect(rewired.__get__("someVar")).to.be("hello");
|
238 | });
|
239 |
|
240 | it("should not be a problem to have a module that exports a boolean", function( ) {
|
241 | rewire("./boolean.js");
|
242 | });
|
243 |
|
244 | it("should not be a problem to have a module that exports null", function () {
|
245 | rewire("./null.js");
|
246 | });
|
247 |
|
248 | it("should not be a problem to have a module that exports a sealed object", function () {
|
249 | rewire("./sealedObject.js");
|
250 | });
|
251 |
|
252 | (supportsObjectSpread ? it : it.skip)("should not be a problem to have a module that uses object spread operator", function () {
|
253 | rewire("./objectSpreadOperator.js");
|
254 | });
|
255 |
|
256 | (supportsObjectRest ? it : it.skip)("should not be a problem to have a module that uses object rest operator", function () {
|
257 | rewire("./objectRestOperator.js");
|
258 | });
|
259 |
|
260 | it("should not influence the original require if nothing has been required within the rewired module", function () {
|
261 | rewire("./emptyModule.js");
|
262 | expect(require("./moduleA.js").__set__).to.be(undefined);
|
263 | });
|
264 |
|
265 | it("subsequent calls of rewire should always return a new instance", function () {
|
266 | expect(rewire("./moduleA.js")).not.to.be(rewire("./moduleA.js"));
|
267 | });
|
268 |
|
269 | it("should preserve the strict mode", function () {
|
270 | var strictModule = rewire("./strictModule.js");
|
271 |
|
272 | expect(function () {
|
273 | strictModule.doSomethingUnstrict();
|
274 | }).to.throwException(checkForTypeError);
|
275 | });
|
276 |
|
277 | it("should not modify line numbers in stack traces", function () {
|
278 | var throwError = rewire("./throwError.js");
|
279 |
|
280 | try {
|
281 | throwError();
|
282 | } catch (err) {
|
283 | expect(err.stack.split("\n")[1]).to.match(/:6:26/);
|
284 | }
|
285 | });
|
286 |
|
287 | it("should be possible to set implicit globals", function () {
|
288 | var implicitGlobalModule,
|
289 | err;
|
290 |
|
291 | try {
|
292 | implicitGlobalModule = rewire("./implicitGlobal.js");
|
293 |
|
294 | implicitGlobalModule.__set__("implicitGlobal", true);
|
295 | expect(implicitGlobalModule.__get__("implicitGlobal")).to.be(true);
|
296 |
|
297 |
|
298 |
|
299 | } catch (e) {
|
300 | err = e;
|
301 | } finally {
|
302 |
|
303 | delete global.implicitGlobal;
|
304 | delete global.undefinedImplicitGlobal;
|
305 | }
|
306 |
|
307 | if (err) {
|
308 | throw err;
|
309 | }
|
310 | });
|
311 |
|
312 | it("should throw a TypeError if the path is not a string", function () {
|
313 | expect(function () {
|
314 | rewire(null);
|
315 | }).to.throwException(checkForTypeError);
|
316 | });
|
317 |
|
318 | it("should also revert nested changes (with dot notation)", function () {
|
319 | var rewiredModuleA = rewire("./moduleA.js"),
|
320 | revert;
|
321 |
|
322 | revert = rewiredModuleA.__set__("myObj.test", true);
|
323 | expect(rewiredModuleA.getMyObj()).to.eql({
|
324 | test: true
|
325 | });
|
326 | revert();
|
327 |
|
328 |
|
329 |
|
330 |
|
331 |
|
332 | expect(rewiredModuleA.getMyObj()).to.eql({
|
333 | test: undefined
|
334 | });
|
335 |
|
336 | revert = rewiredModuleA.__set__({
|
337 | "myObj.test": true
|
338 | });
|
339 | expect(rewiredModuleA.getMyObj()).to.eql({
|
340 | test: true
|
341 | });
|
342 | revert();
|
343 | expect(rewiredModuleA.getMyObj()).to.eql({
|
344 | test: undefined
|
345 | });
|
346 |
|
347 | });
|
348 |
|
349 | it("should be possible to mock undefined, implicit globals", function () {
|
350 | var implicitGlobalModule,
|
351 | err;
|
352 |
|
353 | try {
|
354 | implicitGlobalModule = rewire("./implicitGlobal.js");
|
355 | implicitGlobalModule.__set__("undefinedImplicitGlobal", "yoo!");
|
356 | expect(implicitGlobalModule.__get__("undefinedImplicitGlobal")).to.equal("yoo!");
|
357 |
|
358 | implicitGlobalModule = rewire("./implicitGlobal.js");
|
359 | implicitGlobalModule.__set__({
|
360 | undefinedImplicitGlobal: "bro!"
|
361 | });
|
362 | expect(implicitGlobalModule.__get__("undefinedImplicitGlobal")).to.equal("bro!");
|
363 | } catch (e) {
|
364 | err = e;
|
365 | } finally {
|
366 |
|
367 | delete global.implicitGlobal;
|
368 | delete global.undefinedImplicitGlobal;
|
369 | }
|
370 |
|
371 | if (err) {
|
372 | throw err;
|
373 | }
|
374 | });
|
375 |
|
376 | it("should be possible to mock and revert JSON.parse (see #40)", function () {
|
377 | var moduleA = rewire("./moduleA.js"),
|
378 | revert;
|
379 |
|
380 | revert = moduleA.__set__({
|
381 | JSON: {
|
382 | parse: function () { return true; }
|
383 | }
|
384 | });
|
385 |
|
386 | revert();
|
387 | });
|
388 |
|
389 | it("should be possible to set a const variable", function () {
|
390 | var constModule = rewire("./constModule");
|
391 | var varNames = Object.keys(constModule);
|
392 |
|
393 | expect(varNames.length).to.be.greaterThan(0);
|
394 |
|
395 | varNames.forEach(varName => {
|
396 | constModule.__set__(varName, "this has been changed");
|
397 | expect(constModule[varName]()).to.equal("this has been changed");
|
398 | });
|
399 | });
|
400 |
|
401 | it("should fail with a helpful TypeError when const is re-assigned", function () {
|
402 | expect(function () {
|
403 | rewire("./wrongConstModule");
|
404 | }).to.throwException(/^Assignment to constant variable at .+?wrongConstModule\.js:4:1$/);
|
405 | });
|
406 |
|
407 | };
|