velocious 1.0.85 → 1.0.87
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/bin/velocious.js +10 -1
- package/eslint.config.js +33 -0
- package/package.json +7 -2
- package/peak_flow.yml +6 -0
- package/spec/cli/commands/db/create-spec.js +4 -0
- package/spec/cli/commands/db/migrate-spec.js +4 -2
- package/spec/cli/commands/db/rollback-spec.js +179 -0
- package/spec/cli/commands/destroy/migration-spec.js +4 -0
- package/spec/cli/commands/generate/migration-spec.js +4 -0
- package/spec/cli/commands/init-spec.js +4 -0
- package/spec/dummy/index.js +7 -4
- package/spec/dummy/src/config/configuration.example.js +2 -0
- package/spec/dummy/src/config/configuration.peakflow.mariadb.js +2 -0
- package/spec/dummy/src/config/configuration.peakflow.mssql.js +2 -0
- package/spec/dummy/src/config/configuration.peakflow.pgsql.js +2 -0
- package/spec/dummy/src/config/configuration.peakflow.sqlite.js +2 -0
- package/spec/dummy/src/database/migrations/20250921121002-create-project-details.js +3 -1
- package/src/application.js +12 -0
- package/src/cli/base-command.js +9 -5
- package/src/cli/browser-cli.js +37 -0
- package/src/cli/commands/db/create.js +5 -5
- package/src/cli/commands/db/drop.js +4 -5
- package/src/cli/commands/db/migrate.js +6 -10
- package/src/cli/commands/db/reset.js +8 -12
- package/src/cli/commands/db/rollback.js +15 -0
- package/src/cli/commands/destroy/migration.js +2 -2
- package/src/cli/commands/generate/migration.js +3 -6
- package/src/cli/commands/generate/model.js +3 -6
- package/src/cli/commands/init.js +5 -8
- package/src/cli/commands/server.js +3 -3
- package/src/cli/commands/test.js +1 -1
- package/src/cli/index.js +15 -63
- package/src/cli/use-browser-cli.js +25 -0
- package/src/configuration-resolver.js +1 -1
- package/src/configuration.js +118 -9
- package/src/controller.js +29 -0
- package/src/database/drivers/base-column.js +14 -0
- package/src/database/drivers/base-columns-index.js +3 -0
- package/src/database/drivers/base-foreign-key.js +3 -0
- package/src/database/drivers/base-table.js +3 -0
- package/src/database/drivers/base.js +55 -1
- package/src/database/drivers/mssql/index.js +64 -1
- package/src/database/drivers/mysql/columns-index.js +0 -1
- package/src/database/drivers/sqlite/base.js +39 -0
- package/src/database/drivers/sqlite/connection-remote.js +1 -1
- package/src/database/drivers/sqlite/sql/alter-table.js +1 -1
- package/src/database/drivers/sqlite/sql/delete.js +15 -10
- package/src/database/migration/index.js +122 -1
- package/src/database/migrator/files-finder.js +13 -1
- package/src/database/migrator.js +125 -24
- package/src/database/pool/single-multi-use.js +1 -1
- package/src/database/query/alter-table-base.js +11 -0
- package/src/database/query/base.js +7 -0
- package/src/database/query/create-database-base.js +3 -0
- package/src/database/query/create-index-base.js +3 -1
- package/src/database/query/create-table-base.js +3 -0
- package/src/database/query/drop-table-base.js +4 -1
- package/src/database/query/from-base.js +7 -0
- package/src/database/query/index.js +96 -6
- package/src/database/query/insert-base.js +6 -0
- package/src/database/query/join-base.js +3 -0
- package/src/database/query/order-base.js +3 -0
- package/src/database/query/select-base.js +3 -0
- package/src/database/query/update-base.js +3 -0
- package/src/database/query/where-base.js +3 -0
- package/src/database/record/index.js +272 -19
- package/src/database/record/instance-relationships/base.js +66 -1
- package/src/database/record/relationships/base.js +41 -1
- package/src/database/record/validators/base.js +10 -0
- package/src/database/record/validators/presence.js +1 -1
- package/src/database/table-data/table-column.js +37 -3
- package/src/database/table-data/table-index.js +1 -1
- package/src/database/use-database.js +2 -2
- package/src/environment-handlers/base.js +53 -0
- package/src/environment-handlers/browser.js +171 -0
- package/src/environment-handlers/node.js +162 -0
- package/src/http-server/client/request-buffer/index.js +9 -9
- package/src/http-server/index.js +6 -0
- package/src/http-server/worker-handler/index.js +20 -19
- package/src/initializer.js +17 -1
- package/src/logger.js +3 -0
- package/src/routes/app-routes.js +6 -2
- package/src/routes/base-route.js +1 -1
- package/src/routes/get-route.js +1 -1
- package/src/routes/namespace-route.js +1 -1
- package/src/routes/post-route.js +1 -1
- package/src/routes/resolver.js +1 -1
- package/src/routes/resource-route.js +1 -1
- package/src/templates/configuration.js +4 -0
- package/src/testing/request-client.js +26 -3
- package/src/testing/test-files-finder.js +2 -2
- package/src/testing/test-runner.js +74 -28
- package/src/testing/test.js +62 -0
- package/src/utils/file-exists.js +7 -5
- package/src/utils/rest-args-error.js +5 -3
|
@@ -40,17 +40,17 @@ export default class RequestBuffer {
|
|
|
40
40
|
|
|
41
41
|
break
|
|
42
42
|
case "multi-part-form-data-body":
|
|
43
|
-
const body = this.formDataPart.body
|
|
43
|
+
const body = this.formDataPart.body // eslint-disable-line no-case-declarations
|
|
44
44
|
|
|
45
45
|
body.push(char)
|
|
46
46
|
|
|
47
|
-
const possibleBoundaryEndPosition = body.length - this.boundaryLineEnd.length
|
|
48
|
-
const possibleBoundaryEndChars = body.slice(possibleBoundaryEndPosition, body.length)
|
|
49
|
-
const possibleBoundaryEnd = String.fromCharCode.apply(null, possibleBoundaryEndChars)
|
|
47
|
+
const possibleBoundaryEndPosition = body.length - this.boundaryLineEnd.length // eslint-disable-line no-case-declarations
|
|
48
|
+
const possibleBoundaryEndChars = body.slice(possibleBoundaryEndPosition, body.length) // eslint-disable-line no-case-declarations
|
|
49
|
+
const possibleBoundaryEnd = String.fromCharCode.apply(null, possibleBoundaryEndChars) // eslint-disable-line no-case-declarations
|
|
50
50
|
|
|
51
|
-
const possibleBoundaryNextPosition = body.length - this.boundaryLineNext.length
|
|
52
|
-
const possibleBoundaryNextChars = body.slice(possibleBoundaryNextPosition, body.length)
|
|
53
|
-
const possibleBoundaryNext = String.fromCharCode.apply(null, possibleBoundaryNextChars)
|
|
51
|
+
const possibleBoundaryNextPosition = body.length - this.boundaryLineNext.length // eslint-disable-line no-case-declarations
|
|
52
|
+
const possibleBoundaryNextChars = body.slice(possibleBoundaryNextPosition, body.length) // eslint-disable-line no-case-declarations
|
|
53
|
+
const possibleBoundaryNext = String.fromCharCode.apply(null, possibleBoundaryNextChars) // eslint-disable-line no-case-declarations
|
|
54
54
|
|
|
55
55
|
if (possibleBoundaryEnd == this.boundaryLineEnd) {
|
|
56
56
|
this.formDataPart.removeFromBody(possibleBoundaryEnd)
|
|
@@ -150,9 +150,9 @@ export default class RequestBuffer {
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
readHeaderFromLine(line) {
|
|
153
|
-
|
|
153
|
+
const match = line.match(/^(.+): (.+)\r\n/)
|
|
154
154
|
|
|
155
|
-
if (match
|
|
155
|
+
if (match) {
|
|
156
156
|
const header = new Header(match[1], match[2])
|
|
157
157
|
|
|
158
158
|
return header
|
package/src/http-server/index.js
CHANGED
|
@@ -20,6 +20,9 @@ export default class VelociousHttpServer {
|
|
|
20
20
|
this.maxWorkers = maxWorkers || 16
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @returns {Promise<void>}
|
|
25
|
+
*/
|
|
23
26
|
async start() {
|
|
24
27
|
await this._ensureAtLeastOneWorker()
|
|
25
28
|
this.netServer = new Net.Server()
|
|
@@ -47,6 +50,9 @@ export default class VelociousHttpServer {
|
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
|
|
53
|
+
/**
|
|
54
|
+
* @returns {boolean}
|
|
55
|
+
*/
|
|
50
56
|
isActive() {
|
|
51
57
|
return this.netServer.listening
|
|
52
58
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import {digg, digs} from "diggerize"
|
|
2
|
-
import {dirname} from "path"
|
|
3
|
-
import {fileURLToPath} from "url"
|
|
4
2
|
import {Logger} from "../../logger.js"
|
|
5
3
|
import {Worker} from "worker_threads"
|
|
6
4
|
|
|
@@ -12,26 +10,29 @@ export default class VelociousHttpServerWorker {
|
|
|
12
10
|
this.workerCount = workerCount
|
|
13
11
|
}
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
start() {
|
|
16
14
|
return new Promise((resolve) => {
|
|
17
|
-
const {debug} = digs(this.configuration, "debug")
|
|
18
|
-
const directory = this.configuration.getDirectory()
|
|
19
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
20
|
-
const __dirname = dirname(__filename)
|
|
21
|
-
|
|
22
15
|
this.onStartCallback = resolve
|
|
23
|
-
this.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
16
|
+
this._spawnWorker()
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async _spawnWorker() {
|
|
21
|
+
const {debug} = digs(this.configuration, "debug")
|
|
22
|
+
const directory = this.configuration.getDirectory()
|
|
23
|
+
const velociousPath = await this.configuration.getEnvironmentHandler().getVelociousPath()
|
|
24
|
+
|
|
25
|
+
this.worker = new Worker(`${velociousPath}/src/http-server/worker-handler/worker-script.js`, {
|
|
26
|
+
workerData: {
|
|
27
|
+
debug,
|
|
28
|
+
directory,
|
|
29
|
+
environment: this.configuration.getEnvironment(),
|
|
30
|
+
workerCount: this.workerCount
|
|
31
|
+
}
|
|
34
32
|
})
|
|
33
|
+
this.worker.on("error", this.onWorkerError)
|
|
34
|
+
this.worker.on("exit", this.onWorkerExit)
|
|
35
|
+
this.worker.on("message", this.onWorkerMessage)
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
addSocketConnection(client) {
|
package/src/initializer.js
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
|
+
import restArgsError from "./utils/rest-args-error.js"
|
|
2
|
+
|
|
1
3
|
export default class VelociousInitializer {
|
|
2
|
-
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} args
|
|
6
|
+
* @param {import("./configuration.js").default} args.configuration
|
|
7
|
+
* @param {string} args.type
|
|
8
|
+
*/
|
|
9
|
+
constructor({configuration, type, ...restArgs}) {
|
|
10
|
+
restArgsError(restArgs)
|
|
11
|
+
|
|
3
12
|
this._configuration = configuration
|
|
4
13
|
this._type = type
|
|
5
14
|
}
|
|
6
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @returns {import("./configuration.js").default}
|
|
18
|
+
*/
|
|
7
19
|
getConfiguration() { return this._configuration }
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
8
24
|
getType() { return this._type }
|
|
9
25
|
|
|
10
26
|
run() {
|
package/src/logger.js
CHANGED
package/src/routes/app-routes.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import {digg} from "diggerize"
|
|
2
2
|
|
|
3
3
|
export default class VelociousRoutesAppRoutes {
|
|
4
|
+
/**
|
|
5
|
+
* @param {import("../configuration.js")} configuration
|
|
6
|
+
* @returns {import("./index.js").default}
|
|
7
|
+
*/
|
|
4
8
|
static async getRoutes(configuration) {
|
|
5
9
|
// Every client need to make their own routes because they probably can't be shared across different worker threads
|
|
6
|
-
const routesImport = await
|
|
10
|
+
const routesImport = await configuration.getEnvironmentHandler().importApplicationRoutes()
|
|
7
11
|
|
|
8
|
-
return digg(routesImport, "
|
|
12
|
+
return digg(routesImport, "routes")
|
|
9
13
|
}
|
|
10
14
|
}
|
package/src/routes/base-route.js
CHANGED
package/src/routes/get-route.js
CHANGED
|
@@ -14,7 +14,7 @@ export default class VelociousRouteGetRoute extends BaseRoute {
|
|
|
14
14
|
const match = path.match(this.regExp)
|
|
15
15
|
|
|
16
16
|
if (match) {
|
|
17
|
-
const [_beginnigSlash, _matchedName, restPath] = match
|
|
17
|
+
const [_beginnigSlash, _matchedName, restPath] = match // eslint-disable-line no-unused-vars
|
|
18
18
|
|
|
19
19
|
params.action = this.name
|
|
20
20
|
|
|
@@ -14,7 +14,7 @@ export default class VelociousRouteNamespaceRoute extends BaseRoute {
|
|
|
14
14
|
const match = path.match(this.regExp)
|
|
15
15
|
|
|
16
16
|
if (match) {
|
|
17
|
-
const [_beginnigSlash, _matchedName, restPath] = match
|
|
17
|
+
const [_beginnigSlash, _matchedName, restPath] = match // eslint-disable-line no-unused-vars
|
|
18
18
|
|
|
19
19
|
params.controller = this.name
|
|
20
20
|
|
package/src/routes/post-route.js
CHANGED
|
@@ -14,7 +14,7 @@ export default class VelociousRoutePostRoute extends BaseRoute {
|
|
|
14
14
|
const match = path.match(this.regExp)
|
|
15
15
|
|
|
16
16
|
if (match) {
|
|
17
|
-
const [_beginnigSlash, _matchedName, restPath] = match
|
|
17
|
+
const [_beginnigSlash, _matchedName, restPath] = match // eslint-disable-line no-unused-vars
|
|
18
18
|
|
|
19
19
|
params.action = this.name
|
|
20
20
|
|
package/src/routes/resolver.js
CHANGED
|
@@ -33,7 +33,7 @@ export default class VelociousRoutesResolver {
|
|
|
33
33
|
controller = "errors"
|
|
34
34
|
controllerPath = "./built-in/errors/controller.js"
|
|
35
35
|
action = "notFound"
|
|
36
|
-
viewPath = await fs.realpath(`${__dirname}/built-in/errors`)
|
|
36
|
+
viewPath = await fs.realpath(`${__dirname}/built-in/errors`)
|
|
37
37
|
} else if (action) {
|
|
38
38
|
if (!controller) controller = "_root"
|
|
39
39
|
|
|
@@ -14,7 +14,7 @@ export default class VelociousRouteResourceRoute extends BaseRoute {
|
|
|
14
14
|
const match = path.match(this.regExp)
|
|
15
15
|
|
|
16
16
|
if (match) {
|
|
17
|
-
const [_beginnigSlash, _matchedName, restPath] = match
|
|
17
|
+
const [_beginnigSlash, _matchedName, restPath] = match // eslint-disable-line no-unused-vars
|
|
18
18
|
|
|
19
19
|
let action = "index"
|
|
20
20
|
let subRoutesMatchesRestPath = false
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import AsyncTrackedMultiConnection from "velocious/src/database/pool/async-tracked-multi-connection.js"
|
|
2
2
|
import Configuration from "velocious/src/configuration.js"
|
|
3
|
+
import fs from "fs/promises"
|
|
4
|
+
import InitializerFromRequireContext from "../../../../src/database/initializer-from-require-context.js"
|
|
3
5
|
import MysqlDriver from "velocious/src/database/drivers/mysql/index.js"
|
|
6
|
+
import path from "path"
|
|
7
|
+
import requireContext from "require-context"
|
|
4
8
|
|
|
5
9
|
export default new Configuration({
|
|
6
10
|
database: {
|
|
@@ -3,21 +3,39 @@ class Response {
|
|
|
3
3
|
this.fetchResponse = fetchResponse
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @returns {void}
|
|
8
|
+
*/
|
|
6
9
|
async parse() {
|
|
7
10
|
this._body = await this.fetchResponse.text()
|
|
8
11
|
|
|
9
12
|
if (this.statusCode() != 200) throw new Error(`Request failed with code ${this.statusCode()} and body: ${this.body()}`)
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
/**
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
body() { return this._body }
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @returns {string}
|
|
22
|
+
*/
|
|
23
|
+
contentType() { return this.fetchResponse.headers.get("content-type") }
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @returns {string}
|
|
27
|
+
*/
|
|
28
|
+
statusCode() { return this.fetchResponse.status }
|
|
15
29
|
}
|
|
16
30
|
|
|
17
31
|
export default class RequestClient {
|
|
18
32
|
host = "localhost"
|
|
19
33
|
port = 31006
|
|
20
34
|
|
|
35
|
+
/**
|
|
36
|
+
* @param {string} path
|
|
37
|
+
* @returns {Response}
|
|
38
|
+
*/
|
|
21
39
|
async get(path) {
|
|
22
40
|
const fetchResponse = await fetch(`http://${this.host}:${this.port}${path}`)
|
|
23
41
|
const response = new Response(fetchResponse)
|
|
@@ -27,6 +45,11 @@ export default class RequestClient {
|
|
|
27
45
|
return response
|
|
28
46
|
}
|
|
29
47
|
|
|
48
|
+
/**
|
|
49
|
+
* @param {string} path
|
|
50
|
+
* @param {object} data
|
|
51
|
+
* @returns {Response}
|
|
52
|
+
*/
|
|
30
53
|
async post(path, data) {
|
|
31
54
|
const fetchResponse = await fetch(
|
|
32
55
|
`http://${this.host}:${this.port}${path}`,
|
|
@@ -75,7 +75,7 @@ export default class TestFilesFinder {
|
|
|
75
75
|
if (isDir) {
|
|
76
76
|
this.findTestFilesInDir(fullPath)
|
|
77
77
|
} else {
|
|
78
|
-
if (this.isFileMatchingRequirements(file, localPath
|
|
78
|
+
if (this.isFileMatchingRequirements(file, localPath)) {
|
|
79
79
|
this.foundFiles.push(fullPath)
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -83,7 +83,7 @@ export default class TestFilesFinder {
|
|
|
83
83
|
})
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
isFileMatchingRequirements(file, localPath
|
|
86
|
+
isFileMatchingRequirements(file, localPath) {
|
|
87
87
|
if (this.testArgs.length > 0) {
|
|
88
88
|
for (const testArg of this.testArgs) {
|
|
89
89
|
if (testArg == localPath) {
|
|
@@ -2,18 +2,41 @@ import {addTrackedStackToError} from "../utils/with-tracked-stack.js"
|
|
|
2
2
|
import Application from "../../src/application.js"
|
|
3
3
|
import BacktraceCleaner from "../utils/backtrace-cleaner.js"
|
|
4
4
|
import RequestClient from "./request-client.js"
|
|
5
|
+
import restArgsError from "../utils/rest-args-error.js"
|
|
5
6
|
import {tests} from "./test.js"
|
|
6
7
|
|
|
7
8
|
export default class TestRunner {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* @param {object} args
|
|
11
|
+
* @param {import("../configuration.js").default} args.configuration
|
|
12
|
+
* @param {Array<string>} args.testFiles
|
|
13
|
+
*/
|
|
14
|
+
constructor({configuration, testFiles, ...restArgs}) {
|
|
15
|
+
restArgsError(restArgs)
|
|
16
|
+
|
|
17
|
+
if (!configuration) throw new Error("configuration is required")
|
|
18
|
+
|
|
19
|
+
this._configuration = configuration
|
|
20
|
+
this._testFiles = testFiles
|
|
11
21
|
}
|
|
12
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @returns {import("../configuration.js").default}
|
|
25
|
+
*/
|
|
26
|
+
getConfiguration() { return this._configuration }
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @returns {Array<string>}
|
|
30
|
+
*/
|
|
31
|
+
getTestFiles() { return this._testFiles }
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @returns {Promise<Application>}
|
|
35
|
+
*/
|
|
13
36
|
async application() {
|
|
14
37
|
if (!this._application) {
|
|
15
38
|
this._application = new Application({
|
|
16
|
-
configuration: this.
|
|
39
|
+
configuration: this.getConfiguration(),
|
|
17
40
|
databases: {
|
|
18
41
|
default: {
|
|
19
42
|
host: "mysql",
|
|
@@ -32,6 +55,9 @@ export default class TestRunner {
|
|
|
32
55
|
return this._application
|
|
33
56
|
}
|
|
34
57
|
|
|
58
|
+
/**
|
|
59
|
+
* @returns {RequestClient}
|
|
60
|
+
*/
|
|
35
61
|
async requestClient() {
|
|
36
62
|
if (!this._requestClient) {
|
|
37
63
|
this._requestClient = new RequestClient()
|
|
@@ -40,28 +66,36 @@ export default class TestRunner {
|
|
|
40
66
|
return this._requestClient
|
|
41
67
|
}
|
|
42
68
|
|
|
69
|
+
/**
|
|
70
|
+
* @returns {void}
|
|
71
|
+
*/
|
|
43
72
|
async importTestFiles() {
|
|
44
|
-
|
|
45
|
-
await import(testFile)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
isFailed() {
|
|
50
|
-
return this._failedTests > 0
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
getFailedTests() {
|
|
54
|
-
return this._failedTests
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
getSuccessfulTests() {
|
|
58
|
-
return this._successfulTests
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
getTestsCount() {
|
|
62
|
-
return this._testsCount
|
|
73
|
+
await this.getConfiguration().getEnvironmentHandler().importTestFiles(this.getTestFiles())
|
|
63
74
|
}
|
|
64
75
|
|
|
76
|
+
/**
|
|
77
|
+
* @returns {boolean}
|
|
78
|
+
*/
|
|
79
|
+
isFailed() { return this._failedTests > 0 }
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @returns {number}
|
|
83
|
+
*/
|
|
84
|
+
getFailedTests() { return this._failedTests }
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @returns {number}
|
|
88
|
+
*/
|
|
89
|
+
getSuccessfulTests() { return this._successfulTests }
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @returns {number}
|
|
93
|
+
*/
|
|
94
|
+
getTestsCount() { return this._testsCount }
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @returns {void}
|
|
98
|
+
*/
|
|
65
99
|
async prepare() {
|
|
66
100
|
this.anyTestsFocussed = false
|
|
67
101
|
this._failedTests = 0
|
|
@@ -71,13 +105,16 @@ export default class TestRunner {
|
|
|
71
105
|
await this.analyzeTests(tests)
|
|
72
106
|
this._onlyFocussed = this.anyTestsFocussed
|
|
73
107
|
|
|
74
|
-
const testingConfigPath = this.
|
|
108
|
+
const testingConfigPath = this.getConfiguration().getTesting()
|
|
75
109
|
|
|
76
110
|
if (testingConfigPath) {
|
|
77
|
-
await
|
|
111
|
+
await this.getConfiguration().getEnvironmentHandler().importTestingConfigPath()
|
|
78
112
|
}
|
|
79
113
|
}
|
|
80
114
|
|
|
115
|
+
/**
|
|
116
|
+
* @returns {boolean}
|
|
117
|
+
*/
|
|
81
118
|
areAnyTestsFocussed() {
|
|
82
119
|
if (this.anyTestsFocussed === undefined) {
|
|
83
120
|
throw new Error("Hasn't been detected yet")
|
|
@@ -86,8 +123,11 @@ export default class TestRunner {
|
|
|
86
123
|
return this.anyTestsFocussed
|
|
87
124
|
}
|
|
88
125
|
|
|
126
|
+
/**
|
|
127
|
+
* @returns {void}
|
|
128
|
+
*/
|
|
89
129
|
async run() {
|
|
90
|
-
await this.
|
|
130
|
+
await this.getConfiguration().ensureConnections(async () => {
|
|
91
131
|
await this.runTests({
|
|
92
132
|
afterEaches: [],
|
|
93
133
|
beforeEaches: [],
|
|
@@ -98,6 +138,9 @@ export default class TestRunner {
|
|
|
98
138
|
})
|
|
99
139
|
}
|
|
100
140
|
|
|
141
|
+
/**
|
|
142
|
+
* @returns {object}
|
|
143
|
+
*/
|
|
101
144
|
analyzeTests(tests) {
|
|
102
145
|
let anyTestsFocussedFound = false
|
|
103
146
|
|
|
@@ -127,6 +170,9 @@ export default class TestRunner {
|
|
|
127
170
|
return {anyTestsFocussed: anyTestsFocussedFound}
|
|
128
171
|
}
|
|
129
172
|
|
|
173
|
+
/**
|
|
174
|
+
* @returns {Promise<void>}
|
|
175
|
+
*/
|
|
130
176
|
async runTests({afterEaches, beforeEaches, tests, descriptions, indentLevel}) {
|
|
131
177
|
const leftPadding = " ".repeat(indentLevel * 2)
|
|
132
178
|
const newAfterEaches = [...afterEaches, ...tests.afterEaches]
|
|
@@ -150,7 +196,7 @@ export default class TestRunner {
|
|
|
150
196
|
|
|
151
197
|
try {
|
|
152
198
|
for (const beforeEachData of newBeforeEaches) {
|
|
153
|
-
await beforeEachData.callback({configuration: this.
|
|
199
|
+
await beforeEachData.callback({configuration: this.getConfiguration(), testArgs, testData})
|
|
154
200
|
}
|
|
155
201
|
|
|
156
202
|
await testData.function(testArgs)
|
|
@@ -170,7 +216,7 @@ export default class TestRunner {
|
|
|
170
216
|
}
|
|
171
217
|
} finally {
|
|
172
218
|
for (const afterEachData of newAfterEaches) {
|
|
173
|
-
await afterEachData.callback({configuration: this.
|
|
219
|
+
await afterEachData.callback({configuration: this.getConfiguration(), testArgs, testData})
|
|
174
220
|
}
|
|
175
221
|
}
|
|
176
222
|
}
|
package/src/testing/test.js
CHANGED
|
@@ -31,6 +31,9 @@ class ExpectToChange {
|
|
|
31
31
|
this.changeCallback = changeCallback
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* @returns {Expect}
|
|
36
|
+
*/
|
|
34
37
|
by(count) {
|
|
35
38
|
this.count = count
|
|
36
39
|
|
|
@@ -60,16 +63,25 @@ class Expect {
|
|
|
60
63
|
this.expectations = []
|
|
61
64
|
}
|
|
62
65
|
|
|
66
|
+
/**
|
|
67
|
+
* @returns {ExpectToChange}
|
|
68
|
+
*/
|
|
63
69
|
andChange(...args) {
|
|
64
70
|
return this.toChange(...args)
|
|
65
71
|
}
|
|
66
72
|
|
|
73
|
+
/**
|
|
74
|
+
* @returns {this}
|
|
75
|
+
*/
|
|
67
76
|
get not() {
|
|
68
77
|
this._not = true
|
|
69
78
|
|
|
70
79
|
return this
|
|
71
80
|
}
|
|
72
81
|
|
|
82
|
+
/**
|
|
83
|
+
* @returns {void}
|
|
84
|
+
*/
|
|
73
85
|
toBe(result) {
|
|
74
86
|
if (this._not) {
|
|
75
87
|
if (this._object === result) {
|
|
@@ -82,6 +94,9 @@ class Expect {
|
|
|
82
94
|
}
|
|
83
95
|
}
|
|
84
96
|
|
|
97
|
+
/**
|
|
98
|
+
* @returns {void}
|
|
99
|
+
*/
|
|
85
100
|
toBeDefined() {
|
|
86
101
|
if (this._not) {
|
|
87
102
|
if (this._object !== undefined) {
|
|
@@ -94,24 +109,40 @@ class Expect {
|
|
|
94
109
|
}
|
|
95
110
|
}
|
|
96
111
|
|
|
112
|
+
/**
|
|
113
|
+
* @returns {void}
|
|
114
|
+
*/
|
|
97
115
|
toBeInstanceOf(klass) {
|
|
98
116
|
if (!(this._object instanceof klass)) {
|
|
99
117
|
throw new Error(`Expected ${this._object?.constructor?.name || "null"} to be a ${klass.name} but it wasn't`)
|
|
100
118
|
}
|
|
101
119
|
}
|
|
102
120
|
|
|
121
|
+
/**
|
|
122
|
+
* @returns {void}
|
|
123
|
+
*/
|
|
103
124
|
toBeFalse() {
|
|
104
125
|
this.toBe(false)
|
|
105
126
|
}
|
|
106
127
|
|
|
128
|
+
/**
|
|
129
|
+
* @returns {void}
|
|
130
|
+
*/
|
|
107
131
|
toBeUndefined() {
|
|
108
132
|
this.toBe(undefined)
|
|
109
133
|
}
|
|
110
134
|
|
|
135
|
+
/**
|
|
136
|
+
* @returns {void}
|
|
137
|
+
*/
|
|
111
138
|
toBeTrue() {
|
|
112
139
|
this.toBe(true)
|
|
113
140
|
}
|
|
114
141
|
|
|
142
|
+
/**
|
|
143
|
+
* @param {function(): void} changeCallback
|
|
144
|
+
* @returns {ExpectToChange}
|
|
145
|
+
*/
|
|
115
146
|
toChange(changeCallback) {
|
|
116
147
|
if (this._not) throw new Error("not stub")
|
|
117
148
|
|
|
@@ -122,6 +153,9 @@ class Expect {
|
|
|
122
153
|
return expectToChange
|
|
123
154
|
}
|
|
124
155
|
|
|
156
|
+
/**
|
|
157
|
+
* @returns {void}
|
|
158
|
+
*/
|
|
125
159
|
toContain(valueToContain) {
|
|
126
160
|
if (this._not) throw new Error("not stub")
|
|
127
161
|
|
|
@@ -130,6 +164,9 @@ class Expect {
|
|
|
130
164
|
}
|
|
131
165
|
}
|
|
132
166
|
|
|
167
|
+
/**
|
|
168
|
+
* @returns {void}
|
|
169
|
+
*/
|
|
133
170
|
toEqual(result) {
|
|
134
171
|
if (this._not) {
|
|
135
172
|
if (typeof this._object == "object" && typeof result == "object") {
|
|
@@ -154,6 +191,9 @@ class Expect {
|
|
|
154
191
|
}
|
|
155
192
|
}
|
|
156
193
|
|
|
194
|
+
/**
|
|
195
|
+
* @returns {void}
|
|
196
|
+
*/
|
|
157
197
|
toMatch(regex) {
|
|
158
198
|
const match = this._object.match(regex)
|
|
159
199
|
|
|
@@ -168,6 +208,9 @@ class Expect {
|
|
|
168
208
|
}
|
|
169
209
|
}
|
|
170
210
|
|
|
211
|
+
/**
|
|
212
|
+
* @returns {void}
|
|
213
|
+
*/
|
|
171
214
|
async toThrowError(expectedError) {
|
|
172
215
|
if (this._not) throw new Error("not stub")
|
|
173
216
|
|
|
@@ -218,6 +261,10 @@ class Expect {
|
|
|
218
261
|
return result
|
|
219
262
|
}
|
|
220
263
|
|
|
264
|
+
/**
|
|
265
|
+
* @param {object} result
|
|
266
|
+
* @returns {void}
|
|
267
|
+
*/
|
|
221
268
|
toHaveAttributes(result) {
|
|
222
269
|
if (this._not) throw new Error("not stub")
|
|
223
270
|
|
|
@@ -241,6 +288,10 @@ class Expect {
|
|
|
241
288
|
}
|
|
242
289
|
}
|
|
243
290
|
|
|
291
|
+
/**
|
|
292
|
+
* @param {string} description
|
|
293
|
+
* @returns {void}
|
|
294
|
+
*/
|
|
244
295
|
async function describe(description, arg1, arg2) {
|
|
245
296
|
let testArgs, testFunction
|
|
246
297
|
|
|
@@ -273,10 +324,17 @@ async function describe(description, arg1, arg2) {
|
|
|
273
324
|
}
|
|
274
325
|
}
|
|
275
326
|
|
|
327
|
+
/**
|
|
328
|
+
* @returns {Expect}
|
|
329
|
+
*/
|
|
276
330
|
function expect(arg) {
|
|
277
331
|
return new Expect(arg)
|
|
278
332
|
}
|
|
279
333
|
|
|
334
|
+
/**
|
|
335
|
+
* @param {string} description
|
|
336
|
+
* @returns {void}
|
|
337
|
+
*/
|
|
280
338
|
function it(description, arg1, arg2) {
|
|
281
339
|
const currentTest = currentPath[currentPath.length - 1]
|
|
282
340
|
let testArgs, testFunction
|
|
@@ -296,6 +354,10 @@ function it(description, arg1, arg2) {
|
|
|
296
354
|
currentTest.tests[description] = {args: newTestArgs, function: testFunction}
|
|
297
355
|
}
|
|
298
356
|
|
|
357
|
+
/**
|
|
358
|
+
* @param {string} description
|
|
359
|
+
* @returns {void}
|
|
360
|
+
*/
|
|
299
361
|
function fit(description, arg1, arg2) {
|
|
300
362
|
let testArgs, testFunction
|
|
301
363
|
|
package/src/utils/file-exists.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import fs from "
|
|
1
|
+
import fs from "fs/promises"
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* @param {string} path
|
|
5
|
+
* @returns {boolean}
|
|
6
|
+
*/
|
|
7
|
+
export default async function fileExists(path) {
|
|
4
8
|
try {
|
|
5
9
|
await fs.access(path)
|
|
6
10
|
|
|
7
11
|
return true
|
|
8
|
-
} catch (error) {
|
|
12
|
+
} catch (error) { // eslint-disable-line no-unused-vars
|
|
9
13
|
return false
|
|
10
14
|
}
|
|
11
15
|
}
|
|
12
|
-
|
|
13
|
-
export default fileExists
|