Skip to content

Commit 8cceb6c

Browse files
committed
Add mock.js
1 parent 1f894b9 commit 8cceb6c

File tree

2 files changed

+346
-322
lines changed

2 files changed

+346
-322
lines changed

test/mock.js

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
2+
import * as fs from 'fs/promises';
3+
import * as node from '../source/node.js';
4+
import * as path from 'path';
5+
import * as url from 'url';
6+
import * as worker_threads from 'worker_threads';
7+
8+
const mock = {};
9+
10+
mock.Context = class {
11+
12+
constructor(host, folder, identifier, stream, entries) {
13+
this._host = host;
14+
this._folder = folder;
15+
this._identifier = identifier;
16+
this._stream = stream;
17+
this._entries = entries;
18+
}
19+
20+
get identifier() {
21+
return this._identifier;
22+
}
23+
24+
get stream() {
25+
return this._stream;
26+
}
27+
28+
get entries() {
29+
return this._entries;
30+
}
31+
32+
async request(file, encoding, base) {
33+
return this._host.request(file, encoding, base === undefined ? this._folder : base);
34+
}
35+
36+
async require(id) {
37+
return this._host.require(id);
38+
}
39+
40+
error(error, fatal) {
41+
this._host.exception(error, fatal);
42+
}
43+
};
44+
45+
class CSSStyleDeclaration {
46+
47+
constructor() {
48+
this._properties = new Map();
49+
}
50+
51+
setProperty(name, value) {
52+
this._properties.set(name, value);
53+
}
54+
55+
removeProperty(name) {
56+
this._properties.delete(name);
57+
}
58+
}
59+
60+
class DOMTokenList {
61+
62+
constructor(element) {
63+
this._element = element;
64+
}
65+
66+
add(...tokens) {
67+
const value = this._element.getAttribute('class') || '';
68+
const set = new Set(value.split(' ').concat(...tokens));
69+
this._element.setAttribute('class', Array.from(set).filter((s) => s).join(' '));
70+
}
71+
72+
contains(token) {
73+
const value = this._element.getAttribute('class');
74+
if (value === null || value.indexOf(token) === -1) {
75+
return false;
76+
}
77+
return value.split(' ').some((s) => s === token);
78+
}
79+
}
80+
81+
class HTMLElement {
82+
83+
constructor() {
84+
this._childNodes = [];
85+
this._attributes = new Map();
86+
this._style = new CSSStyleDeclaration();
87+
}
88+
89+
get style() {
90+
return this._style;
91+
92+
}
93+
94+
get childNodes() {
95+
return this._childNodes;
96+
}
97+
98+
get firstChild() {
99+
return this._childNodes.length > 0 ? this._childNodes[0] : null;
100+
}
101+
102+
get lastChild() {
103+
const index = this._childNodes.length - 1;
104+
if (index >= 0) {
105+
return this._childNodes[index];
106+
}
107+
return null;
108+
}
109+
110+
appendChild(node) {
111+
this._childNodes.push(node);
112+
}
113+
114+
insertBefore(newNode, referenceNode) {
115+
const index = this._childNodes.indexOf(referenceNode);
116+
if (index !== -1) {
117+
this._childNodes.splice(index, 0, newNode);
118+
}
119+
}
120+
121+
removeChild(node) {
122+
const index = this._childNodes.lastIndexOf(node);
123+
if (index !== -1) {
124+
this._childNodes.splice(index, 1);
125+
}
126+
}
127+
128+
setAttribute(name, value) {
129+
this._attributes.set(name, value);
130+
}
131+
132+
hasAttribute(name) {
133+
return this._attributes.has(name);
134+
}
135+
136+
getAttribute(name) {
137+
return this._attributes.has(name) ? this._attributes.get(name) : null;
138+
}
139+
140+
getElementsByClassName(name) {
141+
const elements = [];
142+
for (const node of this._childNodes) {
143+
if (node instanceof HTMLElement) {
144+
elements.push(...node.getElementsByClassName(name));
145+
if (node.classList.contains(name)) {
146+
elements.push(node);
147+
}
148+
}
149+
}
150+
return elements;
151+
}
152+
153+
addEventListener(/* event, callback */) {
154+
}
155+
156+
removeEventListener(/* event, callback */) {
157+
}
158+
159+
get classList() {
160+
this._classList = this._classList || new DOMTokenList(this);
161+
return this._classList;
162+
}
163+
164+
getBBox() {
165+
return { x: 0, y: 0, width: 10, height: 10 };
166+
}
167+
168+
getBoundingClientRect() {
169+
return { left: 0, top: 0, width: 0, height: 0 };
170+
}
171+
172+
scrollTo() {
173+
}
174+
175+
focus() {
176+
}
177+
}
178+
179+
class Document {
180+
181+
constructor() {
182+
this._elements = {};
183+
this._documentElement = new HTMLElement();
184+
this._body = new HTMLElement();
185+
}
186+
187+
get documentElement() {
188+
return this._documentElement;
189+
}
190+
191+
get body() {
192+
return this._body;
193+
}
194+
195+
createElement(/* name */) {
196+
return new HTMLElement();
197+
}
198+
199+
createElementNS(/* namespace, name */) {
200+
return new HTMLElement();
201+
}
202+
203+
createTextNode(/* text */) {
204+
return new HTMLElement();
205+
}
206+
207+
getElementById(id) {
208+
let element = this._elements[id];
209+
if (!element) {
210+
element = new HTMLElement();
211+
this._elements[id] = element;
212+
}
213+
return element;
214+
}
215+
216+
addEventListener(/* event, callback */) {
217+
}
218+
219+
removeEventListener(/* event, callback */) {
220+
}
221+
}
222+
223+
class Window {
224+
225+
constructor() {
226+
this._document = new Document();
227+
}
228+
229+
get document() {
230+
return this._document;
231+
}
232+
233+
addEventListener(/* event, callback */) {
234+
}
235+
236+
removeEventListener(/* event, callback */) {
237+
}
238+
239+
requestAnimationFrame(callback) {
240+
callback();
241+
}
242+
}
243+
244+
mock.Host = class {
245+
246+
constructor(environment) {
247+
this._environment = environment;
248+
this._errors = [];
249+
mock.Host.source = mock.Host.source || this._dirname('..', 'source');
250+
mock.Host.window = mock.Host.window || new Window();
251+
}
252+
253+
async view(/* view */) {
254+
}
255+
256+
async start() {
257+
}
258+
259+
get window() {
260+
return mock.Host.window;
261+
}
262+
263+
get document() {
264+
return this.window.document;
265+
}
266+
267+
get errors() {
268+
return this._errors;
269+
}
270+
271+
get type() {
272+
return 'Test';
273+
}
274+
275+
environment(name) {
276+
return this._environment[name];
277+
}
278+
279+
update() {
280+
}
281+
282+
screen(/* name */) {
283+
}
284+
285+
async require(id) {
286+
const file = path.join(mock.Host.source, `${id}.js`);
287+
return await import(`file://${file}`);
288+
}
289+
290+
worker(id) {
291+
const file = path.join(mock.Host.source, `${id}.js`);
292+
const worker = new worker_threads.Worker(file);
293+
worker.addEventListener = (type, listener) => {
294+
worker.on(type, (message) => listener({ data: message }));
295+
};
296+
return worker;
297+
}
298+
299+
async request(file, encoding, basename) {
300+
const pathname = path.join(basename || mock.Host.source, file);
301+
const exists = await this._access(pathname);
302+
if (!exists) {
303+
throw new Error(`The file '${file}' does not exist.`);
304+
}
305+
const stats = await fs.stat(pathname);
306+
if (stats.isDirectory()) {
307+
throw new Error(`The path '${file}' is a directory.`);
308+
}
309+
if (encoding) {
310+
return await fs.readFile(pathname, encoding);
311+
}
312+
return new node.FileStream(pathname, 0, stats.size, stats.mtimeMs);
313+
}
314+
315+
event(/* name, params */) {
316+
}
317+
318+
exception(error /*, fatal */) {
319+
this._errors.push(error);
320+
}
321+
322+
message() {
323+
}
324+
325+
async _access(path) {
326+
try {
327+
await fs.access(path);
328+
return true;
329+
} catch {
330+
return false;
331+
}
332+
}
333+
334+
_dirname(...args) {
335+
const file = url.fileURLToPath(import.meta.url);
336+
const dir = path.dirname(file);
337+
return path.join(dir, ...args);
338+
}
339+
};
340+
341+
export const Host = mock.Host;
342+
export const Context = mock.Context;

0 commit comments

Comments
 (0)