The library for web and native user interfaces.
Enable module.exports mocking in react-test.js.
We don't currently attempt to mock modules automatically, but we do respect require("mock-modules").mock, .dontMock, and .dumpCache. I'm going to keep investigating auto-mocking, since that would move us much closer to the behavior used within Facebook. Closes #154. Closes #155.
Ben Newman committed
Jul 3, 2013 at 12:22 UTC
204796868d377acbcbbb1e2de4698b8827dc6b83
1 file changed
+82
-9
src/test/mock-modules.js
+82
-9
@@ -16,22 +16,95 @@
16
* @providesModule mock-modules
17
*/
18
19
+var mocks = require("mocks");
20
+var exportsRegistry = {};
21
+var hasOwn = exportsRegistry.hasOwnProperty;
22
+var explicitMockMap = {};
23
+
24
+function getMock(exports) {
25
+ try {
26
+ return mocks.generateFromMetadata(mocks.getMetadata(exports));
27
+ } catch (err) {
28
+ console.warn(err);
29
+ return exports;
30
+ }
31
+}
32
+
33
+// This function should be called at the bottom of any module that might
34
+// need to be mocked, after the final value of module.exports is known.
35
exports.register = function(id, module) {
20
- // TODO
36
+ exportsRegistry[id] = {
37
+ module: module,
38
+ actual: module.exports,
39
+ mocked: null // Filled in lazily later.
40
+ };
41
+
42
+ // If doMock or doNotMock was called earlier, before the module was
43
+ // registered, then the choice should have been recorded in
44
+ // explicitMockMap. Now that the module is registered, we can finally
45
+ // fulfill the request.
46
+ if (hasOwn.call(explicitMockMap, id)) {
47
+ if (explicitMockMap[id]) {
48
+ doMock(id);
49
+ } else {
50
+ doNotMock(id);
51
+ }
52
+ }
53
+
54
+ return exports;
55
};
56
57
+function resetEntry(id) {
58
+ if (hasOwn.call(exportsRegistry, id)) {
59
+ delete exportsRegistry[id].module.exports;
60
+ delete exportsRegistry[id];
61
+ }
62
+}
63
+
64
exports.dumpCache = function() {
24
- require("mocks").clear();
25
- return exports;
26
-};
65
+ require("mocks").clear();
66
28
-exports.dontMock = function() {
29
- return exports;
30
-};
67
+ // Deleting module.exports will cause the module to be lazily
68
+ // reevaluated the next time it is required.
69
+ for (var id in exportsRegistry) {
70
+ resetEntry(id);
71
+ }
72
32
-exports.mock = function() {
33
- return exports;
73
+ return exports;
74
};
75
76
+// Call this function to ensure that require(id) returns the actual
77
+// exports object created by the module.
78
+function doNotMock(id) {
79
+ explicitMockMap[id] = false;
80
+
81
+ var entry = exportsRegistry[id];
82
+ if (entry && entry.module && entry.actual) {
83
+ entry.module.exports = entry.actual;
84
+ }
85
+
86
+ return exports;
87
+}
88
+
89
+// Call this function to ensure that require(id) returns a mock exports
90
+// object based on the actual exports object created by the module.
91
+function doMock(id) {
92
+ explicitMockMap[id] = true;
93
+
94
+ var entry = exportsRegistry[id];
95
+ if (entry && entry.module && entry.actual) {
96
+ // Because mocking can be expensive, create the mock exports object on
97
+ // demand, the first time doMock is called.
98
+ entry.mocked || (entry.mocked = getMock(entry.actual));
99
+ entry.module.exports = entry.mocked;
100
+ }
101
+
102
+ return exports;
103
+}
104
+
105
var global = Function("return this")();
106
require('test/mock-timers').installMockTimers(global);
107
+
108
+// Exported names are different for backwards compatibility.
109
+exports.dontMock = doNotMock;
110
+exports.mock = doMock;