UNPKG

5.43 kBJavaScriptView Raw
1require('@lwc/synthetic-shadow/dist/synthetic-shadow.js');
2
3// Provides temporary backward compatibility for wire-protocol reform: lwc > 1.5.0
4global.wireAdaptersRegistryHack = new Map();
5let originalRegisterDecorators;
6
7function isValidWireAdapter(adapter) {
8 let isValid = false;
9 if (typeof adapter === 'function') {
10 // lets check, if it is a valid adapter
11 try {
12 const adapterInstance = new adapter(() => {});
13 isValid =
14 typeof adapterInstance.connect === 'function' &&
15 typeof adapterInstance.update === 'function' &&
16 typeof adapterInstance.disconnect === 'function';
17 } catch (e) {
18 isValid = false;
19 }
20 }
21
22 return isValid;
23}
24
25/**
26 * Returns a wire adapter mock in the shape of:
27 *
28 * fn : Used when adapter is invoked imperatively. It proxies to the original adapter function, if is callable.
29 * fn.adapter : A valid wire adapter class, consumable by @lwc/engine.
30 * If the @originalAdapter.adapter or @originalAdapter is a valid wire adapter class, fn.adapter will
31 * act as a proxy on it until a spy is attached.
32 *
33 * @param originalAdapter
34 * @returns {function(...[*]): *}
35 */
36function createWireAdapterMockClass(originalAdapter) {
37 const noopAdapter = {
38 connect() {},
39 update() {},
40 disconnect() {},
41 };
42 let baseAdapter;
43 let baseAdapterFn = () => {};
44 const spies = [];
45
46 if (Object.prototype.hasOwnProperty.call(originalAdapter, 'adapter')) {
47 // Is more likely that the originalAdapter was registered with the wire service
48 // .adapter is the one that the engine will use, lets make it our base adapter
49 baseAdapter = originalAdapter.adapter;
50 } else if (isValidWireAdapter(originalAdapter)) {
51 // it may be the case that original adapter is a valid one, if is the case, lets use it as our base adapter
52 baseAdapter = originalAdapter;
53 }
54
55 if (typeof originalAdapter === 'function') {
56 // Mostly used in apex methods
57 baseAdapterFn = originalAdapter;
58 }
59
60 // Support for adapters to be called imperatively, mainly for apex.
61 const newAdapterMock = function (...args) {
62 return baseAdapterFn.call(this, ...args);
63 };
64
65 newAdapterMock.adapter = class WireAdapterMock {
66 constructor(dataCallback) {
67 // if a test is spying these adapter, it means is overriding the implementation
68 this._originalAdapter =
69 spies.length === 0 && baseAdapter ? new baseAdapter(dataCallback) : noopAdapter;
70 this._dataCallback = dataCallback;
71
72 spies.forEach((spy) => spy.createInstance(this));
73 }
74 connect() {
75 spies.forEach((spy) => spy.connect(this));
76 this._originalAdapter.connect();
77 }
78 update(config) {
79 spies.forEach((spy) => spy.update(this, config));
80 this._originalAdapter.update(config);
81 }
82 disconnect() {
83 spies.forEach((spy) => spy.disconnect(this));
84 this._originalAdapter.disconnect();
85 }
86 emit(value) {
87 this._dataCallback(value);
88 }
89 static spyAdapter(spy) {
90 // this function is meant to be used by wire-service-jest-util library.
91 // When this is used, register* was called, thus replacing the wire behaviour.
92 // As consequence, it will stop calling the originalAdapter on new instances.
93 spies.push(spy);
94 }
95 };
96
97 return newAdapterMock;
98}
99
100function overriddenRegisterDecorators(Ctor, decoratorsMeta) {
101 const wire = decoratorsMeta.wire || {};
102
103 Object.keys(wire).forEach((adapterName) => {
104 const adapter = wire[adapterName].adapter;
105 let wireAdapterMock = global.wireAdaptersRegistryHack.get(adapter);
106
107 if (!wireAdapterMock) {
108 // Checking if the adapter is extensible, since with the wire reform,
109 // the adapterId must be:
110 // a) An extensible object (so backward compatibility is provided via register)
111 // b) A valid class.
112
113 if (!Object.isExtensible(adapter)) {
114 // if we are in case of a) lets throw now so the developer knows that they need to migrate their
115 // adapters.
116 throw new TypeError('Invalid adapterId, it must be extensible.');
117 }
118
119 // Lets create a whole replacement for this adapter.
120 wireAdapterMock = createWireAdapterMockClass(adapter);
121
122 global.wireAdaptersRegistryHack.set(adapter, wireAdapterMock);
123 }
124
125 // we are entirely replacing the wire adapter with one that can be spied on.
126 wire[adapterName].adapter = wireAdapterMock;
127 });
128
129 return originalRegisterDecorators(Ctor, decoratorsMeta);
130}
131
132function installRegisterDecoratorsTrap(lwc) {
133 const originalDescriptor = Object.getOwnPropertyDescriptor(lwc, 'registerDecorators');
134
135 if (originalDescriptor.value === overriddenRegisterDecorators) {
136 return;
137 }
138
139 originalRegisterDecorators = originalDescriptor.value;
140
141 const newDescriptor = {
142 ...originalDescriptor,
143 value: overriddenRegisterDecorators,
144 };
145
146 Object.defineProperty(lwc, 'registerDecorators', newDescriptor);
147}
148
149const lwc = require('@lwc/engine');
150
151installRegisterDecoratorsTrap(lwc);