diff --git a/package.json b/package.json index aaac8c945..1285e994e 100644 --- a/package.json +++ b/package.json @@ -29,11 +29,12 @@ }, "devDependencies": { "@nx/js": "22.5.3", + "@vitest/coverage-v8": "3.1.1", "eslint": "8.57.1", "eslint-plugin-ghost": "3.4.4", - "mocha": "11.7.5", "nx": "22.5.3", "sinon": "21.0.1", - "ts-node": "10.9.2" + "ts-node": "10.9.2", + "vitest": "3.1.1" } } diff --git a/packages/api-framework/package.json b/packages/api-framework/package.json index b83429274..22988f70b 100644 --- a/packages/api-framework/package.json +++ b/packages/api-framework/package.json @@ -13,7 +13,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha --reporter dot './test/**/*.test.js'", + "test:unit": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "test": "yarn test:unit", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", @@ -24,7 +24,6 @@ "lib" ], "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/api-framework/test/http.test.js b/packages/api-framework/test/http.test.js index 3e41407ce..93b8ec6fd 100644 --- a/packages/api-framework/test/http.test.js +++ b/packages/api-framework/test/http.test.js @@ -65,129 +65,143 @@ describe('HTTP', function () { }); }); - it('api response is fn', function (done) { - const response = sinon.stub().callsFake(function (_req, _res, _next) { - assert.ok(_req); - assert.ok(_res); - assert.ok(_next); - assert.equal(apiImpl.calledOnce, true); - assert.equal(_res.json.called, false); - done(); - }); + it('api response is fn', async function () { + await new Promise((resolve) => { + const response = sinon.stub().callsFake(function (_req, _res, _next) { + assert.ok(_req); + assert.ok(_res); + assert.ok(_next); + assert.equal(apiImpl.calledOnce, true); + assert.equal(_res.json.called, false); + resolve(); + }); - const apiImpl = sinon.stub().resolves(response); - shared.http(apiImpl)(req, res, next); + const apiImpl = sinon.stub().resolves(response); + shared.http(apiImpl)(req, res, next); + }); }); - it('api response is fn (data)', function (done) { - const apiImpl = sinon.stub().resolves('data'); + it('api response is fn (data)', async function () { + await new Promise((resolve) => { + const apiImpl = sinon.stub().resolves('data'); - next.callsFake(done); + next.callsFake(resolve); - res.json.callsFake(function () { - assert.equal(shared.headers.get.calledOnce, true); - assert.equal(res.status.calledOnce, true); - assert.equal(res.send.called, false); - done(); - }); + res.json.callsFake(function () { + assert.equal(shared.headers.get.calledOnce, true); + assert.equal(res.status.calledOnce, true); + assert.equal(res.send.called, false); + resolve(); + }); - shared.http(apiImpl)(req, res, next); + shared.http(apiImpl)(req, res, next); + }); }); - it('handles api key, user and plain text response', function (done) { - req.vhost = null; - req.user = {id: 'user-id'}; - req.api_key = { - get(key) { - return { - id: 'api-key-id', - type: 'admin', - integration_id: 'integration-id' - }[key]; - } - }; - - const apiImpl = sinon.stub().resolves('plain body'); - apiImpl.response = {format: 'plain'}; - apiImpl.statusCode = 201; - - res.send.callsFake(() => { - assert.equal(res.status.calledOnceWithExactly(201), true); - assert.equal(res.headers.constructor, Object); - assert.equal(res.json.called, false); + it('handles api key, user and plain text response', async function () { + await new Promise((resolve) => { + req.vhost = null; + req.user = {id: 'user-id'}; + req.api_key = { + get(key) { + return { + id: 'api-key-id', + type: 'admin', + integration_id: 'integration-id' + }[key]; + } + }; + + const apiImpl = sinon.stub().resolves('plain body'); + apiImpl.response = {format: 'plain'}; + apiImpl.statusCode = 201; + + res.send.callsFake(() => { + assert.equal(res.status.calledOnceWithExactly(201), true); + assert.equal(res.headers.constructor, Object); + assert.equal(res.json.called, false); + + const frame = apiImpl.args[0][0]; + assert.equal(frame.options.context.api_key.id, 'api-key-id'); + assert.equal(frame.options.context.integration.id, 'integration-id'); + assert.equal(frame.options.context.user, 'user-id'); + resolve(); + }); - const frame = apiImpl.args[0][0]; - assert.equal(frame.options.context.api_key.id, 'api-key-id'); - assert.equal(frame.options.context.integration.id, 'integration-id'); - assert.equal(frame.options.context.user, 'user-id'); - done(); + shared.http(apiImpl)(req, res, next); }); - - shared.http(apiImpl)(req, res, next); }); - it('supports async response format and statusCode function', function (done) { - const apiImpl = sinon.stub().resolves({ok: true}); - apiImpl.statusCode = sinon.stub().returns(204); - apiImpl.response = { - format() { - return Promise.resolve('plain'); - } - }; + it('supports async response format and statusCode function', async function () { + await new Promise((resolve) => { + const apiImpl = sinon.stub().resolves({ok: true}); + apiImpl.statusCode = sinon.stub().returns(204); + apiImpl.response = { + format() { + return Promise.resolve('plain'); + } + }; + + res.send.callsFake(() => { + assert.equal(apiImpl.statusCode.calledOnce, true); + assert.equal(res.status.calledOnceWithExactly(204), true); + resolve(); + }); - res.send.callsFake(() => { - assert.equal(apiImpl.statusCode.calledOnce, true); - assert.equal(res.status.calledOnceWithExactly(204), true); - done(); + shared.http(apiImpl)(req, res, next); }); - - shared.http(apiImpl)(req, res, next); }); - it('supports sync response format function', function (done) { - const apiImpl = sinon.stub().resolves('plain body'); - apiImpl.response = { - format() { - return 'plain'; - } - }; + it('supports sync response format function', async function () { + await new Promise((resolve) => { + const apiImpl = sinon.stub().resolves('plain body'); + apiImpl.response = { + format() { + return 'plain'; + } + }; + + res.send.callsFake(() => { + assert.equal(res.send.calledOnce, true); + assert.equal(res.json.called, false); + resolve(); + }); - res.send.callsFake(() => { - assert.equal(res.send.calledOnce, true); - assert.equal(res.json.called, false); - done(); + shared.http(apiImpl)(req, res, next); }); - - shared.http(apiImpl)(req, res, next); }); - it('passes errors to next with frame options', function (done) { - const error = new Error('failure'); - const apiImpl = sinon.stub().rejects(error); - - next.callsFake((err) => { - assert.equal(err, error); - assert.deepEqual(req.frameOptions, { - docName: null, - method: null + it('passes errors to next with frame options', async function () { + await new Promise((resolve) => { + const error = new Error('failure'); + const apiImpl = sinon.stub().rejects(error); + + next.callsFake((err) => { + assert.equal(err, error); + assert.deepEqual(req.frameOptions, { + docName: null, + method: null + }); + resolve(); }); - done(); - }); - shared.http(apiImpl)(req, res, next); + shared.http(apiImpl)(req, res, next); + }); }); - it('uses req.url pathname when originalUrl is missing', function (done) { - req.originalUrl = undefined; - req.url = '/ghost/api/content/posts/?include=authors'; + it('uses req.url pathname when originalUrl is missing', async function () { + await new Promise((resolve) => { + req.originalUrl = undefined; + req.url = '/ghost/api/content/posts/?include=authors'; - const apiImpl = sinon.stub().resolves({}); - res.json.callsFake(() => { - const frame = apiImpl.args[0][0]; - assert.equal(frame.original.url.pathname, '/ghost/api/content/posts/'); - done(); - }); + const apiImpl = sinon.stub().resolves({}); + res.json.callsFake(() => { + const frame = apiImpl.args[0][0]; + assert.equal(frame.original.url.pathname, '/ghost/api/content/posts/'); + resolve(); + }); - shared.http(apiImpl)(req, res, next); + shared.http(apiImpl)(req, res, next); + }); }); }); diff --git a/packages/bookshelf-collision/package.json b/packages/bookshelf-collision/package.json index 2a56fd49b..67c8e012f 100644 --- a/packages/bookshelf-collision/package.json +++ b/packages/bookshelf-collision/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/bookshelf-custom-query/package.json b/packages/bookshelf-custom-query/package.json index aa5cf6a66..8da366602 100644 --- a/packages/bookshelf-custom-query/package.json +++ b/packages/bookshelf-custom-query/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" } diff --git a/packages/bookshelf-eager-load/package.json b/packages/bookshelf-eager-load/package.json index eb5711277..0dcc3a4ac 100644 --- a/packages/bookshelf-eager-load/package.json +++ b/packages/bookshelf-eager-load/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/bookshelf-filter/package.json b/packages/bookshelf-filter/package.json index f8e96299c..2291b2bcb 100644 --- a/packages/bookshelf-filter/package.json +++ b/packages/bookshelf-filter/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/bookshelf-has-posts/package.json b/packages/bookshelf-has-posts/package.json index b0b73859f..39579dcf3 100644 --- a/packages/bookshelf-has-posts/package.json +++ b/packages/bookshelf-has-posts/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/bookshelf-include-count/package.json b/packages/bookshelf-include-count/package.json index 430a4dae9..a1a2360ff 100644 --- a/packages/bookshelf-include-count/package.json +++ b/packages/bookshelf-include-count/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/bookshelf-order/package.json b/packages/bookshelf-order/package.json index 3be7850eb..519febc44 100644 --- a/packages/bookshelf-order/package.json +++ b/packages/bookshelf-order/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/bookshelf-pagination/package.json b/packages/bookshelf-pagination/package.json index d366a0604..efa35727f 100644 --- a/packages/bookshelf-pagination/package.json +++ b/packages/bookshelf-pagination/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -24,7 +24,6 @@ }, "devDependencies": { "mocha": "11.7.5", - "c8": "11.0.0", "sinon": "21.0.1" }, "dependencies": { diff --git a/packages/bookshelf-plugins/package.json b/packages/bookshelf-plugins/package.json index f65bb026f..de8cf974f 100644 --- a/packages/bookshelf-plugins/package.json +++ b/packages/bookshelf-plugins/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/bookshelf-search/package.json b/packages/bookshelf-search/package.json index 7529396e2..79e42a071 100644 --- a/packages/bookshelf-search/package.json +++ b/packages/bookshelf-search/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" } diff --git a/packages/bookshelf-transaction-events/package.json b/packages/bookshelf-transaction-events/package.json index 7eaabeab0..0fd66d09d 100644 --- a/packages/bookshelf-transaction-events/package.json +++ b/packages/bookshelf-transaction-events/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" } diff --git a/packages/config/package.json b/packages/config/package.json index 2cbb94d1e..f008fa7de 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5" }, "dependencies": { diff --git a/packages/database-info/package.json b/packages/database-info/package.json index 31088838a..4feefe32b 100644 --- a/packages/database-info/package.json +++ b/packages/database-info/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "knex": "3.1.0", "mocha": "11.7.5" } diff --git a/packages/debug/package.json b/packages/debug/package.json index 8096509c1..97a9ec97c 100644 --- a/packages/debug/package.json +++ b/packages/debug/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5" }, "dependencies": { diff --git a/packages/domain-events/package.json b/packages/domain-events/package.json index f08faf7bf..1fc21b54a 100644 --- a/packages/domain-events/package.json +++ b/packages/domain-events/package.json @@ -10,7 +10,7 @@ "types": "types", "scripts": { "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --check-coverage --100 -- mocha --reporter dot './test/**/*.test.js'", + "test:unit": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "test": "yarn test:unit", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", @@ -22,7 +22,6 @@ ], "devDependencies": { "@tryghost/logging": "^4.0.0", - "c8": "11.0.0", "mocha": "11.7.5" }, "repository": { diff --git a/packages/elasticsearch/package.json b/packages/elasticsearch/package.json index 2791c2bcb..c3dc40a91 100644 --- a/packages/elasticsearch/package.json +++ b/packages/elasticsearch/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/email-mock-receiver/package.json b/packages/email-mock-receiver/package.json index e15f72376..33aa71061 100644 --- a/packages/email-mock-receiver/package.json +++ b/packages/email-mock-receiver/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test:unit": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "test": "yarn test:unit", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", @@ -25,7 +25,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" } diff --git a/packages/email-mock-receiver/test/.eslintrc.js b/packages/email-mock-receiver/test/.eslintrc.js index 829b601eb..ef13dee0e 100644 --- a/packages/email-mock-receiver/test/.eslintrc.js +++ b/packages/email-mock-receiver/test/.eslintrc.js @@ -2,5 +2,8 @@ module.exports = { plugins: ['ghost'], extends: [ 'plugin:ghost/test' - ] + ], + globals: { + beforeAll: 'readonly' + } }; diff --git a/packages/email-mock-receiver/test/EmailMockReceiver.test.js b/packages/email-mock-receiver/test/EmailMockReceiver.test.js index e41c0895b..d3f51bbd3 100644 --- a/packages/email-mock-receiver/test/EmailMockReceiver.test.js +++ b/packages/email-mock-receiver/test/EmailMockReceiver.test.js @@ -7,7 +7,7 @@ describe('Email mock receiver', function () { let snapshotManager; let emailMockReceiver; - before(function () { + beforeAll(function () { snapshotManager = { assertSnapshot: sinon.spy() }; diff --git a/packages/errors/package.json b/packages/errors/package.json index 88e2bacc6..4f8f24120 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -21,7 +21,7 @@ "build:cjs": "esbuild src/*.ts --target=es2020 --outdir=cjs --format=cjs", "build:es": "esbuild src/*.ts --target=es2020 --outdir=es --format=esm", "build:types": "tsc --emitDeclarationOnly --declaration --declarationMap --outDir types", - "test": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' NODE_ENV=testing c8 --check-coverage --100 --all -n src --reporter text --reporter cobertura mocha -r ts-node/register './test/**/*.test.ts'", + "test": "NODE_ENV=testing vitest run --coverage", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -36,8 +36,6 @@ }, "devDependencies": { "@types/lodash": "4.17.24", - "@types/mocha": "10.0.10", - "c8": "11.0.0", "esbuild": "0.27.3", "lodash": "4.17.23", "mocha": "11.7.5", diff --git a/packages/errors/vitest.config.ts b/packages/errors/vitest.config.ts new file mode 100644 index 000000000..0a51d09c0 --- /dev/null +++ b/packages/errors/vitest.config.ts @@ -0,0 +1,12 @@ +import {defineConfig, mergeConfig} from 'vitest/config'; +import rootConfig from '../../vitest.config'; + +// Override: TypeScript package with source in src/, not lib/. +// Coverage must be scoped to src/ to measure the right files. +export default mergeConfig(rootConfig, defineConfig({ + test: { + coverage: { + include: ['src/**'] + } + } +})); diff --git a/packages/express-test/package.json b/packages/express-test/package.json index 7650710c8..d8ecfba0c 100644 --- a/packages/express-test/package.json +++ b/packages/express-test/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --check-coverage mocha --require ./test/utils/overrides.js './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "express": "5.2.1", "express-session": "1.19.0", "mocha": "11.7.5", diff --git a/packages/express-test/test/.eslintrc.js b/packages/express-test/test/.eslintrc.js index 829b601eb..ef13dee0e 100644 --- a/packages/express-test/test/.eslintrc.js +++ b/packages/express-test/test/.eslintrc.js @@ -2,5 +2,8 @@ module.exports = { plugins: ['ghost'], extends: [ 'plugin:ghost/test' - ] + ], + globals: { + beforeAll: 'readonly' + } }; diff --git a/packages/express-test/test/ExpectRequest.test.js b/packages/express-test/test/ExpectRequest.test.js index 8cbea7cbc..ac75564ad 100644 --- a/packages/express-test/test/ExpectRequest.test.js +++ b/packages/express-test/test/ExpectRequest.test.js @@ -41,127 +41,137 @@ describe('ExpectRequest', function () { } }); - it('finalize with no assertions doesnt try to run assertions', async function (done) { - const fn = (req, res) => { - // This is how reqresnext works - res.emit('finish'); - }; - const jar = {}; - const opts = new RequestOptions(); - const request = new ExpectRequest(fn, jar, opts); - - stubCookies(request); - - try { - const superStub = sinon.stub(Request.prototype, 'finalize').callsArg(0); - const assertSpy = sinon.stub(request, '_assertAll'); - - // I couldn't figure out how to stub the super.finalize call here - request.finalize((error) => { - if (error) { - done(error); - } - - sinon.assert.calledOnce(superStub); - assert.equal(error, null); - sinon.assert.notCalled(assertSpy); - done(); - }); - } catch (error) { - done(error); - } + it('finalize with no assertions doesnt try to run assertions', async function () { + await new Promise((resolve, reject) => { + const fn = (req, res) => { + // This is how reqresnext works + res.emit('finish'); + }; + const jar = {}; + const opts = new RequestOptions(); + const request = new ExpectRequest(fn, jar, opts); + + stubCookies(request); + + try { + const superStub = sinon.stub(Request.prototype, 'finalize').callsArg(0); + const assertSpy = sinon.stub(request, '_assertAll'); + + // I couldn't figure out how to stub the super.finalize call here + request.finalize((error) => { + if (error) { + reject(error); + return; + } + + sinon.assert.calledOnce(superStub); + assert.equal(error, null); + sinon.assert.notCalled(assertSpy); + resolve(); + }); + } catch (error) { + reject(error); + } + }); }); - it('finalize with assertions runs assertions', async function (done) { - const fn = (req, res) => { - // This is how reqresnext works - res.emit('finish'); - }; - const jar = {}; - const opts = new RequestOptions(); - const request = new ExpectRequest(fn, jar, opts); - - request.assertions = [{}]; - - stubCookies(request); - - try { - const superStub = sinon.stub(Request.prototype, 'finalize').callsArg(0); - const assertSpy = sinon.stub(request, '_assertAll'); - - request.finalize((error) => { - if (error) { - done(error); - } - - sinon.assert.calledOnce(superStub); - assert.equal(error, null); - sinon.assert.calledOnce(assertSpy); - done(); - }); - } catch (error) { - done(error); - } + it('finalize with assertions runs assertions', async function () { + await new Promise((resolve, reject) => { + const fn = (req, res) => { + // This is how reqresnext works + res.emit('finish'); + }; + const jar = {}; + const opts = new RequestOptions(); + const request = new ExpectRequest(fn, jar, opts); + + request.assertions = [{}]; + + stubCookies(request); + + try { + const superStub = sinon.stub(Request.prototype, 'finalize').callsArg(0); + const assertSpy = sinon.stub(request, '_assertAll'); + + request.finalize((error) => { + if (error) { + reject(error); + return; + } + + sinon.assert.calledOnce(superStub); + assert.equal(error, null); + sinon.assert.calledOnce(assertSpy); + resolve(); + }); + } catch (error) { + reject(error); + } + }); }); - it('finalize errors correctly when super.finalize is erroring', async function (done) { - const fn = (req, res) => { - // This is how reqresnext works - res.emit('finish'); - }; - const jar = {}; - const opts = new RequestOptions(); - const request = new ExpectRequest(fn, jar, opts); - - request.assertions = []; - - stubCookies(request); - - const theError = new Error(); - - try { - const superStub = sinon.stub(Request.prototype, 'finalize').callsArgWith(0, theError); - const assertSpy = sinon.stub(request, '_assertAll'); - - request.finalize((error) => { - sinon.assert.calledOnce(superStub); - assert.equal(error, theError); - sinon.assert.notCalled(assertSpy); - done(); - }); - } catch (error) { - done(error); - } + it('finalize errors correctly when super.finalize is erroring', async function () { + await new Promise((resolve, reject) => { + const fn = (req, res) => { + // This is how reqresnext works + res.emit('finish'); + }; + const jar = {}; + const opts = new RequestOptions(); + const request = new ExpectRequest(fn, jar, opts); + + request.assertions = []; + + stubCookies(request); + + const theError = new Error(); + + try { + const superStub = sinon.stub(Request.prototype, 'finalize').callsArgWith(0, theError); + const assertSpy = sinon.stub(request, '_assertAll'); + + request.finalize((error) => { + sinon.assert.calledOnce(superStub); + assert.equal(error, theError); + sinon.assert.notCalled(assertSpy); + resolve(); + }); + } catch (error) { + reject(error); + } + }); }); - it('finalize errors correctly when assertions are erroring', async function (done) { - const fn = (req, res) => { - // This is how reqresnext works - res.emit('finish'); - }; - const jar = {}; - const opts = new RequestOptions(); - const request = new ExpectRequest(fn, jar, opts); - - request.assertions = [{}]; - - stubCookies(request); - - const theError = new Error(); - - try { - const superStub = sinon.stub(Request.prototype, 'finalize').callsArg(0); - const assertSpy = sinon.stub(request, '_assertAll').throws(theError); - - request.finalize((error) => { - sinon.assert.calledOnce(superStub); - sinon.assert.calledOnce(assertSpy); - assert.equal(error, theError); - done(); - }); - } catch (error) { - done(error); - } + it('finalize errors correctly when assertions are erroring', async function () { + await new Promise((resolve, reject) => { + const fn = (req, res) => { + // This is how reqresnext works + res.emit('finish'); + }; + const jar = {}; + const opts = new RequestOptions(); + const request = new ExpectRequest(fn, jar, opts); + + request.assertions = [{}]; + + stubCookies(request); + + const theError = new Error(); + + try { + const superStub = sinon.stub(Request.prototype, 'finalize').callsArg(0); + const assertSpy = sinon.stub(request, '_assertAll').throws(theError); + + request.finalize((error) => { + sinon.assert.calledOnce(superStub); + sinon.assert.calledOnce(assertSpy); + assert.equal(error, theError); + resolve(); + }); + } catch (error) { + reject(error); + } + }); }); it('_addAssertion adds an assertion', function () { diff --git a/packages/express-test/test/Request.test.js b/packages/express-test/test/Request.test.js index 1b957e6fc..908d3ed52 100644 --- a/packages/express-test/test/Request.test.js +++ b/packages/express-test/test/Request.test.js @@ -235,26 +235,32 @@ describe('Request', function () { sinon.assert.calledOnceWithMatch(jar.setCookies, 'xyz'); }); - it('_doRequest', async function (done) { - const fn = (req, res) => { - // This is how reqresnext works - res.emit('finish'); - }; - const jar = {}; - const opts = new RequestOptions(); - const request = new Request(fn, jar, opts); - - // Stub cookies, we'll test this behaviour later - const {saveCookiesStub, restoreCookiesStub} = stubCookies(request); - - request._doRequest((error, response) => { - assert.equal(error, null); - assert.equal(response.statusCode, 200); + it('_doRequest', async function () { + await new Promise((resolve, reject) => { + const fn = (req, res) => { + // This is how reqresnext works + res.emit('finish'); + }; + const jar = {}; + const opts = new RequestOptions(); + const request = new Request(fn, jar, opts); + + // Stub cookies, we'll test this behaviour later + const {saveCookiesStub, restoreCookiesStub} = stubCookies(request); + + request._doRequest((error, response) => { + if (error) { + reject(error); + return; + } + assert.equal(error, null); + assert.equal(response.statusCode, 200); - sinon.assert.calledOnce(saveCookiesStub); - sinon.assert.calledOnce(restoreCookiesStub); + sinon.assert.calledOnce(saveCookiesStub); + sinon.assert.calledOnce(restoreCookiesStub); - done(); + resolve(); + }); }); }); diff --git a/packages/express-test/test/__snapshots__/example-app.test.js.snap b/packages/express-test/test/__snapshots__/example-app.test.js.snap index b1d833e84..555f0f088 100644 --- a/packages/express-test/test/__snapshots__/example-app.test.js.snap +++ b/packages/express-test/test/__snapshots__/example-app.test.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Example App Set & Expect check body using snapshot matching errors correctly for random data 1: [body] 1`] = ` Object { diff --git a/packages/express-test/test/example-app.test.js b/packages/express-test/test/example-app.test.js index eee811cbb..140b124d3 100644 --- a/packages/express-test/test/example-app.test.js +++ b/packages/express-test/test/example-app.test.js @@ -40,7 +40,7 @@ async function getExtendedAPIAgent() { } describe('Example App', function () { - before(async function () { + beforeAll(async function () { agent = await getAgent(); }); @@ -65,7 +65,7 @@ describe('Example App', function () { }); describe('API Agent with authentication in two steps', function () { - before(async function () { + beforeAll(async function () { agent = await getAPIAgent(); }); @@ -114,7 +114,7 @@ describe('Example App', function () { }); describe('API Agent with login function', function () { - before(async function () { + beforeAll(async function () { agent = await getExtendedAPIAgent(); await agent.login(); }); @@ -130,7 +130,7 @@ describe('Example App', function () { }); describe('Cookie clearing functionality', function () { - before(async function () { + beforeAll(async function () { agent = await getAPIAgent(); }); @@ -179,7 +179,7 @@ describe('Example App', function () { }); describe('Set & Expect', function () { - before(async function () { + beforeAll(async function () { agent = await getAgent(); }); diff --git a/packages/express-test/test/utils/overrides.js b/packages/express-test/test/utils/overrides.js index f256fa5ff..77dcb5dd7 100644 --- a/packages/express-test/test/utils/overrides.js +++ b/packages/express-test/test/utils/overrides.js @@ -1,2 +1,22 @@ -const {mochaHooks} = require('@tryghost/jest-snapshot'); -exports.mochaHooks = mochaHooks; +const {snapshotManager} = require('@tryghost/jest-snapshot'); + +/* eslint-disable ghost/mocha/no-mocha-arrows, ghost/mocha/no-top-level-hooks, ghost/mocha/handle-done-callback */ +beforeAll(() => { // eslint-disable-line no-undef + snapshotManager.resetRegistry(); +}); + +beforeEach((context) => { // eslint-disable-line no-undef + // Reconstruct full title similar to mocha's fullTitle() + const parts = []; + let suite = context.task.suite; + while (suite && suite.name) { + parts.unshift(suite.name); + suite = suite.suite; + } + parts.push(context.task.name); + + snapshotManager.setCurrentTest({ + testPath: context.task.file.filepath, + testTitle: parts.join(' ') + }); +}); diff --git a/packages/express-test/vitest.config.ts b/packages/express-test/vitest.config.ts new file mode 100644 index 000000000..c69603f55 --- /dev/null +++ b/packages/express-test/vitest.config.ts @@ -0,0 +1,10 @@ +import {defineConfig, mergeConfig} from 'vitest/config'; +import rootConfig from '../../vitest.config'; + +// Override: setupFiles needed to initialize the snapshot test registry +// before each test (replaces Mocha's --require flag). +export default mergeConfig(rootConfig, defineConfig({ + test: { + setupFiles: ['./test/utils/overrides.js'] + } +})); diff --git a/packages/http-cache-utils/package.json b/packages/http-cache-utils/package.json index fa9cf48c8..17cb9eac6 100644 --- a/packages/http-cache-utils/package.json +++ b/packages/http-cache-utils/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --check-coverage --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test:unit": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "test": "yarn test:unit", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", @@ -25,7 +25,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" } diff --git a/packages/http-stream/package.json b/packages/http-stream/package.json index 1248160b7..56f7f86c8 100644 --- a/packages/http-stream/package.json +++ b/packages/http-stream/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", "lint:test": "eslint -c test/.eslintrc.js test/ --ext .js --cache", @@ -25,7 +25,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "express": "5.2.1", "mocha": "11.7.5", "sinon": "21.0.1" diff --git a/packages/jest-snapshot/package.json b/packages/jest-snapshot/package.json index 6b732357c..7a7d653b1 100644 --- a/packages/jest-snapshot/package.json +++ b/packages/jest-snapshot/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura --reporter html-spa mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/jest-snapshot/test/SnapshotManager.test.js b/packages/jest-snapshot/test/SnapshotManager.test.js index bfc0079f0..255646fd3 100644 --- a/packages/jest-snapshot/test/SnapshotManager.test.js +++ b/packages/jest-snapshot/test/SnapshotManager.test.js @@ -99,9 +99,8 @@ describe('Snapshot Manager', function () { outputPath = snapshotManager._resolveSnapshotFilePath(inputPath); assert.equal(outputPath, '/full/path/to/tests/unit/__snapshots__/foo.js.snap'); - // Real example mocha context - const {test} = this; - inputPath = test.file; + // Real example using current test file path + inputPath = __filename; outputPath = snapshotManager._resolveSnapshotFilePath(inputPath); assert.match(outputPath, /\/packages\/jest-snapshot\/test\/__snapshots__\/SnapshotManager\.test\.js\.snap/); }); diff --git a/packages/job-manager/package.json b/packages/job-manager/package.json index d5da327bd..bcaf88cfb 100644 --- a/packages/job-manager/package.json +++ b/packages/job-manager/package.json @@ -9,7 +9,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura -- mocha --reporter dot './test/**/*.test.js'", + "test:unit": "NODE_ENV=testing vitest run --coverage", "test": "yarn test:unit", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", @@ -21,7 +21,6 @@ ], "devDependencies": { "@sinonjs/fake-timers": "15.1.0", - "c8": "11.0.0", "date-fns": "4.1.0", "mocha": "11.7.5", "rewire": "9.0.1", diff --git a/packages/job-manager/test/job-manager.test.js b/packages/job-manager/test/job-manager.test.js index 36e271b11..97aa70dcd 100644 --- a/packages/job-manager/test/job-manager.test.js +++ b/packages/job-manager/test/job-manager.test.js @@ -114,26 +114,18 @@ describe('Job Manager', function () { assert.equal(jobManager.bree.start.called, true); }); - it('fails to schedule for invalid scheduling expression', function () { - try { - jobManager.addJob({ - at: 'invalid expression', - name: 'jobName' - }); - } catch (err) { - assert.equal(err.message, 'Invalid schedule format'); - } + it('fails to schedule for invalid scheduling expression', async function () { + await assert.rejects(() => jobManager.addJob({ + at: 'invalid expression', + name: 'jobName' + }), {message: 'Invalid schedule format'}); }); - it('fails to schedule for no job name', function () { - try { - jobManager.addJob({ - at: 'invalid expression', - job: () => {} - }); - } catch (err) { - assert.equal(err.message, 'Name parameter should be present if job is a function'); - } + it('fails to schedule for no job name', async function () { + await assert.rejects(() => jobManager.addJob({ + at: 'invalid expression', + job: () => {} + }), {message: 'Name parameter should be present if job is a function'}); }); it('schedules a job using date format', async function () { diff --git a/packages/job-manager/vitest.config.ts b/packages/job-manager/vitest.config.ts new file mode 100644 index 000000000..601b1a6ad --- /dev/null +++ b/packages/job-manager/vitest.config.ts @@ -0,0 +1,11 @@ +import {defineConfig, mergeConfig} from 'vitest/config'; +import rootConfig from '../../vitest.config'; + +// Override: Bree spawns background workers that emit unhandled rejections +// during cleanup after tests complete. These are expected and were silently +// ignored by Mocha. +export default mergeConfig(rootConfig, defineConfig({ + test: { + dangerouslyIgnoreUnhandledErrors: true + } +})); diff --git a/packages/logging/package.json b/packages/logging/package.json index 0f24f98d7..ef7fdc521 100644 --- a/packages/logging/package.json +++ b/packages/logging/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha --exit './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -24,7 +24,6 @@ }, "devDependencies": { "@tryghost/errors": "1.0.0", - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/logging/test/logging.test.js b/packages/logging/test/logging.test.js index 0cddfbe57..0c997e40d 100644 --- a/packages/logging/test/logging.test.js +++ b/packages/logging/test/logging.test.js @@ -69,122 +69,136 @@ describe('Logging', function () { // in Bunyan 1.8.3 they have changed this behaviour // they are trying to find the err.message attribute and forward this as msg property // our PrettyStream implementation can't handle this case - it('ensure stdout write properties', function (done) { - sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.req, null); - assert.notEqual(data.req.headers, null); - assert.equal(data.req.body, undefined); - assert.notEqual(data.res, null); - assert.notEqual(data.err, null); - assert.equal(data.name, 'testLogging'); - assert.equal(data.msg, 'message'); - done(); - }); + it('ensure stdout write properties', async function () { + await new Promise((resolve) => { + sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.req, null); + assert.notEqual(data.req.headers, null); + assert.equal(data.req.body, undefined); + assert.notEqual(data.res, null); + assert.notEqual(data.err, null); + assert.equal(data.name, 'testLogging'); + assert.equal(data.msg, 'message'); + resolve(); + }); - var ghostLogger = new GhostLogger({name: 'testLogging'}); - ghostLogger.info({err: new Error('message'), req: {body: {}, headers: {}}, res: {getHeaders: () => ({})}}); + var ghostLogger = new GhostLogger({name: 'testLogging'}); + ghostLogger.info({err: new Error('message'), req: {body: {}, headers: {}}, res: {getHeaders: () => ({})}}); + }); }); - it('ensure stdout write properties with custom message', function (done) { - sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { - assert.notEqual(data, null); - assert.equal(data.name, 'Log'); - assert.equal(data.msg, 'A handled error! Original message'); - done(); - }); + it('ensure stdout write properties with custom message', async function () { + await new Promise((resolve) => { + sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { + assert.notEqual(data, null); + assert.equal(data.name, 'Log'); + assert.equal(data.msg, 'A handled error! Original message'); + resolve(); + }); - var ghostLogger = new GhostLogger(); - ghostLogger.warn('A handled error!', new Error('Original message')); + var ghostLogger = new GhostLogger(); + ghostLogger.warn('A handled error!', new Error('Original message')); + }); }); - it('ensure stdout write properties with object', function (done) { - sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - assert.equal(data.test, 2); - assert.equal(data.name, 'Log'); - assert.equal(data.msg, 'Got an error from 3rd party service X! Resource could not be found.'); - done(); - }); + it('ensure stdout write properties with object', async function () { + await new Promise((resolve) => { + sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.err, null); + assert.equal(data.test, 2); + assert.equal(data.name, 'Log'); + assert.equal(data.msg, 'Got an error from 3rd party service X! Resource could not be found.'); + resolve(); + }); - var ghostLogger = new GhostLogger(); - ghostLogger.error({err: new errors.NotFoundError(), test: 2}, 'Got an error from 3rd party service X!'); + var ghostLogger = new GhostLogger(); + ghostLogger.error({err: new errors.NotFoundError(), test: 2}, 'Got an error from 3rd party service X!'); + }); }); - it('ensure stdout write metadata properties', function (done) { - sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { - assert.equal(data.version, 2); - assert.equal(data.msg, 'Message to be logged!'); - done(); - }); + it('ensure stdout write metadata properties', async function () { + await new Promise((resolve) => { + sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { + assert.equal(data.version, 2); + assert.equal(data.msg, 'Message to be logged!'); + resolve(); + }); - var ghostLogger = new GhostLogger({metadata: {version: 2}}); - ghostLogger.info('Message to be logged!'); + var ghostLogger = new GhostLogger({metadata: {version: 2}}); + ghostLogger.info('Message to be logged!'); + }); }); - it('ensure stdout write properties with util.format', function (done) { - sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { - assert.notEqual(data, null); - assert.equal(data.name, 'Log'); - assert.equal(data.msg, 'Message with format'); - done(); - }); + it('ensure stdout write properties with util.format', async function () { + await new Promise((resolve) => { + sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { + assert.notEqual(data, null); + assert.equal(data.name, 'Log'); + assert.equal(data.msg, 'Message with format'); + resolve(); + }); - var ghostLogger = new GhostLogger(); - var thing = 'format'; - ghostLogger.info('Message with %s', thing); + var ghostLogger = new GhostLogger(); + var thing = 'format'; + ghostLogger.info('Message with %s', thing); + }); }); - it('redact sensitive data with request body', function (done) { - sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.req.body.password, null); - assert.equal(data.req.body.password, '**REDACTED**'); - assert.notEqual(data.req.body.data.attributes.pin, null); - assert.equal(data.req.body.data.attributes.pin, '**REDACTED**'); - assert.notEqual(data.req.body.data.attributes.test, null); - assert.notEqual(data.err, null); - assert.notEqual(data.err.errorDetails, null); - done(); - }); + it('redact sensitive data with request body', async function () { + await new Promise((resolve) => { + sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.req.body.password, null); + assert.equal(data.req.body.password, '**REDACTED**'); + assert.notEqual(data.req.body.data.attributes.pin, null); + assert.equal(data.req.body.data.attributes.pin, '**REDACTED**'); + assert.notEqual(data.req.body.data.attributes.test, null); + assert.notEqual(data.err, null); + assert.notEqual(data.err.errorDetails, null); + resolve(); + }); - var ghostLogger = new GhostLogger({logBody: true}); + var ghostLogger = new GhostLogger({logBody: true}); - ghostLogger.error({ - err: new errors.IncorrectUsageError({message: 'Hallo', errorDetails: []}), - req: { - body: { - password: '12345678', - data: { - attributes: { - pin: '1234', - test: 'ja' + ghostLogger.error({ + err: new errors.IncorrectUsageError({message: 'Hallo', errorDetails: []}), + req: { + body: { + password: '12345678', + data: { + attributes: { + pin: '1234', + test: 'ja' + } } + }, + headers: { + authorization: 'secret', + Connection: 'keep-alive' } }, - headers: { - authorization: 'secret', - Connection: 'keep-alive' - } - }, - res: {getHeaders: () => ({})} + res: {getHeaders: () => ({})} + }); }); }); - it('gelf writes a log message', function (done) { - sandbox.stub(GelfStream.prototype, '_write').callsFake(function (data) { - assert.notEqual(data.err, null); - done(); - }); + it('gelf writes a log message', async function () { + await new Promise((resolve) => { + sandbox.stub(GelfStream.prototype, '_write').callsFake(function (data) { + assert.notEqual(data.err, null); + resolve(); + }); - var ghostLogger = new GhostLogger({ - transports: ['gelf'], - gelf: { - host: 'localhost', - port: 12201 - } - }); + var ghostLogger = new GhostLogger({ + transports: ['gelf'], + gelf: { + host: 'localhost', + port: 12201 + } + }); - ghostLogger.error(new errors.NotFoundError()); - assert.equal(GelfStream.prototype._write.called, true); + ghostLogger.error(new errors.NotFoundError()); + assert.equal(GelfStream.prototype._write.called, true); + }); }); it('gelf uses default host and port when not provided', function () { @@ -212,23 +226,25 @@ describe('Logging', function () { assert.equal(GelfStream.prototype._write.called, false); }); - it('loggly does only stream certain errors', function (done) { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - done(); - }); + it('loggly does only stream certain errors', async function () { + await new Promise((resolve) => { + sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.err, null); + resolve(); + }); - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: 'level:critical' - } - }); + var ghostLogger = new GhostLogger({ + transports: ['loggly'], + loggly: { + token: 'invalid', + subdomain: 'invalid', + match: 'level:critical' + } + }); - ghostLogger.error(new errors.InternalServerError()); - assert.equal(Bunyan2Loggly.prototype.write.called, true); + ghostLogger.error(new errors.InternalServerError()); + assert.equal(Bunyan2Loggly.prototype.write.called, true); + }); }); it('loggly does not stream non-critical errors when matching critical', function () { @@ -295,23 +311,25 @@ describe('Logging', function () { assert.equal(Bunyan2Loggly.prototype.write.called, true); }); - it('loggly does stream errors that match normal level', function (done) { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - done(); - }); + it('loggly does stream errors that match normal level', async function () { + await new Promise((resolve) => { + sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.err, null); + resolve(); + }); - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: 'level:normal' - } - }); + var ghostLogger = new GhostLogger({ + transports: ['loggly'], + loggly: { + token: 'invalid', + subdomain: 'invalid', + match: 'level:normal' + } + }); - ghostLogger.error(new errors.NotFoundError()); - assert.equal(Bunyan2Loggly.prototype.write.called, true); + ghostLogger.error(new errors.NotFoundError()); + assert.equal(Bunyan2Loggly.prototype.write.called, true); + }); }); it('loggly match can evaluate with null err payload', function () { @@ -330,66 +348,72 @@ describe('Logging', function () { assert.equal(Bunyan2Loggly.prototype.write.called, true); }); - it('loggly does stream errors that match an one of multiple match statements', function (done) { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - done(); - }); + it('loggly does stream errors that match an one of multiple match statements', async function () { + await new Promise((resolve) => { + sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.err, null); + resolve(); + }); - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: 'level:critical|statusCode:404' - } - }); + var ghostLogger = new GhostLogger({ + transports: ['loggly'], + loggly: { + token: 'invalid', + subdomain: 'invalid', + match: 'level:critical|statusCode:404' + } + }); - ghostLogger.error(new errors.NotFoundError()); - assert.equal(Bunyan2Loggly.prototype.write.called, true); + ghostLogger.error(new errors.NotFoundError()); + assert.equal(Bunyan2Loggly.prototype.write.called, true); + }); }); - it('loggly does stream errors that match status code: full example', function (done) { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - assert.notEqual(data.req, null); - assert.notEqual(data.res, null); - done(); - }); + it('loggly does stream errors that match status code: full example', async function () { + await new Promise((resolve) => { + sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.err, null); + assert.notEqual(data.req, null); + assert.notEqual(data.res, null); + resolve(); + }); - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid', - match: 'statusCode:404' - } - }); + var ghostLogger = new GhostLogger({ + transports: ['loggly'], + loggly: { + token: 'invalid', + subdomain: 'invalid', + match: 'statusCode:404' + } + }); - ghostLogger.error({ - err: new errors.NotFoundError(), - req: {body: {password: '12345678', data: {attributes: {pin: '1234', test: 'ja'}}}}, - res: {getHeaders: () => ({})} + ghostLogger.error({ + err: new errors.NotFoundError(), + req: {body: {password: '12345678', data: {attributes: {pin: '1234', test: 'ja'}}}}, + res: {getHeaders: () => ({})} + }); + assert.equal(Bunyan2Loggly.prototype.write.called, true); }); - assert.equal(Bunyan2Loggly.prototype.write.called, true); }); - it('loggly does only stream certain errors: match is not defined -> log everything', function (done) { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - done(); - }); + it('loggly does only stream certain errors: match is not defined -> log everything', async function () { + await new Promise((resolve) => { + sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.err, null); + resolve(); + }); - var ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid' - } - }); + var ghostLogger = new GhostLogger({ + transports: ['loggly'], + loggly: { + token: 'invalid', + subdomain: 'invalid' + } + }); - ghostLogger.error(new errors.NotFoundError()); - assert.equal(Bunyan2Loggly.prototype.write.called, true); + ghostLogger.error(new errors.NotFoundError()); + assert.equal(Bunyan2Loggly.prototype.write.called, true); + }); }); it('elasticsearch should make a stream', function () { @@ -430,21 +454,23 @@ describe('Logging', function () { }, 'hello', 1); }); - it('http writes a log message', function (done) { - sandbox.stub(HttpStream.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - done(); - }); + it('http writes a log message', async function () { + await new Promise((resolve) => { + sandbox.stub(HttpStream.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.err, null); + resolve(); + }); - var ghostLogger = new GhostLogger({ - transports: ['http'], - http: { - host: 'http://localhost' - } - }); + var ghostLogger = new GhostLogger({ + transports: ['http'], + http: { + host: 'http://localhost' + } + }); - ghostLogger.error(new errors.NotFoundError()); - assert.equal(HttpStream.prototype.write.called, true); + ghostLogger.error(new errors.NotFoundError()); + assert.equal(HttpStream.prototype.write.called, true); + }); }); it('http does not write an info log in error mode', function () { @@ -691,71 +717,75 @@ describe('Logging', function () { }); describe('serialization', function () { - it('serializes error into correct object', function (done) { - const err = new errors.NotFoundError(); + it('serializes error into correct object', async function () { + await new Promise((resolve) => { + const err = new errors.NotFoundError(); + + sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.err, null); + assert.equal(data.err.id, err.id); + assert.equal(data.err.domain, 'localhost'); + assert.equal(data.err.code, null); + assert.equal(data.err.name, err.errorType); + assert.equal(data.err.statusCode, err.statusCode); + assert.equal(data.err.level, err.level); + assert.equal(data.err.message, err.message); + assert.equal(data.err.context, undefined); + assert.equal(data.err.help, undefined); + assert.notEqual(data.err.stack, null); + assert.equal(data.err.hideStack, undefined); + assert.equal(data.err.errorDetails, undefined); + resolve(); + }); - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - assert.equal(data.err.id, err.id); - assert.equal(data.err.domain, 'localhost'); - assert.equal(data.err.code, null); - assert.equal(data.err.name, err.errorType); - assert.equal(data.err.statusCode, err.statusCode); - assert.equal(data.err.level, err.level); - assert.equal(data.err.message, err.message); - assert.equal(data.err.context, undefined); - assert.equal(data.err.help, undefined); - assert.notEqual(data.err.stack, null); - assert.equal(data.err.hideStack, undefined); - assert.equal(data.err.errorDetails, undefined); - done(); - }); + const ghostLogger = new GhostLogger({ + transports: ['loggly'], + loggly: { + token: 'invalid', + subdomain: 'invalid' + } + }); + ghostLogger.error({ + err + }); - const ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid' - } + assert.equal(Bunyan2Loggly.prototype.write.called, true); }); - ghostLogger.error({ - err - }); - - assert.equal(Bunyan2Loggly.prototype.write.called, true); }); - it('stringifies meta properties', function (done) { - sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.err, null); - assert.equal(data.err.context, '{"a":"b"}'); - assert.equal(data.err.errorDetails, '{"c":"d"}'); - assert.equal(data.err.help, '{"b":"a"}'); - done(); - }); + it('stringifies meta properties', async function () { + await new Promise((resolve) => { + sandbox.stub(Bunyan2Loggly.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.err, null); + assert.equal(data.err.context, '{"a":"b"}'); + assert.equal(data.err.errorDetails, '{"c":"d"}'); + assert.equal(data.err.help, '{"b":"a"}'); + resolve(); + }); - const ghostLogger = new GhostLogger({ - transports: ['loggly'], - loggly: { - token: 'invalid', - subdomain: 'invalid' - } - }); - ghostLogger.error({ - err: new errors.NotFoundError({ - context: { - a: 'b' - }, - errorDetails: { - c: 'd' - }, - help: { - b: 'a' + const ghostLogger = new GhostLogger({ + transports: ['loggly'], + loggly: { + token: 'invalid', + subdomain: 'invalid' } - }) - }); + }); + ghostLogger.error({ + err: new errors.NotFoundError({ + context: { + a: 'b' + }, + errorDetails: { + c: 'd' + }, + help: { + b: 'a' + } + }) + }); - assert.equal(Bunyan2Loggly.prototype.write.called, true); + assert.equal(Bunyan2Loggly.prototype.write.called, true); + }); }); it('serializes req extra and queueDepth fields when present', function () { diff --git a/packages/metrics/package.json b/packages/metrics/package.json index d129d4541..a76c418c0 100644 --- a/packages/metrics/package.json +++ b/packages/metrics/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "rewire": "9.0.1", "sinon": "21.0.1" diff --git a/packages/metrics/test/metrics.test.js b/packages/metrics/test/metrics.test.js index 3495c35bf..f8016b59a 100644 --- a/packages/metrics/test/metrics.test.js +++ b/packages/metrics/test/metrics.test.js @@ -8,6 +8,19 @@ const {getProcessRoot} = require('@tryghost/root-utils'); const GhostMetrics = require('../lib/GhostMetrics'); const sandbox = sinon.createSandbox(); +// Vitest sets process.env.MODE to 'test' which interferes with GhostMetrics mode detection +const originalMode = process.env.MODE; +beforeEach(function () { + delete process.env.MODE; +}); +afterEach(function () { + if (originalMode !== undefined) { + process.env.MODE = originalMode; + } else { + delete process.env.MODE; + } +}); + const loggingConfigPath = path.join(getProcessRoot(), 'loggingrc'); describe('Metrics config', function () { @@ -51,25 +64,27 @@ describe('Logging', function () { sandbox.restore(); }); - it('stdout transport works', function (done) { + it('stdout transport works', async function () { const name = 'test-metric'; const value = 101; - sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { - assert.notEqual(data.msg, undefined); - assert.equal(data.msg, `Metric ${name}: ${JSON.stringify(value)}`); - done(); - }); + await new Promise((resolve) => { + sandbox.stub(PrettyStream.prototype, 'write').callsFake(function (data) { + assert.notEqual(data.msg, undefined); + assert.equal(data.msg, `Metric ${name}: ${JSON.stringify(value)}`); + resolve(); + }); - const ghostMetrics = new GhostMetrics({ - metrics: { - transports: ['stdout'] - } + const ghostMetrics = new GhostMetrics({ + metrics: { + transports: ['stdout'] + } + }); + ghostMetrics.metric(name, value); }); - ghostMetrics.metric(name, value); }); - it('elasticsearch transport works', function (done) { + it('elasticsearch transport works', async function () { const name = 'test-metric'; const value = 101; @@ -88,17 +103,19 @@ describe('Logging', function () { } }); - sandbox.stub(ElasticSearch.prototype, 'index').callsFake(function (data, index) { - assert.notEqual(data.metadata, undefined); - assert.equal(data.metadata.id, ghostMetrics.metadata.id); - assert.equal(data.value, value); + await new Promise((resolve) => { + sandbox.stub(ElasticSearch.prototype, 'index').callsFake(function (data, index) { + assert.notEqual(data.metadata, undefined); + assert.equal(data.metadata.id, ghostMetrics.metadata.id); + assert.equal(data.value, value); - // ElasticSearch shipper prefixes metric names to avoid polluting index namespace - assert.equal(index, 'metrics-' + name); - done(); - }); + // ElasticSearch shipper prefixes metric names to avoid polluting index namespace + assert.equal(index, 'metrics-' + name); + resolve(); + }); - ghostMetrics.metric(name, value); + ghostMetrics.metric(name, value); + }); }); it('throws for invalid transport', function () { diff --git a/packages/mw-error-handler/package.json b/packages/mw-error-handler/package.json index d70c5daa7..a1392eba2 100644 --- a/packages/mw-error-handler/package.json +++ b/packages/mw-error-handler/package.json @@ -10,7 +10,7 @@ }, "scripts": { "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura -- mocha --reporter dot './test/**/*.test.js'", + "test:unit": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "test": "yarn test:unit", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", @@ -21,7 +21,6 @@ "lib" ], "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/mw-error-handler/test/mw-error-handler.test.js b/packages/mw-error-handler/test/mw-error-handler.test.js index 0612f4d4d..009ab3b50 100644 --- a/packages/mw-error-handler/test/mw-error-handler.test.js +++ b/packages/mw-error-handler/test/mw-error-handler.test.js @@ -16,94 +16,106 @@ const { } = require('..'); describe('Prepare Error', function () { - it('Correctly prepares a non-Ghost error', function (done) { - prepareError(new Error('test!'), {}, { - set: () => {} - }, (err) => { - assert.equal(err.statusCode, 500); - assert.equal(err.name, 'InternalServerError'); - assert.equal(err.message, 'An unexpected error occurred, please try again.'); - assert.equal(err.context, 'test!'); - assert.equal(err.code, 'UNEXPECTED_ERROR'); - assert.ok(err.stack.startsWith('Error: test!')); - done(); + it('Correctly prepares a non-Ghost error', async function () { + await new Promise((resolve) => { + prepareError(new Error('test!'), {}, { + set: () => {} + }, (err) => { + assert.equal(err.statusCode, 500); + assert.equal(err.name, 'InternalServerError'); + assert.equal(err.message, 'An unexpected error occurred, please try again.'); + assert.equal(err.context, 'test!'); + assert.equal(err.code, 'UNEXPECTED_ERROR'); + assert.ok(err.stack.startsWith('Error: test!')); + resolve(); + }); }); }); - it('Correctly prepares a Ghost error', function (done) { - prepareError(new InternalServerError({message: 'Handled Error', context: 'Details'}), {}, { - set: () => {} - }, (err) => { - assert.equal(err.statusCode, 500); - assert.equal(err.name, 'InternalServerError'); - assert.equal(err.message, 'Handled Error'); - assert.equal(err.context, 'Details'); - assert.ok(err.stack.startsWith('InternalServerError: Handled Error')); - done(); + it('Correctly prepares a Ghost error', async function () { + await new Promise((resolve) => { + prepareError(new InternalServerError({message: 'Handled Error', context: 'Details'}), {}, { + set: () => {} + }, (err) => { + assert.equal(err.statusCode, 500); + assert.equal(err.name, 'InternalServerError'); + assert.equal(err.message, 'Handled Error'); + assert.equal(err.context, 'Details'); + assert.ok(err.stack.startsWith('InternalServerError: Handled Error')); + resolve(); + }); }); }); - it('Correctly prepares a 404 error', function (done) { + it('Correctly prepares a 404 error', async function () { let error = {message: 'Oh dear', statusCode: 404}; - prepareError(error, {}, { - set: () => {} - }, (err) => { - assert.equal(err.statusCode, 404); - assert.equal(err.name, 'NotFoundError'); - assert.ok(err.stack.startsWith('NotFoundError: Resource could not be found')); - assert.equal(err.hideStack, true); - done(); + await new Promise((resolve) => { + prepareError(error, {}, { + set: () => {} + }, (err) => { + assert.equal(err.statusCode, 404); + assert.equal(err.name, 'NotFoundError'); + assert.ok(err.stack.startsWith('NotFoundError: Resource could not be found')); + assert.equal(err.hideStack, true); + resolve(); + }); }); }); - it('Correctly prepares an error array', function (done) { - prepareError([new Error('test!')], {}, { - set: () => {} - }, (err) => { - assert.equal(err.statusCode, 500); - assert.equal(err.name, 'InternalServerError'); - assert.ok(err.stack.startsWith('Error: test!')); - done(); + it('Correctly prepares an error array', async function () { + await new Promise((resolve) => { + prepareError([new Error('test!')], {}, { + set: () => {} + }, (err) => { + assert.equal(err.statusCode, 500); + assert.equal(err.name, 'InternalServerError'); + assert.ok(err.stack.startsWith('Error: test!')); + resolve(); + }); }); }); - it('Correctly prepares a handlebars error', function (done) { + it('Correctly prepares a handlebars error', async function () { let error = new Error('obscure handlebars message!'); error.stack += '\n'; error.stack += path.join('node_modules', 'handlebars', 'something'); - prepareError(error, {}, { - set: () => {} - }, (err) => { - assert.equal(err.statusCode, 400); - assert.equal(err.name, 'IncorrectUsageError'); - // TODO: consider if the message should be trusted here - assert.equal(err.message, 'obscure handlebars message!'); - assert.ok(err.stack.startsWith('Error: obscure handlebars message!')); - done(); + await new Promise((resolve) => { + prepareError(error, {}, { + set: () => {} + }, (err) => { + assert.equal(err.statusCode, 400); + assert.equal(err.name, 'IncorrectUsageError'); + // TODO: consider if the message should be trusted here + assert.equal(err.message, 'obscure handlebars message!'); + assert.ok(err.stack.startsWith('Error: obscure handlebars message!')); + resolve(); + }); }); }); - it('Correctly prepares an express-hbs error', function (done) { + it('Correctly prepares an express-hbs error', async function () { let error = new Error('obscure express-hbs message!'); error.stack += '\n'; error.stack += path.join('node_modules', 'express-hbs', 'lib'); - prepareError(error, {}, { - set: () => {} - }, (err) => { - assert.equal(err.statusCode, 400); - assert.equal(err.name, 'IncorrectUsageError'); - assert.equal(err.message, 'obscure express-hbs message!'); - assert.ok(err.stack.startsWith('Error: obscure express-hbs message!')); - done(); + await new Promise((resolve) => { + prepareError(error, {}, { + set: () => {} + }, (err) => { + assert.equal(err.statusCode, 400); + assert.equal(err.name, 'IncorrectUsageError'); + assert.equal(err.message, 'obscure express-hbs message!'); + assert.ok(err.stack.startsWith('Error: obscure express-hbs message!')); + resolve(); + }); }); }); - it('Correctly prepares a known ER_WRONG_VALUE mysql2 error', function (done) { + it('Correctly prepares a known ER_WRONG_VALUE mysql2 error', async function () { let error = new Error('select anything from anywhere where something = anything;'); error.stack += '\n'; @@ -112,21 +124,23 @@ describe('Prepare Error', function () { error.sql = 'select anything from anywhere where something = anything;'; error.sqlMessage = 'Incorrect DATETIME value: 3234234234'; - prepareError(error, {}, { - set: () => {} - }, (err) => { - assert.equal(err.statusCode, 422); - assert.equal(err.name, 'ValidationError'); - assert.equal(err.message, 'Invalid value'); - assert.equal(err.code, 'ER_WRONG_VALUE'); - assert.equal(err.sqlErrorCode, 'ER_WRONG_VALUE'); - assert.equal(err.sql, 'select anything from anywhere where something = anything;'); - assert.equal(err.sqlMessage, 'Incorrect DATETIME value: 3234234234'); - done(); + await new Promise((resolve) => { + prepareError(error, {}, { + set: () => {} + }, (err) => { + assert.equal(err.statusCode, 422); + assert.equal(err.name, 'ValidationError'); + assert.equal(err.message, 'Invalid value'); + assert.equal(err.code, 'ER_WRONG_VALUE'); + assert.equal(err.sqlErrorCode, 'ER_WRONG_VALUE'); + assert.equal(err.sql, 'select anything from anywhere where something = anything;'); + assert.equal(err.sqlMessage, 'Incorrect DATETIME value: 3234234234'); + resolve(); + }); }); }); - it('Correctly prepares an unknown mysql2 error', function (done) { + it('Correctly prepares an unknown mysql2 error', async function () { let error = new Error('select anything from anywhere where something = anything;'); error.stack += '\n'; @@ -135,46 +149,52 @@ describe('Prepare Error', function () { error.sql = 'select anything from anywhere where something = anything;'; error.sqlMessage = 'Incorrect value: erororoor'; - prepareError(error, {}, { - set: () => {} - }, (err) => { - assert.equal(err.statusCode, 500); - assert.equal(err.name, 'InternalServerError'); - assert.equal(err.message, 'An unexpected error occurred, please try again.'); - assert.equal(err.code, 'UNEXPECTED_ERROR'); - assert.equal(err.sqlErrorCode, 'ER_BAD_FIELD_ERROR'); - assert.equal(err.sql, 'select anything from anywhere where something = anything;'); - assert.equal(err.sqlMessage, 'Incorrect value: erororoor'); - done(); + await new Promise((resolve) => { + prepareError(error, {}, { + set: () => {} + }, (err) => { + assert.equal(err.statusCode, 500); + assert.equal(err.name, 'InternalServerError'); + assert.equal(err.message, 'An unexpected error occurred, please try again.'); + assert.equal(err.code, 'UNEXPECTED_ERROR'); + assert.equal(err.sqlErrorCode, 'ER_BAD_FIELD_ERROR'); + assert.equal(err.sql, 'select anything from anywhere where something = anything;'); + assert.equal(err.sqlMessage, 'Incorrect value: erororoor'); + resolve(); + }); }); }); }); describe('Prepare Stack', function () { - it('Correctly prepares the stack for an error', function (done) { - prepareStack(new Error('test!'), {}, {}, (err) => { - // Includes "Stack Trace" text prepending human readable trace - assert.ok(err.stack.startsWith('Error: test!\nStack Trace:')); - done(); + it('Correctly prepares the stack for an error', async function () { + await new Promise((resolve) => { + prepareStack(new Error('test!'), {}, {}, (err) => { + // Includes "Stack Trace" text prepending human readable trace + assert.ok(err.stack.startsWith('Error: test!\nStack Trace:')); + resolve(); + }); }); }); }); describe('Prepare Error Cache Control', function () { - it('Sets private cache control by default', function (done) { + it('Sets private cache control by default', async function () { const res = { set: sinon.spy() }; - prepareErrorCacheControl()(new Error('generic error'), {}, res, () => { - assert(res.set.calledOnce); - assert(res.set.calledWith({ - 'Cache-Control': cacheControlValues.private - })); - done(); + await new Promise((resolve) => { + prepareErrorCacheControl()(new Error('generic error'), {}, res, () => { + assert(res.set.calledOnce); + assert(res.set.calledWith({ + 'Cache-Control': cacheControlValues.private + })); + resolve(); + }); }); }); - it('Sets private cache-control header for user-specific 404 responses', function (done) { + it('Sets private cache-control header for user-specific 404 responses', async function () { const req = { method: 'GET', get: (header) => { @@ -186,16 +206,18 @@ describe('Prepare Error Cache Control', function () { const res = { set: sinon.spy() }; - prepareErrorCacheControl()(new NotFoundError(), req, res, () => { - assert(res.set.calledOnce); - assert(res.set.calledWith({ - 'Cache-Control': cacheControlValues.private - })); - done(); + await new Promise((resolve) => { + prepareErrorCacheControl()(new NotFoundError(), req, res, () => { + assert(res.set.calledOnce); + assert(res.set.calledWith({ + 'Cache-Control': cacheControlValues.private + })); + resolve(); + }); }); }); - it('Sets noCache cache-control header for non-user-specific 404 responses', function (done) { + it('Sets noCache cache-control header for non-user-specific 404 responses', async function () { const req = { method: 'GET', get: () => { @@ -208,78 +230,88 @@ describe('Prepare Error Cache Control', function () { return false; } }; - prepareErrorCacheControl()(new NotFoundError(), req, res, () => { - assert(res.set.calledOnce); - assert(res.set.calledWith({ - 'Cache-Control': cacheControlValues.noCacheDynamic - })); - done(); + await new Promise((resolve) => { + prepareErrorCacheControl()(new NotFoundError(), req, res, () => { + assert(res.set.calledOnce); + assert(res.set.calledWith({ + 'Cache-Control': cacheControlValues.noCacheDynamic + })); + resolve(); + }); }); }); }); describe('Error renderers', function () { - it('Renders JSON', function (done) { - jsonErrorRenderer(new Error('test!'), {}, { - json: (data) => { - assert.equal(data.errors.length, 1); - assert.equal(data.errors[0].message, 'test!'); - done(); - } - }, () => {}); + it('Renders JSON', async function () { + await new Promise((resolve) => { + jsonErrorRenderer(new Error('test!'), {}, { + json: (data) => { + assert.equal(data.errors.length, 1); + assert.equal(data.errors[0].message, 'test!'); + resolve(); + } + }, () => {}); + }); }); - it('Handles unknown errors when preparing user message', function (done) { - jsonErrorRenderer(new RangeError('test!'), { - frameOptions: { - docName: 'oembed', - method: 'read' - } - }, { - json: (data) => { - assert.equal(data.errors.length, 1); - assert.equal(data.errors[0].message, 'Unknown error - RangeError, cannot read oembed.'); - assert.equal(data.errors[0].context, 'test!'); - done(); - } - }, () => {}); + it('Handles unknown errors when preparing user message', async function () { + await new Promise((resolve) => { + jsonErrorRenderer(new RangeError('test!'), { + frameOptions: { + docName: 'oembed', + method: 'read' + } + }, { + json: (data) => { + assert.equal(data.errors.length, 1); + assert.equal(data.errors[0].message, 'Unknown error - RangeError, cannot read oembed.'); + assert.equal(data.errors[0].context, 'test!'); + resolve(); + } + }, () => {}); + }); }); - it('Uses templates when required', function (done) { - jsonErrorRenderer(new InternalServerError({ - message: 'test!' - }), { - frameOptions: { - docName: 'blog', - method: 'browse' - } - }, { - json: (data) => { - assert.equal(data.errors.length, 1); - assert.equal(data.errors[0].message, 'Internal server error, cannot list blog.'); - assert.equal(data.errors[0].context, 'test!'); - done(); - } - }, () => {}); + it('Uses templates when required', async function () { + await new Promise((resolve) => { + jsonErrorRenderer(new InternalServerError({ + message: 'test!' + }), { + frameOptions: { + docName: 'blog', + method: 'browse' + } + }, { + json: (data) => { + assert.equal(data.errors.length, 1); + assert.equal(data.errors[0].message, 'Internal server error, cannot list blog.'); + assert.equal(data.errors[0].context, 'test!'); + resolve(); + } + }, () => {}); + }); }); - it('Uses defined message + context when available', function (done) { - jsonErrorRenderer(new InternalServerError({ - message: 'test!', - context: 'Image was too large.' - }), { - frameOptions: { - docName: 'images', - method: 'upload' - } - }, { - json: (data) => { - assert.equal(data.errors.length, 1); - assert.equal(data.errors[0].message, 'Internal server error, cannot upload image.'); - assert.equal(data.errors[0].context, 'test! Image was too large.'); - done(); - } - }, () => {}); + it('Uses defined message + context when available', async function () { + await new Promise((resolve) => { + jsonErrorRenderer(new InternalServerError({ + message: 'test!', + context: 'Image was too large.' + }), { + frameOptions: { + docName: 'images', + method: 'upload' + } + }, { + json: (data) => { + assert.equal(data.errors.length, 1); + assert.equal(data.errors[0].message, 'Internal server error, cannot upload image.'); + assert.equal(data.errors[0].context, 'test! Image was too large.'); + resolve(); + } + }, () => {}); + }); }); it('Exports the HTML renderer', function () { @@ -300,15 +332,17 @@ describe('Error renderers', function () { }); describe('Resource Not Found', function () { - it('Returns 404 Not Found Error for a generic case', function (done) { - resourceNotFound({}, {}, (error) => { - assert.equal(error.statusCode, 404); - assert.equal(error.message, 'Resource not found'); - done(); + it('Returns 404 Not Found Error for a generic case', async function () { + await new Promise((resolve) => { + resourceNotFound({}, {}, (error) => { + assert.equal(error.statusCode, 404); + assert.equal(error.message, 'Resource not found'); + resolve(); + }); }); }); - it('Returns 406 Request Not Acceptable Error for invalid version', function (done) { + it('Returns 406 Request Not Acceptable Error for invalid version', async function () { const req = { headers: { 'accept-version': 'foo' @@ -321,14 +355,16 @@ describe('Resource Not Found', function () { } }; - resourceNotFound(req, res, (error) => { - assert.equal(error.statusCode, 400); - assert.equal(error.message, 'Requested version is not supported.'); - done(); + await new Promise((resolve) => { + resourceNotFound(req, res, (error) => { + assert.equal(error.statusCode, 400); + assert.equal(error.message, 'Requested version is not supported.'); + resolve(); + }); }); }); - it('Returns 406 Request Not Acceptable Error for when requested version is behind current version', function (done) { + it('Returns 406 Request Not Acceptable Error for when requested version is behind current version', async function () { const req = { headers: { 'accept-version': 'v3.9' @@ -341,16 +377,18 @@ describe('Resource Not Found', function () { } }; - resourceNotFound(req, res, (error) => { - assert.equal(error.statusCode, 406); - assert.equal(error.message, 'Request could not be served, the endpoint was not found.'); - assert.equal(error.context, 'Provided client accept-version v3.9 is behind current Ghost version v4.3.'); - assert.equal(error.help, 'Try upgrading your Ghost API client.'); - done(); + await new Promise((resolve) => { + resourceNotFound(req, res, (error) => { + assert.equal(error.statusCode, 406); + assert.equal(error.message, 'Request could not be served, the endpoint was not found.'); + assert.equal(error.context, 'Provided client accept-version v3.9 is behind current Ghost version v4.3.'); + assert.equal(error.help, 'Try upgrading your Ghost API client.'); + resolve(); + }); }); }); - it('Returns 406 Request Not Acceptable Error for when requested version is ahead current version', function (done) { + it('Returns 406 Request Not Acceptable Error for when requested version is ahead current version', async function () { const req = { headers: { 'accept-version': 'v4.8' @@ -363,16 +401,18 @@ describe('Resource Not Found', function () { } }; - resourceNotFound(req, res, (error) => { - assert.equal(error.statusCode, 406); - assert.equal(error.message, 'Request could not be served, the endpoint was not found.'); - assert.equal(error.context, 'Provided client accept-version v4.8 is ahead of current Ghost version v4.3.'); - assert.equal(error.help, 'Try upgrading your Ghost install.'); - done(); + await new Promise((resolve) => { + resourceNotFound(req, res, (error) => { + assert.equal(error.statusCode, 406); + assert.equal(error.message, 'Request could not be served, the endpoint was not found.'); + assert.equal(error.context, 'Provided client accept-version v4.8 is ahead of current Ghost version v4.3.'); + assert.equal(error.help, 'Try upgrading your Ghost install.'); + resolve(); + }); }); }); - it('Returns 404 Not Found Error for when requested version is the same as current version', function (done) { + it('Returns 404 Not Found Error for when requested version is the same as current version', async function () { const req = { headers: { 'accept-version': 'v4.3' @@ -385,27 +425,33 @@ describe('Resource Not Found', function () { } }; - resourceNotFound(req, res, (error) => { - assert.equal(error.statusCode, 404); - assert.equal(error.message, 'Resource not found'); - done(); + await new Promise((resolve) => { + resourceNotFound(req, res, (error) => { + assert.equal(error.statusCode, 404); + assert.equal(error.message, 'Resource not found'); + resolve(); + }); }); }); describe('pageNotFound', function () { - it('returns 404 with special message when message not set', function (done) { - pageNotFound({}, {}, (error) => { - assert.equal(error.statusCode, 404); - assert.equal(error.message, 'Page not found'); - done(); + it('returns 404 with special message when message not set', async function () { + await new Promise((resolve) => { + pageNotFound({}, {}, (error) => { + assert.equal(error.statusCode, 404); + assert.equal(error.message, 'Page not found'); + resolve(); + }); }); }); - it('returns 404 with special message even if message is set', function (done) { - pageNotFound({message: 'uh oh'}, {}, (error) => { - assert.equal(error.statusCode, 404); - assert.equal(error.message, 'Page not found'); - done(); + it('returns 404 with special message even if message is set', async function () { + await new Promise((resolve) => { + pageNotFound({message: 'uh oh'}, {}, (error) => { + assert.equal(error.statusCode, 404); + assert.equal(error.message, 'Page not found'); + resolve(); + }); }); }); }); diff --git a/packages/mw-vhost/package.json b/packages/mw-vhost/package.json index de75417d0..90a484ab9 100644 --- a/packages/mw-vhost/package.json +++ b/packages/mw-vhost/package.json @@ -9,7 +9,7 @@ }, "scripts": { "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura -- mocha --reporter dot './test/**/*.test.js'", + "test:unit": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "test": "yarn test:unit", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", @@ -20,7 +20,6 @@ "lib" ], "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "supertest": "7.2.2" }, diff --git a/packages/nodemailer/package.json b/packages/nodemailer/package.json index 89cfb3f06..e0dc5baf0 100644 --- a/packages/nodemailer/package.json +++ b/packages/nodemailer/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/pretty-cli/package.json b/packages/pretty-cli/package.json index 8894f026e..2c35444d1 100644 --- a/packages/pretty-cli/package.json +++ b/packages/pretty-cli/package.json @@ -12,7 +12,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -24,7 +24,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/pretty-stream/package.json b/packages/pretty-stream/package.json index 357f5fee4..249f1b4b1 100644 --- a/packages/pretty-stream/package.json +++ b/packages/pretty-stream/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/pretty-stream/test/PrettyStream.test.js b/packages/pretty-stream/test/PrettyStream.test.js index e485d9c90..113ea3177 100644 --- a/packages/pretty-stream/test/PrettyStream.test.js +++ b/packages/pretty-stream/test/PrettyStream.test.js @@ -4,595 +4,467 @@ const Writable = require('stream').Writable; const sinon = require('sinon'); describe('PrettyStream', function () { + afterEach(function () { + sinon.restore(); + }); + describe('short mode', function () { - it('data.msg', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data, '[2016-07-01 00:00:00] \u001b[36mINFO\u001b[39m Ghost starts now.\n'); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - msg: 'Ghost starts now.' - })); + it('data.msg', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'short'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data, '[2016-07-01 00:00:00] \u001b[36mINFO\u001b[39m Ghost starts now.\n'); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 30, + msg: 'Ghost starts now.' + })); + }); }); - it('data.err', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data, '[2016-07-01 00:00:00] \u001b[31mERROR\u001b[39m message\n\u001b[31m\n\u001b[31mHey Jude!\u001b[39m\n\n\u001b[1m\u001b[37mError Code: \u001b[39m\u001b[22m\n \u001b[90mHEY_JUDE\u001b[39m\n\n\u001b[90m----------------------------------------\u001b[39m\n\n\u001b[90mstack\u001b[39m\n\u001b[39m\n'); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 50, - msg: 'message', - err: { - message: 'Hey Jude!', - stack: 'stack', - code: 'HEY_JUDE' - } - })); + it('data.err', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'short'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data, '[2016-07-01 00:00:00] \u001b[31mERROR\u001b[39m message\n\u001b[31m\n\u001b[31mHey Jude!\u001b[39m\n\n\u001b[1m\u001b[37mError Code: \u001b[39m\u001b[22m\n \u001b[90mHEY_JUDE\u001b[39m\n\n\u001b[90m----------------------------------------\u001b[39m\n\n\u001b[90mstack\u001b[39m\n\u001b[39m\n'); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 50, + msg: 'message', + err: { + message: 'Hey Jude!', + stack: 'stack', + code: 'HEY_JUDE' + } + })); + }); }); - it('data.req && data.res', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data, '[2016-07-01 00:00:00] \u001b[36mINFO\u001b[39m "GET /test" \u001b[32m200\u001b[39m 39ms\n'); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - req: { - originalUrl: '/test', - method: 'GET', - body: { - a: 'b' + it('data.req && data.res', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'short'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data, '[2016-07-01 00:00:00] \u001b[36mINFO\u001b[39m "GET /test" \u001b[32m200\u001b[39m 39ms\n'); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 30, + req: { + originalUrl: '/test', + method: 'GET', + body: { + a: 'b' + } + }, + res: { + statusCode: 200, + responseTime: '39ms' } - }, - res: { - statusCode: 200, - responseTime: '39ms' - } - })); + })); + }); }); - it('data.req && data.res && data.err', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data, '[2016-07-01 00:00:00] \u001b[31mERROR\u001b[39m "GET /test" \u001b[33m400\u001b[39m 39ms\n\u001b[31m\n\u001b[31mmessage\u001b[39m\n\n\u001b[90m----------------------------------------\u001b[39m\n\n\u001b[90mstack\u001b[39m\n\u001b[39m\n'); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 50, - req: { - originalUrl: '/test', - method: 'GET', - body: { - a: 'b' + it('data.req && data.res && data.err', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'short'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data, '[2016-07-01 00:00:00] \u001b[31mERROR\u001b[39m "GET /test" \u001b[33m400\u001b[39m 39ms\n\u001b[31m\n\u001b[31mmessage\u001b[39m\n\n\u001b[90m----------------------------------------\u001b[39m\n\n\u001b[90mstack\u001b[39m\n\u001b[39m\n'); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 50, + req: { + originalUrl: '/test', + method: 'GET', + body: { + a: 'b' + } + }, + res: { + statusCode: 400, + responseTime: '39ms' + }, + err: { + message: 'message', + stack: 'stack' } - }, - res: { - statusCode: 400, - responseTime: '39ms' - }, - err: { - message: 'message', - stack: 'stack' - } - })); + })); + }); }); }); describe('long mode', function () { - it('data.msg', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'long'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data, '[2016-07-01 00:00:00] \u001b[36mINFO\u001b[39m Ghost starts now.\n'); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - msg: 'Ghost starts now.' - })); - }); - - it('data.err', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'long'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data, '[2016-07-01 00:00:00] \u001b[31mERROR\u001b[39m\n\u001b[31m\n\u001b[31mHey Jude!\u001b[39m\n\n\u001b[90m----------------------------------------\u001b[39m\n\n\u001b[90mstack\u001b[39m\n\u001b[39m\n\u001b[90m\u001b[39m\n'); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 50, - err: { - message: 'Hey Jude!', - stack: 'stack' - } - })); + it('data.msg', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'long'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data, '[2016-07-01 00:00:00] \u001b[36mINFO\u001b[39m Ghost starts now.\n'); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 30, + msg: 'Ghost starts now.' + })); + }); }); - it('data.req && data.res', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'long'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data, '[2016-07-01 00:00:00] \u001b[36mINFO\u001b[39m "GET /test" \u001b[32m200\u001b[39m 39ms\n\u001b[90m\n\u001b[33mREQ\u001b[39m\n\u001b[32mip: \u001b[39m 127.0.01\n\u001b[32moriginalUrl: \u001b[39m/test\n\u001b[32mmethod: \u001b[39m GET\n\u001b[32mbody: \u001b[39m\n \u001b[32ma: \u001b[39mb\n\n\u001b[33mRES\u001b[39m\n\u001b[32mresponseTime: \u001b[39m39ms\n\u001b[39m\n'); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - req: { - ip: '127.0.01', - originalUrl: '/test', - method: 'GET', - body: { - a: 'b' + it('data.err', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'long'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data, '[2016-07-01 00:00:00] \u001b[31mERROR\u001b[39m\n\u001b[31m\n\u001b[31mHey Jude!\u001b[39m\n\n\u001b[90m----------------------------------------\u001b[39m\n\n\u001b[90mstack\u001b[39m\n\u001b[39m\n\u001b[90m\u001b[39m\n'); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 50, + err: { + message: 'Hey Jude!', + stack: 'stack' } - }, - res: { - statusCode: 200, - responseTime: '39ms' - } - })); + })); + }); }); - it('data.req && data.res && data.err', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'long'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data, '[2016-07-01 00:00:00] \u001b[31mERROR\u001b[39m "GET /test" \u001b[33m400\u001b[39m 39ms\n\u001b[31m\n\u001b[31mHey Jude!\u001b[39m\n\n\u001b[90m----------------------------------------\u001b[39m\n\n\u001b[90mstack\u001b[39m\n\u001b[39m\n\u001b[90m\n\u001b[33mREQ\u001b[39m\n\u001b[32moriginalUrl: \u001b[39m/test\n\u001b[32mmethod: \u001b[39m GET\n\u001b[32mbody: \u001b[39m\n \u001b[32ma: \u001b[39mb\n\n\u001b[33mRES\u001b[39m\n\u001b[32mresponseTime: \u001b[39m39ms\n\u001b[39m\n'); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 50, - req: { - originalUrl: '/test', - method: 'GET', - body: { - a: 'b' + it('data.req && data.res', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'long'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data, '[2016-07-01 00:00:00] \u001b[36mINFO\u001b[39m "GET /test" \u001b[32m200\u001b[39m 39ms\n\u001b[90m\n\u001b[33mREQ\u001b[39m\n\u001b[32mip: \u001b[39m 127.0.01\n\u001b[32moriginalUrl: \u001b[39m/test\n\u001b[32mmethod: \u001b[39m GET\n\u001b[32mbody: \u001b[39m\n \u001b[32ma: \u001b[39mb\n\n\u001b[33mRES\u001b[39m\n\u001b[32mresponseTime: \u001b[39m39ms\n\u001b[39m\n'); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 30, + req: { + ip: '127.0.01', + originalUrl: '/test', + method: 'GET', + body: { + a: 'b' + } + }, + res: { + statusCode: 200, + responseTime: '39ms' } - }, - res: { - statusCode: 400, - responseTime: '39ms' - }, - err: { - message: 'Hey Jude!', - stack: 'stack' - } - })); - }); - - it('data.err contains error details && meta fields', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'long'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data, '[2016-07-01 00:00:00] \u001b[31mERROR\u001b[39m\n\u001b[31m\n\u001b[31mType: ValidationError\u001b[39m\n\u001b[31mHey Jude!\u001b[39m\n\n\u001b[37m{"a":"b"}\u001b[39m\n\u001b[33mCheck documentation at https://docs.ghost.org/\u001b[39m\n\n\u001b[1m\u001b[37mError ID:\u001b[39m\u001b[22m\n \u001b[90me8546680-401f-11e9-99a7-ed7d6251b35c\u001b[39m\n\n\u001b[1m\u001b[37mDetails:\u001b[39m\u001b[22m\n\u001b[90m level: error\n rule: Templates must contain valid Handlebars.\n failures: \n - \n ref: default.hbs\n message: Missing helper: "image"\n code: GS005-TPL-ERR\u001b[39m\n\n\u001b[90m----------------------------------------\u001b[39m\n\n\u001b[90mstack\u001b[39m\n\u001b[39m\n\u001b[90m\u001b[39m\n'); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 50, - err: { - message: 'Hey Jude!', - stack: 'stack', - errorType: 'ValidationError', - id: 'e8546680-401f-11e9-99a7-ed7d6251b35c', - context: JSON.stringify({a: 'b'}), - help: 'Check documentation at https://docs.ghost.org/', - errorDetails: JSON.stringify([{ - level: 'error', - rule: 'Templates must contain valid Handlebars.', - failures: [{ref: 'default.hbs', message: 'Missing helper: "image"'}], - code: 'GS005-TPL-ERR' - }]) - } - })); - }); - - it('data with no time field', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - // Hardcode the datetime so we don't have flaky tests - sinon.useFakeTimers(new Date('2024-12-15T13:17:00.000')); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data, `[2024-12-15 13:17:00] \u001b[36mINFO\u001b[39m Ghost starts now.\n`); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - // Write the body with no time field - ghostPrettyStream.write(JSON.stringify({ - level: 30, - msg: 'Ghost starts now.' - })); - }); - }); - - describe('timezone handling', function () { - it('should display provided timestamps consistently', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - // The timestamp should be formatted consistently - assert.equal(data.includes('[2016-07-01 00:00:00]'), true); - assert.equal(data.includes('INFO'), true); - assert.equal(data.includes('Test message'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - // Write with an explicit timestamp - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - msg: 'Test message' - })); + })); + }); }); - it('should handle ISO 8601 timestamps and convert to local time', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - // ISO timestamp should be parsed and converted to local time - // Extract the timestamp to verify format - const timestampMatch = data.match(/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]/); - assert.notEqual(timestampMatch, null); - - // Verify the timestamp represents the correct moment - // 2016-07-01T00:00:00.000Z in local time - const parsedTime = new Date(timestampMatch[1]); - const expectedTime = new Date('2016-07-01T00:00:00.000Z'); - - // The displayed local time should represent the same moment as the UTC time - // Allow for some tolerance due to date parsing - assert.equal(Math.abs(parsedTime.getTime() - expectedTime.getTime()) < 24 * 60 * 60 * 1000, true); - - assert.equal(data.includes('INFO'), true); - assert.equal(data.includes('ISO timestamp test'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - // Write with an ISO 8601 timestamp - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01T00:00:00.000Z', - level: 30, - msg: 'ISO timestamp test' - })); + it('data.req && data.res && data.err', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'long'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data, '[2016-07-01 00:00:00] \u001b[31mERROR\u001b[39m "GET /test" \u001b[33m400\u001b[39m 39ms\n\u001b[31m\n\u001b[31mHey Jude!\u001b[39m\n\n\u001b[90m----------------------------------------\u001b[39m\n\n\u001b[90mstack\u001b[39m\n\u001b[39m\n\u001b[90m\n\u001b[33mREQ\u001b[39m\n\u001b[32moriginalUrl: \u001b[39m/test\n\u001b[32mmethod: \u001b[39m GET\n\u001b[32mbody: \u001b[39m\n \u001b[32ma: \u001b[39mb\n\n\u001b[33mRES\u001b[39m\n\u001b[32mresponseTime: \u001b[39m39ms\n\u001b[39m\n'); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 50, + req: { + originalUrl: '/test', + method: 'GET', + body: { + a: 'b' + } + }, + res: { + statusCode: 400, + responseTime: '39ms' + }, + err: { + message: 'Hey Jude!', + stack: 'stack' + } + })); + }); }); - it('should handle timestamps with timezone offsets', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - // Timestamp with timezone offset should be converted to local time for display - const timestampMatch = data.match(/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]/); - assert.notEqual(timestampMatch, null); - - assert.equal(data.includes('INFO'), true); - assert.equal(data.includes('Timezone offset test'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - // Write with a timestamp that includes timezone offset - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01T00:00:00+02:00', - level: 30, - msg: 'Timezone offset test' - })); + it('data.err contains error details && meta fields', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'long'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data, '[2016-07-01 00:00:00] \u001b[31mERROR\u001b[39m\n\u001b[31m\n\u001b[31mType: ValidationError\u001b[39m\n\u001b[31mHey Jude!\u001b[39m\n\n\u001b[37m{"a":"b"}\u001b[39m\n\u001b[33mCheck documentation at https://docs.ghost.org/\u001b[39m\n\n\u001b[1m\u001b[37mError ID:\u001b[39m\u001b[22m\n \u001b[90me8546680-401f-11e9-99a7-ed7d6251b35c\u001b[39m\n\n\u001b[1m\u001b[37mDetails:\u001b[39m\u001b[22m\n\u001b[90m level: error\n rule: Templates must contain valid Handlebars.\n failures: \n - \n ref: default.hbs\n message: Missing helper: "image"\n code: GS005-TPL-ERR\u001b[39m\n\n\u001b[90m----------------------------------------\u001b[39m\n\n\u001b[90mstack\u001b[39m\n\u001b[39m\n\u001b[90m\u001b[39m\n'); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 50, + err: { + message: 'Hey Jude!', + stack: 'stack', + errorType: 'ValidationError', + id: 'e8546680-401f-11e9-99a7-ed7d6251b35c', + context: JSON.stringify({a: 'b'}), + help: 'Check documentation at https://docs.ghost.org/', + errorDetails: JSON.stringify([{ + level: 'error', + rule: 'Templates must contain valid Handlebars.', + failures: [{ref: 'default.hbs', message: 'Missing helper: "image"'}], + code: 'GS005-TPL-ERR' + }]) + } + })); + }); }); - it('should use current local time when no timestamp is provided', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); + it('data with no time field', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'short'}); + var writeStream = new Writable(); - // Capture the time before the test - const beforeTime = new Date(); + // Hardcode the datetime so we don't have flaky tests + sinon.useFakeTimers(new Date('2024-12-15T13:17:00.000')); - writeStream._write = function (data) { - data = data.toString(); + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data, `[2024-12-15 13:17:00] \u001b[36mINFO\u001b[39m Ghost starts now.\n`); + resolve(); + }; - // Extract the timestamp from the output - const timestampMatch = data.match(/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]/); - assert.notEqual(timestampMatch, null); + ghostPrettyStream.pipe(writeStream); - const loggedTime = new Date(timestampMatch[1]); - const afterTime = new Date(); - - // The logged time should be between beforeTime and afterTime - assert.equal(loggedTime.getTime() >= beforeTime.getTime(), true); - assert.equal(loggedTime.getTime() <= afterTime.getTime(), true); - - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - // Write without a timestamp - ghostPrettyStream.write(JSON.stringify({ - level: 30, - msg: 'No timestamp test' - })); - }); - - it('should work correctly in different timezones', function (done) { - // This test verifies that string timestamps are displayed as-is - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - // String timestamp should be displayed exactly as provided - assert.equal(data.includes('[2016-07-01 00:00:00]'), true); - assert.equal(data.includes('String timestamp'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - // Test with string timestamp - should be displayed as-is - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - msg: 'String timestamp' - })); - }); - - it('regression test: string timestamps should not be affected by timezone offset', function (done) { - // This test ensures the bug from commit be5ddf2 doesn't resurface - // String timestamps like '2016-07-01 00:00:00' should be displayed exactly as provided - // regardless of the system timezone - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - // The exact string '2016-07-01 00:00:00' should appear in the output - // It should NOT be shifted by timezone offset (e.g., NOT '2016-06-30 23:00:00') - assert.match(data, /^\[2016-07-01 00:00:00\]/); - assert.equal(data.includes('Regression test'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - // This timestamp format was causing issues in non-UTC timezones - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - msg: 'Regression test' - })); + // Write the body with no time field + ghostPrettyStream.write(JSON.stringify({ + level: 30, + msg: 'Ghost starts now.' + })); + }); }); }); - describe('edge paths', function () { it('defaults to short mode when no options are provided', function () { var ghostPrettyStream = new PrettyStream(); assert.equal(ghostPrettyStream.mode, 'short'); }); - it('accepts plain object writes and stringifies internally', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data.includes('Object input'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - ghostPrettyStream.write({ - time: '2016-07-01 00:00:00', - level: 30, - msg: 'Object input' + it('accepts plain object writes and stringifies internally', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'short'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data.includes('Object input'), true); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + ghostPrettyStream.write({ + time: '2016-07-01 00:00:00', + level: 30, + msg: 'Object input' + }); }); }); - it('handles invalid JSON input in _transform', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - ghostPrettyStream._transform(Buffer.from('{not-json'), null, (err) => { - assert.notEqual(err, null); - done(); + it('handles invalid JSON input in _transform', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'short'}); + ghostPrettyStream._transform(Buffer.from('{not-json'), null, (err) => { + assert.notEqual(err, null); + resolve(); + }); }); }); - it('renders raw errorDetails when parsing details fails', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'long'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data.includes('Details:'), true); - assert.equal(data.includes('not-json-details'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 50, - err: { - message: 'oops', - stack: 'stack', - errorDetails: 'not-json-details' - } - })); + it('renders raw errorDetails when parsing details fails', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'long'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data.includes('Details:'), true); + assert.equal(data.includes('not-json-details'), true); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 50, + err: { + message: 'oops', + stack: 'stack', + errorDetails: 'not-json-details' + } + })); + }); }); - it('renders parsed object errorDetails payloads', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'long'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data.includes('Details:'), true); - assert.equal(data.includes('CODE1'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 50, - err: { - message: 'oops', - stack: 'stack', - errorDetails: JSON.stringify({code: 'CODE1'}) - } - })); + it('renders parsed object errorDetails payloads', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'long'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data.includes('Details:'), true); + assert.equal(data.includes('CODE1'), true); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 50, + err: { + message: 'oops', + stack: 'stack', + errorDetails: JSON.stringify({code: 'CODE1'}) + } + })); + }); }); - it('renders non-object additional fields', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'long'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data.includes('plain-extra-value'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - msg: 'hello', - extra: 'plain-extra-value' - })); + it('renders non-object additional fields', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'long'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data.includes('plain-extra-value'), true); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 30, + msg: 'hello', + extra: 'plain-extra-value' + })); + }); }); - it('colors 500 status code as red', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data.includes('\u001b[31m500\u001b[39m'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - req: {originalUrl: '/a', method: 'GET'}, - res: {statusCode: 500, responseTime: '1ms'} - })); + it('colors 500 status code as red', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'short'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data.includes('\u001b[31m500\u001b[39m'), true); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 30, + req: {originalUrl: '/a', method: 'GET'}, + res: {statusCode: 500, responseTime: '1ms'} + })); + }); }); - it('colors 301 status code as cyan', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data.includes('\u001b[36m301\u001b[39m'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - req: {originalUrl: '/b', method: 'GET'}, - res: {statusCode: 301, responseTime: '1ms'} - })); + it('colors 301 status code as cyan', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'short'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data.includes('\u001b[36m301\u001b[39m'), true); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 30, + req: {originalUrl: '/b', method: 'GET'}, + res: {statusCode: 301, responseTime: '1ms'} + })); + }); }); - it('colors <200 status code with default color', function (done) { - var ghostPrettyStream = new PrettyStream({mode: 'short'}); - var writeStream = new Writable(); - - writeStream._write = function (data) { - data = data.toString(); - assert.equal(data.includes('\u001b[39m100\u001b[39m'), true); - done(); - }; - - ghostPrettyStream.pipe(writeStream); - - ghostPrettyStream.write(JSON.stringify({ - time: '2016-07-01 00:00:00', - level: 30, - req: {originalUrl: '/c', method: 'GET'}, - res: {statusCode: 100, responseTime: '1ms'} - })); + it('colors <200 status code with default color', async function () { + await new Promise((resolve) => { + var ghostPrettyStream = new PrettyStream({mode: 'short'}); + var writeStream = new Writable(); + + writeStream._write = function (data) { + data = data.toString(); + assert.equal(data.includes('\u001b[39m100\u001b[39m'), true); + resolve(); + }; + + ghostPrettyStream.pipe(writeStream); + + ghostPrettyStream.write(JSON.stringify({ + time: '2016-07-01 00:00:00', + level: 30, + req: {originalUrl: '/c', method: 'GET'}, + res: {statusCode: 100, responseTime: '1ms'} + })); + }); }); }); }); diff --git a/packages/prometheus-metrics/package.json b/packages/prometheus-metrics/package.json index bad888703..1cab13c3a 100644 --- a/packages/prometheus-metrics/package.json +++ b/packages/prometheus-metrics/package.json @@ -17,7 +17,7 @@ "build": "yarn build:ts", "build:ts": "tsc", "prepare": "tsc", - "test:unit": "NODE_ENV=testing c8 --src src --all --check-coverage --100 --reporter text --reporter cobertura mocha -r ts-node/register './test/**/*.test.ts'", + "test:unit": "NODE_ENV=testing vitest run --coverage", "test": "yarn test:types && yarn test:unit", "test:types": "tsc --noEmit", "lint:code": "eslint src/ --ext .ts --cache", @@ -32,7 +32,6 @@ "@types/sinon": "21.0.0", "@types/stoppable": "1.1.3", "@types/supertest": "7.2.0", - "c8": "11.0.0", "knex": "3.1.0", "mocha": "11.7.5", "nock": "14.0.11", diff --git a/packages/prometheus-metrics/test/.eslintrc.js b/packages/prometheus-metrics/test/.eslintrc.js index 6fe6dc150..023956a15 100644 --- a/packages/prometheus-metrics/test/.eslintrc.js +++ b/packages/prometheus-metrics/test/.eslintrc.js @@ -3,5 +3,8 @@ module.exports = { plugins: ['ghost'], extends: [ 'plugin:ghost/test' - ] + ], + globals: { + afterAll: 'readonly' + } }; diff --git a/packages/prometheus-metrics/test/metrics-server.test.ts b/packages/prometheus-metrics/test/metrics-server.test.ts index c19e3d412..a9da243be 100644 --- a/packages/prometheus-metrics/test/metrics-server.test.ts +++ b/packages/prometheus-metrics/test/metrics-server.test.ts @@ -61,7 +61,7 @@ describe('Metrics Server', function () { await metricsServer.stop(); }); - after(async function () { + afterAll(async function () { await metricsServer.shutdown(); }); diff --git a/packages/prometheus-metrics/vitest.config.ts b/packages/prometheus-metrics/vitest.config.ts new file mode 100644 index 000000000..0a51d09c0 --- /dev/null +++ b/packages/prometheus-metrics/vitest.config.ts @@ -0,0 +1,12 @@ +import {defineConfig, mergeConfig} from 'vitest/config'; +import rootConfig from '../../vitest.config'; + +// Override: TypeScript package with source in src/, not lib/. +// Coverage must be scoped to src/ to measure the right files. +export default mergeConfig(rootConfig, defineConfig({ + test: { + coverage: { + include: ['src/**'] + } + } +})); diff --git a/packages/promise/package.json b/packages/promise/package.json index ea9e756a7..987bfee26 100644 --- a/packages/promise/package.json +++ b/packages/promise/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" } diff --git a/packages/request/package.json b/packages/request/package.json index d11a856d5..a4b1871e6 100644 --- a/packages/request/package.json +++ b/packages/request/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "nock": "14.0.11", "rewire": "9.0.1", diff --git a/packages/root-utils/package.json b/packages/root-utils/package.json index 1535a2bc1..76ecace88 100644 --- a/packages/root-utils/package.json +++ b/packages/root-utils/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/root-utils/test/root-utils.test.js b/packages/root-utils/test/root-utils.test.js index 79c4cda08..5e247b822 100644 --- a/packages/root-utils/test/root-utils.test.js +++ b/packages/root-utils/test/root-utils.test.js @@ -3,7 +3,7 @@ const path = require('path'); const fs = require('fs'); const os = require('os'); const Module = require('module'); -const {getCallerRoot, getProcessRoot} = require('../index'); +const {getProcessRoot} = require('../index'); const rootUtilsModulePath = require.resolve('../lib/root-utils'); function loadRootUtilsWithMocks(mocks) { @@ -15,18 +15,26 @@ function loadRootUtilsWithMocks(mocks) { return originalLoad(request, parent, isMain); }; - delete require.cache[rootUtilsModulePath]; - const loaded = require('../lib/root-utils'); - - Module._load = originalLoad; - delete require.cache[rootUtilsModulePath]; - return loaded; + try { + delete require.cache[rootUtilsModulePath]; + return require('../lib/root-utils'); + } finally { + Module._load = originalLoad; + delete require.cache[rootUtilsModulePath]; + } } describe('getCallerRoot', function () { it('Gets the root directory of the caller', function () { - // mocha calls the test function calls getCallerRoot - assert.equal(getCallerRoot().endsWith('mocha'), true); + const mockedModule = loadRootUtilsWithMocks({ + caller: () => __filename, + 'find-root': require('find-root') + }); + + const callerRoot = mockedModule.getCallerRoot(); + assert.ok(callerRoot, 'caller root should be defined'); + assert.ok(typeof callerRoot === 'string', 'caller root should be a string'); + assert.equal(callerRoot.endsWith('root-utils'), true); }); it('returns undefined when caller root cannot be resolved', function () { diff --git a/packages/security/package.json b/packages/security/package.json index 1ec83cb0f..4cf194124 100644 --- a/packages/security/package.json +++ b/packages/security/package.json @@ -15,7 +15,7 @@ }, "scripts": { "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura -- mocha --reporter dot './test/**/*.test.js'", + "test:unit": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "test": "yarn test:unit", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", @@ -26,7 +26,6 @@ "lib" ], "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1", "uuid": "13.0.0" diff --git a/packages/server/package.json b/packages/server/package.json index ccd6bbbb4..0b05364bd 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/server/test/server.test.js b/packages/server/test/server.test.js index 41b6779d2..e94baecd6 100644 --- a/packages/server/test/server.test.js +++ b/packages/server/test/server.test.js @@ -16,184 +16,198 @@ describe('Server Utils', function () { afterEach(function () { sandbox.restore(); }); - - it('Normalises port number correctly', function (done) { + + it('Normalises port number correctly', async function () { const testPort = 180; - sandbox.stub(http, 'createServer').callsFake(function () { - return { - listen: function (port) { - assert.equal(port, testPort); - done(); - } - }; + await new Promise((resolve) => { + sandbox.stub(http, 'createServer').callsFake(function () { + return { + listen: function (port) { + assert.equal(port, testPort); + resolve(); + } + }; + }); + + server.start({ + set: () => {} + }, testPort.toString()); }); - - server.start({ - set: () => {} - }, testPort.toString()); }); - it('Normalises named pipe correctly', function (done) { + it('Normalises named pipe correctly', async function () { const testPipe = 'hello'; - sandbox.stub(http, 'createServer').callsFake(function () { - return { - listen: function (port) { - assert.equal(port, testPipe); - done(); - } - }; + await new Promise((resolve) => { + sandbox.stub(http, 'createServer').callsFake(function () { + return { + listen: function (port) { + assert.equal(port, testPipe); + resolve(); + } + }; + }); + + server.start({ + set: () => {} + }, testPipe); }); - - server.start({ - set: () => {} - }, testPipe); }); - - it('Normalises negative port value correctly', function (done) { + + it('Normalises negative port value correctly', async function () { const testPort = -80; - sandbox.stub(http, 'createServer').callsFake(function () { - return { - listen: function (port) { - assert.equal(port, false); - done(); - } - }; + await new Promise((resolve) => { + sandbox.stub(http, 'createServer').callsFake(function () { + return { + listen: function (port) { + assert.equal(port, false); + resolve(); + } + }; + }); + + server.start({ + set: () => {} + }, testPort.toString()); }); - - server.start({ - set: () => {} - }, testPort.toString()); }); - it('Emits listening event', function (done) { + it('Emits listening event', async function () { const testAddress = 'hello'; - sandbox.stub(logging, 'info').callsFake(function (message) { - assert.equal(message.startsWith(`Listening on pipe ${testAddress}`), true); - done(); - }); - - sandbox.stub(http, 'createServer').callsFake(function () { - class Server extends EventEmitter { - constructor() { - super(); + await new Promise((resolve) => { + sandbox.stub(logging, 'info').callsFake(function (message) { + assert.equal(message.startsWith(`Listening on pipe ${testAddress}`), true); + resolve(); + }); + + sandbox.stub(http, 'createServer').callsFake(function () { + class Server extends EventEmitter { + constructor() { + super(); + } + listen() { + setTimeout(() => { + this.emit('listening'); + }, 0); + } + address() { + return testAddress; + } } - listen() { - setTimeout(() => { - this.emit('listening'); - }, 0); - } - address() { - return testAddress; - } - } - return new Server(); - }); + return new Server(); + }); - server.start({ - set: () => {} - }, 180); + server.start({ + set: () => {} + }, 180); + }); }); - it('Emits nice error for EACCES', function (done) { + it('Emits nice error for EACCES', async function () { const testPort = 180; - sandbox.stub(process, 'exit').callsFake(function () { - }); - - sandbox.stub(logging, 'error').callsFake(function (message) { - assert.equal(message.startsWith(`Port ${testPort} requires elevated privileges`), true); - done(); - }); - - sandbox.stub(http, 'createServer').callsFake(function () { - class Server extends EventEmitter { - constructor() { - super(); - } - listen() { - setTimeout(() => { - this.emit('error', { - code: 'EACCES', - syscall: 'listen' - }); - }, 0); + await new Promise((resolve) => { + sandbox.stub(process, 'exit').callsFake(function () { + }); + + sandbox.stub(logging, 'error').callsFake(function (message) { + assert.equal(message.startsWith(`Port ${testPort} requires elevated privileges`), true); + resolve(); + }); + + sandbox.stub(http, 'createServer').callsFake(function () { + class Server extends EventEmitter { + constructor() { + super(); + } + listen() { + setTimeout(() => { + this.emit('error', { + code: 'EACCES', + syscall: 'listen' + }); + }, 0); + } } - } - - return new Server(); - }); - server.start({ - set: () => {} - }, testPort); - }); - - it('Emits nice error for EADDRINUSE', function (done) { - const testPort = 180; + return new Server(); + }); - sandbox.stub(process, 'exit').callsFake(function () { + server.start({ + set: () => {} + }, testPort); }); + }); - sandbox.stub(logging, 'error').callsFake(function (message) { - assert.equal(message.startsWith(`Port ${testPort} is already in use`), true); - done(); - }); + it('Emits nice error for EADDRINUSE', async function () { + const testPort = 180; - sandbox.stub(http, 'createServer').callsFake(function () { - class Server extends EventEmitter { - constructor() { - super(); - } - listen() { - setTimeout(() => { - this.emit('error', { - code: 'EADDRINUSE', - syscall: 'listen' - }); - }, 0); + await new Promise((resolve) => { + sandbox.stub(process, 'exit').callsFake(function () { + }); + + sandbox.stub(logging, 'error').callsFake(function (message) { + assert.equal(message.startsWith(`Port ${testPort} is already in use`), true); + resolve(); + }); + + sandbox.stub(http, 'createServer').callsFake(function () { + class Server extends EventEmitter { + constructor() { + super(); + } + listen() { + setTimeout(() => { + this.emit('error', { + code: 'EADDRINUSE', + syscall: 'listen' + }); + }, 0); + } } - } - return new Server(); - }); + return new Server(); + }); - server.start({ - set: () => {} - }, testPort); + server.start({ + set: () => {} + }, testPort); + }); }); - it('Emits pipe-specific error message when bound to a named pipe', function (done) { + it('Emits pipe-specific error message when bound to a named pipe', async function () { const testPipe = 'server-pipe'; - sandbox.stub(process, 'exit').callsFake(function () {}); - sandbox.stub(logging, 'error').callsFake(function (message) { - assert.equal(message.startsWith(`Pipe ${testPipe} requires elevated privileges`), true); - done(); - }); - - sandbox.stub(http, 'createServer').callsFake(function () { - class Server extends EventEmitter { - listen() { - setTimeout(() => { - this.emit('error', { - code: 'EACCES', - syscall: 'listen' - }); - }, 0); + await new Promise((resolve) => { + sandbox.stub(process, 'exit').callsFake(function () {}); + sandbox.stub(logging, 'error').callsFake(function (message) { + assert.equal(message.startsWith(`Pipe ${testPipe} requires elevated privileges`), true); + resolve(); + }); + + sandbox.stub(http, 'createServer').callsFake(function () { + class Server extends EventEmitter { + listen() { + setTimeout(() => { + this.emit('error', { + code: 'EACCES', + syscall: 'listen' + }); + }, 0); + } } - } - return new Server(); - }); + return new Server(); + }); - server.start({ - set: () => {} - }, testPipe); + server.start({ + set: () => {} + }, testPipe); + }); }); it('Stops server without throwing', function () { @@ -218,79 +232,85 @@ describe('Server Utils', function () { assert.doesNotThrow(server.stop); }); - it('Emits listening event with numeric port', function (done) { + it('Emits listening event with numeric port', async function () { const testPort = 191; - sandbox.stub(logging, 'info').callsFake(function (message) { - assert.equal(message.startsWith(`Listening on port ${testPort}`), true); - done(); - }); - - sandbox.stub(http, 'createServer').callsFake(function () { - class Server extends EventEmitter { - listen() { - setTimeout(() => { - this.emit('listening'); - }, 0); + await new Promise((resolve) => { + sandbox.stub(logging, 'info').callsFake(function (message) { + assert.equal(message.startsWith(`Listening on port ${testPort}`), true); + resolve(); + }); + + sandbox.stub(http, 'createServer').callsFake(function () { + class Server extends EventEmitter { + listen() { + setTimeout(() => { + this.emit('listening'); + }, 0); + } + address() { + return {port: testPort}; + } } - address() { - return {port: testPort}; - } - } - return new Server(); - }); + return new Server(); + }); - server.start({ - set: () => {} - }, testPort); + server.start({ + set: () => {} + }, testPort); + }); }); - it('Throws unknown listen errors', function (done) { - sandbox.stub(http, 'createServer').callsFake(function () { - class Server extends EventEmitter { - listen() { - setTimeout(() => { - assert.throws(() => { - this.emit('error', { - code: 'EOTHER', - syscall: 'listen' + it('Throws unknown listen errors', async function () { + await new Promise((resolve) => { + sandbox.stub(http, 'createServer').callsFake(function () { + class Server extends EventEmitter { + listen() { + setTimeout(() => { + assert.throws(() => { + this.emit('error', { + code: 'EOTHER', + syscall: 'listen' + }); }); - }); - done(); - }, 0); + resolve(); + }, 0); + } } - } - return new Server(); - }); + return new Server(); + }); - server.start({ - set: () => {} - }, 180); + server.start({ + set: () => {} + }, 180); + }); }); - it('Throws errors not originating from listen syscall', function (done) { - sandbox.stub(http, 'createServer').callsFake(function () { - class Server extends EventEmitter { - listen() { - setTimeout(() => { - assert.throws(() => { - this.emit('error', { - code: 'EACCES', - syscall: 'not-listen' + it('Throws errors not originating from listen syscall', async function () { + await new Promise((resolve) => { + sandbox.stub(http, 'createServer').callsFake(function () { + class Server extends EventEmitter { + listen() { + setTimeout(() => { + assert.throws(() => { + this.emit('error', { + code: 'EACCES', + syscall: 'not-listen' + }); }); - }); - done(); - }, 0); + resolve(); + }, 0); + } } - } - return new Server(); - }); + return new Server(); + }); - server.start({ - set: () => {} - }, 180); + server.start({ + set: () => {} + }, 180); + }); }); }); diff --git a/packages/tpl/package.json b/packages/tpl/package.json index b9394ae76..a33adc239 100644 --- a/packages/tpl/package.json +++ b/packages/tpl/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/tsconfig.json b/packages/tsconfig.json index aaeef1036..f115f241e 100644 --- a/packages/tsconfig.json +++ b/packages/tsconfig.json @@ -36,8 +36,7 @@ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ "types": [ - "mocha", - "node", + "node" ], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ diff --git a/packages/validator/package.json b/packages/validator/package.json index dfb685aaa..0b3df0639 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5" }, "dependencies": { diff --git a/packages/version/package.json b/packages/version/package.json index bbc28c2c7..6ae723636 100644 --- a/packages/version/package.json +++ b/packages/version/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "mocha": "11.7.5", "sinon": "21.0.1" }, diff --git a/packages/webhook-mock-receiver/package.json b/packages/webhook-mock-receiver/package.json index 08cb4dfaa..904732f30 100644 --- a/packages/webhook-mock-receiver/package.json +++ b/packages/webhook-mock-receiver/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint:code": "eslint *.js lib/ --ext .js --cache", "lint": "yarn lint:code && yarn lint:test", "lint:test": "eslint -c test/.eslintrc.js test/ --ext .js --cache", @@ -25,7 +25,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "got": "14.6.6", "mocha": "11.7.5", "sinon": "21.0.1" diff --git a/packages/webhook-mock-receiver/test/.eslintrc.js b/packages/webhook-mock-receiver/test/.eslintrc.js index 829b601eb..ef13dee0e 100644 --- a/packages/webhook-mock-receiver/test/.eslintrc.js +++ b/packages/webhook-mock-receiver/test/.eslintrc.js @@ -2,5 +2,8 @@ module.exports = { plugins: ['ghost'], extends: [ 'plugin:ghost/test' - ] + ], + globals: { + beforeAll: 'readonly' + } }; diff --git a/packages/webhook-mock-receiver/test/WebhookMockReceiver.test.js b/packages/webhook-mock-receiver/test/WebhookMockReceiver.test.js index 0372a5036..5ee66d62f 100644 --- a/packages/webhook-mock-receiver/test/WebhookMockReceiver.test.js +++ b/packages/webhook-mock-receiver/test/WebhookMockReceiver.test.js @@ -9,7 +9,7 @@ describe('Webhook Mock Receiver', function () { let got; const webhookURL = 'https://test-webhook-receiver.com/webhook'; - before(async function () { + beforeAll(async function () { got = (await import('got')).default; snapshotManager = { assertSnapshot: sinon.spy() diff --git a/packages/zip/package.json b/packages/zip/package.json index ba5eed56f..222cf899f 100644 --- a/packages/zip/package.json +++ b/packages/zip/package.json @@ -11,7 +11,7 @@ "main": "index.js", "scripts": { "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura mocha './test/**/*.test.js'", + "test": "NODE_ENV=testing vitest run --coverage --config ../../vitest.config.ts", "lint": "eslint . --ext .js --cache", "posttest": "yarn lint" }, @@ -23,7 +23,6 @@ "access": "public" }, "devDependencies": { - "c8": "11.0.0", "folder-hash": "4.1.1", "mocha": "11.7.5", "sinon": "21.0.1" diff --git a/packages/zip/test/.eslintrc.js b/packages/zip/test/.eslintrc.js index 829b601eb..c0a7056a1 100644 --- a/packages/zip/test/.eslintrc.js +++ b/packages/zip/test/.eslintrc.js @@ -2,5 +2,9 @@ module.exports = { plugins: ['ghost'], extends: [ 'plugin:ghost/test' - ] + ], + globals: { + beforeAll: 'readonly', + afterAll: 'readonly' + } }; diff --git a/packages/zip/test/zip.test.js b/packages/zip/test/zip.test.js index 1e3e34c9a..e43b09eb2 100644 --- a/packages/zip/test/zip.test.js +++ b/packages/zip/test/zip.test.js @@ -18,7 +18,7 @@ describe('Compress and Extract should be opposite functions', function () { fs.rmSync(unzipDestination, {recursive: true, force: true}); }; - before(function () { + beforeAll(function () { symlinkPath = path.join(__dirname, 'fixtures', 'theme-symlink'); themeFolder = path.join(__dirname, 'fixtures', 'test-theme'); zipDestination = path.join(__dirname, 'fixtures', 'test-theme.zip'); @@ -27,41 +27,26 @@ describe('Compress and Extract should be opposite functions', function () { cleanUp(); }); - after(function () { + afterAll(function () { cleanUp(); }); - it('ensure symlinks work', function (done) { + it('ensure symlinks work', async function () { fs.symlinkSync(themeFolder, symlinkPath); - let originalHash; - - hashElement(symlinkPath) - .then((_originalHash) => { - originalHash = _originalHash; - return compress(symlinkPath, zipDestination); - }) - .then((res) => { - assert.equal(typeof res, 'object'); - assert.equal(res.path, zipDestination); - assert.equal(res.size < 619618, true); - - return extract(zipDestination, unzipDestination); - }) - .then((res) => { - assert.equal(typeof res, 'object'); - assert.equal(res.path, unzipDestination); - - return hashElement(unzipDestination); - }) - .then((extractedHash) => { - assert.equal(originalHash.children.toString(), extractedHash.children.toString()); - - done(); - }) - .catch((err) => { - return done(err); - }); + const originalHash = await hashElement(symlinkPath); + + const compressRes = await compress(symlinkPath, zipDestination); + assert.equal(typeof compressRes, 'object'); + assert.equal(compressRes.path, zipDestination); + assert.equal(compressRes.size < 619618, true); + + const extractRes = await extract(zipDestination, unzipDestination); + assert.equal(typeof extractRes, 'object'); + assert.equal(extractRes.path, unzipDestination); + + const extractedHash = await hashElement(unzipDestination); + assert.equal(originalHash.children.toString(), extractedHash.children.toString()); }); it('rejects when archiver emits an async error event', async function () { @@ -98,7 +83,7 @@ describe('Compress and Extract should be opposite functions', function () { describe('Extract zip', function () { let themeFolder, zipDestination, unzipDestination, symLinkPath, longFilePath; - before(function () { + beforeAll(function () { themeFolder = path.join(__dirname, 'fixtures', 'test-theme'); zipDestination = path.join(__dirname, 'fixtures', 'test-theme.zip'); unzipDestination = path.join(__dirname, 'fixtures', 'test-theme-unzipped'); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 000000000..06915f140 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,20 @@ +import {defineConfig} from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['test/**/*.test.{js,ts}'], + coverage: { + provider: 'v8', + all: true, + reporter: ['text', 'cobertura'], + thresholds: { + lines: 90, + functions: 90, + branches: 90, + statements: 90 + } + } + } +}); diff --git a/yarn.lock b/yarn.lock index eaffe3a7f..4e596d7ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@ampproject/remapping@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + "@aws-crypto/sha256-browser@5.2.0": version "5.2.0" resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz#153895ef1dba6f9fce38af550e0ef58988eb649e" @@ -640,7 +648,7 @@ "@babel/template" "^7.28.6" "@babel/types" "^7.28.6" -"@babel/parser@^7.23.9", "@babel/parser@^7.28.6", "@babel/parser@^7.29.0": +"@babel/parser@^7.23.9", "@babel/parser@^7.25.4", "@babel/parser@^7.28.6", "@babel/parser@^7.29.0": version "7.29.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.0.tgz#669ef345add7d057e92b7ed15f0bac07611831b6" integrity sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww== @@ -1384,7 +1392,7 @@ "@babel/types" "^7.29.0" debug "^4.3.1" -"@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.5", "@babel/types@^7.28.6", "@babel/types@^7.29.0", "@babel/types@^7.4.4": +"@babel/types@^7.25.4", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.5", "@babel/types@^7.28.6", "@babel/types@^7.29.0", "@babel/types@^7.4.4": version "7.29.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== @@ -1392,7 +1400,7 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" -"@bcoe/v8-coverage@^1.0.1": +"@bcoe/v8-coverage@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz#bbe12dca5b4ef983a0d0af4b07b9bc90ea0ababa" integrity sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA== @@ -1459,131 +1467,261 @@ dependencies: tslib "^2.4.0" +"@esbuild/aix-ppc64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz#80fcbe36130e58b7670511e888b8e88a259ed76c" + integrity sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA== + "@esbuild/aix-ppc64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz#815b39267f9bffd3407ea6c376ac32946e24f8d2" integrity sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg== +"@esbuild/android-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz#8aa4965f8d0a7982dc21734bf6601323a66da752" + integrity sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg== + "@esbuild/android-arm64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz#19b882408829ad8e12b10aff2840711b2da361e8" integrity sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg== +"@esbuild/android-arm@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz#300712101f7f50f1d2627a162e6e09b109b6767a" + integrity sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg== + "@esbuild/android-arm@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.27.3.tgz#90be58de27915efa27b767fcbdb37a4470627d7b" integrity sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA== +"@esbuild/android-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz#87dfb27161202bdc958ef48bb61b09c758faee16" + integrity sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg== + "@esbuild/android-x64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.27.3.tgz#d7dcc976f16e01a9aaa2f9b938fbec7389f895ac" integrity sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ== +"@esbuild/darwin-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz#79197898ec1ff745d21c071e1c7cc3c802f0c1fd" + integrity sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg== + "@esbuild/darwin-arm64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz#9f6cac72b3a8532298a6a4493ed639a8988e8abd" integrity sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg== +"@esbuild/darwin-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz#146400a8562133f45c4d2eadcf37ddd09718079e" + integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA== + "@esbuild/darwin-x64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz#ac61d645faa37fd650340f1866b0812e1fb14d6a" integrity sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg== +"@esbuild/freebsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz#1c5f9ba7206e158fd2b24c59fa2d2c8bb47ca0fe" + integrity sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg== + "@esbuild/freebsd-arm64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz#b8625689d73cf1830fe58c39051acdc12474ea1b" integrity sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w== +"@esbuild/freebsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz#ea631f4a36beaac4b9279fa0fcc6ca29eaeeb2b3" + integrity sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ== + "@esbuild/freebsd-x64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz#07be7dd3c9d42fe0eccd2ab9f9ded780bc53bead" integrity sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA== +"@esbuild/linux-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz#e1066bce58394f1b1141deec8557a5f0a22f5977" + integrity sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ== + "@esbuild/linux-arm64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz#bf31918fe5c798586460d2b3d6c46ed2c01ca0b6" integrity sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg== +"@esbuild/linux-arm@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz#452cd66b20932d08bdc53a8b61c0e30baf4348b9" + integrity sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw== + "@esbuild/linux-arm@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz#28493ee46abec1dc3f500223cd9f8d2df08f9d11" integrity sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw== +"@esbuild/linux-ia32@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz#b24f8acc45bcf54192c7f2f3be1b53e6551eafe0" + integrity sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA== + "@esbuild/linux-ia32@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz#750752a8b30b43647402561eea764d0a41d0ee29" integrity sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg== +"@esbuild/linux-loong64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz#f9cfffa7fc8322571fbc4c8b3268caf15bd81ad0" + integrity sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng== + "@esbuild/linux-loong64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz#a5a92813a04e71198c50f05adfaf18fc1e95b9ed" integrity sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA== +"@esbuild/linux-mips64el@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz#575a14bd74644ffab891adc7d7e60d275296f2cd" + integrity sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw== + "@esbuild/linux-mips64el@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz#deb45d7fd2d2161eadf1fbc593637ed766d50bb1" integrity sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw== +"@esbuild/linux-ppc64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz#75b99c70a95fbd5f7739d7692befe60601591869" + integrity sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA== + "@esbuild/linux-ppc64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz#6f39ae0b8c4d3d2d61a65b26df79f6e12a1c3d78" integrity sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA== +"@esbuild/linux-riscv64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz#2e3259440321a44e79ddf7535c325057da875cd6" + integrity sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w== + "@esbuild/linux-riscv64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz#4c5c19c3916612ec8e3915187030b9df0b955c1d" integrity sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ== +"@esbuild/linux-s390x@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz#17676cabbfe5928da5b2a0d6df5d58cd08db2663" + integrity sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg== + "@esbuild/linux-s390x@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz#9ed17b3198fa08ad5ccaa9e74f6c0aff7ad0156d" integrity sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw== +"@esbuild/linux-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz#0583775685ca82066d04c3507f09524d3cd7a306" + integrity sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw== + "@esbuild/linux-x64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz#12383dcbf71b7cf6513e58b4b08d95a710bf52a5" integrity sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA== +"@esbuild/netbsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz#f04c4049cb2e252fe96b16fed90f70746b13f4a4" + integrity sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg== + "@esbuild/netbsd-arm64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz#dd0cb2fa543205fcd931df44f4786bfcce6df7d7" integrity sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA== +"@esbuild/netbsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz#77da0d0a0d826d7c921eea3d40292548b258a076" + integrity sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ== + "@esbuild/netbsd-x64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz#028ad1807a8e03e155153b2d025b506c3787354b" integrity sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA== +"@esbuild/openbsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz#6296f5867aedef28a81b22ab2009c786a952dccd" + integrity sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A== + "@esbuild/openbsd-arm64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz#e3c16ff3490c9b59b969fffca87f350ffc0e2af5" integrity sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw== +"@esbuild/openbsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz#f8d23303360e27b16cf065b23bbff43c14142679" + integrity sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw== + "@esbuild/openbsd-x64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz#c5a4693fcb03d1cbecbf8b422422468dfc0d2a8b" integrity sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ== +"@esbuild/openharmony-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz#49e0b768744a3924be0d7fd97dd6ce9b2923d88d" + integrity sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg== + "@esbuild/openharmony-arm64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz#082082444f12db564a0775a41e1991c0e125055e" integrity sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g== +"@esbuild/sunos-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz#a6ed7d6778d67e528c81fb165b23f4911b9b13d6" + integrity sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w== + "@esbuild/sunos-x64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz#5ab036c53f929e8405c4e96e865a424160a1b537" integrity sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA== +"@esbuild/win32-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz#9ac14c378e1b653af17d08e7d3ce34caef587323" + integrity sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg== + "@esbuild/win32-arm64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz#38de700ef4b960a0045370c171794526e589862e" integrity sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA== +"@esbuild/win32-ia32@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz#918942dcbbb35cc14fca39afb91b5e6a3d127267" + integrity sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ== + "@esbuild/win32-ia32@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz#451b93dc03ec5d4f38619e6cd64d9f9eff06f55c" integrity sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q== +"@esbuild/win32-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5" + integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA== + "@esbuild/win32-x64@0.27.3": version "0.27.3" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz#0eaf705c941a218a43dba8e09f1df1d6cd2f1f17" @@ -1885,7 +2023,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": version "1.5.5" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== @@ -1898,7 +2036,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28": +"@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28": version "0.3.31" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== @@ -2132,6 +2270,131 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.9.tgz#d229a7b7f9dac167a156992ef23c7f023653f53b" integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA== +"@rollup/rollup-android-arm-eabi@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz#a6742c74c7d9d6d604ef8a48f99326b4ecda3d82" + integrity sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg== + +"@rollup/rollup-android-arm64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz#97247be098de4df0c11971089fd2edf80a5da8cf" + integrity sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q== + +"@rollup/rollup-darwin-arm64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz#674852cf14cf11b8056e0b1a2f4e872b523576cf" + integrity sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg== + +"@rollup/rollup-darwin-x64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz#36dfd7ed0aaf4d9d89d9ef983af72632455b0246" + integrity sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w== + +"@rollup/rollup-freebsd-arm64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz#2f87c2074b4220260fdb52a9996246edfc633c22" + integrity sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA== + +"@rollup/rollup-freebsd-x64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz#9b5a26522a38a95dc06616d1939d4d9a76937803" + integrity sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg== + +"@rollup/rollup-linux-arm-gnueabihf@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz#86aa4859385a8734235b5e40a48e52d770758c3a" + integrity sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw== + +"@rollup/rollup-linux-arm-musleabihf@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz#cbe70e56e6ece8dac83eb773b624fc9e5a460976" + integrity sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA== + +"@rollup/rollup-linux-arm64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz#d14992a2e653bc3263d284bc6579b7a2890e1c45" + integrity sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA== + +"@rollup/rollup-linux-arm64-musl@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz#2fdd1ddc434ea90aeaa0851d2044789b4d07f6da" + integrity sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA== + +"@rollup/rollup-linux-loong64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz#8a181e6f89f969f21666a743cd411416c80099e7" + integrity sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg== + +"@rollup/rollup-linux-loong64-musl@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz#904125af2babc395f8061daa27b5af1f4e3f2f78" + integrity sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q== + +"@rollup/rollup-linux-ppc64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz#a57970ac6864c9a3447411a658224bdcf948be22" + integrity sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA== + +"@rollup/rollup-linux-ppc64-musl@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz#bb84de5b26870567a4267666e08891e80bb56a63" + integrity sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA== + +"@rollup/rollup-linux-riscv64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz#72d00d2c7fb375ce3564e759db33f17a35bffab9" + integrity sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg== + +"@rollup/rollup-linux-riscv64-musl@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz#4c166ef58e718f9245bd31873384ba15a5c1a883" + integrity sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg== + +"@rollup/rollup-linux-s390x-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz#bb5025cde9a61db478c2ca7215808ad3bce73a09" + integrity sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w== + +"@rollup/rollup-linux-x64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz#9b66b1f9cd95c6624c788f021c756269ffed1552" + integrity sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg== + +"@rollup/rollup-linux-x64-musl@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz#b007ca255dc7166017d57d7d2451963f0bd23fd9" + integrity sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg== + +"@rollup/rollup-openbsd-x64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz#e8b357b2d1aa2c8d76a98f5f0d889eabe93f4ef9" + integrity sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ== + +"@rollup/rollup-openharmony-arm64@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz#96c2e3f4aacd3d921981329831ff8dde492204dc" + integrity sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA== + +"@rollup/rollup-win32-arm64-msvc@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz#2d865149d706d938df8b4b8f117e69a77646d581" + integrity sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A== + +"@rollup/rollup-win32-ia32-msvc@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz#abe1593be0fa92325e9971c8da429c5e05b92c36" + integrity sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA== + +"@rollup/rollup-win32-x64-gnu@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz#c4af3e9518c9a5cd4b1c163dc81d0ad4d82e7eab" + integrity sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA== + +"@rollup/rollup-win32-x64-msvc@4.59.0": + version "4.59.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz#4584a8a87b29188a4c1fe987a9fcf701e256d86c" + integrity sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA== + "@sec-ant/readable-stream@^0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz#60de891bb126abfdc5410fdc6166aca065f10a0c" @@ -2694,7 +2957,7 @@ resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.5.tgz#14a3e83fa641beb169a2dd8422d91c3c345a9a78" integrity sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q== -"@types/estree@^1.0.6": +"@types/estree@1.0.8", "@types/estree@^1.0.0", "@types/estree@^1.0.6": version "1.0.8" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== @@ -2728,7 +2991,7 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.5.tgz#5b749ab2b16ba113423feb1a64a95dcd30398472" integrity sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg== -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.1", "@types/istanbul-lib-coverage@^2.0.6": +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.6": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== @@ -2762,11 +3025,6 @@ resolved "https://registry.yarnpkg.com/@types/methods/-/methods-1.1.4.tgz#d3b7ac30ac47c91054ea951ce9eed07b1051e547" integrity sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ== -"@types/mocha@10.0.10": - version "10.0.10" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.10.tgz#91f62905e8d23cbd66225312f239454a23bebfa0" - integrity sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q== - "@types/node@*": version "25.3.3" resolved "https://registry.yarnpkg.com/@types/node/-/node-25.3.3.tgz#605862544ee7ffd7a936bcbf0135a14012f1e549" @@ -2988,6 +3246,90 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== +"@vitest/coverage-v8@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-3.1.1.tgz#5f24a2a1620dc602fd5eb07b72b5c77f7ad5943b" + integrity sha512-MgV6D2dhpD6Hp/uroUoAIvFqA8AuvXEFBC2eepG3WFc1pxTfdk1LEqqkWoWhjz+rytoqrnUUCdf6Lzco3iHkLQ== + dependencies: + "@ampproject/remapping" "^2.3.0" + "@bcoe/v8-coverage" "^1.0.2" + debug "^4.4.0" + istanbul-lib-coverage "^3.2.2" + istanbul-lib-report "^3.0.1" + istanbul-lib-source-maps "^5.0.6" + istanbul-reports "^3.1.7" + magic-string "^0.30.17" + magicast "^0.3.5" + std-env "^3.8.1" + test-exclude "^7.0.1" + tinyrainbow "^2.0.0" + +"@vitest/expect@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.1.1.tgz#d64ddfdcf9e877d805e1eee67bd845bf0708c6c2" + integrity sha512-q/zjrW9lgynctNbwvFtQkGK9+vvHA5UzVi2V8APrp1C6fG6/MuYYkmlx4FubuqLycCeSdHD5aadWfua/Vr0EUA== + dependencies: + "@vitest/spy" "3.1.1" + "@vitest/utils" "3.1.1" + chai "^5.2.0" + tinyrainbow "^2.0.0" + +"@vitest/mocker@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-3.1.1.tgz#7689d99f87498684c71e9fe9defdbd13ffb7f1ac" + integrity sha512-bmpJJm7Y7i9BBELlLuuM1J1Q6EQ6K5Ye4wcyOpOMXMcePYKSIYlpcrCm4l/O6ja4VJA5G2aMJiuZkZdnxlC3SA== + dependencies: + "@vitest/spy" "3.1.1" + estree-walker "^3.0.3" + magic-string "^0.30.17" + +"@vitest/pretty-format@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-3.1.1.tgz#5b4d577771daccfced47baf3bf026ad59b52c283" + integrity sha512-dg0CIzNx+hMMYfNmSqJlLSXEmnNhMswcn3sXO7Tpldr0LiGmg3eXdLLhwkv2ZqgHb/d5xg5F7ezNFRA1fA13yA== + dependencies: + tinyrainbow "^2.0.0" + +"@vitest/pretty-format@^3.1.1": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-3.2.4.tgz#3c102f79e82b204a26c7a5921bf47d534919d3b4" + integrity sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA== + dependencies: + tinyrainbow "^2.0.0" + +"@vitest/runner@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-3.1.1.tgz#76b598700737089d66c74272b2e1c94ca2891a49" + integrity sha512-X/d46qzJuEDO8ueyjtKfxffiXraPRfmYasoC4i5+mlLEJ10UvPb0XH5M9C3gWuxd7BAQhpK42cJgJtq53YnWVA== + dependencies: + "@vitest/utils" "3.1.1" + pathe "^2.0.3" + +"@vitest/snapshot@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-3.1.1.tgz#42b6aa0d0e2b3b48b95a5c76efdcc66a44cb11f3" + integrity sha512-bByMwaVWe/+1WDf9exFxWWgAixelSdiwo2p33tpqIlM14vW7PRV5ppayVXtfycqze4Qhtwag5sVhX400MLBOOw== + dependencies: + "@vitest/pretty-format" "3.1.1" + magic-string "^0.30.17" + pathe "^2.0.3" + +"@vitest/spy@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-3.1.1.tgz#deca0b025e151302ab514f38390fd7777e294837" + integrity sha512-+EmrUOOXbKzLkTDwlsc/xrwOlPDXyVk3Z6P6K4oiCndxz7YLpp/0R0UsWVOKT0IXWjjBJuSMk6D27qipaupcvQ== + dependencies: + tinyspy "^3.0.2" + +"@vitest/utils@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-3.1.1.tgz#2893c30219ab6bdf109f07ce5cd287fe8058438d" + integrity sha512-1XIjflyaU2k3HMArJ50bwSh3wKWPD6Q47wz/NUSmRV0zNywPc4w79ARjg/i/aNINHwA+mIALhUVqD9/aUvZNgg== + dependencies: + "@vitest/pretty-format" "3.1.1" + loupe "^3.1.3" + tinyrainbow "^2.0.0" + "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" @@ -3180,6 +3522,11 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + async@^3.0.0, async@^3.2.4, async@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" @@ -3559,22 +3906,10 @@ bytes@^3.1.2, bytes@~3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -c8@11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/c8/-/c8-11.0.0.tgz#d0420d93b90202490041c338a8aa95174eca0586" - integrity sha512-e/uRViGHSVIJv7zsaDKM7VRn2390TgHXqUSvYwPHBQaU6L7E9L0n9JbdkwdYPvshDT0KymBmmlwSpms3yBaMNg== - dependencies: - "@bcoe/v8-coverage" "^1.0.1" - "@istanbuljs/schema" "^0.1.3" - find-up "^5.0.0" - foreground-child "^3.1.1" - istanbul-lib-coverage "^3.2.0" - istanbul-lib-report "^3.0.1" - istanbul-reports "^3.1.6" - test-exclude "^8.0.0" - v8-to-istanbul "^9.0.0" - yargs "^17.7.2" - yargs-parser "^21.1.1" +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== cacheable-lookup@7.0.0, cacheable-lookup@^7.0.0: version "7.0.0" @@ -3640,6 +3975,17 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== +chai@^5.2.0: + version "5.3.3" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.3.3.tgz#dd3da955e270916a4bd3f625f4b919996ada7e06" + integrity sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw== + dependencies: + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" + chalk-template@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-0.4.0.tgz#692c034d0ed62436b9062c1707fadcd0f753204b" @@ -3660,6 +4006,11 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +check-error@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.3.tgz#2427361117b70cca8dc89680ead32b157019caf5" + integrity sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA== + chokidar@^4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" @@ -4011,6 +4362,11 @@ decompress-response@^10.0.0: dependencies: mimic-response "^4.0.0" +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== + deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" @@ -4220,6 +4576,11 @@ es-errors@^1.3.0: resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-module-lexer@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a" + integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== + es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" @@ -4269,6 +4630,38 @@ esbuild@0.27.3: "@esbuild/win32-ia32" "0.27.3" "@esbuild/win32-x64" "0.27.3" +esbuild@^0.25.0: + version "0.25.12" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.12.tgz#97a1d041f4ab00c2fce2f838d2b9969a2d2a97a5" + integrity sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.12" + "@esbuild/android-arm" "0.25.12" + "@esbuild/android-arm64" "0.25.12" + "@esbuild/android-x64" "0.25.12" + "@esbuild/darwin-arm64" "0.25.12" + "@esbuild/darwin-x64" "0.25.12" + "@esbuild/freebsd-arm64" "0.25.12" + "@esbuild/freebsd-x64" "0.25.12" + "@esbuild/linux-arm" "0.25.12" + "@esbuild/linux-arm64" "0.25.12" + "@esbuild/linux-ia32" "0.25.12" + "@esbuild/linux-loong64" "0.25.12" + "@esbuild/linux-mips64el" "0.25.12" + "@esbuild/linux-ppc64" "0.25.12" + "@esbuild/linux-riscv64" "0.25.12" + "@esbuild/linux-s390x" "0.25.12" + "@esbuild/linux-x64" "0.25.12" + "@esbuild/netbsd-arm64" "0.25.12" + "@esbuild/netbsd-x64" "0.25.12" + "@esbuild/openbsd-arm64" "0.25.12" + "@esbuild/openbsd-x64" "0.25.12" + "@esbuild/openharmony-arm64" "0.25.12" + "@esbuild/sunos-x64" "0.25.12" + "@esbuild/win32-arm64" "0.25.12" + "@esbuild/win32-ia32" "0.25.12" + "@esbuild/win32-x64" "0.25.12" + escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" @@ -4594,6 +4987,13 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -4621,6 +5021,11 @@ events@^3.3.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +expect-type@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.3.0.tgz#0d58ed361877a31bbc4dd6cf71bbfef7faf6bd68" + integrity sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA== + expect@30.2.0: version "30.2.0" resolved "https://registry.yarnpkg.com/expect/-/expect-30.2.0.tgz#d4013bed267013c14bc1199cec8aa57cee9b5869" @@ -4760,7 +5165,7 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -fdir@^6.5.0: +fdir@^6.4.4, fdir@^6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== @@ -4883,7 +5288,7 @@ follow-redirects@^1.15.11: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== -foreground-child@^3.1.0, foreground-child@^3.1.1: +foreground-child@^3.1.0: version "3.3.1" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== @@ -4966,7 +5371,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.3: +fsevents@^2.3.3, fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -5068,7 +5473,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^10.0.0, glob@^10.4.5: +glob@^10.0.0, glob@^10.4.1, glob@^10.4.5: version "10.5.0" resolved "https://registry.yarnpkg.com/glob/-/glob-10.5.0.tgz#8ec0355919cd3338c28428a23d4f24ecc5fe738c" integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg== @@ -5080,15 +5485,6 @@ glob@^10.0.0, glob@^10.4.5: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^13.0.6: - version "13.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-13.0.6.tgz#078666566a425147ccacfbd2e332deb66a2be71d" - integrity sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw== - dependencies: - minimatch "^10.2.2" - minipass "^7.1.3" - path-scurry "^2.0.2" - glob@^6.0.1: version "6.0.4" resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" @@ -5482,7 +5878,7 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0, istanbul-lib-coverage@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== @@ -5507,7 +5903,16 @@ istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: make-dir "^4.0.0" supports-color "^7.1.0" -istanbul-reports@^3.1.6: +istanbul-lib-source-maps@^5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz#acaef948df7747c8eb5fbf1265cb980f6353a441" + integrity sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A== + dependencies: + "@jridgewell/trace-mapping" "^0.3.23" + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + +istanbul-reports@^3.1.7: version "3.2.0" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== @@ -5930,6 +6335,11 @@ long-timeout@^0.1.1: resolved "https://registry.yarnpkg.com/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514" integrity sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w== +loupe@^3.1.0, loupe@^3.1.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76" + integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ== + lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" @@ -5947,11 +6357,6 @@ lru-cache@^10.2.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== -lru-cache@^11.0.0: - version "11.2.6" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.2.6.tgz#356bf8a29e88a7a2945507b31f6429a65a192c58" - integrity sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ== - lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -5959,6 +6364,22 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +magic-string@^0.30.17: + version "0.30.21" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" + integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + +magicast@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.5.tgz#8301c3c7d66704a0771eb1bad74274f0ec036739" + integrity sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ== + dependencies: + "@babel/parser" "^7.25.4" + "@babel/types" "^7.25.4" + source-map-js "^1.2.0" + mailgun.js@^8.0.1: version "8.2.2" resolved "https://registry.yarnpkg.com/mailgun.js/-/mailgun.js-8.2.2.tgz#97133d69fd76b77c67eedb394fd85b1875cac600" @@ -6131,7 +6552,7 @@ minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2, minipass@^7.1.3: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.3" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b" integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A== @@ -6221,6 +6642,11 @@ nan@^2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.25.0.tgz#937ed345e63d9481362a7942d49c4860d27eeabd" integrity sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g== +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -6604,14 +7030,6 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-scurry@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.2.tgz#6be0d0ee02a10d9e0de7a98bae65e182c9061f85" - integrity sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg== - dependencies: - lru-cache "^11.0.0" - minipass "^7.1.2" - path-to-regexp@^8.0.0: version "8.3.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.3.0.tgz#aa818a6981f99321003a08987d3cec9c3474cd1f" @@ -6622,6 +7040,16 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +pathval@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.1.tgz#8855c5a2899af072d6ac05d11e46045ad0dc605d" + integrity sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ== + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -6667,6 +7095,15 @@ pluralize@^8.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +postcss@^8.5.3: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -7033,6 +7470,40 @@ rimraf@~2.4.0: dependencies: glob "^6.0.1" +rollup@^4.34.9: + version "4.59.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.59.0.tgz#cf74edac17c1486f562d728a4d923a694abdf06f" + integrity sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.59.0" + "@rollup/rollup-android-arm64" "4.59.0" + "@rollup/rollup-darwin-arm64" "4.59.0" + "@rollup/rollup-darwin-x64" "4.59.0" + "@rollup/rollup-freebsd-arm64" "4.59.0" + "@rollup/rollup-freebsd-x64" "4.59.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.59.0" + "@rollup/rollup-linux-arm-musleabihf" "4.59.0" + "@rollup/rollup-linux-arm64-gnu" "4.59.0" + "@rollup/rollup-linux-arm64-musl" "4.59.0" + "@rollup/rollup-linux-loong64-gnu" "4.59.0" + "@rollup/rollup-linux-loong64-musl" "4.59.0" + "@rollup/rollup-linux-ppc64-gnu" "4.59.0" + "@rollup/rollup-linux-ppc64-musl" "4.59.0" + "@rollup/rollup-linux-riscv64-gnu" "4.59.0" + "@rollup/rollup-linux-riscv64-musl" "4.59.0" + "@rollup/rollup-linux-s390x-gnu" "4.59.0" + "@rollup/rollup-linux-x64-gnu" "4.59.0" + "@rollup/rollup-linux-x64-musl" "4.59.0" + "@rollup/rollup-openbsd-x64" "4.59.0" + "@rollup/rollup-openharmony-arm64" "4.59.0" + "@rollup/rollup-win32-arm64-msvc" "4.59.0" + "@rollup/rollup-win32-ia32-msvc" "4.59.0" + "@rollup/rollup-win32-x64-gnu" "4.59.0" + "@rollup/rollup-win32-x64-msvc" "4.59.0" + fsevents "~2.3.2" + router@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef" @@ -7199,6 +7670,11 @@ side-channel@^1.1.0: side-channel-map "^1.0.1" side-channel-weakmap "^1.0.2" +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + signal-exit@^3.0.2: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" @@ -7246,7 +7722,7 @@ snake-case@^3.0.3: dot-case "^3.0.4" tslib "^2.0.3" -source-map-js@^1.0.1: +source-map-js@^1.0.1, source-map-js@^1.2.0, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== @@ -7322,11 +7798,21 @@ stack-utils@^2.0.6: dependencies: escape-string-regexp "^2.0.0" +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== + statuses@^2.0.1, statuses@^2.0.2, statuses@~2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382" integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw== +std-env@^3.8.1: + version "3.10.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b" + integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg== + stoppable@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/stoppable/-/stoppable-1.1.0.tgz#32da568e83ea488b08e4d7ea2c3bcc9d75015d5b" @@ -7557,13 +8043,13 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" -test-exclude@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-8.0.0.tgz#85891add3fa46bb822b1b1579c7f8c9a3d04ebd8" - integrity sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ== +test-exclude@^7.0.1: + version "7.0.2" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-7.0.2.tgz#482392077630bc57d5630c13abe908bb910dfc65" + integrity sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw== dependencies: "@istanbuljs/schema" "^0.1.2" - glob "^13.0.6" + glob "^10.4.1" minimatch "^10.2.2" text-decoder@^1.1.0: @@ -7588,7 +8074,17 @@ tiny-case@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== -tinyglobby@^0.2.12, tinyglobby@^0.2.15: +tinybench@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" + integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== + +tinyexec@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinyglobby@^0.2.12, tinyglobby@^0.2.13, tinyglobby@^0.2.15: version "0.2.15" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== @@ -7596,6 +8092,21 @@ tinyglobby@^0.2.12, tinyglobby@^0.2.15: fdir "^6.5.0" picomatch "^4.0.3" +tinypool@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.1.1.tgz#059f2d042bd37567fbc017d3d426bdd2a2612591" + integrity sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg== + +tinyrainbow@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz#9509b2162436315e80e3eee0fcce4474d2444294" + integrity sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw== + +tinyspy@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" + integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== + tmp@~0.2.1: version "0.2.5" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.5.tgz#b06bcd23f0f3c8357b426891726d16015abfd8f8" @@ -7872,15 +8383,6 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -v8-to-istanbul@^9.0.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" - integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.12" - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^2.0.0" - validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -7908,6 +8410,57 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vite-node@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-3.1.1.tgz#ad186c07859a6e5fca7c7f563e55fb11b16557bc" + integrity sha512-V+IxPAE2FvXpTCHXyNem0M+gWm6J7eRyWPR6vYoG/Gl+IscNOjXzztUhimQgTxaAoUoj40Qqimaa0NLIOOAH4w== + dependencies: + cac "^6.7.14" + debug "^4.4.0" + es-module-lexer "^1.6.0" + pathe "^2.0.3" + vite "^5.0.0 || ^6.0.0" + +"vite@^5.0.0 || ^6.0.0": + version "6.4.1" + resolved "https://registry.yarnpkg.com/vite/-/vite-6.4.1.tgz#afbe14518cdd6887e240a4b0221ab6d0ce733f96" + integrity sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g== + dependencies: + esbuild "^0.25.0" + fdir "^6.4.4" + picomatch "^4.0.2" + postcss "^8.5.3" + rollup "^4.34.9" + tinyglobby "^0.2.13" + optionalDependencies: + fsevents "~2.3.3" + +vitest@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.1.1.tgz#39fa2356e510513fccdc5d16465a9fc066ef1fc6" + integrity sha512-kiZc/IYmKICeBAZr9DQ5rT7/6bD9G7uqQEki4fxazi1jdVl2mWGzedtBs5s6llz59yQhVb7FFY2MbHzHCnT79Q== + dependencies: + "@vitest/expect" "3.1.1" + "@vitest/mocker" "3.1.1" + "@vitest/pretty-format" "^3.1.1" + "@vitest/runner" "3.1.1" + "@vitest/snapshot" "3.1.1" + "@vitest/spy" "3.1.1" + "@vitest/utils" "3.1.1" + chai "^5.2.0" + debug "^4.4.0" + expect-type "^1.2.0" + magic-string "^0.30.17" + pathe "^2.0.3" + std-env "^3.8.1" + tinybench "^2.9.0" + tinyexec "^0.3.2" + tinypool "^1.0.2" + tinyrainbow "^2.0.0" + vite "^5.0.0 || ^6.0.0" + vite-node "3.1.1" + why-is-node-running "^2.3.0" + walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" @@ -7929,6 +8482,14 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +why-is-node-running@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" + word-wrap@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"