diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 74210136b8a..63e5c9936b3 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -6,6 +6,7 @@ _Released 10/21/2025 (PENDING)_ **Bugfixes:** - An error is no longer thrown during command execution when the application under test overwrites the `window.$` property with a non-function. Fixes [#1502](https://github.com/cypress-io/cypress/issues/1502). Fixed in [#32682](https://github.com/cypress-io/cypress/pull/32682). +- When running `cypress` in Cypress development environments, or when `ELECTRON_ENABLE_LOGGING` is otherwise set to 1, certain messages written to `stderr` will no longer be bracketed with verbose tags. Addresses [#32569](https://github.com/cypress-io/cypress/issues/32569). Addressed in [#32674](https://github.com/cypress-io/cypress/pull/32674). **Misc:** diff --git a/packages/stderr-filtering/lib/Filter.ts b/packages/stderr-filtering/lib/Filter.ts index 0559232d03e..4906b8efefb 100644 --- a/packages/stderr-filtering/lib/Filter.ts +++ b/packages/stderr-filtering/lib/Filter.ts @@ -4,17 +4,17 @@ import { START_TAG, END_TAG } from './constants' import { FilterPrefixedContent } from './FilterPrefixedContent' import { FilterTaggedContent } from './FilterTaggedContent' import { WriteToDebug } from './WriteToDebug' +import { tagsDisabled } from './tagsDisabled' -const DISABLE_TAGS = process.env.ELECTRON_ENABLE_LOGGING === '1' - -export function filter (stderr: Writable, debug: Debugger, prefix: RegExp, disableTags: boolean = false): Writable { +export function filter (stderr: Writable, debug: Debugger, prefix: RegExp): Writable { const prefixTx = new FilterPrefixedContent(prefix, stderr) - const tagTx = new FilterTaggedContent(START_TAG, END_TAG, stderr) const debugWriter = new WriteToDebug(debug) - if (DISABLE_TAGS || disableTags) { + if (tagsDisabled()) { prefixTx.pipe(debugWriter) } else { + const tagTx = new FilterTaggedContent(START_TAG, END_TAG, stderr) + prefixTx.pipe(tagTx).pipe(debugWriter) } diff --git a/packages/stderr-filtering/lib/TagStream.ts b/packages/stderr-filtering/lib/TagStream.ts index c9902a8adaa..efc8eb3c185 100644 --- a/packages/stderr-filtering/lib/TagStream.ts +++ b/packages/stderr-filtering/lib/TagStream.ts @@ -2,8 +2,10 @@ import { Transform } from 'stream' import { START_TAG, END_TAG } from './constants' import { StringDecoder } from 'string_decoder' import Debug from 'debug' +import { tagsDisabled } from './tagsDisabled' const debug = Debug('cypress:stderr-filtering:TagStream') +const debugVerbose = Debug('cypress-verbose:stderr-filtering:TagStream') /** * A Transform stream that wraps input data with start and end tags. @@ -66,13 +68,13 @@ export class TagStream extends Transform { const out = chunk instanceof Buffer ? this.initializedDecoder.write(chunk) : chunk - const transformed = `${this.startTag}${out}${this.endTag}` + const transformed = out ? this.tag(out) : Buffer.from('') - debug(`transformed: "${transformed.replaceAll('\n', '\\n')}"`) - const canWrite = this.push(out ? Buffer.from(transformed) : '') + debugVerbose(`transformed: "${transformed.toString().replaceAll('\n', '\\n')}"`) + const canWrite = this.push(transformed) if (!canWrite) { - debug('waiting for drain') + debugVerbose('waiting for drain') await new Promise((resolve) => this.once('drain', resolve)) } @@ -95,6 +97,10 @@ export class TagStream extends Transform { debug('flushing') const out = this.initializedDecoder.end() - callback(undefined, Buffer.from(`${this.startTag}${out}${this.endTag}`)) + callback(undefined, out ? this.tag(out) : Buffer.from('')) + } + + private tag (str: string): Buffer { + return tagsDisabled() ? Buffer.from(str) : Buffer.from(`${this.startTag}${str}${this.endTag}`) } } diff --git a/packages/stderr-filtering/lib/__spec__/Filter.spec.ts b/packages/stderr-filtering/lib/__spec__/Filter.spec.ts index 68f5d381a31..d0f551ed6b3 100644 --- a/packages/stderr-filtering/lib/__spec__/Filter.spec.ts +++ b/packages/stderr-filtering/lib/__spec__/Filter.spec.ts @@ -10,9 +10,6 @@ vi.mock('../FilterPrefixedContent') vi.mock('../FilterTaggedContent') vi.mock('../WriteToDebug') -// Mock process.env -const originalEnv = process.env - describe('Filter', () => { let mockStderr: any let mockDebug: any @@ -21,9 +18,6 @@ describe('Filter', () => { let mockWriteToDebug: any beforeEach(() => { - // Reset environment - process.env = { ...originalEnv } - // Create mock objects mockStderr = { write: vi.fn(), @@ -54,48 +48,38 @@ describe('Filter', () => { afterEach(() => { vi.clearAllMocks() - process.env = originalEnv + vi.unstubAllEnvs() }) - describe('when disableTags is false', () => { - beforeEach(() => { - process.env.ELECTRON_ENABLE_LOGGING = '0' - }) - + describe('when tags are enabled', () => { it('pipes prefixTx -> tagTx -> debugWriter', () => { - const result = filter(mockStderr, mockDebug, DEBUG_PREFIX, false) + vi.stubEnv('ELECTRON_ENABLE_LOGGING', '0') + vi.stubEnv('CYPRESS_INTERNAL_ENV', 'production') + + const result = filter(mockStderr, mockDebug, DEBUG_PREFIX) - // Verify FilterPrefixedContent was created with correct args expect(FilterPrefixedContent).toHaveBeenCalledWith(DEBUG_PREFIX, mockStderr) - // Verify FilterTaggedContent was created with correct args expect(FilterTaggedContent).toHaveBeenCalledWith(START_TAG, END_TAG, mockStderr) - // Verify WriteToDebug was created with correct args expect(WriteToDebug).toHaveBeenCalledWith(mockDebug) - // Verify the pipe chain: prefixTx -> tagTx -> debugWriter expect(mockFilterPrefixedContent.pipe).toHaveBeenCalledWith(mockFilterTaggedContent) expect(mockFilterTaggedContent.pipe).toHaveBeenCalledWith(mockWriteToDebug) - // Verify the result is the prefixTx expect(result).toBe(mockFilterPrefixedContent) }) }) - describe('when disableTags parameter is true', () => { - beforeEach(() => { - process.env.ELECTRON_ENABLE_LOGGING = '0' - }) - - it('should pipe prefixTx -> debugWriter (skip tagTx)', () => { - const result = filter(mockStderr, mockDebug, DEBUG_PREFIX, true) + describe('disabling tags', () => { + function expectNoTags () { + const result = filter(mockStderr, mockDebug, DEBUG_PREFIX) // Verify FilterPrefixedContent was created with correct args expect(FilterPrefixedContent).toHaveBeenCalledWith(DEBUG_PREFIX, mockStderr) // Verify FilterTaggedContent was created with correct args - expect(FilterTaggedContent).toHaveBeenCalledWith(START_TAG, END_TAG, mockStderr) + expect(FilterTaggedContent).not.toHaveBeenCalled() // Verify WriteToDebug was created with correct args expect(WriteToDebug).toHaveBeenCalledWith(mockDebug) @@ -106,6 +90,16 @@ describe('Filter', () => { // Verify the result is the prefixTx expect(result).toBe(mockFilterPrefixedContent) + } + + it('does not add tags when ELECTRON_ENABLE_LOGGING is enabled', () => { + vi.stubEnv('ELECTRON_ENABLE_LOGGING', '1') + expectNoTags() + }) + + it('does not add tags when CYPRESS_INTERNAL_ENV is development', () => { + vi.stubEnv('CYPRESS_INTERNAL_ENV', 'development') + expectNoTags() }) }) }) diff --git a/packages/stderr-filtering/lib/__spec__/TagStream.spec.ts b/packages/stderr-filtering/lib/__spec__/TagStream.spec.ts index 4e9a1da3726..600dee6e068 100644 --- a/packages/stderr-filtering/lib/__spec__/TagStream.spec.ts +++ b/packages/stderr-filtering/lib/__spec__/TagStream.spec.ts @@ -93,7 +93,7 @@ describe('TagStream', () => { const cb = vi.fn() await tagStream.transform(bufInput, 'buffer', cb) - expect(tagStream.push).toHaveBeenCalledWith('') + expect(tagStream.push).toHaveBeenCalledWith(Buffer.from('')) expect(cb).toHaveBeenCalled() }) }) @@ -115,4 +115,63 @@ describe('TagStream', () => { }) }) }) + + describe('disabling tags', () => { + afterEach(() => { + vi.unstubAllEnvs() + }) + + it('passes on the string without the tags in CYPRESS_INTERNAL_ENV development mode', async () => { + vi.stubEnv('CYPRESS_INTERNAL_ENV', 'development') + const cb = vi.fn() + + await tagStream.transform(strInput, 'utf-8', cb) + expect(tagStream.push).toHaveBeenCalledWith(Buffer.from(strInput)) + expect(cb).toHaveBeenCalled() + }) + + describe('when ELECTRON_ENABLE_LOGGING is enabled', () => { + beforeEach(() => { + vi.stubEnv('ELECTRON_ENABLE_LOGGING', '1') + }) + + it('does not add the tags when transforming', async () => { + const cb = vi.fn() + + await tagStream.transform(strInput, 'utf-8', cb) + expect(tagStream.push).toHaveBeenCalledWith(Buffer.from(strInput)) + expect(cb).toHaveBeenCalled() + }) + + it('does not add the tags when flushing', async () => { + const cb = vi.fn() + + mockStringDecoder.end.mockReturnValue(strInput) + await tagStream.flush(cb) + expect(cb).toHaveBeenCalledWith(undefined, Buffer.from(strInput)) + }) + }) + + describe('when CYPRESS_INTERNAL_ENV is development', () => { + beforeEach(() => { + vi.stubEnv('CYPRESS_INTERNAL_ENV', 'development') + }) + + it('does not add the tags when transforming', async () => { + const cb = vi.fn() + + await tagStream.transform(strInput, 'utf-8', cb) + expect(tagStream.push).toHaveBeenCalledWith(Buffer.from(strInput)) + expect(cb).toHaveBeenCalled() + }) + + it('does not add the tags when flushing', async () => { + const cb = vi.fn() + + mockStringDecoder.end.mockReturnValue(strInput) + await tagStream.flush(cb) + expect(cb).toHaveBeenCalledWith(undefined, Buffer.from(strInput)) + }) + }) + }) }) diff --git a/packages/stderr-filtering/lib/__spec__/logError.spec.ts b/packages/stderr-filtering/lib/__spec__/logError.spec.ts index 08cbe4980cf..adc05c04635 100644 --- a/packages/stderr-filtering/lib/__spec__/logError.spec.ts +++ b/packages/stderr-filtering/lib/__spec__/logError.spec.ts @@ -13,6 +13,7 @@ describe('logError', () => { afterEach(() => { // Restore the original console.error consoleErrorSpy.mockRestore() + vi.unstubAllEnvs() }) describe('START_TAG and END_TAG constants', () => { @@ -105,6 +106,22 @@ describe('logError', () => { expect(consoleErrorSpy).toHaveBeenCalledTimes(1) expect(consoleErrorSpy).toHaveBeenCalledWith(START_TAG, error, END_TAG) }) + + it('does not add tags in CYPRESS_INTERNAL_ENV development mode', () => { + vi.stubEnv('CYPRESS_INTERNAL_ENV', 'development') + logError('Test error') + + expect(consoleErrorSpy).toHaveBeenCalledTimes(1) + expect(consoleErrorSpy).toHaveBeenCalledWith('Test error') + }) + + it('does not add tags in ELECTRON_ENABLE_LOGGING enabled', () => { + vi.stubEnv('ELECTRON_ENABLE_LOGGING', '1') + logError('Test error') + + expect(consoleErrorSpy).toHaveBeenCalledTimes(1) + expect(consoleErrorSpy).toHaveBeenCalledWith('Test error') + }) }) describe('integration with console.error', () => { diff --git a/packages/stderr-filtering/lib/logError.ts b/packages/stderr-filtering/lib/logError.ts index 24619122be5..9fa13f9390b 100644 --- a/packages/stderr-filtering/lib/logError.ts +++ b/packages/stderr-filtering/lib/logError.ts @@ -1,7 +1,8 @@ /** - * Standard error logging tags used for stderr filtering.a + * Standard error logging tags used for stderr filtering */ import { START_TAG, END_TAG } from './constants' +import { tagsDisabled } from './tagsDisabled' /** * Logs error messages with special tags for stderr filtering. @@ -14,12 +15,10 @@ import { START_TAG, END_TAG } from './constants' * @param args The arguments to log as an error message */ -const DISABLE_TAGS = process.env.ELECTRON_ENABLE_LOGGING === '1' - export const logError = (...args: any[]) => { // When electron debug is enabled, the output will not be filtered, so // these tags are not needed. - if (DISABLE_TAGS) { + if (tagsDisabled()) { // eslint-disable-next-line no-console console.error(...args) } else { diff --git a/packages/stderr-filtering/lib/tagsDisabled.ts b/packages/stderr-filtering/lib/tagsDisabled.ts new file mode 100644 index 00000000000..60d149ba1d8 --- /dev/null +++ b/packages/stderr-filtering/lib/tagsDisabled.ts @@ -0,0 +1,3 @@ +export function tagsDisabled () { + return process.env.ELECTRON_ENABLE_LOGGING === '1' || process.env.CYPRESS_INTERNAL_ENV === 'development' +}