Replace console.error with structured logger in recordScraperRun
All checks were successful
CI/CD Pipeline - Apartment API / Send Webhook Notification (pull_request) Successful in 3s
CI/CD Pipeline - Apartment API / Build & Push Image (pull_request) Has been skipped
CI/CD Pipeline - Apartment API / Scan Dependencies (pull_request) Successful in 13s
CI/CD Pipeline - Apartment API / Run Linting (pull_request) Successful in 9m36s
CI/CD Pipeline - Apartment API / Run Tests (pull_request) Successful in 9m51s
CI/CD Pipeline - Apartment API / Deploy to Production (pull_request) Has been skipped

Switch error logging from console.error to the injected logger.error
pattern for consistency with the rest of the scraper service layer.
Update tests to verify logger.error is called instead of console.error.
This commit is contained in:
2026-02-06 01:41:50 -07:00
parent 74dc62c53f
commit 48512e01ba
2 changed files with 27 additions and 32 deletions

View File

@ -19,6 +19,7 @@ let recordScraperRun;
let mongoServer;
let client;
let db;
let logger;
beforeAll(async () => {
mongoServer = await MongoMemoryServer.create();
@ -42,6 +43,9 @@ beforeEach(async () => {
for (const col of collections) {
await db.collection(col.name).deleteMany({});
}
// Create fresh mock logger for each test
logger = { info: jest.fn(), warn: jest.fn(), error: jest.fn() };
});
describe('recordScraperRun', () => {
@ -74,7 +78,7 @@ describe('recordScraperRun', () => {
it('should insert a document into the scraper_runs collection', async () => {
const runData = createSampleRunData();
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const docs = await db.collection(SCRAPER_RUNS_COLLECTION).find({}).toArray();
expect(docs).toHaveLength(1);
@ -83,7 +87,7 @@ describe('recordScraperRun', () => {
it('should include a recordedAt field in the inserted document', async () => {
const runData = createSampleRunData();
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const doc = await db.collection(SCRAPER_RUNS_COLLECTION).findOne({});
expect(doc.recordedAt).toBeDefined();
@ -102,7 +106,7 @@ describe('recordScraperRun', () => {
duration: 9999
});
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const doc = await db.collection(SCRAPER_RUNS_COLLECTION).findOne({});
expect(doc.jobId).toBe('preserve-test-001');
@ -120,7 +124,7 @@ describe('recordScraperRun', () => {
staleUnitsCount: 3
});
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const doc = await db.collection(SCRAPER_RUNS_COLLECTION).findOne({});
expect(doc.unitsProcessed).toBe(42);
@ -136,7 +140,7 @@ describe('recordScraperRun', () => {
completedAt: '2026-02-06T10:00:15.500Z'
});
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const doc = await db.collection(SCRAPER_RUNS_COLLECTION).findOne({});
expect(doc.startedAt).toBe('2026-02-06T10:00:00.000Z');
@ -146,7 +150,7 @@ describe('recordScraperRun', () => {
it('should preserve dryRun flag', async () => {
const runData = createSampleRunData({ dryRun: true });
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const doc = await db.collection(SCRAPER_RUNS_COLLECTION).findOne({});
expect(doc.dryRun).toBe(true);
@ -158,7 +162,7 @@ describe('recordScraperRun', () => {
errors: ['Connection timeout', 'Retry exhausted']
});
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const doc = await db.collection(SCRAPER_RUNS_COLLECTION).findOne({});
expect(doc.errors).toEqual(['Connection timeout', 'Retry exhausted']);
@ -167,7 +171,7 @@ describe('recordScraperRun', () => {
it('should preserve empty errors array for successful runs', async () => {
const runData = createSampleRunData({ errors: [] });
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const doc = await db.collection(SCRAPER_RUNS_COLLECTION).findOne({});
expect(doc.errors).toEqual([]);
@ -190,7 +194,7 @@ describe('recordScraperRun', () => {
};
// This should NOT throw
await expect(recordScraperRun(mockDb, runData)).resolves.not.toThrow();
await expect(recordScraperRun(mockDb, runData, logger)).resolves.not.toThrow();
});
it('should log error message when insert fails', async () => {
@ -203,17 +207,12 @@ describe('recordScraperRun', () => {
collection: jest.fn().mockReturnValue(mockCollection)
};
// Spy on console.error
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
await recordScraperRun(mockDb, runData, logger);
await recordScraperRun(mockDb, runData);
expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining('Failed to record scraper run'),
expect.stringContaining('Disk full')
expect(logger.error).toHaveBeenCalledWith(
'Failed to record scraper run',
{ errorMessage: 'Disk full' }
);
consoleSpy.mockRestore();
});
});
@ -231,13 +230,8 @@ describe('recordScraperRun', () => {
collection: jest.fn().mockReturnValue(mockCollection)
};
// Suppress console.error for clean test output
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const result = await recordScraperRun(mockDb, runData);
const result = await recordScraperRun(mockDb, runData, logger);
expect(result).toBeNull();
consoleSpy.mockRestore();
});
});
@ -248,7 +242,7 @@ describe('recordScraperRun', () => {
it('should return the insertOne result object', async () => {
const runData = createSampleRunData();
const result = await recordScraperRun(db, runData);
const result = await recordScraperRun(db, runData, logger);
expect(result).toBeDefined();
expect(result).not.toBeNull();
@ -257,7 +251,7 @@ describe('recordScraperRun', () => {
it('should return result with acknowledged property', async () => {
const runData = createSampleRunData();
const result = await recordScraperRun(db, runData);
const result = await recordScraperRun(db, runData, logger);
expect(result.acknowledged).toBe(true);
});
@ -265,7 +259,7 @@ describe('recordScraperRun', () => {
it('should return result with insertedId', async () => {
const runData = createSampleRunData();
const result = await recordScraperRun(db, runData);
const result = await recordScraperRun(db, runData, logger);
expect(result.insertedId).toBeDefined();
});
@ -278,7 +272,7 @@ describe('recordScraperRun', () => {
it('should set recordedAt as a Date instance', async () => {
const runData = createSampleRunData();
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const doc = await db.collection(SCRAPER_RUNS_COLLECTION).findOne({});
expect(doc.recordedAt).toBeInstanceOf(Date);
@ -288,7 +282,7 @@ describe('recordScraperRun', () => {
const beforeTime = new Date();
const runData = createSampleRunData();
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const afterTime = new Date();
@ -300,7 +294,7 @@ describe('recordScraperRun', () => {
it('should not overwrite any existing runData fields with recordedAt', async () => {
const runData = createSampleRunData();
await recordScraperRun(db, runData);
await recordScraperRun(db, runData, logger);
const doc = await db.collection(SCRAPER_RUNS_COLLECTION).findOne({});

View File

@ -626,9 +626,10 @@ async function updateDailySummary(db, summaryData, logger) {
*
* @param {Db} db - MongoDB database instance
* @param {Object} runData - Run data to record (jobId, trigger, status, duration, etc.)
* @param {Object} logger - Logger instance
* @returns {Promise<Object|null>} Insert result, or null on failure
*/
async function recordScraperRun(db, runData) {
async function recordScraperRun(db, runData, logger) {
const collection = db.collection(config.COLLECTIONS.SCRAPER_RUNS);
try {
@ -641,7 +642,7 @@ async function recordScraperRun(db, runData) {
} catch (error) {
// Log but don't throw - recording history should not break scraper
console.error('Failed to record scraper run:', error.message);
logger.error('Failed to record scraper run', { errorMessage: error.message });
return null;
}
}