velocious 1.0.104 → 1.0.106
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/package.json +1 -1
- package/spec/dummy/dummy-directory.js +2 -0
- package/spec/dummy/index.js +5 -1
- package/src/application.js +1 -0
- package/src/configuration-types.js +6 -0
- package/src/controller.js +44 -24
- package/src/database/drivers/base-foreign-key.js +1 -1
- package/src/database/drivers/base.js +2 -2
- package/src/database/drivers/mssql/column.js +6 -0
- package/src/database/drivers/mssql/columns-index.js +2 -5
- package/src/database/drivers/mssql/foreign-key.js +2 -0
- package/src/database/drivers/mssql/options.js +25 -0
- package/src/database/drivers/mssql/query-parser.js +2 -0
- package/src/database/drivers/mysql/options.js +9 -0
- package/src/database/drivers/mysql/sql/alter-table.js +2 -0
- package/src/database/drivers/mysql/sql/create-database.js +2 -0
- package/src/database/drivers/mysql/sql/create-index.js +2 -0
- package/src/database/drivers/mysql/sql/create-table.js +2 -0
- package/src/database/drivers/mysql/sql/delete.js +2 -0
- package/src/database/drivers/mysql/sql/drop-table.js +2 -0
- package/src/database/drivers/mysql/sql/insert.js +2 -0
- package/src/database/drivers/mysql/sql/update.js +2 -0
- package/src/database/drivers/pgsql/column.js +6 -0
- package/src/database/drivers/pgsql/columns-index.js +2 -0
- package/src/database/drivers/pgsql/foreign-key.js +2 -0
- package/src/database/drivers/pgsql/options.js +9 -0
- package/src/database/drivers/pgsql/query-parser.js +2 -0
- package/src/database/drivers/pgsql/sql/alter-table.js +2 -0
- package/src/database/drivers/pgsql/sql/create-database.js +5 -4
- package/src/database/drivers/pgsql/sql/create-index.js +2 -0
- package/src/database/drivers/pgsql/sql/create-table.js +2 -0
- package/src/database/drivers/pgsql/sql/delete.js +2 -0
- package/src/database/drivers/pgsql/sql/drop-table.js +2 -0
- package/src/database/drivers/pgsql/sql/insert.js +2 -0
- package/src/database/drivers/pgsql/sql/update.js +2 -0
- package/src/database/drivers/pgsql/table.js +6 -0
- package/src/database/drivers/sqlite/columns-index.js +2 -6
- package/src/database/drivers/sqlite/connection-remote.js +7 -0
- package/src/database/drivers/sqlite/connection-sql-js.js +12 -2
- package/src/database/drivers/sqlite/foreign-key.js +7 -0
- package/src/database/drivers/sqlite/index.js +7 -1
- package/src/database/drivers/sqlite/index.web.js +12 -3
- package/src/database/drivers/sqlite/options.js +9 -0
- package/src/database/drivers/sqlite/query-parser.js +2 -0
- package/src/database/drivers/sqlite/query.js +19 -6
- package/src/database/drivers/sqlite/query.web.js +13 -1
- package/src/database/initializer-from-require-context.js +11 -1
- package/src/database/migrator/types.js +2 -0
- package/src/database/pool/base-methods-forward.js +7 -0
- package/src/database/query/delete-base.js +8 -0
- package/src/database/query/preloader/belongs-to.js +16 -1
- package/src/database/query/preloader/has-many.js +19 -1
- package/src/database/query/preloader/has-one.js +20 -2
- package/src/database/query/preloader.js +19 -4
- package/src/database/query/update-base.js +9 -0
- package/src/database/query-parser/limit-parser.js +7 -2
- package/src/database/query-parser/options.js +47 -6
- package/src/database/query-parser/order-parser.js +11 -6
- package/src/database/query-parser/select-parser.js +8 -5
- package/src/database/query-parser/where-parser.js +11 -5
- package/src/database/record/index.js +1 -4
- package/src/database/record/instance-relationships/base.js +10 -1
- package/src/database/record/record-not-found-error.js +2 -0
- package/src/database/record/user-module.js +13 -0
- package/src/database/record/validators/uniqueness.js +13 -2
- package/src/error-logger.js +17 -3
- package/src/http-client/index.js +34 -2
- package/src/http-client/request.js +1 -1
- package/src/http-server/client/params-to-object.js +28 -0
- package/src/initializer.js +2 -0
- package/src/routes/app-routes.js +3 -1
- package/src/routes/base-route.js +67 -58
- package/src/routes/basic-route.js +76 -0
- package/src/routes/get-route.js +21 -5
- package/src/routes/index.js +10 -0
- package/src/routes/namespace-route.js +21 -5
- package/src/routes/post-route.js +20 -5
- package/src/routes/resolver.js +15 -2
- package/src/routes/resource-route.js +21 -5
- package/src/routes/root-route.js +3 -3
- package/src/testing/request-client.js +19 -14
- package/src/testing/test-runner.js +16 -10
- package/src/testing/test.js +71 -23
- package/src/utils/with-tracked-stack-async-hooks.js +22 -4
- package/src/utils/with-tracked-stack.js +9 -0
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import restArgsError from "../utils/rest-args-error.js"
|
|
2
|
-
import BaseRoute
|
|
4
|
+
import BaseRoute from "./base-route.js"
|
|
5
|
+
import BasicRoute from "./base-route.js"
|
|
3
6
|
import escapeStringRegexp from "escape-string-regexp"
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
class VelociousRouteNamespaceRoute extends BasicRoute {
|
|
9
|
+
/**
|
|
10
|
+
* @param {object} args
|
|
11
|
+
* @param {string} args.name
|
|
12
|
+
*/
|
|
8
13
|
constructor({name, ...restArgs}) {
|
|
9
14
|
super()
|
|
10
15
|
restArgsError(restArgs)
|
|
@@ -12,7 +17,14 @@ export default class VelociousRouteNamespaceRoute extends BaseRoute {
|
|
|
12
17
|
this.regExp = new RegExp(`^(${escapeStringRegexp(name)})(.*)$`)
|
|
13
18
|
}
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
/**
|
|
21
|
+
* @param {object} args
|
|
22
|
+
* @param {Record<string, any>} args.params
|
|
23
|
+
* @param {string} args.path
|
|
24
|
+
* @param {import("../http-server/client/request.js").default} args.request
|
|
25
|
+
* @returns {{restPath: string} | undefined}
|
|
26
|
+
*/
|
|
27
|
+
matchWithPath({params, path, request}) { // eslint-disable-line no-unused-vars
|
|
16
28
|
const match = path.match(this.regExp)
|
|
17
29
|
|
|
18
30
|
if (match) {
|
|
@@ -24,3 +36,7 @@ export default class VelociousRouteNamespaceRoute extends BaseRoute {
|
|
|
24
36
|
}
|
|
25
37
|
}
|
|
26
38
|
}
|
|
39
|
+
|
|
40
|
+
BaseRoute.registerRouteNamespaceType(VelociousRouteNamespaceRoute)
|
|
41
|
+
|
|
42
|
+
export default VelociousRouteNamespaceRoute
|
package/src/routes/post-route.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import BaseRoute from "./base-route.js"
|
|
2
4
|
import escapeStringRegexp from "escape-string-regexp"
|
|
3
5
|
import restArgsError from "../utils/rest-args-error.js"
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
class VelociousRoutePostRoute extends BaseRoute {
|
|
8
|
+
/**
|
|
9
|
+
* @param {object} args
|
|
10
|
+
* @param {string} args.name
|
|
11
|
+
*/
|
|
8
12
|
constructor({name, ...restArgs}) {
|
|
9
13
|
super()
|
|
10
14
|
restArgsError(restArgs)
|
|
@@ -12,7 +16,14 @@ export default class VelociousRoutePostRoute extends BaseRoute {
|
|
|
12
16
|
this.regExp = new RegExp(`^(${escapeStringRegexp(name)})(.*)$`)
|
|
13
17
|
}
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
/**
|
|
20
|
+
* @param {object} args
|
|
21
|
+
* @param {Record<string, any>} args.params
|
|
22
|
+
* @param {string} args.path
|
|
23
|
+
* @param {import("../http-server/client/request.js").default} args.request
|
|
24
|
+
* @returns {{restPath: string} | undefined}
|
|
25
|
+
*/
|
|
26
|
+
matchWithPath({params, path, request}) { // eslint-disable-line no-unused-vars
|
|
16
27
|
const match = path.match(this.regExp)
|
|
17
28
|
|
|
18
29
|
if (match) {
|
|
@@ -24,3 +35,7 @@ export default class VelociousRoutePostRoute extends BaseRoute {
|
|
|
24
35
|
}
|
|
25
36
|
}
|
|
26
37
|
}
|
|
38
|
+
|
|
39
|
+
BaseRoute.registerRoutePostType(VelociousRoutePostRoute)
|
|
40
|
+
|
|
41
|
+
export default VelociousRoutePostRoute
|
package/src/routes/resolver.js
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import {digg} from "diggerize"
|
|
2
4
|
import {dirname} from "path"
|
|
3
5
|
import {fileURLToPath} from "url"
|
|
4
6
|
import fs from "fs/promises"
|
|
5
7
|
import * as inflection from "inflection"
|
|
6
8
|
|
|
7
9
|
export default class VelociousRoutesResolver {
|
|
10
|
+
/**
|
|
11
|
+
* @param {object} args
|
|
12
|
+
* @param {import("../configuration.js").default} args.configuration
|
|
13
|
+
* @param {import("../http-server/client/request.js").default} args.request
|
|
14
|
+
* @param {import("../http-server/client/response.js").default} args.response
|
|
15
|
+
*/
|
|
8
16
|
constructor({configuration, request, response}) {
|
|
9
17
|
if (!configuration) throw new Error("No configuration given")
|
|
10
18
|
if (!request) throw new Error("No request given")
|
|
@@ -65,6 +73,11 @@ export default class VelociousRoutesResolver {
|
|
|
65
73
|
})
|
|
66
74
|
}
|
|
67
75
|
|
|
76
|
+
/**
|
|
77
|
+
* @param {import("./base-route.js").default} route
|
|
78
|
+
* @param {string} path
|
|
79
|
+
* @returns {{restPath: string} | undefined}
|
|
80
|
+
*/
|
|
68
81
|
matchPathWithRoutes(route, path) {
|
|
69
82
|
const pathWithoutSlash = path.replace(/^\//, "")
|
|
70
83
|
|
|
@@ -77,7 +90,7 @@ export default class VelociousRoutesResolver {
|
|
|
77
90
|
|
|
78
91
|
if (!matchResult) continue
|
|
79
92
|
|
|
80
|
-
const {restPath} =
|
|
93
|
+
const {restPath} = matchResult
|
|
81
94
|
|
|
82
95
|
if (restPath) {
|
|
83
96
|
return this.matchPathWithRoutes(subRoute, restPath)
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import BaseRoute from "./base-route.js"
|
|
4
|
+
import BasicRoute from "./basic-route.js"
|
|
2
5
|
import escapeStringRegexp from "escape-string-regexp"
|
|
3
6
|
import restArgsError from "../utils/rest-args-error.js"
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
class VelociousRouteResourceRoute extends BasicRoute {
|
|
9
|
+
/**
|
|
10
|
+
* @param {object} args
|
|
11
|
+
* @param {string} args.name
|
|
12
|
+
*/
|
|
8
13
|
constructor({name, ...restArgs}) {
|
|
9
14
|
super()
|
|
10
15
|
restArgsError(restArgs)
|
|
@@ -12,6 +17,13 @@ export default class VelociousRouteResourceRoute extends BaseRoute {
|
|
|
12
17
|
this.regExp = new RegExp(`^(${escapeStringRegexp(name)})(.*)$`)
|
|
13
18
|
}
|
|
14
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @param {object} args
|
|
22
|
+
* @param {Record<string, any>} args.params
|
|
23
|
+
* @param {string} args.path
|
|
24
|
+
* @param {import("../http-server/client/request.js").default} args.request
|
|
25
|
+
* @returns {{restPath: string} | undefined}
|
|
26
|
+
*/
|
|
15
27
|
matchWithPath({params, path, request}) {
|
|
16
28
|
const match = path.match(this.regExp)
|
|
17
29
|
|
|
@@ -22,7 +34,7 @@ export default class VelociousRouteResourceRoute extends BaseRoute {
|
|
|
22
34
|
let subRoutesMatchesRestPath = false
|
|
23
35
|
|
|
24
36
|
for (const route of this.routes) {
|
|
25
|
-
if (route.matchWithPath({path: restPath})) {
|
|
37
|
+
if (route.matchWithPath({params, path: restPath, request})) {
|
|
26
38
|
subRoutesMatchesRestPath = true
|
|
27
39
|
}
|
|
28
40
|
}
|
|
@@ -43,3 +55,7 @@ export default class VelociousRouteResourceRoute extends BaseRoute {
|
|
|
43
55
|
}
|
|
44
56
|
}
|
|
45
57
|
}
|
|
58
|
+
|
|
59
|
+
BaseRoute.registerRouteResourceType(VelociousRouteResourceRoute)
|
|
60
|
+
|
|
61
|
+
export default VelociousRouteResourceRoute
|
package/src/routes/root-route.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import BasicRoute from "./basic-route.js"
|
|
4
4
|
|
|
5
|
-
export default class VelociousRootRoute extends
|
|
5
|
+
export default class VelociousRootRoute extends BasicRoute {
|
|
6
6
|
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
class Response {
|
|
4
|
+
/**
|
|
5
|
+
* @param {globalThis.Response} fetchResponse
|
|
6
|
+
*/
|
|
2
7
|
constructor(fetchResponse) {
|
|
3
8
|
this.fetchResponse = fetchResponse
|
|
4
9
|
}
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
|
-
* @returns {void}
|
|
12
|
+
* @returns {Promise<void>}
|
|
8
13
|
*/
|
|
9
14
|
async parse() {
|
|
10
15
|
this._body = await this.fetchResponse.text()
|
|
@@ -12,19 +17,19 @@ class Response {
|
|
|
12
17
|
if (this.statusCode() != 200) throw new Error(`Request failed with code ${this.statusCode()} and body: ${this.body()}`)
|
|
13
18
|
}
|
|
14
19
|
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
body() { return this._body }
|
|
20
|
+
/** @returns {string} */
|
|
21
|
+
body() {
|
|
22
|
+
if (!this._body) throw new Error("Response body not parsed yet. Call parse() first.")
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
contentType() { return this.fetchResponse.headers.get("content-type") }
|
|
24
|
+
return this._body
|
|
25
|
+
}
|
|
24
26
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
/** @returns {string | null} */
|
|
28
|
+
contentType() {
|
|
29
|
+
return this.fetchResponse.headers.get("content-type")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** @returns {number} */
|
|
28
33
|
statusCode() { return this.fetchResponse.status }
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -34,7 +39,7 @@ export default class RequestClient {
|
|
|
34
39
|
|
|
35
40
|
/**
|
|
36
41
|
* @param {string} path
|
|
37
|
-
* @returns {Response}
|
|
42
|
+
* @returns {Promise<Response>}
|
|
38
43
|
*/
|
|
39
44
|
async get(path) {
|
|
40
45
|
const fetchResponse = await fetch(`http://${this.host}:${this.port}${path}`)
|
|
@@ -48,7 +53,7 @@ export default class RequestClient {
|
|
|
48
53
|
/**
|
|
49
54
|
* @param {string} path
|
|
50
55
|
* @param {object} data
|
|
51
|
-
* @returns {Response}
|
|
56
|
+
* @returns {Promise<Response>}
|
|
52
57
|
*/
|
|
53
58
|
async post(path, data) {
|
|
54
59
|
const fetchResponse = await fetch(
|
|
@@ -9,10 +9,11 @@ import {tests} from "./test.js"
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {object} TestArgs
|
|
12
|
-
* @property {Application} application
|
|
13
|
-
* @property {RequestClient} client
|
|
14
|
-
* @property {boolean} focus
|
|
15
|
-
* @property {
|
|
12
|
+
* @property {Application} [application]
|
|
13
|
+
* @property {RequestClient} [client]
|
|
14
|
+
* @property {boolean} [focus]
|
|
15
|
+
* @property {() => Promise<void>} [function]
|
|
16
|
+
* @property {string} [type]
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -22,15 +23,20 @@ import {tests} from "./test.js"
|
|
|
22
23
|
*/
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
|
-
* @typedef {
|
|
26
|
-
|
|
26
|
+
* @typedef {function({configuration: import("../configuration.js").default, testArgs: TestArgs, testData: TestData}) : Promise<void>} AfterBeforeEachCallbackType
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef {object} AfterBeforeEachCallbackObjectType
|
|
31
|
+
* @property {AfterBeforeEachCallbackType} callback
|
|
27
32
|
*/
|
|
28
33
|
|
|
29
34
|
/**
|
|
30
35
|
* @typedef {object} TestsArgument
|
|
36
|
+
* @property {Record<string, TestData>} args
|
|
31
37
|
* @property {boolean} [anyTestsFocussed]
|
|
32
|
-
* @property {
|
|
33
|
-
* @property {
|
|
38
|
+
* @property {AfterBeforeEachCallbackObjectType[]} afterEaches
|
|
39
|
+
* @property {AfterBeforeEachCallbackObjectType[]} beforeEaches
|
|
34
40
|
* @property {Record<string, TestData>} tests - A unique identifier for the node.
|
|
35
41
|
* @property {Record<string, TestsArgument>} subs - Optional child nodes. Each item is another `Node`, allowing recursion.
|
|
36
42
|
*/
|
|
@@ -212,8 +218,8 @@ export default class TestRunner {
|
|
|
212
218
|
|
|
213
219
|
/**
|
|
214
220
|
* @param {object} args
|
|
215
|
-
* @param {Array<
|
|
216
|
-
* @param {Array<
|
|
221
|
+
* @param {Array<AfterBeforeEachCallbackObjectType>} args.afterEaches
|
|
222
|
+
* @param {Array<AfterBeforeEachCallbackObjectType>} args.beforeEaches
|
|
217
223
|
* @param {TestsArgument} args.tests
|
|
218
224
|
* @param {string[]} args.descriptions
|
|
219
225
|
* @param {number} args.indentLevel
|
package/src/testing/test.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import {anythingDifferent} from "set-state-compare/src/diff-utils.js"
|
|
2
4
|
import restArgsError from "../utils/rest-args-error.js"
|
|
3
5
|
|
|
6
|
+
/** @type {import("./test-runner.js").TestsArgument} */
|
|
4
7
|
const tests = {
|
|
8
|
+
/** @type {import("./test-runner.js").AfterBeforeEachCallbackObjectType[]} */
|
|
5
9
|
afterEaches: [],
|
|
6
10
|
args: {},
|
|
11
|
+
|
|
12
|
+
/** @type {import("./test-runner.js").AfterBeforeEachCallbackObjectType[]} */
|
|
7
13
|
beforeEaches: [],
|
|
8
14
|
subs: {},
|
|
9
15
|
tests: {}
|
|
@@ -12,7 +18,7 @@ const tests = {
|
|
|
12
18
|
let currentPath = [tests]
|
|
13
19
|
|
|
14
20
|
/**
|
|
15
|
-
* @param {
|
|
21
|
+
* @param {import("./test-runner.js").AfterBeforeEachCallbackType} callback
|
|
16
22
|
* @returns {void}
|
|
17
23
|
*/
|
|
18
24
|
function beforeEach(callback) {
|
|
@@ -22,7 +28,7 @@ function beforeEach(callback) {
|
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
/**
|
|
25
|
-
* @param {
|
|
31
|
+
* @param {import("./test-runner.js").AfterBeforeEachCallbackType} callback
|
|
26
32
|
* @returns {void}
|
|
27
33
|
*/
|
|
28
34
|
function afterEach(callback) {
|
|
@@ -31,8 +37,28 @@ function afterEach(callback) {
|
|
|
31
37
|
currentTest.afterEaches.push({callback})
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
class
|
|
40
|
+
class BaseExpect {
|
|
41
|
+
/**
|
|
42
|
+
* @abstract
|
|
43
|
+
* @returns {Promise<void>}
|
|
44
|
+
*/
|
|
45
|
+
async runBefore() { /* do nothing */ }
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @abstract
|
|
49
|
+
* @returns {Promise<void>}
|
|
50
|
+
*/
|
|
51
|
+
async runAfter() { /* do nothing */ }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class ExpectToChange extends BaseExpect {
|
|
55
|
+
/**
|
|
56
|
+
* @param {object} args
|
|
57
|
+
* @param {function(): Promise<number>} args.changeCallback
|
|
58
|
+
* @param {Expect} args.expect
|
|
59
|
+
*/
|
|
35
60
|
constructor({changeCallback, expect, ...restArgs}) {
|
|
61
|
+
super()
|
|
36
62
|
restArgsError(restArgs)
|
|
37
63
|
|
|
38
64
|
this.expect = expect
|
|
@@ -58,9 +84,13 @@ class ExpectToChange {
|
|
|
58
84
|
}
|
|
59
85
|
|
|
60
86
|
/**
|
|
61
|
-
* @returns {void}
|
|
87
|
+
* @returns {Promise<void>}
|
|
62
88
|
*/
|
|
63
89
|
async execute() {
|
|
90
|
+
if (this.newCount === undefined || this.oldCount === undefined) {
|
|
91
|
+
throw new Error("ExpectToChange not executed properly")
|
|
92
|
+
}
|
|
93
|
+
|
|
64
94
|
const difference = this.newCount - this.oldCount
|
|
65
95
|
|
|
66
96
|
if (difference != this.count) {
|
|
@@ -69,20 +99,24 @@ class ExpectToChange {
|
|
|
69
99
|
}
|
|
70
100
|
}
|
|
71
101
|
|
|
72
|
-
class Expect {
|
|
102
|
+
class Expect extends BaseExpect {
|
|
73
103
|
/**
|
|
74
104
|
* @param {any} object
|
|
75
105
|
*/
|
|
76
106
|
constructor(object) {
|
|
107
|
+
super()
|
|
77
108
|
this._object = object
|
|
109
|
+
|
|
110
|
+
/** @type {Array<Expect | ExpectToChange>} */
|
|
78
111
|
this.expectations = []
|
|
79
112
|
}
|
|
80
113
|
|
|
81
114
|
/**
|
|
115
|
+
* @param {function(): Promise<number>} changeCallback
|
|
82
116
|
* @returns {ExpectToChange}
|
|
83
117
|
*/
|
|
84
|
-
andChange(
|
|
85
|
-
return this.toChange(
|
|
118
|
+
andChange(changeCallback) {
|
|
119
|
+
return this.toChange(changeCallback)
|
|
86
120
|
}
|
|
87
121
|
|
|
88
122
|
/**
|
|
@@ -126,6 +160,7 @@ class Expect {
|
|
|
126
160
|
}
|
|
127
161
|
|
|
128
162
|
/**
|
|
163
|
+
* @param {Function} klass
|
|
129
164
|
* @returns {void}
|
|
130
165
|
*/
|
|
131
166
|
toBeInstanceOf(klass) {
|
|
@@ -156,7 +191,7 @@ class Expect {
|
|
|
156
191
|
}
|
|
157
192
|
|
|
158
193
|
/**
|
|
159
|
-
* @param {function():
|
|
194
|
+
* @param {function(): Promise<number>} changeCallback
|
|
160
195
|
* @returns {ExpectToChange}
|
|
161
196
|
*/
|
|
162
197
|
toChange(changeCallback) {
|
|
@@ -230,7 +265,7 @@ class Expect {
|
|
|
230
265
|
/**
|
|
231
266
|
* @template T extends Error
|
|
232
267
|
* @param {string|T} expectedError
|
|
233
|
-
* @returns {void}
|
|
268
|
+
* @returns {Promise<void>}
|
|
234
269
|
*/
|
|
235
270
|
async toThrowError(expectedError) {
|
|
236
271
|
if (this._not) throw new Error("not stub")
|
|
@@ -249,14 +284,18 @@ class Expect {
|
|
|
249
284
|
|
|
250
285
|
if (typeof failedError == "string") {
|
|
251
286
|
failedErrorMessage = failedError
|
|
252
|
-
} else {
|
|
287
|
+
} else if (failedError instanceof Error) {
|
|
253
288
|
failedErrorMessage = failedError.message
|
|
289
|
+
} else {
|
|
290
|
+
failedErrorMessage = String(failedError)
|
|
254
291
|
}
|
|
255
292
|
|
|
256
293
|
if (typeof expectedError == "string") {
|
|
257
294
|
expectedErrorMessage = expectedError
|
|
258
|
-
} else {
|
|
295
|
+
} else if (expectedError instanceof Error) {
|
|
259
296
|
expectedErrorMessage = expectedError.message
|
|
297
|
+
} else {
|
|
298
|
+
expectedErrorMessage = String(expectedError)
|
|
260
299
|
}
|
|
261
300
|
|
|
262
301
|
if (failedErrorMessage != expectedErrorMessage) {
|
|
@@ -265,7 +304,7 @@ class Expect {
|
|
|
265
304
|
}
|
|
266
305
|
|
|
267
306
|
/**
|
|
268
|
-
* @returns {any}
|
|
307
|
+
* @returns {Promise<any>}
|
|
269
308
|
*/
|
|
270
309
|
async execute() {
|
|
271
310
|
for (const expectation of this.expectations) {
|
|
@@ -286,12 +325,13 @@ class Expect {
|
|
|
286
325
|
}
|
|
287
326
|
|
|
288
327
|
/**
|
|
289
|
-
* @param {
|
|
328
|
+
* @param {Record<string, any>} result
|
|
290
329
|
* @returns {void}
|
|
291
330
|
*/
|
|
292
331
|
toHaveAttributes(result) {
|
|
293
332
|
if (this._not) throw new Error("not stub")
|
|
294
333
|
|
|
334
|
+
/** @type {Record<string, any[]>} */
|
|
295
335
|
const differences = {}
|
|
296
336
|
|
|
297
337
|
for (const key in result) {
|
|
@@ -314,9 +354,9 @@ class Expect {
|
|
|
314
354
|
|
|
315
355
|
/**
|
|
316
356
|
* @param {string} description
|
|
317
|
-
* @param {object|() => Promise<void>} arg1
|
|
318
|
-
* @param {undefined|() => Promise<void>} [arg2]
|
|
319
|
-
* @returns {void}
|
|
357
|
+
* @param {object|(() => Promise<void>)} arg1
|
|
358
|
+
* @param {undefined|(() => Promise<void>)} [arg2]
|
|
359
|
+
* @returns {Promise<void>}
|
|
320
360
|
*/
|
|
321
361
|
async function describe(description, arg1, arg2) {
|
|
322
362
|
let testArgs, testFunction
|
|
@@ -360,15 +400,19 @@ function expect(arg) {
|
|
|
360
400
|
|
|
361
401
|
/**
|
|
362
402
|
* @param {string} description
|
|
363
|
-
* @param {object|() => Promise<void>} arg1
|
|
364
|
-
* @param {undefined|() => Promise<void>} [arg2]
|
|
403
|
+
* @param {object|(() => Promise<void>)} arg1
|
|
404
|
+
* @param {undefined|(() => Promise<void>)} [arg2]
|
|
365
405
|
* @returns {void}
|
|
366
406
|
*/
|
|
367
407
|
function it(description, arg1, arg2) {
|
|
368
408
|
const currentTest = currentPath[currentPath.length - 1]
|
|
369
|
-
let testArgs
|
|
409
|
+
let testArgs
|
|
410
|
+
|
|
411
|
+
/** @type {() => Promise<void>} */
|
|
412
|
+
let testFunction
|
|
370
413
|
|
|
371
414
|
if (typeof arg1 == "function") {
|
|
415
|
+
// @ts-expect-error
|
|
372
416
|
testFunction = arg1
|
|
373
417
|
testArgs = {}
|
|
374
418
|
} else if (typeof arg2 == "function") {
|
|
@@ -385,14 +429,18 @@ function it(description, arg1, arg2) {
|
|
|
385
429
|
|
|
386
430
|
/**
|
|
387
431
|
* @param {string} description
|
|
388
|
-
* @param {object|() => Promise<void>} arg1
|
|
389
|
-
* @param {undefined|() => Promise<void>} [arg2]
|
|
432
|
+
* @param {object|(() => Promise<void>)} arg1
|
|
433
|
+
* @param {undefined|(() => Promise<void>)} [arg2]
|
|
390
434
|
* @returns {void}
|
|
391
435
|
*/
|
|
392
436
|
function fit(description, arg1, arg2) {
|
|
393
|
-
let testArgs
|
|
437
|
+
let testArgs
|
|
438
|
+
|
|
439
|
+
/** @type {() => Promise<void>} */
|
|
440
|
+
let testFunction
|
|
394
441
|
|
|
395
442
|
if (typeof arg1 == "function") {
|
|
443
|
+
// @ts-expect-error
|
|
396
444
|
testFunction = arg1
|
|
397
445
|
testArgs = {focus: true}
|
|
398
446
|
} else if (typeof arg2 == "function") {
|
|
@@ -413,4 +461,4 @@ globalThis.expect = expect
|
|
|
413
461
|
globalThis.it = it
|
|
414
462
|
globalThis.fit = fit
|
|
415
463
|
|
|
416
|
-
export {describe, expect, fit, it, tests}
|
|
464
|
+
export {afterEach, beforeEach, describe, expect, fit, it, tests}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import {AsyncLocalStorage} from "async_hooks"
|
|
2
4
|
|
|
5
|
+
/** @type {AsyncLocalStorage<Array<string[]>> | undefined} */
|
|
3
6
|
let asyncLocalStorage
|
|
4
7
|
|
|
5
8
|
if (AsyncLocalStorage) {
|
|
6
9
|
asyncLocalStorage = new AsyncLocalStorage()
|
|
7
10
|
}
|
|
8
11
|
|
|
12
|
+
/** @param {Error} error */
|
|
9
13
|
function addTrackedStackToError(error) {
|
|
10
14
|
// Not supported
|
|
11
15
|
if (!asyncLocalStorage) return
|
|
@@ -23,15 +27,27 @@ function addTrackedStackToError(error) {
|
|
|
23
27
|
error.stack += "\n" + additionalStackLines.join("\n")
|
|
24
28
|
}
|
|
25
29
|
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* @param {() => Promise<void> | string} arg1
|
|
33
|
+
* @param {() => Promise<void> | Error} [arg2]
|
|
34
|
+
* @returns {Promise<void>}
|
|
35
|
+
*/
|
|
26
36
|
async function withTrackedStack(arg1, arg2) {
|
|
27
|
-
|
|
37
|
+
/** @type {() => Promise<void>} */
|
|
38
|
+
let callback
|
|
39
|
+
|
|
40
|
+
/** @type {string} */
|
|
41
|
+
let stack
|
|
28
42
|
|
|
29
|
-
if (arg2) {
|
|
43
|
+
if (typeof arg2 == "function" && typeof arg1 == "string") {
|
|
44
|
+
// @ts-expect-error
|
|
30
45
|
callback = arg2
|
|
31
46
|
stack = arg1
|
|
32
47
|
} else {
|
|
48
|
+
// @ts-expect-error
|
|
33
49
|
callback = arg1
|
|
34
|
-
stack = Error().stack
|
|
50
|
+
stack = Error().stack || ""
|
|
35
51
|
}
|
|
36
52
|
|
|
37
53
|
// Not supported
|
|
@@ -56,13 +72,15 @@ async function withTrackedStack(arg1, arg2) {
|
|
|
56
72
|
const newStacks = [additionalStackLines, ...parentStacks]
|
|
57
73
|
|
|
58
74
|
await asyncLocalStorage.run(newStacks, async () => {
|
|
59
|
-
|
|
75
|
+
await callback()
|
|
60
76
|
})
|
|
61
77
|
}
|
|
62
78
|
|
|
79
|
+
// @ts-expect-error
|
|
63
80
|
if (globalThis.withTrackedStack) {
|
|
64
81
|
console.warn("globalThis.withTrackedStack was already defined")
|
|
65
82
|
} else {
|
|
83
|
+
// @ts-expect-error
|
|
66
84
|
globalThis.withTrackedStack = {addTrackedStackToError, withTrackedStack}
|
|
67
85
|
}
|
|
68
86
|
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/** @param {Error} error */
|
|
1
4
|
function addTrackedStackToError(error) {
|
|
5
|
+
// @ts-expect-error
|
|
2
6
|
globalThis.withTrackedStack?.addTrackedStackToError(error)
|
|
3
7
|
}
|
|
4
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @param {...any} args
|
|
11
|
+
* @returns {Promise<any>}
|
|
12
|
+
*/
|
|
5
13
|
async function withTrackedStack(...args) {
|
|
14
|
+
// @ts-expect-error
|
|
6
15
|
const withTrackedStack = globalThis.withTrackedStack?.withTrackedStack
|
|
7
16
|
|
|
8
17
|
let callback
|