diff --git a/services/web/.eslintrc.js b/services/web/.eslintrc.js index 69b9bff98f..637676c604 100644 --- a/services/web/.eslintrc.js +++ b/services/web/.eslintrc.js @@ -71,7 +71,7 @@ module.exports = { files: ['**/test/**/*.*'], excludedFiles: [ '**/test/unit/src/**/*.test.mjs', - 'test/unit/vitest_bootstrap.mjs', + 'test/unit/bootstrap.mjs', ], // exclude vitest files plugins: ['mocha', 'chai-expect', 'chai-friendly'], env: { @@ -105,10 +105,7 @@ module.exports = { }, }, { - files: [ - '**/test/unit/src/**/*.test.mjs', - 'test/unit/vitest_bootstrap.mjs', - ], + files: ['**/test/unit/src/**/*.test.mjs', 'test/unit/bootstrap.mjs'], env: { jest: true, // best match for vitest API etc. }, diff --git a/services/web/Makefile b/services/web/Makefile index f78e912b6c..62db346a0f 100644 --- a/services/web/Makefile +++ b/services/web/Makefile @@ -101,29 +101,19 @@ test_unit_app: export COMPOSE_PROJECT_NAME=unit_test_$(BUILD_DIR_NAME) test_unit_app: mongo_migrations_for_tests $(DOCKER_COMPOSE) run --name unit_test_$(BUILD_DIR_NAME) --rm test_unit -test_unit_mocha: export MOCHA_ROOT_SUITE_NAME = Mocha unit tests -test_unit_mocha: export COMPOSE_PROJECT_NAME=unit_test_mocha_$(BUILD_DIR_NAME) -test_unit_mocha: mongo_migrations_for_tests - $(DOCKER_COMPOSE) run --rm test_unit npm run test:unit:mocha +test_unit_parallel: export VITEST_ROOT_SUITE_NAME = ESM unit tests - parallel +test_unit_parallel: export COMPOSE_PROJECT_NAME=unit_test_parallel_$(BUILD_DIR_NAME) +test_unit_parallel: mongo_migrations_for_tests + $(DOCKER_COMPOSE) run --rm test_unit npm run test:unit:parallel -test_unit_esm: export VITEST_ROOT_SUITE_NAME = ESM unit tests - parallel -test_unit_esm: export COMPOSE_PROJECT_NAME=unit_test_esm_parallel_$(BUILD_DIR_NAME) -test_unit_esm: mongo_migrations_for_tests - $(DOCKER_COMPOSE) run --rm test_unit npm run test:unit:esm +test_unit_sequential: export VITEST_ROOT_SUITE_NAME = ESM unit tests - sequential +test_unit_sequential: export COMPOSE_PROJECT_NAME=unit_test_sequential_$(BUILD_DIR_NAME) +test_unit_sequential: mongo_migrations_for_tests + $(DOCKER_COMPOSE) run --rm test_unit npm run test:unit:sequential -test_unit_esm_parallel: export VITEST_ROOT_SUITE_NAME = ESM unit tests - parallel -test_unit_esm_parallel: export COMPOSE_PROJECT_NAME=unit_test_esm_parallel_$(BUILD_DIR_NAME) -test_unit_esm_parallel: mongo_migrations_for_tests - $(DOCKER_COMPOSE) run --rm test_unit npm run test:unit:esm:parallel - -test_unit_esm_sequential: export VITEST_ROOT_SUITE_NAME = ESM unit tests - sequential -test_unit_esm_sequential: export COMPOSE_PROJECT_NAME=unit_test_esm_sequential_$(BUILD_DIR_NAME) -test_unit_esm_sequential: mongo_migrations_for_tests - $(DOCKER_COMPOSE) run --rm test_unit npm run test:unit:esm:sequential - -test_unit_esm_watch: export COMPOSE_PROJECT_NAME=unit_test_esm_watch_$(BUILD_DIR_NAME) -test_unit_esm_watch: mongo_migrations_for_tests - $(DOCKER_COMPOSE) run --rm test_unit npm run test:unit:esm:watch +test_unit_watch: export COMPOSE_PROJECT_NAME=unit_test_watch_$(BUILD_DIR_NAME) +test_unit_watch: mongo_migrations_for_tests + $(DOCKER_COMPOSE) run --rm test_unit npm run test:unit:watch TEST_SUITES = $(sort $(filter-out \ $(wildcard test/unit/src/helpers/*), \ diff --git a/services/web/bin/lint_flag_res_send_usage b/services/web/bin/lint_flag_res_send_usage index ea3ad30e23..a4ff1f5f62 100755 --- a/services/web/bin/lint_flag_res_send_usage +++ b/services/web/bin/lint_flag_res_send_usage @@ -15,12 +15,13 @@ POTENTIAL_SEND_USAGE=$(\ --regex "\bsend(" \ ) HELPER_MODULE="app/src/infrastructure/Response.mjs" -if [[ "$POTENTIAL_SEND_USAGE" == "$HELPER_MODULE" ]]; then +MOCK_MODULE="test/acceptance/src/mocks/MockResponse.mjs" +if [[ "$POTENTIAL_SEND_USAGE" == "$HELPER_MODULE" ]] || [[ "$file" == "$MOCK_MODULE" ]]; then exit 0 fi for file in ${POTENTIAL_SEND_USAGE}; do - if [[ "$file" == "$HELPER_MODULE" ]]; then + if [[ "$file" == "$HELPER_MODULE" ]] || [[ "$file" == "$MOCK_MODULE" ]]; then continue fi diff --git a/services/web/bin/test_unit_run_dir b/services/web/bin/test_unit_run_dir index 320b075ce5..39f4cc96d0 100755 --- a/services/web/bin/test_unit_run_dir +++ b/services/web/bin/test_unit_run_dir @@ -2,19 +2,6 @@ declare -a vitest_args=("$@") -has_mocha_test=0 -has_sequential_test=0 - -for dir_path in "$@"; do - if [ -n "$(find "$dir_path" -name "*.js" -type f -print -quit 2>/dev/null)" ]; then - has_mocha_test=1 - fi - - if [ -n "$(find "$dir_path" -name "*.sequential.test.mjs" -type f -print -quit 2>/dev/null)" ]; then - has_sequential_test=1 - fi -done - if [[ -n "$MOCHA_GREP" ]]; then vitest_args+=("--testNamePattern" "$MOCHA_GREP") fi @@ -26,41 +13,24 @@ fi echo "Running unit tests in directory: $*" - -npm run test:unit:esm:parallel -- "${vitest_args[@]}" +npm run test:unit:parallel -- "${vitest_args[@]}" vitest_parallel_status=$? -if (( has_sequential_test == 0 )); then - echo "No sequential vitest tests found, skipping sequential vitest step." - vitest_sequential_status=0 -else - npm run test:unit:esm:sequential -- "${vitest_args[@]}" - vitest_sequential_status=$? -fi -if (( has_mocha_test == 1 )); then - mocha --recursive --timeout 25000 --exit --grep="$MOCHA_GREP" --require test/unit/bootstrap.js --extension=js "$@" - mocha_status=$? -else - echo "No mocha tests found, skipping mocha step." - mocha_status=0 -fi +npm run test:unit:sequential -- "${vitest_args[@]}" +vitest_sequential_status=$? -if [ "$mocha_status" -eq 0 ] && [ "$vitest_sequential_status" -eq 0 ] && [ "$vitest_parallel_status" -eq 0 ]; then +if [ "$vitest_sequential_status" -eq 0 ] && [ "$vitest_parallel_status" -eq 0 ]; then exit 0 fi # Report status briefly at the end for failures -if [ "$mocha_status" -ne 0 ]; then - echo "Mocha tests failed with status: $mocha_status" -fi - if [ "$vitest_parallel_status" -ne 0 ]; then - echo "Vitest parallel tests failed with status: $vitest_parallel_status" + echo "Parallel tests failed with status: $vitest_parallel_status" fi if [ "$vitest_sequential_status" -ne 0 ]; then - echo "Vitest sequential tests failed with status: $vitest_sequential_status" + echo "Sequential tests failed with status: $vitest_sequential_status" fi exit 1 diff --git a/services/web/modules/launchpad/test/unit/src/LaunchpadController.test.mjs b/services/web/modules/launchpad/test/unit/src/LaunchpadController.test.mjs index a0d3ce5b88..3a32265f45 100644 --- a/services/web/modules/launchpad/test/unit/src/LaunchpadController.test.mjs +++ b/services/web/modules/launchpad/test/unit/src/LaunchpadController.test.mjs @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import * as path from 'node:path' import sinon from 'sinon' -import MockResponse from '../../../../../test/unit/src/helpers/MockResponse.js' +import MockResponse from '../../../../../test/unit/src/helpers/MockResponse.mjs' const modulePath = path.join( import.meta.dirname, @@ -9,10 +9,6 @@ const modulePath = path.join( ) describe('LaunchpadController', function () { - // esmock doesn't work well with CommonJS dependencies, global imports for - // @overleaf/settings aren't working until that module is migrated to ESM. In the - // meantime, the workaround is to set and restore settings values - beforeEach(async function (ctx) { ctx.user = { _id: '323123', @@ -89,7 +85,7 @@ describe('LaunchpadController', function () { session: {}, } - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) ctx.res.locals = { translate(key) { return key @@ -127,8 +123,8 @@ describe('LaunchpadController', function () { import.meta.dirname, '../../../app/views/launchpad' ) - ctx.res.render.callCount.should.equal(1) - expect(ctx.res.render).to.have.been.calledWith(viewPath, { + expect(ctx.res.render).toHaveBeenCalledTimes(1) + expect(ctx.res.render).toHaveBeenCalledWith(viewPath, { adminUserExists: false, authMethod: 'local', }) @@ -149,11 +145,11 @@ describe('LaunchpadController', function () { ctx.AuthenticationController.setRedirectInSession.callCount.should.equal( 1 ) - ctx.res.redirect.calledWith('/login').should.equal(true) + expect(ctx.res.redirect).toHaveBeenCalledWith('/login') }) it('should not render the launchpad page', function (ctx) { - ctx.res.render.callCount.should.equal(0) + expect(ctx.res.render).not.toHaveBeenCalled() }) }) }) @@ -185,8 +181,8 @@ describe('LaunchpadController', function () { import.meta.dirname, '../../../app/views/launchpad' ) - ctx.res.render.callCount.should.equal(1) - expect(ctx.res.render).to.have.been.calledWith(viewPath, { + expect(ctx.res.render).toHaveBeenCalledTimes(1) + expect(ctx.res.render).toHaveBeenCalledWith(viewPath, { wsUrl: undefined, adminUserExists: true, authMethod: 'local', @@ -207,8 +203,8 @@ describe('LaunchpadController', function () { }) it('should redirect to restricted page', function (ctx) { - ctx.res.redirect.callCount.should.equal(1) - ctx.res.redirect.calledWith('/restricted').should.equal(true) + expect(ctx.res.redirect).toHaveBeenCalledTimes(1) + expect(ctx.res.redirect).toHaveBeenCalledWith('/restricted') }) }) }) @@ -258,7 +254,7 @@ describe('LaunchpadController', function () { it('should produce a 200 response', async function (ctx) { await ctx.LaunchpadController.sendTestEmail(ctx.req, ctx.res, ctx.next) - ctx.res.json.calledWith({ message: 'email_sent' }).should.equal(true) + expect(ctx.res.json).toHaveBeenCalledWith({ message: 'email_sent' }) }) it('should not call next with an error', function (ctx) { @@ -300,12 +296,10 @@ describe('LaunchpadController', function () { it('should produce a 400 response', function (ctx) { ctx.LaunchpadController.sendTestEmail(ctx.req, ctx.res, ctx.next) - ctx.res.status.calledWith(400).should.equal(true) - ctx.res.json - .calledWith({ - message: 'no email address supplied', - }) - .should.equal(true) + expect(ctx.res.status).toHaveBeenCalledWith(400) + expect(ctx.res.json).toHaveBeenCalledWith({ + message: 'no email address supplied', + }) }) }) }) @@ -341,8 +335,8 @@ describe('LaunchpadController', function () { }) it('should send back a json response', function (ctx) { - ctx.res.json.callCount.should.equal(1) - expect(ctx.res.json).to.have.been.calledWith({ redir: '/launchpad' }) + expect(ctx.res.json).toHaveBeenCalledTimes(1) + expect(ctx.res.json).toHaveBeenCalledWith({ redir: '/launchpad' }) }) it('should have checked for existing admins', function (ctx) { @@ -394,8 +388,8 @@ describe('LaunchpadController', function () { }) it('should send a 400 response', function (ctx) { - ctx.res.sendStatus.callCount.should.equal(1) - ctx.res.sendStatus.calledWith(400).should.equal(true) + expect(ctx.res.sendStatus).toHaveBeenCalledTimes(1) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(400) }) it('should not check for existing admins', function (ctx) { @@ -427,8 +421,8 @@ describe('LaunchpadController', function () { }) it('should send a 400 response', function (ctx) { - ctx.res.sendStatus.callCount.should.equal(1) - ctx.res.sendStatus.calledWith(400).should.equal(true) + expect(ctx.res.sendStatus).toHaveBeenCalledTimes(1) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(400) }) it('should not check for existing admins', function (ctx) { @@ -464,9 +458,9 @@ describe('LaunchpadController', function () { }) it('should send a 400 response', function (ctx) { - ctx.res.status.callCount.should.equal(1) - ctx.res.status.calledWith(400).should.equal(true) - ctx.res.json.calledWith({ + expect(ctx.res.status).toHaveBeenCalledTimes(1) + expect(ctx.res.status).toHaveBeenCalledWith(400) + expect(ctx.res.json).toHaveBeenCalledWith({ message: { type: 'error', text: 'bad email' }, }) }) @@ -500,9 +494,9 @@ describe('LaunchpadController', function () { }) it('should send a 400 response', function (ctx) { - ctx.res.status.callCount.should.equal(1) - ctx.res.status.calledWith(400).should.equal(true) - ctx.res.json.calledWith({ + expect(ctx.res.status).toHaveBeenCalledTimes(1) + expect(ctx.res.status).toHaveBeenCalledWith(400) + expect(ctx.res.json).toHaveBeenCalledWith({ message: { type: 'error', text: 'bad password' }, }) }) @@ -534,8 +528,8 @@ describe('LaunchpadController', function () { }) it('should send a 403 response', function (ctx) { - ctx.res.status.callCount.should.equal(1) - ctx.res.status.calledWith(403).should.equal(true) + expect(ctx.res.status).toHaveBeenCalledTimes(1) + expect(ctx.res.status).toHaveBeenCalledWith(403) }) it('should not call registerNewUser', function (ctx) { @@ -690,8 +684,8 @@ describe('LaunchpadController', function () { }) it('should send back a json response', function (ctx) { - ctx.res.json.callCount.should.equal(1) - expect(ctx.res.json).to.have.been.calledWith({ redir: '/launchpad' }) + expect(ctx.res.json).toHaveBeenCalledTimes(1) + expect(ctx.res.json).toHaveBeenCalledWith({ redir: '/launchpad' }) }) it('should have checked for existing admins', function (ctx) { @@ -757,8 +751,8 @@ describe('LaunchpadController', function () { }) it('should send back a json response', function (ctx) { - ctx.res.json.callCount.should.equal(1) - expect(ctx.res.json.lastCall.args[0].email).to.equal(ctx.email) + expect(ctx.res.json).toHaveBeenCalledTimes(1) + expect(ctx.res.json.mock.lastCall[0].email).to.equal(ctx.email) }) it('should have checked for existing admins', function (ctx) { @@ -824,8 +818,8 @@ describe('LaunchpadController', function () { }) it('should send a 403 response', function (ctx) { - ctx.res.sendStatus.callCount.should.equal(1) - ctx.res.sendStatus.calledWith(403).should.equal(true) + expect(ctx.res.sendStatus).toHaveBeenCalledTimes(1) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(403) }) it('should not check for existing admins', function (ctx) { @@ -859,8 +853,8 @@ describe('LaunchpadController', function () { }) it('should send a 400 response', function (ctx) { - ctx.res.sendStatus.callCount.should.equal(1) - ctx.res.sendStatus.calledWith(400).should.equal(true) + expect(ctx.res.sendStatus).toHaveBeenCalledTimes(1) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(400) }) it('should not check for existing admins', function (ctx) { @@ -894,8 +888,8 @@ describe('LaunchpadController', function () { }) it('should send a 403 response', function (ctx) { - ctx.res.sendStatus.callCount.should.equal(1) - ctx.res.sendStatus.calledWith(403).should.equal(true) + expect(ctx.res.sendStatus).toHaveBeenCalledTimes(1) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(403) }) it('should not call registerNewUser', function (ctx) { diff --git a/services/web/package.json b/services/web/package.json index 4582c1eeeb..1a7ec0c54c 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -13,12 +13,9 @@ "test:unit:all": "npm run test:unit:run_dir -- test/unit/src modules/*/test/unit/src", "test:unit:all:silent": "npm run test:unit:all -- --reporter dot", "test:unit:app": "npm run test:unit:run_dir -- test/unit/src", - "test:unit:mocha": "npm run test:unit:mocha:run_dir -- test/unit/src modules/*/test/unit/src", - "test:unit:mocha:run_dir": "mocha --recursive --timeout 25000 --exit --grep=$MOCHA_GREP --require test/unit/bootstrap.js --extension=js", - "test:unit:esm": "npm run test:unit:esm:parallel && npm run test:unit:esm:sequential", - "test:unit:esm:parallel": "vitest run --project=Parallel", - "test:unit:esm:sequential": "vitest run --project=Sequential --no-file-parallelism", - "test:unit:esm:watch": "vitest", + "test:unit:parallel": "vitest run --project=Parallel", + "test:unit:sequential": "vitest run --project=Sequential --no-file-parallelism", + "test:unit:watch": "vitest", "test:frontend": "NODE_ENV=test TZ=GMT mocha --recursive --timeout 5000 --exit --extension js,jsx,mjs,ts,tsx --grep=$MOCHA_GREP --require test/frontend/bootstrap.js --ignore '**/*.spec.{js,jsx,ts,tsx}' --ignore '**/helpers/**/*.{js,jsx,ts,tsx}' test/frontend modules/*/test/frontend", "test:frontend:coverage": "c8 --all --include 'frontend/js' --include 'modules/*/frontend/js' --exclude 'frontend/js/vendor' --reporter=lcov --reporter=text-summary npm run test:frontend", "test:writefull": "vitest --run --config modules/writefull/frontend/js/integration/vitest.config.ts", diff --git a/services/web/test/unit/src/helpers/MockResponse.js b/services/web/test/acceptance/src/mocks/MockResponse.mjs similarity index 81% rename from services/web/test/unit/src/helpers/MockResponse.js rename to services/web/test/acceptance/src/mocks/MockResponse.mjs index 80e7ae98af..2e63268454 100644 --- a/services/web/test/unit/src/helpers/MockResponse.js +++ b/services/web/test/acceptance/src/mocks/MockResponse.mjs @@ -1,19 +1,6 @@ -/* eslint-disable - no-return-assign, - no-unused-vars, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -const sinon = require('sinon') -const Path = require('path') -const contentDisposition = require('content-disposition') +import sinon from 'sinon' +import Path from 'node:path' +import contentDisposition from 'content-disposition' class MockResponse { static initClass() { @@ -160,7 +147,7 @@ class MockResponse { attachment(filename) { switch (Path.extname(filename)) { case '.csv': - this.contentType('text/csv; charset=utf-8') + this.contentType('text/csv; charset=utf8') break case '.zip': this.contentType('application/zip') @@ -168,12 +155,12 @@ class MockResponse { default: throw new Error('unexpected extension') } - this.header('Content-Disposition', contentDisposition(filename)) + this.header('ContentDisposition', contentDisposition(filename)) return this } contentType(type) { - this.header('Content-Type', type) + this.header('ContentType', type) this.type = type return this } @@ -184,4 +171,4 @@ class MockResponse { } MockResponse.initClass() -module.exports = MockResponse +export default MockResponse diff --git a/services/web/test/unit/bootstrap.js b/services/web/test/unit/bootstrap.js deleted file mode 100644 index 82a1b04072..0000000000 --- a/services/web/test/unit/bootstrap.js +++ /dev/null @@ -1,124 +0,0 @@ -const Path = require('path') -const sinon = require('sinon') -require('./common_bootstrap') -const chai = require('chai') - -/* - * Chai configuration - */ - -// add chai.should() -chai.should() - -// Load sinon-chai assertions so expect(stubFn).to.have.been.calledWith('abc') -// has a nicer failure messages -chai.use(require('sinon-chai')) - -// Load promise support for chai -chai.use(require('chai-as-promised')) - -// Do not truncate assertion errors -chai.config.truncateThreshold = 0 -/* - * Global stubs - */ -const globalStubsSandbox = sinon.createSandbox() -const globalStubs = { - logger: { - debug: globalStubsSandbox.stub(), - info: globalStubsSandbox.stub(), - log: globalStubsSandbox.stub(), - warn: globalStubsSandbox.stub(), - err: globalStubsSandbox.stub(), - error: globalStubsSandbox.stub(), - fatal: globalStubsSandbox.stub(), - }, -} - -/* - * Sandboxed module configuration - */ - -const SandboxedModule = require('sandboxed-module') -SandboxedModule.configure({ - ignoreMissing: true, - requires: getSandboxedModuleRequires(), - globals: { - AbortController, - AbortSignal, - Buffer, - Promise, - console, - process, - URL, - TextEncoder, - TextDecoder, - }, - sourceTransformers: { - removeNodePrefix: function (source) { - return source.replace(/require\(['"]node:/g, "require('") - }, - }, -}) - -function getSandboxedModuleRequires() { - const requires = { - '@overleaf/logger': globalStubs.logger, - } - - const internalModules = ['../../app/src/Features/Errors/Errors'] - const externalLibs = [ - 'async', - 'bull', - 'json2csv', - 'lodash', - 'marked', - 'moment', - '@overleaf/o-error', - 'sanitize-html', - 'sshpk', - 'xml2js', - 'mongodb', - 'mongodb-legacy', - ] - for (const modulePath of internalModules) { - requires[Path.resolve(__dirname, modulePath)] = require(modulePath) - } - for (const lib of externalLibs) { - requires[lib] = require(lib) - } - return requires -} - -/* - * Mocha hooks - */ - -// sandboxed-module somehow registers every fake module it creates in this -// module's children array, which uses quite a big amount of memory. We'll take -// a copy of the module children array and restore it after each test so that -// the garbage collector has a chance to reclaim the fake modules. -let initialModuleChildren - -exports.mochaHooks = { - beforeAll() { - // Record initial module children - initialModuleChildren = module.children.slice() - }, - - beforeEach() { - // Install logger stub - this.logger = globalStubs.logger - }, - - afterEach() { - // Delete leaking sandboxed modules - module.children = initialModuleChildren.slice() - - // Reset global stubs - globalStubsSandbox.reset() - - // Restore other stubs - sinon.restore() - }, -} diff --git a/services/web/test/unit/vitest_bootstrap.mjs b/services/web/test/unit/bootstrap.mjs similarity index 88% rename from services/web/test/unit/vitest_bootstrap.mjs rename to services/web/test/unit/bootstrap.mjs index cc057bd1f0..7173c1308f 100644 --- a/services/web/test/unit/vitest_bootstrap.mjs +++ b/services/web/test/unit/bootstrap.mjs @@ -1,10 +1,13 @@ -import { chai, vi } from 'vitest' -import './common_bootstrap.js' +import { afterEach, beforeEach, chai, vi } from 'vitest' +import 'sinon-mongoose' import sinon from 'sinon' import logger from '@overleaf/logger' import sinonChai from 'sinon-chai' import chaiAsPromised from 'chai-as-promised' import mongoose from 'mongoose' +import mongodb from 'mongodb-legacy' + +mongodb.ObjectId.cacheHexString = true /* * Chai configuration diff --git a/services/web/test/unit/common_bootstrap.js b/services/web/test/unit/common_bootstrap.js deleted file mode 100644 index a77aad61c6..0000000000 --- a/services/web/test/unit/common_bootstrap.js +++ /dev/null @@ -1,5 +0,0 @@ -// add support for mongoose in sinon -require('sinon-mongoose') - -// ensure every ObjectId has the id string as a property for correct comparisons -require('mongodb-legacy').ObjectId.cacheHexString = true diff --git a/services/web/test/unit/src/Analytics/AnalyticsController.test.mjs b/services/web/test/unit/src/Analytics/AnalyticsController.test.mjs index be86f3bd04..ae95397e7d 100644 --- a/services/web/test/unit/src/Analytics/AnalyticsController.test.mjs +++ b/services/web/test/unit/src/Analytics/AnalyticsController.test.mjs @@ -1,6 +1,6 @@ import { vi } from 'vitest' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' const modulePath = new URL( '../../../../app/src/Features/Analytics/AnalyticsController.mjs', import.meta.url diff --git a/services/web/test/unit/src/Analytics/AnalyticsManager.test.mjs b/services/web/test/unit/src/Analytics/AnalyticsManager.test.mjs index 423573421f..805b425c58 100644 --- a/services/web/test/unit/src/Analytics/AnalyticsManager.test.mjs +++ b/services/web/test/unit/src/Analytics/AnalyticsManager.test.mjs @@ -1,8 +1,8 @@ import { vi, assert } from 'vitest' import path from 'node:path' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequestVitest.mjs' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import mongodb from 'mongodb-legacy' const { ObjectId } = mongodb diff --git a/services/web/test/unit/src/Analytics/AnalyticsUTMTrackingMiddleware.test.mjs b/services/web/test/unit/src/Analytics/AnalyticsUTMTrackingMiddleware.test.mjs index dcad6a08cd..46fada8257 100644 --- a/services/web/test/unit/src/Analytics/AnalyticsUTMTrackingMiddleware.test.mjs +++ b/services/web/test/unit/src/Analytics/AnalyticsUTMTrackingMiddleware.test.mjs @@ -1,7 +1,7 @@ import { assert, vi } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequestVitest.mjs' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' const MODULE_PATH = new URL( '../../../../app/src/Features/Analytics/AnalyticsUTMTrackingMiddleware', diff --git a/services/web/test/unit/src/Authentication/AuthenticationController.test.mjs b/services/web/test/unit/src/Authentication/AuthenticationController.test.mjs index 17273d723f..fd14135c72 100644 --- a/services/web/test/unit/src/Authentication/AuthenticationController.test.mjs +++ b/services/web/test/unit/src/Authentication/AuthenticationController.test.mjs @@ -1,8 +1,8 @@ import { beforeEach, describe, it, vi, expect } from 'vitest' import sinon from 'sinon' import tk from 'timekeeper' -import MockRequest from '../helpers/MockRequestVitest.mjs' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import mongodb from 'mongodb-legacy' import AuthenticationErrors from '../../../../app/src/Features/Authentication/AuthenticationErrors.mjs' const modulePath = diff --git a/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs b/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs index a80a24e3c9..2eddd45faf 100644 --- a/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs +++ b/services/web/test/unit/src/BetaProgram/BetaProgramController.test.mjs @@ -1,7 +1,7 @@ import { expect, vi } from 'vitest' import path from 'node:path' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import { fileURLToPath } from 'node:url' const __dirname = fileURLToPath(new URL('.', import.meta.url)) diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsController.test.mjs b/services/web/test/unit/src/Collaborators/CollaboratorsController.test.mjs index 922673f436..eb61d8073f 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsController.test.mjs +++ b/services/web/test/unit/src/Collaborators/CollaboratorsController.test.mjs @@ -2,8 +2,8 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' import Errors from '../../../../app/src/Features/Errors/Errors.js' -import MockRequest from '../helpers/MockRequestVitest.mjs' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' const ObjectId = mongodb.ObjectId diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs b/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs index 7cfa9c71c2..3c3be83b9b 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs +++ b/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs @@ -1,7 +1,7 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequestVitest.mjs' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import mongodb from 'mongodb-legacy' import Errors from '../../../../app/src/Features/Errors/Errors.js' import _ from 'lodash' diff --git a/services/web/test/unit/src/Compile/CompileController.test.mjs b/services/web/test/unit/src/Compile/CompileController.test.mjs index ad74c4dfc3..501772f3e8 100644 --- a/services/web/test/unit/src/Compile/CompileController.test.mjs +++ b/services/web/test/unit/src/Compile/CompileController.test.mjs @@ -1,7 +1,7 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequestVitest.mjs' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import { Headers } from 'node-fetch' import { ReadableString } from '@overleaf/stream-utils' import { RequestFailedError } from '@overleaf/fetch-utils' diff --git a/services/web/test/unit/src/Contact/ContactController.test.mjs b/services/web/test/unit/src/Contact/ContactController.test.mjs index 3f85cf1c88..de1c61bb21 100644 --- a/services/web/test/unit/src/Contact/ContactController.test.mjs +++ b/services/web/test/unit/src/Contact/ContactController.test.mjs @@ -1,6 +1,6 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' const modulePath = '../../../../app/src/Features/Contacts/ContactController.mjs' describe('ContactController', function () { diff --git a/services/web/test/unit/src/DocumentUpdater/DocumentUpdaterController.test.mjs b/services/web/test/unit/src/DocumentUpdater/DocumentUpdaterController.test.mjs index 60b629f099..04d5e329c6 100644 --- a/services/web/test/unit/src/DocumentUpdater/DocumentUpdaterController.test.mjs +++ b/services/web/test/unit/src/DocumentUpdater/DocumentUpdaterController.test.mjs @@ -1,6 +1,6 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponse.js' +import MockResponse from '../helpers/MockResponse.mjs' const MODULE_PATH = '../../../../app/src/Features/DocumentUpdater/DocumentUpdaterController.mjs' @@ -49,7 +49,7 @@ describe('DocumentUpdaterController', function () { }, } ctx.lines = ['test', '', 'testing'] - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() ctx.doc = { name: 'myfile.tex' } }) @@ -62,7 +62,7 @@ describe('DocumentUpdaterController', function () { ctx.ProjectLocator.promises.findElement.resolves({ element: ctx.doc, }) - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) }) it('should call the document updater handler with the project_id and doc_id', async function (ctx) { @@ -96,10 +96,9 @@ describe('DocumentUpdaterController', function () { it('should set the Content-Disposition header', async function (ctx) { await ctx.controller.getDoc(ctx.req, ctx.res) - expect(ctx.res.setContentDisposition).to.have.been.calledWith( - 'attachment', - { filename: ctx.doc.name } - ) + expect(ctx.res.setContentDisposition).toHaveBeenCalledWith('attachment', { + filename: ctx.doc.name, + }) }) }) }) diff --git a/services/web/test/unit/src/Documents/DocumentController.test.mjs b/services/web/test/unit/src/Documents/DocumentController.test.mjs index 6cd4a7e11a..b25ea12a7f 100644 --- a/services/web/test/unit/src/Documents/DocumentController.test.mjs +++ b/services/web/test/unit/src/Documents/DocumentController.test.mjs @@ -1,7 +1,7 @@ import { vi } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import Errors from '../../../../app/src/Features/Errors/Errors.js' const MODULE_PATH = @@ -9,8 +9,8 @@ const MODULE_PATH = describe('DocumentController', function () { beforeEach(async function (ctx) { - ctx.res = new MockResponse() - ctx.req = new MockRequest() + ctx.res = new MockResponse(vi) + ctx.req = new MockRequest(vi) ctx.next = sinon.stub() ctx.doc = { _id: 'doc-id-123' } ctx.doc_lines = ['one', 'two', 'three'] diff --git a/services/web/test/unit/src/Downloads/ProjectDownloadsController.test.mjs b/services/web/test/unit/src/Downloads/ProjectDownloadsController.test.mjs index d202d56896..426af8b225 100644 --- a/services/web/test/unit/src/Downloads/ProjectDownloadsController.test.mjs +++ b/services/web/test/unit/src/Downloads/ProjectDownloadsController.test.mjs @@ -7,16 +7,16 @@ import { vi } from 'vitest' * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' const modulePath = '../../../../app/src/Features/Downloads/ProjectDownloadsController.mjs' describe('ProjectDownloadsController', function () { beforeEach(async function (ctx) { ctx.project_id = 'project-id-123' - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() ctx.DocumentUpdaterHandler = sinon.stub() @@ -78,9 +78,7 @@ describe('ProjectDownloadsController', function () { }) it('should set the correct content type on the request', function (ctx) { - return ctx.res.contentType - .calledWith('application/zip') - .should.equal(true) + expect(ctx.res.contentType).toHaveBeenCalledWith('application/zip') }) it('should flush the project to mongo', function (ctx) { @@ -138,9 +136,7 @@ describe('ProjectDownloadsController', function () { }) it('should set the correct content type on the request', function (ctx) { - return ctx.res.contentType - .calledWith('application/zip') - .should.equal(true) + expect(ctx.res.contentType).toHaveBeenCalledWith('application/zip') }) it('should flush the projects to mongo', function (ctx) { diff --git a/services/web/test/unit/src/Editor/EditorHttpController.test.mjs b/services/web/test/unit/src/Editor/EditorHttpController.test.mjs index 81c5a7b13b..2b883d4e93 100644 --- a/services/web/test/unit/src/Editor/EditorHttpController.test.mjs +++ b/services/web/test/unit/src/Editor/EditorHttpController.test.mjs @@ -2,8 +2,8 @@ import { beforeEach, describe, it, vi, expect } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' import Errors from '../../../../app/src/Features/Errors/Errors.js' -import MockRequest from '../helpers/MockRequestVitest.mjs' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' const { ObjectId } = mongodb diff --git a/services/web/test/unit/src/Errors/HttpErrorHandler.test.mjs b/services/web/test/unit/src/Errors/HttpErrorHandler.test.mjs index 2fca4d4216..41b6ca6cbf 100644 --- a/services/web/test/unit/src/Errors/HttpErrorHandler.test.mjs +++ b/services/web/test/unit/src/Errors/HttpErrorHandler.test.mjs @@ -1,12 +1,12 @@ import { vi, expect } from 'vitest' -import MockResponse from '../helpers/MockResponse.js' -import MockRequest from '../helpers/MockRequest.js' +import MockResponse from '../helpers/MockResponse.mjs' +import MockRequest from '../helpers/MockRequest.mjs' const modulePath = '../../../../app/src/Features/Errors/HttpErrorHandler.mjs' describe('HttpErrorHandler', function () { beforeEach(async function (ctx) { - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) vi.doMock('@overleaf/settings', () => ({ default: { @@ -274,8 +274,8 @@ describe('HttpErrorHandler', function () { it('should send the error to the logger', function (ctx) { const error = new Error('message') ctx.HttpErrorHandler.legacyInternal(ctx.req, ctx.res, 'message', error) - expect(ctx.req.logger.setLevel).to.have.been.calledWith('error') - expect(ctx.req.logger.addFields).to.have.been.calledWith({ + expect(ctx.req.logger.setLevel).toHaveBeenCalledWith('error') + expect(ctx.req.logger.addFields).toHaveBeenCalledWith({ err: error, }) }) diff --git a/services/web/test/unit/src/FileStore/FileStoreController.test.mjs b/services/web/test/unit/src/FileStore/FileStoreController.test.mjs index f2f147b020..9c7526943d 100644 --- a/services/web/test/unit/src/FileStore/FileStoreController.test.mjs +++ b/services/web/test/unit/src/FileStore/FileStoreController.test.mjs @@ -1,7 +1,7 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' import Errors from '../../../../app/src/Features/Errors/Errors.js' -import MockResponse from '../helpers/MockResponse.js' +import MockResponse from '../helpers/MockResponse.mjs' const MODULE_PATH = '../../../../app/src/Features/FileStore/FileStoreController.mjs' @@ -53,7 +53,7 @@ describe('FileStoreController', function () { addFields: sinon.stub(), }, } - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() ctx.hash = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ctx.file = { name: 'myfile.png', hash: ctx.hash } @@ -92,7 +92,7 @@ describe('FileStoreController', function () { it('should set the Content-Disposition header', async function (ctx) { await ctx.controller.getFile(ctx.req, ctx.res) - ctx.res.setContentDisposition.should.be.calledWith('attachment', { + expect(ctx.res.setContentDisposition).toBeCalledWith('attachment', { filename: ctx.file.name, }) }) @@ -216,8 +216,8 @@ describe('FileStoreController', function () { .resolves({ contentLength: expectedFileSize }) ctx.res.end = () => { - expect(ctx.res.status.lastCall.args).to.deep.equal([200]) - expect(ctx.res.header.lastCall.args).to.deep.equal([ + expect(ctx.res.status.mock.lastCall).to.deep.equal([200]) + expect(ctx.res.header.mock.lastCall).to.deep.equal([ 'Content-Length', expectedFileSize, ]) @@ -235,7 +235,7 @@ describe('FileStoreController', function () { ) ctx.res.end = () => { - expect(ctx.res.status.lastCall.args).to.deep.equal([404]) + expect(ctx.res.status.mock.lastCall).to.deep.equal([404]) resolve() } diff --git a/services/web/test/unit/src/HelperFiles/AdminAuthorizationHelper.test.mjs b/services/web/test/unit/src/HelperFiles/AdminAuthorizationHelper.test.mjs index 9ffd126363..418268d533 100644 --- a/services/web/test/unit/src/HelperFiles/AdminAuthorizationHelper.test.mjs +++ b/services/web/test/unit/src/HelperFiles/AdminAuthorizationHelper.test.mjs @@ -1,7 +1,7 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' const modulePath = '../../../../app/src/Features/Helpers/AdminAuthorizationHelper' @@ -68,8 +68,8 @@ describe('AdminAuthorizationHelper', function () { describe('when admin capabilities are not available', function () { describe('user is null', function () { beforeEach(async function (ctx) { - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() ctx.req.session = { @@ -93,8 +93,8 @@ describe('AdminAuthorizationHelper', function () { }) describe('user is not an admin', function () { beforeEach(async function (ctx) { - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() ctx.user = { @@ -122,8 +122,8 @@ describe('AdminAuthorizationHelper', function () { }) describe('user is an admin', function () { beforeEach(async function (ctx) { - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() ctx.user = { @@ -158,8 +158,8 @@ describe('AdminAuthorizationHelper', function () { }) describe('user is not an admin', function () { beforeEach(async function (ctx) { - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() ctx.user = { @@ -187,8 +187,8 @@ describe('AdminAuthorizationHelper', function () { }) describe('user is an admin', function () { beforeEach(async function (ctx) { - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() ctx.user = { @@ -221,8 +221,8 @@ describe('AdminAuthorizationHelper', function () { beforeEach(async function (ctx) { ctx.fireHook.rejects(new Error('Module error')) - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() ctx.user = { @@ -259,8 +259,8 @@ describe('AdminAuthorizationHelper', function () { }) describe('useHasAdminCapability', function () { it('adds hasAdminCapability to res.locals', function (ctx) { - const req = new MockRequest() - const res = new MockResponse() + const req = new MockRequest(vi) + const res = new MockResponse(vi) const next = sinon.stub() ctx.AdminAuthorizationHelper.useHasAdminCapability(req, res, next) @@ -272,8 +272,8 @@ describe('AdminAuthorizationHelper', function () { describe('when the user is not an admin', function () { describe('when req.adminCapabilitiesAvailable is true', function () { it('returns false for any capability', function (ctx) { - const req = new MockRequest() - const res = new MockResponse() + const req = new MockRequest(vi) + const res = new MockResponse(vi) const next = sinon.stub() req.adminCapabilitiesAvailable = true @@ -289,8 +289,8 @@ describe('AdminAuthorizationHelper', function () { describe('when req.adminCapabilitiesAvailable is false', function () { it('returns false for any capability', function (ctx) { - const req = new MockRequest() - const res = new MockResponse() + const req = new MockRequest(vi) + const res = new MockResponse(vi) const next = sinon.stub() req.adminCapabilitiesAvailable = false @@ -306,8 +306,8 @@ describe('AdminAuthorizationHelper', function () { describe('when req.adminCapabilitiesAvailable is undefined', function () { it('returns false for any capability', function (ctx) { - const req = new MockRequest() - const res = new MockResponse() + const req = new MockRequest(vi) + const res = new MockResponse(vi) const next = sinon.stub() req.session.user = { isAdmin: false } @@ -322,8 +322,8 @@ describe('AdminAuthorizationHelper', function () { describe('user is an admin', function () { describe('when req.adminCapabilitiesAvailable is false', function () { it('returns true for any capability', function (ctx) { - const req = new MockRequest() - const res = new MockResponse() + const req = new MockRequest(vi) + const res = new MockResponse(vi) const next = sinon.stub() req.session.user = { isAdmin: true } @@ -337,8 +337,8 @@ describe('AdminAuthorizationHelper', function () { describe('when req.adminCapabilitiesAvailable is undefined', function () { it('returns true for any capability', function (ctx) { - const req = new MockRequest() - const res = new MockResponse() + const req = new MockRequest(vi) + const res = new MockResponse(vi) const next = sinon.stub() req.session.user = { isAdmin: true } @@ -352,8 +352,8 @@ describe('AdminAuthorizationHelper', function () { describe('when req.adminCapabilitiesAvailable is true', function () { let req, res, next beforeEach(function (ctx) { - req = new MockRequest() - res = new MockResponse() + req = new MockRequest(vi) + res = new MockResponse(vi) next = sinon.stub() req.session.user = { isAdmin: true } diff --git a/services/web/test/unit/src/Metadata/MetaController.test.mjs b/services/web/test/unit/src/Metadata/MetaController.test.mjs index ee3488137a..3f25c59cde 100644 --- a/services/web/test/unit/src/Metadata/MetaController.test.mjs +++ b/services/web/test/unit/src/Metadata/MetaController.test.mjs @@ -1,6 +1,6 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponse.js' +import MockResponse from '../helpers/MockResponse.mjs' const modulePath = '../../../../app/src/Features/Metadata/MetaController.mjs' describe('MetaController', function () { @@ -45,7 +45,7 @@ describe('MetaController', function () { .resolves(projectMeta) const req = { params: { project_id: 'project-id' } } - const res = new MockResponse() + const res = new MockResponse(vi) const next = sinon.stub() await ctx.MetadataController.getMetadata(req, res, next) @@ -53,7 +53,8 @@ describe('MetaController', function () { ctx.MetaHandler.promises.getAllMetaForProject.should.have.been.calledWith( 'project-id' ) - res.json.should.have.been.calledOnceWith({ + expect(res.json).toHaveBeenCalledTimes(1) + expect(res.json).toHaveBeenCalledWith({ projectId: 'project-id', projectMeta, }) @@ -66,7 +67,7 @@ describe('MetaController', function () { .throws(new Error('woops')) const req = { params: { project_id: 'project-id' } } - const res = new MockResponse() + const res = new MockResponse(vi) const next = sinon.stub() await ctx.MetadataController.getMetadata(req, res, next) @@ -74,7 +75,7 @@ describe('MetaController', function () { ctx.MetaHandler.promises.getAllMetaForProject.should.have.been.calledWith( 'project-id' ) - res.json.should.not.have.been.called + expect(res.json).not.toHaveBeenCalled() next.should.have.been.calledWithMatch(error => error instanceof Error) }) }) @@ -93,7 +94,7 @@ describe('MetaController', function () { params: { project_id: 'project-id', doc_id: 'doc-id' }, body: { broadcast: true }, } - const res = new MockResponse() + const res = new MockResponse(vi) const next = sinon.stub() await ctx.MetadataController.broadcastMetadataForDoc(req, res, next) @@ -101,8 +102,9 @@ describe('MetaController', function () { ctx.MetaHandler.promises.getMetaForDoc.should.have.been.calledWith( 'project-id' ) - res.json.should.not.have.been.called - res.sendStatus.should.have.been.calledOnceWith(200) + expect(res.json).not.toHaveBeenCalled() + expect(res.sendStatus).toHaveBeenCalledTimes(1) + expect(res.sendStatus).toHaveBeenCalledWith(200) next.should.not.have.been.called ctx.EditorRealTimeController.emitToRoom.should.have.been.calledOnce @@ -127,7 +129,7 @@ describe('MetaController', function () { params: { project_id: 'project-id', doc_id: 'doc-id' }, body: { broadcast: false }, } - const res = new MockResponse() + const res = new MockResponse(vi) const next = sinon.stub() await ctx.MetadataController.broadcastMetadataForDoc(req, res, next) @@ -136,7 +138,8 @@ describe('MetaController', function () { 'project-id' ) ctx.EditorRealTimeController.emitToRoom.should.not.have.been.called - res.json.should.have.been.calledOnceWith({ + expect(res.json).toHaveBeenCalledTimes(1) + expect(res.json).toHaveBeenCalledWith({ docId: 'doc-id', meta: docMeta, }) @@ -154,7 +157,7 @@ describe('MetaController', function () { params: { project_id: 'project-id', doc_id: 'doc-id' }, body: { broadcast: true }, } - const res = new MockResponse() + const res = new MockResponse(vi) const next = sinon.stub() await ctx.MetadataController.broadcastMetadataForDoc(req, res, next) @@ -162,7 +165,7 @@ describe('MetaController', function () { ctx.MetaHandler.promises.getMetaForDoc.should.have.been.calledWith( 'project-id' ) - res.json.should.not.have.been.called + expect(res.json).not.toHaveBeenCalled() next.should.have.been.calledWithMatch(error => error instanceof Error) }) }) diff --git a/services/web/test/unit/src/PasswordReset/PasswordResetController.test.mjs b/services/web/test/unit/src/PasswordReset/PasswordResetController.test.mjs index cbc587b570..19c9b87956 100644 --- a/services/web/test/unit/src/PasswordReset/PasswordResetController.test.mjs +++ b/services/web/test/unit/src/PasswordReset/PasswordResetController.test.mjs @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponse.js' +import MockResponse from '../helpers/MockResponse.mjs' const MODULE_PATH = '../../../../app/src/Features/PasswordReset/PasswordResetController.mjs' @@ -25,7 +25,7 @@ describe('PasswordResetController', function () { session: {}, query: {}, } - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) ctx.settings = {} ctx.PasswordResetHandler = { @@ -110,21 +110,18 @@ describe('PasswordResetController', function () { describe('requestReset', function () { it('should tell the handler to process that email', async function (ctx) { - await new Promise(resolve => { - ctx.PasswordResetHandler.promises.generateAndEmailResetToken.resolves( - 'primary' - ) - ctx.res.callback = () => { - ctx.res.statusCode.should.equal(200) - ctx.res.json.calledWith(sinon.match.has('message')).should.equal(true) - expect( - ctx.PasswordResetHandler.promises.generateAndEmailResetToken - .lastCall.args[0] - ).equal(ctx.email) - resolve() - } - ctx.PasswordResetController.requestReset(ctx.req, ctx.res) - }) + ctx.PasswordResetHandler.promises.generateAndEmailResetToken.resolves( + 'primary' + ) + await ctx.PasswordResetController.requestReset(ctx.req, ctx.res) + expect(ctx.res.statusCode).to.equal(200) + expect(ctx.res.json).toHaveBeenCalledWith( + expect.objectContaining({ message: expect.anything() }) + ) + expect( + ctx.PasswordResetHandler.promises.generateAndEmailResetToken.lastCall + .args[0] + ).equal(ctx.email) }) it('should send a 500 if there is an error', async function (ctx) { @@ -140,47 +137,41 @@ describe('PasswordResetController', function () { }) it("should send a 404 if the email doesn't exist", async function (ctx) { - await new Promise(resolve => { - ctx.PasswordResetHandler.promises.generateAndEmailResetToken.resolves( - null - ) - ctx.res.callback = () => { - ctx.res.statusCode.should.equal(404) - ctx.res.json.calledWith(sinon.match.has('message')).should.equal(true) - resolve() - } - ctx.PasswordResetController.requestReset(ctx.req, ctx.res) - }) + ctx.PasswordResetHandler.promises.generateAndEmailResetToken.resolves( + null + ) + + await ctx.PasswordResetController.requestReset(ctx.req, ctx.res) + expect(ctx.res.statusCode).to.equal(404) + expect(ctx.res.json).toHaveBeenCalledWith( + expect.objectContaining({ message: expect.anything() }) + ) }) it('should send a 404 if the email is registered as a secondard email', async function (ctx) { - await new Promise(resolve => { - ctx.PasswordResetHandler.promises.generateAndEmailResetToken.resolves( - 'secondary' - ) - ctx.res.callback = () => { - ctx.res.statusCode.should.equal(404) - ctx.res.json.calledWith(sinon.match.has('message')).should.equal(true) - resolve() - } - ctx.PasswordResetController.requestReset(ctx.req, ctx.res) - }) + ctx.PasswordResetHandler.promises.generateAndEmailResetToken.resolves( + 'secondary' + ) + + await ctx.PasswordResetController.requestReset(ctx.req, ctx.res) + expect(ctx.res.statusCode).to.equal(404) + expect(ctx.res.json).toHaveBeenCalledWith( + expect.objectContaining({ message: expect.anything() }) + ) }) it('should normalize the email address', async function (ctx) { - await new Promise(resolve => { - ctx.email = ' UPperCaseEMAILWithSpacesAround@example.Com ' - ctx.req.body.email = ctx.email - ctx.PasswordResetHandler.promises.generateAndEmailResetToken.resolves( - 'primary' - ) - ctx.res.callback = () => { - ctx.res.statusCode.should.equal(200) - ctx.res.json.calledWith(sinon.match.has('message')).should.equal(true) - resolve() - } - ctx.PasswordResetController.requestReset(ctx.req, ctx.res) - }) + ctx.email = ' UPperCaseEMAILWithSpacesAround@example.Com ' + ctx.req.body.email = ctx.email + ctx.PasswordResetHandler.promises.generateAndEmailResetToken.resolves( + 'primary' + ) + + await ctx.PasswordResetController.requestReset(ctx.req, ctx.res) + expect(ctx.res.statusCode).to.equal(200) + expect(ctx.res.json).toHaveBeenCalledWith( + expect.objectContaining({ message: expect.anything() }) + ) }) }) diff --git a/services/web/test/unit/src/References/ReferencesController.test.mjs b/services/web/test/unit/src/References/ReferencesController.test.mjs index aaba6ad853..16ccf5e6a8 100644 --- a/services/web/test/unit/src/References/ReferencesController.test.mjs +++ b/services/web/test/unit/src/References/ReferencesController.test.mjs @@ -1,7 +1,7 @@ import { vi } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' const modulePath = '../../../../app/src/Features/References/ReferencesController' @@ -25,13 +25,13 @@ describe('ReferencesController', function () { ) ctx.controller = (await import(modulePath)).default - ctx.req = new MockRequest() + ctx.req = new MockRequest(vi) ctx.req.params.Project_id = ctx.projectId ctx.req.body = { docIds: (ctx.docIds = ['aaa', 'bbb']), shouldBroadcast: false, } - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) ctx.res.json = sinon.stub() ctx.res.sendStatus = sinon.stub() ctx.next = sinon.stub() diff --git a/services/web/test/unit/src/Settings/SettingsTests.js b/services/web/test/unit/src/Settings/Settings.test.mjs similarity index 95% rename from services/web/test/unit/src/Settings/SettingsTests.js rename to services/web/test/unit/src/Settings/Settings.test.mjs index 39e7efafd0..21e53061ad 100644 --- a/services/web/test/unit/src/Settings/SettingsTests.js +++ b/services/web/test/unit/src/Settings/Settings.test.mjs @@ -1,5 +1,7 @@ -const chai = require('chai') -const { expect } = chai +import { expect } from 'vitest' +import { createRequire } from 'node:module' + +const require = createRequire(import.meta.url) function clearSettingsCache() { const monorepoPath = require diff --git a/services/web/test/unit/src/SplitTests/SplitTestHandler.test.mjs b/services/web/test/unit/src/SplitTests/SplitTestHandler.test.mjs index a4c9dc61df..fcf4194378 100644 --- a/services/web/test/unit/src/SplitTests/SplitTestHandler.test.mjs +++ b/services/web/test/unit/src/SplitTests/SplitTestHandler.test.mjs @@ -2,8 +2,8 @@ import { vi, assert, expect } from 'vitest' import Path from 'node:path' import sinon from 'sinon' import mongodb from 'mongodb-legacy' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' const { ObjectId } = mongodb @@ -131,8 +131,8 @@ describe('SplitTestHandler', function () { ctx.SplitTestHandler = (await import(MODULE_PATH)).default - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) }) describe('with an existing user', function () { diff --git a/services/web/test/unit/src/SplitTests/SplitTestMiddleware.test.mjs b/services/web/test/unit/src/SplitTests/SplitTestMiddleware.test.mjs index dceecd664e..a14a913e28 100644 --- a/services/web/test/unit/src/SplitTests/SplitTestMiddleware.test.mjs +++ b/services/web/test/unit/src/SplitTests/SplitTestMiddleware.test.mjs @@ -1,7 +1,7 @@ import { vi } from 'vitest' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponse.js' -import MockRequest from '../helpers/MockRequest.js' +import MockResponse from '../helpers/MockResponse.mjs' +import MockRequest from '../helpers/MockRequest.mjs' const modulePath = '../../../../app/src/Features/SplitTests/SplitTestMiddleware' @@ -20,8 +20,8 @@ describe('SplitTestMiddleware', function () { ctx.SplitTestMiddleware = (await import(modulePath)).default - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() }) diff --git a/services/web/test/unit/src/Subscription/SubscriptionController.test.mjs b/services/web/test/unit/src/Subscription/SubscriptionController.test.mjs index b6020458aa..f515c068fc 100644 --- a/services/web/test/unit/src/Subscription/SubscriptionController.test.mjs +++ b/services/web/test/unit/src/Subscription/SubscriptionController.test.mjs @@ -1,7 +1,7 @@ import { vi, assert, expect } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import SubscriptionErrors from '../../../../app/src/Features/Subscription/Errors.mjs' import SubscriptionHelper from '../../../../app/src/Features/Subscription/SubscriptionHelper.mjs' import { AI_ADD_ON_CODE } from '../../../../app/src/Features/Subscription/AiHelper.mjs' @@ -375,8 +375,8 @@ describe('SubscriptionController', function () { ctx.SubscriptionController = (await import(modulePath)).default - ctx.res = new MockResponse() - ctx.req = new MockRequest() + ctx.res = new MockResponse(vi) + ctx.req = new MockRequest(vi) ctx.req.body = {} ctx.req.query = { planCode: '123123' } @@ -658,8 +658,8 @@ describe('SubscriptionController', function () { describe('pauseSubscription', function () { it('should throw an error if no pause length is provided', async function (ctx) { - ctx.res = new MockResponse() - ctx.req = new MockRequest() + ctx.res = new MockResponse(vi) + ctx.req = new MockRequest(vi) ctx.next = sinon.stub() await expect( ctx.SubscriptionController.pauseSubscription(ctx.req, ctx.res, ctx.next) @@ -667,8 +667,8 @@ describe('SubscriptionController', function () { }) it('should throw an error if an invalid pause length is provided', async function (ctx) { - ctx.res = new MockResponse() - ctx.req = new MockRequest() + ctx.res = new MockResponse(vi) + ctx.req = new MockRequest(vi) ctx.req.params = { pauseCycles: '-10' } ctx.next = sinon.stub() await ctx.SubscriptionController.pauseSubscription( @@ -680,8 +680,8 @@ describe('SubscriptionController', function () { }) it('should return a 200 when requesting a pause', async function (ctx) { - ctx.res = new MockResponse() - ctx.req = new MockRequest() + ctx.res = new MockResponse(vi) + ctx.req = new MockRequest(vi) ctx.req.params = { pauseCycles: '3' } ctx.next = sinon.stub() await ctx.SubscriptionController.pauseSubscription( @@ -695,8 +695,8 @@ describe('SubscriptionController', function () { describe('resumeSubscription', function () { it('should return a 200 when resuming a subscription', async function (ctx) { - ctx.res = new MockResponse() - ctx.req = new MockRequest() + ctx.res = new MockResponse(vi) + ctx.req = new MockRequest(vi) ctx.next = sinon.stub() await ctx.SubscriptionController.resumeSubscription( ctx.req, @@ -1066,7 +1066,7 @@ describe('SubscriptionController', function () { expect( ctx.FeaturesUpdater.promises.refreshFeatures ).to.have.been.calledWith(ctx.user._id, 'add-on-purchase') - expect(ctx.res.sendStatus).to.have.been.calledWith(200) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(200) }) it('should handle PaymentActionRequiredError and return 402 with details', async function (ctx) { @@ -1079,14 +1079,12 @@ describe('SubscriptionController', function () { await ctx.SubscriptionController.purchaseAddon(ctx.req, ctx.res, ctx.next) - ctx.res.status.calledWith(402).should.equal(true) - ctx.res.json - .calledWith({ - message: 'Payment action required', - clientSecret: 'secret123', - publicKey: 'pubkey456', - }) - .should.equal(true) + expect(ctx.res.status).toHaveBeenCalledWith(402) + expect(ctx.res.json).toHaveBeenCalledWith({ + message: 'Payment action required', + clientSecret: 'secret123', + publicKey: 'pubkey456', + }) expect(ctx.FeaturesUpdater.promises.refreshFeatures).to.not.have.been .called @@ -1503,10 +1501,10 @@ describe('SubscriptionController', function () { describe('previewAddonPurchase', function () { beforeEach(function (ctx) { - ctx.req = new MockRequest() + ctx.req = new MockRequest(vi) ctx.req.params = { addOnCode: 'assistant' } ctx.req.query = { purchaseReferrer: 'fake-referrer' } - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) ctx.Modules.promises.hooks.fire .withArgs('getPaymentMethod') diff --git a/services/web/test/unit/src/Subscription/SubscriptionGroupHandler.test.mjs b/services/web/test/unit/src/Subscription/SubscriptionGroupHandler.test.mjs index 70e29bdc29..7ea2548db6 100644 --- a/services/web/test/unit/src/Subscription/SubscriptionGroupHandler.test.mjs +++ b/services/web/test/unit/src/Subscription/SubscriptionGroupHandler.test.mjs @@ -1,7 +1,7 @@ import { vi, expect } from 'vitest' import mongodb from 'mongodb-legacy' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' +import MockRequest from '../helpers/MockRequest.mjs' import { InvalidEmailError } from '../../../../app/src/Features/Errors/Errors.js' const { ObjectId } = mongodb @@ -416,7 +416,7 @@ describe('SubscriptionGroupHandler', function () { describe('getUsersGroupSubscriptionDetails', function () { beforeEach(function (ctx) { - ctx.req = new MockRequest() + ctx.req = new MockRequest(vi) ctx.PlansLocator.findLocalPlanInSettings = sinon.stub().returns({ ...ctx.localPlanInSettings, canUseFlexibleLicensing: true, @@ -459,7 +459,7 @@ describe('SubscriptionGroupHandler', function () { describe('add seats subscription change', function () { beforeEach(function (ctx) { - ctx.req = new MockRequest() + ctx.req = new MockRequest(vi) Object.assign(ctx.req.body, { adding: ctx.adding }) ctx.PlansLocator.findLocalPlanInSettings = sinon.stub().returns({ ...ctx.localPlanInSettings, diff --git a/services/web/test/unit/src/ThirdPartyDataStore/TpdsController.test.mjs b/services/web/test/unit/src/ThirdPartyDataStore/TpdsController.test.mjs index f59273eed1..e6a0cb9619 100644 --- a/services/web/test/unit/src/ThirdPartyDataStore/TpdsController.test.mjs +++ b/services/web/test/unit/src/ThirdPartyDataStore/TpdsController.test.mjs @@ -2,8 +2,8 @@ import { expect, vi } from 'vitest' import mongodb from 'mongodb-legacy' import sinon from 'sinon' import Errors from '../../../../app/src/Features/Errors/Errors.js' -import MockResponse from '../helpers/MockResponse.js' -import MockRequest from '../helpers/MockRequest.js' +import MockResponse from '../helpers/MockResponse.mjs' +import MockRequest from '../helpers/MockRequest.mjs' const ObjectId = mongodb.ObjectId @@ -120,8 +120,8 @@ describe('TpdsController', function () { describe('creating a project', function () { it('should yield the new projects id', async function (ctx) { await new Promise(resolve => { - const res = new MockResponse() - const req = new MockRequest() + const res = new MockResponse(vi) + const req = new MockRequest(vi) req.params.user_id = ctx.user_id req.body = { projectName: 'foo' } res.callback = err => { diff --git a/services/web/test/unit/src/TokenAccess/TokenAccessController.test.mjs b/services/web/test/unit/src/TokenAccess/TokenAccessController.test.mjs index 9fd93ac294..6283e67e3d 100644 --- a/services/web/test/unit/src/TokenAccess/TokenAccessController.test.mjs +++ b/services/web/test/unit/src/TokenAccess/TokenAccessController.test.mjs @@ -1,8 +1,8 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' import mongodb from 'mongodb-legacy' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import PrivilegeLevels from '../../../../app/src/Features/Authorization/PrivilegeLevels.mjs' import UrlHelper from '../../../../app/src/Features/Helpers/UrlHelper.mjs' @@ -23,8 +23,8 @@ describe('TokenAccessController', function () { tokenAccessReadAndWrite_refs: [], tokenAccessReadOnly_refs: [], } - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub().returns() ctx.Settings = { @@ -567,7 +567,7 @@ describe('TokenAccessController', function () { }) it('redirects to restricted', function (ctx) { - expect(ctx.res.json).to.have.been.calledWith({ + expect(ctx.res.json).toHaveBeenCalledWith({ redirect: '/restricted', anonWriteAccessDenied: true, }) @@ -609,7 +609,7 @@ describe('TokenAccessController', function () { }) it('redirects to project', function (ctx) { - expect(ctx.res.json).to.have.been.calledWith({ + expect(ctx.res.json).toHaveBeenCalledWith({ redirect: `/project/${ctx.project._id}`, grantAnonymousAccess: 'readAndWrite', }) @@ -655,7 +655,7 @@ describe('TokenAccessController', function () { }) }) it('returns v1 import data', function (ctx) { - expect(ctx.res.json).to.have.been.calledWith({ + expect(ctx.res.json).toHaveBeenCalledWith({ v1Import: { status: 'canDownloadZip', projectId: ctx.token, @@ -698,7 +698,7 @@ describe('TokenAccessController', function () { }) }) it('returns 404', function (ctx) { - expect(ctx.res.sendStatus).to.have.been.calledWith(404) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(404) }) it('checks the hash prefix and includes log data', function (ctx) { expect( @@ -768,7 +768,7 @@ describe('TokenAccessController', function () { ctx.req, ctx.res ) - expect(ctx.res.json).to.have.been.calledWith({ + expect(ctx.res.json).toHaveBeenCalledWith({ redirect: `${ctx.Settings.adminUrl}/#prefix`, }) }) @@ -838,7 +838,7 @@ describe('TokenAccessController', function () { ctx.req.params = { token: ctx.token } ctx.req.body = { tokenHashPrefix: '#prefix' } ctx.TokenAccessController.grantTokenAccessReadAndWrite(ctx.req, ctx.res) - expect(ctx.res.sendStatus).to.have.been.calledWith(400) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(400) }) }) @@ -930,7 +930,7 @@ describe('TokenAccessController', function () { ctx.req.params = { token: ctx.token } ctx.req.body = { tokenHashPrefix: '#prefix' } ctx.TokenAccessController.grantTokenAccessReadOnly(ctx.req, ctx.res) - expect(ctx.res.sendStatus).to.have.been.calledWith(400) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(400) }) describe('anonymous users', function () { @@ -949,7 +949,7 @@ describe('TokenAccessController', function () { }) it('allows anonymous users and checks the token hash', function (ctx) { - expect(ctx.res.json).to.have.been.calledWith({ + expect(ctx.res.json).toHaveBeenCalledWith({ redirect: `/project/${ctx.project._id}`, grantAnonymousAccess: 'readOnly', }) @@ -1183,7 +1183,7 @@ describe('TokenAccessController', function () { ctx.user._id, PrivilegeLevels.READ_AND_WRITE ) - expect(ctx.res.sendStatus).to.have.been.calledWith(204) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(204) }) }) }) @@ -1223,7 +1223,7 @@ describe('TokenAccessController', function () { PrivilegeLevels.READ_ONLY, { pendingEditor: true } ) - expect(ctx.res.sendStatus).to.have.been.calledWith(204) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(204) }) }) }) @@ -1250,7 +1250,7 @@ describe('TokenAccessController', function () { expect( ctx.TokenAccessHandler.promises.moveReadAndWriteUserToReadOnly ).to.have.been.calledWith(ctx.user._id, ctx.project._id) - expect(ctx.res.sendStatus).to.have.been.calledWith(204) + expect(ctx.res.sendStatus).toHaveBeenCalledWith(204) }) it('writes a project audit log', function (ctx) { diff --git a/services/web/test/unit/src/Uploads/ProjectUploadController.test.mjs b/services/web/test/unit/src/Uploads/ProjectUploadController.test.mjs index a5b5ed410e..f21383e776 100644 --- a/services/web/test/unit/src/Uploads/ProjectUploadController.test.mjs +++ b/services/web/test/unit/src/Uploads/ProjectUploadController.test.mjs @@ -7,8 +7,8 @@ */ import { expect, vi } from 'vitest' import sinon from 'sinon' -import MockRequest from '../helpers/MockRequest.js' -import MockResponse from '../helpers/MockResponse.js' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import ArchiveErrors from '../../../../app/src/Features/Uploads/ArchiveErrors.mjs' const modulePath = @@ -17,8 +17,8 @@ const modulePath = describe('ProjectUploadController', function () { beforeEach(async function (ctx) { let Timer - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.user_id = 'user-id-123' ctx.metrics = { Timer: (Timer = (function () { diff --git a/services/web/test/unit/src/User/UserEmailsController.test.mjs b/services/web/test/unit/src/User/UserEmailsController.test.mjs index aea104fbe7..f222ca5173 100644 --- a/services/web/test/unit/src/User/UserEmailsController.test.mjs +++ b/services/web/test/unit/src/User/UserEmailsController.test.mjs @@ -1,7 +1,7 @@ import { vi, assert, expect } from 'vitest' import { setTimeout } from 'node:timers/promises' -import MockRequest from '../helpers/MockRequestVitest.mjs' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import Errors from '../../../../app/src/Features/Errors/Errors.js' const modulePath = '../../../../app/src/Features/User/UserEmailsController.mjs' diff --git a/services/web/test/unit/src/User/UserInfoController.test.mjs b/services/web/test/unit/src/User/UserInfoController.test.mjs index 9c78e90e5e..9a40a979c8 100644 --- a/services/web/test/unit/src/User/UserInfoController.test.mjs +++ b/services/web/test/unit/src/User/UserInfoController.test.mjs @@ -1,7 +1,7 @@ import { vi, expect } from 'vitest' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponse.js' -import MockRequest from '../helpers/MockRequest.js' +import MockResponse from '../helpers/MockResponse.mjs' +import MockRequest from '../helpers/MockRequest.mjs' import mongodb from 'mongodb-legacy' const modulePath = '../../../../app/src/Features/User/UserInfoController.mjs' @@ -45,8 +45,8 @@ describe('UserInfoController', function () { ctx.UserInfoController = (await import(modulePath)).default - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.next = sinon.stub() }) @@ -192,8 +192,8 @@ describe('UserInfoController', function () { }) it('should return the features as JSON', function (ctx) { - expect(ctx.res.json.callCount).to.equal(1) - expect(ctx.res.json.calledWith(ctx.features)).to.equal(true) + expect(ctx.res.json).toHaveBeenCalledTimes(1) + expect(ctx.res.json).toHaveBeenCalledWith(ctx.features) }) }) diff --git a/services/web/test/unit/src/User/UserPagesController.test.mjs b/services/web/test/unit/src/User/UserPagesController.test.mjs index 5a5d301e55..8fca549554 100644 --- a/services/web/test/unit/src/User/UserPagesController.test.mjs +++ b/services/web/test/unit/src/User/UserPagesController.test.mjs @@ -1,8 +1,8 @@ import { expect, vi } from 'vitest' import assert from 'node:assert' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponse.js' -import MockRequest from '../helpers/MockRequest.js' +import MockResponse from '../helpers/MockResponse.mjs' +import MockRequest from '../helpers/MockRequest.mjs' const modulePath = '../../../../app/src/Features/User/UserPagesController' @@ -154,10 +154,10 @@ describe('UserPagesController', function () { })) ctx.UserPagesController = (await import(modulePath)).default - ctx.req = new MockRequest() + ctx.req = new MockRequest(vi) ctx.req.capabilitySet = new Set() ctx.req.session.user = ctx.user - ctx.res = new MockResponse() + ctx.res = new MockResponse(vi) }) describe('registerPage', function () { diff --git a/services/web/test/unit/src/UserMembership/UserMembershipController.test.mjs b/services/web/test/unit/src/UserMembership/UserMembershipController.test.mjs index 5bdd73eef4..a93e666995 100644 --- a/services/web/test/unit/src/UserMembership/UserMembershipController.test.mjs +++ b/services/web/test/unit/src/UserMembership/UserMembershipController.test.mjs @@ -1,6 +1,6 @@ import { expect, vi, describe, it, beforeEach } from 'vitest' -import MockRequest from '../helpers/MockRequestVitest.mjs' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' import EntityConfigs from '../../../../app/src/Features/UserMembership/UserMembershipEntityConfigs.mjs' import Errors from '../../../../app/src/Features/Errors/Errors.js' import UserMembershipErrors from '../../../../app/src/Features/UserMembership/UserMembershipErrors.mjs' diff --git a/services/web/test/unit/src/helpers/MockClient.js b/services/web/test/unit/src/helpers/MockClient.js deleted file mode 100644 index 3142a20765..0000000000 --- a/services/web/test/unit/src/helpers/MockClient.js +++ /dev/null @@ -1,38 +0,0 @@ -/* eslint-disable - no-unused-vars, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -let MockClient -const sinon = require('sinon') - -let idCounter = 0 - -module.exports = MockClient = class MockClient { - constructor() { - this.attributes = {} - this.join = sinon.stub() - this.emit = sinon.stub() - this.disconnect = sinon.stub() - this.id = idCounter++ - } - - set(key, value, callback) { - this.attributes[key] = value - if (callback != null) { - return callback() - } - } - - get(key, callback) { - return callback(null, this.attributes[key]) - } - - disconnect() {} -} diff --git a/services/web/test/unit/src/helpers/MockRequest.js b/services/web/test/unit/src/helpers/MockRequest.js deleted file mode 100644 index 9771fb2358..0000000000 --- a/services/web/test/unit/src/helpers/MockRequest.js +++ /dev/null @@ -1,32 +0,0 @@ -const sinon = require('sinon') - -class MockRequest { - constructor() { - this.session = { destroy() {} } - - this.ip = '42.42.42.42' - this.headers = {} - this.params = {} - this.query = {} - this.body = {} - this._parsedUrl = {} - this.i18n = { - translate(str) { - return str - }, - } - this.route = { path: '' } - this.accepts = () => {} - this.setHeader = () => {} - this.logger = { - addFields: sinon.stub(), - setLevel: sinon.stub(), - } - } - - param(param) { - return this.params[param] - } -} - -module.exports = MockRequest diff --git a/services/web/test/unit/src/helpers/MockRequestVitest.mjs b/services/web/test/unit/src/helpers/MockRequest.mjs similarity index 100% rename from services/web/test/unit/src/helpers/MockRequestVitest.mjs rename to services/web/test/unit/src/helpers/MockRequest.mjs diff --git a/services/web/test/unit/src/helpers/MockResponseVitest.mjs b/services/web/test/unit/src/helpers/MockResponse.mjs similarity index 100% rename from services/web/test/unit/src/helpers/MockResponseVitest.mjs rename to services/web/test/unit/src/helpers/MockResponse.mjs diff --git a/services/web/test/unit/src/infrastructure/HTTPPermissionsPolicy.test.mjs b/services/web/test/unit/src/infrastructure/HTTPPermissionsPolicy.test.mjs index 427d638c34..7ce1567dac 100644 --- a/services/web/test/unit/src/infrastructure/HTTPPermissionsPolicy.test.mjs +++ b/services/web/test/unit/src/infrastructure/HTTPPermissionsPolicy.test.mjs @@ -1,8 +1,8 @@ import { expect, vi } from 'vitest' import sinon from 'sinon' import HttpPermissionsPolicyMiddleware from '../../../../app/src/infrastructure/HttpPermissionsPolicy.mjs' -import MockRequest from '../helpers/MockRequestVitest.mjs' -import MockResponse from '../helpers/MockResponseVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' +import MockResponse from '../helpers/MockResponse.mjs' const modulePath = '../../../../app/src/infrastructure/HttpPermissionsPolicy.mjs' diff --git a/services/web/test/unit/src/infrastructure/RequestContentTypeDetection.test.mjs b/services/web/test/unit/src/infrastructure/RequestContentTypeDetection.test.mjs index 2d0ae588c4..2a6568c6e7 100644 --- a/services/web/test/unit/src/infrastructure/RequestContentTypeDetection.test.mjs +++ b/services/web/test/unit/src/infrastructure/RequestContentTypeDetection.test.mjs @@ -1,6 +1,6 @@ import accepts from 'accepts' import { expect, vi } from 'vitest' -import MockRequest from '../helpers/MockRequestVitest.mjs' +import MockRequest from '../helpers/MockRequest.mjs' const MODULE_PATH = '../../../../app/src/infrastructure/RequestContentTypeDetection.mjs' diff --git a/services/web/test/unit/src/infrastructure/ServeStaticWrapper.test.mjs b/services/web/test/unit/src/infrastructure/ServeStaticWrapper.test.mjs index 619fe74a2b..8e316c86f6 100644 --- a/services/web/test/unit/src/infrastructure/ServeStaticWrapper.test.mjs +++ b/services/web/test/unit/src/infrastructure/ServeStaticWrapper.test.mjs @@ -1,8 +1,8 @@ import { expect, vi } from 'vitest' import Path from 'node:path' import sinon from 'sinon' -import MockResponse from '../helpers/MockResponse.js' -import MockRequest from '../helpers/MockRequest.js' +import MockResponse from '../helpers/MockResponse.mjs' +import MockRequest from '../helpers/MockRequest.mjs' const modulePath = Path.join( import.meta.dirname, @@ -13,8 +13,8 @@ describe('ServeStaticWrapperTests', function () { let error = null beforeEach(async function (ctx) { - ctx.req = new MockRequest() - ctx.res = new MockResponse() + ctx.req = new MockRequest(vi) + ctx.res = new MockResponse(vi) ctx.express = { static: () => (req, res, next) => { if (error) { diff --git a/services/web/vitest.config.js b/services/web/vitest.config.js index 2ad9400deb..b9c12aa63d 100644 --- a/services/web/vitest.config.js +++ b/services/web/vitest.config.js @@ -17,9 +17,10 @@ if (process.env.CI && process.env.MOCHA_ROOT_SUITE_NAME) { } module.exports = defineConfig({ test: { - setupFiles: ['./test/unit/vitest_bootstrap.mjs'], + setupFiles: ['./test/unit/bootstrap.mjs'], globals: true, isolate: false, + passWithNoTests: true, // in case there are no tests from one project or other in a module projects: [ { extends: true,