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:
Pascal Jufer
2022-11-14 22:09:47 +01:00
committed by GitHub
parent 20b8146221
commit c303bdcf10
40 changed files with 416 additions and 392 deletions

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
import { calculateFieldDepth } from '../../src/utils/calculate-field-depth';
import { test, expect } from 'vitest';
test('Calculates basic depth', () => {
const filter = {

View File

@@ -1,4 +1,5 @@
import { filterItems } from '../../src/utils/filter-items';
import { describe, test, expect } from 'vitest';
const items = [
{

View File

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

View File

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

View File

@@ -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';
/*
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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