Clean Up Integration Test Console Output (#1566)

- Also fix issue where integration tests were making actual network requests
- this also slightly speeds up tests
- Fixes issues where there were JS errors thrown during tests due to incorrect mocks, causing confusion when adding/fixing other tests

Before (note: too much content to even see all tests)

https://github.com/user-attachments/assets/346bb57d-aa64-4a62-b666-3cf47fcc2a6c

After:

https://github.com/user-attachments/assets/f6379a93-2d1d-4f12-a467-02d874f98de6




Fixes HDX-3165
This commit is contained in:
Brandon Pereira 2026-01-07 10:38:01 -07:00 committed by GitHub
parent e9eb84eb1d
commit e767d79e02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 125 additions and 69 deletions

View file

@ -8,3 +8,5 @@ MONGO_URI=mongodb://localhost:29999/hyperdx-test
NODE_ENV=test
PORT=9000
OPAMP_PORT=4320
# Default to only logging warnings/errors. Adjust if you need more verbosity
HYPERDX_LOG_LEVEL=warn

View file

@ -1,2 +1,21 @@
// @eslint-disable @typescript-eslint/no-var-requires
jest.retryTimes(1, { logErrorsBeforeRetry: true });
global.console = {
...console,
// Turn off console.debug logs in tests (useful since we log db queries aggressively)
debug: jest.fn(),
};
// Mock alert notification functions to prevent HTTP calls during tests
jest.mock('@/utils/slack', () => ({
...jest.requireActual('@/utils/slack'),
postMessageToWebhook: jest.fn().mockResolvedValue(null),
}));
// Mock global fetch for generic webhook calls
global.fetch = jest.fn().mockResolvedValue({
ok: true,
text: jest.fn().mockResolvedValue(''),
json: jest.fn().mockResolvedValue({}),
} as any);

View file

@ -73,7 +73,7 @@
"supertest": "^6.3.1",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"ts-jest": "^28.0.5",
"ts-jest": "^29.4.5",
"ts-node": "^10.8.1",
"tsc-alias": "^1.8.8",
"tsconfig-paths": "^4.2.0",

View file

@ -54,7 +54,9 @@ if (!config.IS_LOCAL_APP_MODE) {
app.use(passport.session());
}
app.use(expressLogger);
if (!config.IS_CI) {
app.use(expressLogger);
}
// Allows timing data from frontend package
// see: https://github.com/expressjs/cors/issues/102
app.use(function (req, res, next) {

View file

@ -108,7 +108,6 @@ describe('renderChartConfig', () => {
});
afterEach(async () => {
console.log('running db cleanup code');
await server.clearDBs();
jest.clearAllMocks();
});

View file

@ -1,4 +1,5 @@
import _ from 'lodash';
import { ObjectId } from 'mongodb';
import mongoose from 'mongoose';
import { getLoggedInAgent, getServer } from '@/fixtures';
@ -60,7 +61,7 @@ Object {
team: team.id,
kind: 'log',
name: 'My New Source',
connection: 'local',
connection: new ObjectId().toString(),
from: {
databaseName: 'system',
tableName: 'query_log',

View file

@ -231,6 +231,11 @@ describe('External API Alerts', () => {
});
it('should handle validation errors when creating alerts', async () => {
// Spy on console.error to suppress error output in tests
const consoleErrorSpy = jest
.spyOn(console, 'error')
.mockImplementation(() => {});
// Missing required fields
const invalidInput = {
name: 'Invalid Alert',
@ -243,6 +248,9 @@ describe('External API Alerts', () => {
.expect(500);
expect(response.body).toHaveProperty('message');
// Restore console.error
consoleErrorSpy.mockRestore();
});
it('should create multiple alerts for different tiles', async () => {

View file

@ -414,6 +414,11 @@ describe('External API v2 Charts', () => {
});
it('should handle lucene query errors gracefully', async () => {
// Spy on console.error to suppress expected error output
const consoleErrorSpy = jest
.spyOn(console, 'error')
.mockImplementation(() => {});
const payload = createSeriesRequestPayload(logSource.id.toString(), {
series: [{ aggFn: 'count', where: '(invalid query', groupBy: [] }],
});
@ -421,9 +426,17 @@ describe('External API v2 Charts', () => {
.send(payload)
.expect(500);
expect(response.body).toHaveProperty('error');
// Restore console.error
consoleErrorSpy.mockRestore();
});
it('should handle sql query errors gracefully', async () => {
// Spy on console.error to suppress expected error output
const consoleErrorSpy = jest
.spyOn(console, 'error')
.mockImplementation(() => {});
const payload = createSeriesRequestPayload(logSource.id.toString(), {
series: [
{
@ -438,6 +451,9 @@ describe('External API v2 Charts', () => {
.send(payload)
.expect(500);
expect(response.body).toHaveProperty('error');
// Restore console.error
consoleErrorSpy.mockRestore();
});
it('should return data grouped by a single field', async () => {

View file

@ -123,6 +123,37 @@ describe('checkAlerts', () => {
});
describe('Alert Templates', () => {
// Create a mock metadata object with the necessary methods
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const mockMetadata = {
getColumn: jest.fn().mockImplementation(({ column }) => {
// Provide basic column definitions for common columns to avoid warnings
const columnMap = {
Timestamp: { name: 'Timestamp', type: 'DateTime' },
Body: { name: 'Body', type: 'String' },
SeverityText: { name: 'SeverityText', type: 'String' },
ServiceName: { name: 'ServiceName', type: 'String' },
};
return Promise.resolve(columnMap[column]);
}),
getColumns: jest.fn().mockResolvedValue([]),
getMapKeys: jest.fn().mockResolvedValue([]),
getMapValues: jest.fn().mockResolvedValue([]),
getAllFields: jest.fn().mockResolvedValue([]),
getTableMetadata: jest.fn().mockResolvedValue({}),
getClickHouseSettings: jest.fn().mockReturnValue({}),
setClickHouseSettings: jest.fn(),
} as any;
// Create a mock clickhouse client
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const mockClickhouseClient = {
query: jest.fn().mockResolvedValue({
json: jest.fn().mockResolvedValue({ data: [] }),
text: jest.fn().mockResolvedValue(''),
}),
} as any;
const defaultSearchView: AlertMessageTemplateDefaultView = {
alert: {
thresholdType: AlertThresholdType.ABOVE,
@ -525,8 +556,8 @@ describe('checkAlerts', () => {
await renderAlertTemplate({
alertProvider,
clickhouseClient: {} as any,
metadata: {} as any,
clickhouseClient: mockClickhouseClient,
metadata: mockMetadata,
state: AlertState.ALERT,
template: 'Custom body @webhook-My_Web', // partial name should work
view: {
@ -560,8 +591,8 @@ describe('checkAlerts', () => {
await renderAlertTemplate({
alertProvider,
clickhouseClient: {} as any,
metadata: {} as any,
clickhouseClient: mockClickhouseClient,
metadata: mockMetadata,
state: AlertState.ALERT,
template: 'Custom body @webhook-My_Web', // partial name should work
view: {
@ -617,8 +648,8 @@ describe('checkAlerts', () => {
await renderAlertTemplate({
alertProvider,
clickhouseClient: {} as any,
metadata: {} as any,
clickhouseClient: mockClickhouseClient,
metadata: mockMetadata,
state: AlertState.ALERT,
template: 'Custom body @webhook-{{attributes.webhookName}}', // partial name should work
view: {
@ -687,8 +718,8 @@ describe('checkAlerts', () => {
await renderAlertTemplate({
alertProvider,
clickhouseClient: {} as any,
metadata: {} as any,
clickhouseClient: mockClickhouseClient,
metadata: mockMetadata,
state: AlertState.ALERT,
template: `
{{#is_match "attributes.k8s.pod.name" "otel-collector-123"}}
@ -725,8 +756,8 @@ describe('checkAlerts', () => {
// @webhook should not be called
await renderAlertTemplate({
alertProvider,
clickhouseClient: {} as any,
metadata: {} as any,
clickhouseClient: mockClickhouseClient,
metadata: mockMetadata,
state: AlertState.ALERT,
template:
'{{#is_match "attributes.host" "web"}} @webhook-My_Web {{/is_match}}', // partial name should work
@ -818,8 +849,8 @@ describe('checkAlerts', () => {
await renderAlertTemplate({
alertProvider,
clickhouseClient: {} as any,
metadata: {} as any,
clickhouseClient: mockClickhouseClient,
metadata: mockMetadata,
state: AlertState.OK, // Resolved state
template: '@webhook-My_Webhook',
view: {

View file

@ -18,6 +18,16 @@ const MOCK_SAVED_SEARCH: any = {
id: 'fake-saved-search-id',
};
// Mock logger to suppress error output in tests for this file
jest.mock('@/utils/logger', () => ({
__esModule: true,
default: {
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
},
}));
describe('DefaultAlertProvider', () => {
let provider: AlertProvider;
const server = getServer();

View file

@ -6,6 +6,7 @@
"@/*": ["./*"]
},
"outDir": "build",
"isolatedModules": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,

View file

@ -41,7 +41,7 @@
"nodemon": "^2.0.20",
"rimraf": "^4.4.1",
"supertest": "^6.3.1",
"ts-jest": "^28.0.5",
"ts-jest": "^29.4.5",
"ts-node": "^10.8.1",
"tsc-alias": "^1.8.8",
"tsconfig-paths": "^4.2.0",

View file

@ -4298,7 +4298,7 @@ __metadata:
supertest: "npm:^6.3.1"
swagger-jsdoc: "npm:^6.2.8"
swagger-ui-express: "npm:^5.0.1"
ts-jest: "npm:^28.0.5"
ts-jest: "npm:^29.4.5"
ts-node: "npm:^10.8.1"
tsc-alias: "npm:^1.8.8"
tsconfig-paths: "npm:^4.2.0"
@ -4483,7 +4483,7 @@ __metadata:
sqlstring: "npm:^2.3.3"
store2: "npm:^2.14.4"
supertest: "npm:^6.3.1"
ts-jest: "npm:^28.0.5"
ts-jest: "npm:^29.4.5"
ts-node: "npm:^10.8.1"
tsc-alias: "npm:^1.8.8"
tsconfig-paths: "npm:^4.2.0"
@ -11592,7 +11592,7 @@ __metadata:
languageName: node
linkType: hard
"bs-logger@npm:0.x, bs-logger@npm:^0.2.6":
"bs-logger@npm:^0.2.6":
version: 0.2.6
resolution: "bs-logger@npm:0.2.6"
dependencies:
@ -18711,7 +18711,7 @@ __metadata:
languageName: node
linkType: hard
"jest-util@npm:^28.0.0, jest-util@npm:^28.1.3":
"jest-util@npm:^28.1.3":
version: 28.1.3
resolution: "jest-util@npm:28.1.3"
dependencies:
@ -19085,7 +19085,7 @@ __metadata:
languageName: node
linkType: hard
"json5@npm:^2.1.2, json5@npm:^2.2.1, json5@npm:^2.2.2, json5@npm:^2.2.3":
"json5@npm:^2.1.2, json5@npm:^2.2.2, json5@npm:^2.2.3":
version: 2.2.3
resolution: "json5@npm:2.2.3"
bin:
@ -19534,7 +19534,7 @@ __metadata:
languageName: node
linkType: hard
"lodash.memoize@npm:4.x, lodash.memoize@npm:^4.1.2":
"lodash.memoize@npm:^4.1.2":
version: 4.1.2
resolution: "lodash.memoize@npm:4.1.2"
checksum: 10c0/c8713e51eccc650422716a14cece1809cfe34bc5ab5e242b7f8b4e2241c2483697b971a604252807689b9dd69bfe3a98852e19a5b89d506b000b4187a1285df8
@ -19759,7 +19759,7 @@ __metadata:
languageName: node
linkType: hard
"make-error@npm:1.x, make-error@npm:^1.1.1, make-error@npm:^1.3.6":
"make-error@npm:^1.1.1, make-error@npm:^1.3.6":
version: 1.3.6
resolution: "make-error@npm:1.3.6"
checksum: 10c0/171e458d86854c6b3fc46610cfacf0b45149ba043782558c6875d9f42f222124384ad0b468c92e996d815a8a2003817a710c0a160e49c1c394626f76fa45396f
@ -25215,17 +25215,6 @@ __metadata:
languageName: node
linkType: hard
"semver@npm:7.x, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.2":
version: 7.5.2
resolution: "semver@npm:7.5.2"
dependencies:
lru-cache: "npm:^6.0.0"
bin:
semver: bin/semver.js
checksum: 10c0/d151207ab762a8067f6302076edc04e5b8da2362eb9e3f21c2567ceadfd415064936d215b4aae7791da118c230649d29089be979ffa49c5b56a6bcf82147efdd
languageName: node
linkType: hard
"semver@npm:^6.0.0, semver@npm:^6.3.0, semver@npm:^6.3.1":
version: 6.3.1
resolution: "semver@npm:6.3.1"
@ -25246,6 +25235,17 @@ __metadata:
languageName: node
linkType: hard
"semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.2":
version: 7.5.2
resolution: "semver@npm:7.5.2"
dependencies:
lru-cache: "npm:^6.0.0"
bin:
semver: bin/semver.js
checksum: 10c0/d151207ab762a8067f6302076edc04e5b8da2362eb9e3f21c2567ceadfd415064936d215b4aae7791da118c230649d29089be979ffa49c5b56a6bcf82147efdd
languageName: node
linkType: hard
"semver@npm:^7.6.0, semver@npm:^7.6.2":
version: 7.6.2
resolution: "semver@npm:7.6.2"
@ -27186,39 +27186,6 @@ __metadata:
languageName: node
linkType: hard
"ts-jest@npm:^28.0.5":
version: 28.0.8
resolution: "ts-jest@npm:28.0.8"
dependencies:
bs-logger: "npm:0.x"
fast-json-stable-stringify: "npm:2.x"
jest-util: "npm:^28.0.0"
json5: "npm:^2.2.1"
lodash.memoize: "npm:4.x"
make-error: "npm:1.x"
semver: "npm:7.x"
yargs-parser: "npm:^21.0.1"
peerDependencies:
"@babel/core": ">=7.0.0-beta.0 <8"
"@jest/types": ^28.0.0
babel-jest: ^28.0.0
jest: ^28.0.0
typescript: ">=4.3"
peerDependenciesMeta:
"@babel/core":
optional: true
"@jest/types":
optional: true
babel-jest:
optional: true
esbuild:
optional: true
bin:
ts-jest: cli.js
checksum: 10c0/4f6d7c8dbf6deaf56f4490ae819071077e8ed30c1a3c87c7d2e21b3103e6d12aaa53d2776cb5c947bac3f3a05cd9f8dea2aedc4c6550c14fbf639c1368a0fbc9
languageName: node
linkType: hard
"ts-jest@npm:^29.4.5":
version: 29.4.5
resolution: "ts-jest@npm:29.4.5"
@ -28978,7 +28945,7 @@ __metadata:
languageName: node
linkType: hard
"yargs-parser@npm:21.1.1, yargs-parser@npm:^21.0.1, yargs-parser@npm:^21.1.1":
"yargs-parser@npm:21.1.1, yargs-parser@npm:^21.1.1":
version: 21.1.1
resolution: "yargs-parser@npm:21.1.1"
checksum: 10c0/f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2