diff --git a/node-src/index.test.ts b/node-src/index.test.ts index 0ba0b7c3c..a9f34a9c1 100644 --- a/node-src/index.test.ts +++ b/node-src/index.test.ts @@ -284,6 +284,7 @@ vi.mock('fs', async (importOriginal) => { const originalModule = (await importOriginal()) as any; return { pathExists: async () => true, + mkdirSync: vi.fn(), readFileSync: originalModule.readFileSync, writeFileSync: vi.fn(), createReadStream: vi.fn(() => mockStatsFile), diff --git a/node-src/lib/log.ts b/node-src/lib/log.ts index ffa999cab..4773e79af 100644 --- a/node-src/lib/log.ts +++ b/node-src/lib/log.ts @@ -1,6 +1,7 @@ import chalk from 'chalk'; import debug from 'debug'; -import { createWriteStream, rm } from 'fs'; +import { createWriteStream, mkdirSync, rm } from 'fs'; +import path from 'path'; import stripAnsi from 'strip-ansi'; import { format } from 'util'; @@ -96,13 +97,16 @@ const fileLogger = { this.append = () => {}; this.queue = []; }, - initialize(path: string, onError: LogFunction) { - rm(path, { force: true }, (err) => { + initialize(filepath: string, onError: LogFunction) { + rm(filepath, { force: true }, (err) => { if (err) { this.disable(); onError(err); } else { - const stream = createWriteStream(path, { flags: 'a' }); + // Ensure the parent directory exists before we create the stream + mkdirSync(path.dirname(filepath), { recursive: true }); + + const stream = createWriteStream(filepath, { flags: 'a' }); this.append = (...messages: string[]) => { stream?.write( messages diff --git a/node-src/lib/writeChromaticDiagnostics.test.ts b/node-src/lib/writeChromaticDiagnostics.test.ts index ecc8e4841..2dea57000 100644 --- a/node-src/lib/writeChromaticDiagnostics.test.ts +++ b/node-src/lib/writeChromaticDiagnostics.test.ts @@ -1,6 +1,13 @@ -import { describe, expect, it } from 'vitest'; +import { mkdirSync } from 'fs'; +import jsonfile from 'jsonfile'; +import path from 'path'; +import { describe, expect, it, vi } from 'vitest'; -import { getDiagnostics } from './writeChromaticDiagnostics'; +import { createLogger } from './log'; +import { getDiagnostics, writeChromaticDiagnostics } from './writeChromaticDiagnostics'; + +vi.mock('jsonfile'); +vi.mock('fs'); describe('getDiagnostics', () => { it('returns context object', () => { @@ -26,3 +33,22 @@ describe('getDiagnostics', () => { }); }); }); + +describe('writeChromaticDiagnostics', () => { + it('should create the parent directory if it does not exist', async () => { + const ctx = { + log: createLogger({}), + options: { diagnosticsFile: '/tmp/doesnotexist/diagnostics.json' }, + }; + await writeChromaticDiagnostics(ctx as any); + + expect(mkdirSync).toHaveBeenCalledWith(path.dirname(ctx.options.diagnosticsFile), { + recursive: true, + }); + expect(jsonfile.writeFile).toHaveBeenCalledWith( + ctx.options.diagnosticsFile, + expect.any(Object), + expect.any(Object) + ); + }); +}); diff --git a/node-src/lib/writeChromaticDiagnostics.ts b/node-src/lib/writeChromaticDiagnostics.ts index 8fcd3a8d6..25c9b0719 100644 --- a/node-src/lib/writeChromaticDiagnostics.ts +++ b/node-src/lib/writeChromaticDiagnostics.ts @@ -1,4 +1,6 @@ +import { mkdirSync } from 'fs'; import jsonfile from 'jsonfile'; +import path from 'path'; import { Context } from '..'; import wroteReport from '../ui/messages/info/wroteReport'; @@ -17,6 +19,9 @@ export async function writeChromaticDiagnostics(ctx: Context) { } try { + // Ensure the parent directory exists before writing file + mkdirSync(path.dirname(ctx.options.diagnosticsFile), { recursive: true }); + await writeFile(ctx.options.diagnosticsFile, getDiagnostics(ctx), { spaces: 2 }); ctx.log.info(wroteReport(ctx.options.diagnosticsFile, 'Chromatic diagnostics')); } catch (error) {