mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2026-06-23 04:10:17 +00:00
fix(backend): type and linting fixes found by oxlint type-aware check
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
committed by
Philip Molares
parent
420925f490
commit
ea9e0bdbd1
@@ -11,7 +11,6 @@
|
||||
"hedgedoc-local/correct-logger-context": "error",
|
||||
"typescript/no-unused-vars": ["warn", { "argsIgnorePattern": "^_+$" }],
|
||||
"typescript/return-await": ["error", "always"],
|
||||
"typescript/naming-convention": "off",
|
||||
"typescript/no-base-to-string": "error"
|
||||
},
|
||||
"overrides": [
|
||||
@@ -24,19 +23,22 @@
|
||||
"typescript/no-unsafe-member-access": "off",
|
||||
"typescript/require-await": "off",
|
||||
"typescript/explicit-function-return-type": "off",
|
||||
"jest/unbound-method": "error",
|
||||
"jest/no-standalone-expect": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["src/database/**"],
|
||||
"rules": {
|
||||
"typescript/naming-convention": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"node": true,
|
||||
"jest": true
|
||||
},
|
||||
"options": {
|
||||
"typeAware": true,
|
||||
"typeCheck": true,
|
||||
"maxWarnings": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
"zod": "3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/types": "30.3.0",
|
||||
"@nestjs/cli": "10.4.9",
|
||||
"@nestjs/schematics": "10.2.3",
|
||||
"@nestjs/testing": "10.4.22",
|
||||
@@ -84,7 +85,6 @@
|
||||
"@types/cli-color": "2.0.6",
|
||||
"@types/cookie": "1.0.0",
|
||||
"@types/cookie-signature": "1.1.2",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/luxon": "3.7.1",
|
||||
"@types/markdown-it": "13.0.8",
|
||||
"@types/node": "24.10.7",
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import { FieldNameAlias, TableAlias } from '@hedgedoc/database';
|
||||
import { Provider } from '@nestjs/common';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
@@ -27,7 +29,6 @@ import { LoggerModule } from '../logger/logger.module';
|
||||
import { AliasService } from './alias.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { NoteEventMap } from '../events';
|
||||
import SpyInstance = jest.SpyInstance;
|
||||
|
||||
describe('AliasService', () => {
|
||||
const alias1 = 'testAlias1';
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import { FieldNameApiToken, TableApiToken } from '@hedgedoc/database';
|
||||
import { Provider } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
@@ -47,7 +47,7 @@ export class AuthController {
|
||||
if (request.session.loginAuthProviderType === AuthProviderType.OIDC) {
|
||||
logoutUrl = this.oidcService.getLogoutUrl(request);
|
||||
}
|
||||
const destroySessionPromise = promisify(request.session.destroy).bind(request.session);
|
||||
const destroySessionPromise = promisify(request.session.destroy.bind(request.session));
|
||||
try {
|
||||
await destroySessionPromise();
|
||||
return LogoutResponseDto.create({
|
||||
|
||||
@@ -45,7 +45,7 @@ export class CsrfGuard implements CanActivate {
|
||||
throw new ForbiddenException('CSRF token required');
|
||||
}
|
||||
|
||||
const csrfProtection = request.server.csrfProtection;
|
||||
const csrfProtection = request.server.csrfProtection.bind(request.server);
|
||||
if (!csrfProtection) {
|
||||
throw new ForbiddenException('CSRF protection failed to load');
|
||||
}
|
||||
|
||||
@@ -71,8 +71,8 @@ export class MeController {
|
||||
this.logger.debug(`Deleted all media uploads for user with id ${userId}`);
|
||||
await this.userService.deleteUser(userId);
|
||||
this.logger.debug(`Deleted user with id ${userId}`);
|
||||
const destroySessionPromise = promisify(request.session.destroy).bind(request.session);
|
||||
destroySessionPromise().catch((error) => {
|
||||
const destroySessionPromise = promisify(request.session.destroy.bind(request.session));
|
||||
destroySessionPromise().catch((error: Error) => {
|
||||
this.logger.error('Error while destroying session:' + String(error), undefined, 'deleteUser');
|
||||
throw new InternalServerErrorException('Error trying to destroy session of deleted user');
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach } from '@jest/globals';
|
||||
import { Note } from '@hedgedoc/database';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import { Note } from '@hedgedoc/database';
|
||||
import { CallHandler, ExecutionContext } from '@nestjs/common';
|
||||
import { HttpArgumentsHost } from '@nestjs/common/interfaces/features/arguments-host.interface';
|
||||
@@ -22,7 +24,7 @@ describe('get note interceptor', () => {
|
||||
});
|
||||
|
||||
let notesService: NoteService;
|
||||
let noteFetchSpy: jest.SpyInstance;
|
||||
let noteFetchSpy: SpyInstance<typeof notesService.getNoteIdByAlias>;
|
||||
|
||||
beforeEach(() => {
|
||||
notesService = Mock.of<NoteService>({
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { AuthProviderType } from '@hedgedoc/commons';
|
||||
import { FieldNameNote, FieldNameUser, Note, User } from '@hedgedoc/database';
|
||||
import { FastifyRequest } from 'fastify';
|
||||
import { SessionState } from 'src/sessions/session-state';
|
||||
import { SessionState } from '../../sessions/session-state';
|
||||
|
||||
export type CompleteRequest = FastifyRequest & {
|
||||
userId?: User[FieldNameUser.id];
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import { AuthProviderType } from '@hedgedoc/commons';
|
||||
import { FieldNameIdentity, Identity } from '@hedgedoc/database';
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
@@ -71,8 +72,8 @@ describe('OidcService', () => {
|
||||
{
|
||||
provide: SessionService,
|
||||
useValue: Mock.of<SessionService>({
|
||||
terminateSessionByOidcSid: jest.fn(),
|
||||
terminateAllSessionsOfUser: jest.fn(),
|
||||
terminateSessionByOidcSid: jest.fn<typeof sessionService.terminateSessionByOidcSid>(),
|
||||
terminateAllSessionsOfUser: jest.fn<typeof sessionService.terminateAllSessionsOfUser>(),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -311,7 +311,9 @@ export class OidcService {
|
||||
field: string,
|
||||
defaultValue: T,
|
||||
): string | T {
|
||||
return response[field] ? String(response[field]) : defaultValue;
|
||||
return field in response && response[field] !== undefined && response[field] !== null
|
||||
? (response[field] as string | T)
|
||||
: defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
import appConfig from './app.config';
|
||||
@@ -183,7 +185,7 @@ describe('appConfig', () => {
|
||||
});
|
||||
|
||||
describe('throws error', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
import * as utilsModule from './utils';
|
||||
@@ -14,9 +16,7 @@ import { TEST_CERT_FILE_CONTENT, TEST_CERT_FILE_PATH } from './shared-test-data'
|
||||
describe('authConfig', () => {
|
||||
const secret = 'this-is-a-long-but-insecure-secret';
|
||||
const neededAuthConfig = {
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
HD_AUTH_SESSION_SECRET: secret,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
};
|
||||
|
||||
describe('local', () => {
|
||||
@@ -24,20 +24,16 @@ describe('authConfig', () => {
|
||||
const enableRegister = true;
|
||||
const minimalPasswordStrength = 1;
|
||||
const completeLocalConfig = {
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
HD_AUTH_LOCAL_ENABLE_LOGIN: String(enableLogin),
|
||||
HD_AUTH_LOCAL_ENABLE_REGISTER: String(enableRegister),
|
||||
HD_AUTH_LOCAL_MINIMAL_PASSWORD_STRENGTH: String(minimalPasswordStrength),
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
};
|
||||
describe('is correctly parsed', () => {
|
||||
it('when given correct and complete environment variables', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLocalConfig,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -53,11 +49,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_LOCAL_ENABLE_LOGIN is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLocalConfig,
|
||||
HD_AUTH_LOCAL_ENABLE_LOGIN: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -73,11 +67,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_LOCAL_ENABLE_REGISTER is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLocalConfig,
|
||||
HD_AUTH_LOCAL_ENABLE_REGISTER: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -93,11 +85,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_LOCAL_MINIMAL_PASSWORD_STRENGTH is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLocalConfig,
|
||||
HD_AUTH_LOCAL_MINIMAL_PASSWORD_STRENGTH: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -112,7 +102,7 @@ describe('authConfig', () => {
|
||||
});
|
||||
|
||||
describe('fails to be parsed', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
@@ -134,11 +124,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_LOCAL_MINIMAL_PASSWORD_STRENGTH is 5', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLocalConfig,
|
||||
HD_AUTH_LOCAL_MINIMAL_PASSWORD_STRENGTH: '5',
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -154,11 +142,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_LOCAL_MINIMAL_PASSWORD_STRENGTH is -1', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLocalConfig,
|
||||
HD_AUTH_LOCAL_MINIMAL_PASSWORD_STRENGTH: '-1',
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -180,9 +166,7 @@ describe('authConfig', () => {
|
||||
const longSecret = 'a'.repeat(40);
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
HD_AUTH_SESSION_SECRET: longSecret,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -197,9 +181,7 @@ describe('authConfig', () => {
|
||||
const exactSecret = 'a'.repeat(32);
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
HD_AUTH_SESSION_SECRET: exactSecret,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -212,7 +194,7 @@ describe('authConfig', () => {
|
||||
});
|
||||
|
||||
describe('fails to be parsed', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
@@ -248,9 +230,7 @@ describe('authConfig', () => {
|
||||
const shortSecret = 'a'.repeat(31);
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
HD_AUTH_SESSION_SECRET: shortSecret,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -290,7 +270,6 @@ describe('authConfig', () => {
|
||||
const tlsCa = [TEST_CERT_FILE_PATH];
|
||||
const tlsCaContent = [TEST_CERT_FILE_CONTENT];
|
||||
const completeLdapConfig = {
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
HD_AUTH_LDAP_SERVERS: ldapNames.join(','),
|
||||
HD_AUTH_LDAP_FUTURAMA_PROVIDER_NAME: providerName,
|
||||
HD_AUTH_LDAP_FUTURAMA_URL: url,
|
||||
@@ -304,16 +283,13 @@ describe('authConfig', () => {
|
||||
HD_AUTH_LDAP_FUTURAMA_BIND_DN: bindDn,
|
||||
HD_AUTH_LDAP_FUTURAMA_BIND_CREDENTIALS: bindCredentials,
|
||||
HD_AUTH_LDAP_FUTURAMA_TLS_CERT_PATHS: tlsCa.join(','),
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
};
|
||||
describe('is correctly parsed', () => {
|
||||
it('when given correct and complete environment variables', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -342,11 +318,9 @@ describe('authConfig', () => {
|
||||
it('when no HD_AUTH_LDAP_FUTURAMA_PROVIDER_NAME is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_PROVIDER_NAME: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -374,11 +348,9 @@ describe('authConfig', () => {
|
||||
it('when no HD_AUTH_LDAP_FUTURAMA_SEARCH_FILTER is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_SEARCH_FILTER: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -406,11 +378,9 @@ describe('authConfig', () => {
|
||||
it('when no HD_AUTH_LDAP_FUTURAMA_USER_ID_FIELD is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_USER_ID_FIELD: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -438,11 +408,9 @@ describe('authConfig', () => {
|
||||
it('when no HD_AUTH_LDAP_FUTURAMA_DISPLAY_NAME_FIELD is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_DISPLAY_NAME_FIELD: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -470,11 +438,9 @@ describe('authConfig', () => {
|
||||
it('when no HD_AUTH_LDAP_FUTURAMA_PROFILE_PICTURE_FIELD is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_PROFILE_PICTURE_FIELD: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -502,11 +468,9 @@ describe('authConfig', () => {
|
||||
it('when no HD_AUTH_LDAP_FUTURAMA_BIND_DN is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_BIND_DN: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -534,11 +498,9 @@ describe('authConfig', () => {
|
||||
it('when no HD_AUTH_LDAP_FUTURAMA_BIND_CREDENTIALS is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_BIND_CREDENTIALS: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -566,11 +528,9 @@ describe('authConfig', () => {
|
||||
it('when no HD_AUTH_LDAP_FUTURAMA_TLS_CERT_PATHS is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_TLS_CERT_PATHS: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -596,12 +556,12 @@ describe('authConfig', () => {
|
||||
});
|
||||
});
|
||||
describe('throws error', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
beforeEach(() => {
|
||||
spyConsoleError = jest.spyOn(console, 'error').mockImplementation();
|
||||
spyConsoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
spyProcessExit = jest.fn();
|
||||
originalProcess = global.process;
|
||||
global.process = {
|
||||
@@ -618,11 +578,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_LDAP_FUTURAMA_URL is wrong', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_URL: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -636,11 +594,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_LDAP_FUTURAMA_SEARCH_BASE is wrong', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_SEARCH_BASE: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -656,11 +612,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_LDAP_FUTURAMA_TLS_CERT_PATHS is wrong', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeLdapConfig,
|
||||
HD_AUTH_LDAP_FUTURAMA_TLS_CERT_PATHS: 'not-a-file.pem',
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -700,7 +654,6 @@ describe('authConfig', () => {
|
||||
const defaultEmailField = 'email';
|
||||
const enableRegistration = 'false';
|
||||
const completeOidcConfig = {
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
HD_AUTH_OIDC_SERVERS: oidcNames.join(','),
|
||||
HD_AUTH_OIDC_GITLAB_PROVIDER_NAME: providerName,
|
||||
HD_AUTH_OIDC_GITLAB_ISSUER: issuer,
|
||||
@@ -718,16 +671,13 @@ describe('authConfig', () => {
|
||||
HD_AUTH_OIDC_GITLAB_PROFILE_PICTURE_FIELD: profilePictureField,
|
||||
HD_AUTH_OIDC_GITLAB_EMAIL_FIELD: emailField,
|
||||
HD_AUTH_OIDC_GITLAB_ENABLE_REGISTRATION: enableRegistration,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
};
|
||||
describe('is correctly parsed', () => {
|
||||
it('when given correct and complete environment variables', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -758,11 +708,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_THEME is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_THEME: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -793,11 +741,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_AUTHORIZE_URL is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_AUTHORIZE_URL: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -828,11 +774,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_TOKEN_URL is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_TOKEN_URL: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -863,11 +807,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_USERINFO_URL is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_USERINFO_URL: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -898,11 +840,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_END_SESSION_URL is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_END_SESSION_URL: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -933,11 +873,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_SCOPE is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_SCOPE: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -968,11 +906,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_USER_ID_FIELD is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_USER_ID_FIELD: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -1003,11 +939,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_DISPLAY_NAME_FIELD is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_DISPLAY_NAME_FIELD: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -1038,11 +972,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_PROFILE_PICTURE_FIELD is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_PROFILE_PICTURE_FIELD: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -1073,11 +1005,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_EMAIL_FIELD is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_EMAIL_FIELD: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -1108,11 +1038,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_ENABLE_REGISTRATION is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_ENABLE_REGISTRATION: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -1142,12 +1070,12 @@ describe('authConfig', () => {
|
||||
});
|
||||
});
|
||||
describe('throws error', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
beforeEach(() => {
|
||||
spyConsoleError = jest.spyOn(console, 'error').mockImplementation();
|
||||
spyConsoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
spyProcessExit = jest.fn();
|
||||
originalProcess = global.process;
|
||||
global.process = {
|
||||
@@ -1164,11 +1092,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_ISSUER is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_ISSUER: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -1182,11 +1108,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_CLIENT_ID is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_CLIENT_ID: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -1202,11 +1126,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_CLIENT_SECRET is not set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_CLIENT_SECRET: undefined,
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
@@ -1222,11 +1144,9 @@ describe('authConfig', () => {
|
||||
it('when HD_AUTH_OIDC_GITLAB_THEME is set to a wrong value', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* oxlint-disable @typescript-eslint/naming-convention */
|
||||
...neededAuthConfig,
|
||||
...completeOidcConfig,
|
||||
HD_AUTH_OIDC_GITLAB_THEME: 'something else',
|
||||
/* oxlint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
import customizationConfig from './customization.config';
|
||||
@@ -43,7 +45,7 @@ describe('customizationConfig', () => {
|
||||
});
|
||||
|
||||
describe('throws error', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import * as utilsModule from './utils';
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
@@ -249,7 +251,7 @@ describe('databaseConfig', () => {
|
||||
});
|
||||
|
||||
describe('throws error', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
import externalServicesConfig from './external-services.config';
|
||||
@@ -28,7 +30,7 @@ describe('externalServices', () => {
|
||||
});
|
||||
|
||||
describe('throws error', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import { MediaBackendType } from '@hedgedoc/commons';
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
@@ -181,7 +183,7 @@ describe('mediaConfig', () => {
|
||||
});
|
||||
|
||||
describe('throws error', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import { PermissionLevel, PermissionLevelNames } from '@hedgedoc/commons';
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
@@ -301,7 +303,7 @@ describe('noteConfig', () => {
|
||||
});
|
||||
|
||||
describe('throws error', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
import securityConfig from './security.config';
|
||||
@@ -131,7 +133,7 @@ describe('securityConfig: rate limiting', () => {
|
||||
});
|
||||
|
||||
describe('throws error', () => {
|
||||
let spyConsoleError: jest.SpyInstance;
|
||||
let spyConsoleError: SpyInstance;
|
||||
let spyProcessExit: jest.Mock;
|
||||
let originalProcess: typeof process;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, jest } from '@jest/globals';
|
||||
import { Loglevel } from './loglevel.enum';
|
||||
import {
|
||||
ensureNoDuplicatesExist,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import z from 'zod';
|
||||
|
||||
import { extractDescriptionFromZodIssue } from './zod-error-message';
|
||||
|
||||
@@ -11,7 +11,7 @@ export function extendKnexQueryBuilder() {
|
||||
QueryBuilder.extend('whereEqualLowercase', function (field: string, value: string) {
|
||||
return this.whereRaw('LOWER(??) = ?', [field, value.toLowerCase()]);
|
||||
});
|
||||
} catch (e) {
|
||||
} catch {
|
||||
console.warn('Could not extend KnexQueryBuilder with whereEqualLowercase');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { Tracker } from 'knex-mock-client';
|
||||
import { expect } from '@jest/globals';
|
||||
|
||||
export const IS_FIRST = 1;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import { SortMode } from '@hedgedoc/commons';
|
||||
import { OptionalNoteType, OptionalSortMode } from '@hedgedoc/commons';
|
||||
import {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import { AuthProviderType, PermissionLevel, PermissionLevelNames } from '@hedgedoc/commons';
|
||||
import { ConfigModule, registerAs } from '@nestjs/config';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
@@ -73,12 +74,16 @@ describe('FrontendConfigService', () => {
|
||||
enableRegistration: true,
|
||||
},
|
||||
];
|
||||
for (const authConfigConfigured of [ldap, oidc]) {
|
||||
for (const [providerType, authConfigConfigured] of [
|
||||
['ldap', ldap],
|
||||
['oidc', oidc],
|
||||
] as const) {
|
||||
it(`works with ${JSON.stringify(authConfigConfigured)}`, async () => {
|
||||
const appConfig: AppConfig = {
|
||||
baseUrl: domain,
|
||||
rendererBaseUrl: 'https://renderer.example.org',
|
||||
backendPort: 3000,
|
||||
backendBindIp: '127.0.0.1',
|
||||
log: {
|
||||
level: Loglevel.ERROR,
|
||||
showTimestamp: false,
|
||||
@@ -86,9 +91,9 @@ describe('FrontendConfigService', () => {
|
||||
};
|
||||
const authConfig: AuthConfig = {
|
||||
...emptyAuthConfig,
|
||||
...authConfigConfigured,
|
||||
[providerType]: authConfigConfigured,
|
||||
};
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const testingModule: TestingModule = await Test.createTestingModule({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
@@ -128,7 +133,7 @@ describe('FrontendConfigService', () => {
|
||||
],
|
||||
providers: [FrontendConfigService],
|
||||
}).compile();
|
||||
const service = module.get(FrontendConfigService);
|
||||
const service = testingModule.get(FrontendConfigService);
|
||||
const config = await service.getFrontendConfig();
|
||||
if (authConfig.local.enableLogin) {
|
||||
expect(config.authProviders).toContainEqual({
|
||||
@@ -179,6 +184,7 @@ describe('FrontendConfigService', () => {
|
||||
baseUrl: domain,
|
||||
rendererBaseUrl: 'https://renderer.example.org',
|
||||
backendPort: 3000,
|
||||
backendBindIp: '127.0.0.1',
|
||||
log: {
|
||||
level: Loglevel.ERROR,
|
||||
showTimestamp: false,
|
||||
@@ -214,6 +220,7 @@ describe('FrontendConfigService', () => {
|
||||
default: {
|
||||
everyone: PermissionLevel.READ,
|
||||
loggedIn: PermissionLevel.WRITE,
|
||||
publiclyVisible: false,
|
||||
},
|
||||
maxGuestLevel: PermissionLevel.FULL,
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import {
|
||||
FieldNameGroup,
|
||||
FieldNameGroupUser,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import { ConsoleLoggerService } from './console-logger.service';
|
||||
|
||||
describe('sanitize', () => {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import { MediaBackendType } from '@hedgedoc/commons';
|
||||
import * as MinioModule from 'minio';
|
||||
import { Client, ClientOptions } from 'minio';
|
||||
@@ -26,7 +28,7 @@ describe('s3 backend', () => {
|
||||
});
|
||||
|
||||
let mockedClient: Client;
|
||||
let clientConstructorSpy: jest.SpyInstance<Client, [options: ClientOptions]>;
|
||||
let clientConstructorSpy: SpyInstance<(params: ClientOptions) => Client>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockedClient = Mock.of<Client>({
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, afterEach, jest } from '@jest/globals';
|
||||
import {
|
||||
FieldNameAlias,
|
||||
FieldNameMediaUpload,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { Knex } from 'knex';
|
||||
import { getConnectionToken } from 'nest-knexjs';
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import { PermissionLevel } from '@hedgedoc/commons';
|
||||
import {
|
||||
FieldNameAlias,
|
||||
@@ -11,19 +13,21 @@ import {
|
||||
NoteType,
|
||||
TableAlias,
|
||||
TableNote,
|
||||
type Revision,
|
||||
} from '@hedgedoc/database';
|
||||
import { Provider } from '@nestjs/common';
|
||||
import type { Provider } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import type { TestingModule } from '@nestjs/testing';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import type { Tracker } from 'knex-mock-client';
|
||||
import { DateTime } from 'luxon';
|
||||
import type { DateTime } from 'luxon';
|
||||
|
||||
import { AliasService } from '../alias/alias.service';
|
||||
import appConfigMock from '../config/mock/app.config.mock';
|
||||
import databaseConfigMock from '../config/mock/database.config.mock';
|
||||
import { createDefaultMockNoteConfig, registerNoteConfig } from '../config/mock/note.config.mock';
|
||||
import { NoteConfig } from '../config/note.config';
|
||||
import type { NoteConfig } from '../config/note.config';
|
||||
import { expectBindings } from '../database/mock/expect-bindings';
|
||||
import { mockDelete, mockInsert, mockSelect } from '../database/mock/mock-queries';
|
||||
import { mockKnexDb } from '../database/mock/provider';
|
||||
@@ -34,15 +38,18 @@ import {
|
||||
MaximumDocumentLengthExceededError,
|
||||
NotInDBError,
|
||||
} from '../errors/errors';
|
||||
import { NoteEvent, NoteEventMap } from '../events';
|
||||
import type { NoteEventMap } from '../events';
|
||||
import { NoteEvent } from '../events';
|
||||
import { GroupsService } from '../groups/groups.service';
|
||||
import { LoggerModule } from '../logger/logger.module';
|
||||
import { PermissionService } from '../permissions/permission.service';
|
||||
import { RealtimeNoteStore } from '../realtime/realtime-note/realtime-note-store';
|
||||
import type { RealtimeNote } from '../realtime/realtime-note/realtime-note';
|
||||
import { RevisionsService } from '../revisions/revisions.service';
|
||||
import { UsersService } from '../users/users.service';
|
||||
import { dateTimeToDB, getCurrentDateTime } from '../utils/datetime';
|
||||
import { NoteService } from './note.service';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
describe('NoteService', () => {
|
||||
let service: NoteService;
|
||||
@@ -84,7 +91,7 @@ describe('NoteService', () => {
|
||||
beforeAll(async () => {
|
||||
[tracker, knexProvider] = mockKnexDb();
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const testingModule: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
NoteService,
|
||||
knexProvider,
|
||||
@@ -105,13 +112,13 @@ describe('NoteService', () => {
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<NoteService>(NoteService);
|
||||
aliasService = module.get<AliasService>(AliasService);
|
||||
eventEmitter = module.get<EventEmitter2<NoteEventMap>>(EventEmitter2<NoteEventMap>);
|
||||
revisionService = module.get<RevisionsService>(RevisionsService);
|
||||
realtimeNoteStore = module.get<RealtimeNoteStore>(RealtimeNoteStore);
|
||||
groupsService = module.get<GroupsService>(GroupsService);
|
||||
permissionService = module.get<PermissionService>(PermissionService);
|
||||
service = testingModule.get<NoteService>(NoteService);
|
||||
aliasService = testingModule.get<AliasService>(AliasService);
|
||||
eventEmitter = testingModule.get<EventEmitter2<NoteEventMap>>(EventEmitter2<NoteEventMap>);
|
||||
revisionService = testingModule.get<RevisionsService>(RevisionsService);
|
||||
realtimeNoteStore = testingModule.get<RealtimeNoteStore>(RealtimeNoteStore);
|
||||
groupsService = testingModule.get<GroupsService>(GroupsService);
|
||||
permissionService = testingModule.get<PermissionService>(PermissionService);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -202,12 +209,12 @@ describe('NoteService', () => {
|
||||
],
|
||||
])('inserts a new note', (everyoneLevel, loggedInLevel, inputAlias, outputAlias, descr) => {
|
||||
let result: number;
|
||||
let mockEnsureAliasIsAvailable: jest.SpyInstance;
|
||||
let mockGenerateRandomAlias: jest.SpyInstance;
|
||||
let mockAddAlias: jest.SpyInstance;
|
||||
let mockCreateRevision: jest.SpyInstance;
|
||||
let mockGetGroupIdByName: jest.SpyInstance;
|
||||
let mockSetGroupPermission: jest.SpyInstance;
|
||||
let mockEnsureAliasIsAvailable: SpyInstance<typeof aliasService.ensureAliasIsAvailable>;
|
||||
let mockGenerateRandomAlias: SpyInstance<typeof aliasService.generateRandomAlias>;
|
||||
let mockAddAlias: SpyInstance<typeof aliasService.addAlias>;
|
||||
let mockCreateRevision: SpyInstance<typeof revisionService.createRevision>;
|
||||
let mockGetGroupIdByName: SpyInstance<typeof groupsService.getGroupIdByName>;
|
||||
let mockSetGroupPermission: SpyInstance<typeof permissionService.setGroupPermission>;
|
||||
beforeEach(() => {
|
||||
mockEnsureAliasIsAvailable = jest
|
||||
.spyOn(aliasService, 'ensureAliasIsAvailable')
|
||||
@@ -235,23 +242,6 @@ describe('NoteService', () => {
|
||||
[{ [FieldNameNote.id]: mockNoteId }],
|
||||
);
|
||||
});
|
||||
afterEach(() => {
|
||||
expect(mockCreateRevision).toHaveBeenCalledWith(
|
||||
mockNoteId,
|
||||
mockNoteContent,
|
||||
true,
|
||||
expect.anything(),
|
||||
);
|
||||
expect(result).toBe(mockNoteId);
|
||||
expectBindings(tracker, 'insert', [
|
||||
[
|
||||
dateTimeToDB(now),
|
||||
mockOwnerUserId,
|
||||
noteMockConfig.permissions.default.publiclyVisible,
|
||||
2,
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it(`with settings: ${descr}`, async () => {
|
||||
noteMockConfig.permissions.default.everyone = everyoneLevel as
|
||||
@@ -297,42 +287,62 @@ describe('NoteService', () => {
|
||||
expect.anything(),
|
||||
);
|
||||
}
|
||||
expect(mockCreateRevision).toHaveBeenCalledWith(
|
||||
mockNoteId,
|
||||
mockNoteContent,
|
||||
true,
|
||||
expect.anything(),
|
||||
);
|
||||
expect(result).toBe(mockNoteId);
|
||||
expectBindings(tracker, 'insert', [
|
||||
[
|
||||
dateTimeToDB(now),
|
||||
mockOwnerUserId,
|
||||
noteMockConfig.permissions.default.publiclyVisible,
|
||||
2,
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
/* oxlint-enable jest/no-conditional-expect */
|
||||
|
||||
describe('getNoteContent', () => {
|
||||
let realtimeNoteStoreSpy: jest.SpyInstance;
|
||||
let revsisionServiceSpy: jest.SpyInstance;
|
||||
let realtimeNoteStoreSpy: SpyInstance<typeof realtimeNoteStore.find>;
|
||||
let revsisionServiceSpy: SpyInstance<typeof revisionService.getLatestRevision>;
|
||||
|
||||
beforeEach(() => {
|
||||
realtimeNoteStoreSpy = jest.spyOn(realtimeNoteStore, 'find');
|
||||
revsisionServiceSpy = jest.spyOn(revisionService, 'getLatestRevision');
|
||||
});
|
||||
it('returns content from RealtimeNoteStore if note is active', async () => {
|
||||
realtimeNoteStoreSpy.mockReturnValue({
|
||||
getRealtimeDoc: () => ({
|
||||
getCurrentContent: () => mockNoteContent,
|
||||
realtimeNoteStoreSpy.mockReturnValue(
|
||||
Mock.of<RealtimeNote>({
|
||||
getRealtimeDoc: () => ({
|
||||
getCurrentContent: () => mockNoteContent,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
);
|
||||
const result = await service.getNoteContent(mockNoteId);
|
||||
expect(result).toEqual(mockNoteContent);
|
||||
});
|
||||
|
||||
it('returns latest revision otherwise', async () => {
|
||||
realtimeNoteStoreSpy.mockReturnValue(undefined);
|
||||
revsisionServiceSpy.mockReturnValue({
|
||||
content: mockNoteContent,
|
||||
});
|
||||
revsisionServiceSpy.mockReturnValue(
|
||||
Promise.resolve(
|
||||
Mock.of<Revision>({
|
||||
content: mockNoteContent,
|
||||
}),
|
||||
),
|
||||
);
|
||||
const result = await service.getNoteContent(mockNoteId);
|
||||
expect(result).toEqual(mockNoteContent);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNoteIdByAlias', () => {
|
||||
let aliasServiceSpy: jest.SpyInstance;
|
||||
// oxlint-disable-next-line func-style
|
||||
let aliasServiceSpy: SpyInstance<typeof aliasService.isAliasForbidden>;
|
||||
const buildMockSelect = (returnValues: unknown) => {
|
||||
mockSelect(
|
||||
tracker,
|
||||
@@ -380,46 +390,45 @@ describe('NoteService', () => {
|
||||
});
|
||||
|
||||
describe('deleteNote', () => {
|
||||
let eventEmitterSpy: jest.SpyInstance;
|
||||
let eventEmitterSpy: SpyInstance<typeof eventEmitter.emit>;
|
||||
beforeEach(() => {
|
||||
eventEmitterSpy = jest.spyOn(eventEmitter, 'emit').mockReturnValue(true);
|
||||
});
|
||||
afterEach(() => {
|
||||
expect(eventEmitterSpy).toHaveBeenCalledWith(NoteEvent.DELETION, mockNoteId);
|
||||
});
|
||||
|
||||
it('throws NotInDBError if note not found', async () => {
|
||||
mockDelete(tracker, TableNote, [FieldNameNote.id], 0);
|
||||
await expect(service.deleteNote(mockNoteId)).rejects.toThrow(NotInDBError);
|
||||
expectBindings(tracker, 'delete', [[mockNoteId]]);
|
||||
expect(eventEmitterSpy).toHaveBeenCalledWith(NoteEvent.DELETION, mockNoteId);
|
||||
});
|
||||
|
||||
it('deletes a note by id', async () => {
|
||||
mockDelete(tracker, TableNote, [FieldNameNote.id], 1);
|
||||
await service.deleteNote(mockNoteId);
|
||||
expectBindings(tracker, 'delete', [[mockNoteId]]);
|
||||
expect(eventEmitterSpy).toHaveBeenCalledWith(NoteEvent.DELETION, mockNoteId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateNote', () => {
|
||||
let eventEmitterSpy: jest.SpyInstance;
|
||||
let revisionServiceSpy: jest.SpyInstance;
|
||||
let eventEmitterSpy: SpyInstance<typeof eventEmitter.emit>;
|
||||
let revisionServiceSpy: SpyInstance<typeof revisionService.createRevision>;
|
||||
beforeEach(() => {
|
||||
eventEmitterSpy = jest.spyOn(eventEmitter, 'emit').mockReturnValue(true);
|
||||
revisionServiceSpy = jest
|
||||
.spyOn(revisionService, 'createRevision')
|
||||
.mockImplementation(async () => {});
|
||||
});
|
||||
afterEach(() => {
|
||||
expect(eventEmitterSpy).toHaveBeenCalledWith(NoteEvent.CLOSE_REALTIME, mockNoteId);
|
||||
});
|
||||
|
||||
it('creates a new revision', async () => {
|
||||
await service.updateNote(mockNoteId, mockNoteContent);
|
||||
expect(revisionServiceSpy).toHaveBeenCalledWith(mockNoteId, mockNoteContent);
|
||||
expect(eventEmitterSpy).toHaveBeenCalledWith(NoteEvent.CLOSE_REALTIME, mockNoteId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toNoteMetadataDto', () => {
|
||||
let spyAliasService: jest.SpyInstance;
|
||||
let spyAliasService: SpyInstance<typeof aliasService.getAllAliases>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
@@ -431,20 +440,22 @@ describe('NoteService', () => {
|
||||
});
|
||||
|
||||
it('throws NotInDBError if the note does not have a primary alias', async () => {
|
||||
spyAliasService.mockReturnValue([]);
|
||||
spyAliasService.mockReturnValue(Promise.resolve([]));
|
||||
await expect(service.toNoteMetadataDto(mockNoteId)).rejects.toThrow(NotInDBError);
|
||||
});
|
||||
it('throws NotInDBError if the note does not exist', async () => {
|
||||
spyAliasService.mockReturnValue([
|
||||
{
|
||||
[FieldNameAlias.alias]: mockAliasRandom,
|
||||
[FieldNameAlias.isPrimary]: true,
|
||||
},
|
||||
{
|
||||
[FieldNameAlias.alias]: mockAliasCustom,
|
||||
[FieldNameAlias.isPrimary]: false,
|
||||
},
|
||||
]);
|
||||
spyAliasService.mockReturnValue(
|
||||
Promise.resolve([
|
||||
{
|
||||
[FieldNameAlias.alias]: mockAliasRandom,
|
||||
[FieldNameAlias.isPrimary]: true,
|
||||
},
|
||||
{
|
||||
[FieldNameAlias.alias]: mockAliasCustom,
|
||||
[FieldNameAlias.isPrimary]: false,
|
||||
},
|
||||
]),
|
||||
);
|
||||
mockSelect(
|
||||
tracker,
|
||||
[FieldNameNote.createdAt, FieldNameNote.version],
|
||||
@@ -456,16 +467,18 @@ describe('NoteService', () => {
|
||||
expectBindings(tracker, 'select', [[mockNoteId]], true);
|
||||
});
|
||||
it('returns correct NoteMetadataDto', async () => {
|
||||
spyAliasService.mockReturnValue([
|
||||
{
|
||||
[FieldNameAlias.alias]: mockAliasRandom,
|
||||
[FieldNameAlias.isPrimary]: true,
|
||||
},
|
||||
{
|
||||
[FieldNameAlias.alias]: mockAliasCustom,
|
||||
[FieldNameAlias.isPrimary]: false,
|
||||
},
|
||||
]);
|
||||
spyAliasService.mockReturnValue(
|
||||
Promise.resolve([
|
||||
{
|
||||
[FieldNameAlias.alias]: mockAliasRandom,
|
||||
[FieldNameAlias.isPrimary]: true,
|
||||
},
|
||||
{
|
||||
[FieldNameAlias.alias]: mockAliasCustom,
|
||||
[FieldNameAlias.isPrimary]: false,
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
jest.spyOn(revisionService, 'getLatestRevision').mockResolvedValue({
|
||||
[FieldNameRevision.content]: mockNoteContent,
|
||||
|
||||
@@ -306,7 +306,9 @@ export class NoteService {
|
||||
transaction,
|
||||
);
|
||||
this.logger.debug(`Retrieved ${updateUsers.users.length} users`, 'innerToNoteMetadataDto');
|
||||
updateUsers.users.sort();
|
||||
updateUsers.users.sort(
|
||||
(a, b) => dbToDateTime(a.createdAt).toMillis() - dbToDateTime(b.createdAt).toMillis(),
|
||||
);
|
||||
|
||||
const updatedAt = dateTimeToISOString(
|
||||
dbToDateTime(latestRevision[FieldNameRevision.createdAt]),
|
||||
@@ -326,6 +328,8 @@ export class NoteService {
|
||||
this.logger.debug(`updatedAt ${updatedAt}`, 'innerToNoteMetadataDto');
|
||||
|
||||
return NoteMetadataDto.create({
|
||||
// We're expanding a DTO here which is technically a class - in this case this is fine.
|
||||
// oxlint-disable-next-line typescript/no-misused-spread
|
||||
...noteAliases,
|
||||
title: latestRevision.title,
|
||||
description: latestRevision.description,
|
||||
|
||||
@@ -3,21 +3,23 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import { PermissionLevel, PermissionLevelNames } from '@hedgedoc/commons';
|
||||
import { ExecutionContext } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import type { ExecutionContext } from '@nestjs/common';
|
||||
import type { Reflector } from '@nestjs/core';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
import * as ExtractNoteIdOrAliasModule from '../api/utils/extract-note-id-from-request';
|
||||
import { CompleteRequest } from '../api/utils/request.type';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { PermissionService } from './permission.service';
|
||||
import type { CompleteRequest } from '../api/utils/request.type';
|
||||
import type { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import type { PermissionService } from './permission.service';
|
||||
import { PermissionsGuard } from './permissions.guard';
|
||||
import { PERMISSION_METADATA_KEY } from './require-permission.decorator';
|
||||
import type { extractNoteIdFromRequest } from '../api/utils/extract-note-id-from-request';
|
||||
|
||||
jest.mock('../api/utils/extract-note-id-from-request');
|
||||
|
||||
// oxlint-disable-next-line func-style
|
||||
const buildContext = (userId: number | undefined, handler: () => void): ExecutionContext => {
|
||||
const request = Mock.of<CompleteRequest>({
|
||||
userId: userId,
|
||||
@@ -38,7 +40,7 @@ describe('PermissionsGuard', () => {
|
||||
let handler: () => void;
|
||||
let permissionsService: PermissionService;
|
||||
let permissionGuard: PermissionsGuard;
|
||||
let spyOnExtractNoteId: jest.SpyInstance;
|
||||
let spyOnExtractNoteId: SpyInstance<typeof extractNoteIdFromRequest>;
|
||||
|
||||
const mockUserId = 42;
|
||||
const mockNoteId = 23;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import { PermissionLevel } from '@hedgedoc/commons';
|
||||
import {
|
||||
FieldNameGroup,
|
||||
@@ -11,6 +13,7 @@ import {
|
||||
FieldNameNoteGroupPermission,
|
||||
FieldNameNoteUserPermission,
|
||||
FieldNameUser,
|
||||
Group,
|
||||
TableGroup,
|
||||
TableMediaUpload,
|
||||
TableNote,
|
||||
@@ -44,6 +47,7 @@ import { RevisionsService } from '../revisions/revisions.service';
|
||||
import { UsersService } from '../users/users.service';
|
||||
import { PermissionService } from './permission.service';
|
||||
import { determinePermissionTestCases } from './test/determine-permission.fixture';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
describe('PermissionsService', () => {
|
||||
let service: PermissionService;
|
||||
@@ -67,7 +71,7 @@ describe('PermissionsService', () => {
|
||||
beforeAll(async () => {
|
||||
[tracker, knexProvider] = mockKnexDb();
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const testingModule: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
PermissionService,
|
||||
knexProvider,
|
||||
@@ -93,13 +97,11 @@ describe('PermissionsService', () => {
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<PermissionService>(PermissionService);
|
||||
usersService = module.get<UsersService>(UsersService);
|
||||
groupsService = module.get<GroupsService>(GroupsService);
|
||||
service = testingModule.get<PermissionService>(PermissionService);
|
||||
usersService = testingModule.get<UsersService>(UsersService);
|
||||
groupsService = testingModule.get<GroupsService>(GroupsService);
|
||||
});
|
||||
|
||||
beforeEach(() => {});
|
||||
|
||||
afterEach(() => {
|
||||
tracker.reset();
|
||||
jest.resetModules();
|
||||
@@ -111,7 +113,6 @@ describe('PermissionsService', () => {
|
||||
expectBindings(tracker, 'select', [[mockMediaUploadUuid]], true);
|
||||
});
|
||||
|
||||
// oxlint-disable-next-line func-style
|
||||
const buildMockSelect = (returnValues: unknown) => {
|
||||
mockSelect(
|
||||
tracker,
|
||||
@@ -179,7 +180,6 @@ describe('PermissionsService', () => {
|
||||
});
|
||||
|
||||
describe('isOwner', () => {
|
||||
// oxlint-disable-next-line func-style
|
||||
const buildMockSelect = (returnValues: unknown) => {
|
||||
mockSelect(tracker, [FieldNameNote.ownerId], TableNote, FieldNameNote.id, returnValues);
|
||||
};
|
||||
@@ -211,7 +211,7 @@ describe('PermissionsService', () => {
|
||||
});
|
||||
|
||||
describe('checkIfUserMayCreateNote', () => {
|
||||
let spyUserServiceIsRegisteredUser: jest.SpyInstance;
|
||||
let spyUserServiceIsRegisteredUser: SpyInstance<typeof usersService.isRegisteredUser>;
|
||||
beforeEach(() => {
|
||||
spyUserServiceIsRegisteredUser = jest.spyOn(usersService, 'isRegisteredUser');
|
||||
});
|
||||
@@ -232,9 +232,9 @@ describe('PermissionsService', () => {
|
||||
});
|
||||
|
||||
describe('determinePermission', () => {
|
||||
let spyOnPermissionsServiceIsOwner: jest.SpyInstance;
|
||||
let spyOnUserServiceIsRegisteredUser: jest.SpyInstance;
|
||||
let spyOnGroupServiceGetGroupsForUser: jest.SpyInstance;
|
||||
let spyOnPermissionsServiceIsOwner: SpyInstance<typeof service.isOwner>;
|
||||
let spyOnUserServiceIsRegisteredUser: SpyInstance<typeof usersService.isRegisteredUser>;
|
||||
let spyOnGroupServiceGetGroupsForUser: SpyInstance<typeof groupsService.getGroupsForUser>;
|
||||
|
||||
beforeEach(() => {
|
||||
spyOnPermissionsServiceIsOwner = jest.spyOn(service, 'isOwner');
|
||||
@@ -271,16 +271,16 @@ describe('PermissionsService', () => {
|
||||
// Groups
|
||||
spyOnGroupServiceGetGroupsForUser.mockImplementation(() => {
|
||||
const alwaysAvailableGroups = [
|
||||
{ [FieldNameGroup.id]: mockGroupIdEveryone },
|
||||
{ [FieldNameGroup.id]: mockGroupId1 },
|
||||
Mock.of<Group>({ [FieldNameGroup.id]: mockGroupIdEveryone }),
|
||||
Mock.of<Group>({ [FieldNameGroup.id]: mockGroupId1 }),
|
||||
];
|
||||
const loggedInGroup = {
|
||||
const loggedInGroup = Mock.of<Group>({
|
||||
[FieldNameGroup.id]: mockGroupIdLoggedIn,
|
||||
};
|
||||
});
|
||||
if (testCase.isRegisteredUser) {
|
||||
return [...alwaysAvailableGroups, loggedInGroup];
|
||||
return Promise.resolve([...alwaysAvailableGroups, loggedInGroup]);
|
||||
}
|
||||
return alwaysAvailableGroups;
|
||||
return Promise.resolve(alwaysAvailableGroups);
|
||||
});
|
||||
// GroupPermissions
|
||||
mockSelect(
|
||||
@@ -315,7 +315,7 @@ describe('PermissionsService', () => {
|
||||
});
|
||||
|
||||
describe('setUserPermission', () => {
|
||||
let spyOnIsOwner: jest.SpyInstance;
|
||||
let spyOnIsOwner: SpyInstance<typeof service.isOwner>;
|
||||
beforeEach(() => {
|
||||
spyOnIsOwner = jest.spyOn(service, 'isOwner');
|
||||
});
|
||||
@@ -325,7 +325,7 @@ describe('PermissionsService', () => {
|
||||
expect(spyOnIsOwner).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
describe('user is not owner', () => {
|
||||
let spyOnIsRegisteredUser: jest.SpyInstance;
|
||||
let spyOnIsRegisteredUser: SpyInstance<typeof usersService.isRegisteredUser>;
|
||||
beforeEach(() => {
|
||||
spyOnIsOwner.mockResolvedValue(false);
|
||||
spyOnIsRegisteredUser = jest.spyOn(usersService, 'isRegisteredUser');
|
||||
@@ -338,8 +338,8 @@ describe('PermissionsService', () => {
|
||||
});
|
||||
it('and user is registered', async () => {
|
||||
const spyOneNotifyOthers = jest.spyOn(
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
service as any,
|
||||
// Typecast is required as we're mocking a private method here
|
||||
service as typeof service & { notifyOthers: (_: number) => void },
|
||||
'notifyOthers',
|
||||
);
|
||||
spyOnIsRegisteredUser.mockResolvedValue(true);
|
||||
@@ -356,11 +356,11 @@ describe('PermissionsService', () => {
|
||||
});
|
||||
|
||||
describe('removeUserPermission', () => {
|
||||
let spyOneNotifyOthers: jest.SpyInstance;
|
||||
let spyOneNotifyOthers: SpyInstance;
|
||||
beforeEach(() => {
|
||||
spyOneNotifyOthers = jest.spyOn(
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
service as any,
|
||||
// Typecast is required as we're mocking a private method here
|
||||
service as typeof service & { notifyOthers: (_: number) => void },
|
||||
'notifyOthers',
|
||||
);
|
||||
});
|
||||
@@ -403,8 +403,8 @@ describe('PermissionsService', () => {
|
||||
describe('setGroupPermission', () => {
|
||||
it('correctly sets group permissions and notifies other user', async () => {
|
||||
const spyOneNotifyOthers = jest.spyOn(
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
service as any,
|
||||
// Typecast is required as we're mocking a private method here
|
||||
service as typeof service & { notifyOthers: (_: number) => void },
|
||||
'notifyOthers',
|
||||
);
|
||||
mockInsert(tracker, TableNoteGroupPermission, [
|
||||
@@ -419,15 +419,14 @@ describe('PermissionsService', () => {
|
||||
});
|
||||
|
||||
describe('removeGroupPermission', () => {
|
||||
let spyOneNotifyOthers: jest.SpyInstance;
|
||||
let spyOneNotifyOthers: SpyInstance;
|
||||
beforeEach(() => {
|
||||
spyOneNotifyOthers = jest.spyOn(
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
service as any,
|
||||
// Typecast is required as we're mocking a private method here
|
||||
service as typeof service & { notifyOthers: (_: number) => void },
|
||||
'notifyOthers',
|
||||
);
|
||||
});
|
||||
// oxlint-disable-next-line func-style
|
||||
const buildMockDelete = (deletedEntries: number) => {
|
||||
mockDelete(
|
||||
tracker,
|
||||
@@ -453,15 +452,14 @@ describe('PermissionsService', () => {
|
||||
});
|
||||
|
||||
describe('changeOwner', () => {
|
||||
let spyOneNotifyOthers: jest.SpyInstance;
|
||||
let spyOneNotifyOthers: SpyInstance;
|
||||
beforeEach(() => {
|
||||
spyOneNotifyOthers = jest.spyOn(
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
service as any,
|
||||
// Typecast is required as we're mocking a private method here
|
||||
service as typeof service & { notifyOthers: (_: number) => void },
|
||||
'notifyOthers',
|
||||
);
|
||||
});
|
||||
// oxlint-disable-next-line func-style
|
||||
const buildMockUpdate = (updatedEntries: number) => {
|
||||
mockUpdate(tracker, TableNote, [FieldNameNote.ownerId], FieldNameNote.id, updatedEntries);
|
||||
};
|
||||
@@ -480,7 +478,6 @@ describe('PermissionsService', () => {
|
||||
});
|
||||
|
||||
describe('changePubliclyVisibly', () => {
|
||||
// oxlint-disable-next-line func-style
|
||||
const buildMockUpdate = (updatedEntries: number) => {
|
||||
mockUpdate(
|
||||
tracker,
|
||||
@@ -503,7 +500,6 @@ describe('PermissionsService', () => {
|
||||
});
|
||||
|
||||
describe('getPermissionsDtoForNote', () => {
|
||||
// oxlint-disable-next-line func-style
|
||||
const buildMockOwnerSelect = (returnValues: unknown) => {
|
||||
mockSelect(
|
||||
tracker,
|
||||
@@ -523,7 +519,6 @@ describe('PermissionsService', () => {
|
||||
],
|
||||
);
|
||||
};
|
||||
// oxlint-disable-next-line func-style
|
||||
const buildMockUserPermissionsSelect = (returnValues: unknown) => {
|
||||
mockSelect(
|
||||
tracker,
|
||||
@@ -543,7 +538,6 @@ describe('PermissionsService', () => {
|
||||
],
|
||||
);
|
||||
};
|
||||
// oxlint-disable-next-line func-style
|
||||
const buildMockGroupPermissionsSelect = (returnValues: unknown) => {
|
||||
mockSelect(
|
||||
tracker,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import { PermissionLevel } from '@hedgedoc/commons';
|
||||
|
||||
import { convertEditabilityToPermissionLevel } from './convert-editability-to-permission-level';
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import {
|
||||
MessageTransporter,
|
||||
MockedBackendTransportAdapter,
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import * as realtimeNoteModule from './realtime-note';
|
||||
import { RealtimeNote } from './realtime-note';
|
||||
import { RealtimeNoteStore } from './realtime-note-store';
|
||||
@@ -10,7 +12,9 @@ import { RealtimeNoteStore } from './realtime-note-store';
|
||||
describe('RealtimeNoteStore', () => {
|
||||
let realtimeNoteStore: RealtimeNoteStore;
|
||||
let mockedRealtimeNote: RealtimeNote;
|
||||
let realtimeNoteConstructorSpy: jest.SpyInstance;
|
||||
let realtimeNoteConstructorSpy: SpyInstance<
|
||||
(noteId: number, initialTextContent: string, initialYjsState?: number[]) => RealtimeNote
|
||||
>;
|
||||
const mockedContent = 'mockedContent';
|
||||
const mockedNoteId = 4711;
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterAll, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import { PermissionLevel } from '@hedgedoc/commons';
|
||||
import { FieldNameRevision, Revision } from '@hedgedoc/database';
|
||||
import { SchedulerRegistry } from '@nestjs/schedule';
|
||||
@@ -31,13 +33,13 @@ describe('RealtimeNoteService', () => {
|
||||
let mockedPermissionService: PermissionService;
|
||||
let consoleLoggerService: ConsoleLoggerService;
|
||||
let mockedNoteConfig: NoteConfig;
|
||||
let addIntervalSpy: jest.SpyInstance;
|
||||
let setIntervalSpy: jest.SpyInstance;
|
||||
let clearIntervalSpy: jest.SpyInstance;
|
||||
let addIntervalSpy: SpyInstance<typeof SchedulerRegistry.prototype.addInterval>;
|
||||
let setIntervalSpy: SpyInstance<typeof setInterval>;
|
||||
let clearIntervalSpy: SpyInstance<typeof clearInterval>;
|
||||
let clientWithReadWrite: RealtimeConnection;
|
||||
let clientWithRead: RealtimeConnection;
|
||||
let clientWithoutReadWrite: RealtimeConnection;
|
||||
let deleteIntervalSpy: jest.SpyInstance;
|
||||
let deleteIntervalSpy: SpyInstance<typeof SchedulerRegistry.prototype.deleteInterval>;
|
||||
|
||||
const readWriteUserId = 2;
|
||||
const onlyReadUserId = 1;
|
||||
@@ -84,9 +86,9 @@ describe('RealtimeNoteService', () => {
|
||||
error: jest.fn(),
|
||||
});
|
||||
realtimeNoteStore = Mock.of<RealtimeNoteStore>({
|
||||
find: jest.fn(),
|
||||
find: jest.fn<typeof RealtimeNoteStore.prototype.find>(),
|
||||
create: jest.fn(),
|
||||
getAllRealtimeNotes: jest.fn(),
|
||||
getAllRealtimeNotes: jest.fn<typeof RealtimeNoteStore.prototype.getAllRealtimeNotes>(),
|
||||
});
|
||||
|
||||
mockedNoteConfig = Mock.of<NoteConfig>({ persistInterval: 0 });
|
||||
@@ -109,7 +111,7 @@ describe('RealtimeNoteService', () => {
|
||||
|
||||
addIntervalSpy = jest.spyOn(schedulerRegistry, 'addInterval');
|
||||
deleteIntervalSpy = jest.spyOn(schedulerRegistry, 'deleteInterval');
|
||||
setIntervalSpy = jest.spyOn(global, 'setInterval');
|
||||
setIntervalSpy = jest.spyOn(global, 'setInterval') as SpyInstance<typeof setInterval>;
|
||||
clearIntervalSpy = jest.spyOn(global, 'clearInterval');
|
||||
|
||||
clientWithReadWrite = new MockConnectionBuilder(realtimeNote)
|
||||
@@ -208,8 +210,8 @@ describe('RealtimeNoteService', () => {
|
||||
});
|
||||
|
||||
describe('handleNoteAliasesChanged', () => {
|
||||
let spyRealtimeNoteStoreFind: jest.SpyInstance;
|
||||
let spyAnnounceAliasesUpdate: jest.SpyInstance;
|
||||
let spyRealtimeNoteStoreFind: SpyInstance<typeof realtimeNoteStore.find>;
|
||||
let spyAnnounceAliasesUpdate: SpyInstance<typeof realtimeNote.announceAliasesUpdate>;
|
||||
|
||||
beforeEach(() => {
|
||||
spyRealtimeNoteStoreFind = jest.spyOn(realtimeNoteStore, 'find').mockImplementation(() => {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, afterAll, jest } from '@jest/globals';
|
||||
import { MessageType, RealtimeDoc } from '@hedgedoc/commons';
|
||||
|
||||
import { RealtimeNote } from './realtime-note';
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import {
|
||||
describe,
|
||||
it,
|
||||
expect,
|
||||
beforeAll,
|
||||
beforeEach,
|
||||
afterAll,
|
||||
afterEach,
|
||||
jest,
|
||||
} from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import {
|
||||
Message,
|
||||
MessageTransporter,
|
||||
@@ -12,7 +23,7 @@ import {
|
||||
|
||||
import { RealtimeUserStatusAdapter } from './realtime-user-status-adapter';
|
||||
|
||||
type SendMessageSpy = jest.SpyInstance<void, [content: Message<MessageType>]>;
|
||||
type SendMessageSpy = SpyInstance<typeof MessageTransporter.prototype.sendMessage>;
|
||||
|
||||
describe('realtime user status adapter', () => {
|
||||
let clientLoggedIn1: RealtimeUserStatusAdapter | undefined;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
import { MockedBackendTransportAdapter, YDocSyncServerAdapter } from '@hedgedoc/commons';
|
||||
import { FieldNameUser, User } from '@hedgedoc/database';
|
||||
import { jest } from '@jest/globals';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
import { RealtimeConnection } from '../realtime-connection';
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
import {
|
||||
ConnectionState,
|
||||
DisconnectReason,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import { IncomingMessage } from 'http';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import { PermissionLevel } from '@hedgedoc/commons';
|
||||
import { FieldNameUser } from '@hedgedoc/database';
|
||||
import { Provider } from '@nestjs/common';
|
||||
@@ -48,8 +50,8 @@ describe('Websocket gateway', () => {
|
||||
let permissionsService: PermissionService;
|
||||
let mockedWebsocketConnection: RealtimeConnection;
|
||||
let mockedWebsocket: WebSocket;
|
||||
let mockedWebsocketCloseSpy: jest.SpyInstance;
|
||||
let addClientSpy: jest.SpyInstance;
|
||||
let mockedWebsocketCloseSpy: SpyInstance<typeof WebSocket.WebSocket.prototype.close>;
|
||||
let addClientSpy: SpyInstance<typeof RealtimeNote.prototype.addClient>;
|
||||
|
||||
const mockedValidSessionCookie = 'mockedValidSessionCookie';
|
||||
const mockedSessionIdWithUser = 'mockedSessionIdWithUser';
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import type { SpyInstance } from 'jest-mock';
|
||||
import {
|
||||
FieldNameAlias,
|
||||
FieldNameAuthorshipInfo,
|
||||
@@ -155,8 +157,7 @@ describe('RevisionsService', () => {
|
||||
});
|
||||
|
||||
describe('purgeRevisions', () => {
|
||||
let spyOnGetPrimaryAlias: jest.SpyInstance;
|
||||
// oxlint-disable-next-line func-style
|
||||
let spyOnGetPrimaryAlias: SpyInstance<typeof aliasService.getPrimaryAliasByNoteId>;
|
||||
const buildMockSelect = (returnValues: unknown) => {
|
||||
mockSelect(tracker, [], TableRevision, [FieldNameRevision.noteId], returnValues);
|
||||
};
|
||||
|
||||
@@ -134,6 +134,8 @@ export class RevisionsService {
|
||||
recordMap.set(
|
||||
revision[FieldNameRevision.uuid],
|
||||
RevisionMetadataDto.create({
|
||||
// We're extending a DTO here which is technically a class but valid in this case.
|
||||
// oxlint-disable-next-line typescript/no-misused-spread
|
||||
...currentMappedRevision,
|
||||
authorUsernames,
|
||||
authorGuestUuids,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import { extractRevisionMetadataFromContent } from './extract-revision-metadata-from-content';
|
||||
|
||||
describe('revision entity', () => {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import { AuthProviderType } from '@hedgedoc/commons';
|
||||
import { FieldNameSession, Session, TableSession } from '@hedgedoc/database';
|
||||
import { Session as FastifySession } from 'fastify';
|
||||
|
||||
@@ -68,5 +68,5 @@ export interface SessionState {
|
||||
}
|
||||
|
||||
declare module 'fastify' {
|
||||
interface Session extends SessionState {}
|
||||
interface Session extends Omit<SessionState, 'cookie'> {}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, afterEach } from '@jest/globals';
|
||||
import { Provider } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import { generateRandomName } from './name-randomizer';
|
||||
|
||||
describe('name randomizer', () => {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeAll, afterEach, jest } from '@jest/globals';
|
||||
import { FieldNameUser, TableUser, User } from '@hedgedoc/database';
|
||||
import { BadRequestException, Provider } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
@@ -216,6 +217,7 @@ describe('UsersService', () => {
|
||||
['returns true if username already exists', [{ [FieldNameUser.username]: username }], true],
|
||||
['returns false if username does not already exists', [], false],
|
||||
])('isUsernameTaken', (title, returnValue, result) => {
|
||||
// oxlint-disable-next-line jest/valid-title
|
||||
it(title, async () => {
|
||||
mockSelect(tracker, [FieldNameUser.username], TableUser, FieldNameUser.username, returnValue);
|
||||
expect(await service.isUsernameTaken(username)).toBe(result);
|
||||
@@ -228,6 +230,7 @@ describe('UsersService', () => {
|
||||
['returns false if user does not exist', [], false],
|
||||
['returns true if user is not a guest', [{ [FieldNameUser.username]: username }], true],
|
||||
])('isRegisteredUser', (title, returnValue, result) => {
|
||||
// oxlint-disable-next-line jest/valid-title
|
||||
it(title, async () => {
|
||||
mockSelect(tracker, [FieldNameUser.username], TableUser, FieldNameUser.id, returnValue);
|
||||
expect(await service.isRegisteredUser(userId)).toBe(result);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, jest } from '@jest/globals';
|
||||
import argon2 from '@node-rs/argon2';
|
||||
|
||||
import {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, afterEach, jest } from '@jest/globals';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
import { clearCachedVersion, getServerVersionFromPackageJson } from './server-version';
|
||||
|
||||
@@ -3,20 +3,16 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { BadRequestException, ValidationPipe } from '@nestjs/common';
|
||||
import { BadRequestException, PipeTransform } from '@nestjs/common';
|
||||
import { createZodValidationPipe } from 'nestjs-zod';
|
||||
import { ZodError } from 'zod';
|
||||
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
|
||||
export function setupValidationPipe(logger: ConsoleLoggerService): ValidationPipe {
|
||||
// This issue is only relevant for usage of class-validator, however we use Zod
|
||||
// oxlint-disable-next-line @darraghor/nestjs-typed/should-specify-forbid-unknown-values
|
||||
return new ValidationPipe({
|
||||
forbidUnknownValues: false,
|
||||
skipMissingProperties: false,
|
||||
transform: true,
|
||||
exceptionFactory: (errors): BadRequestException => {
|
||||
// strip the trailing newline for cleaner logs
|
||||
const errorMessage = errors.toString().trimEnd();
|
||||
export function setupValidationPipe(logger: ConsoleLoggerService): PipeTransform {
|
||||
const ZodValidationPipe = createZodValidationPipe({
|
||||
createValidationException: (error: ZodError): BadRequestException => {
|
||||
const errorMessage = error.toString().trimEnd();
|
||||
logger.debug(
|
||||
`Errors were encountered while validating a request:\n${errorMessage}`,
|
||||
'ValidationPipe',
|
||||
@@ -26,4 +22,6 @@ export function setupValidationPipe(logger: ConsoleLoggerService): ValidationPip
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
return new ZodValidationPipe();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { PRIVATE_API_PREFIX } from '../../src/app.module';
|
||||
import type { TestSetup } from '../test-setup';
|
||||
import { noteAlias1, password3, TestSetupBuilder, username3 } from '../test-setup';
|
||||
@@ -85,6 +86,7 @@ describe('Alias', () => {
|
||||
});
|
||||
});
|
||||
describe.each(AliasTestCases)('returns the note', (testName, _aliasToUse, aliasToQuery) => {
|
||||
// oxlint-disable-next-line jest/valid-title
|
||||
it(testName, async () => {
|
||||
const result = await agentUser1
|
||||
.get(`${PRIVATE_API_PREFIX}/alias/${aliasToQuery}`)
|
||||
@@ -107,6 +109,7 @@ describe('Alias', () => {
|
||||
};
|
||||
|
||||
describe.each(AliasTestCases)('creates', (testName, alias) => {
|
||||
// oxlint-disable-next-line jest/valid-title
|
||||
it(testName, async () => {
|
||||
newAliasDto.newAlias = alias;
|
||||
await agentUser1
|
||||
@@ -179,6 +182,7 @@ describe('Alias', () => {
|
||||
const newAlias = DefaultTestAlias;
|
||||
|
||||
describe.each(AliasTestCases)('correctly set primary alias', (testName, alias) => {
|
||||
// oxlint-disable-next-line jest/valid-title
|
||||
it(testName, async () => {
|
||||
await testSetup.aliasService.addAlias(noteId, newAlias);
|
||||
await agentUser1
|
||||
@@ -242,10 +246,13 @@ describe('Alias', () => {
|
||||
await testSetup.aliasService.addAlias(noteId, newAlias);
|
||||
});
|
||||
describe.each(AliasTestCases)('correctly deletes the alias', (testName, alias) => {
|
||||
// oxlint-disable-next-line jest/valid-title
|
||||
it(testName, async () => {
|
||||
await expect(testSetup.notesService.getNoteIdByAlias(newAlias)).resolves.toBe(noteId);
|
||||
await agentUser1.delete(`${PRIVATE_API_PREFIX}/alias/${alias}`).expect(204);
|
||||
await expect(testSetup.notesService.getNoteIdByAlias(newAlias)).rejects.toThrow();
|
||||
await expect(testSetup.notesService.getNoteIdByAlias(newAlias)).rejects.toThrow(
|
||||
'Could not find note',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import request from 'supertest';
|
||||
import { ApiTokenWithSecretInterface } from '@hedgedoc/commons';
|
||||
import { dateTimeToISOString, getCurrentDateTime } from '../../src/utils/datetime';
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
@typescript-eslint/no-unsafe-assignment,
|
||||
@typescript-eslint/no-unsafe-member-access
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import request from 'supertest';
|
||||
import { AuthProviderType, FieldNameIdentity, FieldNameUser } from '@hedgedoc/database';
|
||||
import { checkPassword } from '../../src/utils/password';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { PRIVATE_API_PREFIX } from '../../src/app.module';
|
||||
import { getServerVersionFromPackageJson } from '../../src/utils/server-version';
|
||||
import { TestSetup, TestSetupBuilder } from '../test-setup';
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { PRIVATE_API_PREFIX } from '../../src/app.module';
|
||||
import { password1, TestSetup, TestSetupBuilder, username1 } from '../test-setup';
|
||||
import { setupAgent } from './utils/setup-agent';
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { SortMode } from '@hedgedoc/commons';
|
||||
import { NoteType } from '@hedgedoc/database';
|
||||
import { PRIVATE_API_PREFIX } from '../../src/app.module';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, test, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { PRIVATE_API_PREFIX } from '../../src/app.module';
|
||||
import { createDefaultMockNoteConfig } from '../../src/config/mock/note.config.mock';
|
||||
import { NoteConfig } from '../../src/config/note.config';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { PRIVATE_API_PREFIX } from '../../src/app.module';
|
||||
import { NotInDBError } from '../../src/errors/errors';
|
||||
import {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { promises as fs } from 'fs';
|
||||
import { join } from 'path';
|
||||
import type request from 'supertest';
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { PRIVATE_API_PREFIX } from '../../src/app.module';
|
||||
import type { NoteMetadataDto } from '../../src/dtos/note-metadata.dto';
|
||||
import { NotInDBError } from '../../src/errors/errors';
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import request from 'supertest';
|
||||
import { PRIVATE_API_PREFIX } from '../../src/app.module';
|
||||
import {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { PUBLIC_API_PREFIX } from '../../src/app.module';
|
||||
import type { AliasUpdateDto } from '../../src/dtos/alias-update.dto';
|
||||
import { NotInDBError } from '../../src/errors/errors';
|
||||
@@ -33,6 +34,7 @@ describe('Alias', () => {
|
||||
|
||||
describe(`POST ${PUBLIC_API_PREFIX}/alias`, () => {
|
||||
describe.each(AliasTestCases)('create normal alias', (testName, aliasToUse, aliasToQuery) => {
|
||||
// oxlint-disable-next-line jest/valid-title
|
||||
it(testName, async () => {
|
||||
const newAliasDto: AliasCreateDto = {
|
||||
noteAlias: noteAlias1,
|
||||
@@ -126,6 +128,7 @@ describe('Alias', () => {
|
||||
describe.each(AliasTestCases)(
|
||||
'updates a note with a normal alias',
|
||||
(testName, aliasToUse, aliasToQuery) => {
|
||||
// oxlint-disable-next-line jest/valid-title
|
||||
it(testName, async () => {
|
||||
await testSetup.aliasService.addAlias(noteId, aliasToUse);
|
||||
const metadata = await agent
|
||||
@@ -203,6 +206,7 @@ describe('Alias', () => {
|
||||
describe.each(AliasTestCases)(
|
||||
'deletes a normal alias',
|
||||
(testName, aliasToUse, aliasToQuery) => {
|
||||
// oxlint-disable-next-line jest/valid-title
|
||||
it(testName, async () => {
|
||||
await testSetup.aliasService.addAlias(testSetup.ownedNoteIds[0], aliasToUse);
|
||||
|
||||
@@ -244,6 +248,7 @@ describe('Alias', () => {
|
||||
});
|
||||
|
||||
describe.each(AliasTestCases)('if alias is primary', (testName, aliasToUse, aliasToQuery) => {
|
||||
// oxlint-disable-next-line jest/valid-title
|
||||
it(testName, async () => {
|
||||
// add another alias
|
||||
await testSetup.aliasService.addAlias(testSetup.ownedNoteIds[0], aliasToUse);
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import { PUBLIC_API_PREFIX } from '../../src/app.module';
|
||||
import { NoteMetadataDto } from '../../src/dtos/note-metadata.dto';
|
||||
import {
|
||||
@@ -8,11 +14,6 @@ import {
|
||||
TestSetupBuilder,
|
||||
username1,
|
||||
} from '../test-setup';
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { AuthProviderType, FieldNameUser } from '@hedgedoc/database';
|
||||
import { promises as fs } from 'fs';
|
||||
import { join } from 'path';
|
||||
@@ -77,7 +78,7 @@ describe('Me', () => {
|
||||
});
|
||||
describe(`GET ${PUBLIC_API_PREFIX}/me/media`, () => {
|
||||
let newNoteId1: number;
|
||||
const imageIds = [];
|
||||
const imageIds: string[] = [];
|
||||
beforeEach(async () => {
|
||||
newNoteId1 = await testSetup.notesService.getNoteIdByAlias(noteAlias1);
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import { PUBLIC_API_PREFIX } from '../../src/app.module';
|
||||
import type { MediaUploadDto } from '../../src/dtos/media-upload.dto';
|
||||
import { ConsoleLoggerService } from '../../src/logger/console-logger.service';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
|
||||
import { PUBLIC_API_PREFIX } from '../../src/app.module';
|
||||
import { NotePermissionsDto } from '../../src/dtos/note-permissions.dto';
|
||||
import { NotInDBError } from '../../src/errors/errors';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"strict": false
|
||||
"strict": false,
|
||||
"rootDir": ".."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { expect } from '@jest/globals';
|
||||
import { promises as fs } from 'fs';
|
||||
import request from 'supertest';
|
||||
import { PUBLIC_API_PREFIX } from '../src/app.module';
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"strictPropertyInitialization": false,
|
||||
"resolveJsonModule": true,
|
||||
"useDefineForClassFields": false,
|
||||
|
||||
@@ -2862,6 +2862,7 @@ __metadata:
|
||||
"@fastify/static": "npm:9.0.0"
|
||||
"@hedgedoc/commons": "workspace:commons"
|
||||
"@hedgedoc/database": "workspace:database"
|
||||
"@jest/types": "npm:30.3.0"
|
||||
"@mrdrogdrog/optional": "npm:1.2.1"
|
||||
"@nestjs/cli": "npm:10.4.9"
|
||||
"@nestjs/common": "npm:10.4.22"
|
||||
@@ -2881,7 +2882,6 @@ __metadata:
|
||||
"@types/cli-color": "npm:2.0.6"
|
||||
"@types/cookie": "npm:1.0.0"
|
||||
"@types/cookie-signature": "npm:1.1.2"
|
||||
"@types/jest": "npm:29.5.14"
|
||||
"@types/luxon": "npm:3.7.1"
|
||||
"@types/markdown-it": "npm:13.0.8"
|
||||
"@types/node": "npm:24.10.7"
|
||||
@@ -3561,6 +3561,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jest/pattern@npm:30.0.1":
|
||||
version: 30.0.1
|
||||
resolution: "@jest/pattern@npm:30.0.1"
|
||||
dependencies:
|
||||
"@types/node": "npm:*"
|
||||
jest-regex-util: "npm:30.0.1"
|
||||
checksum: 10c0/32c5a7bfb6c591f004dac0ed36d645002ed168971e4c89bd915d1577031672870032594767557b855c5bc330aa1e39a2f54bf150d2ee88a7a0886e9cb65318bc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jest/reporters@npm:^29.7.0":
|
||||
version: 29.7.0
|
||||
resolution: "@jest/reporters@npm:29.7.0"
|
||||
@@ -3598,6 +3608,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jest/schemas@npm:30.0.5":
|
||||
version: 30.0.5
|
||||
resolution: "@jest/schemas@npm:30.0.5"
|
||||
dependencies:
|
||||
"@sinclair/typebox": "npm:^0.34.0"
|
||||
checksum: 10c0/449dcd7ec5c6505e9ac3169d1143937e67044ae3e66a729ce4baf31812dfd30535f2b3b2934393c97cfdf5984ff581120e6b38f62b8560c8b5b7cc07f4175f65
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jest/schemas@npm:^29.6.3":
|
||||
version: 29.6.3
|
||||
resolution: "@jest/schemas@npm:29.6.3"
|
||||
@@ -3679,6 +3698,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jest/types@npm:30.3.0":
|
||||
version: 30.3.0
|
||||
resolution: "@jest/types@npm:30.3.0"
|
||||
dependencies:
|
||||
"@jest/pattern": "npm:30.0.1"
|
||||
"@jest/schemas": "npm:30.0.5"
|
||||
"@types/istanbul-lib-coverage": "npm:^2.0.6"
|
||||
"@types/istanbul-reports": "npm:^3.0.4"
|
||||
"@types/node": "npm:*"
|
||||
"@types/yargs": "npm:^17.0.33"
|
||||
chalk: "npm:^4.1.2"
|
||||
checksum: 10c0/c3e3f4de0b77a7ced345f47d3687b1094c1b6c1521529a7ca66a76f9a80194f79179a1dbc32d6761a5b67914a8f78be1e65d1408107efcb1f252c4a63b5ddd92
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5":
|
||||
version: 0.3.5
|
||||
resolution: "@jridgewell/gen-mapping@npm:0.3.5"
|
||||
@@ -5242,6 +5276,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sinclair/typebox@npm:^0.34.0":
|
||||
version: 0.34.49
|
||||
resolution: "@sinclair/typebox@npm:0.34.49"
|
||||
checksum: 10c0/16b7d87f039a49b68c10bb4cdcae2ce5242b2472228851fd6483731616aba4ef977690aa517b230a8d20da8185bb416eb34e326f30568b3963c1cf26b05d1ad8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sindresorhus/merge-streams@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "@sindresorhus/merge-streams@npm:1.0.0"
|
||||
@@ -6144,7 +6185,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1":
|
||||
"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1, @types/istanbul-lib-coverage@npm:^2.0.6":
|
||||
version: 2.0.6
|
||||
resolution: "@types/istanbul-lib-coverage@npm:2.0.6"
|
||||
checksum: 10c0/3948088654f3eeb45363f1db158354fb013b362dba2a5c2c18c559484d5eb9f6fd85b23d66c0a7c2fcfab7308d0a585b14dadaca6cc8bf89ebfdc7f8f5102fb7
|
||||
@@ -6160,7 +6201,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/istanbul-reports@npm:^3.0.0":
|
||||
"@types/istanbul-reports@npm:^3.0.0, @types/istanbul-reports@npm:^3.0.4":
|
||||
version: 3.0.4
|
||||
resolution: "@types/istanbul-reports@npm:3.0.4"
|
||||
dependencies:
|
||||
@@ -6485,6 +6526,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/yargs@npm:^17.0.33":
|
||||
version: 17.0.35
|
||||
resolution: "@types/yargs@npm:17.0.35"
|
||||
dependencies:
|
||||
"@types/yargs-parser": "npm:*"
|
||||
checksum: 10c0/609557826a6b85e73ccf587923f6429850d6dc70e420b455bab4601b670bfadf684b09ae288bccedab042c48ba65f1666133cf375814204b544009f57d6eef63
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/yargs@npm:^17.0.8":
|
||||
version: 17.0.32
|
||||
resolution: "@types/yargs@npm:17.0.32"
|
||||
@@ -12113,6 +12163,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jest-regex-util@npm:30.0.1":
|
||||
version: 30.0.1
|
||||
resolution: "jest-regex-util@npm:30.0.1"
|
||||
checksum: 10c0/f30c70524ebde2d1012afe5ffa5691d5d00f7d5ba9e43d588f6460ac6fe96f9e620f2f9b36a02d0d3e7e77bc8efb8b3450ae3b80ac53c8be5099e01bf54f6728
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jest-regex-util@npm:^29.6.3":
|
||||
version: 29.6.3
|
||||
resolution: "jest-regex-util@npm:29.6.3"
|
||||
|
||||
Reference in New Issue
Block a user