-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathtest-setup.ts
121 lines (113 loc) · 3.36 KB
/
test-setup.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// @ts-nocheck
import 'regenerator-runtime/runtime';
import mitt from 'mitt';
import * as util from 'util';
import { TextDecoder } from 'util';
import CacheMock from 'browser-cache-mock';
import 'isomorphic-fetch';
import { Buffer } from './node_modules/buffer/index.js';
globalThis.Buffer = Buffer;
// mock the global fetch API
window.fetchPreHandler = (url, options) => {};
window.fetchResponseFactory = (url, options) => '<empty></empty>';
window.originalFetch = window.fetch;
window.mockFetch = jest.fn().mockImplementation(async (url, options) => {
const preResult = await window.fetchPreHandler(url, options);
if (preResult) return preResult;
return {
text: () => Promise.resolve(globalThis.fetchResponseFactory(url, options)),
json: () =>
Promise.resolve(
JSON.parse(globalThis.fetchResponseFactory(url, options))
),
arrayBuffer: () =>
Promise.resolve(
Buffer.from(globalThis.fetchResponseFactory(url, options), 'utf-8')
),
clone: function () {
return this;
},
status: 200,
ok: true,
headers: { get: () => null },
};
});
window.fetch = window.mockFetch;
// reset fetch response to XML by default
beforeEach(() => {
window.fetchResponseFactory = (url) => '<empty></empty>';
});
window.caches = {
open: async () => new CacheMock(),
};
// mock Worker class to work synchronously
// requires an absolute file path
// this is mainly ripped off of https://github.com/developit/jsdom-worker
global.Worker = function Worker(filePath) {
let getScopeVar;
let messageQueue = [];
const inside = mitt();
const outside = mitt();
const scope = {
onmessage: null,
dispatchEvent: inside.emit,
addEventListener: inside.on,
removeEventListener: inside.off,
postMessage(data) {
outside.emit('message', { data });
},
fetch: global.fetch,
importScripts() {},
};
inside.on('message', (e) => {
const f = scope.onmessage || getScopeVar('onmessage');
if (f) f.call(scope, e);
});
this.addEventListener = outside.on;
this.removeEventListener = outside.off;
this.dispatchEvent = outside.emit;
outside.on('message', (e) => {
if (this.onmessage) this.onmessage(e);
});
this.postMessage = (data) => {
if (messageQueue != null) messageQueue.push(data);
else inside.emit('message', { data });
};
this.terminate = () => {
throw Error('Not Supported');
};
// bundle the worker code and create a function from it
import('esbuild')
.then((esbuild) =>
esbuild.build({
entryPoints: [filePath],
bundle: true,
write: false,
})
)
.then((result) => {
const code = new util.TextDecoder('utf-8').decode(
result.outputFiles[0].contents
);
let vars = 'var self=this,global=self,globalThis=self';
for (const k in scope) vars += `,${k}=self.${k}`;
getScopeVar = Function(
vars +
';\n' +
code +
'\nreturn function(n){return n=="onmessage"?onmessage:null;}'
).call(scope);
const q = messageQueue;
messageQueue = null;
q.forEach(this.postMessage);
})
.catch((e) => {
outside.emit('error', e);
console.error(e);
});
// mock global scope
global.WorkerGlobalScope = scope;
};
// global.TextDecoder = StringDecoder
// global.TextDecoder.prototype.decode = StringDecoder.prototype.write
global.TextDecoder = TextDecoder;