velocious 1.0.429 → 1.0.431
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 +48 -0
- package/build/bin/velocious.js +39 -34
- package/build/index.js +1 -2
- package/build/src/application.js +214 -187
- package/build/src/authorization/ability.d.ts +24 -23
- package/build/src/authorization/ability.d.ts.map +1 -1
- package/build/src/authorization/ability.js +300 -252
- package/build/src/authorization/base-resource.d.ts +20 -26
- package/build/src/authorization/base-resource.d.ts.map +1 -1
- package/build/src/authorization/base-resource.js +136 -118
- package/build/src/background-jobs/client.js +47 -43
- package/build/src/background-jobs/cron-expression.js +166 -127
- package/build/src/background-jobs/forked-runner-child.js +47 -37
- package/build/src/background-jobs/job-record.js +10 -8
- package/build/src/background-jobs/job-registry.js +84 -72
- package/build/src/background-jobs/job-runner.js +81 -74
- package/build/src/background-jobs/job.js +72 -62
- package/build/src/background-jobs/json-socket.js +70 -65
- package/build/src/background-jobs/main.js +900 -841
- package/build/src/background-jobs/normalize-error.js +11 -12
- package/build/src/background-jobs/scheduler.js +247 -205
- package/build/src/background-jobs/socket-request.js +65 -60
- package/build/src/background-jobs/status-reporter.js +96 -86
- package/build/src/background-jobs/store.js +980 -862
- package/build/src/background-jobs/types.js +3 -2
- package/build/src/background-jobs/web/authorization.js +50 -38
- package/build/src/background-jobs/web/controller.js +268 -232
- package/build/src/background-jobs/web/index.js +40 -36
- package/build/src/background-jobs/web/path-matcher.js +48 -45
- package/build/src/background-jobs/web/registry.js +14 -9
- package/build/src/background-jobs/worker.js +639 -585
- package/build/src/beacon/client.js +293 -264
- package/build/src/beacon/in-process-broker.js +25 -20
- package/build/src/beacon/in-process-client.js +116 -104
- package/build/src/beacon/server.js +126 -110
- package/build/src/beacon/types.js +8 -2
- package/build/src/cli/base-command.js +57 -49
- package/build/src/cli/browser-cli.js +42 -37
- package/build/src/cli/commands/background-jobs-main.js +5 -5
- package/build/src/cli/commands/background-jobs-runner.js +5 -5
- package/build/src/cli/commands/background-jobs-worker.js +5 -5
- package/build/src/cli/commands/beacon.js +5 -5
- package/build/src/cli/commands/console.js +10 -10
- package/build/src/cli/commands/db/base-command.js +76 -71
- package/build/src/cli/commands/db/create.js +61 -53
- package/build/src/cli/commands/db/drop.js +71 -62
- package/build/src/cli/commands/db/migrate.js +15 -13
- package/build/src/cli/commands/db/reset.js +19 -16
- package/build/src/cli/commands/db/rollback.js +13 -12
- package/build/src/cli/commands/db/schema/dump.js +9 -9
- package/build/src/cli/commands/db/schema/load.js +9 -9
- package/build/src/cli/commands/db/seed.js +9 -9
- package/build/src/cli/commands/db/tenants/check.js +35 -32
- package/build/src/cli/commands/db/tenants/create.js +29 -26
- package/build/src/cli/commands/db/tenants/migrate.js +44 -40
- package/build/src/cli/commands/destroy/migration.js +5 -5
- package/build/src/cli/commands/generate/base-models.js +5 -5
- package/build/src/cli/commands/generate/frontend-models.js +9 -9
- package/build/src/cli/commands/generate/migration.js +5 -5
- package/build/src/cli/commands/generate/model.js +5 -5
- package/build/src/cli/commands/init.js +9 -7
- package/build/src/cli/commands/routes.js +6 -6
- package/build/src/cli/commands/run-script.js +9 -9
- package/build/src/cli/commands/runner.js +9 -9
- package/build/src/cli/commands/server.js +6 -6
- package/build/src/cli/commands/test.js +7 -6
- package/build/src/cli/index.js +141 -127
- package/build/src/cli/tenant-database-command-helper.js +185 -154
- package/build/src/cli/use-browser-cli.js +20 -15
- package/build/src/configuration-resolver.js +54 -47
- package/build/src/configuration-types.d.ts +21 -2
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +60 -3
- package/build/src/configuration.js +2547 -2240
- package/build/src/controller.js +407 -363
- package/build/src/current-configuration.js +12 -9
- package/build/src/current.js +75 -70
- package/build/src/database/annotations-async-hooks.js +22 -16
- package/build/src/database/annotations.js +18 -12
- package/build/src/database/drivers/base-column.js +179 -155
- package/build/src/database/drivers/base-columns-index.js +78 -69
- package/build/src/database/drivers/base-foreign-key.js +101 -89
- package/build/src/database/drivers/base-table.js +149 -124
- package/build/src/database/drivers/base.js +1489 -1306
- package/build/src/database/drivers/mssql/column.js +50 -39
- package/build/src/database/drivers/mssql/columns-index.js +3 -2
- package/build/src/database/drivers/mssql/connect-connection.js +9 -11
- package/build/src/database/drivers/mssql/foreign-key.js +9 -8
- package/build/src/database/drivers/mssql/index.js +587 -507
- package/build/src/database/drivers/mssql/options.js +75 -68
- package/build/src/database/drivers/mssql/query-parser.js +3 -2
- package/build/src/database/drivers/mssql/sql/alter-table.js +2 -2
- package/build/src/database/drivers/mssql/sql/create-database.js +31 -24
- package/build/src/database/drivers/mssql/sql/create-index.js +2 -2
- package/build/src/database/drivers/mssql/sql/create-table.js +2 -2
- package/build/src/database/drivers/mssql/sql/delete.js +16 -14
- package/build/src/database/drivers/mssql/sql/drop-database.js +31 -24
- package/build/src/database/drivers/mssql/sql/drop-table.js +2 -2
- package/build/src/database/drivers/mssql/sql/insert.js +2 -2
- package/build/src/database/drivers/mssql/sql/update.js +28 -24
- package/build/src/database/drivers/mssql/sql/upsert.js +20 -18
- package/build/src/database/drivers/mssql/structure-sql.js +114 -102
- package/build/src/database/drivers/mssql/table.js +96 -81
- package/build/src/database/drivers/mysql/column.js +92 -75
- package/build/src/database/drivers/mysql/columns-index.js +19 -16
- package/build/src/database/drivers/mysql/foreign-key.js +9 -8
- package/build/src/database/drivers/mysql/index.js +457 -396
- package/build/src/database/drivers/mysql/options.js +30 -26
- package/build/src/database/drivers/mysql/query-parser.js +3 -2
- package/build/src/database/drivers/mysql/query.js +29 -26
- package/build/src/database/drivers/mysql/sql/alter-table.js +3 -2
- package/build/src/database/drivers/mysql/sql/create-database.js +28 -23
- package/build/src/database/drivers/mysql/sql/create-index.js +3 -2
- package/build/src/database/drivers/mysql/sql/create-table.js +3 -2
- package/build/src/database/drivers/mysql/sql/delete.js +17 -14
- package/build/src/database/drivers/mysql/sql/drop-database.js +3 -2
- package/build/src/database/drivers/mysql/sql/drop-table.js +3 -2
- package/build/src/database/drivers/mysql/sql/insert.js +3 -2
- package/build/src/database/drivers/mysql/sql/update.js +29 -24
- package/build/src/database/drivers/mysql/sql/upsert.js +10 -8
- package/build/src/database/drivers/mysql/structure-sql.js +88 -79
- package/build/src/database/drivers/mysql/table.js +98 -83
- package/build/src/database/drivers/pgsql/column.js +72 -56
- package/build/src/database/drivers/pgsql/columns-index.js +3 -2
- package/build/src/database/drivers/pgsql/foreign-key.js +9 -8
- package/build/src/database/drivers/pgsql/index.js +438 -377
- package/build/src/database/drivers/pgsql/options.js +28 -25
- package/build/src/database/drivers/pgsql/query-parser.js +3 -2
- package/build/src/database/drivers/pgsql/sql/alter-table.js +3 -2
- package/build/src/database/drivers/pgsql/sql/create-database.js +23 -19
- package/build/src/database/drivers/pgsql/sql/create-index.js +3 -2
- package/build/src/database/drivers/pgsql/sql/create-table.js +3 -2
- package/build/src/database/drivers/pgsql/sql/delete.js +17 -14
- package/build/src/database/drivers/pgsql/sql/drop-database.js +3 -2
- package/build/src/database/drivers/pgsql/sql/drop-table.js +3 -2
- package/build/src/database/drivers/pgsql/sql/insert.js +3 -2
- package/build/src/database/drivers/pgsql/sql/update.js +29 -24
- package/build/src/database/drivers/pgsql/sql/upsert.js +11 -9
- package/build/src/database/drivers/pgsql/structure-sql.js +120 -108
- package/build/src/database/drivers/pgsql/table.js +77 -60
- package/build/src/database/drivers/sqlite/base.js +478 -405
- package/build/src/database/drivers/sqlite/column.js +69 -54
- package/build/src/database/drivers/sqlite/columns-index.js +27 -22
- package/build/src/database/drivers/sqlite/connection-sql-js.js +42 -35
- package/build/src/database/drivers/sqlite/foreign-key.js +21 -18
- package/build/src/database/drivers/sqlite/index.js +373 -330
- package/build/src/database/drivers/sqlite/index.native.js +64 -55
- package/build/src/database/drivers/sqlite/index.web.js +87 -69
- package/build/src/database/drivers/sqlite/options.js +28 -25
- package/build/src/database/drivers/sqlite/query-parser.js +3 -2
- package/build/src/database/drivers/sqlite/query.js +24 -21
- package/build/src/database/drivers/sqlite/query.native.js +25 -20
- package/build/src/database/drivers/sqlite/query.web.js +37 -30
- package/build/src/database/drivers/sqlite/sql/alter-table.js +179 -159
- package/build/src/database/drivers/sqlite/sql/create-index.js +3 -2
- package/build/src/database/drivers/sqlite/sql/create-table.js +3 -2
- package/build/src/database/drivers/sqlite/sql/delete.js +22 -17
- package/build/src/database/drivers/sqlite/sql/drop-table.js +3 -2
- package/build/src/database/drivers/sqlite/sql/insert.js +3 -2
- package/build/src/database/drivers/sqlite/sql/update.js +29 -24
- package/build/src/database/drivers/sqlite/sql/upsert.js +11 -9
- package/build/src/database/drivers/sqlite/structure-sql.js +52 -49
- package/build/src/database/drivers/sqlite/table-rebuilder.js +75 -62
- package/build/src/database/drivers/sqlite/table.js +125 -102
- package/build/src/database/drivers/structure-sql/utils.js +17 -14
- package/build/src/database/handler.js +10 -9
- package/build/src/database/initializer-from-require-context.js +87 -76
- package/build/src/database/migration/index.js +395 -332
- package/build/src/database/migrator/files-finder.js +50 -40
- package/build/src/database/migrator/types.js +30 -2
- package/build/src/database/migrator.js +526 -454
- package/build/src/database/pool/async-tracked-multi-connection.js +1147 -997
- package/build/src/database/pool/base-methods-forward.js +43 -40
- package/build/src/database/pool/base.js +343 -298
- package/build/src/database/pool/single-multi-use.js +110 -93
- package/build/src/database/query/alter-table-base.js +99 -84
- package/build/src/database/query/base.js +46 -39
- package/build/src/database/query/create-database-base.js +30 -25
- package/build/src/database/query/create-index-base.js +94 -75
- package/build/src/database/query/create-table-base.js +193 -151
- package/build/src/database/query/delete-base.js +16 -14
- package/build/src/database/query/drop-database-base.js +28 -23
- package/build/src/database/query/drop-table-base.js +53 -42
- package/build/src/database/query/from-base.js +33 -30
- package/build/src/database/query/from-plain.js +13 -11
- package/build/src/database/query/from-table.js +15 -13
- package/build/src/database/query/index.js +472 -410
- package/build/src/database/query/insert-base.js +164 -143
- package/build/src/database/query/join-base.js +40 -35
- package/build/src/database/query/join-object.js +153 -128
- package/build/src/database/query/join-plain.js +15 -13
- package/build/src/database/query/join-tracker.js +90 -76
- package/build/src/database/query/model-class-query.js +1370 -1134
- package/build/src/database/query/order-base.js +30 -27
- package/build/src/database/query/order-column.js +53 -44
- package/build/src/database/query/order-plain.js +24 -20
- package/build/src/database/query/preloader/belongs-to.js +258 -210
- package/build/src/database/query/preloader/ensure-model-class-initialized.js +9 -8
- package/build/src/database/query/preloader/has-many.js +301 -240
- package/build/src/database/query/preloader/has-one.js +117 -91
- package/build/src/database/query/preloader/selection.js +129 -117
- package/build/src/database/query/preloader.js +185 -160
- package/build/src/database/query/query-data.js +201 -157
- package/build/src/database/query/select-base.js +27 -25
- package/build/src/database/query/select-plain.js +15 -13
- package/build/src/database/query/select-table-and-column.js +25 -21
- package/build/src/database/query/update-base.js +38 -35
- package/build/src/database/query/upsert-base.js +100 -93
- package/build/src/database/query/where-base.js +35 -32
- package/build/src/database/query/where-combinator.d.ts.map +1 -1
- package/build/src/database/query/where-combinator.js +28 -26
- package/build/src/database/query/where-hash.js +68 -61
- package/build/src/database/query/where-model-class-hash.js +469 -414
- package/build/src/database/query/where-not.js +20 -18
- package/build/src/database/query/where-plain.js +17 -15
- package/build/src/database/query/with-count.js +159 -125
- package/build/src/database/query-parser/base-query-parser.js +37 -32
- package/build/src/database/query-parser/from-parser.js +45 -36
- package/build/src/database/query-parser/group-parser.js +50 -42
- package/build/src/database/query-parser/joins-parser.js +33 -28
- package/build/src/database/query-parser/limit-parser.js +70 -67
- package/build/src/database/query-parser/options.js +82 -75
- package/build/src/database/query-parser/order-parser.js +40 -36
- package/build/src/database/query-parser/select-parser.js +60 -49
- package/build/src/database/query-parser/where-parser.js +41 -36
- package/build/src/database/record/acts-as-list.d.ts.map +1 -1
- package/build/src/database/record/acts-as-list.js +273 -229
- package/build/src/database/record/attachments/download.js +45 -44
- package/build/src/database/record/attachments/handle.js +161 -141
- package/build/src/database/record/attachments/normalize-input.js +138 -128
- package/build/src/database/record/attachments/storage-drivers/filesystem.js +91 -77
- package/build/src/database/record/attachments/storage-drivers/native.js +121 -112
- package/build/src/database/record/attachments/storage-drivers/s3.js +208 -177
- package/build/src/database/record/attachments/store.d.ts +1 -1
- package/build/src/database/record/attachments/store.d.ts.map +1 -1
- package/build/src/database/record/attachments/store.js +540 -468
- package/build/src/database/record/index.d.ts +23 -15
- package/build/src/database/record/index.d.ts.map +1 -1
- package/build/src/database/record/index.js +3894 -3350
- package/build/src/database/record/instance-relationships/base.js +268 -234
- package/build/src/database/record/instance-relationships/belongs-to.js +73 -58
- package/build/src/database/record/instance-relationships/has-many.js +264 -225
- package/build/src/database/record/instance-relationships/has-one.js +105 -85
- package/build/src/database/record/record-not-found-error.js +2 -3
- package/build/src/database/record/relationships/base.d.ts +2 -2
- package/build/src/database/record/relationships/base.d.ts.map +1 -1
- package/build/src/database/record/relationships/base.js +167 -145
- package/build/src/database/record/relationships/belongs-to.js +51 -44
- package/build/src/database/record/relationships/has-many.js +40 -32
- package/build/src/database/record/relationships/has-one.js +40 -32
- package/build/src/database/record/state-machine.js +208 -156
- package/build/src/database/record/user-module.js +38 -32
- package/build/src/database/record/validators/base.js +24 -22
- package/build/src/database/record/validators/format.js +46 -36
- package/build/src/database/record/validators/presence.js +20 -18
- package/build/src/database/record/validators/uniqueness.js +117 -99
- package/build/src/database/table-data/index.js +231 -199
- package/build/src/database/table-data/table-column.js +382 -338
- package/build/src/database/table-data/table-foreign-key.js +66 -57
- package/build/src/database/table-data/table-index.js +36 -29
- package/build/src/database/table-data/table-reference.js +10 -10
- package/build/src/database/use-database.js +40 -32
- package/build/src/environment-handlers/base.js +544 -484
- package/build/src/environment-handlers/browser.js +294 -241
- package/build/src/environment-handlers/node/cli/commands/background-jobs-main.js +19 -16
- package/build/src/environment-handlers/node/cli/commands/background-jobs-runner.js +21 -18
- package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.js +29 -22
- package/build/src/environment-handlers/node/cli/commands/beacon.js +19 -16
- package/build/src/environment-handlers/node/cli/commands/cli-command-context.js +15 -14
- package/build/src/environment-handlers/node/cli/commands/console.js +120 -99
- package/build/src/environment-handlers/node/cli/commands/db/schema/dump.js +39 -34
- package/build/src/environment-handlers/node/cli/commands/db/schema/load.js +63 -57
- package/build/src/environment-handlers/node/cli/commands/db/seed.js +63 -51
- package/build/src/environment-handlers/node/cli/commands/destroy/migration.js +40 -32
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +353 -298
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +844 -729
- package/build/src/environment-handlers/node/cli/commands/generate/migration.js +38 -34
- package/build/src/environment-handlers/node/cli/commands/generate/model.js +38 -34
- package/build/src/environment-handlers/node/cli/commands/init.js +61 -56
- package/build/src/environment-handlers/node/cli/commands/routes.js +59 -51
- package/build/src/environment-handlers/node/cli/commands/run-script.js +68 -54
- package/build/src/environment-handlers/node/cli/commands/runner.js +74 -56
- package/build/src/environment-handlers/node/cli/commands/server.js +106 -93
- package/build/src/environment-handlers/node/cli/commands/test.js +113 -97
- package/build/src/environment-handlers/node.js +874 -753
- package/build/src/error-logger.js +21 -22
- package/build/src/frontend-model-controller.d.ts +6 -6
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +3288 -2788
- package/build/src/frontend-model-resource/base-resource.d.ts +18 -17
- package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/base-resource.js +869 -759
- package/build/src/frontend-models/base.d.ts +19 -12
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +3602 -3114
- package/build/src/frontend-models/clear-pending-debounced-callback.js +8 -7
- package/build/src/frontend-models/event-hook-models.js +21 -16
- package/build/src/frontend-models/model-registry.js +11 -9
- package/build/src/frontend-models/outgoing-event-buffer.js +17 -10
- package/build/src/frontend-models/preloader.d.ts +6 -6
- package/build/src/frontend-models/preloader.d.ts.map +1 -1
- package/build/src/frontend-models/preloader.js +149 -131
- package/build/src/frontend-models/query.d.ts.map +1 -1
- package/build/src/frontend-models/query.js +1855 -1560
- package/build/src/frontend-models/resource-config-validation.js +37 -27
- package/build/src/frontend-models/resource-definition.js +288 -234
- package/build/src/frontend-models/transport-serialization.js +266 -203
- package/build/src/frontend-models/use-created-event.js +7 -5
- package/build/src/frontend-models/use-destroyed-event.js +93 -80
- package/build/src/frontend-models/use-model-class-event.js +91 -79
- package/build/src/frontend-models/use-updated-event.js +97 -84
- package/build/src/frontend-models/websocket-channel.js +441 -381
- package/build/src/frontend-models/websocket-publishers.js +173 -140
- package/build/src/http-client/header.js +14 -13
- package/build/src/http-client/index.js +132 -116
- package/build/src/http-client/request.js +87 -71
- package/build/src/http-client/response.js +140 -122
- package/build/src/http-client/websocket-client.js +17 -15
- package/build/src/http-server/client/index.js +465 -409
- package/build/src/http-server/client/params-to-object.js +135 -124
- package/build/src/http-server/client/request-buffer/form-data-part.js +132 -111
- package/build/src/http-server/client/request-buffer/header.js +16 -15
- package/build/src/http-server/client/request-buffer/index.js +506 -446
- package/build/src/http-server/client/request-parser.js +186 -163
- package/build/src/http-server/client/request-runner.js +259 -226
- package/build/src/http-server/client/request-timing.js +151 -132
- package/build/src/http-server/client/request.js +108 -96
- package/build/src/http-server/client/response.js +235 -213
- package/build/src/http-server/client/uploaded-file/memory-uploaded-file.js +29 -25
- package/build/src/http-server/client/uploaded-file/temporary-uploaded-file.js +29 -25
- package/build/src/http-server/client/uploaded-file/uploaded-file.js +33 -33
- package/build/src/http-server/client/websocket-request.js +137 -114
- package/build/src/http-server/client/websocket-session.js +1657 -1452
- package/build/src/http-server/cookie.js +236 -216
- package/build/src/http-server/development-reloader.js +221 -190
- package/build/src/http-server/index.js +525 -451
- package/build/src/http-server/remote-address.js +50 -38
- package/build/src/http-server/server-client.js +208 -181
- package/build/src/http-server/server-lock.js +167 -153
- package/build/src/http-server/websocket-channel-subscribers.js +93 -81
- package/build/src/http-server/websocket-channel.js +117 -104
- package/build/src/http-server/websocket-connection.js +104 -96
- package/build/src/http-server/websocket-event-log-store.js +404 -350
- package/build/src/http-server/websocket-events-host.js +164 -145
- package/build/src/http-server/websocket-events.js +47 -47
- package/build/src/http-server/worker-handler/channel-subscriber-dispatch.js +14 -13
- package/build/src/http-server/worker-handler/in-process.js +141 -123
- package/build/src/http-server/worker-handler/index.js +349 -313
- package/build/src/http-server/worker-handler/worker-script.js +5 -4
- package/build/src/http-server/worker-handler/worker-thread.js +269 -240
- package/build/src/initializer.js +36 -31
- package/build/src/jobs/mail-delivery.js +15 -13
- package/build/src/logger/base-logger.js +26 -24
- package/build/src/logger/console-logger.js +23 -21
- package/build/src/logger/file-logger.js +31 -29
- package/build/src/logger/outputs/array-output.js +42 -37
- package/build/src/logger/outputs/console-output.js +24 -20
- package/build/src/logger/outputs/file-output.js +48 -43
- package/build/src/logger/outputs/stdout-output.js +48 -39
- package/build/src/logger.js +394 -338
- package/build/src/mailer/backends/smtp.js +163 -134
- package/build/src/mailer/base.js +251 -211
- package/build/src/mailer/delivery.js +64 -56
- package/build/src/mailer/index.js +22 -4
- package/build/src/mailer.js +13 -4
- package/build/src/plugins/sqljs-wasm-route-controller.js +52 -42
- package/build/src/plugins/sqljs-wasm-route.js +38 -28
- package/build/src/record-payload-values.js +28 -25
- package/build/src/routes/app-routes.js +14 -12
- package/build/src/routes/base-route.js +130 -112
- package/build/src/routes/basic-route.js +102 -83
- package/build/src/routes/built-in/debug/controller.js +10 -10
- package/build/src/routes/built-in/errors/controller.js +5 -5
- package/build/src/routes/get-route.js +63 -50
- package/build/src/routes/hooks/frontend-model-command-route-hook.js +80 -66
- package/build/src/routes/index.js +43 -36
- package/build/src/routes/namespace-route.js +47 -38
- package/build/src/routes/plugin-routes.js +124 -107
- package/build/src/routes/post-route.js +62 -51
- package/build/src/routes/resolver.js +494 -422
- package/build/src/routes/resource-route.js +143 -124
- package/build/src/routes/root-route.js +8 -7
- package/build/src/testing/base-expect.js +14 -13
- package/build/src/testing/browser-frontend-model-event-hook-scenarios.js +405 -329
- package/build/src/testing/browser-test-app.js +29 -23
- package/build/src/testing/expect-to-change.js +50 -41
- package/build/src/testing/expect-utils.js +184 -139
- package/build/src/testing/expect.js +731 -638
- package/build/src/testing/request-client.js +85 -70
- package/build/src/testing/test-files-finder.js +339 -285
- package/build/src/testing/test-filter-parser.js +155 -124
- package/build/src/testing/test-runner.js +1020 -883
- package/build/src/testing/test-suite-splitter.js +142 -114
- package/build/src/testing/test.js +256 -216
- package/build/src/utils/backtrace-cleaner-node.js +69 -62
- package/build/src/utils/backtrace-cleaner.js +216 -188
- package/build/src/utils/ensure-error.js +7 -7
- package/build/src/utils/event-emitter.js +6 -4
- package/build/src/utils/file-exists.js +10 -9
- package/build/src/utils/format-value.js +76 -67
- package/build/src/utils/model-scope.js +31 -27
- package/build/src/utils/nest-callbacks.js +13 -10
- package/build/src/utils/plain-object.js +6 -5
- package/build/src/utils/ransack.d.ts.map +1 -1
- package/build/src/utils/ransack.js +563 -449
- package/build/src/utils/rest-args-error.js +6 -5
- package/build/src/utils/singularize-model-name.js +11 -9
- package/build/src/utils/split-sql-statements.js +79 -68
- package/build/src/utils/to-import-specifier.js +30 -24
- package/build/src/utils/with-tracked-stack-async-hooks.js +74 -60
- package/build/src/utils/with-tracked-stack.js +18 -14
- package/build/src/velocious-error.js +30 -27
- package/index.js +1 -0
- package/package.json +10 -4
- package/scripts/clean-build.js +8 -0
- package/scripts/ensure-bin-executable.js +13 -0
- package/scripts/run-tests.js +37 -0
- package/scripts/test-browser.js +486 -0
- package/src/application.js +229 -0
- package/src/authorization/ability.js +329 -0
- package/src/authorization/base-resource.js +143 -0
- package/src/background-jobs/client.js +50 -0
- package/src/background-jobs/cron-expression.js +277 -0
- package/src/background-jobs/forked-runner-child.js +86 -0
- package/src/background-jobs/job-record.js +13 -0
- package/src/background-jobs/job-registry.js +92 -0
- package/src/background-jobs/job-runner.js +107 -0
- package/src/background-jobs/job.js +77 -0
- package/src/background-jobs/json-socket.js +78 -0
- package/src/background-jobs/main.js +926 -0
- package/src/background-jobs/normalize-error.js +26 -0
- package/src/background-jobs/scheduler.js +274 -0
- package/src/background-jobs/socket-request.js +68 -0
- package/src/background-jobs/status-reporter.js +101 -0
- package/src/background-jobs/store.js +994 -0
- package/src/background-jobs/types.js +70 -0
- package/src/background-jobs/web/authorization.js +89 -0
- package/src/background-jobs/web/controller.js +280 -0
- package/src/background-jobs/web/index.js +57 -0
- package/src/background-jobs/web/path-matcher.js +74 -0
- package/src/background-jobs/web/registry.js +49 -0
- package/src/background-jobs/worker.js +683 -0
- package/src/beacon/client.js +330 -0
- package/src/beacon/in-process-broker.js +71 -0
- package/src/beacon/in-process-client.js +139 -0
- package/src/beacon/server.js +148 -0
- package/src/beacon/types.js +55 -0
- package/src/cli/base-command.js +67 -0
- package/src/cli/browser-cli.js +45 -0
- package/src/cli/commands/background-jobs-main.js +7 -0
- package/src/cli/commands/background-jobs-runner.js +7 -0
- package/src/cli/commands/background-jobs-worker.js +7 -0
- package/src/cli/commands/beacon.js +7 -0
- package/src/cli/commands/console.js +12 -0
- package/src/cli/commands/db/base-command.js +82 -0
- package/src/cli/commands/db/create.js +64 -0
- package/src/cli/commands/db/drop.js +75 -0
- package/src/cli/commands/db/migrate.js +17 -0
- package/src/cli/commands/db/reset.js +22 -0
- package/src/cli/commands/db/rollback.js +15 -0
- package/src/cli/commands/db/schema/dump.js +12 -0
- package/src/cli/commands/db/schema/load.js +12 -0
- package/src/cli/commands/db/seed.js +12 -0
- package/src/cli/commands/db/tenants/check.js +38 -0
- package/src/cli/commands/db/tenants/create.js +33 -0
- package/src/cli/commands/db/tenants/migrate.js +49 -0
- package/src/cli/commands/destroy/migration.js +7 -0
- package/src/cli/commands/generate/base-models.js +7 -0
- package/src/cli/commands/generate/frontend-models.js +12 -0
- package/src/cli/commands/generate/migration.js +7 -0
- package/src/cli/commands/generate/model.js +7 -0
- package/src/cli/commands/init.js +11 -0
- package/src/cli/commands/routes.js +7 -0
- package/src/cli/commands/run-script.js +12 -0
- package/src/cli/commands/runner.js +12 -0
- package/src/cli/commands/server.js +7 -0
- package/src/cli/commands/test.js +9 -0
- package/src/cli/index.js +152 -0
- package/src/cli/tenant-database-command-helper.js +198 -0
- package/src/cli/use-browser-cli.js +30 -0
- package/src/configuration-resolver.js +65 -0
- package/src/configuration-types.js +429 -0
- package/src/configuration.js +2590 -0
- package/src/controller.js +421 -0
- package/src/current-configuration.js +31 -0
- package/src/current.js +80 -0
- package/src/database/annotations-async-hooks.js +47 -0
- package/src/database/annotations.js +40 -0
- package/src/database/drivers/base-column.js +182 -0
- package/src/database/drivers/base-columns-index.js +81 -0
- package/src/database/drivers/base-foreign-key.js +104 -0
- package/src/database/drivers/base-table.js +156 -0
- package/src/database/drivers/base.js +1609 -0
- package/src/database/drivers/mssql/column.js +74 -0
- package/src/database/drivers/mssql/columns-index.js +6 -0
- package/src/database/drivers/mssql/connect-connection.js +16 -0
- package/src/database/drivers/mssql/foreign-key.js +12 -0
- package/src/database/drivers/mssql/index.js +590 -0
- package/src/database/drivers/mssql/options.js +79 -0
- package/src/database/drivers/mssql/query-parser.js +6 -0
- package/src/database/drivers/mssql/sql/alter-table.js +4 -0
- package/src/database/drivers/mssql/sql/create-database.js +36 -0
- package/src/database/drivers/mssql/sql/create-index.js +4 -0
- package/src/database/drivers/mssql/sql/create-table.js +4 -0
- package/src/database/drivers/mssql/sql/delete.js +19 -0
- package/src/database/drivers/mssql/sql/drop-database.js +36 -0
- package/src/database/drivers/mssql/sql/drop-table.js +4 -0
- package/src/database/drivers/mssql/sql/insert.js +4 -0
- package/src/database/drivers/mssql/sql/update.js +31 -0
- package/src/database/drivers/mssql/sql/upsert.js +23 -0
- package/src/database/drivers/mssql/structure-sql.js +120 -0
- package/src/database/drivers/mssql/table.js +145 -0
- package/src/database/drivers/mysql/column.js +112 -0
- package/src/database/drivers/mysql/columns-index.js +22 -0
- package/src/database/drivers/mysql/foreign-key.js +12 -0
- package/src/database/drivers/mysql/index.js +473 -0
- package/src/database/drivers/mysql/options.js +34 -0
- package/src/database/drivers/mysql/query-parser.js +6 -0
- package/src/database/drivers/mysql/query.js +37 -0
- package/src/database/drivers/mysql/sql/alter-table.js +6 -0
- package/src/database/drivers/mysql/sql/create-database.js +39 -0
- package/src/database/drivers/mysql/sql/create-index.js +6 -0
- package/src/database/drivers/mysql/sql/create-table.js +6 -0
- package/src/database/drivers/mysql/sql/delete.js +21 -0
- package/src/database/drivers/mysql/sql/drop-database.js +6 -0
- package/src/database/drivers/mysql/sql/drop-table.js +6 -0
- package/src/database/drivers/mysql/sql/insert.js +6 -0
- package/src/database/drivers/mysql/sql/update.js +33 -0
- package/src/database/drivers/mysql/sql/upsert.js +13 -0
- package/src/database/drivers/mysql/structure-sql.js +93 -0
- package/src/database/drivers/mysql/table.js +121 -0
- package/src/database/drivers/pgsql/column.js +90 -0
- package/src/database/drivers/pgsql/columns-index.js +6 -0
- package/src/database/drivers/pgsql/foreign-key.js +12 -0
- package/src/database/drivers/pgsql/index.js +441 -0
- package/src/database/drivers/pgsql/options.js +32 -0
- package/src/database/drivers/pgsql/query-parser.js +6 -0
- package/src/database/drivers/pgsql/sql/alter-table.js +6 -0
- package/src/database/drivers/pgsql/sql/create-database.js +38 -0
- package/src/database/drivers/pgsql/sql/create-index.js +6 -0
- package/src/database/drivers/pgsql/sql/create-table.js +6 -0
- package/src/database/drivers/pgsql/sql/delete.js +21 -0
- package/src/database/drivers/pgsql/sql/drop-database.js +6 -0
- package/src/database/drivers/pgsql/sql/drop-table.js +6 -0
- package/src/database/drivers/pgsql/sql/insert.js +6 -0
- package/src/database/drivers/pgsql/sql/update.js +33 -0
- package/src/database/drivers/pgsql/sql/upsert.js +14 -0
- package/src/database/drivers/pgsql/structure-sql.js +126 -0
- package/src/database/drivers/pgsql/table.js +135 -0
- package/src/database/drivers/sqlite/base.js +509 -0
- package/src/database/drivers/sqlite/column.js +75 -0
- package/src/database/drivers/sqlite/columns-index.js +30 -0
- package/src/database/drivers/sqlite/connection-sql-js.js +46 -0
- package/src/database/drivers/sqlite/foreign-key.js +24 -0
- package/src/database/drivers/sqlite/index.js +394 -0
- package/src/database/drivers/sqlite/index.native.js +72 -0
- package/src/database/drivers/sqlite/index.web.js +99 -0
- package/src/database/drivers/sqlite/options.js +32 -0
- package/src/database/drivers/sqlite/query-parser.js +6 -0
- package/src/database/drivers/sqlite/query.js +35 -0
- package/src/database/drivers/sqlite/query.native.js +35 -0
- package/src/database/drivers/sqlite/query.web.js +49 -0
- package/src/database/drivers/sqlite/sql/alter-table.js +187 -0
- package/src/database/drivers/sqlite/sql/create-index.js +6 -0
- package/src/database/drivers/sqlite/sql/create-table.js +6 -0
- package/src/database/drivers/sqlite/sql/delete.js +26 -0
- package/src/database/drivers/sqlite/sql/drop-table.js +6 -0
- package/src/database/drivers/sqlite/sql/insert.js +6 -0
- package/src/database/drivers/sqlite/sql/update.js +33 -0
- package/src/database/drivers/sqlite/sql/upsert.js +14 -0
- package/src/database/drivers/sqlite/structure-sql.js +56 -0
- package/src/database/drivers/sqlite/table-rebuilder.js +96 -0
- package/src/database/drivers/sqlite/table.js +131 -0
- package/src/database/drivers/structure-sql/utils.js +35 -0
- package/src/database/handler.js +13 -0
- package/src/database/initializer-from-require-context.js +101 -0
- package/src/database/migration/index.js +438 -0
- package/src/database/migrator/files-finder.js +55 -0
- package/src/database/migrator/types.js +31 -0
- package/src/database/migrator.js +557 -0
- package/src/database/pool/async-tracked-multi-connection.js +1164 -0
- package/src/database/pool/base-methods-forward.js +52 -0
- package/src/database/pool/base.js +380 -0
- package/src/database/pool/single-multi-use.js +118 -0
- package/src/database/query/alter-table-base.js +104 -0
- package/src/database/query/base.js +49 -0
- package/src/database/query/create-database-base.js +42 -0
- package/src/database/query/create-index-base.js +117 -0
- package/src/database/query/create-table-base.js +205 -0
- package/src/database/query/delete-base.js +19 -0
- package/src/database/query/drop-database-base.js +38 -0
- package/src/database/query/drop-table-base.js +58 -0
- package/src/database/query/from-base.js +36 -0
- package/src/database/query/from-plain.js +16 -0
- package/src/database/query/from-table.js +18 -0
- package/src/database/query/index.js +533 -0
- package/src/database/query/insert-base.js +172 -0
- package/src/database/query/join-base.js +43 -0
- package/src/database/query/join-object.js +167 -0
- package/src/database/query/join-plain.js +18 -0
- package/src/database/query/join-tracker.js +93 -0
- package/src/database/query/model-class-query.js +1577 -0
- package/src/database/query/order-base.js +33 -0
- package/src/database/query/order-column.js +77 -0
- package/src/database/query/order-plain.js +28 -0
- package/src/database/query/preloader/belongs-to.js +267 -0
- package/src/database/query/preloader/ensure-model-class-initialized.js +18 -0
- package/src/database/query/preloader/has-many.js +316 -0
- package/src/database/query/preloader/has-one.js +123 -0
- package/src/database/query/preloader/selection.js +152 -0
- package/src/database/query/preloader.js +201 -0
- package/src/database/query/query-data.js +305 -0
- package/src/database/query/select-base.js +30 -0
- package/src/database/query/select-plain.js +18 -0
- package/src/database/query/select-table-and-column.js +28 -0
- package/src/database/query/update-base.js +41 -0
- package/src/database/query/upsert-base.js +103 -0
- package/src/database/query/where-base.js +38 -0
- package/src/database/query/where-combinator.js +31 -0
- package/src/database/query/where-hash.js +77 -0
- package/src/database/query/where-model-class-hash.js +505 -0
- package/src/database/query/where-not.js +23 -0
- package/src/database/query/where-plain.js +20 -0
- package/src/database/query/with-count.js +219 -0
- package/src/database/query-parser/base-query-parser.js +40 -0
- package/src/database/query-parser/from-parser.js +49 -0
- package/src/database/query-parser/group-parser.js +55 -0
- package/src/database/query-parser/joins-parser.js +37 -0
- package/src/database/query-parser/limit-parser.js +77 -0
- package/src/database/query-parser/options.js +94 -0
- package/src/database/query-parser/order-parser.js +45 -0
- package/src/database/query-parser/select-parser.js +67 -0
- package/src/database/query-parser/where-parser.js +46 -0
- package/src/database/record/acts-as-list.js +374 -0
- package/src/database/record/attachments/download.js +49 -0
- package/src/database/record/attachments/handle.js +188 -0
- package/src/database/record/attachments/normalize-input.js +213 -0
- package/src/database/record/attachments/storage-drivers/filesystem.js +114 -0
- package/src/database/record/attachments/storage-drivers/native.js +146 -0
- package/src/database/record/attachments/storage-drivers/s3.js +245 -0
- package/src/database/record/attachments/store.js +591 -0
- package/src/database/record/index.js +3970 -0
- package/src/database/record/instance-relationships/base.js +289 -0
- package/src/database/record/instance-relationships/belongs-to.js +84 -0
- package/src/database/record/instance-relationships/has-many.js +284 -0
- package/src/database/record/instance-relationships/has-one.js +117 -0
- package/src/database/record/record-not-found-error.js +3 -0
- package/src/database/record/relationships/base.js +195 -0
- package/src/database/record/relationships/belongs-to.js +57 -0
- package/src/database/record/relationships/has-many.js +46 -0
- package/src/database/record/relationships/has-one.js +46 -0
- package/src/database/record/state-machine.js +278 -0
- package/src/database/record/user-module.js +43 -0
- package/src/database/record/validators/base.js +27 -0
- package/src/database/record/validators/format.js +50 -0
- package/src/database/record/validators/presence.js +24 -0
- package/src/database/record/validators/uniqueness.js +124 -0
- package/src/database/table-data/index.js +241 -0
- package/src/database/table-data/table-column.js +416 -0
- package/src/database/table-data/table-foreign-key.js +69 -0
- package/src/database/table-data/table-index.js +46 -0
- package/src/database/table-data/table-reference.js +13 -0
- package/src/database/use-database.js +48 -0
- package/src/environment-handlers/base.js +561 -0
- package/src/environment-handlers/browser.js +338 -0
- package/src/environment-handlers/node/cli/commands/background-jobs-main.js +21 -0
- package/src/environment-handlers/node/cli/commands/background-jobs-runner.js +24 -0
- package/src/environment-handlers/node/cli/commands/background-jobs-worker.js +47 -0
- package/src/environment-handlers/node/cli/commands/beacon.js +21 -0
- package/src/environment-handlers/node/cli/commands/cli-command-context.js +31 -0
- package/src/environment-handlers/node/cli/commands/console.js +149 -0
- package/src/environment-handlers/node/cli/commands/db/schema/dump.js +43 -0
- package/src/environment-handlers/node/cli/commands/db/schema/load.js +69 -0
- package/src/environment-handlers/node/cli/commands/db/seed.js +79 -0
- package/src/environment-handlers/node/cli/commands/destroy/migration.js +47 -0
- package/src/environment-handlers/node/cli/commands/generate/base-models.js +367 -0
- package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +872 -0
- package/src/environment-handlers/node/cli/commands/generate/migration.js +45 -0
- package/src/environment-handlers/node/cli/commands/generate/model.js +45 -0
- package/src/environment-handlers/node/cli/commands/init.js +68 -0
- package/src/environment-handlers/node/cli/commands/routes.js +63 -0
- package/src/environment-handlers/node/cli/commands/run-script.js +85 -0
- package/src/environment-handlers/node/cli/commands/runner.js +84 -0
- package/src/environment-handlers/node/cli/commands/server.js +151 -0
- package/src/environment-handlers/node/cli/commands/test.js +118 -0
- package/src/environment-handlers/node.js +887 -0
- package/src/error-logger.js +30 -0
- package/src/frontend-model-controller.js +3491 -0
- package/src/frontend-model-resource/base-resource.js +935 -0
- package/src/frontend-models/base.js +4004 -0
- package/src/frontend-models/clear-pending-debounced-callback.js +16 -0
- package/src/frontend-models/event-hook-models.js +49 -0
- package/src/frontend-models/model-registry.js +28 -0
- package/src/frontend-models/outgoing-event-buffer.js +51 -0
- package/src/frontend-models/preloader.js +169 -0
- package/src/frontend-models/query.js +2245 -0
- package/src/frontend-models/resource-config-validation.js +56 -0
- package/src/frontend-models/resource-definition.js +399 -0
- package/src/frontend-models/transport-serialization.js +369 -0
- package/src/frontend-models/use-created-event.js +21 -0
- package/src/frontend-models/use-destroyed-event.js +148 -0
- package/src/frontend-models/use-model-class-event.js +164 -0
- package/src/frontend-models/use-updated-event.js +152 -0
- package/src/frontend-models/websocket-channel.js +494 -0
- package/src/frontend-models/websocket-publishers.js +224 -0
- package/src/http-client/header.js +17 -0
- package/src/http-client/index.js +139 -0
- package/src/http-client/request.js +94 -0
- package/src/http-client/response.js +151 -0
- package/src/http-client/websocket-client.js +27 -0
- package/src/http-server/client/index.js +507 -0
- package/src/http-server/client/params-to-object.js +152 -0
- package/src/http-server/client/request-buffer/form-data-part.js +139 -0
- package/src/http-server/client/request-buffer/header.js +19 -0
- package/src/http-server/client/request-buffer/index.js +535 -0
- package/src/http-server/client/request-parser.js +195 -0
- package/src/http-server/client/request-runner.js +321 -0
- package/src/http-server/client/request-timing.js +171 -0
- package/src/http-server/client/request.js +114 -0
- package/src/http-server/client/response.js +251 -0
- package/src/http-server/client/uploaded-file/memory-uploaded-file.js +32 -0
- package/src/http-server/client/uploaded-file/temporary-uploaded-file.js +32 -0
- package/src/http-server/client/uploaded-file/uploaded-file.js +36 -0
- package/src/http-server/client/websocket-request.js +147 -0
- package/src/http-server/client/websocket-session.js +1755 -0
- package/src/http-server/cookie.js +245 -0
- package/src/http-server/development-reloader.js +240 -0
- package/src/http-server/index.js +561 -0
- package/src/http-server/remote-address.js +77 -0
- package/src/http-server/server-client.js +222 -0
- package/src/http-server/server-lock.js +178 -0
- package/src/http-server/websocket-channel-subscribers.js +110 -0
- package/src/http-server/websocket-channel.js +137 -0
- package/src/http-server/websocket-connection.js +118 -0
- package/src/http-server/websocket-event-log-store.js +433 -0
- package/src/http-server/websocket-events-host.js +170 -0
- package/src/http-server/websocket-events.js +50 -0
- package/src/http-server/worker-handler/channel-subscriber-dispatch.js +28 -0
- package/src/http-server/worker-handler/in-process.js +155 -0
- package/src/http-server/worker-handler/index.js +370 -0
- package/src/http-server/worker-handler/worker-script.js +6 -0
- package/src/http-server/worker-handler/worker-thread.js +286 -0
- package/src/initializer.js +39 -0
- package/src/jobs/.gitkeep +1 -0
- package/src/jobs/mail-delivery.js +22 -0
- package/src/logger/base-logger.js +34 -0
- package/src/logger/console-logger.js +28 -0
- package/src/logger/file-logger.js +36 -0
- package/src/logger/outputs/array-output.js +50 -0
- package/src/logger/outputs/console-output.js +32 -0
- package/src/logger/outputs/file-output.js +55 -0
- package/src/logger/outputs/stdout-output.js +64 -0
- package/src/logger.js +507 -0
- package/src/mailer/backends/smtp.js +197 -0
- package/src/mailer/base.js +337 -0
- package/src/mailer/delivery.js +70 -0
- package/src/mailer/index.js +24 -0
- package/src/mailer.js +15 -0
- package/src/plugins/sqljs-wasm-route-controller.js +70 -0
- package/src/plugins/sqljs-wasm-route.js +71 -0
- package/src/record-payload-values.js +83 -0
- package/src/routes/app-routes.js +17 -0
- package/src/routes/base-route.js +133 -0
- package/src/routes/basic-route.js +109 -0
- package/src/routes/built-in/debug/controller.js +12 -0
- package/src/routes/built-in/errors/controller.js +7 -0
- package/src/routes/built-in/errors/not-found.ejs +1 -0
- package/src/routes/get-route.js +75 -0
- package/src/routes/hooks/frontend-model-command-route-hook.js +100 -0
- package/src/routes/index.js +50 -0
- package/src/routes/namespace-route.js +51 -0
- package/src/routes/plugin-routes.js +141 -0
- package/src/routes/post-route.js +74 -0
- package/src/routes/resolver.js +535 -0
- package/src/routes/resource-route.js +154 -0
- package/src/routes/root-route.js +11 -0
- package/src/templates/configuration.js +61 -0
- package/src/templates/generate-migration.js +11 -0
- package/src/templates/generate-model.js +6 -0
- package/src/templates/routes.js +11 -0
- package/src/testing/base-expect.js +17 -0
- package/src/testing/browser-frontend-model-event-hook-scenarios.js +520 -0
- package/src/testing/browser-test-app.js +32 -0
- package/src/testing/expect-to-change.js +55 -0
- package/src/testing/expect-utils.js +269 -0
- package/src/testing/expect.js +763 -0
- package/src/testing/request-client.js +90 -0
- package/src/testing/test-files-finder.js +364 -0
- package/src/testing/test-filter-parser.js +198 -0
- package/src/testing/test-runner.js +1168 -0
- package/src/testing/test-suite-splitter.js +177 -0
- package/src/testing/test.js +370 -0
- package/src/types/external-modules.d.ts +57 -0
- package/src/utils/backtrace-cleaner-node.js +87 -0
- package/src/utils/backtrace-cleaner.js +266 -0
- package/src/utils/ensure-error.js +15 -0
- package/src/utils/event-emitter.js +8 -0
- package/src/utils/file-exists.js +18 -0
- package/src/utils/format-value.js +101 -0
- package/src/utils/model-scope.js +56 -0
- package/src/utils/nest-callbacks.js +22 -0
- package/src/utils/plain-object.js +14 -0
- package/src/utils/ransack.js +859 -0
- package/src/utils/rest-args-error.js +14 -0
- package/src/utils/singularize-model-name.js +18 -0
- package/src/utils/split-sql-statements.js +88 -0
- package/src/utils/to-import-specifier.js +53 -0
- package/src/utils/with-tracked-stack-async-hooks.js +103 -0
- package/src/utils/with-tracked-stack.js +38 -0
- package/src/velocious-error.js +34 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,1168 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import {addTrackedStackToError} from "../utils/with-tracked-stack.js"
|
|
4
|
+
import fs from "node:fs/promises"
|
|
5
|
+
import path from "path"
|
|
6
|
+
import {format} from "node:util"
|
|
7
|
+
import Application from "../../src/application.js"
|
|
8
|
+
import BacktraceCleaner from "../utils/backtrace-cleaner-node.js"
|
|
9
|
+
import RequestClient from "./request-client.js"
|
|
10
|
+
import picocolors from "picocolors"
|
|
11
|
+
import restArgsError from "../utils/rest-args-error.js"
|
|
12
|
+
import {testConfig, testEvents, tests} from "./test.js"
|
|
13
|
+
import {pathToFileURL} from "url"
|
|
14
|
+
import {clearDeliveries} from "../mailer.js"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Runs run with timeout.
|
|
18
|
+
* @param {Promise<?> | ?} promise - Promise or value.
|
|
19
|
+
* @param {number} timeoutMs - Timeout in milliseconds.
|
|
20
|
+
* @param {string} testDescription - Test description.
|
|
21
|
+
* @returns {Promise<?>} - Resolves or rejects based on timeout or promise result.
|
|
22
|
+
*/
|
|
23
|
+
function runWithTimeout(promise, timeoutMs, testDescription) {
|
|
24
|
+
const timeoutSeconds = (timeoutMs / 1000).toFixed(3).replace(/\.?0+$/, "")
|
|
25
|
+
const timeoutError = new Error(`Timed out after ${timeoutSeconds}s: ${testDescription}`)
|
|
26
|
+
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
const timeout = setTimeout(() => reject(timeoutError), timeoutMs)
|
|
29
|
+
|
|
30
|
+
Promise.resolve(promise).then((result) => {
|
|
31
|
+
clearTimeout(timeout)
|
|
32
|
+
resolve(result)
|
|
33
|
+
}).catch((error) => {
|
|
34
|
+
clearTimeout(timeout)
|
|
35
|
+
reject(error)
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* ConsoleMethodName type.
|
|
42
|
+
@typedef {"log" | "info" | "warn" | "error" | "debug"} ConsoleMethodName */
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Captured console methods.
|
|
46
|
+
@type {ConsoleMethodName[]} */
|
|
47
|
+
const CAPTURED_CONSOLE_METHODS = ["log", "info", "warn", "error", "debug"]
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* AttemptConsoleOutput type.
|
|
51
|
+
* @typedef {object} AttemptConsoleOutput
|
|
52
|
+
* @property {number} attemptNumber - Attempt number.
|
|
53
|
+
* @property {string} output - Captured console output.
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Runs to file slug.
|
|
58
|
+
* @param {string} value - Value to sanitize.
|
|
59
|
+
* @returns {string} - Slug-safe value.
|
|
60
|
+
*/
|
|
61
|
+
function toFileSlug(value) {
|
|
62
|
+
return value
|
|
63
|
+
.toLowerCase()
|
|
64
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
65
|
+
.replace(/^-+|-+$/g, "")
|
|
66
|
+
.slice(0, 80) || "failed-test"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* TestArgs type.
|
|
71
|
+
* @typedef {object} TestArgs
|
|
72
|
+
* @property {Application} [application] - Application instance for integration tests.
|
|
73
|
+
* @property {RequestClient} [client] - HTTP client for request tests.
|
|
74
|
+
* @property {object} [databaseCleaning] - Database cleanup options for tests.
|
|
75
|
+
* @property {boolean} [databaseCleaning.transaction] - Use transactions to rollback between tests.
|
|
76
|
+
* @property {boolean} [databaseCleaning.truncate] - Truncate tables between tests.
|
|
77
|
+
* @property {boolean} [focus] - Whether this test is focused.
|
|
78
|
+
* @property {() => (void|Promise<void>)} [function] - Test callback function.
|
|
79
|
+
* @property {number} [retry] - Number of retries when a test fails.
|
|
80
|
+
* @property {string[] | string} [tags] - Tags for filtering.
|
|
81
|
+
* @property {number} [timeoutSeconds] - Timeout in seconds for the test.
|
|
82
|
+
* @property {string} [type] - Test type identifier.
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* TestData type.
|
|
87
|
+
* @typedef {object} TestData
|
|
88
|
+
* @property {TestArgs} args - Arguments passed to the test.
|
|
89
|
+
* @property {string} [filePath] - Source file path.
|
|
90
|
+
* @property {number} [line] - Source line number.
|
|
91
|
+
* @property {function(TestArgs) : (void|Promise<void>)} function - Test callback to execute.
|
|
92
|
+
*/
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* FailedTestDetail type.
|
|
96
|
+
* @typedef {object} FailedTestDetail
|
|
97
|
+
* @property {string} fullDescription - Full test description.
|
|
98
|
+
* @property {string} [filePath] - Source file path.
|
|
99
|
+
* @property {number} [line] - Source line number.
|
|
100
|
+
* @property {?} error - Failure error.
|
|
101
|
+
* @property {string} [consoleOutput] - Captured console output while test ran.
|
|
102
|
+
* @property {string} [consoleLogPath] - Saved console log path.
|
|
103
|
+
*/
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* ActiveAfterAllScopeEntry type.
|
|
107
|
+
* @typedef {object} ActiveAfterAllScopeEntry
|
|
108
|
+
* @property {TestsArgument} tests - Scope test tree.
|
|
109
|
+
* @property {boolean} afterAllsRun - Whether cleanup hooks have run.
|
|
110
|
+
*/
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Defines this typedef.
|
|
114
|
+
* @typedef {function({configuration: import("../configuration.js").default, testArgs: TestArgs, testData: TestData}) : (void|Promise<void>)} AfterBeforeEachCallbackType
|
|
115
|
+
*/
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* AfterBeforeEachCallbackObjectType type.
|
|
119
|
+
* @typedef {object} AfterBeforeEachCallbackObjectType
|
|
120
|
+
* @property {AfterBeforeEachCallbackType} callback - Hook callback to execute.
|
|
121
|
+
*/
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Defines this typedef.
|
|
125
|
+
* @typedef {function({configuration: import("../configuration.js").default}) : (void|Promise<void>)} BeforeAfterAllCallbackType
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* BeforeAfterAllCallbackObjectType type.
|
|
130
|
+
* @typedef {object} BeforeAfterAllCallbackObjectType
|
|
131
|
+
* @property {BeforeAfterAllCallbackType} callback - Hook callback to execute.
|
|
132
|
+
*/
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* TestsArgument type.
|
|
136
|
+
* @typedef {object} TestsArgument
|
|
137
|
+
* @property {Record<string, TestData>} args - Arguments keyed by test description.
|
|
138
|
+
* @property {boolean} [anyTestsFocussed] - Whether any tests in the tree are focused.
|
|
139
|
+
* @property {AfterBeforeEachCallbackObjectType[]} afterEaches - After-each hooks for this scope.
|
|
140
|
+
* @property {BeforeAfterAllCallbackObjectType[]} afterAlls - After-all hooks for this scope.
|
|
141
|
+
* @property {BeforeAfterAllCallbackObjectType[]} beforeAlls - Before-all hooks for this scope.
|
|
142
|
+
* @property {AfterBeforeEachCallbackObjectType[]} beforeEaches - Before-each hooks for this scope.
|
|
143
|
+
* @property {string} [filePath] - Source file path.
|
|
144
|
+
* @property {number} [line] - Source line number.
|
|
145
|
+
* @property {Record<string, TestData>} tests - A unique identifier for the node.
|
|
146
|
+
* @property {Record<string, TestsArgument>} subs - Optional child nodes. Each item is another `Node`, allowing recursion.
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
export default class TestRunner {
|
|
150
|
+
/**
|
|
151
|
+
* Narrows the runtime value to the documented type.
|
|
152
|
+
@type {ActiveAfterAllScopeEntry[]} */
|
|
153
|
+
_activeAfterAllScopes
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Narrows the runtime value to the documented type.
|
|
157
|
+
@type {FailedTestDetail[]} */
|
|
158
|
+
_failedTestDetails
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Runs constructor.
|
|
162
|
+
* @param {object} args - Options object.
|
|
163
|
+
* @param {import("../configuration.js").default} args.configuration - Configuration instance.
|
|
164
|
+
* @param {string[] | string} [args.excludeTags] - Tags to exclude.
|
|
165
|
+
* @param {string[] | string} [args.includeTags] - Tags to include.
|
|
166
|
+
* @param {Array<string>} args.testFiles - Test files.
|
|
167
|
+
* @param {Record<string, number[]>} [args.lineFilters] - Line filters by file.
|
|
168
|
+
* @param {RegExp[]} [args.examplePatterns] - Example patterns.
|
|
169
|
+
*/
|
|
170
|
+
constructor({configuration, excludeTags, includeTags, testFiles, lineFilters, examplePatterns, ...restArgs}) {
|
|
171
|
+
restArgsError(restArgs)
|
|
172
|
+
|
|
173
|
+
if (!configuration) throw new Error("configuration is required")
|
|
174
|
+
|
|
175
|
+
this._configuration = configuration
|
|
176
|
+
this._excludeTags = this.normalizeTags(excludeTags)
|
|
177
|
+
this._excludeTagSet = new Set(this._excludeTags)
|
|
178
|
+
this._includeTags = this.normalizeTags(includeTags)
|
|
179
|
+
this._includeTagSet = new Set(this._includeTags)
|
|
180
|
+
this._testFiles = testFiles
|
|
181
|
+
this._lineFilters = lineFilters || {}
|
|
182
|
+
this._examplePatterns = examplePatterns || []
|
|
183
|
+
|
|
184
|
+
this._failedTests = 0
|
|
185
|
+
this._successfulTests = 0
|
|
186
|
+
this._testsCount = 0
|
|
187
|
+
this._activeAfterAllScopes = []
|
|
188
|
+
this._failedTestDetails = []
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Runs get configuration.
|
|
193
|
+
* @returns {import("../configuration.js").default} - The configuration.
|
|
194
|
+
*/
|
|
195
|
+
getConfiguration() { return this._configuration }
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Runs get test files.
|
|
199
|
+
* @returns {string[]} - The test files.
|
|
200
|
+
*/
|
|
201
|
+
getTestFiles() { return this._testFiles }
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Runs get line filters.
|
|
205
|
+
* @returns {Record<string, number[]>} - Line filters.
|
|
206
|
+
*/
|
|
207
|
+
getLineFilters() { return this._lineFilters }
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Runs get example patterns.
|
|
211
|
+
* @returns {RegExp[]} - Example patterns.
|
|
212
|
+
*/
|
|
213
|
+
getExamplePatterns() { return this._examplePatterns }
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Runs normalize tags.
|
|
217
|
+
* @param {string[] | string | undefined} tags - Tags.
|
|
218
|
+
* @returns {string[]} - Normalized tags.
|
|
219
|
+
*/
|
|
220
|
+
normalizeTags(tags) {
|
|
221
|
+
if (!tags) return []
|
|
222
|
+
|
|
223
|
+
const values = []
|
|
224
|
+
const rawTags = Array.isArray(tags) ? tags : [tags]
|
|
225
|
+
|
|
226
|
+
for (const rawTag of rawTags) {
|
|
227
|
+
if (rawTag === undefined || rawTag === null) continue
|
|
228
|
+
|
|
229
|
+
const parts = String(rawTag).split(",")
|
|
230
|
+
|
|
231
|
+
for (const part of parts) {
|
|
232
|
+
const trimmed = part.trim()
|
|
233
|
+
|
|
234
|
+
if (trimmed) values.push(trimmed)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return Array.from(new Set(values))
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Runs has tag.
|
|
243
|
+
* @param {TestArgs} testArgs - Test args.
|
|
244
|
+
* @param {string} tag - Tag to check for.
|
|
245
|
+
* @returns {boolean} - Whether tag is present.
|
|
246
|
+
*/
|
|
247
|
+
hasTag(testArgs, tag) {
|
|
248
|
+
return this.normalizeTags(testArgs?.tags).includes(tag)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Runs is browser test mode.
|
|
253
|
+
* @returns {boolean} - Whether running browser tests.
|
|
254
|
+
*/
|
|
255
|
+
isBrowserTestMode() {
|
|
256
|
+
return process.env.VELOCIOUS_BROWSER_TESTS === "true"
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Runs run with dummy if needed.
|
|
261
|
+
* @param {TestArgs} testArgs - Test args.
|
|
262
|
+
* @param {() => Promise<void>} callback - Callback to run.
|
|
263
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
264
|
+
*/
|
|
265
|
+
async runWithDummyIfNeeded(testArgs, callback) {
|
|
266
|
+
if (!this.hasTag(testArgs, "dummy")) {
|
|
267
|
+
await callback()
|
|
268
|
+
return
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (this.isBrowserTestMode()) {
|
|
272
|
+
await this.runBrowserDummy(callback)
|
|
273
|
+
return
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
await this.runNodeDummy(callback)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Runs run node dummy.
|
|
281
|
+
* @param {() => Promise<void>} callback - Callback to run.
|
|
282
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
283
|
+
*/
|
|
284
|
+
async runNodeDummy(callback) {
|
|
285
|
+
const dummyPath = process.env.VELOCIOUS_DUMMY_PATH || this.defaultDummyPath()
|
|
286
|
+
const dummyImport = await import(pathToFileURL(dummyPath).href)
|
|
287
|
+
const Dummy = dummyImport.default
|
|
288
|
+
|
|
289
|
+
if (!Dummy?.run) {
|
|
290
|
+
throw new Error(`Dummy helper not found at ${dummyPath}`)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
await Dummy.run(callback)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Runs default dummy path.
|
|
298
|
+
* @returns {string} - Default dummy helper path.
|
|
299
|
+
*/
|
|
300
|
+
defaultDummyPath() {
|
|
301
|
+
const cwd = path.resolve(process.cwd())
|
|
302
|
+
const normalized = cwd.split(path.sep).join("/")
|
|
303
|
+
|
|
304
|
+
if (normalized.endsWith("/spec/dummy")) {
|
|
305
|
+
return path.join(cwd, "index.js")
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return path.join(cwd, "spec/dummy/index.js")
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Runs run browser dummy.
|
|
313
|
+
* @param {() => Promise<void>} callback - Callback to run.
|
|
314
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
315
|
+
*/
|
|
316
|
+
async runBrowserDummy(callback) {
|
|
317
|
+
await this.getConfiguration().ensureConnections({name: "Test runner browser dummy"}, async (dbs) => {
|
|
318
|
+
await this.truncateDatabases(dbs)
|
|
319
|
+
|
|
320
|
+
try {
|
|
321
|
+
await callback()
|
|
322
|
+
} finally {
|
|
323
|
+
await this.truncateDatabases(dbs)
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Runs truncate databases.
|
|
330
|
+
* @param {Record<string, import("../database/drivers/base.js").default>} dbs - Database connections.
|
|
331
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
332
|
+
*/
|
|
333
|
+
async truncateDatabases(dbs) {
|
|
334
|
+
for (const identifier of Object.keys(dbs)) {
|
|
335
|
+
await dbs[identifier].truncateAllTables()
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Runs get exclude tag set.
|
|
341
|
+
* @returns {Set<string>} - Exclude tag set.
|
|
342
|
+
*/
|
|
343
|
+
getExcludeTagSet() {
|
|
344
|
+
/**
|
|
345
|
+
* Config tags.
|
|
346
|
+
@type {string[]} */
|
|
347
|
+
const configTags = Array.isArray(testConfig.excludeTags) ? testConfig.excludeTags : []
|
|
348
|
+
|
|
349
|
+
return new Set([...this._excludeTags, ...configTags])
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Runs has matching tag.
|
|
354
|
+
* @param {string[] | string | undefined} testTags - Test tags.
|
|
355
|
+
* @param {Set<string>} tagSet - Tag set.
|
|
356
|
+
* @returns {boolean} - Whether any tags match.
|
|
357
|
+
*/
|
|
358
|
+
hasMatchingTag(testTags, tagSet) {
|
|
359
|
+
if (!tagSet.size) return false
|
|
360
|
+
|
|
361
|
+
const normalized = this.normalizeTags(testTags)
|
|
362
|
+
|
|
363
|
+
for (const tag of normalized) {
|
|
364
|
+
if (tagSet.has(tag)) return true
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return false
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Runs has runnable tests.
|
|
372
|
+
* @param {TestsArgument} tests - Tests.
|
|
373
|
+
* @param {string[]} [descriptions] - Description stack.
|
|
374
|
+
* @param {boolean} [lineMatchedInScope] - Whether line matched in scope.
|
|
375
|
+
* @returns {boolean} - Whether any tests in this scope will run.
|
|
376
|
+
*/
|
|
377
|
+
hasRunnableTests(tests, descriptions = [], lineMatchedInScope = false) {
|
|
378
|
+
for (const testDescription in tests.tests) {
|
|
379
|
+
const testData = tests.tests[testDescription]
|
|
380
|
+
const testArgs = /**
|
|
381
|
+
* Narrows the runtime value to the documented type.
|
|
382
|
+
@type {TestArgs} */ (Object.assign({}, testData.args))
|
|
383
|
+
const includeByLine = lineMatchedInScope || this.matchesLineFilter(testData)
|
|
384
|
+
|
|
385
|
+
if (this._onlyFocussed && !testArgs.focus) continue
|
|
386
|
+
if (this.shouldSkipTest(testArgs, testData, testDescription, descriptions, includeByLine)) continue
|
|
387
|
+
|
|
388
|
+
return true
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
for (const subDescription in tests.subs) {
|
|
392
|
+
const subTest = tests.subs[subDescription]
|
|
393
|
+
const scopeLineMatch = lineMatchedInScope || this.matchesLineFilter(subTest)
|
|
394
|
+
const nextDescriptions = descriptions.concat([subDescription])
|
|
395
|
+
|
|
396
|
+
if (this._onlyFocussed && !subTest.anyTestsFocussed) continue
|
|
397
|
+
if (this.hasRunnableTests(subTest, nextDescriptions, scopeLineMatch)) return true
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return false
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Runs should skip test.
|
|
405
|
+
* @param {TestArgs} testArgs - Test args.
|
|
406
|
+
* @param {TestData} testData - Test data.
|
|
407
|
+
* @param {string} testDescription - Test description.
|
|
408
|
+
* @param {string[]} descriptions - Description stack.
|
|
409
|
+
* @param {boolean} lineMatchedInScope - Whether line matched in scope.
|
|
410
|
+
* @returns {boolean} - Whether the test should be skipped.
|
|
411
|
+
*/
|
|
412
|
+
shouldSkipTest(testArgs, testData, testDescription, descriptions, lineMatchedInScope) {
|
|
413
|
+
if (this.hasMatchingTag(testArgs.tags, this.getExcludeTagSet())) return true
|
|
414
|
+
|
|
415
|
+
if (this._includeTagSet.size > 0 && !testArgs.focus) {
|
|
416
|
+
if (!this.hasMatchingTag(testArgs.tags, this._includeTagSet)) return true
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (this.getExamplePatterns().length > 0) {
|
|
420
|
+
const fullDescription = this.buildFullDescription(descriptions, testDescription)
|
|
421
|
+
const matches = this.getExamplePatterns().some((pattern) => {
|
|
422
|
+
pattern.lastIndex = 0
|
|
423
|
+
return pattern.test(fullDescription)
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
if (!matches) return true
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const lineFilters = this.getLineFilters()
|
|
430
|
+
|
|
431
|
+
if (Object.keys(lineFilters).length > 0) {
|
|
432
|
+
if (!lineMatchedInScope && !this.matchesLineFilter(testData)) return true
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return false
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Runs matches line filter.
|
|
440
|
+
* @param {TestData | TestsArgument} entry - Test entry.
|
|
441
|
+
* @returns {boolean} - Whether line filter matches entry.
|
|
442
|
+
*/
|
|
443
|
+
matchesLineFilter(entry) {
|
|
444
|
+
if (!entry || !entry.filePath || !entry.line) return false
|
|
445
|
+
|
|
446
|
+
const filePath = path.resolve(entry.filePath)
|
|
447
|
+
const lines = this.getLineFilters()[filePath]
|
|
448
|
+
|
|
449
|
+
if (!lines || lines.length === 0) return false
|
|
450
|
+
|
|
451
|
+
return lines.includes(entry.line)
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Runs build full description.
|
|
456
|
+
* @param {string[]} descriptions - Description stack.
|
|
457
|
+
* @param {string} testDescription - Test description.
|
|
458
|
+
* @returns {string} - Full description.
|
|
459
|
+
*/
|
|
460
|
+
buildFullDescription(descriptions, testDescription) {
|
|
461
|
+
const parts = descriptions.concat([testDescription])
|
|
462
|
+
|
|
463
|
+
return parts.join(" ").trim()
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Runs application.
|
|
468
|
+
* @returns {Promise<Application>} - Resolves with the application.
|
|
469
|
+
*/
|
|
470
|
+
async application() {
|
|
471
|
+
if (!this._application) {
|
|
472
|
+
this._application = new Application({
|
|
473
|
+
configuration: this.getConfiguration(),
|
|
474
|
+
httpServer: {port: 31006},
|
|
475
|
+
type: "test-runner"
|
|
476
|
+
})
|
|
477
|
+
|
|
478
|
+
await this._application.initialize()
|
|
479
|
+
await this._application.startHttpServer()
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return this._application
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Runs request client.
|
|
487
|
+
* @returns {Promise<RequestClient>} - Resolves with the request client.
|
|
488
|
+
*/
|
|
489
|
+
async requestClient() {
|
|
490
|
+
if (!this._requestClient) {
|
|
491
|
+
this._requestClient = new RequestClient()
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return this._requestClient
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Runs import test files.
|
|
499
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
500
|
+
*/
|
|
501
|
+
async importTestFiles() {
|
|
502
|
+
await this.getConfiguration().getEnvironmentHandler().importTestFiles(this.getTestFiles())
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Runs is failed.
|
|
507
|
+
* @returns {boolean} - Whether failed.
|
|
508
|
+
*/
|
|
509
|
+
isFailed() { return this._failedTests !== undefined && this._failedTests > 0 }
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Runs get failed tests.
|
|
513
|
+
* @returns {number} - The failed tests.
|
|
514
|
+
*/
|
|
515
|
+
getFailedTests() {
|
|
516
|
+
if (this._failedTests === undefined) throw new Error("Tests hasn't been run yet")
|
|
517
|
+
|
|
518
|
+
return this._failedTests
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Runs get failed test details.
|
|
523
|
+
* @returns {FailedTestDetail[]} - Failed test details.
|
|
524
|
+
*/
|
|
525
|
+
getFailedTestDetails() {
|
|
526
|
+
return this._failedTestDetails
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Runs persist failed test console outputs to assets.
|
|
531
|
+
* @param {object} [args] - Options object.
|
|
532
|
+
* @param {string} [args.assetsPath] - Assets directory path.
|
|
533
|
+
* @returns {Promise<string[]>} - Written log file paths.
|
|
534
|
+
*/
|
|
535
|
+
async persistFailedTestConsoleOutputsToAssets({assetsPath = path.join(process.cwd(), "tmp/screenshots")} = {}) {
|
|
536
|
+
const failedTestDetails = this.getFailedTestDetails()
|
|
537
|
+
const writtenLogPaths = []
|
|
538
|
+
let createdDirectory = false
|
|
539
|
+
|
|
540
|
+
for (let index = 0; index < failedTestDetails.length; index++) {
|
|
541
|
+
const failedTestDetail = failedTestDetails[index]
|
|
542
|
+
const consoleOutput = failedTestDetail.consoleOutput
|
|
543
|
+
|
|
544
|
+
if (!consoleOutput) continue
|
|
545
|
+
|
|
546
|
+
if (!createdDirectory) {
|
|
547
|
+
await fs.mkdir(assetsPath, {recursive: true})
|
|
548
|
+
createdDirectory = true
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const now = new Date()
|
|
552
|
+
const timestamp = [
|
|
553
|
+
String(now.getFullYear()),
|
|
554
|
+
String(now.getMonth() + 1).padStart(2, "0"),
|
|
555
|
+
String(now.getDate()).padStart(2, "0"),
|
|
556
|
+
String(now.getHours()).padStart(2, "0"),
|
|
557
|
+
String(now.getMinutes()).padStart(2, "0"),
|
|
558
|
+
String(now.getSeconds()).padStart(2, "0"),
|
|
559
|
+
String(now.getMilliseconds()).padStart(3, "0")
|
|
560
|
+
].join("")
|
|
561
|
+
const slug = toFileSlug(failedTestDetail.fullDescription)
|
|
562
|
+
const fileName = `${timestamp}-${String(index + 1).padStart(2, "0")}-${slug}.console.log`
|
|
563
|
+
const filePath = path.join(assetsPath, fileName)
|
|
564
|
+
|
|
565
|
+
await fs.writeFile(filePath, consoleOutput, "utf8")
|
|
566
|
+
failedTestDetail.consoleLogPath = filePath
|
|
567
|
+
writtenLogPaths.push(filePath)
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return writtenLogPaths
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Runs get successful tests.
|
|
575
|
+
* @returns {number} - The successful tests.
|
|
576
|
+
*/
|
|
577
|
+
getSuccessfulTests() {
|
|
578
|
+
if (this._successfulTests === undefined) throw new Error("Tests hasn't been run yet")
|
|
579
|
+
|
|
580
|
+
return this._successfulTests
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Runs get tests count.
|
|
585
|
+
* @returns {number} - The tests count.
|
|
586
|
+
*/
|
|
587
|
+
getTestsCount() {
|
|
588
|
+
if (this._testsCount === undefined) throw new Error("Tests hasn't been run yet")
|
|
589
|
+
|
|
590
|
+
return this._testsCount
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Runs get executed tests count.
|
|
595
|
+
* @returns {number} - The executed tests count.
|
|
596
|
+
*/
|
|
597
|
+
getExecutedTestsCount() {
|
|
598
|
+
if (this._successfulTests === undefined || this._failedTests === undefined) {
|
|
599
|
+
throw new Error("Tests hasn't been run yet")
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
return this._successfulTests + this._failedTests
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Runs prepare.
|
|
607
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
608
|
+
*/
|
|
609
|
+
async prepare() {
|
|
610
|
+
this.anyTestsFocussed = false
|
|
611
|
+
this._failedTests = 0
|
|
612
|
+
this._successfulTests = 0
|
|
613
|
+
this._testsCount = 0
|
|
614
|
+
this._failedTestDetails = []
|
|
615
|
+
await this.importTestFiles()
|
|
616
|
+
await this.analyzeTests(tests)
|
|
617
|
+
this._onlyFocussed = this.anyTestsFocussed
|
|
618
|
+
|
|
619
|
+
const testingConfigPath = this.getConfiguration().getTesting()
|
|
620
|
+
|
|
621
|
+
if (testingConfigPath) {
|
|
622
|
+
await this.getConfiguration().getEnvironmentHandler().importTestingConfigPath()
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Runs are any tests focussed.
|
|
628
|
+
* @returns {boolean} - Whether any tests focussed.
|
|
629
|
+
*/
|
|
630
|
+
areAnyTestsFocussed() {
|
|
631
|
+
if (this.anyTestsFocussed === undefined) {
|
|
632
|
+
throw new Error("Hasn't been detected yet")
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return this.anyTestsFocussed
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Runs run.
|
|
640
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
641
|
+
*/
|
|
642
|
+
async run() {
|
|
643
|
+
await this.getConfiguration().ensureConnections({name: "Test runner suite"}, async () => {
|
|
644
|
+
await this.runTests({
|
|
645
|
+
afterEaches: [],
|
|
646
|
+
beforeEaches: [],
|
|
647
|
+
tests,
|
|
648
|
+
descriptions: [],
|
|
649
|
+
indentLevel: 0
|
|
650
|
+
})
|
|
651
|
+
})
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Runs run after alls for active scopes.
|
|
656
|
+
* @returns {Promise<void>} - Resolves when cleanup hooks finish.
|
|
657
|
+
*/
|
|
658
|
+
async runAfterAllsForActiveScopes() {
|
|
659
|
+
const scopes = [...this._activeAfterAllScopes].reverse()
|
|
660
|
+
|
|
661
|
+
for (const scope of scopes) {
|
|
662
|
+
await this.runAfterAllsForScope(scope)
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
this._activeAfterAllScopes = []
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Runs analyze tests.
|
|
670
|
+
* @param {TestsArgument} tests - Tests.
|
|
671
|
+
* @returns {{anyTestsFocussed: boolean}} - Whether any tests in the tree are focused.
|
|
672
|
+
*/
|
|
673
|
+
analyzeTests(tests) {
|
|
674
|
+
let anyTestsFocussedFound = false
|
|
675
|
+
|
|
676
|
+
for (const testDescription in tests.tests) {
|
|
677
|
+
const testData = tests.tests[testDescription]
|
|
678
|
+
const testArgs = Object.assign({}, testData.args)
|
|
679
|
+
|
|
680
|
+
this._testsCount++
|
|
681
|
+
|
|
682
|
+
if (testArgs.focus) {
|
|
683
|
+
anyTestsFocussedFound = true
|
|
684
|
+
this.anyTestsFocussed = true
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
for (const subDescription in tests.subs) {
|
|
689
|
+
const subTest = tests.subs[subDescription]
|
|
690
|
+
const {anyTestsFocussed} = this.analyzeTests(subTest)
|
|
691
|
+
|
|
692
|
+
if (anyTestsFocussed) {
|
|
693
|
+
anyTestsFocussedFound = true
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
subTest.anyTestsFocussed = anyTestsFocussed
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
return {anyTestsFocussed: anyTestsFocussedFound}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Runs run tests.
|
|
704
|
+
* @param {object} args - Options object.
|
|
705
|
+
* @param {Array<AfterBeforeEachCallbackObjectType>} args.afterEaches - After eaches.
|
|
706
|
+
* @param {Array<AfterBeforeEachCallbackObjectType>} args.beforeEaches - Before eaches.
|
|
707
|
+
* @param {TestsArgument} args.tests - Tests.
|
|
708
|
+
* @param {string[]} args.descriptions - Descriptions.
|
|
709
|
+
* @param {number} args.indentLevel - Indent level.
|
|
710
|
+
* @param {boolean} [args.lineMatchedInScope] - Whether line matched in scope.
|
|
711
|
+
* @returns {Promise<void>} - Resolves when complete.
|
|
712
|
+
*/
|
|
713
|
+
async runTests({afterEaches, beforeEaches, tests, descriptions, indentLevel, lineMatchedInScope = false}) {
|
|
714
|
+
const leftPadding = " ".repeat(indentLevel * 2)
|
|
715
|
+
const newAfterEaches = [...afterEaches, ...tests.afterEaches]
|
|
716
|
+
const newBeforeEaches = [...beforeEaches, ...tests.beforeEaches]
|
|
717
|
+
const scopeLineMatch = lineMatchedInScope || this.matchesLineFilter(tests)
|
|
718
|
+
const shouldRunAnyTests = this.hasRunnableTests(tests, descriptions, scopeLineMatch)
|
|
719
|
+
|
|
720
|
+
if (!shouldRunAnyTests) return
|
|
721
|
+
|
|
722
|
+
/** Scope entry. @type {ActiveAfterAllScopeEntry} */
|
|
723
|
+
const scopeEntry = {tests, afterAllsRun: false}
|
|
724
|
+
this._activeAfterAllScopes.push(scopeEntry)
|
|
725
|
+
|
|
726
|
+
try {
|
|
727
|
+
for (const beforeAllData of tests.beforeAlls || []) {
|
|
728
|
+
await beforeAllData.callback({configuration: this.getConfiguration()})
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
for (const testDescription in tests.tests) {
|
|
732
|
+
const testData = tests.tests[testDescription]
|
|
733
|
+
const testArgs = /**
|
|
734
|
+
* Narrows the runtime value to the documented type.
|
|
735
|
+
@type {TestArgs} */ (Object.assign({}, testData.args))
|
|
736
|
+
const includeByLine = scopeLineMatch || this.matchesLineFilter(testData)
|
|
737
|
+
|
|
738
|
+
if (this._onlyFocussed && !testArgs.focus) continue
|
|
739
|
+
if (this.shouldSkipTest(testArgs, testData, testDescription, descriptions, includeByLine)) continue
|
|
740
|
+
|
|
741
|
+
if (testArgs.type == "model" || testArgs.type == "request") {
|
|
742
|
+
testArgs.application = await this.application()
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (testArgs.type == "request") {
|
|
746
|
+
testArgs.client = await this.requestClient()
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const retryCount = typeof testArgs.retry === "number" && Number.isFinite(testArgs.retry)
|
|
750
|
+
? Math.max(0, Math.floor(testArgs.retry))
|
|
751
|
+
: 0
|
|
752
|
+
const configTimeoutSeconds = typeof testConfig.defaultTimeoutSeconds === "number" ? testConfig.defaultTimeoutSeconds : undefined
|
|
753
|
+
const timeoutSeconds = typeof testArgs.timeoutSeconds === "number" ? testArgs.timeoutSeconds : configTimeoutSeconds
|
|
754
|
+
const useTimeout = typeof timeoutSeconds === "number" && Number.isFinite(timeoutSeconds) && timeoutSeconds > 0
|
|
755
|
+
const timeoutMs = useTimeout ? timeoutSeconds * 1000 : undefined
|
|
756
|
+
let retriesUsed = 0
|
|
757
|
+
let attemptNumber = 1
|
|
758
|
+
/**
|
|
759
|
+
* Attempt console outputs.
|
|
760
|
+
@type {AttemptConsoleOutput[]} */
|
|
761
|
+
const attemptConsoleOutputs = []
|
|
762
|
+
|
|
763
|
+
console.log(`${leftPadding}it ${testDescription}`)
|
|
764
|
+
|
|
765
|
+
while (true) {
|
|
766
|
+
let shouldRetry = false
|
|
767
|
+
/**
|
|
768
|
+
* Defines caughtError.
|
|
769
|
+
@type {?} */
|
|
770
|
+
let caughtError
|
|
771
|
+
/**
|
|
772
|
+
* Defines failedError.
|
|
773
|
+
@type {?} */
|
|
774
|
+
let failedError
|
|
775
|
+
/**
|
|
776
|
+
* Defines lastError.
|
|
777
|
+
@type {?} */
|
|
778
|
+
let lastError
|
|
779
|
+
let willRetry = false
|
|
780
|
+
const stopConsoleCapture = this.startConsoleCapture({
|
|
781
|
+
passthrough: testConfig.consoleOutput === "live"
|
|
782
|
+
})
|
|
783
|
+
|
|
784
|
+
try {
|
|
785
|
+
// Run the whole per-test lifecycle (dummy/server startup, connection
|
|
786
|
+
// acquisition, beforeEach hooks, the test body and afterEach hooks) as
|
|
787
|
+
// one promise so the timeout below can cover all of it.
|
|
788
|
+
const testLifecycle = this.runWithDummyIfNeeded(testArgs, async () => {
|
|
789
|
+
// Pin one connection per test so beforeEach, the test body and afterEach
|
|
790
|
+
// all run on the SAME connection. This is required for transaction-based
|
|
791
|
+
// database cleaning (beforeEach starts a transaction, afterEach rolls it
|
|
792
|
+
// back). ensureConnections reuses the suite-level pinned connection while
|
|
793
|
+
// it is healthy and transparently re-establishes a per-test pin if an
|
|
794
|
+
// earlier spec closed the suite connection (which would otherwise leave a
|
|
795
|
+
// stale async-context pin and force every later test onto a fresh checkout,
|
|
796
|
+
// breaking isolation).
|
|
797
|
+
await this.getConfiguration().ensureConnections({name: `Test: ${testDescription}`}, async () => {
|
|
798
|
+
try {
|
|
799
|
+
clearDeliveries()
|
|
800
|
+
for (const beforeEachData of newBeforeEaches) {
|
|
801
|
+
await beforeEachData.callback({configuration: this.getConfiguration(), testArgs, testData})
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
await testData.function(testArgs)
|
|
805
|
+
this._successfulTests++
|
|
806
|
+
} finally {
|
|
807
|
+
for (const afterEachData of newAfterEaches) {
|
|
808
|
+
await afterEachData.callback({configuration: this.getConfiguration(), testArgs, testData})
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
})
|
|
812
|
+
})
|
|
813
|
+
|
|
814
|
+
// Time out the ENTIRE lifecycle, not just the test body. A hang in any
|
|
815
|
+
// phase — a connection checkout that never resolves, a beforeEach/afterEach
|
|
816
|
+
// waiting on a lock, or dummy server startup — would otherwise stall the
|
|
817
|
+
// whole run indefinitely (until CI kills the build) instead of failing the
|
|
818
|
+
// single offending test.
|
|
819
|
+
if (useTimeout && timeoutMs !== undefined) {
|
|
820
|
+
await runWithTimeout(testLifecycle, timeoutMs, testDescription)
|
|
821
|
+
} else {
|
|
822
|
+
await testLifecycle
|
|
823
|
+
}
|
|
824
|
+
} catch (error) {
|
|
825
|
+
caughtError = error
|
|
826
|
+
lastError = error
|
|
827
|
+
willRetry = retriesUsed < retryCount
|
|
828
|
+
|
|
829
|
+
if (willRetry) {
|
|
830
|
+
retriesUsed++
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
if (willRetry) {
|
|
834
|
+
shouldRetry = true
|
|
835
|
+
} else {
|
|
836
|
+
failedError = error
|
|
837
|
+
}
|
|
838
|
+
} finally {
|
|
839
|
+
const consoleOutput = stopConsoleCapture()
|
|
840
|
+
|
|
841
|
+
if (consoleOutput) {
|
|
842
|
+
attemptConsoleOutputs.push({attemptNumber, output: consoleOutput})
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
if (caughtError !== undefined) {
|
|
847
|
+
await this.emitEvent("testAttemptFailed", {
|
|
848
|
+
configuration: this.getConfiguration(),
|
|
849
|
+
descriptions,
|
|
850
|
+
error: caughtError,
|
|
851
|
+
attemptNumber,
|
|
852
|
+
nextAttempt: willRetry ? attemptNumber + 1 : undefined,
|
|
853
|
+
retriesUsed,
|
|
854
|
+
retryCount,
|
|
855
|
+
testArgs,
|
|
856
|
+
testData,
|
|
857
|
+
testDescription,
|
|
858
|
+
testRunner: this,
|
|
859
|
+
willRetry
|
|
860
|
+
})
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
if (shouldRetry) {
|
|
864
|
+
console.warn(picocolors.red(`${leftPadding} Retrying (${retriesUsed}/${retryCount}) after error: ${lastError instanceof Error ? lastError.message : String(lastError)}`))
|
|
865
|
+
await this.emitEvent("testRetrying", {
|
|
866
|
+
configuration: this.getConfiguration(),
|
|
867
|
+
descriptions,
|
|
868
|
+
error: lastError,
|
|
869
|
+
nextAttempt: attemptNumber + 1,
|
|
870
|
+
retriesUsed,
|
|
871
|
+
retryCount,
|
|
872
|
+
testArgs,
|
|
873
|
+
testData,
|
|
874
|
+
testDescription,
|
|
875
|
+
testRunner: this
|
|
876
|
+
})
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
if (attemptNumber > 1) {
|
|
880
|
+
await this.emitEvent("testRetried", {
|
|
881
|
+
configuration: this.getConfiguration(),
|
|
882
|
+
descriptions,
|
|
883
|
+
error: lastError,
|
|
884
|
+
attemptNumber,
|
|
885
|
+
retriesUsed,
|
|
886
|
+
retryCount,
|
|
887
|
+
testArgs,
|
|
888
|
+
testData,
|
|
889
|
+
testDescription,
|
|
890
|
+
testRunner: this
|
|
891
|
+
})
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
attemptNumber++
|
|
895
|
+
|
|
896
|
+
if (shouldRetry) continue
|
|
897
|
+
|
|
898
|
+
if (failedError) {
|
|
899
|
+
const consoleOutput = this.buildConsoleOutput(attemptConsoleOutputs)
|
|
900
|
+
|
|
901
|
+
if (failedError instanceof Error) {
|
|
902
|
+
console.error(picocolors.red(`${leftPadding} Test failed: ${failedError.message}`))
|
|
903
|
+
addTrackedStackToError(failedError)
|
|
904
|
+
|
|
905
|
+
const backtraceCleaner = new BacktraceCleaner(failedError)
|
|
906
|
+
const cleanedStack = backtraceCleaner.getCleanedStack()
|
|
907
|
+
const stackLines = cleanedStack?.split("\n")
|
|
908
|
+
|
|
909
|
+
if (stackLines) {
|
|
910
|
+
for (const stackLine of stackLines) {
|
|
911
|
+
console.error(picocolors.red(`${leftPadding} ${stackLine}`))
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
} else {
|
|
915
|
+
console.error(picocolors.red(`${leftPadding} Test failed with a ${typeof failedError}: ${String(failedError)}`))
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
this.printFailedConsoleOutput({consoleOutput, leftPadding})
|
|
919
|
+
this._failedTests++
|
|
920
|
+
this._failedTestDetails.push({
|
|
921
|
+
fullDescription: this.buildFullDescription(descriptions, testDescription),
|
|
922
|
+
filePath: testData.filePath,
|
|
923
|
+
line: testData.line,
|
|
924
|
+
error: failedError,
|
|
925
|
+
consoleOutput: consoleOutput || undefined
|
|
926
|
+
})
|
|
927
|
+
|
|
928
|
+
await this.emitEvent("testFailed", {
|
|
929
|
+
configuration: this.getConfiguration(),
|
|
930
|
+
descriptions,
|
|
931
|
+
error: failedError,
|
|
932
|
+
testArgs,
|
|
933
|
+
testData,
|
|
934
|
+
testDescription,
|
|
935
|
+
testRunner: this
|
|
936
|
+
})
|
|
937
|
+
|
|
938
|
+
this.printRerunCommand({descriptions, testDescription, testData, leftPadding})
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
break
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
for (const subDescription in tests.subs) {
|
|
946
|
+
const subTest = tests.subs[subDescription]
|
|
947
|
+
const newDecriptions = descriptions.concat([subDescription])
|
|
948
|
+
const childScopeLineMatch = scopeLineMatch || this.matchesLineFilter(subTest)
|
|
949
|
+
|
|
950
|
+
if (!this._onlyFocussed || subTest.anyTestsFocussed) {
|
|
951
|
+
console.log(`${leftPadding}${subDescription}`)
|
|
952
|
+
await this.runTests({
|
|
953
|
+
afterEaches: newAfterEaches,
|
|
954
|
+
beforeEaches: newBeforeEaches,
|
|
955
|
+
tests: subTest,
|
|
956
|
+
descriptions: newDecriptions,
|
|
957
|
+
indentLevel: indentLevel + 1,
|
|
958
|
+
lineMatchedInScope: childScopeLineMatch
|
|
959
|
+
})
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
} finally {
|
|
963
|
+
await this.runAfterAllsForScope(scopeEntry)
|
|
964
|
+
const scopeIndex = this._activeAfterAllScopes.indexOf(scopeEntry)
|
|
965
|
+
|
|
966
|
+
if (scopeIndex >= 0) {
|
|
967
|
+
this._activeAfterAllScopes.splice(scopeIndex, 1)
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* Runs run after alls for scope.
|
|
974
|
+
* @param {ActiveAfterAllScopeEntry} scopeEntry - Scope entry.
|
|
975
|
+
* @returns {Promise<void>} - Resolves when scope cleanup finishes.
|
|
976
|
+
*/
|
|
977
|
+
async runAfterAllsForScope(scopeEntry) {
|
|
978
|
+
if (scopeEntry.afterAllsRun) return
|
|
979
|
+
|
|
980
|
+
scopeEntry.afterAllsRun = true
|
|
981
|
+
|
|
982
|
+
for (const afterAllData of scopeEntry.tests.afterAlls || []) {
|
|
983
|
+
await afterAllData.callback({configuration: this.getConfiguration()})
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Runs emit event.
|
|
989
|
+
* @param {string} eventName - Event name.
|
|
990
|
+
* @param {object} payload - Event payload.
|
|
991
|
+
* @returns {Promise<void>} - Resolves when all listeners complete.
|
|
992
|
+
*/
|
|
993
|
+
async emitEvent(eventName, payload) {
|
|
994
|
+
const listeners = testEvents.listeners(eventName)
|
|
995
|
+
|
|
996
|
+
for (const listener of listeners) {
|
|
997
|
+
await listener(payload)
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Runs print rerun command.
|
|
1003
|
+
* @param {object} args - Options object.
|
|
1004
|
+
* @param {string[]} args.descriptions - Description stack.
|
|
1005
|
+
* @param {string} args.testDescription - Test description.
|
|
1006
|
+
* @param {TestData} args.testData - Test data.
|
|
1007
|
+
* @param {string} args.leftPadding - Left padding.
|
|
1008
|
+
* @returns {void} - No return value.
|
|
1009
|
+
*/
|
|
1010
|
+
printRerunCommand({descriptions, testDescription, testData, leftPadding}) {
|
|
1011
|
+
const rerun = this.buildRerunCommand({descriptions, testDescription, testData})
|
|
1012
|
+
|
|
1013
|
+
if (rerun) {
|
|
1014
|
+
console.error(`${leftPadding} Re-run: ${rerun}`)
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* Runs build rerun command.
|
|
1020
|
+
* @param {object} args - Options object.
|
|
1021
|
+
* @param {string[]} args.descriptions - Description stack.
|
|
1022
|
+
* @param {string} args.testDescription - Test description.
|
|
1023
|
+
* @param {TestData} args.testData - Test data.
|
|
1024
|
+
* @returns {string | undefined} - Rerun command.
|
|
1025
|
+
*/
|
|
1026
|
+
buildRerunCommand({descriptions, testDescription, testData}) {
|
|
1027
|
+
const baseCommand = "npx velocious test"
|
|
1028
|
+
const filePath = testData.filePath
|
|
1029
|
+
const line = testData.line
|
|
1030
|
+
|
|
1031
|
+
if (filePath && line) {
|
|
1032
|
+
const relativePath = path.relative(process.cwd(), filePath)
|
|
1033
|
+
return `${baseCommand} ${relativePath}:${line}`
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
const fullDescription = this.buildFullDescription(descriptions, testDescription)
|
|
1037
|
+
|
|
1038
|
+
if (fullDescription) {
|
|
1039
|
+
return `${baseCommand} --example ${JSON.stringify(fullDescription)}`
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
return undefined
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
/**
|
|
1046
|
+
* Runs build console output.
|
|
1047
|
+
* @param {AttemptConsoleOutput[]} attemptConsoleOutputs - Attempt output entries.
|
|
1048
|
+
* @returns {string} - Combined console output.
|
|
1049
|
+
*/
|
|
1050
|
+
buildConsoleOutput(attemptConsoleOutputs) {
|
|
1051
|
+
if (attemptConsoleOutputs.length === 0) return ""
|
|
1052
|
+
if (attemptConsoleOutputs.length === 1) return attemptConsoleOutputs[0].output
|
|
1053
|
+
|
|
1054
|
+
return attemptConsoleOutputs.map((attemptConsoleOutput) => {
|
|
1055
|
+
return `--- Attempt ${attemptConsoleOutput.attemptNumber} ---\n${attemptConsoleOutput.output}`
|
|
1056
|
+
}).join("\n")
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Runs get failed console output max lines.
|
|
1061
|
+
* @returns {number} - Maximum failed console lines.
|
|
1062
|
+
*/
|
|
1063
|
+
getFailedConsoleOutputMaxLines() {
|
|
1064
|
+
const maxLines = testConfig.failedConsoleOutputMaxLines
|
|
1065
|
+
|
|
1066
|
+
if (typeof maxLines !== "number" || !Number.isFinite(maxLines)) return 200
|
|
1067
|
+
|
|
1068
|
+
return Math.max(0, Math.floor(maxLines))
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
/**
|
|
1072
|
+
* Runs truncate failed console output lines.
|
|
1073
|
+
* @param {string} consoleOutput - Console output.
|
|
1074
|
+
* @returns {string[]} - Lines for inline output.
|
|
1075
|
+
*/
|
|
1076
|
+
truncateFailedConsoleOutputLines(consoleOutput) {
|
|
1077
|
+
const lines = consoleOutput.split("\n")
|
|
1078
|
+
const maxLines = this.getFailedConsoleOutputMaxLines()
|
|
1079
|
+
|
|
1080
|
+
if (maxLines === 0) return []
|
|
1081
|
+
if (lines.length <= maxLines) return lines
|
|
1082
|
+
|
|
1083
|
+
const omittedLines = lines.length - maxLines
|
|
1084
|
+
const plural = omittedLines === 1 ? "" : "s"
|
|
1085
|
+
|
|
1086
|
+
return [
|
|
1087
|
+
`... ${omittedLines} console output line${plural} omitted ...`,
|
|
1088
|
+
...lines.slice(-maxLines)
|
|
1089
|
+
]
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Runs print failed console output.
|
|
1094
|
+
* @param {object} args - Options object.
|
|
1095
|
+
* @param {string} args.consoleOutput - Console output.
|
|
1096
|
+
* @param {string} args.leftPadding - Left padding.
|
|
1097
|
+
* @returns {void} - No return value.
|
|
1098
|
+
*/
|
|
1099
|
+
printFailedConsoleOutput({consoleOutput, leftPadding}) {
|
|
1100
|
+
if (testConfig.consoleOutput !== "failure") return
|
|
1101
|
+
if (!consoleOutput) return
|
|
1102
|
+
|
|
1103
|
+
const lines = this.truncateFailedConsoleOutputLines(consoleOutput)
|
|
1104
|
+
|
|
1105
|
+
if (lines.length === 0) return
|
|
1106
|
+
|
|
1107
|
+
console.error(picocolors.red(`${leftPadding} Console output:`))
|
|
1108
|
+
|
|
1109
|
+
for (const line of lines) {
|
|
1110
|
+
console.error(picocolors.red(`${leftPadding} ${line}`))
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
/**
|
|
1115
|
+
* Runs start console capture.
|
|
1116
|
+
* @param {object} [args] - Options object.
|
|
1117
|
+
* @param {boolean} [args.passthrough] - Whether to pass through to the original console.
|
|
1118
|
+
* @returns {() => string} - Stops the capture and returns captured text.
|
|
1119
|
+
*/
|
|
1120
|
+
startConsoleCapture({passthrough = false} = {}) {
|
|
1121
|
+
/**
|
|
1122
|
+
* Lines.
|
|
1123
|
+
@type {string[]} */
|
|
1124
|
+
const lines = []
|
|
1125
|
+
/**
|
|
1126
|
+
* Console object.
|
|
1127
|
+
@type {Record<ConsoleMethodName, (...args: Array<?>) => void>} */
|
|
1128
|
+
const consoleObject = /**
|
|
1129
|
+
* Narrows the runtime value to the documented type.
|
|
1130
|
+
@type {Record<ConsoleMethodName, (...args: Array<?>) => void>} */ (console)
|
|
1131
|
+
/**
|
|
1132
|
+
* Original console methods.
|
|
1133
|
+
@type {Record<ConsoleMethodName, (...args: Array<?>) => void>} */
|
|
1134
|
+
const originalConsoleMethods = {
|
|
1135
|
+
debug: consoleObject.debug.bind(console),
|
|
1136
|
+
error: consoleObject.error.bind(console),
|
|
1137
|
+
info: consoleObject.info.bind(console),
|
|
1138
|
+
log: consoleObject.log.bind(console),
|
|
1139
|
+
warn: consoleObject.warn.bind(console)
|
|
1140
|
+
}
|
|
1141
|
+
let stopped = false
|
|
1142
|
+
let outputText = ""
|
|
1143
|
+
|
|
1144
|
+
for (const methodName of CAPTURED_CONSOLE_METHODS) {
|
|
1145
|
+
consoleObject[methodName] = (...args) => {
|
|
1146
|
+
lines.push(`[${new Date().toISOString()}] [${methodName}] ${format(...args)}`)
|
|
1147
|
+
|
|
1148
|
+
if (passthrough) {
|
|
1149
|
+
originalConsoleMethods[methodName](...args)
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
return () => {
|
|
1155
|
+
if (!stopped) {
|
|
1156
|
+
stopped = true
|
|
1157
|
+
|
|
1158
|
+
for (const methodName of CAPTURED_CONSOLE_METHODS) {
|
|
1159
|
+
consoleObject[methodName] = originalConsoleMethods[methodName]
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
outputText = lines.join("\n")
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
return outputText
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
}
|