mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Finish switch from Jest to Vitest in API (#16263)
* build: ➕ add vitest and update test scripts * build: 🔧 add vitest config * build: ✅ Migrate tests to vitest Remove jest references from test api test files and replace with vitest equivalents. Tests: 13 tests are failing. * build: 🚚 move vite.config.ts to api/src folder * build: 🔥 remove unused vitest.config from api root * build: ✅ import vitest modules for tests * build: ✅ add type conversion for actual object * Finish switch from Jest to Vitest in API * Replace some leftovers * Load "sharp" before tests * Try with cjs * Temporary enable verbose reporter * Try with globalSetup * Fix path to globalSetup * Provide default export in globalSetup * Final clean-up * Remove @vitest/ui & update vitest to 0.25.0 * Add vitest c8 coverage dependency * Update vitest to v0.25.1 * Replace unnecessary Vitest workaround * Rework new tests * Resolve build errors Co-authored-by: Dorian C Brown <brown.3794@gmail.com> Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
This commit is contained in:
7
api/globalSetup.js
Normal file
7
api/globalSetup.js
Normal file
@@ -0,0 +1,7 @@
|
||||
// From https://sharp.pixelplumbing.com/install#worker-threads:
|
||||
// On some platforms, including glibc-based Linux, the main thread must call require('sharp') before worker threads are created.
|
||||
// This is to ensure shared libraries remain loaded in memory until after all threads are complete.
|
||||
// Without this, the following error may occur: Module did not self-register
|
||||
import 'sharp';
|
||||
|
||||
export default function () {}
|
||||
@@ -1,14 +0,0 @@
|
||||
const base = require('../jest.config.js');
|
||||
|
||||
require('dotenv').config();
|
||||
|
||||
module.exports = {
|
||||
...base,
|
||||
roots: ['<rootDir>/src'],
|
||||
verbose: true,
|
||||
setupFiles: ['dotenv/config'],
|
||||
collectCoverageFrom: ['src/**/*.ts'],
|
||||
testEnvironmentOptions: {
|
||||
url: process.env.TEST_URL || 'http://localhost',
|
||||
},
|
||||
};
|
||||
@@ -63,9 +63,9 @@
|
||||
"cleanup": "rimraf dist",
|
||||
"dev": "cross-env NODE_ENV=development SERVE_APP=false ts-node-dev --files --transpile-only --respawn --watch \".env\" --inspect=0 --exit-child -- src/start.ts",
|
||||
"cli": "cross-env NODE_ENV=development SERVE_APP=false ts-node --script-mode --transpile-only src/cli/run.ts",
|
||||
"test": "jest",
|
||||
"test:coverage": "jest --coverage",
|
||||
"test:watch": "jest --watch"
|
||||
"test": "vitest run",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"test:watch": "vitest"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
@@ -197,7 +197,6 @@
|
||||
"@types/flat": "5.0.2",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
"@types/inquirer": "8.2.1",
|
||||
"@types/jest": "29.2.0",
|
||||
"@types/js-yaml": "4.0.5",
|
||||
"@types/json2csv": "5.0.3",
|
||||
"@types/jsonwebtoken": "8.5.9",
|
||||
@@ -221,16 +220,16 @@
|
||||
"@types/uuid": "8.3.4",
|
||||
"@types/uuid-validate": "0.0.1",
|
||||
"@types/wellknown": "0.5.3",
|
||||
"@vitest/coverage-c8": "^0.25.1",
|
||||
"copyfiles": "2.4.1",
|
||||
"cross-env": "7.0.3",
|
||||
"form-data": "4.0.0",
|
||||
"jest": "29.2.1",
|
||||
"knex-mock-client": "1.8.4",
|
||||
"rimraf": "3.0.2",
|
||||
"supertest": "6.3.0",
|
||||
"ts-jest": "29.0.3",
|
||||
"ts-node": "10.9.1",
|
||||
"ts-node-dev": "2.0.0",
|
||||
"typescript": "4.8.4"
|
||||
"typescript": "4.8.4",
|
||||
"vitest": "0.25.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const getCache = jest.fn().mockReturnValue({ cache: undefined, systemCache: undefined, lockCache: undefined });
|
||||
export const flushCaches = jest.fn();
|
||||
export const clearSystemCache = jest.fn();
|
||||
export const setSystemCache = jest.fn();
|
||||
import { vi } from 'vitest';
|
||||
export const getCache = vi.fn().mockReturnValue({ cache: undefined, systemCache: undefined, lockCache: undefined });
|
||||
export const flushCaches = vi.fn();
|
||||
export const clearSystemCache = vi.fn();
|
||||
export const setSystemCache = vi.fn();
|
||||
|
||||
@@ -1,39 +1,48 @@
|
||||
import path from 'path';
|
||||
import { Command } from 'commander';
|
||||
import { Extension, HookConfig } from '@directus/shared/types';
|
||||
import { createCli } from './index';
|
||||
import path from 'path';
|
||||
import { test, describe, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
jest.mock('../../src/env', () => ({
|
||||
...jest.requireActual('../../src/env').default,
|
||||
EXTENSIONS_PATH: '',
|
||||
SERVE_APP: false,
|
||||
DB_CLIENT: 'pg',
|
||||
DB_HOST: 'localhost',
|
||||
DB_PORT: 5432,
|
||||
DB_DATABASE: 'directus',
|
||||
DB_USER: 'postgres',
|
||||
DB_PASSWORD: 'psql1234',
|
||||
}));
|
||||
vi.mock('../../src/env', async () => {
|
||||
const actual = (await vi.importActual('../../src/env')) as { default: Record<string, any> };
|
||||
|
||||
jest.mock('@directus/shared/utils/node/get-extensions', () => ({
|
||||
getPackageExtensions: jest.fn(() => Promise.resolve([])),
|
||||
getLocalExtensions: jest.fn(() => Promise.resolve([customCliExtension])),
|
||||
}));
|
||||
return {
|
||||
default: {
|
||||
...actual.default,
|
||||
EXTENSIONS_PATH: '',
|
||||
SERVE_APP: false,
|
||||
DB_CLIENT: 'pg',
|
||||
DB_HOST: 'localhost',
|
||||
DB_PORT: 5432,
|
||||
DB_DATABASE: 'directus',
|
||||
DB_USER: 'postgres',
|
||||
DB_PASSWORD: 'psql1234',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const customHookPath = path.resolve('/hooks/custom-cli', 'index.js');
|
||||
jest.doMock(customHookPath, () => customCliHook, { virtual: true });
|
||||
vi.mock('@directus/shared/utils/node', async () => {
|
||||
const actual = await vi.importActual('@directus/shared/utils/node');
|
||||
|
||||
const customCliExtension: Extension = {
|
||||
path: `/hooks/custom-cli`,
|
||||
name: 'custom-cli',
|
||||
type: 'hook',
|
||||
entrypoint: 'index.js',
|
||||
local: true,
|
||||
};
|
||||
const customCliExtension: Extension = {
|
||||
path: '/hooks/custom-cli',
|
||||
name: 'custom-cli',
|
||||
type: 'hook',
|
||||
entrypoint: 'index.js',
|
||||
local: true,
|
||||
};
|
||||
|
||||
const beforeHook = jest.fn();
|
||||
const afterAction = jest.fn();
|
||||
const afterHook = jest.fn(({ program }) => {
|
||||
return {
|
||||
...(actual as object),
|
||||
getPackageExtensions: vi.fn(() => Promise.resolve([])),
|
||||
getLocalExtensions: vi.fn(() => Promise.resolve([customCliExtension])),
|
||||
};
|
||||
});
|
||||
|
||||
const beforeHook = vi.fn();
|
||||
const afterAction = vi.fn();
|
||||
const afterHook = vi.fn(({ program }) => {
|
||||
(program as Command).command('custom').action(afterAction);
|
||||
});
|
||||
|
||||
@@ -42,8 +51,12 @@ const customCliHook: HookConfig = ({ init }) => {
|
||||
init('cli.after', afterHook);
|
||||
};
|
||||
|
||||
const writeOut = jest.fn();
|
||||
const writeErr = jest.fn();
|
||||
vi.mock(path.resolve('/hooks/custom-cli', 'index.js'), () => ({
|
||||
default: customCliHook,
|
||||
}));
|
||||
|
||||
const writeOut = vi.fn();
|
||||
const writeErr = vi.fn();
|
||||
|
||||
const setup = async () => {
|
||||
const program = await createCli();
|
||||
@@ -52,7 +65,9 @@ const setup = async () => {
|
||||
return program;
|
||||
};
|
||||
|
||||
beforeEach(jest.clearAllMocks);
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('cli hooks', () => {
|
||||
test('should call hooks before and after creating the cli', async () => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// @ts-nocheck
|
||||
|
||||
jest.mock('../../src/cache');
|
||||
jest.mock('../../src/database');
|
||||
jest.mock('../../src/utils/validate-env');
|
||||
|
||||
import { multipartHandler } from './files';
|
||||
import { InvalidPayloadException } from '../exceptions/invalid-payload';
|
||||
import { PassThrough } from 'stream';
|
||||
|
||||
import FormData from 'form-data';
|
||||
import { vi, describe, expect, it } from 'vitest';
|
||||
|
||||
vi.mock('../../src/cache');
|
||||
vi.mock('../../src/database');
|
||||
vi.mock('../../src/utils/validate-env');
|
||||
|
||||
describe('multipartHandler', () => {
|
||||
it(`Errors out if request doesn't contain any files to upload`, () => {
|
||||
@@ -18,7 +18,7 @@ describe('multipartHandler', () => {
|
||||
|
||||
const req = {
|
||||
headers: fakeForm.getHeaders(),
|
||||
is: jest.fn().mockReturnValue(true),
|
||||
is: vi.fn().mockReturnValue(true),
|
||||
body: fakeForm.getBuffer(),
|
||||
params: {},
|
||||
pipe: (input) => stream.pipe(input),
|
||||
@@ -45,7 +45,7 @@ describe('multipartHandler', () => {
|
||||
|
||||
const req = {
|
||||
headers: fakeForm.getHeaders(),
|
||||
is: jest.fn().mockReturnValue(true),
|
||||
is: vi.fn().mockReturnValue(true),
|
||||
body: fakeForm.getBuffer(),
|
||||
params: {},
|
||||
pipe: (input) => stream.pipe(input),
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import knex, { Knex } from 'knex';
|
||||
import { getTracker, MockClient, Tracker } from 'knex-mock-client';
|
||||
import run from './run';
|
||||
import { describe, beforeAll, afterEach, it, expect } from 'vitest';
|
||||
|
||||
describe('run', () => {
|
||||
let db: jest.Mocked<Knex>;
|
||||
let db: Knex;
|
||||
let tracker: Tracker;
|
||||
|
||||
beforeAll(() => {
|
||||
db = knex({ client: MockClient }) as jest.Mocked<Knex>;
|
||||
db = knex({ client: MockClient });
|
||||
tracker = getTracker();
|
||||
});
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ export default async function run(database: Knex, direction: 'up' | 'down' | 'la
|
||||
throw Error('Nothing to upgrade');
|
||||
}
|
||||
|
||||
const { up } = require(nextVersion.file);
|
||||
const { up } = await import(nextVersion.file);
|
||||
|
||||
if (log) {
|
||||
logger.info(`Applying ${nextVersion.name}...`);
|
||||
@@ -86,7 +86,7 @@ export default async function run(database: Knex, direction: 'up' | 'down' | 'la
|
||||
throw new Error("Couldn't find migration");
|
||||
}
|
||||
|
||||
const { down } = require(migration.file);
|
||||
const { down } = await import(migration.file);
|
||||
|
||||
if (log) {
|
||||
logger.info(`Undoing ${migration.name}...`);
|
||||
@@ -99,7 +99,7 @@ export default async function run(database: Knex, direction: 'up' | 'down' | 'la
|
||||
async function latest() {
|
||||
for (const migration of migrations) {
|
||||
if (migration.completed === false) {
|
||||
const { up } = require(migration.file);
|
||||
const { up } = await import(migration.file);
|
||||
|
||||
if (log) {
|
||||
logger.info(`Applying ${migration.name}...`);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { describe, test, expect, vi } from 'vitest';
|
||||
|
||||
const testEnv = {
|
||||
NUMBER: '1234',
|
||||
NUMBER_CAST_AS_STRING: 'string:1234',
|
||||
@@ -7,20 +9,9 @@ const testEnv = {
|
||||
MULTIPLE: 'array:string:https://example.com,regex:\\.example2\\.com$',
|
||||
};
|
||||
|
||||
describe('env processed values', () => {
|
||||
const originalEnv = process.env;
|
||||
let env: Record<string, any>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
process.env = { ...testEnv };
|
||||
env = jest.requireActual('../src/env').default;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
describe('env processed values', async () => {
|
||||
process.env = { ...testEnv };
|
||||
const env = ((await vi.importActual('../src/env')) as { default: Record<string, any> }).default;
|
||||
|
||||
test('Number value should be a number', () => {
|
||||
expect(env.NUMBER).toStrictEqual(1234);
|
||||
|
||||
@@ -197,7 +197,7 @@ class ExtensionManager {
|
||||
logger.warn(err);
|
||||
}
|
||||
|
||||
this.registerHooks();
|
||||
await this.registerHooks();
|
||||
this.registerEndpoints();
|
||||
await this.registerOperations();
|
||||
|
||||
@@ -341,13 +341,12 @@ class ExtensionManager {
|
||||
return depsMapping;
|
||||
}
|
||||
|
||||
private registerHooks(): void {
|
||||
private async registerHooks(): Promise<void> {
|
||||
const hooks = this.extensions.filter((extension): extension is ApiExtension => extension.type === 'hook');
|
||||
|
||||
for (const hook of hooks) {
|
||||
try {
|
||||
const hookPath = path.resolve(hook.path, hook.entrypoint);
|
||||
const hookInstance: HookConfig | { default: HookConfig } = require(hookPath);
|
||||
const hookInstance: HookConfig | { default: HookConfig } = await import(hookPath);
|
||||
|
||||
const config = getModuleDefault(hookInstance);
|
||||
|
||||
|
||||
@@ -7,28 +7,31 @@ import env from '../env';
|
||||
import { InvalidCredentialsException } from '../exceptions';
|
||||
import { handler } from './authenticate';
|
||||
import '../../src/types/express.d.ts';
|
||||
import { vi, afterEach, test, expect } from 'vitest';
|
||||
|
||||
jest.mock('../../src/database');
|
||||
jest.mock('../../src/env', () => ({
|
||||
SECRET: 'test',
|
||||
vi.mock('../../src/database');
|
||||
vi.mock('../../src/env', () => ({
|
||||
default: {
|
||||
SECRET: 'test',
|
||||
},
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
test('Short-circuits when authenticate filter is used', async () => {
|
||||
const req = {
|
||||
ip: '127.0.0.1',
|
||||
get: jest.fn(),
|
||||
get: vi.fn(),
|
||||
};
|
||||
|
||||
const res = {};
|
||||
const next = jest.fn();
|
||||
const next = vi.fn();
|
||||
|
||||
const customAccountability = { admin: true };
|
||||
|
||||
jest.spyOn(emitter, 'emitFilter').mockResolvedValue(customAccountability);
|
||||
vi.spyOn(emitter, 'emitFilter').mockResolvedValue(customAccountability);
|
||||
|
||||
await handler(req, res, next);
|
||||
|
||||
@@ -39,7 +42,7 @@ test('Short-circuits when authenticate filter is used', async () => {
|
||||
test('Uses default public accountability when no token is given', async () => {
|
||||
const req = {
|
||||
ip: '127.0.0.1',
|
||||
get: jest.fn((string) => {
|
||||
get: vi.fn((string) => {
|
||||
switch (string) {
|
||||
case 'user-agent':
|
||||
return 'fake-user-agent';
|
||||
@@ -52,9 +55,9 @@ test('Uses default public accountability when no token is given', async () => {
|
||||
};
|
||||
|
||||
const res = {};
|
||||
const next = jest.fn();
|
||||
const next = vi.fn();
|
||||
|
||||
jest.spyOn(emitter, 'emitFilter').mockImplementation((_, payload) => payload);
|
||||
vi.spyOn(emitter, 'emitFilter').mockImplementation((_, payload) => payload);
|
||||
|
||||
await handler(req, res, next);
|
||||
|
||||
@@ -97,7 +100,7 @@ test('Sets accountability to payload contents if valid token is passed', async (
|
||||
|
||||
const req = {
|
||||
ip: '127.0.0.1',
|
||||
get: jest.fn((string) => {
|
||||
get: vi.fn((string) => {
|
||||
switch (string) {
|
||||
case 'user-agent':
|
||||
return 'fake-user-agent';
|
||||
@@ -111,7 +114,7 @@ test('Sets accountability to payload contents if valid token is passed', async (
|
||||
};
|
||||
|
||||
const res = {};
|
||||
const next = jest.fn();
|
||||
const next = vi.fn();
|
||||
|
||||
await handler(req, res, next);
|
||||
|
||||
@@ -163,17 +166,17 @@ test('Sets accountability to payload contents if valid token is passed', async (
|
||||
});
|
||||
|
||||
test('Throws InvalidCredentialsException when static token is used, but user does not exist', async () => {
|
||||
jest.mocked(getDatabase).mockReturnValue({
|
||||
select: jest.fn().mockReturnThis(),
|
||||
from: jest.fn().mockReturnThis(),
|
||||
leftJoin: jest.fn().mockReturnThis(),
|
||||
where: jest.fn().mockReturnThis(),
|
||||
first: jest.fn().mockResolvedValue(undefined),
|
||||
vi.mocked(getDatabase).mockReturnValue({
|
||||
select: vi.fn().mockReturnThis(),
|
||||
from: vi.fn().mockReturnThis(),
|
||||
leftJoin: vi.fn().mockReturnThis(),
|
||||
where: vi.fn().mockReturnThis(),
|
||||
first: vi.fn().mockResolvedValue(undefined),
|
||||
});
|
||||
|
||||
const req = {
|
||||
ip: '127.0.0.1',
|
||||
get: jest.fn((string) => {
|
||||
get: vi.fn((string) => {
|
||||
switch (string) {
|
||||
case 'user-agent':
|
||||
return 'fake-user-agent';
|
||||
@@ -187,7 +190,7 @@ test('Throws InvalidCredentialsException when static token is used, but user doe
|
||||
};
|
||||
|
||||
const res = {};
|
||||
const next = jest.fn();
|
||||
const next = vi.fn();
|
||||
|
||||
expect(handler(req, res, next)).rejects.toEqual(new InvalidCredentialsException());
|
||||
expect(next).toHaveBeenCalledTimes(0);
|
||||
@@ -196,7 +199,7 @@ test('Throws InvalidCredentialsException when static token is used, but user doe
|
||||
test('Sets accountability to user information when static token is used', async () => {
|
||||
const req = {
|
||||
ip: '127.0.0.1',
|
||||
get: jest.fn((string) => {
|
||||
get: vi.fn((string) => {
|
||||
switch (string) {
|
||||
case 'user-agent':
|
||||
return 'fake-user-agent';
|
||||
@@ -210,7 +213,7 @@ test('Sets accountability to user information when static token is used', async
|
||||
};
|
||||
|
||||
const res = {};
|
||||
const next = jest.fn();
|
||||
const next = vi.fn();
|
||||
|
||||
const testUser = { id: 'test-id', role: 'test-role', admin_access: true, app_access: false };
|
||||
|
||||
@@ -224,12 +227,12 @@ test('Sets accountability to user information when static token is used', async
|
||||
origin: 'fake-origin',
|
||||
};
|
||||
|
||||
jest.mocked(getDatabase).mockReturnValue({
|
||||
select: jest.fn().mockReturnThis(),
|
||||
from: jest.fn().mockReturnThis(),
|
||||
leftJoin: jest.fn().mockReturnThis(),
|
||||
where: jest.fn().mockReturnThis(),
|
||||
first: jest.fn().mockResolvedValue(testUser),
|
||||
vi.mocked(getDatabase).mockReturnValue({
|
||||
select: vi.fn().mockReturnThis(),
|
||||
from: vi.fn().mockReturnThis(),
|
||||
leftJoin: vi.fn().mockReturnThis(),
|
||||
where: vi.fn().mockReturnThis(),
|
||||
first: vi.fn().mockResolvedValue(testUser),
|
||||
});
|
||||
|
||||
await handler(req, res, next);
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import { Request, Response } from 'express';
|
||||
import extractToken from '../../src/middleware/extract-token';
|
||||
import '../../src/types/express.d.ts';
|
||||
import { vi, beforeEach, test, expect } from 'vitest';
|
||||
|
||||
let mockRequest: Partial<Request & { token?: string }>;
|
||||
let mockResponse: Partial<Response>;
|
||||
const nextFunction: NextFunction = jest.fn();
|
||||
const nextFunction = vi.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
mockRequest = {};
|
||||
mockResponse = {};
|
||||
jest.clearAllMocks();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test('Token from query', () => {
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import type { NextFunction, Request, Response } from 'express';
|
||||
import type { Request, Response } from 'express';
|
||||
import { validateBatch } from './validate-batch';
|
||||
import '../../src/types/express.d.ts';
|
||||
import { InvalidPayloadException } from '../exceptions';
|
||||
import { FailedValidationException } from '@directus/shared/exceptions';
|
||||
import { vi, beforeEach, test, expect } from 'vitest';
|
||||
|
||||
let mockRequest: Partial<Request & { token?: string }>;
|
||||
let mockResponse: Partial<Response>;
|
||||
const nextFunction: NextFunction = jest.fn();
|
||||
const nextFunction = vi.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
mockRequest = {};
|
||||
mockResponse = {};
|
||||
jest.clearAllMocks();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test('Sets body to empty, calls next on GET requests', async () => {
|
||||
@@ -39,7 +40,7 @@ test('Throws InvalidPayloadException on missing body', async () => {
|
||||
await validateBatch('read')(mockRequest as Request, mockResponse as Response, nextFunction);
|
||||
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
expect(jest.mocked(nextFunction).mock.calls[0][0]).toBeInstanceOf(InvalidPayloadException);
|
||||
expect(vi.mocked(nextFunction).mock.calls[0][0]).toBeInstanceOf(InvalidPayloadException);
|
||||
});
|
||||
|
||||
test(`Short circuits on Array body in update/delete use`, async () => {
|
||||
@@ -74,10 +75,10 @@ test(`Doesn't allow both query and keys in a batch delete`, async () => {
|
||||
query: { filter: {} },
|
||||
};
|
||||
|
||||
await validateBatch('delete')(mockRequest as Request, mockResponse as Response, nextFunction as NextFunction);
|
||||
await validateBatch('delete')(mockRequest as Request, mockResponse as Response, nextFunction);
|
||||
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
expect(jest.mocked(nextFunction).mock.calls[0][0]).toBeInstanceOf(FailedValidationException);
|
||||
expect(vi.mocked(nextFunction).mock.calls[0][0]).toBeInstanceOf(FailedValidationException);
|
||||
});
|
||||
|
||||
test(`Requires 'data' on batch update`, async () => {
|
||||
@@ -87,10 +88,10 @@ test(`Requires 'data' on batch update`, async () => {
|
||||
query: { filter: {} },
|
||||
};
|
||||
|
||||
await validateBatch('update')(mockRequest as Request, mockResponse as Response, nextFunction as NextFunction);
|
||||
await validateBatch('update')(mockRequest as Request, mockResponse as Response, nextFunction);
|
||||
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
expect(jest.mocked(nextFunction).mock.calls[0][0]).toBeInstanceOf(FailedValidationException);
|
||||
expect(vi.mocked(nextFunction).mock.calls[0][0]).toBeInstanceOf(FailedValidationException);
|
||||
});
|
||||
|
||||
test(`Calls next when all is well`, async () => {
|
||||
@@ -101,8 +102,8 @@ test(`Calls next when all is well`, async () => {
|
||||
data: {},
|
||||
};
|
||||
|
||||
await validateBatch('update')(mockRequest as Request, mockResponse as Response, nextFunction as NextFunction);
|
||||
await validateBatch('update')(mockRequest as Request, mockResponse as Response, nextFunction);
|
||||
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
expect(jest.mocked(nextFunction).mock.calls[0][0]).toBeUndefined();
|
||||
expect(vi.mocked(nextFunction).mock.calls[0][0]).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { VMError } from 'vm2';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
import config from './index';
|
||||
|
||||
@@ -29,7 +30,7 @@ test('Rejects when code contains syntax errors', async () => {
|
||||
FLOWS_EXEC_ALLOWED_MODULES: '',
|
||||
},
|
||||
} as any)
|
||||
).rejects.toEqual(new Error("Couldn't compile code: Unexpected end of input"));
|
||||
).rejects.toEqual(new SyntaxError('Unexpected end of input'));
|
||||
});
|
||||
|
||||
test('Rejects when returned function does something illegal', async () => {
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
import { Field } from '@directus/shared/types';
|
||||
import knex, { Knex } from 'knex';
|
||||
import { getTracker, MockClient, Tracker } from 'knex-mock-client';
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, MockedFunction, SpyInstance, vi } from 'vitest';
|
||||
import { FieldsService } from '.';
|
||||
import { InvalidPayloadException } from '../exceptions';
|
||||
|
||||
jest.mock('../../src/database/index', () => {
|
||||
vi.mock('../../src/database/index', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
default: jest.fn(),
|
||||
getDatabaseClient: jest.fn().mockReturnValue('postgres'),
|
||||
getSchemaInspector: jest.fn(),
|
||||
default: vi.fn(),
|
||||
getDatabaseClient: vi.fn().mockReturnValue('postgres'),
|
||||
getSchemaInspector: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
let db: jest.Mocked<Knex>;
|
||||
let db: MockedFunction<Knex>;
|
||||
let tracker: Tracker;
|
||||
|
||||
beforeAll(() => {
|
||||
db = knex({ client: MockClient }) as jest.Mocked<Knex>;
|
||||
db = vi.mocked(knex({ client: MockClient }));
|
||||
tracker = getTracker();
|
||||
});
|
||||
|
||||
@@ -36,11 +37,11 @@ describe('Integration Tests', () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('addColumnToTable', () => {
|
||||
let knexCreateTableBuilderSpy: jest.SpyInstance;
|
||||
let knexCreateTableBuilderSpy: SpyInstance;
|
||||
|
||||
it.each(['alias', 'unknown'])('%s fields should be skipped', async (type) => {
|
||||
const testCollection = 'test_collection';
|
||||
@@ -101,7 +102,7 @@ describe('Integration Tests', () => {
|
||||
tracker.on.any(regex).response({});
|
||||
|
||||
await db.schema.alterTable(testCollection, (table) => {
|
||||
knexCreateTableBuilderSpy = jest.spyOn(table, method as keyof Knex.CreateTableBuilder);
|
||||
knexCreateTableBuilderSpy = vi.spyOn(table, method as keyof Knex.CreateTableBuilder);
|
||||
|
||||
service.addColumnToTable(table, {
|
||||
collection: testCollection,
|
||||
@@ -129,7 +130,7 @@ describe('Integration Tests', () => {
|
||||
tracker.on.any(regex).response({});
|
||||
|
||||
await db.schema.alterTable(testCollection, (table) => {
|
||||
knexCreateTableBuilderSpy = jest.spyOn(table, type as keyof Knex.CreateTableBuilder);
|
||||
knexCreateTableBuilderSpy = vi.spyOn(table, type as keyof Knex.CreateTableBuilder);
|
||||
|
||||
service.addColumnToTable(table, {
|
||||
collection: testCollection,
|
||||
@@ -158,7 +159,7 @@ describe('Integration Tests', () => {
|
||||
tracker.on.any(regex).response({});
|
||||
|
||||
await db.schema.alterTable(testCollection, (table) => {
|
||||
knexCreateTableBuilderSpy = jest.spyOn(table, type as keyof Knex.CreateTableBuilder);
|
||||
knexCreateTableBuilderSpy = vi.spyOn(table, type as keyof Knex.CreateTableBuilder);
|
||||
|
||||
service.addColumnToTable(table, {
|
||||
collection: testCollection,
|
||||
@@ -187,7 +188,7 @@ describe('Integration Tests', () => {
|
||||
tracker.on.any(regex).response({});
|
||||
|
||||
await db.schema.alterTable('test_collection', (table) => {
|
||||
knexCreateTableBuilderSpy = jest.spyOn(table, type as keyof Knex.CreateTableBuilder);
|
||||
knexCreateTableBuilderSpy = vi.spyOn(table, type as keyof Knex.CreateTableBuilder);
|
||||
|
||||
service.addColumnToTable(table, {
|
||||
collection: testCollection,
|
||||
@@ -217,7 +218,7 @@ describe('Integration Tests', () => {
|
||||
tracker.on.any(regex).response({});
|
||||
|
||||
await db.schema.alterTable(testCollection, (table) => {
|
||||
knexCreateTableBuilderSpy = jest.spyOn(table, 'string');
|
||||
knexCreateTableBuilderSpy = vi.spyOn(table, 'string');
|
||||
|
||||
service.addColumnToTable(table, {
|
||||
collection: testCollection,
|
||||
@@ -244,7 +245,7 @@ describe('Integration Tests', () => {
|
||||
tracker.on.any(regex).response({});
|
||||
|
||||
await db.schema.alterTable(testCollection, (table) => {
|
||||
knexCreateTableBuilderSpy = jest.spyOn(table, 'string');
|
||||
knexCreateTableBuilderSpy = vi.spyOn(table, 'string');
|
||||
|
||||
service.addColumnToTable(table, {
|
||||
collection: testCollection,
|
||||
@@ -273,7 +274,7 @@ describe('Integration Tests', () => {
|
||||
tracker.on.any(regex).response({});
|
||||
|
||||
await db.schema.alterTable(testCollection, (table) => {
|
||||
knexCreateTableBuilderSpy = jest.spyOn(table, type as keyof Knex.CreateTableBuilder);
|
||||
knexCreateTableBuilderSpy = vi.spyOn(table, type as keyof Knex.CreateTableBuilder);
|
||||
|
||||
service.addColumnToTable(table, {
|
||||
collection: testCollection,
|
||||
@@ -298,7 +299,7 @@ describe('Integration Tests', () => {
|
||||
const regex = new RegExp(`alter table "${testCollection}" add column "${testField}" .*`);
|
||||
tracker.on.any(regex).response({});
|
||||
|
||||
const thisHelpersStCreateColumnSpy = jest.spyOn(service.helpers.st, 'createColumn');
|
||||
const thisHelpersStCreateColumnSpy = vi.spyOn(service.helpers.st, 'createColumn');
|
||||
|
||||
await db.schema.alterTable(testCollection, (table) => {
|
||||
service.addColumnToTable(table, {
|
||||
@@ -334,7 +335,7 @@ describe('Integration Tests', () => {
|
||||
tracker.on.any(regex).response({});
|
||||
|
||||
await db.schema.alterTable(testCollection, (table) => {
|
||||
knexCreateTableBuilderSpy = jest.spyOn(table, type as keyof Knex.CreateTableBuilder);
|
||||
knexCreateTableBuilderSpy = vi.spyOn(table, type as keyof Knex.CreateTableBuilder);
|
||||
|
||||
service.addColumnToTable(table, {
|
||||
collection: testCollection,
|
||||
|
||||
@@ -3,38 +3,39 @@ import knex, { Knex } from 'knex';
|
||||
import { MockClient, Tracker, getTracker } from 'knex-mock-client';
|
||||
import { FilesService, ItemsService } from '.';
|
||||
import { InvalidPayloadException } from '../exceptions';
|
||||
import { describe, beforeAll, afterEach, expect, it, vi, beforeEach, SpyInstance } from 'vitest';
|
||||
|
||||
jest.mock('exifr');
|
||||
jest.mock('../../src/database/index', () => {
|
||||
return { getDatabaseClient: jest.fn().mockReturnValue('postgres') };
|
||||
vi.mock('exifr');
|
||||
vi.mock('../../src/database/index', () => {
|
||||
return { getDatabaseClient: vi.fn().mockReturnValue('postgres') };
|
||||
});
|
||||
jest.requireMock('../../src/database/index');
|
||||
vi.mock('../../src/database/index');
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
let db: jest.Mocked<Knex>;
|
||||
let db: Knex;
|
||||
let tracker: Tracker;
|
||||
|
||||
beforeAll(async () => {
|
||||
db = knex({ client: MockClient }) as jest.Mocked<Knex>;
|
||||
db = knex({ client: MockClient });
|
||||
tracker = getTracker();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
tracker.reset();
|
||||
jest.clearAllMocks();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Services / Files', () => {
|
||||
describe('createOne', () => {
|
||||
let service: FilesService;
|
||||
let superCreateOne: jest.SpyInstance;
|
||||
let superCreateOne: SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
service = new FilesService({
|
||||
knex: db,
|
||||
schema: { collections: {}, relations: [] },
|
||||
});
|
||||
superCreateOne = jest.spyOn(ItemsService.prototype, 'createOne').mockImplementation(jest.fn());
|
||||
superCreateOne = vi.spyOn(ItemsService.prototype, 'createOne').mockReturnValue(Promise.resolve(1));
|
||||
});
|
||||
|
||||
it('throws InvalidPayloadException when "type" is not provided', async () => {
|
||||
@@ -66,7 +67,7 @@ describe('Integration Tests', () => {
|
||||
|
||||
describe('getMetadata', () => {
|
||||
let service: FilesService;
|
||||
let exifrParseSpy: jest.SpyInstance<any>;
|
||||
let exifrParseSpy: SpyInstance<any>;
|
||||
|
||||
const sampleMetadata = {
|
||||
CustomTagA: 'value a',
|
||||
@@ -75,7 +76,7 @@ describe('Integration Tests', () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
exifrParseSpy = jest.spyOn(exifr, 'parse');
|
||||
exifrParseSpy = vi.spyOn(exifr, 'parse');
|
||||
service = new FilesService({
|
||||
knex: db,
|
||||
schema: { collections: {}, relations: [] },
|
||||
|
||||
@@ -5,14 +5,15 @@ import { ItemsService } from '../../src/services';
|
||||
import { sqlFieldFormatter, sqlFieldList } from '../__utils__/items-utils';
|
||||
import { systemSchema, userSchema } from '../__utils__/schemas';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { describe, beforeAll, afterEach, it, expect, vi } from 'vitest';
|
||||
|
||||
jest.mock('../../src/database/index', () => {
|
||||
return { getDatabaseClient: jest.fn().mockReturnValue('postgres') };
|
||||
vi.mock('../../src/database/index', () => {
|
||||
return { getDatabaseClient: vi.fn().mockReturnValue('postgres') };
|
||||
});
|
||||
jest.requireMock('../../src/database/index');
|
||||
vi.mock('../../src/database/index');
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
let db: jest.Mocked<Knex>;
|
||||
let db: Knex;
|
||||
let tracker: Tracker;
|
||||
|
||||
const schemas: Record<string, any> = {
|
||||
@@ -21,7 +22,7 @@ describe('Integration Tests', () => {
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
db = knex({ client: MockClient }) as jest.Mocked<Knex>;
|
||||
db = knex({ client: MockClient });
|
||||
tracker = getTracker();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { NotificationsService, ItemsService } from '.';
|
||||
import { afterEach, beforeEach, describe, expect, it, SpyInstance, vi } from 'vitest';
|
||||
import { ItemsService, NotificationsService } from '.';
|
||||
|
||||
jest.mock('../../src/env', () => ({
|
||||
...jest.requireActual('../../src/env').default,
|
||||
vi.mock('../../src/env', async () => ({
|
||||
...(await vi.importActual<any>('../../src/env')),
|
||||
PUBLIC_URL: '/',
|
||||
}));
|
||||
|
||||
jest.mock('../../src/database/index', () => {
|
||||
return { __esModule: true, default: jest.fn(), getDatabaseClient: jest.fn().mockReturnValue('postgres') };
|
||||
vi.mock('../../src/database/index', () => {
|
||||
return { __esModule: true, default: vi.fn(), getDatabaseClient: vi.fn().mockReturnValue('postgres') };
|
||||
});
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
@@ -20,16 +21,16 @@ describe('Integration Tests', () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('createOne', () => {
|
||||
let superCreateOneSpy: jest.SpyInstance;
|
||||
let thisSendEmailSpy: jest.SpyInstance;
|
||||
let superCreateOneSpy: SpyInstance;
|
||||
let thisSendEmailSpy: SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
superCreateOneSpy = jest.spyOn(ItemsService.prototype, 'createOne').mockImplementation(jest.fn());
|
||||
thisSendEmailSpy = jest.spyOn(NotificationsService.prototype, 'sendEmail').mockImplementation(jest.fn());
|
||||
superCreateOneSpy = vi.spyOn(ItemsService.prototype, 'createOne').mockResolvedValue(0);
|
||||
thisSendEmailSpy = vi.spyOn(NotificationsService.prototype, 'sendEmail').mockResolvedValue();
|
||||
});
|
||||
|
||||
it('create a notification and send email', async () => {
|
||||
@@ -49,12 +50,12 @@ describe('Integration Tests', () => {
|
||||
});
|
||||
|
||||
describe('createMany', () => {
|
||||
let superCreateManySpy: jest.SpyInstance;
|
||||
let thisSendEmailSpy: jest.SpyInstance;
|
||||
let superCreateManySpy: SpyInstance;
|
||||
let thisSendEmailSpy: SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
superCreateManySpy = jest.spyOn(ItemsService.prototype, 'createMany').mockImplementation(jest.fn());
|
||||
thisSendEmailSpy = jest.spyOn(NotificationsService.prototype, 'sendEmail').mockImplementation(jest.fn());
|
||||
superCreateManySpy = vi.spyOn(ItemsService.prototype, 'createMany').mockResolvedValue([]);
|
||||
thisSendEmailSpy = vi.spyOn(NotificationsService.prototype, 'sendEmail').mockResolvedValue();
|
||||
});
|
||||
|
||||
it('create many notifications and send email for notification', async () => {
|
||||
@@ -81,12 +82,12 @@ describe('Integration Tests', () => {
|
||||
});
|
||||
|
||||
describe('sendEmail', () => {
|
||||
let usersServiceReadOneSpy: jest.SpyInstance;
|
||||
let mailServiceSendSpy: jest.SpyInstance;
|
||||
let usersServiceReadOneSpy: SpyInstance;
|
||||
let mailServiceSendSpy: SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
usersServiceReadOneSpy = jest.spyOn(service.usersService, 'readOne').mockImplementation(jest.fn());
|
||||
mailServiceSendSpy = jest.spyOn(service.mailService, 'send').mockImplementation(jest.fn());
|
||||
usersServiceReadOneSpy = vi.spyOn(service.usersService, 'readOne').mockResolvedValue({});
|
||||
mailServiceSendSpy = vi.spyOn(service.mailService, 'send').mockResolvedValue(0);
|
||||
});
|
||||
|
||||
it('do nothing when there is no recipient', async () => {
|
||||
|
||||
@@ -2,18 +2,19 @@ import knex, { Knex } from 'knex';
|
||||
import { MockClient, Tracker, getTracker } from 'knex-mock-client';
|
||||
import { PayloadService } from '../../src/services';
|
||||
import { getHelpers, Helpers } from '../../src/database/helpers';
|
||||
import { describe, beforeAll, afterEach, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
jest.mock('../../src/database/index', () => {
|
||||
return { getDatabaseClient: jest.fn().mockReturnValue('postgres') };
|
||||
vi.mock('../../src/database/index', () => {
|
||||
return { getDatabaseClient: vi.fn().mockReturnValue('postgres') };
|
||||
});
|
||||
jest.requireMock('../../src/database/index');
|
||||
vi.mock('../../src/database/index');
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
let db: jest.Mocked<Knex>;
|
||||
let db: Knex;
|
||||
let tracker: Tracker;
|
||||
|
||||
beforeAll(async () => {
|
||||
db = knex({ client: MockClient }) as jest.Mocked<Knex>;
|
||||
db = knex({ client: MockClient });
|
||||
tracker = getTracker();
|
||||
});
|
||||
|
||||
@@ -218,7 +219,6 @@ describe('Integration Tests', () => {
|
||||
],
|
||||
'read'
|
||||
);
|
||||
|
||||
expect(result).toMatchObject([
|
||||
{
|
||||
[dateFieldId]: '2022-01-10',
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
import knex, { Knex } from 'knex';
|
||||
import { getTracker, MockClient, Tracker } from 'knex-mock-client';
|
||||
import { CollectionsService, FieldsService, RelationsService, SpecificationService } from '../../src/services';
|
||||
import { describe, beforeAll, afterEach, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
jest.mock('../../src/database/index', () => {
|
||||
return { getDatabaseClient: jest.fn().mockReturnValue('postgres') };
|
||||
vi.mock('../../src/database/index', async () => {
|
||||
const actual = await vi.importActual('@directus/shared/utils/node');
|
||||
|
||||
return {
|
||||
...(actual as object),
|
||||
getDatabaseClient: vi.fn().mockReturnValue('postgres'),
|
||||
};
|
||||
});
|
||||
jest.requireMock('../../src/database/index');
|
||||
|
||||
class Client_PG extends MockClient {}
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
let db: jest.Mocked<Knex>;
|
||||
let db: Knex;
|
||||
let tracker: Tracker;
|
||||
|
||||
beforeAll(async () => {
|
||||
db = knex({ client: Client_PG }) as jest.Mocked<Knex>;
|
||||
db = knex({ client: Client_PG });
|
||||
tracker = getTracker();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
tracker.reset();
|
||||
jest.clearAllMocks();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Services / Specifications', () => {
|
||||
@@ -38,8 +43,8 @@ describe('Integration Tests', () => {
|
||||
|
||||
describe('schema', () => {
|
||||
it('returns untyped schema for json fields', async () => {
|
||||
jest.spyOn(CollectionsService.prototype, 'readByQuery').mockImplementation(
|
||||
jest.fn().mockReturnValue([
|
||||
vi.spyOn(CollectionsService.prototype, 'readByQuery').mockImplementation(
|
||||
vi.fn().mockReturnValue([
|
||||
{
|
||||
collection: 'test_table',
|
||||
meta: {
|
||||
@@ -60,8 +65,8 @@ describe('Integration Tests', () => {
|
||||
])
|
||||
);
|
||||
|
||||
jest.spyOn(FieldsService.prototype, 'readAll').mockImplementation(
|
||||
jest.fn().mockReturnValue([
|
||||
vi.spyOn(FieldsService.prototype, 'readAll').mockImplementation(
|
||||
vi.fn().mockReturnValue([
|
||||
{
|
||||
collection: 'test_table',
|
||||
field: 'id',
|
||||
@@ -80,7 +85,7 @@ describe('Integration Tests', () => {
|
||||
},
|
||||
])
|
||||
);
|
||||
jest.spyOn(RelationsService.prototype, 'readAll').mockImplementation(jest.fn().mockReturnValue([]));
|
||||
vi.spyOn(RelationsService.prototype, 'readAll').mockImplementation(vi.fn().mockReturnValue([]));
|
||||
|
||||
const spec = await service.oas.generate();
|
||||
expect(spec.components?.schemas).toEqual({
|
||||
@@ -121,12 +126,12 @@ describe('Integration Tests', () => {
|
||||
},
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(CollectionsService.prototype, 'readByQuery')
|
||||
.mockImplementation(jest.fn().mockReturnValue([collection]));
|
||||
vi.spyOn(CollectionsService.prototype, 'readByQuery').mockImplementation(
|
||||
vi.fn().mockReturnValue([collection])
|
||||
);
|
||||
|
||||
jest.spyOn(FieldsService.prototype, 'readAll').mockImplementation(
|
||||
jest.fn().mockReturnValue([
|
||||
vi.spyOn(FieldsService.prototype, 'readAll').mockImplementation(
|
||||
vi.fn().mockReturnValue([
|
||||
{
|
||||
collection: collection.collection,
|
||||
field: 'id',
|
||||
@@ -137,7 +142,7 @@ describe('Integration Tests', () => {
|
||||
},
|
||||
])
|
||||
);
|
||||
jest.spyOn(RelationsService.prototype, 'readAll').mockImplementation(jest.fn().mockReturnValue([]));
|
||||
vi.spyOn(RelationsService.prototype, 'readAll').mockImplementation(vi.fn().mockReturnValue([]));
|
||||
|
||||
const spec = await service.oas.generate();
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { SchemaOverview } from '@directus/shared/types';
|
||||
import knex, { Knex } from 'knex';
|
||||
import { getTracker, MockClient, Tracker } from 'knex-mock-client';
|
||||
import { UsersService, ItemsService } from '.';
|
||||
import { afterEach, beforeAll, describe, it, vi, expect, MockedFunction } from 'vitest';
|
||||
import { ItemsService, UsersService } from '.';
|
||||
import { InvalidPayloadException } from '../exceptions';
|
||||
|
||||
jest.mock('../../src/database/index', () => {
|
||||
return { __esModule: true, default: jest.fn(), getDatabaseClient: jest.fn().mockReturnValue('postgres') };
|
||||
vi.mock('../../src/database/index', () => {
|
||||
return { __esModule: true, default: vi.fn(), getDatabaseClient: vi.fn().mockReturnValue('postgres') };
|
||||
});
|
||||
|
||||
const testSchema = {
|
||||
@@ -39,11 +40,11 @@ const testSchema = {
|
||||
} as SchemaOverview;
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
let db: jest.Mocked<Knex>;
|
||||
let db: MockedFunction<Knex>;
|
||||
let tracker: Tracker;
|
||||
|
||||
beforeAll(async () => {
|
||||
db = knex({ client: MockClient }) as jest.Mocked<Knex>;
|
||||
db = vi.mocked(knex({ client: MockClient }));
|
||||
tracker = getTracker();
|
||||
});
|
||||
|
||||
@@ -162,7 +163,7 @@ describe('Integration Tests', () => {
|
||||
accountability: { role: 'test', admin: false },
|
||||
});
|
||||
|
||||
jest.spyOn(ItemsService.prototype, 'getKeysByQuery').mockImplementation(jest.fn(() => Promise.resolve([1])));
|
||||
vi.spyOn(ItemsService.prototype, 'getKeysByQuery').mockImplementation(vi.fn(() => Promise.resolve([1])));
|
||||
|
||||
const promise = service.updateByQuery({}, { [field]: 'test' });
|
||||
|
||||
@@ -184,7 +185,7 @@ describe('Integration Tests', () => {
|
||||
accountability: { role: 'admin', admin: true },
|
||||
});
|
||||
|
||||
jest.spyOn(ItemsService.prototype, 'getKeysByQuery').mockImplementation(jest.fn(() => Promise.resolve([1])));
|
||||
vi.spyOn(ItemsService.prototype, 'getKeysByQuery').mockImplementation(vi.fn(() => Promise.resolve([1])));
|
||||
|
||||
const promise = service.updateByQuery({}, { [field]: 'test' });
|
||||
|
||||
@@ -199,7 +200,7 @@ describe('Integration Tests', () => {
|
||||
schema: testSchema,
|
||||
});
|
||||
|
||||
jest.spyOn(ItemsService.prototype, 'getKeysByQuery').mockImplementation(jest.fn(() => Promise.resolve([1])));
|
||||
vi.spyOn(ItemsService.prototype, 'getKeysByQuery').mockImplementation(vi.fn(() => Promise.resolve([1])));
|
||||
|
||||
const promise = service.updateByQuery({}, { [field]: 'test' });
|
||||
|
||||
|
||||
@@ -12,28 +12,29 @@ import {
|
||||
snapshotBeforeDeleteCollection,
|
||||
} from '../__utils__/snapshots';
|
||||
import { Snapshot } from '../types';
|
||||
import { describe, afterEach, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
jest.mock('../../src/database/index', () => {
|
||||
vi.mock('../../src/database/index', () => {
|
||||
return {
|
||||
getDatabaseClient: jest.fn().mockReturnValue('postgres'),
|
||||
getDatabaseClient: vi.fn().mockReturnValue('postgres'),
|
||||
};
|
||||
});
|
||||
jest.requireMock('../../src/database/index');
|
||||
vi.mock('../../src/database/index');
|
||||
|
||||
class Client_PG extends MockClient {}
|
||||
|
||||
describe('applySnapshot', () => {
|
||||
let db: jest.Mocked<Knex>;
|
||||
let db: Knex;
|
||||
let tracker: Tracker;
|
||||
|
||||
beforeEach(() => {
|
||||
db = knex({ client: Client_PG }) as jest.Mocked<Knex>;
|
||||
db = knex({ client: Client_PG });
|
||||
tracker = getTracker();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
tracker.reset();
|
||||
jest.clearAllMocks();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Creating new collection(s)', () => {
|
||||
@@ -102,12 +103,14 @@ describe('applySnapshot', () => {
|
||||
};
|
||||
|
||||
// Stop call to db later on in apply-snapshot
|
||||
jest.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(snapshotApplyTestSchema));
|
||||
vi.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(snapshotApplyTestSchema));
|
||||
// We are not actually testing that createOne works, just that is is called correctly
|
||||
const createOneCollectionSpy = jest
|
||||
const createOneCollectionSpy = vi
|
||||
.spyOn(CollectionsService.prototype, 'createOne')
|
||||
.mockImplementation(jest.fn());
|
||||
const createFieldSpy = jest.spyOn(FieldsService.prototype, 'createField').mockImplementation(jest.fn());
|
||||
.mockImplementation(vi.fn().mockReturnValue([]));
|
||||
const createFieldSpy = vi
|
||||
.spyOn(FieldsService.prototype, 'createField')
|
||||
.mockImplementation(vi.fn().mockReturnValue([]));
|
||||
|
||||
await applySnapshot(snapshotCreateCollectionNotNested, {
|
||||
database: db,
|
||||
@@ -251,12 +254,14 @@ describe('applySnapshot', () => {
|
||||
};
|
||||
|
||||
// Stop call to db later on in apply-snapshot
|
||||
jest.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(snapshotApplyTestSchema));
|
||||
vi.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(snapshotApplyTestSchema));
|
||||
// We are not actually testing that createOne works, just that is is called correctly
|
||||
const createOneCollectionSpy = jest
|
||||
const createOneCollectionSpy = vi
|
||||
.spyOn(CollectionsService.prototype, 'createOne')
|
||||
.mockImplementation(jest.fn());
|
||||
const createFieldSpy = jest.spyOn(FieldsService.prototype, 'createField').mockImplementation(jest.fn());
|
||||
.mockImplementation(vi.fn().mockReturnValue([]));
|
||||
const createFieldSpy = vi
|
||||
.spyOn(FieldsService.prototype, 'createField')
|
||||
.mockImplementation(vi.fn().mockReturnValue([]));
|
||||
|
||||
await applySnapshot(snapshotCreateCollection, {
|
||||
database: db,
|
||||
@@ -285,11 +290,11 @@ describe('applySnapshot', () => {
|
||||
};
|
||||
|
||||
// Stop call to db later on in apply-snapshot
|
||||
jest.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(snapshotApplyTestSchema));
|
||||
vi.spyOn(getSchema, 'getSchema').mockReturnValue(Promise.resolve(snapshotApplyTestSchema));
|
||||
// We are not actually testing that deleteOne works, just that is is called correctly
|
||||
const deleteOneCollectionSpy = jest
|
||||
const deleteOneCollectionSpy = vi
|
||||
.spyOn(CollectionsService.prototype, 'deleteOne')
|
||||
.mockImplementation(jest.fn());
|
||||
.mockImplementation(vi.fn().mockReturnValue([]));
|
||||
|
||||
await applySnapshot(snapshotToApply, {
|
||||
database: db,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { RequestHandler, NextFunction, Request, Response } from 'express';
|
||||
import type { RequestHandler, Request, Response } from 'express';
|
||||
import '../../src/types/express.d.ts';
|
||||
import asyncHandler from './async-handler';
|
||||
import { expect, vi, test } from 'vitest';
|
||||
|
||||
let mockRequest: Partial<Request & { token?: string }>;
|
||||
let mockResponse: Partial<Response>;
|
||||
const nextFunction: NextFunction = jest.fn();
|
||||
const nextFunction = vi.fn();
|
||||
|
||||
test('Wraps async middleware in Promise resolve that will catch rejects and pass them to the nextFn', async () => {
|
||||
const err = new Error('testing');
|
||||
@@ -13,7 +14,7 @@ test('Wraps async middleware in Promise resolve that will catch rejects and pass
|
||||
throw err;
|
||||
};
|
||||
|
||||
await asyncHandler(middleware)(mockRequest as Request, mockResponse as Response, nextFunction as NextFunction);
|
||||
await asyncHandler(middleware)(mockRequest as Request, mockResponse as Response, nextFunction);
|
||||
|
||||
expect(nextFunction).toHaveBeenCalledWith(err);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { calculateFieldDepth } from '../../src/utils/calculate-field-depth';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
test('Calculates basic depth', () => {
|
||||
const filter = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { filterItems } from '../../src/utils/filter-items';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
|
||||
const items = [
|
||||
{
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { describe, expect, vi, test } from 'vitest';
|
||||
import { getAuthProviders } from '../../src/utils/get-auth-providers';
|
||||
|
||||
let factoryEnv: { [k: string]: any } = {};
|
||||
|
||||
jest.mock(
|
||||
'../../src/env',
|
||||
() =>
|
||||
new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target, prop) {
|
||||
return factoryEnv[prop as string];
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
import { getAuthProviders } from '../../src/utils/get-auth-providers';
|
||||
vi.mock('../../src/env', () => ({
|
||||
default: new Proxy(
|
||||
{},
|
||||
{
|
||||
get(_target, prop) {
|
||||
return factoryEnv[prop as string];
|
||||
},
|
||||
}
|
||||
),
|
||||
}));
|
||||
|
||||
const scenarios = [
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Request } from 'express';
|
||||
import { getCacheKey } from '../../src/utils/get-cache-key';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
|
||||
const restUrl = 'http://localhost/items/example';
|
||||
const graphQlUrl = 'http://localhost/graphql';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { getColumnPath, ColPathProps } from '../../src/utils/get-column-path';
|
||||
import { InvalidQueryException } from '../../src/exceptions';
|
||||
import { DeepPartial } from '@directus/shared/types';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
/*
|
||||
{
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { getConfigFromEnv } from '../../src/utils/get-config-from-env';
|
||||
import { describe, test, expect, vi } from 'vitest';
|
||||
|
||||
jest.mock('../../src/env', () => ({
|
||||
OBJECT_BRAND__COLOR: 'purple',
|
||||
OBJECT_BRAND__HEX: '#6644FF',
|
||||
CAMELCASE_OBJECT__FIRST_KEY: 'firstValue',
|
||||
CAMELCASE_OBJECT__SECOND_KEY: 'secondValue',
|
||||
vi.mock('../../src/env', () => ({
|
||||
default: {
|
||||
OBJECT_BRAND__COLOR: 'purple',
|
||||
OBJECT_BRAND__HEX: '#6644FF',
|
||||
CAMELCASE_OBJECT__FIRST_KEY: 'firstValue',
|
||||
CAMELCASE_OBJECT__SECOND_KEY: 'secondValue',
|
||||
},
|
||||
}));
|
||||
|
||||
describe('get config from env', () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { getRelationInfo } from '../../src/utils/get-relation-info';
|
||||
import { Relation, DeepPartial } from '@directus/shared/types';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('getRelationInfo', () => {
|
||||
it('Errors on suspiciously long implicit $FOLLOW', () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { getRelationType } from '../../src/utils/get-relation-type';
|
||||
import { Relation } from '@directus/shared/types';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
test('Returns null if no relation object is included', () => {
|
||||
const result = getRelationType({ relation: null, collection: null, field: 'test' });
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { stringByteSize } from '../../src/utils/get-string-byte-size';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
test('Returns correct byte size for given input string', () => {
|
||||
expect(stringByteSize('test')).toBe(4);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import isDirectusJWT from '../../src/utils/is-directus-jwt';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
test('Returns false for non JWT string', () => {
|
||||
const result = isDirectusJWT('test');
|
||||
|
||||
@@ -2,6 +2,7 @@ import { verifyAccessJWT } from '../../src/utils/jwt';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { InvalidTokenException, ServiceUnavailableException, TokenExpiredException } from '../../src/exceptions';
|
||||
import { DirectusTokenPayload } from '../../src/types';
|
||||
import { test, expect, vi } from 'vitest';
|
||||
|
||||
const payload: DirectusTokenPayload = { role: null, app_access: false, admin_access: false };
|
||||
const secret = 'test-secret';
|
||||
@@ -32,7 +33,7 @@ Object.entries(InvalidTokenCases).forEach(([title, token]) =>
|
||||
);
|
||||
|
||||
test(`Throws ServiceUnavailableException for unexpected error from jsonwebtoken`, () => {
|
||||
jest.spyOn(jwt, 'verify').mockImplementation(() => {
|
||||
vi.spyOn(jwt, 'verify').mockImplementation(() => {
|
||||
throw new Error();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { mergePermission } from '../../src/utils/merge-permissions';
|
||||
import { Permission, Filter } from '@directus/shared/types';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
const fullFilter = {} as Filter;
|
||||
const conditionalFilter = { user: { id: { _eq: '$CURRENT_USER' } } } as Filter;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { validateKeys } from '../../src/utils/validate-keys';
|
||||
import { SchemaOverview } from '@directus/shared/types';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
const schema: SchemaOverview = {
|
||||
collections: {
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
"lib": ["es2019"],
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"resolveJsonModule": true,
|
||||
"types": ["jest"]
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"exclude": ["node_modules", "dist", "extensions", "tests"]
|
||||
"exclude": ["node_modules", "dist", "extensions", "**/__utils__/*.*", "**/__mocks__/*.*", "**/*.test.ts"]
|
||||
}
|
||||
|
||||
15
api/vitest.config.js
Normal file
15
api/vitest.config.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import path from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globalSetup: 'globalSetup.js',
|
||||
alias: [
|
||||
// TODO: Remove this after moving to ESM
|
||||
{
|
||||
find: '@directus/format-title',
|
||||
replacement: path.resolve(__dirname, '../app/node_modules/@directus/format-title'),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user