Merge pull request #29967 from overleaf/ar/web-remove-mocha-unit-tests

[web] remove mocha unit tests

GitOrigin-RevId: eda753af3470dbd1f385cb0bc3f06d78ade8a764
This commit is contained in:
Andrew Rumble
2025-12-02 09:19:32 +00:00
committed by Copybot
parent a3ec5b2797
commit f1e788d9b3
49 changed files with 293 additions and 563 deletions

View File

@@ -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.
},

View File

@@ -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/*), \

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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",

View File

@@ -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

View File

@@ -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()
},
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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',

View File

@@ -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 =

View File

@@ -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))

View File

@@ -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

View File

@@ -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'

View File

@@ -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'

View File

@@ -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 () {

View File

@@ -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,
})
})
})
})

View File

@@ -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']

View File

@@ -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) {

View File

@@ -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

View File

@@ -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,
})
})

View File

@@ -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()
}

View File

@@ -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 }

View File

@@ -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)
})
})

View File

@@ -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() })
)
})
})

View File

@@ -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()

View File

@@ -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

View File

@@ -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 () {

View File

@@ -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()
})

View File

@@ -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')

View File

@@ -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,

View File

@@ -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 => {

View File

@@ -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) {

View File

@@ -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 () {

View File

@@ -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'

View File

@@ -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)
})
})

View File

@@ -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 () {

View File

@@ -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'

View File

@@ -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() {}
}

View File

@@ -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

View File

@@ -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'

View File

@@ -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'

View File

@@ -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) {

View File

@@ -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,