qunitx 0.5.3 → 0.6.0
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.
- package/lib/commands/run/tests-in-browser.js +2 -2
- package/lib/commands/run.js +1 -1
- package/lib/servers/http.js +229 -0
- package/lib/setup/bind-server-to-port.js +1 -1
- package/lib/setup/browser.js +2 -4
- package/lib/setup/web-server.js +49 -57
- package/lib/utils/parse-cli-flags.js +0 -2
- package/lib/utils/run-user-module.js +1 -1
- package/lol.ts +18 -0
- package/package.json +3 -4
- package/test-output.log +21 -1014
|
@@ -122,8 +122,8 @@ async function runTestInsideHTMLFile(filePath, { page, server }, config) {
|
|
|
122
122
|
let targetError;
|
|
123
123
|
try {
|
|
124
124
|
await wait(350);
|
|
125
|
-
console.log('#', kleur.blue(`QUnitX running: http://localhost:${
|
|
126
|
-
await page.goto(`http://localhost:${
|
|
125
|
+
console.log('#', kleur.blue(`QUnitX running: http://localhost:${config.port}${filePath}`));
|
|
126
|
+
await page.goto(`http://localhost:${config.port}${filePath}`, { timeout: 0 });
|
|
127
127
|
await page.evaluate(() => {
|
|
128
128
|
window.IS_PUPPETEER = true;
|
|
129
129
|
});
|
package/lib/commands/run.js
CHANGED
|
@@ -142,7 +142,7 @@ async function addCachedContentMainHTML(projectRoot, cachedContent) {
|
|
|
142
142
|
|
|
143
143
|
function logWatcherAndKeyboardShortcutInfo(config, server) {
|
|
144
144
|
if (config.browser) {
|
|
145
|
-
console.log('#', kleur.blue(`Watching files... You can browse the tests on http://localhost:${
|
|
145
|
+
console.log('#', kleur.blue(`Watching files... You can browse the tests on http://localhost:${config.port} ...`)); // NOTE: maybe add also qx to exit
|
|
146
146
|
console.log('#', kleur.blue(`Shortcuts: Press "qq" to abort running tests, "qa" to run all the tests, "qf" to run last failing test, "ql" to repeat last test`)); // NOTE: maybe add also qx to test specific
|
|
147
147
|
} else {
|
|
148
148
|
console.log('#', kleur.blue(`Watching files...`));
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import WebSocket, { WebSocketServer } from 'ws';
|
|
3
|
+
import bindServerToPort from '../setup/bind-server-to-port.js';
|
|
4
|
+
|
|
5
|
+
export const MIME_TYPES = {
|
|
6
|
+
html: "text/html; charset=UTF-8",
|
|
7
|
+
js: "application/javascript",
|
|
8
|
+
css: "text/css",
|
|
9
|
+
png: "image/png",
|
|
10
|
+
jpg: "image/jpg",
|
|
11
|
+
gif: "image/gif",
|
|
12
|
+
ico: "image/x-icon",
|
|
13
|
+
svg: "image/svg+xml",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default class HTTPServer {
|
|
17
|
+
static serve(config = { port: 1234 }, handler) {
|
|
18
|
+
let onListen = config.onListen || ((server) => {});
|
|
19
|
+
let onError = config.onError || ((error) => {});
|
|
20
|
+
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
let server = http.createServer((req, res) => {
|
|
23
|
+
return handler(req, res);
|
|
24
|
+
});
|
|
25
|
+
server = server;
|
|
26
|
+
server.on('error', (error) => {
|
|
27
|
+
onError(error);
|
|
28
|
+
reject(error);
|
|
29
|
+
}).once('listening', () => {
|
|
30
|
+
onListen(Object.assign({ hostname: '127.0.0.1', server }, config));
|
|
31
|
+
resolve(server);
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
server.wss = new WebSocketServer({ server });
|
|
35
|
+
server.wss.on('error', (error) => {
|
|
36
|
+
console.log('# [WebSocketServer] Error:');
|
|
37
|
+
console.trace(error);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
bindServerToPort(server, config)
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
constructor() {
|
|
45
|
+
this.routes = {
|
|
46
|
+
GET: {},
|
|
47
|
+
POST: {},
|
|
48
|
+
DELETE: {},
|
|
49
|
+
PUT: {}
|
|
50
|
+
};
|
|
51
|
+
this.middleware = [];
|
|
52
|
+
this._server = http.createServer((req, res) => {
|
|
53
|
+
res.send = (data) => {
|
|
54
|
+
res.setHeader('Content-Type', 'text/plain');
|
|
55
|
+
res.end(data);
|
|
56
|
+
};
|
|
57
|
+
res.json = (data) => {
|
|
58
|
+
res.setHeader('Content-Type', 'application/json');
|
|
59
|
+
res.end(JSON.stringify(data));
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return this.handleRequest(req, res);
|
|
63
|
+
});
|
|
64
|
+
this.wss = new WebSocketServer({ server: this._server });
|
|
65
|
+
this.wss.on('error', (error) => {
|
|
66
|
+
console.log('### WebSocketServer Error:');
|
|
67
|
+
console.log(error);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get(path, handler) {
|
|
72
|
+
this.registerRouteHandler('GET', path, handler);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
listen(port = 0, callback = () => {}) {
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
this._server.listen(port, (error) => {
|
|
78
|
+
if (error) {
|
|
79
|
+
reject(error);
|
|
80
|
+
} else {
|
|
81
|
+
resolve(callback());
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
publish(data) {
|
|
88
|
+
this.wss.clients.forEach((client) => {
|
|
89
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
90
|
+
client.send(data);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
post(path, handler) {
|
|
96
|
+
this.registerRouteHandler('POST', path, handler);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
delete(path, handler) {
|
|
100
|
+
this.registerRouteHandler('DELETE', path, handler);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
put(path, handler) {
|
|
104
|
+
this.registerRouteHandler('PUT', path, handler);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
use(middleware) {
|
|
108
|
+
this.middleware.push(middleware);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
registerRouteHandler(method, path, handler) {
|
|
112
|
+
if (!this.routes[method]) {
|
|
113
|
+
this.routes[method] = {};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.routes[method][path] = {
|
|
117
|
+
path,
|
|
118
|
+
handler,
|
|
119
|
+
paramNames: this.extractParamNames(path),
|
|
120
|
+
isWildcard: path === '/*'
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
handleRequest(req, res) {
|
|
125
|
+
const { method, url } = req;
|
|
126
|
+
const matchingRoute = this.findRouteHandler(method, url);
|
|
127
|
+
|
|
128
|
+
if (matchingRoute) {
|
|
129
|
+
req.params = this.extractParams(matchingRoute, url);
|
|
130
|
+
this.runMiddleware(req, res, matchingRoute.handler);
|
|
131
|
+
} else {
|
|
132
|
+
res.statusCode = 404;
|
|
133
|
+
res.setHeader('Content-Type', 'text/plain');
|
|
134
|
+
res.end('Not found');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
runMiddleware(req, res, callback) {
|
|
139
|
+
let index = 0;
|
|
140
|
+
const next = () => {
|
|
141
|
+
if (index >= this.middleware.length) {
|
|
142
|
+
callback(req, res);
|
|
143
|
+
} else {
|
|
144
|
+
const middleware = this.middleware[index];
|
|
145
|
+
index++;
|
|
146
|
+
middleware(req, res, next);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
next();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
findRouteHandler(method, url) {
|
|
153
|
+
const routes = this.routes[method];
|
|
154
|
+
if (!routes) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return routes[url] || Object.values(routes).find(route => {
|
|
159
|
+
const { path, isWildcard } = route;
|
|
160
|
+
|
|
161
|
+
if (!isWildcard && !path.includes(':')) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (isWildcard || this.matchPathSegments(path, url)) {
|
|
166
|
+
if (route.paramNames.length > 0) {
|
|
167
|
+
const regexPattern = this.buildRegexPattern(path, route.paramNames);
|
|
168
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
169
|
+
const regexMatches = regex.exec(url);
|
|
170
|
+
if (regexMatches) {
|
|
171
|
+
route.paramValues = regexMatches.slice(1);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return false;
|
|
178
|
+
}) || routes['/*'] || null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
matchPathSegments(path, url) {
|
|
182
|
+
const pathSegments = path.split('/');
|
|
183
|
+
const urlSegments = url.split('/');
|
|
184
|
+
|
|
185
|
+
if (pathSegments.length !== urlSegments.length) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
for (let i = 0; i < pathSegments.length; i++) {
|
|
190
|
+
const pathSegment = pathSegments[i];
|
|
191
|
+
const urlSegment = urlSegments[i];
|
|
192
|
+
|
|
193
|
+
if (pathSegment.startsWith(':')) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (pathSegment !== urlSegment) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
buildRegexPattern(path, paramNames) {
|
|
206
|
+
let regexPattern = path.replace(/:[^/]+/g, '([^/]+)');
|
|
207
|
+
regexPattern = regexPattern.replace(/\//g, '\\/');
|
|
208
|
+
|
|
209
|
+
return regexPattern;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
extractParamNames(path) {
|
|
213
|
+
const paramRegex = /:(\w+)/g;
|
|
214
|
+
const paramMatches = path.match(paramRegex);
|
|
215
|
+
|
|
216
|
+
return paramMatches ? paramMatches.map(match => match.slice(1)) : [];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
extractParams(route, url) {
|
|
220
|
+
const { paramNames, paramValues } = route;
|
|
221
|
+
const params = {};
|
|
222
|
+
|
|
223
|
+
for (let i = 0; i < paramNames.length; i++) {
|
|
224
|
+
params[paramNames[i]] = paramValues[i];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return params;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import resolvePortNumberFor from '../utils/resolve-port-number-for.js';
|
|
2
2
|
|
|
3
3
|
// NOTE: there was a race condition between socket.connection and server.listen, check if nanoexpress fixes it
|
|
4
|
-
export default async function bindServerToPort(
|
|
4
|
+
export default async function bindServerToPort(server, config) {
|
|
5
5
|
try {
|
|
6
6
|
let port = await resolvePortNumberFor(config.port);
|
|
7
7
|
|
package/lib/setup/browser.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import kleur from 'kleur';
|
|
3
1
|
import Puppeteer from 'puppeteer';
|
|
4
2
|
import setupWebServer from './web-server.js';
|
|
5
3
|
import bindServerToPort from './bind-server-to-port.js';
|
|
@@ -16,9 +14,9 @@ export default async function setupBrowser(config = {
|
|
|
16
14
|
headless: 'new',
|
|
17
15
|
}),
|
|
18
16
|
]);
|
|
19
|
-
let [page,
|
|
17
|
+
let [page, _] = await Promise.all([
|
|
20
18
|
browser.newPage(),
|
|
21
|
-
bindServerToPort(
|
|
19
|
+
bindServerToPort(server, config)
|
|
22
20
|
]);
|
|
23
21
|
|
|
24
22
|
page.on('console', async (msg) => {
|
package/lib/setup/web-server.js
CHANGED
|
@@ -1,37 +1,21 @@
|
|
|
1
|
-
import fs from 'node:fs
|
|
1
|
+
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import kleur from 'kleur';
|
|
4
|
-
import express from 'nanoexpress';
|
|
5
|
-
import staticServe from '@nanoexpress/middleware-static-serve';
|
|
6
3
|
import findInternalAssetsFromHTML from '../utils/find-internal-assets-from-html.js';
|
|
7
4
|
import TAPDisplayTestResult from '../tap/display-test-result.js';
|
|
5
|
+
import pathExists from '../utils/path-exists.js';
|
|
6
|
+
import HTTPServer, { MIME_TYPES } from '../servers/http.js';
|
|
7
|
+
|
|
8
|
+
const fsPromise = fs.promises;
|
|
8
9
|
|
|
9
10
|
export default async function setupWebServer(config = {
|
|
10
11
|
port: 1234, debug: false, watch: false, timeout: 10000
|
|
11
12
|
}, cachedContent) {
|
|
12
|
-
let
|
|
13
|
-
|
|
14
|
-
[type]: (...messages) => {
|
|
15
|
-
console.log(`# HTTPServer[${type}] :`, ...messages);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
}, {});
|
|
19
|
-
ServerConsole.debug = (...messages) => {
|
|
20
|
-
if (config.debug) {
|
|
21
|
-
console.log('#', kleur.blue(`HTTPServer`), ...messages);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
13
|
+
let STATIC_FILES_PATH = path.join(config.projectRoot, config.output);
|
|
14
|
+
let server = new HTTPServer();
|
|
24
15
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
app.ws('/', {
|
|
29
|
-
open(ws) {
|
|
30
|
-
ws.subscribe('refresh');
|
|
31
|
-
ws.subscribe('abort');
|
|
32
|
-
},
|
|
33
|
-
message(ws, message) {
|
|
34
|
-
const { event, details, abort } = JSON.parse(Decoder.decode(message));
|
|
16
|
+
server.wss.on('connection', function connection(socket) {
|
|
17
|
+
socket.on('message', function message(data) {
|
|
18
|
+
const { event, details, abort } = JSON.parse(data);
|
|
35
19
|
|
|
36
20
|
if (event === "connection") {
|
|
37
21
|
console.log('TAP version 13');
|
|
@@ -42,67 +26,75 @@ export default async function setupWebServer(config = {
|
|
|
42
26
|
|
|
43
27
|
TAPDisplayTestResult(config.COUNTER, details)
|
|
44
28
|
}
|
|
45
|
-
}
|
|
29
|
+
});
|
|
46
30
|
});
|
|
47
31
|
|
|
48
|
-
|
|
49
|
-
let TEST_RUNTIME_TO_INJECT = testRuntimeToInject(
|
|
32
|
+
server.get('/', async (req, res) => {
|
|
33
|
+
let TEST_RUNTIME_TO_INJECT = testRuntimeToInject(config.port, config);
|
|
50
34
|
let htmlContent = escapeAndInjectTestsToHTML(
|
|
51
35
|
replaceAssetPaths(cachedContent.mainHTML.html, cachedContent.mainHTML.filePath, config.projectRoot),
|
|
52
36
|
TEST_RUNTIME_TO_INJECT,
|
|
53
37
|
cachedContent.allTestCode
|
|
54
38
|
);
|
|
55
39
|
|
|
56
|
-
res.
|
|
40
|
+
res.write(htmlContent);
|
|
41
|
+
res.end();
|
|
57
42
|
|
|
58
|
-
return await
|
|
43
|
+
return await fsPromise.writeFile(`${config.projectRoot}/${config.output}/index.html`, htmlContent);
|
|
59
44
|
});
|
|
60
45
|
|
|
61
|
-
|
|
62
|
-
let TEST_RUNTIME_TO_INJECT = testRuntimeToInject(
|
|
46
|
+
server.get('/qunitx.html', async (req, res) => {
|
|
47
|
+
let TEST_RUNTIME_TO_INJECT = testRuntimeToInject(config.port, config);
|
|
63
48
|
let htmlContent = escapeAndInjectTestsToHTML(
|
|
64
49
|
replaceAssetPaths(cachedContent.mainHTML.html, cachedContent.mainHTML.filePath, config.projectRoot),
|
|
65
50
|
TEST_RUNTIME_TO_INJECT,
|
|
66
51
|
cachedContent.filteredTestCode
|
|
67
52
|
);
|
|
68
53
|
|
|
69
|
-
res.
|
|
54
|
+
res.write(htmlContent);
|
|
55
|
+
res.end();
|
|
70
56
|
|
|
71
|
-
return await
|
|
57
|
+
return await fsPromise.writeFile(`${config.projectRoot}/${config.output}/qunitx.html`, htmlContent);
|
|
72
58
|
});
|
|
73
59
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}));
|
|
79
|
-
|
|
80
|
-
app.get('/*', async (req, res) => {
|
|
81
|
-
if (config.debug) {
|
|
82
|
-
console.log(`# [HTTPServer] ${req.method} ${req.path}`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
let dynamicHTML = cachedContent.dynamicContentHTMLs[`${config.projectRoot}${req.path}`];
|
|
86
|
-
if (dynamicHTML) {
|
|
87
|
-
let TEST_RUNTIME_TO_INJECT = testRuntimeToInject(app.config.port, config);
|
|
60
|
+
server.get('/*', async (req, res) => {
|
|
61
|
+
let possibleDynamicHTML = cachedContent.dynamicContentHTMLs[`${config.projectRoot}${req.path}`];
|
|
62
|
+
if (possibleDynamicHTML) {
|
|
63
|
+
let TEST_RUNTIME_TO_INJECT = testRuntimeToInject(config.port, config);
|
|
88
64
|
let htmlContent = escapeAndInjectTestsToHTML(
|
|
89
|
-
|
|
65
|
+
possibleDynamicHTML,
|
|
90
66
|
TEST_RUNTIME_TO_INJECT,
|
|
91
67
|
cachedContent.allTestCode
|
|
92
68
|
);
|
|
93
69
|
|
|
94
|
-
res.
|
|
70
|
+
res.write(htmlContent);
|
|
71
|
+
res.end();
|
|
72
|
+
|
|
73
|
+
return await fsPromise.writeFile(`${config.projectRoot}/${config.output}${req.path}`, htmlContent);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let url = req.url;
|
|
77
|
+
let requestStartedAt = new Date();
|
|
78
|
+
let filePath = (url.endsWith("/") ? [STATIC_FILES_PATH, url, "index.html"] : [STATIC_FILES_PATH, url]).join('');
|
|
79
|
+
let statusCode = await pathExists(filePath) ? 200 : 404;
|
|
80
|
+
|
|
81
|
+
res.writeHead(statusCode, {
|
|
82
|
+
"Content-Type": req.headers.accept?.includes('text/html')
|
|
83
|
+
? MIME_TYPES.html
|
|
84
|
+
: MIME_TYPES[path.extname(filePath).substring(1).toLowerCase()] || MIME_TYPES.html
|
|
85
|
+
});
|
|
95
86
|
|
|
96
|
-
|
|
87
|
+
if (statusCode === 404) {
|
|
88
|
+
res.end();
|
|
89
|
+
} else {
|
|
90
|
+
fs.createReadStream(filePath)
|
|
91
|
+
.pipe(res);
|
|
97
92
|
}
|
|
98
93
|
|
|
99
|
-
|
|
100
|
-
code: 404,
|
|
101
|
-
message: 'Not found'
|
|
102
|
-
})
|
|
94
|
+
console.log(`# [HTTPServer] GET ${url} ${statusCode} - ${new Date() - requestStartedAt}ms`);
|
|
103
95
|
});
|
|
104
96
|
|
|
105
|
-
return
|
|
97
|
+
return server;
|
|
106
98
|
}
|
|
107
99
|
|
|
108
100
|
function replaceAssetPaths(html, htmlPath, projectRoot) {
|
|
@@ -10,7 +10,7 @@ export default async function runUserModule(modulePath, params, scriptPosition)
|
|
|
10
10
|
}
|
|
11
11
|
} catch (error) {
|
|
12
12
|
console.log('#', kleur.red(`QUnitX ${scriptPosition} script failed:`));
|
|
13
|
-
console.
|
|
13
|
+
console.trace(error);
|
|
14
14
|
console.error(error);
|
|
15
15
|
|
|
16
16
|
return process.exit(1);
|
package/lol.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Deno.serve((req) => {
|
|
2
|
+
let timer: number;
|
|
3
|
+
const body = new ReadableStream({
|
|
4
|
+
async start(controller) {
|
|
5
|
+
timer = setInterval(() => {
|
|
6
|
+
controller.enqueue("Hello, World!\n");
|
|
7
|
+
}, 1000);
|
|
8
|
+
},
|
|
9
|
+
cancel() {
|
|
10
|
+
clearInterval(timer);
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
return new Response(body.pipeThrough(new TextEncoderStream()), {
|
|
14
|
+
headers: {
|
|
15
|
+
"content-type": "text/plain; charset=utf-8",
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qunitx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"description": "Experimental improvements, suggestions for qunit CLI",
|
|
6
6
|
"author": "Izel Nakri",
|
|
7
7
|
"license": "MIT",
|
|
@@ -52,18 +52,17 @@
|
|
|
52
52
|
"test:sanity-second": "./cli.js test/helpers/passing-tests.js test/helpers/passing-tests.ts"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@nanoexpress/middleware-static-serve": "^1.0.4",
|
|
56
55
|
"cheerio": "^1.0.0-rc.10",
|
|
57
56
|
"chokidar": "^3.5.3",
|
|
58
57
|
"esbuild": "^0.17.19",
|
|
59
58
|
"js-yaml": "^4.1.0",
|
|
60
59
|
"jsdom": "^22.0.0",
|
|
61
60
|
"kleur": "^4.1.5",
|
|
62
|
-
"nanoexpress": "^6.2.1",
|
|
63
61
|
"picomatch": "^2.3.1",
|
|
64
62
|
"puppeteer": "20.2.0",
|
|
65
63
|
"recursive-lookup": "1.1.0",
|
|
66
|
-
"ts-node": "^10.7.0"
|
|
64
|
+
"ts-node": "^10.7.0",
|
|
65
|
+
"ws": "^8.13.0"
|
|
67
66
|
},
|
|
68
67
|
"devDependencies": {
|
|
69
68
|
"auto-changelog": "^2.4.0",
|