Skip to content

Commit

Permalink
avoid ANSI clearScreen (jestjs#7523)
Browse files Browse the repository at this point in the history
* avoid ANSI clearScreen

clearScreen is quite aggressive and can e.g.
brick the user's shell theme.

* move specialChars to jest-util
  • Loading branch information
jeysal authored and captain-yossarian committed Jul 18, 2019
1 parent 35e4cd6 commit 297bd6e
Show file tree
Hide file tree
Showing 14 changed files with 96 additions and 54 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- `[jest-haste-map]` [**BREAKING**] Remove name from hash in `HasteMap.getCacheFilePath` ([#7218](https://github.com/facebook/jest/pull/7218))
- `[babel-preset-jest]` [**BREAKING**] Export a function instead of an object for Babel 7 compatibility ([#7203](https://github.com/facebook/jest/pull/7203))
- `[jest-haste-map]` [**BREAKING**] Expose relative paths when getting the file iterator ([#7321](https://github.com/facebook/jest/pull/7321))
- `[jest-util]` Export `specialChars` containing Unicode characters and ANSI escapes for console output ([#7532](https://github.com/facebook/jest/pull/7532))
- `[jest-config]` Handle typescript (`ts` and `tsx`) by default ([#7533](https://github.com/facebook/jest/pull/7533))
- `[jest-validate]` Add support for comments in `package.json` using a `"//"` key ([#7295](https://github.com/facebook/jest/pull/7295))
- `[jest-config]` Add shorthand for watch plugins and runners ([#7213](https://github.com/facebook/jest/pull/7213))
Expand Down Expand Up @@ -48,6 +49,7 @@
- `[jest-haste-map]` [**BREAKING**] Recover files correctly after haste name collisions are fixed ([#7329](https://github.com/facebook/jest/pull/7329))
- `[pretty-format]` [**BREAKING**] Omit non-enumerable symbol properties ([#7448](https://github.com/facebook/jest/pull/7448))
- `[*]` [**BREAKING**] Upgrade to Babel 7, dropping support for Babel 6 ([#7016](https://github.com/facebook/jest/pull/7016))
- `[jest-cli]` Avoid watch mode causing bad terminal behavior in some cases ([#7523](https://github.com/facebook/jest/pull/7523))
- `[jest-runner/jest-worker]` Fix missing console output in verbose mode ([#6871](https://github.com/facebook/jest/pull/6871))
- `[expect]` Standardize file naming in `expect` ([#7306](https://github.com/facebook/jest/pull/7306))
- `[jest-each]` Add empty array validation check ([#7249](https://github.com/facebook/jest/pull/7249))
Expand Down
8 changes: 5 additions & 3 deletions packages/jest-cli/src/SnapshotInteractiveMode.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import ansiEscapes from 'ansi-escapes';
import {KEYS} from 'jest-watcher';

import {pluralize} from './reporters/utils';
import {ARROW} from './constants';
import {specialChars} from 'jest-util';

const {ARROW, CLEAR} = specialChars;

export default class SnapshotInteractiveMode {
_pipe: stream$Writable | tty$WriteStream;
Expand Down Expand Up @@ -90,7 +92,7 @@ export default class SnapshotInteractiveMode {
}

_drawUIDoneWithSkipped() {
this._pipe.write(ansiEscapes.clearScreen);
this._pipe.write(CLEAR);
const numPass = this._countPaths - this._testAssertions.length;

let stats = chalk.bold.dim(
Expand Down Expand Up @@ -123,7 +125,7 @@ export default class SnapshotInteractiveMode {
}

_drawUIDone() {
this._pipe.write(ansiEscapes.clearScreen);
this._pipe.write(CLEAR);
const numPass = this._countPaths - this._testAssertions.length;

let stats = chalk.bold.dim(
Expand Down
25 changes: 16 additions & 9 deletions packages/jest-cli/src/__tests__/SnapshotInteractiveMode.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,22 @@ import chalk from 'chalk';
import {KEYS} from 'jest-watcher';
import SnapshotInteractiveMode from '../SnapshotInteractiveMode';

jest.mock('ansi-escapes', () => ({
clearScreen: '[MOCK - eraseDown]',
cursorRestorePosition: '[MOCK - cursorRestorePosition]',
cursorSavePosition: '[MOCK - cursorSavePosition]',
cursorScrollDown: '[MOCK - cursorScrollDown]',
cursorTo: (x, y) => `[MOCK - cursorTo(${x}, ${y})]`,
cursorUp: () => '[MOCK - cursorUp]',
eraseDown: '[MOCK - eraseDown]',
}));
jest
.mock('ansi-escapes', () => ({
cursorRestorePosition: '[MOCK - cursorRestorePosition]',
cursorSavePosition: '[MOCK - cursorSavePosition]',
cursorScrollDown: '[MOCK - cursorScrollDown]',
cursorTo: (x, y) => `[MOCK - cursorTo(${x}, ${y})]`,
cursorUp: () => '[MOCK - cursorUp]',
eraseDown: '[MOCK - eraseDown]',
}))
.mock('jest-util', () => {
const {specialChars, ...util} = jest.requireActual('jest-util');
return {
...util,
specialChars: {...specialChars, CLEAR: '[MOCK - clear]'},
};
});

jest.doMock('chalk', () =>
Object.assign(new chalk.constructor({enabled: false}), {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ exports[`SnapshotInteractiveMode skip 1 test, then quit 1`] = `
`;

exports[`SnapshotInteractiveMode skip 1 test, then quit 2`] = `
"[MOCK - eraseDown]
"[MOCK - clear]

<bold>Interactive Snapshot Result</>
› <bold><dim>1 snapshot reviewed<bold></>, <bold><yellow>1 snapshot skipped</></>
Expand All @@ -43,7 +43,7 @@ exports[`SnapshotInteractiveMode skip 1 test, then restart 1`] = `
`;

exports[`SnapshotInteractiveMode skip 1 test, then restart 2`] = `
"[MOCK - eraseDown]
"[MOCK - clear]

<bold>Interactive Snapshot Result</>
› <bold><dim>1 snapshot reviewed<bold></>, <bold><yellow>1 snapshot skipped</></>
Expand Down Expand Up @@ -100,7 +100,7 @@ exports[`SnapshotInteractiveMode skip 1 test, update 1 test, then finish and res
`;

exports[`SnapshotInteractiveMode skip 1 test, update 1 test, then finish and restart 3`] = `
"[MOCK - eraseDown]
"[MOCK - clear]

<bold>Interactive Snapshot Result</>
› <bold><dim>2 snapshots reviewed<bold></>, <bold><green>1 snapshot updated</></>, <bold><yellow>1 snapshot skipped</></>
Expand Down Expand Up @@ -157,7 +157,7 @@ exports[`SnapshotInteractiveMode skip 2 tests, then finish and restart 2`] = `
`;

exports[`SnapshotInteractiveMode skip 2 tests, then finish and restart 3`] = `
"[MOCK - eraseDown]
"[MOCK - clear]

<bold>Interactive Snapshot Result</>
› <bold><dim>2 snapshots reviewed<bold></>, <bold><yellow>2 snapshots skipped</></>
Expand Down Expand Up @@ -214,7 +214,7 @@ exports[`SnapshotInteractiveMode update 1 test, skip 1 test, then finish and res
`;

exports[`SnapshotInteractiveMode update 1 test, skip 1 test, then finish and restart 3`] = `
"[MOCK - eraseDown]
"[MOCK - clear]

<bold>Interactive Snapshot Result</>
› <bold><dim>2 snapshots reviewed<bold></>, <bold><green>1 snapshot updated</></>, <bold><yellow>1 snapshot skipped</></>
Expand Down Expand Up @@ -256,7 +256,7 @@ exports[`SnapshotInteractiveMode update 1 test, then finish and return 1`] = `
`;

exports[`SnapshotInteractiveMode update 1 test, then finish and return 2`] = `
"[MOCK - eraseDown]
"[MOCK - clear]

<bold>Interactive Snapshot Result</>
› <bold><dim>1 snapshot reviewed<bold></>, <bold><green>1 snapshot updated</></>
Expand Down Expand Up @@ -297,7 +297,7 @@ exports[`SnapshotInteractiveMode update 2 tests, then finish and return 2`] = `
`;

exports[`SnapshotInteractiveMode update 2 tests, then finish and return 3`] = `
"[MOCK - eraseDown]
"[MOCK - clear]

<bold>Interactive Snapshot Result</>
› <bold><dim>2 snapshots reviewed<bold></>, <bold><green>2 snapshots updated</></>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Object {

exports[`Watch mode flows Pressing "c" clears the filters 1`] = `
"[MOCK - cursorHide]
[MOCK - clearScreen]
[MOCK - clear]
<bold>Pattern Mode Usage</>
<dim>› Press</> Esc <dim>to exit pattern mode.</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,22 @@ import {KEYS} from 'jest-watcher';

const runJestMock = jest.fn();

jest.mock('ansi-escapes', () => ({
clearScreen: '[MOCK - clearScreen]',
cursorDown: (count = 1) => `[MOCK - cursorDown(${count})]`,
cursorHide: '[MOCK - cursorHide]',
cursorRestorePosition: '[MOCK - cursorRestorePosition]',
cursorSavePosition: '[MOCK - cursorSavePosition]',
cursorShow: '[MOCK - cursorShow]',
cursorTo: (x, y) => `[MOCK - cursorTo(${x}, ${y})]`,
}));
jest
.mock('ansi-escapes', () => ({
cursorDown: (count = 1) => `[MOCK - cursorDown(${count})]`,
cursorHide: '[MOCK - cursorHide]',
cursorRestorePosition: '[MOCK - cursorRestorePosition]',
cursorSavePosition: '[MOCK - cursorSavePosition]',
cursorShow: '[MOCK - cursorShow]',
cursorTo: (x, y) => `[MOCK - cursorTo(${x}, ${y})]`,
}))
.mock('jest-util', () => {
const {specialChars, ...util} = jest.requireActual('jest-util');
return {
...util,
specialChars: {...specialChars, CLEAR: '[MOCK - clear]'},
};
});

jest.mock(
'../SearchSource',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,22 @@ import {KEYS} from 'jest-watcher';

const runJestMock = jest.fn();

jest.mock('ansi-escapes', () => ({
clearScreen: '[MOCK - clearScreen]',
cursorDown: (count = 1) => `[MOCK - cursorDown(${count})]`,
cursorHide: '[MOCK - cursorHide]',
cursorRestorePosition: '[MOCK - cursorRestorePosition]',
cursorSavePosition: '[MOCK - cursorSavePosition]',
cursorShow: '[MOCK - cursorShow]',
cursorTo: (x, y) => `[MOCK - cursorTo(${x}, ${y})]`,
}));
jest
.mock('ansi-escapes', () => ({
cursorDown: (count = 1) => `[MOCK - cursorDown(${count})]`,
cursorHide: '[MOCK - cursorHide]',
cursorRestorePosition: '[MOCK - cursorRestorePosition]',
cursorSavePosition: '[MOCK - cursorSavePosition]',
cursorShow: '[MOCK - cursorShow]',
cursorTo: (x, y) => `[MOCK - cursorTo(${x}, ${y})]`,
}))
.mock('jest-util', () => {
const {specialChars, ...util} = jest.requireActual('jest-util');
return {
...util,
specialChars: {...specialChars, CLEAR: '[MOCK - clear]'},
};
});

jest.mock(
'../SearchSource',
Expand Down
10 changes: 0 additions & 10 deletions packages/jest-cli/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,5 @@
* @flow
*/

const isWindows = process.platform === 'win32';

export const CLEAR = isWindows ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H';
export const ARROW = ' \u203A ';
export const ICONS = {
failed: isWindows ? '\u00D7' : '\u2715',
pending: '\u25CB',
success: isWindows ? '\u221A' : '\u2713',
todo: '\u270E',
};
export const PACKAGE_JSON = 'package.json';
export const JEST_CONFIG = 'jest.config.js';
4 changes: 3 additions & 1 deletion packages/jest-cli/src/reporters/verbose_reporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ import type {
import type {Test} from 'types/TestRunner';

import chalk from 'chalk';
import {ICONS} from '../constants';
import {specialChars} from 'jest-util';
import DefaultReporter from './default_reporter';

const {ICONS} = specialChars;

export default class VerboseReporter extends DefaultReporter {
_globalConfig: GlobalConfig;

Expand Down
7 changes: 3 additions & 4 deletions packages/jest-cli/src/watch.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@ import getChangedFilesPromise from './getChangedFilesPromise';
import exit from 'exit';
import HasteMap from 'jest-haste-map';
import isValidPath from './lib/is_valid_path';
import {isInteractive} from 'jest-util';
import {isInteractive, specialChars} from 'jest-util';
import {print as preRunMessagePrint} from './preRunMessage';
import createContext from './lib/create_context';
import runJest from './runJest';
import updateGlobalConfig from './lib/update_global_config';
import SearchSource from './SearchSource';
import TestWatcher from './TestWatcher';
import FailedTestsCache from './FailedTestsCache';
import {CLEAR} from './constants';
import {KEYS, JestHook} from 'jest-watcher';
import TestPathPatternPlugin from './plugins/test_path_pattern';
import TestNamePatternPlugin from './plugins/test_name_pattern';
Expand Down Expand Up @@ -236,7 +235,7 @@ export default function watch(
}

testWatcher = new TestWatcher({isWatchMode: true});
isInteractive && outputStream.write(CLEAR);
isInteractive && outputStream.write(specialChars.CLEAR);
preRunMessagePrint(outputStream);
isRunning = true;
const configs = contexts.map(context => context.config);
Expand Down Expand Up @@ -395,7 +394,7 @@ export default function watch(

const onCancelPatternPrompt = () => {
outputStream.write(ansiEscapes.cursorHide);
outputStream.write(ansiEscapes.clearScreen);
outputStream.write(specialChars.CLEAR);
outputStream.write(usage(globalConfig, watchPlugins));
outputStream.write(ansiEscapes.cursorShow);
};
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-util/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import getCallsite from './getCallsite';
import setGlobal from './setGlobal';
import deepCyclicCopy from './deepCyclicCopy';
import convertDescriptorToString from './convertDescriptorToString';
import * as specialChars from './specialChars';

const createDirectory = (path: string) => {
try {
Expand Down Expand Up @@ -52,4 +53,5 @@ module.exports = {
installCommonGlobals,
isInteractive,
setGlobal,
specialChars,
};
20 changes: 20 additions & 0 deletions packages/jest-util/src/specialChars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) 2018-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

const isWindows = process.platform === 'win32';

export const ARROW = ' \u203A ';
export const ICONS = {
failed: isWindows ? '\u00D7' : '\u2715',
pending: '\u25CB',
success: isWindows ? '\u221A' : '\u2713',
todo: '\u270E',
};

export const CLEAR = isWindows ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H';
1 change: 1 addition & 0 deletions packages/jest-watcher/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"dependencies": {
"ansi-escapes": "^3.0.0",
"chalk": "^2.0.1",
"jest-util": "^23.4.0",
"string-length": "^2.0.0"
},
"repository": {
Expand Down
5 changes: 4 additions & 1 deletion packages/jest-watcher/src/PatternPrompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import type {ScrollOptions} from 'types/Watch';

import chalk from 'chalk';
import ansiEscapes from 'ansi-escapes';
import {specialChars} from 'jest-util';
import Prompt from './lib/Prompt';
import {
printPatternCaret,
printRestoredPatternCaret,
} from './lib/patternModeHelpers';

const {CLEAR} = specialChars;

const usage = (entity: string) =>
`\n${chalk.bold('Pattern Mode Usage')}\n` +
` ${chalk.dim('\u203A Press')} Esc ${chalk.dim('to exit pattern mode.')}\n` +
Expand Down Expand Up @@ -51,7 +54,7 @@ export default class PatternPrompt {

run(onSuccess: Function, onCancel: Function, options?: {header: string}) {
this._pipe.write(ansiEscapes.cursorHide);
this._pipe.write(ansiEscapes.clearScreen);
this._pipe.write(CLEAR);

if (options && options.header) {
this._pipe.write(options.header + '\n');
Expand Down

0 comments on commit 297bd6e

Please sign in to comment.