mirror of
https://github.com/fluxerapp/fluxer.git
synced 2026-09-02 21:04:06 +03:00
chore(workspace): tighten quality gates (#2230)
This commit is contained in:
@@ -7,7 +7,7 @@ import {
|
||||
extractKVClientConfig,
|
||||
extractRateLimit,
|
||||
} from '@fluxer/config/src/ServiceConfigSlices';
|
||||
import {describe, expect, test} from 'vitest';
|
||||
import {describe, expect, test, vi} from 'vitest';
|
||||
|
||||
function createMasterStub(overrides: Partial<MasterConfig> = {}): MasterConfig {
|
||||
return {
|
||||
@@ -55,12 +55,23 @@ describe('extractKVClientConfig', () => {
|
||||
});
|
||||
|
||||
describe('extractBuildInfoConfig', () => {
|
||||
test('returns releaseChannel and buildVersion', () => {
|
||||
const result = extractBuildInfoConfig();
|
||||
expect(result).toHaveProperty('releaseChannel');
|
||||
expect(result).toHaveProperty('buildVersion');
|
||||
expect(typeof result.releaseChannel).toBe('string');
|
||||
expect(typeof result.buildVersion).toBe('string');
|
||||
test('returns fallback build metadata and reports the missing environment variables', () => {
|
||||
vi.stubEnv('BUILD_VERSION', undefined);
|
||||
vi.stubEnv('RELEASE_CHANNEL', undefined);
|
||||
const stdout = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
||||
try {
|
||||
const result = extractBuildInfoConfig();
|
||||
expect(result).toEqual({
|
||||
releaseChannel: 'stable',
|
||||
buildVersion: 'dev',
|
||||
});
|
||||
expect(stdout).toHaveBeenCalledExactlyOnceWith(
|
||||
'[build-metadata] Using fallback values for: BUILD_VERSION, RELEASE_CHANNEL. This indicates missing env vars in CI/production.\n',
|
||||
);
|
||||
} finally {
|
||||
stdout.mockRestore();
|
||||
vi.unstubAllEnvs();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ import {BadRequestError} from '@fluxer/errors/src/domains/core/BadRequestError';
|
||||
import {AppErrorHandler} from '@fluxer/errors/src/domains/core/ErrorHandlers';
|
||||
import {getErrorMessage} from '@fluxer/errors/src/i18n/ErrorI18n';
|
||||
import type {BaseHonoEnv} from '@fluxer/hono_types/src/HonoTypes';
|
||||
import {Logger} from '@fluxer/logger/src/Logger';
|
||||
import {Hono} from 'hono';
|
||||
import {describe, expect, it} from 'vitest';
|
||||
import {describe, expect, it, vi} from 'vitest';
|
||||
|
||||
interface ErrorResponse {
|
||||
code: string;
|
||||
@@ -22,19 +23,30 @@ function createApp(): Hono<BaseHonoEnv> {
|
||||
|
||||
describe('AppErrorHandler i18n fallbacks', () => {
|
||||
it('localizes unexpected errors from Accept-Language when middleware locale is missing', async () => {
|
||||
const errorLoggerSpy = vi.spyOn(Logger.prototype, 'error').mockImplementation(() => {});
|
||||
const error = new Error('boom');
|
||||
const app = createApp();
|
||||
app.get('/test', () => {
|
||||
throw new Error('boom');
|
||||
throw error;
|
||||
});
|
||||
const response = await app.request('/test', {
|
||||
headers: {
|
||||
'accept-language': 'fr-CA,fr;q=0.9,en;q=0.8',
|
||||
},
|
||||
});
|
||||
expect(response.status).toBe(500);
|
||||
const body = (await response.json()) as ErrorResponse;
|
||||
expect(body.code).toBe(APIErrorCodes.INTERNAL_SERVER_ERROR);
|
||||
expect(body.message).toBe('Erreur interne du serveur.');
|
||||
try {
|
||||
const response = await app.request('/test', {
|
||||
headers: {
|
||||
'accept-language': 'fr-CA,fr;q=0.9,en;q=0.8',
|
||||
},
|
||||
});
|
||||
expect(response.status).toBe(500);
|
||||
const body = (await response.json()) as ErrorResponse;
|
||||
expect(body.code).toBe(APIErrorCodes.INTERNAL_SERVER_ERROR);
|
||||
expect(body.message).toBe('Erreur interne du serveur.');
|
||||
expect(errorLoggerSpy).toHaveBeenCalledTimes(1);
|
||||
expect(errorLoggerSpy).toHaveBeenCalledWith(
|
||||
{err: error, status: 500, method: 'GET', path: '/test', requestId: undefined},
|
||||
'Unhandled error occurred',
|
||||
);
|
||||
} finally {
|
||||
errorLoggerSpy.mockRestore();
|
||||
}
|
||||
});
|
||||
it('localizes FluxerError responses without errorI18nService in context', async () => {
|
||||
const app = createApp();
|
||||
@@ -52,32 +64,54 @@ describe('AppErrorHandler i18n fallbacks', () => {
|
||||
expect(body.message).toBe(getErrorMessage('http.bad_request', 'fr'));
|
||||
});
|
||||
it('prefers requestLocale context over Accept-Language header', async () => {
|
||||
const errorLoggerSpy = vi.spyOn(Logger.prototype, 'error').mockImplementation(() => {});
|
||||
const error = new Error('boom');
|
||||
const app = createApp();
|
||||
app.use('*', async (ctx, next) => {
|
||||
ctx.set('requestLocale', Locales.EN_US);
|
||||
await next();
|
||||
});
|
||||
app.get('/test', () => {
|
||||
throw new Error('boom');
|
||||
throw error;
|
||||
});
|
||||
const response = await app.request('/test', {
|
||||
headers: {
|
||||
'accept-language': 'fr',
|
||||
},
|
||||
});
|
||||
expect(response.status).toBe(500);
|
||||
const body = (await response.json()) as ErrorResponse;
|
||||
expect(body.code).toBe(APIErrorCodes.INTERNAL_SERVER_ERROR);
|
||||
expect(body.message).toBe('Internal server error.');
|
||||
try {
|
||||
const response = await app.request('/test', {
|
||||
headers: {
|
||||
'accept-language': 'fr',
|
||||
},
|
||||
});
|
||||
expect(response.status).toBe(500);
|
||||
const body = (await response.json()) as ErrorResponse;
|
||||
expect(body.code).toBe(APIErrorCodes.INTERNAL_SERVER_ERROR);
|
||||
expect(body.message).toBe('Internal server error.');
|
||||
expect(errorLoggerSpy).toHaveBeenCalledTimes(1);
|
||||
expect(errorLoggerSpy).toHaveBeenCalledWith(
|
||||
{err: error, status: 500, method: 'GET', path: '/test', requestId: undefined},
|
||||
'Unhandled error occurred',
|
||||
);
|
||||
} finally {
|
||||
errorLoggerSpy.mockRestore();
|
||||
}
|
||||
});
|
||||
it('returns 500 for unexpected errors with request metadata', async () => {
|
||||
const errorLoggerSpy = vi.spyOn(Logger.prototype, 'error').mockImplementation(() => {});
|
||||
const error = new Error('boom');
|
||||
const app = createApp();
|
||||
app.get('/test', () => {
|
||||
throw new Error('boom');
|
||||
throw error;
|
||||
});
|
||||
const response = await app.request('/test');
|
||||
expect(response.status).toBe(500);
|
||||
const body = (await response.json()) as ErrorResponse;
|
||||
expect(body.code).toBe(APIErrorCodes.INTERNAL_SERVER_ERROR);
|
||||
try {
|
||||
const response = await app.request('/test');
|
||||
expect(response.status).toBe(500);
|
||||
const body = (await response.json()) as ErrorResponse;
|
||||
expect(body.code).toBe(APIErrorCodes.INTERNAL_SERVER_ERROR);
|
||||
expect(errorLoggerSpy).toHaveBeenCalledTimes(1);
|
||||
expect(errorLoggerSpy).toHaveBeenCalledWith(
|
||||
{err: error, status: 500, method: 'GET', path: '/test', requestId: undefined},
|
||||
'Unhandled error occurred',
|
||||
);
|
||||
} finally {
|
||||
errorLoggerSpy.mockRestore();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -188,15 +188,23 @@ describe('applyMiddlewareStack', () => {
|
||||
expect(response.headers.get('Cache-Control')).toBeNull();
|
||||
});
|
||||
test('skips errorHandler when skipErrorHandler is true', async () => {
|
||||
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const error = new Error('Test error');
|
||||
const app = new Hono();
|
||||
applyMiddlewareStack(app, {
|
||||
skipErrorHandler: true,
|
||||
});
|
||||
app.get('/test', () => {
|
||||
throw new Error('Test error');
|
||||
throw error;
|
||||
});
|
||||
const response = await app.request('/test');
|
||||
expect(response.status).toBe(500);
|
||||
try {
|
||||
const response = await app.request('/test');
|
||||
expect(response.status).toBe(500);
|
||||
expect(consoleErrorSpy).toHaveBeenCalledTimes(1);
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith(error);
|
||||
} finally {
|
||||
consoleErrorSpy.mockRestore();
|
||||
}
|
||||
});
|
||||
test('applies custom middleware', async () => {
|
||||
const customMiddleware = vi.fn().mockImplementation(async (_c, next) => {
|
||||
|
||||
Reference in New Issue
Block a user