From a09f023651913982cb9f936a6c9d90c451e925c3 Mon Sep 17 00:00:00 2001 From: larryrider Date: Tue, 16 Jun 2026 13:59:33 +0200 Subject: [PATCH] refactor: changed all test cases from 'it' to 'test' for uniformity across the codebase --- eslint.config.mjs | 12 +++- test/commands/login.test.ts | 12 ++-- test/commands/logout.test.ts | 6 +- test/commands/upload-folder.test.ts | 20 +++--- test/commands/whoami.test.ts | 8 +-- test/services/auth.service.test.ts | 24 +++---- test/services/config.service.test.ts | 36 +++++----- test/services/crypto.service.test.ts | 14 ++-- .../database/database.service.test.ts | 10 +-- .../drive-item/drive-item.repository.test.ts | 24 +++---- .../services/drive/drive-file.service.test.ts | 6 +- .../drive/drive-folder.service.test.ts | 12 ++-- .../services/drive/drive-item.service.test.ts | 36 +++++----- test/services/keys.service.test.ts | 6 +- .../local-filesystem.service.test.ts | 22 +++--- .../services/network/download.service.test.ts | 6 +- .../network/network-facade.service.test.ts | 21 +++--- .../upload/upload-facade.service.test.ts | 14 ++-- .../upload/upload-file.service.test.ts | 28 ++++---- .../upload/upload-folder.service.test.ts | 24 +++---- test/services/sdkmanager.service.test.ts | 22 +++--- test/services/thumbnail.service.test.ts | 6 +- test/services/usage.service.test.ts | 6 +- test/services/validation.service.test.ts | 52 +++++++------- .../webdav/webdav-folder.service.test.ts | 20 +++--- test/utils/cli.utils.test.ts | 72 +++++++++---------- test/utils/crypto.utils.test.ts | 6 +- test/utils/errors.utils.test.ts | 22 +++--- test/utils/format.utils.test.ts | 10 +-- test/utils/network.utils.test.ts | 14 ++-- test/utils/pm2.utils.test.ts | 16 ++--- test/utils/stream.utils.test.ts | 6 +- test/utils/thumbnail.utils.test.ts | 40 +++++------ test/utils/upload.utils.test.ts | 32 ++++----- test/utils/webdav.utils.test.ts | 34 ++++----- test/utils/xml.utils.test.ts | 8 +-- test/webdav/handlers/DELETE.handler.test.ts | 8 +-- test/webdav/handlers/GET.handler.test.ts | 10 +-- test/webdav/handlers/HEAD.handler.test.ts | 8 +-- test/webdav/handlers/LOCK.handler.test.ts | 16 ++--- test/webdav/handlers/MKCOL.handler.test.ts | 6 +- test/webdav/handlers/MOVE.handler.test.ts | 14 ++-- test/webdav/handlers/OPTIONS.handler.test.ts | 8 +-- test/webdav/handlers/PROPFIND.handler.test.ts | 21 +++--- test/webdav/handlers/PUT.handler.test.ts | 8 +-- test/webdav/handlers/UNLOCK.handler.test.ts | 6 +- .../middlewares/auth.middleware.test.ts | 8 +-- .../middlewares/errors.middleware.test.ts | 10 +-- .../middlewares/mkcol.middleware.test.ts | 10 +-- .../request-logger.middleware.test.ts | 6 +- test/webdav/webdav-server.test.ts | 6 +- 51 files changed, 428 insertions(+), 424 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index d90d6315..f4d76615 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,8 +1,14 @@ import eslintConfigInternxt from '@internxt/eslint-config-internxt'; export default [ - { - ignores: ['dist', 'tmp', 'scripts'], + { + ignores: ['dist', 'tmp', 'scripts'], + }, + ...eslintConfigInternxt, + { + files: ['test/**/*.test.ts'], + rules: { + 'max-len': 'off', }, - ...eslintConfigInternxt, + }, ]; diff --git a/test/commands/login.test.ts b/test/commands/login.test.ts index c75736d1..6fcf0ffe 100644 --- a/test/commands/login.test.ts +++ b/test/commands/login.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { ConfigService } from '../../src/services/config.service'; import { UserCredentialsFixture, UserLoginFixture } from '../fixtures/login.fixture'; import { fail } from 'node:assert'; @@ -7,7 +7,7 @@ import { AuthService } from '../../src/services/auth.service'; import { CLIUtils, NoFlagProvidedError } from '../../src/utils/cli.utils'; describe('Login Command', () => { - it('When user logs in with non-interactive and no email, then it throws error', async () => { + test('When user logs in with non-interactive and no email, then it throws error', async () => { const getValueFromFlagsSpy = vi .spyOn(CLIUtils, 'getValueFromFlag') .mockRejectedValueOnce(new NoFlagProvidedError('email')) // email @@ -32,7 +32,7 @@ describe('Login Command', () => { expect(saveUserSpy).not.toHaveBeenCalled(); }); - it('When user logs in with non-interactive and no password, then it throws error', async () => { + test('When user logs in with non-interactive and no password, then it throws error', async () => { const getValueFromFlagsSpy = vi .spyOn(CLIUtils, 'getValueFromFlag') .mockResolvedValueOnce(UserLoginFixture.email) // email @@ -57,7 +57,7 @@ describe('Login Command', () => { expect(saveUserSpy).not.toHaveBeenCalled(); }); - it('When user logs in with non-interactive and no two factor code, then it throws error', async () => { + test('When user logs in with non-interactive and no two factor code, then it throws error', async () => { const getValueFromFlagsSpy = vi .spyOn(CLIUtils, 'getValueFromFlag') .mockResolvedValueOnce(UserLoginFixture.email) // email @@ -86,7 +86,7 @@ describe('Login Command', () => { expect(saveUserSpy).not.toHaveBeenCalled(); }); - it('When two factor is not needed, then it saves and returns the credentials', async () => { + test('When two factor is not needed, then it saves and returns the credentials', async () => { const getValueFromFlagsSpy = vi .spyOn(CLIUtils, 'getValueFromFlag') .mockResolvedValueOnce(UserLoginFixture.email) // email @@ -112,7 +112,7 @@ describe('Login Command', () => { expect(saveUserSpy).toHaveBeenCalledOnce(); }); - it('When two factor is needed, then it saves and returns the credentials', async () => { + test('When two factor is needed, then it saves and returns the credentials', async () => { const getValueFromFlagsSpy = vi .spyOn(CLIUtils, 'getValueFromFlag') .mockResolvedValueOnce(UserLoginFixture.email) // email diff --git a/test/commands/logout.test.ts b/test/commands/logout.test.ts index 66d70017..d774cf03 100644 --- a/test/commands/logout.test.ts +++ b/test/commands/logout.test.ts @@ -1,11 +1,11 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { ConfigService } from '../../src/services/config.service'; import { UserCredentialsFixture } from '../fixtures/login.fixture'; import Logout from '../../src/commands/logout'; import { AuthService } from '../../src/services/auth.service'; describe('Logout Command', () => { - it('When user is logged out, then it returns false', async () => { + test('When user is logged out, then it returns false', async () => { const readUserSpy = vi.spyOn(ConfigService.instance, 'readUser').mockResolvedValue(undefined); const networkLogout = vi.spyOn(AuthService.instance, 'logout').mockRejectedValue(new Error()); const clearUserSpy = vi.spyOn(ConfigService.instance, 'clearUser').mockRejectedValue(new Error()); @@ -21,7 +21,7 @@ describe('Logout Command', () => { expect(clearUserSpy).not.toHaveBeenCalled(); }); - it('When user is logged in, then the current user logged out', async () => { + test('When user is logged in, then the user is logged out', async () => { const readUserSpy = vi.spyOn(ConfigService.instance, 'readUser').mockResolvedValue(UserCredentialsFixture); const networkLogout = vi.spyOn(AuthService.instance, 'logout').mockResolvedValue(); const clearUserSpy = vi.spyOn(ConfigService.instance, 'clearUser').mockResolvedValue(); diff --git a/test/commands/upload-folder.test.ts b/test/commands/upload-folder.test.ts index 54c4c98f..01840e2f 100644 --- a/test/commands/upload-folder.test.ts +++ b/test/commands/upload-folder.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, MockInstance, vi } from 'vitest'; +import { beforeEach, describe, expect, test, MockInstance, vi } from 'vitest'; import UploadFolder from '../../src/commands/upload-folder'; import { LoginCredentials } from '../../src/types/command.types'; import { ValidationService } from '../../src/services/validation.service'; @@ -37,7 +37,7 @@ describe('Upload Folder Command', () => { vi.spyOn(AsyncUtils, 'sleep').mockResolvedValue(undefined); }); - it('should call UploadFacade when user uploads a folder with valid path', async () => { + test('when user uploads a folder with a valid path, then the upload process completes successfully', async () => { await UploadFolder.run(['--folder=/valid/folder/path']); expect(configReadUserSpy).toHaveBeenCalledTimes(2); @@ -53,7 +53,7 @@ describe('Upload Folder Command', () => { expect(cliSuccessSpy).toHaveBeenCalledOnce(); }); - it('should use provided destination folder UUID when destination flag is passed', async () => { + test('when a destination folder is specified, then the folder is uploaded to the chosen destination', async () => { const customDestinationId = 'custom-folder-uuid-123'; const getDestinationFolderUuidSpy = vi @@ -73,7 +73,7 @@ describe('Upload Folder Command', () => { expect(cliSuccessSpy).toHaveBeenCalledOnce(); }); - it('should default to user.rootFolderId when no destination is passed', async () => { + test('when no destination folder is specified, then the folder is uploaded to the default location', async () => { await UploadFolder.run(['--folder=/valid/folder/path']); expect(UploadFacadeSpy).toHaveBeenCalledWith( @@ -83,7 +83,7 @@ describe('Upload Folder Command', () => { ); }); - it('should call CLIUtils.success with proper message when upload succeeds', async () => { + test('when upload succeeds, then a success message with upload time and link is displayed', async () => { const cliSuccessSpy = vi.spyOn(CLIUtils, 'success').mockImplementation(() => {}); await UploadFolder.run(['--folder=/valid/folder/path']); @@ -99,7 +99,7 @@ describe('Upload Folder Command', () => { ); }); - it('should throw an error when user does not provide a valid path', async () => { + test('when the folder path is invalid, then an error is shown', async () => { const validateDirectoryExistsSpy = vi .spyOn(ValidationService.instance, 'validateDirectoryExists') .mockResolvedValue(false); @@ -117,7 +117,7 @@ describe('Upload Folder Command', () => { expect(UploadFacadeSpy).not.toHaveBeenCalled(); }); - it('should throw an error when user does not have credentials', async () => { + test('when user is not logged in, then an error is shown', async () => { const readUserSpy = vi.spyOn(ConfigService.instance, 'readUser').mockResolvedValue(undefined); const result = UploadFolder.run(['--folder=/some/folder/path']); @@ -132,7 +132,7 @@ describe('Upload Folder Command', () => { }); describe('Folder path resolution (getFolderPath)', () => { - it('should prompt user for folder path in interactive mode when --folder flag is not provided', async () => { + test('when no folder path is given in interactive mode, then the user is prompted for one', async () => { const getValueFromFlagSpy = vi.spyOn(CLIUtils, 'getValueFromFlag').mockResolvedValue('/prompted/folder/path'); await UploadFolder.run([]); @@ -157,7 +157,7 @@ describe('Upload Folder Command', () => { ); }); - it('should throw NoFlagProvidedError in non-interactive mode when --folder flag is not provided', async () => { + test('when no folder path is given in non-interactive mode, then an error is shown', async () => { const getValueFromFlagSpy = vi .spyOn(CLIUtils, 'getValueFromFlag') .mockRejectedValue(new NoFlagProvidedError('folder')); @@ -187,7 +187,7 @@ describe('Upload Folder Command', () => { expect(UploadFacadeSpy).not.toHaveBeenCalled(); }); - it('should use folder path from --folder flag when provided', async () => { + test('when a folder path is provided via the folder flag, then that path is used for the upload', async () => { await UploadFolder.run(['--folder=/explicit/folder/path']); expect(validateDirectoryExistsSpy).toHaveBeenCalledWith('/explicit/folder/path'); diff --git a/test/commands/whoami.test.ts b/test/commands/whoami.test.ts index f9d31fcd..0bba1141 100644 --- a/test/commands/whoami.test.ts +++ b/test/commands/whoami.test.ts @@ -1,11 +1,11 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { ConfigService } from '../../src/services/config.service'; import { UserCredentialsFixture } from '../fixtures/login.fixture'; import Whoami from '../../src/commands/whoami'; import { ValidationService } from '../../src/services/validation.service'; describe('Whoami Command', () => { - it('When user is logged out, then it returns false', async () => { + test('When user is logged out, then it returns false', async () => { const readUserSpy = vi.spyOn(ConfigService.instance, 'readUser').mockResolvedValue(undefined); const clearUserSpy = vi.spyOn(ConfigService.instance, 'clearUser').mockRejectedValue(new Error()); const validateTokensSpy = vi @@ -25,7 +25,7 @@ describe('Whoami Command', () => { expect(validateMnemonicSpy).not.toHaveBeenCalled(); }); - it('When user is logged in with expired credentials, then it returns the user credentials', async () => { + test('When user is logged in with expired credentials, then it returns the user credentials', async () => { const readUserSpy = vi.spyOn(ConfigService.instance, 'readUser').mockResolvedValue(UserCredentialsFixture); const clearUserSpy = vi.spyOn(ConfigService.instance, 'clearUser').mockResolvedValue(); const validateTokensSpy = vi @@ -45,7 +45,7 @@ describe('Whoami Command', () => { expect(validateMnemonicSpy).toHaveBeenCalledOnce(); }); - it('When user is logged in with valid credentials, then it returns the user credentials', async () => { + test('When user is logged in with valid credentials, then it returns the user credentials', async () => { const readUserSpy = vi.spyOn(ConfigService.instance, 'readUser').mockResolvedValue(UserCredentialsFixture); const clearUserSpy = vi.spyOn(ConfigService.instance, 'clearUser').mockResolvedValue(); const validateTokensSpy = vi diff --git a/test/services/auth.service.test.ts b/test/services/auth.service.test.ts index 8b0962f2..be1877f5 100644 --- a/test/services/auth.service.test.ts +++ b/test/services/auth.service.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import crypto from 'node:crypto'; import { Auth, LoginDetails, SecurityDetails } from '@internxt/sdk'; import { AuthService } from '../../src/services/auth.service'; @@ -25,7 +25,7 @@ describe('Auth service', () => { vi.spyOn(CacheService.instance, 'get').mockReturnValue(undefined); }); - it('should generate login user credentials when user logs in', async () => { + test('when the user logs in successfully, then login credentials are generated', async () => { const loginResponse = { token: crypto.randomBytes(16).toString('hex'), newToken: crypto.randomBytes(16).toString('hex'), @@ -50,7 +50,7 @@ describe('Auth service', () => { expect(responseLogin).to.be.deep.equal(expectedResponseLogin); }); - it('should throw an error when user logs in and credentials are not correct', async () => { + test('when the user provides incorrect login credentials, then an error is thrown', async () => { const loginDetails: LoginDetails = { email: crypto.randomBytes(16).toString('hex'), password: crypto.randomBytes(8).toString('hex'), @@ -69,7 +69,7 @@ describe('Auth service', () => { expect(loginStub).toHaveBeenCalledOnce(); }); - it('should return true from is2FANeeded when two factor authentication is enabled', async () => { + test('when two-factor authentication is enabled on the account, then the system reports it as required', async () => { const email = crypto.randomBytes(16).toString('hex'); const securityDetails: SecurityDetails = { encryptedSalt: crypto.randomBytes(16).toString('hex'), @@ -85,7 +85,7 @@ describe('Auth service', () => { expect(responseLogin).to.be.equal(securityDetails.tfaEnabled); }); - it('should throw an error when checking two factor authentication with an incorrect email', async () => { + test('when an invalid email is provided for authentication validation, then an error is thrown', async () => { const email = crypto.randomBytes(16).toString('hex'); const securityStub = vi.spyOn(Auth.prototype, 'securityDetails').mockRejectedValue(new Error()); @@ -100,7 +100,7 @@ describe('Auth service', () => { expect(securityStub).toHaveBeenCalledOnce(); }); - it('should return auth details when all credentials are found', async () => { + test('when all stored credentials are complete and valid, then authentication details are returned', async () => { const sut = AuthService.instance; const loginCreds: LoginCredentials = UserCredentialsFixture; @@ -127,7 +127,7 @@ describe('Auth service', () => { expect(result).to.deep.equal(loginCreds); }); - it('should throw an error when credentials are missing', async () => { + test('when no stored credentials exist, then an error is thrown', async () => { const sut = AuthService.instance; const readUserStub = vi.spyOn(ConfigService.instance, 'readUser').mockResolvedValue(undefined); @@ -141,7 +141,7 @@ describe('Auth service', () => { expect(readUserStub).toHaveBeenCalledOnce(); }); - it('should throw an error when auth token is missing', async () => { + test('when the session token is missing from stored credentials, then an error is thrown', async () => { const sut = AuthService.instance; const readUserStub = vi.spyOn(ConfigService.instance, 'readUser').mockResolvedValue({ @@ -159,7 +159,7 @@ describe('Auth service', () => { expect(readUserStub).toHaveBeenCalledOnce(); }); - it('should throw an error when mnemonic is invalid', async () => { + test('when the recovery phrase is invalid, then an error is thrown', async () => { const sut = AuthService.instance; const mockToken = { @@ -187,7 +187,7 @@ describe('Auth service', () => { expect(validateMnemonicStub).toHaveBeenCalledWith(UserCredentialsFixture.user.mnemonic); }); - it('should throw an error when token has expired', async () => { + test('when the session token has expired, then an error is thrown', async () => { const sut = AuthService.instance; const mockToken = { @@ -215,7 +215,7 @@ describe('Auth service', () => { expect(validateMnemonicStub).toHaveBeenCalledWith(UserCredentialsFixture.user.mnemonic); }); - it('should refresh tokens when they are going to expire soon', async () => { + test('when the session token is about to expire, then it is refreshed automatically', async () => { const sut = AuthService.instance; const mockToken = { @@ -240,7 +240,7 @@ describe('Auth service', () => { expect(refreshTokensStub).toHaveBeenCalledOnce(); }); - it('should clear and throw exception when exception is thrown while refreshing user token', async () => { + test('when the token refresh fails, then stored credentials are cleared and an error is thrown', async () => { const sut = AuthService.instance; const mockToken = { diff --git a/test/services/config.service.test.ts b/test/services/config.service.test.ts index b6114527..b95e389d 100644 --- a/test/services/config.service.test.ts +++ b/test/services/config.service.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import crypto from 'node:crypto'; import fs from 'node:fs/promises'; import { ConfigService } from '../../src/services/config.service'; @@ -42,7 +42,7 @@ describe('Config service', () => { vi.spyOn(CacheService.instance, 'set').mockImplementation(() => {}); }); - it('should return the value when an env property is requested', async () => { + test('when an environment variable is requested, then its value is returned', async () => { const envKey = 'APP_CRYPTO_SECRET'; const envValue = crypto.randomBytes(8).toString('hex'); process.env[envKey] = envValue; @@ -51,7 +51,7 @@ describe('Config service', () => { expect(newEnvValue).to.be.equal(envValue); }); - it('should throw an error when an env property has no value', async () => { + test('when an environment variable has no value set, then an error is thrown', async () => { const envKey = 'APP_CRYPTO_SECRET'; process.env = {}; @@ -64,7 +64,7 @@ describe('Config service', () => { } }); - it('should write credentials encrypted to a temp file and rename atomically when saveUser is called', async () => { + test('when user credentials are saved, then they are encrypted and written to a temporary file before being renamed', async () => { const userCredentials: LoginCredentials = UserCredentialsFixture; const stringCredentials = JSON.stringify(userCredentials); const encryptedUserCredentials = CryptoService.instance.encryptText(stringCredentials); @@ -80,7 +80,7 @@ describe('Config service', () => { expect(renameStub).toHaveBeenCalledWith(tempPath, CREDENTIALS_FILE); }); - it('should read and decrypt credentials from file when readUser is called', async () => { + test('when stored credentials are read, then they are decrypted and returned', async () => { const userCredentials: LoginCredentials = UserCredentialsFixture; const stringCredentials = JSON.stringify(userCredentials); const encryptedUserCredentials = CryptoService.instance.encryptText(stringCredentials); @@ -94,7 +94,7 @@ describe('Config service', () => { expect(configServiceStub).toHaveBeenCalledWith(encryptedUserCredentials); }); - it('should return undefined when credentials file does not exist', async () => { + test('when the credentials file does not exist, then undefined is returned', async () => { const fsStub = vi.spyOn(fs, 'readFile').mockRejectedValue(new Error()); const configServiceStub = vi.spyOn(CryptoService.instance, 'decryptText'); @@ -104,7 +104,7 @@ describe('Config service', () => { expect(configServiceStub).not.toHaveBeenCalled(); }); - it('should clear credentials from file when clearUser is called', async () => { + test('when stored credentials are cleared, then the file content is wiped', async () => { const writeFileStub = vi.spyOn(fs, 'writeFile').mockResolvedValue(); const readFileStub = vi.spyOn(fs, 'readFile').mockResolvedValue(''); const existFileStub = vi @@ -121,7 +121,7 @@ describe('Config service', () => { expect(credentialsFileContent).to.be.equal(''); }); - it('should not throw exception when user credentials are cleared and the file is already empty', async () => { + test('when the credentials file is already empty, then clearing does not throw an error', async () => { const statStub = vi .spyOn(fs, 'stat') // @ts-expect-error - We stub the stat method partially @@ -134,7 +134,7 @@ describe('Config service', () => { expect(writeFileStub).not.toHaveBeenCalled(); }); - it('should not throw exception when user credentials are cleared and the file does not exist', async () => { + test('when the credentials file does not exist, then clearing does not throw an error', async () => { const fileNotFoundError = new Error('File not found'); Object.assign(fileNotFoundError, { code: 'ENOENT' }); @@ -147,7 +147,7 @@ describe('Config service', () => { expect(writeFileStub).not.toHaveBeenCalled(); }); - it('should create the webdav certs directory when it does not exist', async () => { + test('when the certificates directory does not exist, then it is created', async () => { vi.spyOn(fs, 'access').mockRejectedValue(new Error()); const stubMkdir = vi.spyOn(fs, 'mkdir').mockResolvedValue(''); @@ -157,7 +157,7 @@ describe('Config service', () => { expect(stubMkdir).toHaveBeenCalledWith(WEBDAV_SSL_CERTS_DIR); }); - it('should write webdav config to a temp file and rename atomically when saveWebdavConfig is called', async () => { + test('when the WebDAV configuration is saved, then it is written to a temporary file before being renamed', async () => { const webdavConfig: WebdavConfig = getWebdavConfigMock(); const stringConfig = JSON.stringify(webdavConfig); const tempPath = WEBDAV_CONFIGS_FILE + '.tmp'; @@ -172,7 +172,7 @@ describe('Config service', () => { expect(renameStub).toHaveBeenCalledWith(tempPath, WEBDAV_CONFIGS_FILE); }); - it('should read webdav config from file and cache it when readWebdavConfig is called', async () => { + test('when the WebDAV configuration is read from storage, then it is cached in memory', async () => { const webdavConfig: WebdavConfig = getWebdavConfigMock(); const stringConfig = JSON.stringify(webdavConfig); @@ -185,7 +185,7 @@ describe('Config service', () => { expect(cacheSetSpy).toHaveBeenCalledWith(CacheService.WEBDAV_CONFIG_CACHE_KEY, webdavConfig); }); - it('should return cached webdav config without reading file when cache hits', async () => { + test('when the WebDAV configuration is already cached, then it is returned without reading storage', async () => { const webdavConfig: WebdavConfig = getWebdavConfigMock(); vi.spyOn(CacheService.instance, 'get').mockReturnValue(webdavConfig); const fsStub = vi.spyOn(fs, 'readFile'); @@ -195,7 +195,7 @@ describe('Config service', () => { expect(fsStub).not.toHaveBeenCalled(); }); - it('should return default config when webdav config file is empty', async () => { + test('when the WebDAV configuration file is empty, then default values are used', async () => { const fsStub = vi.spyOn(fs, 'readFile').mockResolvedValue(''); const webdavConfigResult = await ConfigService.instance.readWebdavConfig(); @@ -203,7 +203,7 @@ describe('Config service', () => { expect(fsStub).toHaveBeenCalledWith(WEBDAV_CONFIGS_FILE, 'utf8'); }); - it('should return default config when readWebdavConfig throws an error', async () => { + test('when reading the WebDAV configuration fails, then default values are used', async () => { const fsStub = vi.spyOn(fs, 'readFile').mockRejectedValue(new Error()); const webdavConfigResult = await ConfigService.instance.readWebdavConfig(); @@ -211,7 +211,7 @@ describe('Config service', () => { expect(fsStub).toHaveBeenCalledWith(WEBDAV_CONFIGS_FILE, 'utf8'); }); - it('should default to true when webdav config exists but createFullPath property is missing', async () => { + test('when the WebDAV configuration is missing the directory creation setting, then it defaults to enabled', async () => { const partialWebdavConfig = { host: '192.168.1.1', port: '8080', @@ -229,7 +229,7 @@ describe('Config service', () => { expect(fsStub).toHaveBeenCalledWith(WEBDAV_CONFIGS_FILE, 'utf8'); }); - it('shoud return false when webdav config has createFullPath explicitly set to false', async () => { + test('when the directory creation option is explicitly disabled in the WebDAV configuration, then it is returned as disabled', async () => { const webdavConfig = { host: '192.168.1.1', port: '8080', @@ -246,7 +246,7 @@ describe('Config service', () => { expect(fsStub).toHaveBeenCalledWith(WEBDAV_CONFIGS_FILE, 'utf8'); }); - it('should return true when webdav config has createFullPath explicitly set to true', async () => { + test('when the directory creation option is explicitly enabled in the WebDAV configuration, then it is returned as enabled', async () => { const webdavConfig = { host: '192.168.1.1', port: '8080', diff --git a/test/services/crypto.service.test.ts b/test/services/crypto.service.test.ts index cf66355c..62476b7c 100644 --- a/test/services/crypto.service.test.ts +++ b/test/services/crypto.service.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import crypto from 'node:crypto'; import { ConfigService } from '../../src/services/config.service'; import { CryptoService } from '../../src/services/crypto.service'; @@ -7,7 +7,7 @@ import { Keys } from '@internxt/sdk'; import { KeysService } from '../../src/services/keys.service'; describe('Crypto service', () => { - it('When text is encrypted using crypto secret env, then it can be decrypted back', () => { + test('when sensitive data is encrypted with the application secret, then it can be decrypted back to its original form', () => { const envEndpoint: { key: keyof ConfigKeys; value: string } = { key: 'APP_CRYPTO_SECRET', value: crypto.randomBytes(16).toString('hex'), @@ -22,7 +22,7 @@ describe('Crypto service', () => { expect(spyConfigService).toHaveBeenCalledWith(envEndpoint.key); }); - it('When text is encrypted using crypto secret env, then it can be decrypted back', () => { + test('when encrypted data is decrypted with the application secret, then the original content is restored', () => { const envEndpoint: { key: keyof ConfigKeys; value: string } = { key: 'APP_CRYPTO_SECRET', value: crypto.randomBytes(16).toString('hex'), @@ -37,7 +37,7 @@ describe('Crypto service', () => { expect(spyConfigService).toHaveBeenCalledWith(envEndpoint.key); }); - it('When a password is hashed using CryptoProvider, then it is hashed successfully', async () => { + test('when a password is hashed with the cryptographic provider, then the result matches the expected hash', async () => { const envEndpoint: { key: keyof ConfigKeys; value: string } = { key: 'APP_CRYPTO_SECRET', value: crypto.randomBytes(16).toString('hex'), @@ -64,7 +64,7 @@ describe('Crypto service', () => { expect(spyConfigService).toHaveBeenCalledWith(envEndpoint.key); }); - it('When a password is hashed using passToHash without salt, then it is hashed with a new generated salt', () => { + test('when a password is hashed without a provided salt, then a new salt is generated automatically', () => { const password = crypto.randomBytes(16).toString('hex'); const hashedPassword = CryptoService.instance.passToHash({ password }); @@ -73,7 +73,7 @@ describe('Crypto service', () => { expect(hashedPassword.salt.length).to.be.equal(32); }); - it('When auth keys are generated using CryptoProvider, then they are generated using KeysService', async () => { + test('when encryption keys are generated, then they include public and private key components', async () => { const password = crypto.randomBytes(8).toString('hex'); const keysReturned = { privateKeyArmored: crypto.randomBytes(16).toString('hex'), @@ -111,7 +111,7 @@ describe('Crypto service', () => { * * We migrated from CryptoJS to node:crypto. This test ensures that the new implementation works the same as the old one. */ - it('The node:crypto works the same as CryptoJS library', () => { + test('when using the native cryptography module, then the results match the legacy library behavior', () => { /* const password = { value: crypto.randomBytes(16).toString('hex'), diff --git a/test/services/database/database.service.test.ts b/test/services/database/database.service.test.ts index 1a8c06d3..8d0dfc36 100644 --- a/test/services/database/database.service.test.ts +++ b/test/services/database/database.service.test.ts @@ -1,12 +1,12 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { DatabaseService } from '../../../src/services/database/database.service'; import { DriveItemModel } from '../../../src/services/database/drive-item/drive-item.model'; import { ConfigService } from '../../../src/services/config.service'; import { DRIVE_SQLITE_FILE } from '../../../src/constants/configs'; -describe('DatabaseService', () => { +describe('Database Service', () => { describe('dataSource configuration', () => { - it('should configure sqljs when NODE_ENV is test', () => { + test('when the environment is set to test, then the in-memory database is configured', () => { const configServiceInstancespyOn = vi.spyOn(ConfigService.instance, 'get'); configServiceInstancespyOn.mockReturnValueOnce('test'); @@ -18,7 +18,7 @@ describe('DatabaseService', () => { expect(configServiceInstancespyOn).toHaveBeenCalledWith('NODE_ENV', false); }); - it('should configure better-sqlite3 when NODE_ENV is not test', () => { + test('when the environment is not test, then a file-based database is configured', () => { const configServiceInstancespyOn = vi.spyOn(ConfigService.instance, 'get'); configServiceInstancespyOn.mockReturnValueOnce('production'); @@ -33,7 +33,7 @@ describe('DatabaseService', () => { }); describe('Integration scenarios', () => { - it('should handle initialize, clear, and destroy sequence', async () => { + test('when the database is initialized, cleared, and destroyed, then the sequence completes successfully', async () => { const configServiceInstancespyOn = vi.spyOn(ConfigService.instance, 'get'); configServiceInstancespyOn.mockReturnValueOnce('test'); diff --git a/test/services/database/drive-item/drive-item.repository.test.ts b/test/services/database/drive-item/drive-item.repository.test.ts index 7f50dafc..5967273e 100644 --- a/test/services/database/drive-item/drive-item.repository.test.ts +++ b/test/services/database/drive-item/drive-item.repository.test.ts @@ -1,9 +1,9 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { DriveItemRepository } from '../../../../src/services/database/drive-item/drive-item.repository'; import { DriveItemBD } from '../../../../src/services/database/drive-item/drive-item.domain'; -describe('DriveItemRepository', () => { - it('should create and retrieve an item via createOrUpdate', async () => { +describe('Drive Item Repository', () => { + test('when an item is saved, then it can be retrieved', async () => { const mockItem = { uuid: 'uuid-1', path: '/folder/file.txt', @@ -22,7 +22,7 @@ describe('DriveItemRepository', () => { expect(item?.type).toBe('file'); }); - it('should update an existing item when uuid matches', async () => { + test('when an existing item is updated, then the changes are saved', async () => { const items = [ { uuid: 'uuid-1', path: '/old/path.txt', type: 'file' as const, createdAt: new Date(), updatedAt: new Date() }, ]; @@ -43,7 +43,7 @@ describe('DriveItemRepository', () => { expect(createOrUpdateSpy).toHaveBeenCalledTimes(2); }); - it('should retrieve an item by uuid', async () => { + test('when an item is requested by its identifier, then it is returned', async () => { const driveItem = new DriveItemBD({ uuid: 'uuid-1', path: '/folder/', @@ -58,19 +58,19 @@ describe('DriveItemRepository', () => { expect(item?.uuid).toBe('uuid-1'); }); - it('should return undefined when item not found by path', async () => { + test('when no item matches the given path, then undefined is returned', async () => { vi.spyOn(DriveItemRepository.instance, 'getByPath').mockResolvedValue(undefined); const item = await DriveItemRepository.instance.getByPath('/nonexistent'); expect(item).toBeUndefined(); }); - it('should return undefined when item not found by uuid', async () => { + test('when no item matches the given identifier, then undefined is returned', async () => { vi.spyOn(DriveItemRepository.instance, 'getByUuid').mockResolvedValue(undefined); const item = await DriveItemRepository.instance.getByUuid('nonexistent-uuid'); expect(item).toBeUndefined(); }); - it('should delete items by uuids', async () => { + test('when items are removed by their identifiers, then they are no longer available', async () => { const allItems = [ new DriveItemBD({ uuid: 'uuid-1', @@ -96,7 +96,7 @@ describe('DriveItemRepository', () => { expect(remaining[0].uuid).toBe('uuid-2'); }); - it('should return all items', async () => { + test('when all stored items are requested, then they are returned', async () => { const allItems = [ new DriveItemBD({ uuid: 'uuid-1', @@ -119,7 +119,7 @@ describe('DriveItemRepository', () => { expect(result).toHaveLength(2); }); - it('should update items by path when uuid differs', async () => { + test('when an item at a given path is replaced with a different identifier, then the update is saved', async () => { const items = [ { uuid: 'uuid-1', path: '/same/path.txt', type: 'file' as const, createdAt: new Date(), updatedAt: new Date() }, ]; @@ -138,7 +138,7 @@ describe('DriveItemRepository', () => { expect(item?.uuid).toBe('uuid-2'); }); - it('should update an item by uuid with partial data', async () => { + test('when an item is partially updated, then only the specified fields change', async () => { const updatedPath = '/renamed.txt'; vi.spyOn(DriveItemRepository.instance, 'updateByUuid').mockResolvedValue(undefined); vi.spyOn(DriveItemRepository.instance, 'getByUuid').mockResolvedValue( @@ -157,7 +157,7 @@ describe('DriveItemRepository', () => { expect(item?.path).toBe(updatedPath); }); - it('should return DriveItem instances from all methods', async () => { + test('when items are returned, then they have the expected structure', async () => { const driveItem = new DriveItemBD({ uuid: 'uuid-1', path: '/file.txt', diff --git a/test/services/drive/drive-file.service.test.ts b/test/services/drive/drive-file.service.test.ts index c4bec013..44096bbf 100644 --- a/test/services/drive/drive-file.service.test.ts +++ b/test/services/drive/drive-file.service.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { DriveFileService } from '../../../src/services/drive/drive-file.service'; import { SdkManager } from '../../../src/services/sdk-manager.service'; import Storage, { DriveFileData, EncryptionVersion } from '@internxt/sdk/dist/drive/storage/types'; @@ -16,7 +16,7 @@ describe('Drive file Service', () => { vi.spyOn(ConfigService.instance, 'saveUser').mockResolvedValue(undefined); }); - it('When a file is created, should be created successfully', async () => { + test('when a file entry is created, then it is created successfully', async () => { const payload: Storage.FileEntryByUuid = { plainName: 'example.txt', type: 'txt', @@ -49,7 +49,7 @@ describe('Drive file Service', () => { expect(result.folderUuid).to.be.equal(payload.folderUuid); }); - it('When we want to obtain a file metadata, should return it successfully', async () => { + test('when file metadata is requested, then it is returned successfully', async () => { const fakeFileData: DriveFileData = { uuid: randomUUID(), bucket: CommonFixture.createObjectId(), diff --git a/test/services/drive/drive-folder.service.test.ts b/test/services/drive/drive-folder.service.test.ts index 7f99c639..e12fa1f2 100644 --- a/test/services/drive/drive-folder.service.test.ts +++ b/test/services/drive/drive-folder.service.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { randomUUID } from 'node:crypto'; import { Storage } from '@internxt/sdk/dist/drive'; import { DriveFolderService } from '../../../src/services/drive/drive-folder.service'; @@ -9,7 +9,7 @@ import { CreateFolderResponse, FetchPaginatedFile, FetchPaginatedFolder } from ' import { ConfigService } from '../../../src/services/config.service'; import { UserCredentialsFixture } from '../../fixtures/login.fixture'; -describe('Drive folder Service', () => { +describe('Drive Folder Service', () => { const sut = DriveFolderService.instance; beforeEach(() => { @@ -17,7 +17,7 @@ describe('Drive folder Service', () => { vi.spyOn(ConfigService.instance, 'saveUser').mockResolvedValue(undefined); }); - it('When folder metadata is requested by UUID, it is aquired successfully', async () => { + test('when folder metadata is requested by its identifier, then it is acquired successfully', async () => { const expectedFolderMeta = newFolderMeta(); const expectedFolderItem = DriveUtils.driveFolderMetaToItem(expectedFolderMeta); @@ -30,7 +30,7 @@ describe('Drive folder Service', () => { expect(spy).toHaveBeenCalledWith(expectedFolderMeta.uuid); }); - it('When folder metadata is requested by ID, it is aquired successfully', async () => { + test('when folder metadata is requested by its internal identifier, then it is acquired successfully', async () => { const expectedFolderMeta = newFolderMeta(); const expectedFolderItem = DriveUtils.driveFolderMetaToItem(expectedFolderMeta); @@ -43,7 +43,7 @@ describe('Drive folder Service', () => { expect(spy).toHaveBeenCalledWith(expectedFolderMeta.id); }); - it('When folder content is requested, then all its subfolders and subfiles are returned', async () => { + test('when folder content is requested, then all its subfolders and subfiles are returned', async () => { const parentUuid = randomUUID(); const subContentFixture = generateSubcontent(parentUuid, 112, 117); //112 subfolders and 117 subfiles const requestCancelerMock = { cancel: () => {} }; @@ -81,7 +81,7 @@ describe('Drive folder Service', () => { expect(subContentFixture).to.deep.equal(resultContent); }); - it('When a folder is created, the new folder and a request canceler are returned', async () => { + test('when a folder is created, then the new folder and a request canceler are returned', async () => { const newFolderResponse = newCreateFolderResponse(); vi.spyOn(Storage.prototype, 'createFolderByUuid').mockReturnValue([ diff --git a/test/services/drive/drive-item.service.test.ts b/test/services/drive/drive-item.service.test.ts index fefded6e..de712dec 100644 --- a/test/services/drive/drive-item.service.test.ts +++ b/test/services/drive/drive-item.service.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { DriveItemService } from '../../../src/services/drive/drive-item.service'; import { DriveItemRepository } from '../../../src/services/database/drive-item/drive-item.repository'; import { DriveItemBD } from '../../../src/services/database/drive-item/drive-item.domain'; @@ -7,11 +7,11 @@ import { DriveFolderService } from '../../../src/services/drive/drive-folder.ser import { newFileItem, newFolderItem } from '../../fixtures/drive.fixture'; import { NotFoundError } from '../../../src/utils/errors.utils'; -describe('DriveItemService', () => { +describe('Drive Item Service', () => { const sut = DriveItemService.instance; - describe('getFileByPath', () => { - it('should return file from cache when cached and API succeeds', async () => { + describe('getting a file by path', () => { + test('when the file is in cache and the API responds, then the cached file is returned', async () => { const path = '/test/file.txt'; const cachedItem = new DriveItemBD({ uuid: 'cached-uuid', @@ -32,7 +32,7 @@ describe('DriveItemService', () => { expect(createOrUpdateSpy).toHaveBeenCalled(); }); - it('should throw NotFoundError when cached file status is not EXISTS', async () => { + test('when the cached file is no longer available on the server, then a not found error is thrown', async () => { const path = '/test/file.txt'; const cachedItem = new DriveItemBD({ uuid: 'cached-uuid', @@ -54,7 +54,7 @@ describe('DriveItemService', () => { expect(deleteSpy).toHaveBeenCalledWith(['cached-uuid']); }); - it('should fallback to path lookup when cached API call throws and path succeeds', async () => { + test('when the cached lookup fails but the path lookup succeeds, then the file is resolved via the path', async () => { const path = '/test/file.txt'; const cachedItem = new DriveItemBD({ uuid: 'cached-uuid', @@ -80,7 +80,7 @@ describe('DriveItemService', () => { expect(createOrUpdateSpy).toHaveBeenCalled(); }); - it('should throw NotFoundError when cache and fallback both fail', async () => { + test('when both cache and path lookup fail, then a not found error is thrown', async () => { const path = '/test/file.txt'; const cachedItem = new DriveItemBD({ uuid: 'cached-uuid', @@ -97,7 +97,7 @@ describe('DriveItemService', () => { await expect(sut.getFileByPath(path)).rejects.toThrow('File not found at path'); }); - it('should cache and return file from path lookup when no cache exists', async () => { + test('when there is no cached file and the path lookup succeeds, then the file is cached and returned', async () => { const path = '/test/file.txt'; vi.spyOn(DriveItemRepository.instance, 'getByPath').mockResolvedValue(undefined); @@ -111,7 +111,7 @@ describe('DriveItemService', () => { expect(createOrUpdateSpy).toHaveBeenCalled(); }); - it('should throw NotFoundError when path lookup fails with no cache', async () => { + test('when there is no cache and the path lookup fails, then a not found error is thrown', async () => { const path = '/test/nonexistent.txt'; vi.spyOn(DriveItemRepository.instance, 'getByPath').mockResolvedValue(undefined); vi.spyOn(DriveFileService.instance, 'getFileMetadataByPath').mockRejectedValue(new Error('Not found')); @@ -119,7 +119,7 @@ describe('DriveItemService', () => { await expect(sut.getFileByPath(path)).rejects.toThrow('File not found at path'); }); - it('should throw NotFoundError when path lookup returns non-EXISTS status', async () => { + test('when the path lookup returns a non-existing status, then a not found error is thrown', async () => { const path = '/test/file.txt'; vi.spyOn(DriveItemRepository.instance, 'getByPath').mockResolvedValue(undefined); vi.spyOn(DriveFileService.instance, 'getFileMetadataByPath').mockRejectedValue( @@ -130,8 +130,8 @@ describe('DriveItemService', () => { }); }); - describe('getFolderByPath', () => { - it('should return folder from cache when cached and API succeeds', async () => { + describe('getting a folder by path', () => { + test('when the folder is in cache and the API responds, then the cached folder is returned', async () => { const path = '/test/folder/'; const cachedItem = new DriveItemBD({ uuid: 'cached-uuid', @@ -152,7 +152,7 @@ describe('DriveItemService', () => { expect(createOrUpdateSpy).toHaveBeenCalled(); }); - it('should throw NotFoundError when cached folder status is not EXISTS', async () => { + test('when the cached folder is no longer available on the server, then a not found error is thrown', async () => { const path = '/test/folder/'; const cachedItem = new DriveItemBD({ uuid: 'cached-uuid', @@ -174,7 +174,7 @@ describe('DriveItemService', () => { expect(deleteSpy).toHaveBeenCalledWith(['cached-uuid']); }); - it('should fallback to path lookup when cached folder API throws and path succeeds', async () => { + test('when the cached lookup fails but the path lookup succeeds, then the folder is resolved via the path', async () => { const path = '/test/folder/'; const cachedItem = new DriveItemBD({ uuid: 'cached-uuid', @@ -200,7 +200,7 @@ describe('DriveItemService', () => { expect(createOrUpdateSpy).toHaveBeenCalled(); }); - it('should throw NotFoundError when folder cache and fallback both fail', async () => { + test('when both cache and path lookup fail, then a not found error is thrown', async () => { const path = '/test/folder/'; const cachedItem = new DriveItemBD({ uuid: 'cached-uuid', @@ -217,7 +217,7 @@ describe('DriveItemService', () => { await expect(sut.getFolderByPath(path)).rejects.toThrow('Folder not found at path'); }); - it('should cache and return folder from path lookup when no cache exists', async () => { + test('when there is no cached folder and the path lookup succeeds, then the folder is cached and returned', async () => { const path = '/test/folder/'; vi.spyOn(DriveItemRepository.instance, 'getByPath').mockResolvedValue(undefined); @@ -231,7 +231,7 @@ describe('DriveItemService', () => { expect(createOrUpdateSpy).toHaveBeenCalled(); }); - it('should throw NotFoundError when folder path lookup fails with no cache', async () => { + test('when there is no cache and the path lookup fails, then a not found error is thrown', async () => { const path = '/test/nonexistent/'; vi.spyOn(DriveItemRepository.instance, 'getByPath').mockResolvedValue(undefined); vi.spyOn(DriveFolderService.instance, 'getFolderMetaByPath').mockRejectedValue(new Error('Not found')); @@ -239,7 +239,7 @@ describe('DriveItemService', () => { await expect(sut.getFolderByPath(path)).rejects.toThrow('Folder not found at path'); }); - it('should throw NotFoundError when folder path lookup returns non-EXISTS status', async () => { + test('when the path lookup returns a non-existing status, then a not found error is thrown', async () => { const path = '/test/folder/'; vi.spyOn(DriveItemRepository.instance, 'getByPath').mockResolvedValue(undefined); vi.spyOn(DriveFolderService.instance, 'getFolderMetaByPath').mockRejectedValue( diff --git a/test/services/keys.service.test.ts b/test/services/keys.service.test.ts index 954cc18c..91d398fd 100644 --- a/test/services/keys.service.test.ts +++ b/test/services/keys.service.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import crypto from 'node:crypto'; import * as openpgp from 'openpgp'; import { KeysService } from '../../src/services/keys.service'; @@ -13,7 +13,7 @@ describe('Keys service', () => { salt: crypto.randomBytes(64).toString('hex'), }; - it('When message is encrypted with private key & password, then it can be decrypted using same data', async () => { + test('when a private key is encrypted with a password, then it can be decrypted with the same password', async () => { const plainPrivateKey = crypto.randomBytes(16).toString('hex'); const password = crypto.randomBytes(8).toString('hex'); @@ -27,7 +27,7 @@ describe('Keys service', () => { expect(decryptedPrivateKey).to.be.equal(plainPrivateKey); }); - it('When new pgp keys are required, then it generates them from the openpgp library', async () => { + test('when new encryption keys are needed, then they are generated using the cryptography library', async () => { interface KeyPair { privateKey: openpgp.PrivateKey; publicKey: openpgp.PublicKey; diff --git a/test/services/local-filesystem/local-filesystem.service.test.ts b/test/services/local-filesystem/local-filesystem.service.test.ts index 509cef4a..f944ce3f 100644 --- a/test/services/local-filesystem/local-filesystem.service.test.ts +++ b/test/services/local-filesystem/local-filesystem.service.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi, MockedFunction } from 'vitest'; +import { beforeEach, describe, expect, test, vi, MockedFunction } from 'vitest'; import { LocalFilesystemService } from '../../../src/services/local-filesystem/local-filesystem.service'; import { Dirent, promises, Stats } from 'node:fs'; import { logger } from '../../../src/utils/logger.utils'; @@ -36,8 +36,8 @@ describe('Local Filesystem Service', () => { mockReaddir.mockResolvedValue([]); }); - describe('scanRecursive', () => { - it('should handle a single file', async () => { + describe('scanning recursively', () => { + test('when scanning a single file, then it is processed correctly', async () => { mockStat.mockResolvedValue(createMockStats(true, 100)); const folders: FileSystemNode[] = []; @@ -49,7 +49,7 @@ describe('Local Filesystem Service', () => { expect(folders).toHaveLength(0); }); - it('should handle an empty directory', async () => { + test('when scanning an empty directory, then it is processed correctly', async () => { mockStat.mockResolvedValue(createMockStats(false, 0)); mockReaddir.mockResolvedValue([]); @@ -66,7 +66,7 @@ describe('Local Filesystem Service', () => { expect(files).toHaveLength(0); }); - it('should handle a directory with files', async () => { + test('when scanning a directory with files, then they are all processed correctly', async () => { mockStat .mockResolvedValueOnce(createMockStats(false, 0)) .mockResolvedValueOnce(createMockStats(true, 50)) @@ -83,7 +83,7 @@ describe('Local Filesystem Service', () => { expect(files).toHaveLength(2); }); - it('should skip symbolic links', async () => { + test('when a symbolic link is encountered, then it is skipped', async () => { mockStat.mockResolvedValueOnce(createMockStats(false, 0)).mockResolvedValueOnce(createMockStats(true, 100)); mockReaddir.mockResolvedValueOnce([createMockDirent('symlink', true), createMockDirent('file.txt', false)]); @@ -95,7 +95,7 @@ describe('Local Filesystem Service', () => { expect(files).toHaveLength(1); }); - it('should handle errors gracefully', async () => { + test('when a permission error occurs, then it is handled gracefully', async () => { mockStat.mockRejectedValue(new Error('Permission denied')); const folders: FileSystemNode[] = []; @@ -106,7 +106,7 @@ describe('Local Filesystem Service', () => { expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Permission denied')); }); - it('should handle nested directories', async () => { + test('when scanning nested directories, then they are all processed correctly', async () => { mockStat .mockResolvedValueOnce(createMockStats(false, 0)) .mockResolvedValueOnce(createMockStats(false, 0)) @@ -125,7 +125,7 @@ describe('Local Filesystem Service', () => { expect(folders).toHaveLength(2); expect(files).toHaveLength(1); }); - it('should properly skip empty files', async () => { + test('when an empty file is encountered, then it is skipped', async () => { mockStat .mockResolvedValueOnce(createMockStats(false, 0)) .mockResolvedValueOnce(createMockStats(true, 0)) @@ -140,8 +140,8 @@ describe('Local Filesystem Service', () => { expect(files).toHaveLength(1); }); }); - describe('scanLocalDirectory', () => { - it('should scan a directory and return complete results', async () => { + describe('scanning a local directory', () => { + test('when a directory is scanned, then complete results are returned', async () => { mockStat.mockResolvedValueOnce(createMockStats(false, 0)).mockResolvedValueOnce(createMockStats(true, 100)); mockReaddir.mockResolvedValueOnce([createMockDirent('file.txt', false)]); diff --git a/test/services/network/download.service.test.ts b/test/services/network/download.service.test.ts index b39e0e2d..720b5a23 100644 --- a/test/services/network/download.service.test.ts +++ b/test/services/network/download.service.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { DownloadService } from '../../../src/services/network/download.service'; import { Readable } from 'node:stream'; import axios from 'axios'; @@ -6,7 +6,7 @@ import axios from 'axios'; describe('Download Service', () => { const sut = DownloadService.instance; - it('When a file is downloaded, should return a ReadableStream', async () => { + test('when a file is downloaded, then a readable stream is returned', async () => { const fileContent = Buffer.from('file-content'); const readableContent = new Readable({ read() { @@ -25,7 +25,7 @@ describe('Download Service', () => { expect(read.value).to.deep.equal(fileContent); }); - it('When a file is downloaded, progress should be reported', async () => { + test('when a file is downloaded, then progress is reported', async () => { const fileContent = Buffer.from('file-content'); const options = { progressCallback: vi.fn(), diff --git a/test/services/network/network-facade.service.test.ts b/test/services/network/network-facade.service.test.ts index 18cc2eee..7dd57dbb 100644 --- a/test/services/network/network-facade.service.test.ts +++ b/test/services/network/network-facade.service.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { NetworkFacade } from '../../../src/services/network/network-facade.service'; import { SdkManager } from '../../../src/services/sdk-manager.service'; import path from 'node:path'; @@ -30,7 +30,7 @@ describe('Network Facade Service', () => { }); }; - it('Should call the inxt-js upload functionality when a file is uploaded', async () => { + test('when a file is uploaded, then the upload functionality is called', async () => { const mockEnvironment = { upload: vi.fn(), }; @@ -59,7 +59,7 @@ describe('Network Facade Service', () => { expect(mockEnvironment.upload).toHaveBeenCalledOnce(); }); - it('Should throw an error when a file exceeds maxUploadFileSize limit', async () => { + test('when a file exceeds the account upload size limit, then an error is thrown', async () => { const mockEnvironment = { upload: vi.fn(), }; @@ -87,7 +87,7 @@ describe('Network Facade Service', () => { expect(mockEnvironment.upload).not.toHaveBeenCalled(); }); - it('Should throw an error when a file exceeds 100 GB', async () => { + test('when a file exceeds the maximum allowed size, then an error is thrown', async () => { const mockEnvironment = { upload: vi.fn(), }; @@ -115,7 +115,7 @@ describe('Network Facade Service', () => { expect(mockEnvironment.upload).not.toHaveBeenCalled(); }); - it('Should enforce API limit over 100 GB hard cap when maxUploadFileSize is smaller', async () => { + test('when the account limit is stricter than the maximum allowed size, then the account limit is enforced', async () => { const mockEnvironment = { upload: vi.fn(), }; @@ -143,7 +143,7 @@ describe('Network Facade Service', () => { expect(mockEnvironment.upload).not.toHaveBeenCalled(); }); - it('Should proceed with upload when file size is within maxUploadFileSize limit', async () => { + test('when a file is within the allowed size limit, then the upload proceeds', async () => { const mockEnvironment = { upload: vi.fn(), }; @@ -169,7 +169,7 @@ describe('Network Facade Service', () => { expect(mockEnvironment.upload).toHaveBeenCalledOnce(); }); - it('Should write a downloaded file to a stream', async () => { + test('when a file is downloaded, then it is written to a stream', async () => { const encryptedContent = Buffer.from('b6ccfa381c150f3a4b65245bffa4d84087', 'hex'); const bucket = 'cd8abd7e8b13081660b58dbe'; const readableContent = new ReadableStream({ @@ -208,7 +208,6 @@ describe('Network Facade Service', () => { const [executeDownload] = await sut.downloadToStream( bucket, - // eslint-disable-next-line max-len 'index course habit soon assist dragon tragic helmet salute stuff later twice consider grit pulse cement obvious trick sponsor stereo hello win royal more', 'f1858bc9675f9e4f7ab29429', encryptedContent.length, @@ -221,7 +220,7 @@ describe('Network Facade Service', () => { expect(fileContent.toString('utf-8')).to.be.equal('encrypted-content'); }); - it('Should abort the download when requested', async () => { + test('when the download is aborted, then the operation is cancelled', async () => { const encryptedContent = Buffer.from('b6ccfa381c150f3a4b65245bffa4d84087', 'hex'); const bucket = 'cd8abd7e8b13081660b58dbe'; const readableContent = new ReadableStream({ @@ -254,7 +253,6 @@ describe('Network Facade Service', () => { const [executeDownload, abort] = await sut.downloadToStream( bucket, - // eslint-disable-next-line max-len 'index course habit soon assist dragon tragic helmet salute stuff later twice consider grit pulse cement obvious trick sponsor stereo hello win royal more', 'f1858bc9675f9e4f7ab29429', encryptedContent.length, @@ -270,7 +268,7 @@ describe('Network Facade Service', () => { } }); - it('Should report download progress when a file is downloaded', async () => { + test('when a file is downloaded, then download progress is reported', async () => { const encryptedContent = Buffer.from('b6ccfa381c150f3a4b65245bffa4d84087', 'hex'); const bucket = 'cd8abd7e8b13081660b58dbe'; @@ -316,7 +314,6 @@ describe('Network Facade Service', () => { const [executeDownload] = await sut.downloadToStream( bucket, - // eslint-disable-next-line max-len 'index course habit soon assist dragon tragic helmet salute stuff later twice consider grit pulse cement obvious trick sponsor stereo hello win royal more', 'f1858bc9675f9e4f7ab29429', encryptedContent.length, diff --git a/test/services/network/upload/upload-facade.service.test.ts b/test/services/network/upload/upload-facade.service.test.ts index ca36d77f..63404134 100644 --- a/test/services/network/upload/upload-facade.service.test.ts +++ b/test/services/network/upload/upload-facade.service.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, it, vi, expect } from 'vitest'; +import { beforeEach, describe, test, vi, expect } from 'vitest'; import { UploadFacade } from '../../../../src/services/network/upload/upload-facade.service'; import { CLIUtils } from '../../../../src/utils/cli.utils'; import { logger } from '../../../../src/utils/logger.utils'; @@ -11,7 +11,7 @@ import { AsyncUtils } from '../../../../src/utils/async.utils'; import { UserFixture } from '../../../fixtures/auth.fixture'; import { getNetworkOptionsMock } from '../../../fixtures/webdav.fixture'; -describe('UploadFacade', () => { +describe('Upload Facade', () => { let sut: UploadFacade; const mockNetworkOptions = getNetworkOptionsMock(); @@ -45,12 +45,12 @@ describe('UploadFacade', () => { vi.spyOn(logger, 'info').mockImplementation(vi.fn()); }); - describe('uploadFolder', () => { + describe('uploading a folder', () => { const localPath = '/local/test-folder'; const destinationFolderUuid = 'dest-uuid'; const onProgress = vi.fn(); - it('should throw an error if createFolders returns an empty map', async () => { + test('when folder creation returns no results, then an error is thrown', async () => { vi.spyOn(LocalFilesystemService.instance, 'scanLocalDirectory').mockResolvedValue({ folders: [createFileSystemNodeFixture({ type: 'folder', name: 'test', relativePath: 'test' })], files: [], @@ -76,7 +76,7 @@ describe('UploadFacade', () => { expect(UploadFileService.instance.uploadFilesConcurrently).not.toHaveBeenCalled(); }); - it('should properly handle the upload of folder and the creation of file and return proper result', async () => { + test('when a folder is uploaded with files, then the correct result is returned', async () => { const reporter = vi.fn(); const result = await sut.uploadFolder({ localPath, @@ -99,7 +99,7 @@ describe('UploadFacade', () => { ); }); - it('should report progress correctly during upload', async () => { + test('when uploading, then progress is reported correctly', async () => { const folderMap = new Map([[folderName, 'folder-uuid-123']]); vi.spyOn(UploadFolderService.instance, 'createFolders').mockImplementation( @@ -134,7 +134,7 @@ describe('UploadFacade', () => { expect(onProgress).toHaveBeenNthCalledWith(2, { percentage: 100 }); }); - it('should wait 500ms between folder creation and file upload to prevent backend indexing issues', async () => { + test('when folders are created before uploading files, then the system waits to prevent indexing issues', async () => { vi.useFakeTimers(); vi.spyOn(UploadFolderService.instance, 'createFolders').mockResolvedValue(folderMap); diff --git a/test/services/network/upload/upload-file.service.test.ts b/test/services/network/upload/upload-file.service.test.ts index 71dc40fd..4d503289 100644 --- a/test/services/network/upload/upload-file.service.test.ts +++ b/test/services/network/upload/upload-file.service.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, it, vi, expect } from 'vitest'; +import { beforeEach, describe, test, vi, expect } from 'vitest'; import { UploadFileService } from '../../../../src/services/network/upload/upload-file.service'; import { NetworkFacade } from '../../../../src/services/network/network-facade.service'; import { DriveFileService } from '../../../../src/services/drive/drive-file.service'; @@ -24,7 +24,7 @@ vi.mock('fs/promises', () => ({ stat: vi.fn(), })); -describe('UploadFileService', () => { +describe('Upload File Service', () => { let sut: UploadFileService; const mockFile = newFileItem({ fileId: 'mock-uploaded-file-id' }); @@ -46,12 +46,12 @@ describe('UploadFileService', () => { vi.spyOn(DriveFileService.instance, 'createFile').mockResolvedValue(mockFile); }); - describe('uploadFilesConcurrently', () => { + describe('uploading files concurrently', () => { const bucket = 'test-bucket'; const destinationFolderUuid = 'dest-uuid'; const folderMap = new Map(); - it('should properly return the total amount of bytes uploaded once finished with the uploads', async () => { + test('when all files finish uploading, then the total bytes uploaded is returned', async () => { const files = [ createFileSystemNodeFixture({ type: 'file', name: 'file1.txt', relativePath: 'file1.txt', size: 100 }), createFileSystemNodeFixture({ type: 'file', name: 'file2.txt', relativePath: 'file2.txt', size: 200 }), @@ -78,7 +78,7 @@ describe('UploadFileService', () => { uploadFileWithRetrySpy.mockRestore(); }); - it('should properly upload files in arrays of max 10', async () => { + test('when there are more than ten files to upload, then they are processed in batches', async () => { const files = Array.from({ length: 12 }, (_, i) => createFileSystemNodeFixture({ type: 'file', @@ -116,7 +116,7 @@ describe('UploadFileService', () => { concurrencyArraySpy.mockRestore(); }); - it('should properly emit progress and update the currentProgress object', async () => { + test('when files are uploaded, then progress is emitted and updated', async () => { const files = [ createFileSystemNodeFixture({ type: 'file', name: 'file1.txt', relativePath: 'file1.txt', size: 500 }), createFileSystemNodeFixture({ type: 'file', name: 'file2.txt', relativePath: 'file2.txt', size: 1000 }), @@ -143,7 +143,7 @@ describe('UploadFileService', () => { uploadFileWithRetrySpy.mockRestore(); }); - it('should skip files when parent folder is not found in folderMap', async () => { + test('when a parent folder is not found, then the file is skipped', async () => { const bucket = 'test-bucket'; const destinationFolderUuid = 'dest-uuid'; const folderMap = new Map(); @@ -183,11 +183,11 @@ describe('UploadFileService', () => { }); }); - describe('uploadFileWithRetry', () => { + describe('uploading a file with retry', () => { const bucket = 'test-bucket'; const destinationFolderUuid = 'dest-uuid'; - it('should properly create a file and return the created file', async () => { + test('when a file is uploaded, then the created file entry is returned', async () => { const file = createFileSystemNodeFixture({ type: 'file', name: 'test', @@ -226,7 +226,7 @@ describe('UploadFileService', () => { ); }); - it('should retry a maximum of 2 retries (3 total attempts) if an exception is thrown while uploading', async () => { + test('when an error occurs during upload, then up to three attempts are made', async () => { vi.useFakeTimers(); const file = createFileSystemNodeFixture({ type: 'file', @@ -263,7 +263,7 @@ describe('UploadFileService', () => { vi.useRealTimers(); }); - it('should upload empty files and return the created file', async () => { + test('when an empty file is uploaded, then the file entry is still created', async () => { const file = createFileSystemNodeFixture({ type: 'file', name: 'empty', @@ -299,7 +299,7 @@ describe('UploadFileService', () => { ); }); - it('should call tryUploadThumbnail when bufferStream is present', async () => { + test('when a thumbnailable file is uploaded, then a thumbnail is generated', async () => { const mockBufferStream = { getBuffer: vi.fn() }; vi.spyOn(ThumbnailService.instance, 'createFileStreamWithBuffer').mockReturnValue({ fileStream: createMockReadStream() as ReturnType, @@ -334,7 +334,7 @@ describe('UploadFileService', () => { }); }); - it('should return null when file already exists', async () => { + test('when the file already exists, then null is returned', async () => { vi.spyOn(ErrorUtils, 'isAlreadyExistsError').mockReturnValue(true); vi.mocked(mockNetworkFacade.uploadFile).mockRejectedValue(new Error('File already exists')); @@ -358,7 +358,7 @@ describe('UploadFileService', () => { expect(logger.info).toHaveBeenCalledWith('File duplicate.txt already exists, skipping...'); }); - it('should return null after max retries exceeded', async () => { + test('when all upload attempts fail, then null is returned', async () => { vi.useFakeTimers(); const file = createFileSystemNodeFixture({ type: 'file', diff --git a/test/services/network/upload/upload-folder.service.test.ts b/test/services/network/upload/upload-folder.service.test.ts index 42a9ea70..e45c135c 100644 --- a/test/services/network/upload/upload-folder.service.test.ts +++ b/test/services/network/upload/upload-folder.service.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, onTestFinished, vi } from 'vitest'; +import { beforeEach, describe, expect, test, onTestFinished, vi } from 'vitest'; import { DriveFolderService } from '../../../../src/services/drive/drive-folder.service'; import { UploadFolderService } from '../../../../src/services/network/upload/upload-folder.service'; import { logger } from '../../../../src/utils/logger.utils'; @@ -6,7 +6,7 @@ import { ErrorUtils } from '../../../../src/utils/errors.utils'; import { createFileSystemNodeFixture, createProgressFixtures } from './upload.service.helpers'; import { DELAYS_MS } from '../../../../src/services/network/upload/upload.types'; -describe('UploadFolderService', () => { +describe('Upload Folder Service', () => { let sut: UploadFolderService; beforeEach(() => { @@ -17,10 +17,10 @@ describe('UploadFolderService', () => { vi.spyOn(ErrorUtils, 'isAlreadyExistsError').mockReturnValue(false); }); - describe('createFolders', () => { + describe('creating multiple folders', () => { const destinationFolderUuid = 'dest-uuid'; - it('should properly return a map of created folders where key is relativePath and value is uuid', async () => { + test('when folders are created, then a mapping of paths to identifiers is returned', async () => { const { currentProgress, emitProgress } = createProgressFixtures(); vi.spyOn(DriveFolderService.instance, 'createFolder') .mockReturnValueOnce([Promise.resolve({ uuid: 'root-uuid' })] as unknown as ReturnType< @@ -47,7 +47,7 @@ describe('UploadFolderService', () => { expect(result.get('root/subfolder')).toBe('subfolder-uuid'); }); - it('should properly skip over folders that dont have a parentUuid', async () => { + test('when a folder has no known parent, then it is skipped', async () => { const { currentProgress, emitProgress } = createProgressFixtures(); const result = await sut.createFolders({ @@ -66,7 +66,7 @@ describe('UploadFolderService', () => { expect(DriveFolderService.instance.createFolder).not.toHaveBeenCalled(); }); - it('should properly set as parent folder the destinationFolderUuid for base folder', async () => { + test('when creating a top-level folder, then the destination folder is set as its parent', async () => { const { currentProgress, emitProgress } = createProgressFixtures(); await sut.createFolders({ @@ -84,7 +84,7 @@ describe('UploadFolderService', () => { }); }); - it('should properly update the progress on successful folder creation', async () => { + test('when a folder is created successfully, then the progress is updated', async () => { const { currentProgress, emitProgress } = createProgressFixtures(); await sut.createFolders({ @@ -101,11 +101,11 @@ describe('UploadFolderService', () => { }); }); - describe('createFolderWithRetry', () => { + describe('creating a folder with retry', () => { const folderName = 'test-folder'; const parentFolderUuid = 'parent-uuid'; - it('should properly create a folder and return the created folder uuid', async () => { + test('when a folder is created, then its identifier is returned', async () => { vi.spyOn(DriveFolderService.instance, 'createFolder').mockReturnValueOnce([ Promise.resolve({ uuid: 'created-folder-uuid' }), ] as unknown as ReturnType); @@ -124,7 +124,7 @@ describe('UploadFolderService', () => { }); }); - it('should properly return null if the folder already exists', async () => { + test('when the folder already exists, then null is returned', async () => { const alreadyExistsError = new Error('Folder already exists'); vi.spyOn(ErrorUtils, 'isAlreadyExistsError').mockReturnValue(true); vi.spyOn(DriveFolderService.instance, 'createFolder').mockRejectedValue(alreadyExistsError); @@ -140,7 +140,7 @@ describe('UploadFolderService', () => { expect(logger.warn).toHaveBeenCalledWith(`Folder ${folderName} already exists, skipping...`); }); - it('should properly retry up to 3 times when error caught', async () => { + test('when a transient error occurs during creation, then up to three retries are attempted', async () => { vi.useFakeTimers(); const transientError = new Error('Network error'); @@ -176,7 +176,7 @@ describe('UploadFolderService', () => { vi.useRealTimers(); }); - it('should properly throw an error when multiple unsuccessfull retries', async () => { + test('when all creation attempts fail, then the error is thrown', async () => { const unhandledRejectionListener = vi.fn(); process.on('unhandledRejection', unhandledRejectionListener); onTestFinished(() => { diff --git a/test/services/sdkmanager.service.test.ts b/test/services/sdkmanager.service.test.ts index e9ee7040..a3d953f1 100644 --- a/test/services/sdkmanager.service.test.ts +++ b/test/services/sdkmanager.service.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import crypto from 'node:crypto'; import { Auth, Drive, Network } from '@internxt/sdk'; import { Trash } from '@internxt/sdk/dist/drive'; @@ -16,7 +16,7 @@ describe('SDKManager service', () => { clientVersion: crypto.randomBytes(16).toString('hex'), }; - it('When SDKManager ApiSecurityFixture is requested, then it is returned from static property', () => { + test('when the security configuration is requested after initialization, then it is returned from the stored settings', () => { const ApiSecurityFixture: SdkManagerApiSecurity = { token: crypto.randomBytes(16).toString('hex'), retryOptions: { @@ -28,7 +28,7 @@ describe('SDKManager service', () => { expect(SdkManager.getApiSecurity()).to.be.deep.equal(ApiSecurityFixture); }); - it('When SDKManager ApiSecurityFixture is requested but it is not started, then an error is thrown', () => { + test('when the security configuration is requested before initialization, then an error is thrown', () => { try { SdkManager.getApiSecurity(); fail('Expected function to throw an error, but it did not.'); @@ -37,7 +37,7 @@ describe('SDKManager service', () => { } }); - it('When SDKManager is cleaned, then ApiSecurityFixture property is cleaned', () => { + test('when the SDK manager is reset, then the stored security configuration is cleared', () => { SdkManager.init(ApiSecurityFixture); SdkManager.clean(); try { @@ -50,7 +50,7 @@ describe('SDKManager service', () => { expect(apiSecurityResponse).to.be.equal(undefined); }); - it('When getAppDetails is requested, then it is generated using packageJson values', () => { + test('when application details are requested, then they are generated from the package information', () => { const expectedAppdetails = { clientName: packageJson.clientName, clientVersion: packageJson.version, @@ -63,7 +63,7 @@ describe('SDKManager service', () => { expect(expectedAppdetails).to.be.deep.equal(appDetailsResponse); }); - it('When Auth client is requested, then it returns the sdk that uses the new API endpoint', () => { + test('when an authentication client is requested, then it is configured with the API endpoint from environment', () => { const envEndpoint: { key: keyof ConfigKeys; value: string } = { key: 'DRIVE_NEW_API_URL', value: 'test/new-api', @@ -83,7 +83,7 @@ describe('SDKManager service', () => { expect(auth).to.be.deep.equal(authClient); }); - it('When Users client is requested, then it is generated using internxt sdk', () => { + test('when a users client is requested, then it is configured with the API endpoint from environment', () => { const envEndpoint: { key: keyof ConfigKeys; value: string } = { key: 'DRIVE_NEW_API_URL', value: 'test/api', @@ -103,7 +103,7 @@ describe('SDKManager service', () => { expect(newClient).to.be.deep.equal(client); }); - it('When Storage client is requested, then it is generated using internxt sdk', () => { + test('when a storage client is requested, then it is configured with the API endpoint from environment', () => { const envEndpoint: { key: keyof ConfigKeys; value: string } = { key: 'DRIVE_NEW_API_URL', value: 'test/api', @@ -123,7 +123,7 @@ describe('SDKManager service', () => { expect(newClient).to.be.deep.equal(client); }); - it('When Trash client is requested, then it is generated using internxt sdk', () => { + test('when a trash client is requested, then it is configured with the API endpoint from environment', () => { const envEndpoint: { key: keyof ConfigKeys; value: string } = { key: 'DRIVE_NEW_API_URL', value: 'test/api', @@ -143,7 +143,7 @@ describe('SDKManager service', () => { expect(newClient).to.be.deep.equal(client); }); - it('When Share client is requested, then it is generated using internxt sdk', () => { + test('when a share client is requested, then it is configured with the API endpoint from environment', () => { const envEndpoint: { key: keyof ConfigKeys; value: string } = { key: 'DRIVE_NEW_API_URL', value: 'test/api', @@ -163,7 +163,7 @@ describe('SDKManager service', () => { expect(newClient).to.be.deep.equal(client); }); - it('When Network client is requested, then it is generated using internxt sdk', () => { + test('when a network client is requested, then it is configured with the network endpoint from environment', () => { const envEndpoint: { key: keyof ConfigKeys; value: string } = { key: 'NETWORK_URL', value: 'test/network', diff --git a/test/services/thumbnail.service.test.ts b/test/services/thumbnail.service.test.ts index b509559b..fb072829 100644 --- a/test/services/thumbnail.service.test.ts +++ b/test/services/thumbnail.service.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from 'vitest'; +import { describe, expect, test } from 'vitest'; import { BufferStream } from '../../src/utils/stream.utils'; import { ThumbnailService } from '../../src/services/thumbnail.service'; import path from 'node:path'; @@ -8,7 +8,7 @@ describe('Thumbnail Service tests', () => { const testFilePath = path.join(process.cwd(), 'test/fixtures/test-content.fixture.txt'); describe('createFileStreamWithBuffer', () => { - it('should create BufferStream and pipe stream when file type is thumbnailable', () => { + test('when the file has a supported image type, then a buffer stream and file stream are created', () => { const result = ThumbnailService.instance.createFileStreamWithBuffer({ path: testFilePath, fileType: 'png' }); expect(result.bufferStream).toBeDefined(); @@ -17,7 +17,7 @@ describe('Thumbnail Service tests', () => { expect(result.fileStream).toBeInstanceOf(Readable); }); - it('should not create BufferStream when file type is not thumbnailable', () => { + test('when the file has an unsupported type, then only a file stream is created without buffering', () => { const result = ThumbnailService.instance.createFileStreamWithBuffer({ path: testFilePath, fileType: 'txt' }); expect(result.bufferStream).toBeUndefined(); diff --git a/test/services/usage.service.test.ts b/test/services/usage.service.test.ts index 230e1473..7b27225b 100644 --- a/test/services/usage.service.test.ts +++ b/test/services/usage.service.test.ts @@ -1,11 +1,11 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { randomInt, randomUUID } from 'node:crypto'; import { Storage } from '@internxt/sdk/dist/drive'; import { UsageService } from '../../src/services/usage.service'; import { SdkManager } from '../../src/services/sdk-manager.service'; describe('Usage Service', () => { - it('When getting user usage, it should return the total usage', async () => { + test('when the user requests storage usage, then the total used space is returned', async () => { const drive = randomInt(2000000000); const backups = randomInt(2000000000); const total = drive + backups; @@ -19,7 +19,7 @@ describe('Usage Service', () => { expect(result).to.be.deep.equal(driveSpaceUsage.total); }); - it('When getting user space limit, it should return the total usage', async () => { + test('when the user requests the storage limit, then the maximum allowed space is returned', async () => { const driveSpaceLimit = { maxSpaceBytes: randomInt(5000000000) }; vi.spyOn(Storage.prototype, 'spaceLimitV2').mockResolvedValue(driveSpaceLimit); diff --git a/test/services/validation.service.test.ts b/test/services/validation.service.test.ts index ce4bf38e..fb5ba356 100644 --- a/test/services/validation.service.test.ts +++ b/test/services/validation.service.test.ts @@ -1,23 +1,23 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { auth } from '@internxt/lib'; import { randomInt, randomUUID } from 'node:crypto'; import { UserFixture } from '../fixtures/auth.fixture'; import { ValidationService } from '../../src/services/validation.service'; describe('Validation Service', () => { - it('When email is not valid, then validation service validates it as expected', () => { + test('when an email address is invalid, then validation reports it as invalid', () => { vi.spyOn(auth, 'isValidEmail').mockReturnValue(false); const isValidEmail = ValidationService.instance.validateEmail(UserFixture.email); expect(isValidEmail).to.be.equal(false); }); - it('When two factor auth code is validated, then validation service validates it as expected', () => { + test('when a two-factor authentication code is validated, then it must be exactly six digits', () => { expect(ValidationService.instance.validate2FA('1234567')).to.be.equal(false); expect(ValidationService.instance.validate2FA('loremi')).to.be.equal(false); expect(ValidationService.instance.validate2FA('123456')).to.be.equal(true); }); - it('When v4 uuid is validated, then validation service validates it as expected', () => { + test('when a version 4 UUID is validated, then it must follow the expected format', () => { expect(ValidationService.instance.validateUUIDv4('1234567')).to.be.equal(false); expect(ValidationService.instance.validateUUIDv4('loremipsum')).to.be.equal(false); expect(ValidationService.instance.validateUUIDv4('AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA')).to.be.equal(false); @@ -28,7 +28,7 @@ describe('Validation Service', () => { expect(ValidationService.instance.validateUUIDv4(randomUUID())).to.be.equal(true); }); - it('When yes or not string is validated, then validation service validates it as expected', () => { + test('when a yes or no input is validated, then it accepts various affirmative and negative forms', () => { expect(ValidationService.instance.validateYesOrNoString('1234567')).to.be.equal(false); expect(ValidationService.instance.validateYesOrNoString('loremipsum')).to.be.equal(false); expect(ValidationService.instance.validateYesOrNoString('')).to.be.equal(false); @@ -43,7 +43,7 @@ describe('Validation Service', () => { expect(ValidationService.instance.validateYesOrNoString('n')).to.be.equal(true); }); - it('When tcp port is validated, then validation service validates it as expected', () => { + test('when a TCP port number is validated, then it must be between 1 and 65535', () => { expect(ValidationService.instance.validateTCPIntegerPort('0')).to.be.equal(false); expect(ValidationService.instance.validateTCPIntegerPort('65536')).to.be.equal(false); expect(ValidationService.instance.validateTCPIntegerPort('')).to.be.equal(false); @@ -57,7 +57,7 @@ describe('Validation Service', () => { expect(ValidationService.instance.validateTCPIntegerPort(String(randomInt(1, 65535)))).to.be.equal(true); }); - it('When empty string is validated, then validation service validates it as expected', () => { + test('when a string is checked for non-emptiness, then whitespace-only strings are rejected', () => { expect(ValidationService.instance.validateStringIsNotEmpty('1234567')).to.be.equal(true); expect(ValidationService.instance.validateStringIsNotEmpty('loremipsum')).to.be.equal(true); expect(ValidationService.instance.validateStringIsNotEmpty(' a')).to.be.equal(true); @@ -70,37 +70,37 @@ describe('Validation Service', () => { expect(ValidationService.instance.validateStringIsNotEmpty('\t\n')).to.be.equal(false); }); describe('parseJwtExpiration', () => { - it('When token is undefined, then returns null', () => { + test('when the token is not provided, then null is returned', () => { expect(ValidationService.instance.validateJwtAndCheckExpiration(undefined)).to.be.equal(null); }); - it('When token is not a string, then returns null', () => { + test('when the token is an empty string, then null is returned', () => { expect(ValidationService.instance.validateJwtAndCheckExpiration('')).to.be.equal(null); }); - it('When token does not have 3 parts, then returns null', () => { + test('when the token does not have the expected format, then null is returned', () => { expect(ValidationService.instance.validateJwtAndCheckExpiration('invalid')).to.be.equal(null); expect(ValidationService.instance.validateJwtAndCheckExpiration('invalid.token')).to.be.equal(null); }); - it('When token payload is not valid base64, then returns null', () => { + test('when the token payload is not valid base64 encoding, then null is returned', () => { const invalidToken = 'header.!!!invalid_base64!!!.signature'; expect(ValidationService.instance.validateJwtAndCheckExpiration(invalidToken)).to.be.equal(null); }); - it('When token payload does not contain exp claim, then returns null', () => { + test('when the token does not contain an expiration claim, then null is returned', () => { const payload = btoa(JSON.stringify({ sub: 'user123' })); const token = `header.${payload}.signature`; expect(ValidationService.instance.validateJwtAndCheckExpiration(token)).to.be.equal(null); }); - it('When token payload exp is not a number, then returns null', () => { + test('when the token expiration value is not a number, then null is returned', () => { const payload = btoa(JSON.stringify({ exp: 'not-a-number' })); const token = `header.${payload}.signature`; expect(ValidationService.instance.validateJwtAndCheckExpiration(token)).to.be.equal(null); }); - it('When token has valid structure with exp claim, then returns expiration timestamp', () => { + test('when the token has a valid structure with expiration, then the expiration timestamp is returned', () => { const expiration = Math.floor(Date.now() / 1000) + 3600; // 1 hour from now const payload = btoa(JSON.stringify({ exp: expiration, sub: 'user123' })); const token = `header.${payload}.signature`; @@ -109,49 +109,49 @@ describe('Validation Service', () => { }); describe('checkTokenExpiration', () => { - it('When token expired more than 2 days ago, then expired is true and refreshRequired is false', () => { + test('when the token expired more than two days ago, then it is expired and cannot be refreshed', () => { const threeDaysAgo = Math.floor(Date.now() / 1000) - 3 * 24 * 60 * 60; const result = ValidationService.instance.checkTokenExpiration(threeDaysAgo); expect(result.expired).to.be.equal(true); expect(result.refreshRequired).to.be.equal(false); }); - it('When token expired 1 second ago, then expired is true and refreshRequired is false', () => { + test('when the token expired one second ago, then it is expired and cannot be refreshed', () => { const oneSecondAgo = Math.floor(Date.now() / 1000) - 1; const result = ValidationService.instance.checkTokenExpiration(oneSecondAgo); expect(result.expired).to.be.equal(true); expect(result.refreshRequired).to.be.equal(false); }); - it('When token expires in exactly 0 seconds (now), then expired is true', () => { + test('when the token expires at the current moment, then it is considered expired', () => { const now = Math.floor(Date.now() / 1000); const result = ValidationService.instance.checkTokenExpiration(now); expect(result.expired).to.be.equal(true); expect(result.refreshRequired).to.be.equal(false); }); - it('When token expires in 1 day, then expired is false and refreshRequired is true', () => { + test('when the token expires within one day, then it is not yet expired but requires refresh', () => { const oneDayFromNow = Math.floor(Date.now() / 1000) + 24 * 60 * 60; const result = ValidationService.instance.checkTokenExpiration(oneDayFromNow); expect(result.expired).to.be.equal(false); expect(result.refreshRequired).to.be.equal(true); }); - it('When token expires in exactly 2 days, then expired is false and refreshRequired is true', () => { + test('when the token expires in exactly two days, then it is not yet expired but requires refresh', () => { const twoDaysFromNow = Math.floor(Date.now() / 1000) + 2 * 24 * 60 * 60; const result = ValidationService.instance.checkTokenExpiration(twoDaysFromNow); expect(result.expired).to.be.equal(false); expect(result.refreshRequired).to.be.equal(true); }); - it('When token expires in 2 days + 1 second, then expired is false and refreshRequired is false', () => { + test('when the token expires in more than two days, then it is not expired and does not require refresh', () => { const twoDaysPlusOneSecond = Math.floor(Date.now() / 1000) + 2 * 24 * 60 * 60 + 1; const result = ValidationService.instance.checkTokenExpiration(twoDaysPlusOneSecond); expect(result.expired).to.be.equal(false); expect(result.refreshRequired).to.be.equal(false); }); - it('When token expires in 30 days, then expired is false and refreshRequired is false', () => { + test('when the token expires in thirty days, then it is not expired and does not require refresh', () => { const thirtyDaysFromNow = Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60; const result = ValidationService.instance.checkTokenExpiration(thirtyDaysFromNow); expect(result.expired).to.be.equal(false); @@ -160,21 +160,21 @@ describe('Validation Service', () => { }); describe('validateTokenAndCheckExpiration', () => { - it('When token is undefined, then returns invalid with expired true', () => { + test('when the token is not provided, then it is invalid and marked as expired', () => { const result = ValidationService.instance.validateTokenAndCheckExpiration(undefined); expect(result.isValid).to.be.equal(false); expect(result.expiration.expired).to.be.equal(true); expect(result.expiration.refreshRequired).to.be.equal(false); }); - it('When token is malformed, then returns invalid with expired true', () => { + test('when the token is malformed, then it is invalid and marked as expired', () => { const result = ValidationService.instance.validateTokenAndCheckExpiration('invalid.token'); expect(result.isValid).to.be.equal(false); expect(result.expiration.expired).to.be.equal(true); expect(result.expiration.refreshRequired).to.be.equal(false); }); - it('When token is valid but expired, then returns valid with expired true', () => { + test('when the token is structurally valid but has expired, then it is marked as valid but expired', () => { const expiration = Math.floor(Date.now() / 1000) - 3600; // 1 hour ago const payload = btoa(JSON.stringify({ exp: expiration })); const token = `header.${payload}.signature`; @@ -185,7 +185,7 @@ describe('Validation Service', () => { expect(result.expiration.refreshRequired).to.be.equal(false); }); - it('When token is valid and expires in 1 day, then returns valid with refreshRequired true', () => { + test('when the token is valid and expires within one day, then it is valid and requires refresh', () => { const expiration = Math.floor(Date.now() / 1000) + 24 * 60 * 60; // 1 day from now const payload = btoa(JSON.stringify({ exp: expiration })); const token = `header.${payload}.signature`; @@ -196,7 +196,7 @@ describe('Validation Service', () => { expect(result.expiration.refreshRequired).to.be.equal(true); }); - it('When token is valid and expires in 30 days, then returns valid with both false', () => { + test('when the token is valid and expires in thirty days, then it is valid with no action needed', () => { const expiration = Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60; // 30 days from now const payload = btoa(JSON.stringify({ exp: expiration })); const token = `header.${payload}.signature`; diff --git a/test/services/webdav/webdav-folder.service.test.ts b/test/services/webdav/webdav-folder.service.test.ts index 73dbb081..57ba2b3f 100644 --- a/test/services/webdav/webdav-folder.service.test.ts +++ b/test/services/webdav/webdav-folder.service.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { fail } from 'node:assert'; import { WebDavFolderService } from '../../../src/services/webdav/webdav-folder.service'; import { DriveFolderService } from '../../../src/services/drive/drive-folder.service'; @@ -21,6 +21,10 @@ describe('WebDavFolderService', () => { protocol: 'https', host: 'localhost', timeoutMinutes: 5, + customAuth: false, + username: '', + password: '', + deleteFilesPermanently: false, }); }; @@ -37,8 +41,8 @@ describe('WebDavFolderService', () => { sut = WebDavFolderService.instance; }); - describe('createParentPathOrThrow', () => { - it('should throw ConflictError when createFullPath is disabled ', async () => { + describe('creating parent folders', () => { + test('when the full path creation is disabled, then a conflict error is thrown', async () => { mockWebdavConfig(false); try { @@ -52,7 +56,7 @@ describe('WebDavFolderService', () => { } }); - it('should create a single folder at root level when path has one segment', async () => { + test('when the path has a single segment, then a single folder is created at the root level', async () => { const createdFolder = newFolderItem({ name: 'backup', uuid: 'backup-uuid' }); mockWebdavConfig(true); @@ -70,7 +74,7 @@ describe('WebDavFolderService', () => { }); }); - it('should return existing folder without creating when folder already exists', async () => { + test('when the folder already exists, then the existing folder is returned without creating a new one', async () => { const existingFolder = newFolderItem({ name: 'backup', uuid: 'backup-uuid' }); mockWebdavConfig(true); @@ -85,7 +89,7 @@ describe('WebDavFolderService', () => { expect(createFolderSpy).not.toHaveBeenCalled(); }); - it('should recursively create nested folders when path has multiple segments', async () => { + test('when the path has multiple segments, then nested folders are created recursively', async () => { const backupFolder = newFolderItem({ name: 'backup', uuid: 'backup-uuid' }); const folder1 = newFolderItem({ name: 'folder1', uuid: 'folder1-uuid' }); const subfolder = newFolderItem({ name: 'subfolder', uuid: 'subfolder-uuid' }); @@ -125,8 +129,8 @@ describe('WebDavFolderService', () => { }); }); - describe('createFolder', () => { - it('it should wait 500ms for backend propagation when folder is created', async () => { + describe('creating a folder', () => { + test('when a folder is created, then the system waits for backend propagation', async () => { vi.useFakeTimers(); const folderResponse = newCreateFolderResponse({ diff --git a/test/utils/cli.utils.test.ts b/test/utils/cli.utils.test.ts index f2b61e68..1a837531 100644 --- a/test/utils/cli.utils.test.ts +++ b/test/utils/cli.utils.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, vi, beforeEach, MockInstance } from 'vitest'; +import { describe, test, expect, vi, beforeEach, MockInstance } from 'vitest'; import { ux } from '@oclif/core'; import { CLIUtils, LogReporter } from '../../src/utils/cli.utils'; import { Direction } from 'node:readline'; @@ -65,47 +65,47 @@ describe('CliUtils', () => { }); describe('clearPreviousLine', () => { - it('should move cursor up and clear line when jsonFlag is false', () => { + test('when json output is disabled, then the previous line is cleared', () => { CLIUtils.clearPreviousLine(false); expect(stdoutWrite).toHaveBeenCalledWith('\x1b[1A'); expect(stdoutClear).toHaveBeenCalledWith(0); }); - it('should not call stdout methods when jsonFlag is true', () => { + test('when json output is enabled, then the previous line is not cleared', () => { CLIUtils.clearPreviousLine(true); expect(stdoutWrite).not.toHaveBeenCalled(); expect(stdoutClear).not.toHaveBeenCalled(); }); - it('should not throw when no flags provided', () => { + test('when no flags are provided, then no error is thrown', () => { expect(() => CLIUtils.clearPreviousLine()).not.toThrow(); expect(stdoutWrite).toHaveBeenCalled(); }); }); describe('warning, error, success, log', () => { - it('warning should call reporter with colored warning', () => { + test('when a warning is reported, then the message is formatted and passed to the reporter', () => { vi.spyOn(ux, 'colorize').mockImplementation(vi.fn((color: string | undefined, text: string) => text)); CLIUtils.warning(reporter, 'Test'); expect(ux.colorize).toHaveBeenCalledWith('#a67805', '⚠ Warning: Test'); expect(reporter).toHaveBeenCalledWith('⚠ Warning: Test'); }); - it('error should call reporter with colored error', () => { + test('when an error is reported, then the message is formatted and passed to the reporter', () => { vi.spyOn(ux, 'colorize').mockImplementation(vi.fn((color: string | undefined, text: string) => text)); CLIUtils.error(reporter, 'Test'); expect(ux.colorize).toHaveBeenCalledWith('red', '⚠ Error: Test'); expect(reporter).toHaveBeenCalledWith('⚠ Error: Test'); }); - it('success should call reporter with colored success', () => { + test('when a success is reported, then the message is formatted and passed to the reporter', () => { vi.spyOn(ux, 'colorize').mockImplementation(vi.fn((color: string | undefined, text: string) => text)); CLIUtils.success(reporter, 'Test'); expect(ux.colorize).toHaveBeenCalledWith('green', '✓ Test'); expect(reporter).toHaveBeenCalledWith('✓ Test'); }); - it('log should call reporter with message', () => { + test('when a log message is reported, then it is passed to the reporter', () => { vi.spyOn(ux, 'colorize').mockImplementation(vi.fn((color: string | undefined, text: string) => text)); CLIUtils.log(reporter, 'Hello'); expect(reporter).toHaveBeenCalledWith('Hello'); @@ -113,7 +113,7 @@ describe('CliUtils', () => { }); describe('consoleLog', () => { - it('consoleLog should print to console', () => { + test('when logging to console, then the message is printed', () => { const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); CLIUtils.consoleLog('Hi'); expect(consoleSpy).toHaveBeenCalledWith('Hi'); @@ -122,7 +122,7 @@ describe('CliUtils', () => { }); describe('doing, done, failed', () => { - it('doing should start ux action when jsonFlag is false', () => { + test('when json output is disabled, then a spinner action is started', () => { vi.spyOn(ux.action, 'start').mockImplementation( // eslint-disable-next-line @typescript-eslint/no-unused-vars vi.fn((action: string, status?: string, opts?: Options) => {}), @@ -131,7 +131,7 @@ describe('CliUtils', () => { expect(ux.action.start).toHaveBeenCalledWith('Working', undefined, {}); }); - it('doing should not call when jsonFlag is true', () => { + test('when json output is enabled, then no spinner action is started', () => { vi.spyOn(ux.action, 'start').mockImplementation( // eslint-disable-next-line @typescript-eslint/no-unused-vars vi.fn((action: string, status?: string, opts?: Options) => {}), @@ -140,7 +140,7 @@ describe('CliUtils', () => { expect(ux.action.start).not.toHaveBeenCalled(); }); - it('done should stop ux action with colored done when running', () => { + test('when an action is running, then it is marked as done', () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars vi.spyOn(ux.action, 'stop').mockImplementation(vi.fn((msg?: string) => {})); vi.spyOn(ux.action, 'running', 'get').mockReturnValue(true); @@ -148,7 +148,7 @@ describe('CliUtils', () => { expect(ux.action.stop).toHaveBeenCalledWith('done ✓'); }); - it('done should not stop action when jsonFlag is true', () => { + test('when json output is enabled, then the action is not stopped', () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars vi.spyOn(ux.action, 'stop').mockImplementation(vi.fn((msg?: string) => {})); vi.spyOn(ux.action, 'running', 'get').mockReturnValue(true); @@ -156,7 +156,7 @@ describe('CliUtils', () => { expect(ux.action.stop).not.toHaveBeenCalled(); }); - it('failed should stop ux action with colored failed when running', () => { + test('when an action is running, then it is marked as failed', () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars vi.spyOn(ux.action, 'stop').mockImplementation(vi.fn((msg?: string) => {})); vi.spyOn(ux.action, 'running', 'get').mockReturnValue(true); @@ -164,7 +164,7 @@ describe('CliUtils', () => { expect(ux.action.stop).toHaveBeenCalledWith('failed ✕'); }); - it('failed should not stop when jsonFlag is true', () => { + test('when json output is enabled, then the action is not marked as failed', () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars vi.spyOn(ux.action, 'stop').mockImplementation(vi.fn((msg?: string) => {})); vi.spyOn(ux.action, 'running', 'get').mockReturnValue(true); @@ -174,7 +174,7 @@ describe('CliUtils', () => { }); describe('prepareNetwork', () => { - it('should properly create a networkFacade instance and return it', async () => { + test('when preparing the network, then a configured network instance is returned', async () => { vi.spyOn(CLIUtils, 'getNetworkCreds').mockResolvedValue({ bucket: mockLoginUserDetails.bucket, credentials: { @@ -202,7 +202,7 @@ describe('CliUtils', () => { }); describe('timer', () => { - it('should measure elapsed time correctly', () => { + test('when time passes, then the elapsed time is measured correctly', () => { vi.useFakeTimers(); const timer = CLIUtils.timer(); vi.advanceTimersByTime(1500); @@ -211,7 +211,7 @@ describe('CliUtils', () => { vi.useRealTimers(); }); - it('should measure zero time when stopped immediately', () => { + test('when stopped immediately, then the elapsed time is zero', () => { vi.useFakeTimers(); const timer = CLIUtils.timer(); const elapsed = timer.stop(); @@ -219,7 +219,7 @@ describe('CliUtils', () => { vi.useRealTimers(); }); - it('should handle multiple timers independently', () => { + test('when multiple timers are running, then they each measure independently', () => { vi.useFakeTimers(); const timer1 = CLIUtils.timer(); vi.advanceTimersByTime(500); @@ -234,79 +234,79 @@ describe('CliUtils', () => { }); describe('formatDuration', () => { - it('should format seconds correctly', () => { + test('when formatting seconds, then the duration is displayed correctly', () => { expect(CLIUtils.formatDuration(5000)).toBe('00:00:05.000'); }); - it('should format minutes and seconds correctly', () => { + test('when formatting minutes and seconds, then the duration is displayed correctly', () => { expect(CLIUtils.formatDuration(125000)).toBe('00:02:05.000'); }); - it('should format hours, minutes, and seconds correctly', () => { + test('when formatting hours, minutes, and seconds, then the duration is displayed correctly', () => { expect(CLIUtils.formatDuration(3665000)).toBe('01:01:05.000'); }); - it('should format zero milliseconds', () => { + test('when formatting zero milliseconds, then the duration is zero', () => { expect(CLIUtils.formatDuration(0)).toBe('00:00:00.000'); }); - it('should handle milliseconds less than a second', () => { + test('when formatting less than a second, then the duration is displayed correctly', () => { expect(CLIUtils.formatDuration(999)).toBe('00:00:00.999'); }); - it('should handle large durations', () => { + test('when formatting large durations, then the duration is displayed correctly', () => { expect(CLIUtils.formatDuration(86400000)).toBe('24:00:00.000'); }); - it('should pad single digits with zeros', () => { + test('when formatting durations, then single digits are padded with zeros', () => { expect(CLIUtils.formatDuration(3661000)).toBe('01:01:01.000'); }); - it('should handle negative values gracefully', () => { + test('when a negative value is given, then zero is returned', () => { expect(CLIUtils.formatDuration(-5000)).toBe('00:00:00.000'); }); - it('should format milliseconds correctly', () => { + test('when formatting milliseconds, then the duration is displayed correctly', () => { expect(CLIUtils.formatDuration(1234)).toBe('00:00:01.234'); }); - it('should pad milliseconds with zeros', () => { + test('when formatting milliseconds, then they are padded with zeros', () => { expect(CLIUtils.formatDuration(5001)).toBe('00:00:05.001'); }); }); describe('calculateThroughputMBps', () => { - it('should calculate throughput in MB/s correctly', () => { + test('when calculating throughput, then the value in MB/s is correct', () => { const throughput = CLIUtils.calculateThroughputMBps(10485760, 1000); expect(throughput).toBe(10); }); - it('should handle zero bytes', () => { + test('when zero bytes are transferred, then the throughput is zero', () => { const throughput = CLIUtils.calculateThroughputMBps(0, 1000); expect(throughput).toBe(0); }); - it('should handle fractional throughput', () => { + test('when calculating throughput, then fractional values are handled', () => { const throughput = CLIUtils.calculateThroughputMBps(5242880, 2000); expect(throughput).toBe(2.5); }); - it('should handle very small time values', () => { + test('when the time is very small, then the throughput is calculated correctly', () => { const throughput = CLIUtils.calculateThroughputMBps(1048576, 100); expect(throughput).toBe(10); }); - it('should handle large byte values', () => { + test('when large amounts of data are transferred, then the throughput is calculated correctly', () => { const throughput = CLIUtils.calculateThroughputMBps(104857600, 10000); expect(throughput).toBe(10); }); - it('should handle negative bytes gracefully', () => { + test('when negative bytes are given, then the throughput is zero', () => { const throughput = CLIUtils.calculateThroughputMBps(-1048576, 1000); expect(throughput).toBe(0); }); - it('should handle negative time gracefully', () => { + test('when negative time is given, then the throughput is zero', () => { const throughput = CLIUtils.calculateThroughputMBps(1048576, -1000); expect(throughput).toBe(0); }); diff --git a/test/utils/crypto.utils.test.ts b/test/utils/crypto.utils.test.ts index e5570ab5..c709e34b 100644 --- a/test/utils/crypto.utils.test.ts +++ b/test/utils/crypto.utils.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import crypto from 'node:crypto'; import { CryptoUtils } from '../../src/utils/crypto.utils'; import { ConfigService } from '../../src/services/config.service'; @@ -11,7 +11,7 @@ describe('Crypto utils', () => { salt: crypto.randomBytes(64).toString('hex'), }; - it('When Magic IV or Magic Salt are missing should throw an error', () => { + test('when encryption settings are missing, then an error is thrown', () => { try { CryptoUtils.getAesInit(); fail('Expected function to throw an error, but it did not.'); @@ -20,7 +20,7 @@ describe('Crypto utils', () => { } }); - it('When aes information is required, then it is read from the config service', async () => { + test('when encryption settings are requested, then they are retrieved from storage', async () => { const configServiceInstancespyOn = vi.spyOn(ConfigService.instance, 'get'); configServiceInstancespyOn.mockReturnValueOnce(aesInit.iv); configServiceInstancespyOn.mockReturnValueOnce(aesInit.salt); diff --git a/test/utils/errors.utils.test.ts b/test/utils/errors.utils.test.ts index 44175372..4be873f5 100644 --- a/test/utils/errors.utils.test.ts +++ b/test/utils/errors.utils.test.ts @@ -1,9 +1,9 @@ -import { describe, expect, it } from 'vitest'; +import { describe, expect, test } from 'vitest'; import { ErrorUtils } from '../../src/utils/errors.utils'; import { logger } from '../../src/utils/logger.utils'; describe('Errors Utils', () => { - it('When reporting an error, should log with the expected message and properties', () => { + test('when an error is reported, then it is logged with its details', () => { const error = new Error('Test Error'); const props = { key: 'value' }; @@ -15,7 +15,7 @@ describe('Errors Utils', () => { ); }); - it('When reporting an object, should log with the expected message and properties', () => { + test('when an object is reported, then it is logged with its details', () => { const error = { data: 'error data' }; const props = { key: 'value' }; @@ -27,19 +27,19 @@ describe('Errors Utils', () => { ); }); describe('isAlreadyExistsError', () => { - it('should properly detect an error object that has an already exists as message', () => { + test('when an error has an already-exists message, then it is detected', () => { const error = new Error('File already exists'); expect(ErrorUtils.isAlreadyExistsError(error)).toBe(true); }); - it('should properly detect an error object that has 409 as status', () => { + test('when an error has a conflict status, then it is detected', () => { const error = { status: 409, message: 'Conflict' }; expect(ErrorUtils.isAlreadyExistsError(error)).toBe(true); }); - it('should return false if the passed error is not an object', () => { + test('when the input is not an error object, then it is not detected', () => { expect(ErrorUtils.isAlreadyExistsError('string error')).toBe(false); expect(ErrorUtils.isAlreadyExistsError(123)).toBe(false); expect(ErrorUtils.isAlreadyExistsError(null)).toBe(false); @@ -48,14 +48,14 @@ describe('Errors Utils', () => { }); describe('isFileNotFoundError', () => { - it('should return true when error has code ENOENT', () => { + test('when an error has a file-not-found code, then it is detected', () => { const error = new Error('File not found'); Object.assign(error, { code: 'ENOENT' }); expect(ErrorUtils.isFileNotFoundError(error)).toBe(true); }); - it('should return true when error is a real ENOENT error from fs operations', () => { + test('when a filesystem file-not-found error occurs, then it is detected', () => { const error = Object.assign(new Error('ENOENT: no such file or directory'), { code: 'ENOENT', errno: -2, @@ -66,20 +66,20 @@ describe('Errors Utils', () => { expect(ErrorUtils.isFileNotFoundError(error)).toBe(true); }); - it('should return false when error has a different error code', () => { + test('when an error has a different code, then it is not detected', () => { const error = new Error('Permission denied'); Object.assign(error, { code: 'EACCES' }); expect(ErrorUtils.isFileNotFoundError(error)).toBe(false); }); - it('should return false when error has no code property', () => { + test('when an error has no code, then it is not detected', () => { const error = new Error('Some error'); expect(ErrorUtils.isFileNotFoundError(error)).toBe(false); }); - it('should return false when error is not an Error object', () => { + test('when the input is not an error object, then it is not detected', () => { expect(ErrorUtils.isFileNotFoundError({ code: 'ENOENT' })).toBe(false); expect(ErrorUtils.isFileNotFoundError('ENOENT')).toBe(false); expect(ErrorUtils.isFileNotFoundError(null)).toBe(false); diff --git a/test/utils/format.utils.test.ts b/test/utils/format.utils.test.ts index 33d8efa5..1ac1432a 100644 --- a/test/utils/format.utils.test.ts +++ b/test/utils/format.utils.test.ts @@ -1,16 +1,16 @@ -import { describe, expect, it } from 'vitest'; +import { describe, expect, test } from 'vitest'; import { randomInt } from 'node:crypto'; import { FormatUtils } from '../../src/utils/format.utils'; import { UsageService } from '../../src/services/usage.service'; describe('Format utils', () => { - it('should return a formatted date for WebDav when providing a date', () => { + test('when a date is provided, then a formatted date string is returned', () => { const date = new Date('2021-10-10T10:10:10Z'); const result = FormatUtils.formatDateForWebDav(date); expect(result).to.be.equal('Sun, 10 Oct 2021 10:10:10 GMT'); }); - it('should return a formatted human readable size when providing a size', () => { + test('when a file size is provided, then a human-readable size string is returned', () => { const value = randomInt(1, 500); const expectedSizes = [ { @@ -56,7 +56,7 @@ describe('Format utils', () => { }); }); - it('should return a formatted human readable size with decimals when providing a size', () => { + test('when a file size with decimals is provided, then a human-readable size string is returned', () => { const expectedSizes = [ { value: 1.5 * Math.pow(1024, 1), @@ -85,7 +85,7 @@ describe('Format utils', () => { }); }); - it('should return a formatted human readable limit when providing a limit', () => { + test('when a storage limit is provided, then a human-readable limit string is returned', () => { const limit = randomInt(100000000000000); const expectedLimits = [ { diff --git a/test/utils/network.utils.test.ts b/test/utils/network.utils.test.ts index f61b4c1f..3298df17 100644 --- a/test/utils/network.utils.test.ts +++ b/test/utils/network.utils.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { randomBytes, randomInt, X509Certificate } from 'node:crypto'; import selfsigned, { GenerateResult } from 'selfsigned'; import { readFile, stat, writeFile } from 'node:fs/promises'; @@ -31,7 +31,7 @@ vi.mock('node:crypto', async () => { const mock509Certificate = vi.mocked(X509Certificate); describe('Network utils', () => { - it('When obtaining auth credentials, should return the password as a SHA256 hash', async () => { + test('when obtaining authentication credentials, then the password is returned as a hash', async () => { const result = NetworkUtils.getAuthFromCredentials({ user: 'test', pass: 'password123!', @@ -40,7 +40,7 @@ describe('Network utils', () => { expect(result.password).to.be.equal('5751a44782594819e4cb8aa27c2c9d87a420af82bc6a5a05bc7f19c3bb00452b'); }); - it('When webdav ssl certs do not exist, then they should be self signed and saved to files', async () => { + test('when SSL certificates do not exist, then they are self-signed and saved', async () => { const webdavConfig: WebdavConfig = getWebdavConfigMock(); const sslSelfSigned: GenerateResult = { @@ -68,7 +68,7 @@ describe('Network utils', () => { }); // We will need to find a way to mock the X509Certificate successfully - it.skip('When webdav ssl certs exist, then they are read from the files', async () => { + test.skip('when SSL certificates exist, then they are read from storage', async () => { const webdavConfig: WebdavConfig = getWebdavConfigMock(); const sslMock = { private: randomBytes(8).toString('hex'), @@ -104,7 +104,7 @@ describe('Network utils', () => { }); // We will need to find a way to mock the X509Certificate successfully - it.skip('When webdav ssl certs exist but they are expired, then they are generated and saved to files', async () => { + test.skip('when SSL certificates exist but are expired, then new ones are generated and saved', async () => { const webdavConfig: WebdavConfig = getWebdavConfigMock(); const sslSelfSigned: GenerateResult = { private: randomBytes(8).toString('hex'), @@ -146,7 +146,7 @@ describe('Network utils', () => { expect(mockReadFile).toHaveBeenCalledTimes(2); }); - it('When parsing range, it should parse it if its all good', () => { + test('when a valid range header is provided, then it is parsed successfully', () => { const mockSize = randomInt(500, 10000); const rangeStart = randomInt(0, 450); const range = `bytes=${rangeStart}-${mockSize}`; @@ -161,7 +161,7 @@ describe('Network utils', () => { }); }); - it('When parsing range, it should return errors if found', () => { + test('when an invalid range header is provided, then an error is returned', () => { const totalFileSize = randomInt(500, 10000); expect(NetworkUtils.parseRangeHeader({ range: undefined, totalFileSize })).to.be.equal(undefined); diff --git a/test/utils/pm2.utils.test.ts b/test/utils/pm2.utils.test.ts index 8001c280..ae314f1f 100644 --- a/test/utils/pm2.utils.test.ts +++ b/test/utils/pm2.utils.test.ts @@ -1,10 +1,10 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import pm2 from 'pm2'; import { PM2Utils } from '../../src/utils/pm2.utils'; import { fail } from 'node:assert'; describe('PM2 utils', () => { - it('When connecting, should connect to PM2 daemon', async () => { + test('when connecting to the process manager, then the connection is established', async () => { // @ts-expect-error - The error callback does not include an error const connectStub = vi.spyOn(pm2, 'connect').mockImplementation((callback) => callback()); @@ -12,7 +12,7 @@ describe('PM2 utils', () => { expect(connectStub).toHaveBeenCalledOnce(); }); - it('When connecting, and daemon is not available, should reject', async () => { + test('when connecting and the process manager is not available, then the connection is rejected', async () => { const error = new Error('Failed to connect'); // @ts-expect-error - The error callback does not include an error vi.spyOn(pm2, 'connect').mockImplementation((callback) => callback(error)); @@ -24,21 +24,21 @@ describe('PM2 utils', () => { } }); - it('When killing the WebDav server, should delete the process', async () => { + test('when stopping the WebDAV server, then the server process is deleted', async () => { // @ts-expect-error - The error callback does not include an error const deleteStub = vi.spyOn(pm2, 'delete').mockImplementation((_, callback) => callback()); await PM2Utils.killWebDavServer(); expect(deleteStub).toHaveBeenCalledOnce(); }); - it('When getting server process status, should return online status when WebDav server is running', async () => { + test('when the WebDAV server is running, then the status is reported as online', async () => { // @ts-expect-error - The error callback does not include an error vi.spyOn(pm2, 'describe').mockImplementation((_, callback) => callback(null, [{ pm2_env: { status: 'online' } }])); const status = await PM2Utils.webdavServerStatus(); expect(status.status).to.be.equal('online'); }); - it('When getting server process status, should return offline status when WebDav server is not running', async () => { + test('when the WebDAV server is not running, then the status is reported as offline', async () => { // @ts-expect-error - The error callback does not include an error vi.spyOn(pm2, 'describe').mockImplementation((_, callback) => callback(null, [])); @@ -46,14 +46,14 @@ describe('PM2 utils', () => { expect(status.status).to.be.equal('offline'); }); - it('When starting the WebDav server process, should start the WebDav server', async () => { + test('when starting the WebDAV server, then the server process is started', async () => { // @ts-expect-error - The error callback does not include an error const startStub = vi.spyOn(pm2, 'start').mockImplementation((_, callback) => callback()); await PM2Utils.startWebDavServer(); expect(startStub).toHaveBeenCalledOnce(); }); - it('When starting the WebDav server process, should reject when failing to start the WebDav server', async () => { + test('when starting the WebDAV server fails, then an error is returned', async () => { const error = new Error('Failed to start server'); // @ts-expect-error - The error callback does not include an error vi.spyOn(pm2, 'start').mockImplementation((_, callback) => callback(error)); diff --git a/test/utils/stream.utils.test.ts b/test/utils/stream.utils.test.ts index 03f5a352..2aab45a2 100644 --- a/test/utils/stream.utils.test.ts +++ b/test/utils/stream.utils.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { StreamUtils } from '../../src/utils/stream.utils'; import { createReadStream, readFileSync, WriteStream } from 'node:fs'; import path from 'node:path'; @@ -6,7 +6,7 @@ import path from 'node:path'; describe('Stream utils', () => { const fileWithContent = path.join(process.cwd(), 'test/fixtures/test-content.fixture.txt'); - it('When a ReadStream is given, should return a ReadableStream', async () => { + test('when a readable Node stream is given, then a web ReadableStream is returned', async () => { const content = readFileSync(fileWithContent, 'utf-8'); const readStream = createReadStream(fileWithContent); @@ -19,7 +19,7 @@ describe('Stream utils', () => { expect(Buffer.from(read.value as Uint8Array).toString('utf-8')).to.be.equal(content); }); - it('When a WriteStream is given, should return a WritableStream', async () => { + test('when a writable Node stream is given, then a web WritableStream is returned', async () => { const writeStub = vi.fn(); // @ts-expect-error - We only mock the properties we need const writeStream: WriteStream = { diff --git a/test/utils/thumbnail.utils.test.ts b/test/utils/thumbnail.utils.test.ts index b8566d57..4137ad18 100644 --- a/test/utils/thumbnail.utils.test.ts +++ b/test/utils/thumbnail.utils.test.ts @@ -1,9 +1,9 @@ -import { describe, expect, it } from 'vitest'; +import { describe, expect, test } from 'vitest'; import { ThumbnailUtils } from '../../src/utils/thumbnail.utils'; describe('Thumbnail Utils tests', () => { describe('isFileThumbnailable', () => { - it('should return true for valid image extensions', () => { + test('when a valid image extension is given, then true is returned', () => { expect(ThumbnailUtils.isFileThumbnailable('jpg')).toBe(true); expect(ThumbnailUtils.isFileThumbnailable('jpeg')).toBe(true); expect(ThumbnailUtils.isFileThumbnailable('png')).toBe(true); @@ -13,20 +13,20 @@ describe('Thumbnail Utils tests', () => { expect(ThumbnailUtils.isFileThumbnailable('tiff')).toBe(true); }); - it('should return true regardless of case', () => { + test('when an extension has mixed case, then true is returned', () => { expect(ThumbnailUtils.isFileThumbnailable('JPG')).toBe(true); expect(ThumbnailUtils.isFileThumbnailable('PNG')).toBe(true); expect(ThumbnailUtils.isFileThumbnailable('Webp')).toBe(true); expect(ThumbnailUtils.isFileThumbnailable('GIF')).toBe(true); }); - it('should handle whitespace correctly', () => { + test('when an extension has surrounding whitespace, then true is returned', () => { expect(ThumbnailUtils.isFileThumbnailable(' jpg ')).toBe(true); expect(ThumbnailUtils.isFileThumbnailable(' png ')).toBe(true); expect(ThumbnailUtils.isFileThumbnailable('\tgif\t')).toBe(true); }); - it('should return false for non-thumbnailable extensions', () => { + test('when a non-thumbnailable extension is given, then false is returned', () => { expect(ThumbnailUtils.isFileThumbnailable('pdf')).toBe(false); expect(ThumbnailUtils.isFileThumbnailable('doc')).toBe(false); expect(ThumbnailUtils.isFileThumbnailable('txt')).toBe(false); @@ -36,36 +36,36 @@ describe('Thumbnail Utils tests', () => { expect(ThumbnailUtils.isFileThumbnailable('heic')).toBe(false); }); - it('should return false for empty strings', () => { + test('when an empty or blank string is given, then false is returned', () => { expect(ThumbnailUtils.isFileThumbnailable('')).toBe(false); expect(ThumbnailUtils.isFileThumbnailable(' ')).toBe(false); expect(ThumbnailUtils.isFileThumbnailable('\t\n')).toBe(false); }); - it('should return false for invalid input', () => { + test('when an invalid extension is given, then false is returned', () => { expect(ThumbnailUtils.isFileThumbnailable('unknown')).toBe(false); expect(ThumbnailUtils.isFileThumbnailable('jpgg')).toBe(false); }); }); describe('isPDFThumbnailable', () => { - it('should return true for pdf extension', () => { + test('when a pdf extension is given, then true is returned', () => { expect(ThumbnailUtils.isPDFThumbnailable('pdf')).toBe(true); }); - it('should return true regardless of case', () => { + test('when an extension has mixed case, then true is returned', () => { expect(ThumbnailUtils.isPDFThumbnailable('PDF')).toBe(true); expect(ThumbnailUtils.isPDFThumbnailable('Pdf')).toBe(true); expect(ThumbnailUtils.isPDFThumbnailable('pDf')).toBe(true); }); - it('should handle whitespace correctly', () => { + test('when an extension has surrounding whitespace, then true is returned', () => { expect(ThumbnailUtils.isPDFThumbnailable(' pdf ')).toBe(true); expect(ThumbnailUtils.isPDFThumbnailable(' PDF ')).toBe(true); expect(ThumbnailUtils.isPDFThumbnailable('\tpdf\n')).toBe(true); }); - it('should return false for non-pdf extensions', () => { + test('when a non-pdf extension is given, then false is returned', () => { expect(ThumbnailUtils.isPDFThumbnailable('jpg')).toBe(false); expect(ThumbnailUtils.isPDFThumbnailable('png')).toBe(false); expect(ThumbnailUtils.isPDFThumbnailable('doc')).toBe(false); @@ -73,20 +73,20 @@ describe('Thumbnail Utils tests', () => { expect(ThumbnailUtils.isPDFThumbnailable('txt')).toBe(false); }); - it('should return false for empty strings', () => { + test('when an empty or blank string is given, then false is returned', () => { expect(ThumbnailUtils.isPDFThumbnailable('')).toBe(false); expect(ThumbnailUtils.isPDFThumbnailable(' ')).toBe(false); expect(ThumbnailUtils.isPDFThumbnailable('\t\n')).toBe(false); }); - it('should return false for invalid input', () => { + test('when an invalid extension is given, then false is returned', () => { expect(ThumbnailUtils.isPDFThumbnailable('pdff')).toBe(false); expect(ThumbnailUtils.isPDFThumbnailable('pd')).toBe(false); }); }); describe('isImageThumbnailable', () => { - it('should return true for all thumbnailable image extensions', () => { + test('when a thumbnailable image extension is given, then true is returned', () => { expect(ThumbnailUtils.isImageThumbnailable('jpg')).toBe(true); expect(ThumbnailUtils.isImageThumbnailable('jpeg')).toBe(true); expect(ThumbnailUtils.isImageThumbnailable('png')).toBe(true); @@ -96,20 +96,20 @@ describe('Thumbnail Utils tests', () => { expect(ThumbnailUtils.isImageThumbnailable('tiff')).toBe(true); }); - it('should return true regardless of case', () => { + test('when an extension has mixed case, then true is returned', () => { expect(ThumbnailUtils.isImageThumbnailable('JPG')).toBe(true); expect(ThumbnailUtils.isImageThumbnailable('PNG')).toBe(true); expect(ThumbnailUtils.isImageThumbnailable('GIF')).toBe(true); expect(ThumbnailUtils.isImageThumbnailable('Jpeg')).toBe(true); }); - it('should handle whitespace correctly', () => { + test('when an extension has surrounding whitespace, then true is returned', () => { expect(ThumbnailUtils.isImageThumbnailable(' jpg ')).toBe(true); expect(ThumbnailUtils.isImageThumbnailable(' png ')).toBe(true); expect(ThumbnailUtils.isImageThumbnailable('\twebp\n')).toBe(true); }); - it('should return false for non-thumbnailable image formats', () => { + test('when a non-thumbnailable image format is given, then false is returned', () => { expect(ThumbnailUtils.isImageThumbnailable('bmp')).toBe(false); expect(ThumbnailUtils.isImageThumbnailable('heic')).toBe(false); expect(ThumbnailUtils.isImageThumbnailable('raw')).toBe(false); @@ -118,7 +118,7 @@ describe('Thumbnail Utils tests', () => { expect(ThumbnailUtils.isImageThumbnailable('eps')).toBe(false); }); - it('should return false for non-image extensions', () => { + test('when a non-image extension is given, then false is returned', () => { expect(ThumbnailUtils.isImageThumbnailable('pdf')).toBe(false); expect(ThumbnailUtils.isImageThumbnailable('doc')).toBe(false); expect(ThumbnailUtils.isImageThumbnailable('txt')).toBe(false); @@ -126,13 +126,13 @@ describe('Thumbnail Utils tests', () => { expect(ThumbnailUtils.isImageThumbnailable('mp3')).toBe(false); }); - it('should return false for empty strings', () => { + test('when an empty or blank string is given, then false is returned', () => { expect(ThumbnailUtils.isImageThumbnailable('')).toBe(false); expect(ThumbnailUtils.isImageThumbnailable(' ')).toBe(false); expect(ThumbnailUtils.isImageThumbnailable('\t\n')).toBe(false); }); - it('should return false for invalid input', () => { + test('when an invalid extension is given, then false is returned', () => { expect(ThumbnailUtils.isImageThumbnailable('jpgg')).toBe(false); expect(ThumbnailUtils.isImageThumbnailable('unknown')).toBe(false); }); diff --git a/test/utils/upload.utils.test.ts b/test/utils/upload.utils.test.ts index 0ebdb8e9..4f349611 100644 --- a/test/utils/upload.utils.test.ts +++ b/test/utils/upload.utils.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { Readable } from 'node:stream'; import { UploadUtils } from '../../src/utils/upload.utils'; import { UsageService } from '../../src/services/usage.service'; @@ -13,19 +13,19 @@ describe('UploadUtils', () => { }); describe('checkUploadSizeLimits', () => { - it('should not throw when fetchLimits returns no maxUploadFileSize and size is under 100GB', async () => { + test('when no upload limit is set and the file is under 100GB, then no error is thrown', async () => { vi.spyOn(UsageService.instance, 'fetchLimits').mockResolvedValue(undefined as never); await expect(UploadUtils.checkUploadSizeLimits(5 * 1024 * 1024 * 1024)).resolves.toBeUndefined(); }); - it('should not throw when fetchLimits returns null', async () => { + test('when the upload limit is unavailable, then no error is thrown', async () => { vi.spyOn(UsageService.instance, 'fetchLimits').mockResolvedValue(null as never); await expect(UploadUtils.checkUploadSizeLimits(5 * 1024 * 1024 * 1024)).resolves.toBeUndefined(); }); - it('should not throw when size is below the account upload limit', async () => { + test('when the file size is below the account upload limit, then no error is thrown', async () => { vi.spyOn(UsageService.instance, 'fetchLimits').mockResolvedValue({ maxUploadFileSize: 8 * 1024 * 1024 * 1024, versioning: { enabled: false, maxFileSize: 0, retentionDays: 0, maxVersions: 0 }, @@ -34,7 +34,7 @@ describe('UploadUtils', () => { await expect(UploadUtils.checkUploadSizeLimits(5 * 1024 * 1024 * 1024)).resolves.toBeUndefined(); }); - it('should throw when size exceeds the account upload limit', async () => { + test('when the file size exceeds the account upload limit, then an error is thrown', async () => { const limitBytes = 10 * 1024 * 1024 * 1024; const sizeBytes = 15 * 1024 * 1024 * 1024; vi.spyOn(UsageService.instance, 'fetchLimits').mockResolvedValue({ @@ -48,7 +48,7 @@ describe('UploadUtils', () => { ); }); - it('should not throw when size equals the account upload limit', async () => { + test('when the file size equals the account upload limit, then no error is thrown', async () => { const limitBytes = 10 * 1024 * 1024 * 1024; vi.spyOn(UsageService.instance, 'fetchLimits').mockResolvedValue({ maxUploadFileSize: limitBytes, @@ -58,7 +58,7 @@ describe('UploadUtils', () => { await expect(UploadUtils.checkUploadSizeLimits(limitBytes)).resolves.toBeUndefined(); }); - it('should throw when size exceeds 100GB even if no account limit is set', async () => { + test('when the file exceeds 100GB and no account limit is set, then an error is thrown', async () => { vi.spyOn(UsageService.instance, 'fetchLimits').mockResolvedValue(undefined as never); await expect(UploadUtils.checkUploadSizeLimits(101 * 1024 * 1024 * 1024)).rejects.toThrow( @@ -66,7 +66,7 @@ describe('UploadUtils', () => { ); }); - it('should throw when size > 100GB', async () => { + test('when the file exceeds 100GB, then an error is thrown', async () => { vi.spyOn(UsageService.instance, 'fetchLimits').mockResolvedValue({ maxUploadFileSize: 200 * 1024 * 1024 * 1024, versioning: { enabled: false, maxFileSize: 0, retentionDays: 0, maxVersions: 0 }, @@ -77,7 +77,7 @@ describe('UploadUtils', () => { ); }); - it('should use the account limit when it is below the default limit', async () => { + test('when the account limit is lower than the default, then the account limit is enforced', async () => { const limitBytes = 8 * 1024 * 1024 * 1024; vi.spyOn(UsageService.instance, 'fetchLimits').mockResolvedValue({ maxUploadFileSize: limitBytes, @@ -92,7 +92,7 @@ describe('UploadUtils', () => { }); describe('prepareUploadStreams', () => { - it('should return the original stream and no thumbnail when file type is not thumbnailable', () => { + test('when the file type does not support thumbnails, then the original stream is returned without a thumbnail', () => { vi.spyOn(ThumbnailUtils, 'isFileThumbnailable').mockReturnValue(false); const readable = Readable.from(['test']); @@ -103,7 +103,7 @@ describe('UploadUtils', () => { expect(result.isThumbnailable).toBe(false); }); - it('should return a piped stream and a BufferStream when file type is thumbnailable', () => { + test('when the file type supports thumbnails, then a piped stream and thumbnail stream are returned', () => { vi.spyOn(ThumbnailUtils, 'isFileThumbnailable').mockReturnValue(true); const readable = Readable.from(['test-data']); @@ -117,7 +117,7 @@ describe('UploadUtils', () => { }); describe('getTimings', () => { - it('should calculate total time as the sum of all timings', () => { + test('when calculating upload timing, then the total time is the sum of all stages', () => { vi.spyOn(CLIUtils, 'calculateThroughputMBps').mockReturnValue(5); vi.spyOn(CLIUtils, 'formatDuration').mockReturnValue('00:00:01.000'); @@ -130,7 +130,7 @@ describe('UploadUtils', () => { expect(result.totalTime).toBe(3500); }); - it('should call calculateThroughputMBps with size and networkUpload time', () => { + test('when calculating throughput, then the size and upload time are used', () => { const calculateThroughputSpy = vi.spyOn(CLIUtils, 'calculateThroughputMBps').mockReturnValue(2.5); vi.spyOn(CLIUtils, 'formatDuration').mockReturnValue('00:00:01.000'); @@ -143,7 +143,7 @@ describe('UploadUtils', () => { expect(calculateThroughputSpy).toHaveBeenCalledWith(1024 * 1024 * 5, 2000); }); - it('should return throughputMBps from calculateThroughputMBps', () => { + test('when calculating throughput, then the speed in MB/s is returned', () => { vi.spyOn(CLIUtils, 'calculateThroughputMBps').mockReturnValue(12.34); vi.spyOn(CLIUtils, 'formatDuration').mockReturnValue('00:00:01.000'); @@ -156,7 +156,7 @@ describe('UploadUtils', () => { expect(result.throughputMBps).toBe(12.34); }); - it('should build a timing breakdown string with formatted durations', () => { + test('when calculating timing, then a detailed breakdown string is built', () => { vi.spyOn(CLIUtils, 'calculateThroughputMBps').mockReturnValue(10); vi.spyOn(CLIUtils, 'formatDuration').mockImplementation((ms: number) => `formatted-${ms}`); @@ -173,7 +173,7 @@ describe('UploadUtils', () => { ); }); - it('should handle all-zero timings', () => { + test('when all timing values are zero, then the totals are zero', () => { vi.spyOn(CLIUtils, 'calculateThroughputMBps').mockReturnValue(0); vi.spyOn(CLIUtils, 'formatDuration').mockReturnValue('00:00:00.000'); diff --git a/test/utils/webdav.utils.test.ts b/test/utils/webdav.utils.test.ts index 5d36e4af..12750973 100644 --- a/test/utils/webdav.utils.test.ts +++ b/test/utils/webdav.utils.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { WebDavUtils } from '../../src/utils/webdav.utils'; import { WebDavRequestedResource } from '../../src/types/webdav.types'; import { newFileItem, newFolderItem } from '../fixtures/drive.fixture'; @@ -10,19 +10,19 @@ import { getWebdavConfigMock } from '../fixtures/webdav.fixture'; describe('Webdav utils', () => { describe('joinURL', () => { - it('When a list of path components are given, then it should generate a correct href', () => { + test('when path components are given, then a correct URL is generated', () => { const href = WebDavUtils.joinURL('/path', 'to', 'file'); expect(href).to.be.equal('/path/to/file'); }); - it('When a list of path components are given, then it should remove incorrect characters', () => { + test('when path components contain trailing slashes, then they are handled correctly', () => { const href = WebDavUtils.joinURL('/path', 'to', 'folder/'); expect(href).to.be.equal('/path/to/folder/'); }); }); describe('removeHostFromURL', () => { - it('When a list of path components are given, then it should generate a correct href', () => { + test('when a URL with a host is given, then the host is removed', () => { expect(WebDavUtils.removeHostFromURL('https://test.com/folder1')).to.be.equal('/folder1'); expect(WebDavUtils.removeHostFromURL('http://test.com/folder1')).to.be.equal('/folder1'); expect(WebDavUtils.removeHostFromURL('test.com/folder1')).to.be.equal('/folder1'); @@ -34,7 +34,7 @@ describe('Webdav utils', () => { }); describe('getRequestedResource', () => { - it('When folder url is given, then it should generate the requested resource', async () => { + test('when a folder URL is given, then the requested resource is created', async () => { const requestURL = '/url/to/folder/'; const resource = await WebDavUtils.getRequestedResource(requestURL); expect(resource).to.deep.equal({ @@ -51,7 +51,7 @@ describe('Webdav utils', () => { }); }); - it('When file url is given, then it should generate the requested resource', async () => { + test('when a file URL is given, then the requested resource is created', async () => { const requestURL = '/url/to/test.png'; const resource = await WebDavUtils.getRequestedResource(requestURL); expect(resource).to.deep.equal({ @@ -95,7 +95,7 @@ describe('Webdav utils', () => { }, }; - it('When folder resource is looked by its path, then it is returned', async () => { + test('when a folder is looked up by path, then it is returned', async () => { const expectedFolder = newFolderItem(); const findFolderStub = vi.spyOn(DriveItemService.instance, 'getFolderByPath').mockResolvedValue(expectedFolder); const findFileStub = vi.spyOn(DriveItemService.instance, 'getFileByPath').mockRejectedValue(new Error()); @@ -106,7 +106,7 @@ describe('Webdav utils', () => { expect(findFileStub).not.toHaveBeenCalled(); }); - it('When folder is not found, then it returns undefined', async () => { + test('when a folder is not found, then undefined is returned', async () => { const findFolderStub = vi .spyOn(DriveItemService.instance, 'getFolderByPath') .mockRejectedValue(new Error('Folder not found')); @@ -116,7 +116,7 @@ describe('Webdav utils', () => { expect(item).toBeUndefined(); }); - it('When file resource is looked by its path, then it is returned', async () => { + test('when a file is looked up by path, then it is returned', async () => { const expectedFile = newFileItem(); const findFileStub = vi.spyOn(DriveItemService.instance, 'getFileByPath').mockResolvedValue(expectedFile); const findFolderStub = vi.spyOn(DriveItemService.instance, 'getFolderByPath').mockRejectedValue(new Error()); @@ -129,7 +129,7 @@ describe('Webdav utils', () => { }); describe('getDriveFileFromResource', () => { - it('When the file exists, then it should return the file item', async () => { + test('when the file exists, then the file item is returned', async () => { const expectedFile = newFileItem(); vi.spyOn(DriveItemService.instance, 'getFileByPath').mockResolvedValue(expectedFile); @@ -138,7 +138,7 @@ describe('Webdav utils', () => { expect(result).toBe(expectedFile); }); - it('When the file does not exist, then it should return undefined', async () => { + test('when the file does not exist, then undefined is returned', async () => { vi.spyOn(DriveItemService.instance, 'getFileByPath').mockRejectedValue(new Error('Not found')); const result = await WebDavUtils.getDriveFileFromResource('/path/to/nonexistent.txt'); @@ -148,7 +148,7 @@ describe('Webdav utils', () => { }); describe('getDriveFolderFromResource', () => { - it('When the folder exists, then it should return the folder item', async () => { + test('when the folder exists, then the folder item is returned', async () => { const expectedFolder = newFolderItem(); vi.spyOn(DriveItemService.instance, 'getFolderByPath').mockResolvedValue(expectedFolder); @@ -157,7 +157,7 @@ describe('Webdav utils', () => { expect(result).toBe(expectedFolder); }); - it('When the folder does not exist, then it should return undefined', async () => { + test('when the folder does not exist, then undefined is returned', async () => { vi.spyOn(DriveItemService.instance, 'getFolderByPath').mockRejectedValue(new Error('Not found')); const result = await WebDavUtils.getDriveFolderFromResource('/path/to/nonexistent/'); @@ -167,7 +167,7 @@ describe('Webdav utils', () => { }); describe('deleteOrTrashItem', () => { - it('should delete file permanently and clear cache when deleteFilesPermanently is true', async () => { + test('when permanent deletion is enabled for files, then files are deleted permanently and cache is cleared', async () => { const fileItem = newFileItem(); vi.spyOn(ConfigService.instance, 'readWebdavConfig').mockResolvedValue( getWebdavConfigMock({ deleteFilesPermanently: true }), @@ -183,7 +183,7 @@ describe('Webdav utils', () => { expect(deleteCacheSpy).toHaveBeenCalledWith([fileItem.uuid]); }); - it('should delete folder permanently and clear cache when deleteFilesPermanently is true', async () => { + test('when permanent deletion is enabled for folders, then folders are deleted permanently and cache is cleared', async () => { const folderItem = newFolderItem(); vi.spyOn(ConfigService.instance, 'readWebdavConfig').mockResolvedValue( getWebdavConfigMock({ deleteFilesPermanently: true }), @@ -199,7 +199,7 @@ describe('Webdav utils', () => { expect(deleteCacheSpy).toHaveBeenCalledWith([folderItem.uuid]); }); - it('When deleteFilesPermanently is false for a file, then it should trash the file and clear cache', async () => { + test('when permanent deletion is disabled for files, then files are trashed and cache is cleared', async () => { const fileItem = newFileItem(); vi.spyOn(ConfigService.instance, 'readWebdavConfig').mockResolvedValue( getWebdavConfigMock({ deleteFilesPermanently: false }), @@ -217,7 +217,7 @@ describe('Webdav utils', () => { expect(deleteCacheSpy).toHaveBeenCalledWith([fileItem.uuid]); }); - it('should trash folder and clear cache when deleteFilesPermanently is false', async () => { + test('when permanent deletion is disabled for folders, then folders are trashed and cache is cleared', async () => { const folderItem = newFolderItem(); vi.spyOn(ConfigService.instance, 'readWebdavConfig').mockResolvedValue( getWebdavConfigMock({ deleteFilesPermanently: false }), diff --git a/test/utils/xml.utils.test.ts b/test/utils/xml.utils.test.ts index 85d6ea06..aac11d00 100644 --- a/test/utils/xml.utils.test.ts +++ b/test/utils/xml.utils.test.ts @@ -1,9 +1,9 @@ -import { describe, expect, it } from 'vitest'; +import { describe, expect, test } from 'vitest'; import { XMLUtils } from '../../src/utils/xml.utils'; describe('XML utils', () => { describe('toJSON', () => { - it('should return a json parsed XML object when the XML is valid', () => { + test('when valid XML is provided, then a parsed object is returned', () => { const xml = 'value'; const result = XMLUtils.toJSON(xml); expect(result).to.be.deep.equal({ root: { child: 'value' } }); @@ -11,13 +11,13 @@ describe('XML utils', () => { }); describe('toXML', () => { - it('should return an unformatted XML when format is false', () => { + test('when formatting is disabled, then unformatted XML is returned', () => { const object = { root: { child: 'value' } }; const result = XMLUtils.toXML(object, { format: false }); expect(result).to.be.equal('value'); }); - it('should return a formatted XML when format is true', () => { + test('when formatting is enabled, then formatted XML is returned', () => { const object = { root: { child: 'value' } }; const result = XMLUtils.toXML(object, { format: true }); expect(result).to.be.equal('\n value\n\n'); diff --git a/test/webdav/handlers/DELETE.handler.test.ts b/test/webdav/handlers/DELETE.handler.test.ts index 770a841e..f66b24a0 100644 --- a/test/webdav/handlers/DELETE.handler.test.ts +++ b/test/webdav/handlers/DELETE.handler.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { fail } from 'node:assert'; import { DELETERequestHandler } from '../../../src/webdav/handlers/DELETE.handler'; import { @@ -22,7 +22,7 @@ describe('DELETE request handler', () => { vi.spyOn(ConfigService.instance, 'readWebdavConfig').mockResolvedValue(getWebdavConfigMock()); }); - it('When the item does not exist, it should reply with a 404 error', async () => { + test('when the requested item does not exist, then the server responds with a not found error', async () => { const requestHandler = new DELETERequestHandler(); const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); @@ -51,7 +51,7 @@ describe('DELETE request handler', () => { expect(getAndSearchItemFromResourceStub).toHaveBeenCalledOnce(); }); - it('When the file exists, then it should reply with a 204 response', async () => { + test('when a file is deleted, then the server confirms the deletion', async () => { const requestHandler = new DELETERequestHandler(); const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const request = createWebDavRequestFixture({ @@ -79,7 +79,7 @@ describe('DELETE request handler', () => { expect(removeItemsStub).toHaveBeenCalledWith(mockFile); }); - it('When folder exists, then it should reply with a 204 response', async () => { + test('when a folder is deleted, then the server confirms the deletion', async () => { const requestHandler = new DELETERequestHandler(); const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource(); diff --git a/test/webdav/handlers/GET.handler.test.ts b/test/webdav/handlers/GET.handler.test.ts index c8d3c577..576979c3 100644 --- a/test/webdav/handlers/GET.handler.test.ts +++ b/test/webdav/handlers/GET.handler.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { fail } from 'node:assert'; import { createWebDavRequestFixture, @@ -33,7 +33,7 @@ describe('GET request handler', () => { sut = new GETRequestHandler(); }); - it('should throw a NotFoundError when the Drive file is not found', async () => { + test('when the requested file is not found, then the server returns an error', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const request = createWebDavRequestFixture({ @@ -62,7 +62,7 @@ describe('GET request handler', () => { expect(getFileMetadataStub).toHaveBeenCalledOnce(); }); - it('should write a response with the content when a file is requested', async () => { + test('when a file is requested, then the server responds with its content', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const request = createWebDavRequestFixture({ @@ -105,7 +105,7 @@ describe('GET request handler', () => { ); }); - it('should write a response with the ranged content when a file is requested with Range', async () => { + test('when a file is requested with a specific range, then the server responds with only that portion', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const mockSize = randomInt(500, 10000); @@ -160,7 +160,7 @@ describe('GET request handler', () => { ); }); - it('should write a response with no content when an empty file is requested', async () => { + test('when an empty file is requested, then the server responds with no content', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const request = createWebDavRequestFixture({ diff --git a/test/webdav/handlers/HEAD.handler.test.ts b/test/webdav/handlers/HEAD.handler.test.ts index 9460799e..10ae1b32 100644 --- a/test/webdav/handlers/HEAD.handler.test.ts +++ b/test/webdav/handlers/HEAD.handler.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { HEADRequestHandler } from '../../../src/webdav/handlers/HEAD.handler'; import { createWebDavRequestFixture, @@ -19,7 +19,7 @@ describe('HEAD request handler', () => { sut = new HEADRequestHandler(); }); - it('When a folder is requested, it should reply with a 200', async () => { + test('when a folder is requested, then the server responds with a success status', async () => { const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource(); const request = createWebDavRequestFixture({ method: 'HEAD', @@ -44,7 +44,7 @@ describe('HEAD request handler', () => { expect(getFolderMetadataStub).toHaveBeenCalledOnce(); }); - it('When a file is requested, it should reply with a 200 with the correct headers', async () => { + test('when a file is requested, then the server responds with the correct metadata headers', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const request = createWebDavRequestFixture({ @@ -72,7 +72,7 @@ describe('HEAD request handler', () => { expect(getFileMetadataStub).toHaveBeenCalledOnce(); }); - it('When a file is requested with range-request, it should reply with a 200 with the correct headers', async () => { + test('when a file is requested with a range constraint, then the server responds with the adjusted metadata', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const mockSize = randomInt(500, 10000); diff --git a/test/webdav/handlers/LOCK.handler.test.ts b/test/webdav/handlers/LOCK.handler.test.ts index 28e50b9c..8799b2b0 100644 --- a/test/webdav/handlers/LOCK.handler.test.ts +++ b/test/webdav/handlers/LOCK.handler.test.ts @@ -1,9 +1,9 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { LOCKRequestHandler } from '../../../src/webdav/handlers/LOCK.handler'; import { createWebDavRequestFixture, createWebDavResponseFixture } from '../../fixtures/webdav.fixture'; describe('LOCK request handler', () => { - it('should return 200 with a valid lock token header and content type', async () => { + test('when a lock request is made, then the server responds with a valid lock token', async () => { const requestHandler = new LOCKRequestHandler(); const request = createWebDavRequestFixture({ @@ -33,7 +33,7 @@ describe('LOCK request handler', () => { expect(sendSpy.mock.calls[0]?.[0]).toBe(expectedXml); }); - it('should include default depth 0 and timeout in the XML response body', async () => { + test('when no depth or timeout are specified, then the server uses default values in the response', async () => { const requestHandler = new LOCKRequestHandler(); const request = createWebDavRequestFixture({ @@ -57,7 +57,7 @@ describe('LOCK request handler', () => { expect(sendSpy.mock.calls[0]?.[0]).toBe(expectedXml); }); - it('should use the depth and timeout from the request headers', async () => { + test('when depth and timeout headers are provided, then the server reflects them in the response', async () => { const requestHandler = new LOCKRequestHandler(); const request = createWebDavRequestFixture({ @@ -85,7 +85,7 @@ describe('LOCK request handler', () => { expect(sendSpy.mock.calls[0]?.[0]).toBe(expectedXml); }); - it('should generate a unique lock token on each request', async () => { + test('when multiple lock requests are made, then each receives a unique token', async () => { const requestHandler = new LOCKRequestHandler(); const request = createWebDavRequestFixture({ @@ -106,7 +106,7 @@ describe('LOCK request handler', () => { expect(token1).not.toBe(token2); }); - it('should echo back the owner from the request body', async () => { + test('when the request includes an owner, then the server echoes it back', async () => { const requestHandler = new LOCKRequestHandler(); const request = createWebDavRequestFixture({ @@ -135,7 +135,7 @@ describe('LOCK request handler', () => { expect(sendSpy.mock.calls[0]?.[0]).toBe(expectedXml); }); - it('should handle request body without owner gracefully', async () => { + test('when the request body does not contain an owner, then the server still responds successfully', async () => { const requestHandler = new LOCKRequestHandler(); const request = createWebDavRequestFixture({ @@ -160,7 +160,7 @@ describe('LOCK request handler', () => { expect(sendSpy.mock.calls[0]?.[0]).toBe(expectedXml); }); - it('should return valid DAV: XML structure', async () => { + test('when a lock request is made, then the server returns a valid XML structure', async () => { const requestHandler = new LOCKRequestHandler(); const request = createWebDavRequestFixture({ diff --git a/test/webdav/handlers/MKCOL.handler.test.ts b/test/webdav/handlers/MKCOL.handler.test.ts index 254faf80..cff468e4 100644 --- a/test/webdav/handlers/MKCOL.handler.test.ts +++ b/test/webdav/handlers/MKCOL.handler.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { MKCOLRequestHandler } from '../../../src/webdav/handlers/MKCOL.handler'; import { createWebDavRequestFixture, @@ -22,7 +22,7 @@ describe('MKCOL request handler', () => { vi.spyOn(AuthService.instance, 'getAuthDetails').mockResolvedValue(UserCredentialsFixture); }); - it('should wait 500ms for backend propagation before returning 201 when a folder is created', async () => { + test('when a folder is created, then the server waits for propagation before confirming', async () => { const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/test', folderName: 'FolderA', @@ -53,7 +53,7 @@ describe('MKCOL request handler', () => { expect(endTime - startTime).toBeGreaterThanOrEqual(500); }); - it('When a WebDav client sends a MKCOL request, it should reply with a 201 if success', async () => { + test('when a folder creation request succeeds, then the server confirms with a success status', async () => { const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/test', folderName: 'FolderA', diff --git a/test/webdav/handlers/MOVE.handler.test.ts b/test/webdav/handlers/MOVE.handler.test.ts index fdf4f23b..cf563a10 100644 --- a/test/webdav/handlers/MOVE.handler.test.ts +++ b/test/webdav/handlers/MOVE.handler.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { createWebDavRequestFixture, createWebDavResponseFixture, @@ -20,7 +20,7 @@ describe('MOVE request handler', () => { sut = new MOVERequestHandler(); }); - it('should throw when no destination header is provided', async () => { + test('when no destination is specified, then the server returns an error', async () => { const request = createWebDavRequestFixture({ method: 'MOVE', url: '/source/file.txt', @@ -30,7 +30,7 @@ describe('MOVE request handler', () => { await expect(sut.handle(request, response)).rejects.toThrow('Destination folder not received'); }); - it('should throw when the source resource is not found', async () => { + test('when the source item is not found, then the server returns an error', async () => { const request = createWebDavRequestFixture({ method: 'MOVE', url: '/source/file.txt', @@ -46,7 +46,7 @@ describe('MOVE request handler', () => { await expect(sut.handle(request, response)).rejects.toThrow('Resource not found on Internxt Drive'); }); - it('should rename a folder when destination is in the same directory', async () => { + test('when a folder is moved within the same directory, then the server renames it', async () => { const folderItem = newFolderItem({ uuid: 'folder-uuid' }); const request = createWebDavRequestFixture({ method: 'MOVE', @@ -74,7 +74,7 @@ describe('MOVE request handler', () => { expect(response.status).toHaveBeenCalledWith(204); }); - it('should rename a file when destination is in the same directory', async () => { + test('when a file is moved within the same directory, then the server renames it', async () => { const fileItem = newFileItem({ uuid: 'file-uuid' }); const request = createWebDavRequestFixture({ method: 'MOVE', @@ -104,7 +104,7 @@ describe('MOVE request handler', () => { expect(response.status).toHaveBeenCalledWith(204); }); - it('should move a folder to a different directory', async () => { + test('when a folder is moved to a different directory, then the server processes the move', async () => { const folderItem = newFolderItem({ uuid: 'folder-uuid' }); const destFolderItem = newFolderItem({ uuid: 'dest-folder-uuid' }); const request = createWebDavRequestFixture({ @@ -137,7 +137,7 @@ describe('MOVE request handler', () => { expect(response.status).toHaveBeenCalledWith(204); }); - it('should move a file to a different directory', async () => { + test('when a file is moved to a different directory, then the server processes the move', async () => { const fileItem = newFileItem({ uuid: 'file-uuid' }); const destFolderItem = newFolderItem({ uuid: 'dest-folder-uuid' }); const request = createWebDavRequestFixture({ diff --git a/test/webdav/handlers/OPTIONS.handler.test.ts b/test/webdav/handlers/OPTIONS.handler.test.ts index 174c67da..28d2daa1 100644 --- a/test/webdav/handlers/OPTIONS.handler.test.ts +++ b/test/webdav/handlers/OPTIONS.handler.test.ts @@ -1,10 +1,10 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { OPTIONSRequestHandler } from '../../../src/webdav/handlers/OPTIONS.handler'; import { UserSettingsFixture } from '../../fixtures/auth.fixture'; import { createWebDavRequestFixture, createWebDavResponseFixture } from '../../fixtures/webdav.fixture'; describe('OPTIONS request handler', () => { - it('When the root folder is requested, it should return all of the server allowed methods', async () => { + test('when the root folder is requested, then the server lists all available capabilities', async () => { const requestHandler = new OPTIONSRequestHandler(); const request = createWebDavRequestFixture({ @@ -25,7 +25,7 @@ describe('OPTIONS request handler', () => { expect(response.header).toHaveBeenCalledWith('DAV', '1, 2, ordered-collections'); }); - it('When a folder is requested, it should return all of the folder allowed methods', async () => { + test('when a folder is requested, then the server lists the folder capabilities', async () => { const requestHandler = new OPTIONSRequestHandler(); const request = createWebDavRequestFixture({ @@ -46,7 +46,7 @@ describe('OPTIONS request handler', () => { expect(response.header).toHaveBeenCalledWith('DAV', '1, 2, ordered-collections'); }); - it('When a file is requested, it should return all of the file allowed methods', async () => { + test('when a file is requested, then the server lists the file capabilities', async () => { const requestHandler = new OPTIONSRequestHandler(); const request = createWebDavRequestFixture({ diff --git a/test/webdav/handlers/PROPFIND.handler.test.ts b/test/webdav/handlers/PROPFIND.handler.test.ts index 830afb73..728b86ee 100644 --- a/test/webdav/handlers/PROPFIND.handler.test.ts +++ b/test/webdav/handlers/PROPFIND.handler.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { PROPFINDRequestHandler } from '../../../src/webdav/handlers/PROPFIND.handler'; import { DriveFolderService } from '../../../src/services/drive/drive-folder.service'; import { DriveItemService } from '../../../src/services/drive/drive-item.service'; @@ -36,7 +36,7 @@ describe('PROPFIND request handler', () => { sut = new PROPFINDRequestHandler(); }); - it('should return the correct XML when root folder exists and is empty', async () => { + test('when the root folder is empty, then the server returns the correct folder properties', async () => { const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', folderName: '', @@ -73,7 +73,6 @@ describe('PROPFIND request handler', () => { await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(207); expect(response.send).toHaveBeenCalledWith( - // eslint-disable-next-line max-len `${XMLUtils.encodeWebDavUri('/')}HTTP/1.1 200 OKapplication/octet-stream${FormatUtils.formatDateForWebDav(folderFixture.updatedAt)}F00000030${spaceLimitFixture - usageFixture}${usageFixture}`, ); expect(getRequestedResourceStub).toHaveBeenCalledOnce(); @@ -83,7 +82,7 @@ describe('PROPFIND request handler', () => { expect(spaceLimitStub).toHaveBeenCalledOnce(); }); - it('should not cache folder content items when root folder is empty', async () => { + test('when the root folder has no content, then the server does not cache any items', async () => { const requestedFolderResource = getRequestedFolderResource({ parentFolder: '/', folderName: '', @@ -113,7 +112,7 @@ describe('PROPFIND request handler', () => { expect(createOrUpdateSpy).not.toHaveBeenCalled(); }); - it('should return the correct XML with child items when root folder has content', async () => { + test('when the root folder contains items, then the server returns them in the response', async () => { const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', folderName: '', @@ -155,7 +154,6 @@ describe('PROPFIND request handler', () => { await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(207); expect(response.send).toHaveBeenCalledWith( - // eslint-disable-next-line max-len `${XMLUtils.encodeWebDavUri('/')}HTTP/1.1 200 OKapplication/octet-stream${FormatUtils.formatDateForWebDav(folderFixture.updatedAt)}F00000030${spaceLimitFixture - usageFixture}${usageFixture}${XMLUtils.encodeWebDavUri(`/${paginatedFolder1.plainName}/`)}HTTP/1.1 200 OK${paginatedFolder1.plainName}${FormatUtils.formatDateForWebDav(paginatedFolder1.updatedAt)}0`, ); expect(getRequestedResourceStub).toHaveBeenCalledOnce(); @@ -165,7 +163,7 @@ describe('PROPFIND request handler', () => { expect(spaceLimitStub).toHaveBeenCalledOnce(); }); - it('should cache child items via createOrUpdate when root folder has content', async () => { + test('when the root folder contains items, then the server caches them for future requests', async () => { const requestedFolderResource = getRequestedFolderResource({ parentFolder: '/', folderName: '', @@ -200,7 +198,7 @@ describe('PROPFIND request handler', () => { ); }); - it('should return the correct XML for a file', async () => { + test('when a file is requested, then the server returns its properties', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource({ parentFolder: '/', fileName: 'file', @@ -234,7 +232,6 @@ describe('PROPFIND request handler', () => { await sut.handle(request, response); expect(response.status).toHaveBeenCalledWith(207); expect(response.send).toHaveBeenCalledWith( - // eslint-disable-next-line max-len `${XMLUtils.encodeWebDavUri(requestedFileResource.url)}HTTP/1.1 200 OK"${etagFixture}"${fileFixture.name + '.' + fileFixture.type}${mimeFixture}${FormatUtils.formatDateForWebDav(fileFixture.modificationTime)}${fileFixture.size}`, ); expect(getRequestedResourceStub).toHaveBeenCalledOnce(); @@ -243,7 +240,7 @@ describe('PROPFIND request handler', () => { expect(mimeLookupStub).toHaveBeenCalledOnce(); }); - it('should return the correct XML for a folder', async () => { + test('when a folder is requested, then the server returns its properties', async () => { const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', folderName: 'folder_a', @@ -280,7 +277,7 @@ describe('PROPFIND request handler', () => { expect(getFolderContentStub).toHaveBeenCalledOnce(); }); - it('should cache child items when folder has content', async () => { + test('when a folder contains items, then the server caches them for future requests', async () => { const requestedFolderResource = getRequestedFolderResource({ parentFolder: '/', folderName: 'folder_a', @@ -313,7 +310,7 @@ describe('PROPFIND request handler', () => { ); }); - it('should return a 404 empty response when folder does not exist', async () => { + test('when a folder does not exist, then the server responds with a not found status', async () => { const requestedFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', folderName: 'folder_a', diff --git a/test/webdav/handlers/PUT.handler.test.ts b/test/webdav/handlers/PUT.handler.test.ts index 11cd97e3..ee20c94f 100644 --- a/test/webdav/handlers/PUT.handler.test.ts +++ b/test/webdav/handlers/PUT.handler.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; import { createWebDavRequestFixture, createWebDavResponseFixture, @@ -33,7 +33,7 @@ describe('PUT request handler', () => { sut = new PUTRequestHandler(); }); - it('should upload an empty file when the content-length request is 0', async () => { + test('when an empty file is uploaded, then the server creates it without uploading content', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const requestedParentFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', @@ -84,7 +84,7 @@ describe('PUT request handler', () => { expect(createDriveFileStub).toHaveBeenCalledOnce(); }); - it('should upload the file to the folder when the Drive destination folder is found', async () => { + test('when a file is uploaded to an existing folder, then the server stores it', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const requestedParentFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', @@ -131,7 +131,7 @@ describe('PUT request handler', () => { expect(createDriveFileStub).toHaveBeenCalledOnce(); }); - it('it should upload and replace the file to the folder when the file already exists', async () => { + test('when a file already exists at the destination, then the server replaces it', async () => { const requestedFileResource: WebDavRequestedResource = getRequestedFileResource(); const requestedParentFolderResource: WebDavRequestedResource = getRequestedFolderResource({ parentFolder: '/', diff --git a/test/webdav/handlers/UNLOCK.handler.test.ts b/test/webdav/handlers/UNLOCK.handler.test.ts index 227cc01a..56e101db 100644 --- a/test/webdav/handlers/UNLOCK.handler.test.ts +++ b/test/webdav/handlers/UNLOCK.handler.test.ts @@ -1,9 +1,9 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { UNLOCKRequestHandler } from '../../../src/webdav/handlers/UNLOCK.handler'; import { createWebDavRequestFixture, createWebDavResponseFixture } from '../../fixtures/webdav.fixture'; describe('UNLOCK request handler', () => { - it('should return 204 when a valid lock token is provided', async () => { + test('when a valid lock token is provided, then the server releases the lock', async () => { const requestHandler = new UNLOCKRequestHandler(); const request = createWebDavRequestFixture({ @@ -22,7 +22,7 @@ describe('UNLOCK request handler', () => { expect(response.status).toHaveBeenCalledWith(204); }); - it('should return 204 even when no lock token header is provided', async () => { + test('when no lock token is provided, then the server still releases the lock', async () => { const requestHandler = new UNLOCKRequestHandler(); const request = createWebDavRequestFixture({ diff --git a/test/webdav/middlewares/auth.middleware.test.ts b/test/webdav/middlewares/auth.middleware.test.ts index cf153677..d2a76ce3 100644 --- a/test/webdav/middlewares/auth.middleware.test.ts +++ b/test/webdav/middlewares/auth.middleware.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi, beforeEach } from 'vitest'; +import { describe, expect, test, vi, beforeEach } from 'vitest'; import { AuthMiddleware } from '../../../src/webdav/middewares/auth.middleware'; import { createWebDavRequestFixture, createWebDavResponseFixture } from '../../fixtures/webdav.fixture'; import { UserCredentialsFixture } from '../../fixtures/login.fixture'; @@ -12,7 +12,7 @@ describe('Auth middleware', () => { CacheService.instance.clearCaches(); }); - it('should return 401 when the user is not authenticated', async () => { + test('when the user is not authenticated, then the server returns an unauthorized status', async () => { const req = createWebDavRequestFixture({}); const res = createWebDavResponseFixture({ status: vi.fn().mockReturnValue({ send: vi.fn() }), @@ -39,7 +39,7 @@ describe('Auth middleware', () => { ); }); - it('should call next and cache the result when the user is authenticated', async () => { + test('when the user is authenticated, then the middleware proceeds and caches the result', async () => { const req = createWebDavRequestFixture({}); const res = createWebDavResponseFixture({}); const next = vi.fn(); @@ -56,7 +56,7 @@ describe('Auth middleware', () => { expect(cached).toEqual(UserCredentialsFixture); }); - it('should not call getAuthDetails when the auth details are cached', async () => { + test('when authentication details are already cached, then the middleware skips re-fetching', async () => { const req = createWebDavRequestFixture({}); const res = createWebDavResponseFixture({}); const next = vi.fn(); diff --git a/test/webdav/middlewares/errors.middleware.test.ts b/test/webdav/middlewares/errors.middleware.test.ts index 41924107..91537fbd 100644 --- a/test/webdav/middlewares/errors.middleware.test.ts +++ b/test/webdav/middlewares/errors.middleware.test.ts @@ -1,11 +1,11 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { ErrorHandlingMiddleware } from '../../../src/webdav/middewares/errors.middleware'; import { createWebDavRequestFixture, createWebDavResponseFixture } from '../../fixtures/webdav.fixture'; import { BadRequestError, NotFoundError, NotImplementedError } from '../../../src/utils/errors.utils'; import { XMLUtils } from '../../../src/utils/xml.utils'; describe('Error handling middleware', () => { - it('When a not found error is received, should respond with a 404', () => { + test('when a not found error occurs, then the server responds with a 404 status', () => { const errorMessage = 'Item not found'; const error = new NotFoundError('Item not found'); const res = createWebDavResponseFixture({ @@ -30,7 +30,7 @@ describe('Error handling middleware', () => { ); }); - it('When a bad request error is received, should respond with a 400', () => { + test('when a bad request error occurs, then the server responds with a 400 status', () => { const errorMessage = 'Missing property "size"'; const error = new BadRequestError(errorMessage); const res = createWebDavResponseFixture({ @@ -55,7 +55,7 @@ describe('Error handling middleware', () => { ); }); - it('When a not implement error is received, should respond with a 501', () => { + test('when a not implemented error occurs, then the server responds with a 501 status', () => { const errorMessage = 'Content-range is not supported'; const error = new NotImplementedError(errorMessage); const res = createWebDavResponseFixture({ @@ -80,7 +80,7 @@ describe('Error handling middleware', () => { ); }); - it('When something that does not have status code arrives, should return a 500 status code', () => { + test('when an unknown error occurs, then the server responds with a 500 status', () => { const errorMessage = 'Cannot read property "id" of undefined'; const error = new TypeError(errorMessage); const res = createWebDavResponseFixture({ diff --git a/test/webdav/middlewares/mkcol.middleware.test.ts b/test/webdav/middlewares/mkcol.middleware.test.ts index 721b6f89..fa362118 100644 --- a/test/webdav/middlewares/mkcol.middleware.test.ts +++ b/test/webdav/middlewares/mkcol.middleware.test.ts @@ -1,11 +1,11 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { createWebDavRequestFixture, createWebDavResponseFixture } from '../../fixtures/webdav.fixture'; import { MkcolMiddleware } from '../../../src/webdav/middewares/mkcol.middleware'; import { fail } from 'node:assert'; import { UnsupportedMediaTypeError } from '../../../src/utils/errors.utils'; describe('MKCOL middleware', () => { - it('When MKCOL content is application/xml, then it should call next', () => { + test('when the request content type is XML, then the middleware allows the request to proceed', () => { const req = createWebDavRequestFixture({ method: 'MKCOL', url: '/anypath', @@ -19,7 +19,7 @@ describe('MKCOL middleware', () => { expect(next).toHaveBeenCalledExactlyOnceWith(); }); - it('When MKCOL content is text/xml, then it should call next', () => { + test('when the request content type is text XML, then the middleware allows the request to proceed', () => { const req = createWebDavRequestFixture({ method: 'MKCOL', url: '/anypath', @@ -33,7 +33,7 @@ describe('MKCOL middleware', () => { expect(next).toHaveBeenCalledExactlyOnceWith(); }); - it('When MKCOL content is not XML, then it should call next with error', async () => { + test('when the request content type is not XML, then the middleware rejects the request', async () => { const req = createWebDavRequestFixture({ method: 'MKCOL', url: '/anypath', @@ -50,7 +50,7 @@ describe('MKCOL middleware', () => { } }); - it('When MKCOL has body content, then it should call next with error', async () => { + test('when the request has a body, then the middleware rejects the request', async () => { const req = createWebDavRequestFixture({ method: 'MKCOL', url: '/anypath', diff --git a/test/webdav/middlewares/request-logger.middleware.test.ts b/test/webdav/middlewares/request-logger.middleware.test.ts index 282e87d2..0b147674 100644 --- a/test/webdav/middlewares/request-logger.middleware.test.ts +++ b/test/webdav/middlewares/request-logger.middleware.test.ts @@ -1,10 +1,10 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import { webdavLogger } from '../../../src/utils/logger.utils'; import { RequestLoggerMiddleware } from '../../../src/webdav/middewares/request-logger.middleware'; import { createWebDavRequestFixture, createWebDavResponseFixture } from '../../fixtures/webdav.fixture'; describe('Request logger middleware', () => { - it('When a request is received, should log only the specified methods', () => { + test('when a request is received, then the logger records only the specified methods', () => { const req = createWebDavRequestFixture({ method: 'PROPFIND', url: '/path', @@ -20,7 +20,7 @@ describe('Request logger middleware', () => { expect(next).toHaveBeenCalledOnce(); }); - it('When a request is received, should not log the request if the method is not specified', () => { + test('when a request method is not in the specified list, then the logger does not record it', () => { const req = createWebDavRequestFixture({ method: 'GET', url: '/path', diff --git a/test/webdav/webdav-server.test.ts b/test/webdav/webdav-server.test.ts index 14438ec5..1b196ecb 100644 --- a/test/webdav/webdav-server.test.ts +++ b/test/webdav/webdav-server.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import express from 'express'; import { randomBytes } from 'node:crypto'; import http from 'http'; @@ -11,7 +11,7 @@ import { UserCredentialsFixture } from '../fixtures/login.fixture'; import { getWebdavConfigMock } from '../fixtures/webdav.fixture'; describe('WebDav server', () => { - it('When the WebDav server is started with https, it should generate self-signed certificates', async () => { + test('when the server is started over a secure connection, then it generates security certificates', async () => { const webdavConfig: WebdavConfig = getWebdavConfigMock({ protocol: 'https' }); const sslSelfSigned = { private: randomBytes(8).toString('hex'), @@ -44,7 +44,7 @@ describe('WebDav server', () => { expect(createHTTPServerStub).not.toHaveBeenCalled(); }); - it('When the WebDav server is started with http, it should run http', async () => { + test('when the server is started over a standard connection, then it uses a regular HTTP server', async () => { const webdavConfig: WebdavConfig = getWebdavConfigMock({ protocol: 'http' }); vi.spyOn(ConfigService.instance, 'readWebdavConfig').mockResolvedValue(webdavConfig);