diff --git a/.eslintrc.js b/.eslintrc.js index 347ca90d1ae8..d2e5ea2f3adb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -100,6 +100,12 @@ module.exports = { 'import/no-extraneous-dependencies': 0, }, }, + { + files: ['packages/jest-jasmine2/**', 'packages/jest-circus/**'], + rules: { + 'no-array-constructor': 0, + }, + }, ], parser: 'babel-eslint', plugins: ['markdown', 'import', 'prettier'], diff --git a/e2e/__tests__/iterator-to-null-test.js b/e2e/__tests__/iterator-to-null.test.js similarity index 100% rename from e2e/__tests__/iterator-to-null-test.js rename to e2e/__tests__/iterator-to-null.test.js diff --git a/packages/jest-circus/src/eventHandler.ts b/packages/jest-circus/src/eventHandler.ts index a29b69828d7b..1f648d364638 100644 --- a/packages/jest-circus/src/eventHandler.ts +++ b/packages/jest-circus/src/eventHandler.ts @@ -111,10 +111,10 @@ const eventHandler: EventHandler = (event, state): void => { } else if (type === 'afterAll') { // Attaching `afterAll` errors to each test makes execution flow // too complicated, so we'll consider them to be global. - state.unhandledErrors.push([error, asyncError]); + state.unhandledErrors.push(new Array(error, asyncError)); } else { invariant(test, 'always present for `*Each` hooks'); - test!.errors.push([error, asyncError]); + test!.errors.push(new Array(error, asyncError)); } break; } @@ -143,11 +143,11 @@ const eventHandler: EventHandler = (event, state): void => { error, test: {asyncError}, } = event; - event.test.errors.push([error, asyncError]); + event.test.errors.push(new Array(error, asyncError)); break; } case 'test_retry': { - event.test.errors = []; + event.test.errors = new Array(); break; } case 'run_start': { diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index 04d5b8459b8d..537853ea68b7 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -45,7 +45,7 @@ const _runTestsForDescribeBlock = async (describeBlock: DescribeBlock) => { // Tests that fail and are retried we run after other tests const retryTimes = parseInt(global[RETRY_TIMES], 10) || 0; - const deferredRetryTests = []; + const deferredRetryTests = new Array(); for (const test of describeBlock.tests) { await _runTest(test); diff --git a/packages/jest-circus/src/state.ts b/packages/jest-circus/src/state.ts index 8f684d254d16..4128598b8b2e 100644 --- a/packages/jest-circus/src/state.ts +++ b/packages/jest-circus/src/state.ts @@ -29,7 +29,7 @@ const INITIAL_STATE: State = { rootDescribeBlock: ROOT_DESCRIBE_BLOCK, testNamePattern: null, testTimeout: 5000, - unhandledErrors: [], + unhandledErrors: new Array(), }; global[STATE_SYM] = INITIAL_STATE; diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index 7917d1356e9d..aea6e6e6aa38 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -44,12 +44,12 @@ export const makeDescribe = ( } return { - children: [], - hooks: [], + children: new Array(), + hooks: new Array(), mode: _mode, name: convertDescriptorToString(name), parent, - tests: [], + tests: new Array(), }; }; @@ -63,7 +63,7 @@ export const makeTest = ( ): TestEntry => ({ asyncError, duration: null, - errors: [], + errors: new Array(), fn, invocations: 0, mode, @@ -95,8 +95,8 @@ export const getAllHooksForDescribe = (describe: DescribeBlock) => { beforeAll: Array; afterAll: Array; } = { - afterAll: [], - beforeAll: [], + afterAll: new Array(), + beforeAll: new Array(), }; if (hasEnabledTest(describe)) { @@ -119,11 +119,11 @@ export const getEachHooksForTest = (test: TestEntry) => { const result: { beforeEach: Array; afterEach: Array; - } = {afterEach: [], beforeEach: []}; + } = {afterEach: new Array(), beforeEach: new Array()}; let block: DescribeBlock | undefined | null = test.parent; do { - const beforeEachForCurrentBlock = []; + const beforeEachForCurrentBlock = new Array(); for (const hook of block.hooks) { switch (hook.type) { case 'beforeEach': @@ -136,7 +136,10 @@ export const getEachHooksForTest = (test: TestEntry) => { } // 'beforeEach' hooks are executed from top to bottom, the opposite of the // way we traversed it. - result.beforeEach = [...beforeEachForCurrentBlock, ...result.beforeEach]; + result.beforeEach = new Array( + ...beforeEachForCurrentBlock, + ...result.beforeEach, + ); } while ((block = block.parent)); return result; }; @@ -248,9 +251,9 @@ export const makeRunResult = ( const makeTestResults = (describeBlock: DescribeBlock): TestResults => { const {includeTestLocationInResult} = getState(); - let testResults: TestResults = []; + let testResults: TestResults = new Array(); for (const test of describeBlock.tests) { - const testPath = []; + const testPath = new Array(); let parent: TestEntry | DescribeBlock = test; do { testPath.unshift(parent.name); @@ -298,7 +301,7 @@ const makeTestResults = (describeBlock: DescribeBlock): TestResults => { // Return a string that identifies the test (concat of parent describe block // names + test title) export const getTestID = (test: TestEntry) => { - const titles = []; + const titles = new Array(); let parent: TestEntry | DescribeBlock = test; do { titles.unshift(parent.name); @@ -342,7 +345,7 @@ export const addErrorToEachTestUnderDescribe = ( asyncError: Exception, ) => { for (const test of describeBlock.tests) { - test.errors.push([error, asyncError]); + test.errors.push(new Array(error, asyncError)); } for (const child of describeBlock.children) { diff --git a/packages/jest-jasmine2/src/queueRunner.js b/packages/jest-jasmine2/src/queueRunner.js index e55108b66b18..6fe7902a5588 100644 --- a/packages/jest-jasmine2/src/queueRunner.js +++ b/packages/jest-jasmine2/src/queueRunner.js @@ -51,7 +51,9 @@ export default function queueRunner(options: Options) { } }); - promise = Promise.race([promise, token]); + // `new Array` to avoid contaminated array prototypes + // $FlowFixMe + promise = Promise.race(new Array(promise, token)); if (!timeout) { return promise; diff --git a/packages/jest-util/src/installCommonGlobals.ts b/packages/jest-util/src/installCommonGlobals.ts index 17c87ff980db..8c6b94289a9c 100644 --- a/packages/jest-util/src/installCommonGlobals.ts +++ b/packages/jest-util/src/installCommonGlobals.ts @@ -46,6 +46,11 @@ export default function( value: fs.existsSync.bind(fs), writable: false, }, + [symbol.for('jest-native-array')]: { + enumerable: false, + value: Array.bind(Array), + writable: false, + }, 'jest-symbol-do-not-touch': { enumerable: false, value: symbol, diff --git a/scripts/babel-plugin-jest-native-globals.js b/scripts/babel-plugin-jest-native-globals.js index c1e60921917a..81193de3c9f0 100644 --- a/scripts/babel-plugin-jest-native-globals.js +++ b/scripts/babel-plugin-jest-native-globals.js @@ -29,6 +29,9 @@ module.exports = ({template}) => { const fsExistsFileDeclaration = template(` var jestExistsFile = global[Symbol.for('jest-native-exists-file')] || fs.existsSync; `); + const arrayDeclaration = template(` + var Array = global[Symbol.for('jest-native-array')] || Array; + `); return { name: 'jest-native-globals', @@ -116,6 +119,15 @@ module.exports = ({template}) => { path.parentPath.replaceWithSourceString('jestExistsFile'); } } + if (path.node.name === 'Array' && !state.jestInjectedArray) { + state.jestInjectedArray = true; + path + .findParent(p => p.isProgram()) + .unshiftContainer('body', arrayDeclaration()); + path + .findParent(p => p.isProgram()) + .unshiftContainer('body', symbolDeclaration()); + } }, }, };