capybara-simulated 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +225 -0
- data/lib/capybara/simulated/browser.rb +1012 -0
- data/lib/capybara/simulated/driver.rb +191 -0
- data/lib/capybara/simulated/errors.rb +9 -0
- data/lib/capybara/simulated/node.rb +235 -0
- data/lib/capybara/simulated/version.rb +5 -0
- data/lib/capybara/simulated.rb +10 -0
- data/lib/capybara-simulated.rb +1 -0
- data/vendor/esbuild-wasm/LICENSE.md +21 -0
- data/vendor/esbuild-wasm/bin/esbuild +91 -0
- data/vendor/esbuild-wasm/esbuild.wasm +0 -0
- data/vendor/esbuild-wasm/lib/main.js +2337 -0
- data/vendor/esbuild-wasm/wasm_exec.js +575 -0
- data/vendor/esbuild-wasm/wasm_exec_node.js +40 -0
- data/vendor/js/bundle-modules.mjs +168 -0
- data/vendor/js/csim.bundle.js +101015 -0
- data/vendor/js/entry.mjs +8 -0
- data/vendor/js/prelude.js +186 -0
- data/vendor/js/runtime.js +2054 -0
- metadata +106 -0
data/vendor/js/entry.mjs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Bundle entry: brings happy-dom and an XPath engine into one IIFE that
|
|
2
|
+
// exposes them on a single `__csim_bundle` global. happy-dom does not
|
|
3
|
+
// implement document.evaluate, so we layer fontoxpath on top.
|
|
4
|
+
import {Window} from 'happy-dom';
|
|
5
|
+
import {URL, URLSearchParams} from 'whatwg-url';
|
|
6
|
+
import {evaluateXPathToNodes} from 'fontoxpath';
|
|
7
|
+
|
|
8
|
+
export {Window, URL, URLSearchParams, evaluateXPathToNodes};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// Prelude evaluated before the happy-dom bundle. mini_racer's V8 isolate
|
|
2
|
+
// is bare ECMA — every Web Platform API needed by happy-dom must be
|
|
3
|
+
// provided here. The bundle imports its own URL implementation from the
|
|
4
|
+
// `url` shim, so the polyfills below only cover the truly global APIs.
|
|
5
|
+
|
|
6
|
+
(function () {
|
|
7
|
+
// ---- TextEncoder / TextDecoder (UTF-8 only) ---------------------------
|
|
8
|
+
if (typeof globalThis.TextEncoder === 'undefined') {
|
|
9
|
+
globalThis.TextEncoder = class TextEncoder {
|
|
10
|
+
get encoding() { return 'utf-8'; }
|
|
11
|
+
encode(str) {
|
|
12
|
+
const s = String(str || '');
|
|
13
|
+
const bytes = [];
|
|
14
|
+
for (let i = 0; i < s.length; i++) {
|
|
15
|
+
let cp = s.charCodeAt(i);
|
|
16
|
+
if (cp >= 0xd800 && cp <= 0xdbff && i + 1 < s.length) {
|
|
17
|
+
cp = ((cp - 0xd800) << 10) + (s.charCodeAt(++i) - 0xdc00) + 0x10000;
|
|
18
|
+
}
|
|
19
|
+
if (cp < 0x80) bytes.push(cp);
|
|
20
|
+
else if (cp < 0x800) bytes.push(0xc0 | (cp >> 6), 0x80 | (cp & 0x3f));
|
|
21
|
+
else if (cp < 0x10000) bytes.push(0xe0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
|
|
22
|
+
else bytes.push(0xf0 | (cp >> 18), 0x80 | ((cp >> 12) & 0x3f), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
|
|
23
|
+
}
|
|
24
|
+
return new Uint8Array(bytes);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (typeof globalThis.TextDecoder === 'undefined') {
|
|
29
|
+
globalThis.TextDecoder = class TextDecoder {
|
|
30
|
+
constructor(encoding = 'utf-8') { this.encoding = String(encoding).toLowerCase(); }
|
|
31
|
+
decode(buf) {
|
|
32
|
+
if (buf == null) return '';
|
|
33
|
+
const arr = buf instanceof Uint8Array ? buf : new Uint8Array(buf.buffer || buf);
|
|
34
|
+
let out = '';
|
|
35
|
+
let i = 0;
|
|
36
|
+
while (i < arr.length) {
|
|
37
|
+
const b1 = arr[i++];
|
|
38
|
+
if (b1 < 0x80) out += String.fromCharCode(b1);
|
|
39
|
+
else if (b1 < 0xc0) continue;
|
|
40
|
+
else if (b1 < 0xe0) {
|
|
41
|
+
const b2 = arr[i++] & 0x3f;
|
|
42
|
+
out += String.fromCharCode(((b1 & 0x1f) << 6) | b2);
|
|
43
|
+
} else if (b1 < 0xf0) {
|
|
44
|
+
const b2 = arr[i++] & 0x3f;
|
|
45
|
+
const b3 = arr[i++] & 0x3f;
|
|
46
|
+
out += String.fromCharCode(((b1 & 0x0f) << 12) | (b2 << 6) | b3);
|
|
47
|
+
} else {
|
|
48
|
+
const b2 = arr[i++] & 0x3f;
|
|
49
|
+
const b3 = arr[i++] & 0x3f;
|
|
50
|
+
const b4 = arr[i++] & 0x3f;
|
|
51
|
+
let cp = ((b1 & 0x07) << 18) | (b2 << 12) | (b3 << 6) | b4;
|
|
52
|
+
cp -= 0x10000;
|
|
53
|
+
out += String.fromCharCode(0xd800 + (cp >> 10), 0xdc00 + (cp & 0x3ff));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---- atob / btoa ------------------------------------------------------
|
|
62
|
+
const B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
63
|
+
if (typeof globalThis.atob === 'undefined') {
|
|
64
|
+
globalThis.atob = (input) => {
|
|
65
|
+
const str = String(input).replace(/[\t\n\f\r ]+/g, '').replace(/=+$/, '');
|
|
66
|
+
if (str.length % 4 === 1) throw new Error('Invalid base64');
|
|
67
|
+
let out = '', buffer = 0, bits = 0;
|
|
68
|
+
for (const ch of str) {
|
|
69
|
+
const idx = B64.indexOf(ch);
|
|
70
|
+
if (idx === -1) throw new Error('Invalid base64 character');
|
|
71
|
+
buffer = (buffer << 6) | idx;
|
|
72
|
+
bits += 6;
|
|
73
|
+
if (bits >= 8) { bits -= 8; out += String.fromCharCode((buffer >> bits) & 0xff); }
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (typeof globalThis.btoa === 'undefined') {
|
|
79
|
+
globalThis.btoa = (input) => {
|
|
80
|
+
const str = String(input);
|
|
81
|
+
let out = '', buffer = 0, bits = 0;
|
|
82
|
+
for (let i = 0; i < str.length; i++) {
|
|
83
|
+
const code = str.charCodeAt(i);
|
|
84
|
+
if (code > 0xff) throw new Error('btoa: non-Latin1 character');
|
|
85
|
+
buffer = (buffer << 8) | code;
|
|
86
|
+
bits += 8;
|
|
87
|
+
while (bits >= 6) { bits -= 6; out += B64[(buffer >> bits) & 0x3f]; }
|
|
88
|
+
}
|
|
89
|
+
if (bits > 0) out += B64[(buffer << (6 - bits)) & 0x3f];
|
|
90
|
+
while (out.length % 4) out += '=';
|
|
91
|
+
return out;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ---- crypto (subset) --------------------------------------------------
|
|
96
|
+
if (typeof globalThis.crypto === 'undefined') {
|
|
97
|
+
globalThis.crypto = {
|
|
98
|
+
getRandomValues(arr) {
|
|
99
|
+
for (let i = 0; i < arr.length; i++) arr[i] = (Math.random() * 0x100000000) >>> 0;
|
|
100
|
+
return arr;
|
|
101
|
+
},
|
|
102
|
+
randomUUID() {
|
|
103
|
+
const r = (n) => Math.floor(Math.random() * (1 << n)).toString(16).padStart(n / 4, '0');
|
|
104
|
+
return `${r(32)}-${r(16)}-${r(16)}-${r(16)}-${r(48)}`;
|
|
105
|
+
},
|
|
106
|
+
subtle: {}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ---- timers (no real event loop) -------------------------------------
|
|
111
|
+
const _timers = new Map();
|
|
112
|
+
let _nextTimer = 0;
|
|
113
|
+
let _virtualClock = 0;
|
|
114
|
+
|
|
115
|
+
globalThis.setTimeout = (fn, ms, ...args) => {
|
|
116
|
+
const id = ++_nextTimer;
|
|
117
|
+
const delay = Math.max(0, Number(ms) || 0);
|
|
118
|
+
_timers.set(id, {fn: () => fn.apply(null, args), at: _virtualClock + delay});
|
|
119
|
+
return id;
|
|
120
|
+
};
|
|
121
|
+
globalThis.clearTimeout = (id) => _timers.delete(id);
|
|
122
|
+
globalThis.setInterval = globalThis.setTimeout;
|
|
123
|
+
globalThis.clearInterval = globalThis.clearTimeout;
|
|
124
|
+
globalThis.setImmediate = (fn, ...args) => globalThis.setTimeout(fn, 0, ...args);
|
|
125
|
+
globalThis.clearImmediate = globalThis.clearTimeout;
|
|
126
|
+
globalThis.queueMicrotask = globalThis.queueMicrotask || ((fn) => Promise.resolve().then(fn));
|
|
127
|
+
|
|
128
|
+
// Advance the virtual clock by `ms` and run any timer whose deadline has
|
|
129
|
+
// passed. Iteratively flushes nested setTimeout(0) chains so a callback
|
|
130
|
+
// that schedules another runs in the same tick.
|
|
131
|
+
globalThis.__csim_runTimers = function (ms) {
|
|
132
|
+
const advance = (typeof ms === 'number') ? Math.max(0, ms) : Infinity;
|
|
133
|
+
_virtualClock += advance;
|
|
134
|
+
while (true) {
|
|
135
|
+
let fired = false;
|
|
136
|
+
const due = [];
|
|
137
|
+
for (const [id, t] of _timers) if (t.at <= _virtualClock) due.push([id, t]);
|
|
138
|
+
due.sort((a, b) => a[1].at - b[1].at);
|
|
139
|
+
for (const [id, t] of due) {
|
|
140
|
+
if (!_timers.has(id)) continue;
|
|
141
|
+
_timers.delete(id);
|
|
142
|
+
try { t.fn(); } catch (_) {}
|
|
143
|
+
fired = true;
|
|
144
|
+
}
|
|
145
|
+
if (!fired) break;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
globalThis.__csim_clearTimers = function () {
|
|
149
|
+
_timers.clear();
|
|
150
|
+
_virtualClock = 0;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
globalThis.navigator = globalThis.navigator || {userAgent: 'Mozilla/5.0 capybara-simulated'};
|
|
154
|
+
|
|
155
|
+
if (typeof globalThis.performance === 'undefined') {
|
|
156
|
+
globalThis.performance = {
|
|
157
|
+
now: () => Date.now(),
|
|
158
|
+
timeOrigin: Date.now(),
|
|
159
|
+
mark() {}, measure() {}, clearMarks() {}, clearMeasures() {},
|
|
160
|
+
getEntries: () => [], getEntriesByName: () => [], getEntriesByType: () => []
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
if (typeof globalThis.location === 'undefined') {
|
|
164
|
+
globalThis.location = {
|
|
165
|
+
href: 'http://www.example.com/', origin: 'http://www.example.com',
|
|
166
|
+
protocol: 'http:', host: 'www.example.com', hostname: 'www.example.com',
|
|
167
|
+
port: '', pathname: '/', search: '', hash: '',
|
|
168
|
+
assign() {}, replace() {}, reload() {}, toString() { return this.href; }
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// happy-dom and many polyfills assume `process` exists.
|
|
173
|
+
if (typeof globalThis.process === 'undefined') {
|
|
174
|
+
globalThis.process = {
|
|
175
|
+
env: {NODE_ENV: 'production'},
|
|
176
|
+
platform: 'browser',
|
|
177
|
+
version: 'v20.0.0',
|
|
178
|
+
versions: {node: '20.0.0'},
|
|
179
|
+
nextTick: (cb, ...args) => Promise.resolve().then(() => cb(...args)),
|
|
180
|
+
cwd: () => '/',
|
|
181
|
+
argv: []
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (typeof globalThis.global === 'undefined') globalThis.global = globalThis;
|
|
186
|
+
})();
|