diff --git a/.eslintrc.js b/.eslintrc.js index 053fc383039e..fc737bf0a8f2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -63,6 +63,8 @@ module.exports = { 'packages/jest-editor-support/src/Process.js', 'packages/jest-editor-support/src/Runner.js', 'packages/jest-editor-support/src/Settings.js', + 'packages/jest-editor-support/src/Snapshot.js', + 'packages/jest-editor-support/src/__tests__/Snapshot-test.js', 'packages/jest-jasmine2/src/jasmine/Env.js', 'packages/jest-jasmine2/src/jasmine/Spec.js', 'packages/jest-jasmine2/src/jasmine/Suite.js', diff --git a/packages/jest-editor-support/package.json b/packages/jest-editor-support/package.json index 3af7167b2330..79415dfbdd73 100644 --- a/packages/jest-editor-support/package.json +++ b/packages/jest-editor-support/package.json @@ -8,7 +8,9 @@ "license": "MIT", "main": "build/index.js", "dependencies": { - "babylon": "^6.14.1" + "babylon": "^6.14.1", + "babel-traverse": "^6.14.1", + "jest-snapshot": "^21.1.0" }, "typings": "index.d.ts" } diff --git a/packages/jest-editor-support/src/Snapshot.js b/packages/jest-editor-support/src/Snapshot.js new file mode 100644 index 000000000000..8b445a88a028 --- /dev/null +++ b/packages/jest-editor-support/src/Snapshot.js @@ -0,0 +1,167 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +'use strict'; + +import traverse from 'babel-traverse'; +import {getASTfor} from './parsers/babylon_parser'; +import {utils} from 'jest-snapshot'; + +type Node = any; + +type SnapshotMetadata = { + exists: true | false, + name: string, + node: Node, + content?: string, +}; + +const describeVariants = Object.assign( + (Object.create(null): {[string]: boolean}), + { + describe: true, + fdescribe: true, + xdescribe: true, + }, +); +const base = Object.assign((Object.create(null): {[string]: boolean}), { + describe: true, + it: true, + test: true, +}); +const decorators = Object.assign((Object.create(null): {[string]: boolean}), { + only: true, + skip: true, +}); + +const validParents = Object.assign( + (Object.create(null): any), + base, + describeVariants, + Object.assign((Object.create(null): {[string]: boolean}), { + fit: true, + xit: true, + xtest: true, + }), +); + +const isValidMemberExpression = node => + node.object && + base[node.object.name] && + node.property && + decorators[node.property.name]; + +const isDescribe = node => + describeVariants[node.name] || + (isValidMemberExpression(node) && node.object.name === 'describe'); + +const isValidParent = parent => + parent.callee && + (validParents[parent.callee.name] || isValidMemberExpression(parent.callee)); + +const getArrayOfParents = path => { + const result = []; + let parent = path.parentPath; + while (parent) { + result.unshift(parent.node); + parent = parent.parentPath; + } + return result; +}; + +const buildName: ( + snapshotNode: Node, + parents: Array, + position: number, +) => string = (snapshotNode, parents, position) => { + const fullName = parents.map(parent => parent.arguments[0].value).join(' '); + + let describeLess = ''; + if (!isDescribe(parents[0].callee)) { + // If `it` or `test` exists without a surrounding `describe` + // then `test ` is prepended to the snapshot fullName. + describeLess = 'test '; + } + + return utils.testNameToKey(describeLess + fullName, position); +}; + +export default class Snapshot { + _parser: Function; + _matchers: Array; + constructor(parser: any, customMatchers?: Array) { + this._parser = parser || getASTfor; + this._matchers = ['toMatchSnapshot', 'toThrowErrorMatchingSnapshot'].concat( + customMatchers || [], + ); + } + + getMetadata(filePath: string): Array { + const fileNode = this._parser(filePath); + const state = { + found: [], + }; + const Visitors = { + Identifier(path, state, matchers) { + if (matchers.includes(path.node.name)) { + state.found.push({ + node: path.node, + parents: getArrayOfParents(path), + }); + } + }, + }; + + traverse(fileNode, { + enter: path => { + const visitor = Visitors[path.node.type]; + if (visitor != null) { + visitor(path, state, this._matchers); + } + }, + }); + + const snapshotPath = utils.getSnapshotPath(filePath); + const snapshots = utils.getSnapshotData(snapshotPath, 'none').data; + let lastParent = null; + let count = 1; + + return state.found.map((snapshotNode, index) => { + const parents = snapshotNode.parents.filter(isValidParent); + const innerAssertion = parents[parents.length - 1]; + + if (lastParent !== innerAssertion) { + lastParent = innerAssertion; + count = 1; + } + + const result = { + content: undefined, + count: count++, + exists: false, + name: '', + node: snapshotNode.node, + }; + + if (!innerAssertion || isDescribe(innerAssertion.callee)) { + // An expectation inside describe never gets executed. + return result; + } + + result.name = buildName(snapshotNode, parents, result.count); + + if (snapshots[result.name]) { + result.exists = true; + result.content = snapshots[result.name]; + } + return result; + }); + } +} diff --git a/packages/jest-editor-support/src/__tests__/Snapshot-test.js b/packages/jest-editor-support/src/__tests__/Snapshot-test.js new file mode 100644 index 000000000000..ca076a7ae800 --- /dev/null +++ b/packages/jest-editor-support/src/__tests__/Snapshot-test.js @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +'use strict'; + +const path = require('path'); +const Snapshot = require('../Snapshot'); +const snapshotHelper = new Snapshot(); +const snapshotFixturePath = path.resolve(__dirname, 'fixtures/snapshots'); + +test('nodescribe.example', () => { + const filePath = path.join(snapshotFixturePath, 'nodescribe.example'); + const results = snapshotHelper.getMetadata(filePath); + const allAssertion = [ + 'fit', + 'it', + 'it.only', + 'it.skip', + 'test', + 'test.only', + 'test.skip', + 'xit', + 'xtest', + ]; + + const expectations = Object.create(null); + allAssertion.forEach(assertion => { + expectations['test ' + assertion + ' 1'] = { + assertion, + checked: false, + number: 1, + }; + expectations['test ' + assertion + ' 2'] = { + assertion, + checked: false, + number: 2, + }; + }); + + results.forEach(result => { + const check = expectations[result.name]; + check.checked = result.content === `${check.assertion} ${check.number}`; + }); + + expect( + Object.keys(expectations) + .map(key => expectations[key]) + .filter(expectation => !expectation.checked).length, + ).toBe(0); +}); + +test('describe.example', () => { + const filePath = path.join(snapshotFixturePath, 'describe.example'); + const results = snapshotHelper.getMetadata(filePath); + const allDescribe = [ + 'describe', + 'describe.only', + 'describe.skip', + 'fdescribe', + 'xdescribe', + ]; + const allAssertion = [ + 'fit', + 'it', + 'it.only', + 'it.skip', + 'test', + 'test.only', + 'test.skip', + 'xit', + 'xtest', + ]; + + const expectations = Object.create(null); + + allDescribe.forEach(describe => { + allAssertion.forEach(assertion => { + expectations[describe.toUpperCase() + ' ' + assertion + ' 1'] = { + assertion, + checked: false, + describe, + number: 1, + }; + + expectations[describe.toUpperCase() + ' ' + assertion + ' 2'] = { + assertion, + checked: false, + describe, + number: 2, + }; + }); + }); + + results.forEach(result => { + const check = expectations[result.name]; + check.checked = + result.content === `${check.number} ${check.assertion} ${check.describe}`; + }); + expect( + Object.keys(expectations) + .map(key => expectations[key]) + .filter(expectation => !expectation.checked).length, + ).toBe(0); +}); + +test('nested.example', () => { + const filePath = path.join(snapshotFixturePath, 'nested.example'); + const results = snapshotHelper.getMetadata(filePath); + expect(results[0].content).toBe('first nested'); + expect(results[1].content).toBe('second nested'); + + expect(results[0].name).toBe( + 'outer describe outer it inner describe inner it 1', + ); + expect(results[1].name).toBe( + 'outer describe outer it inner describe inner it 2', + ); + + expect(results[0].node.loc.start).toEqual({column: 21, line: 5}); + expect(results[0].node.loc.end).toEqual({column: 36, line: 5}); + expect(results[1].node.loc.start).toEqual({column: 21, line: 6}); + expect(results[1].node.loc.end).toEqual({column: 36, line: 6}); +}); diff --git a/packages/jest-editor-support/src/__tests__/fixtures/snapshots/__snapshots__/describe.example.snap b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/__snapshots__/describe.example.snap new file mode 100644 index 000000000000..d60e6dc0998d --- /dev/null +++ b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/__snapshots__/describe.example.snap @@ -0,0 +1,91 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`DESCRIBE fit 1`] = `1 fit describe`; +exports[`DESCRIBE fit 2`] = `2 fit describe`; +exports[`DESCRIBE it 1`] = `1 it describe`; +exports[`DESCRIBE it 2`] = `2 it describe`; +exports[`DESCRIBE it.only 1`] = `1 it.only describe`; +exports[`DESCRIBE it.only 2`] = `2 it.only describe`; +exports[`DESCRIBE it.skip 1`] = `1 it.skip describe`; +exports[`DESCRIBE it.skip 2`] = `2 it.skip describe`; +exports[`DESCRIBE test 1`] = `1 test describe`; +exports[`DESCRIBE test 2`] = `2 test describe`; +exports[`DESCRIBE test.only 1`] = `1 test.only describe`; +exports[`DESCRIBE test.only 2`] = `2 test.only describe`; +exports[`DESCRIBE test.skip 1`] = `1 test.skip describe`; +exports[`DESCRIBE test.skip 2`] = `2 test.skip describe`; +exports[`DESCRIBE xit 1`] = `1 xit describe`; +exports[`DESCRIBE xit 2`] = `2 xit describe`; +exports[`DESCRIBE xtest 1`] = `1 xtest describe`; +exports[`DESCRIBE xtest 2`] = `2 xtest describe`; +exports[`DESCRIBE.ONLY fit 1`] = `1 fit describe.only`; +exports[`DESCRIBE.ONLY fit 2`] = `2 fit describe.only`; +exports[`DESCRIBE.ONLY it 1`] = `1 it describe.only`; +exports[`DESCRIBE.ONLY it 2`] = `2 it describe.only`; +exports[`DESCRIBE.ONLY it.only 1`] = `1 it.only describe.only`; +exports[`DESCRIBE.ONLY it.only 2`] = `2 it.only describe.only`; +exports[`DESCRIBE.ONLY it.skip 1`] = `1 it.skip describe.only`; +exports[`DESCRIBE.ONLY it.skip 2`] = `2 it.skip describe.only`; +exports[`DESCRIBE.ONLY test 1`] = `1 test describe.only`; +exports[`DESCRIBE.ONLY test 2`] = `2 test describe.only`; +exports[`DESCRIBE.ONLY test.only 1`] = `1 test.only describe.only`; +exports[`DESCRIBE.ONLY test.only 2`] = `2 test.only describe.only`; +exports[`DESCRIBE.ONLY test.skip 1`] = `1 test.skip describe.only`; +exports[`DESCRIBE.ONLY test.skip 2`] = `2 test.skip describe.only`; +exports[`DESCRIBE.ONLY xit 1`] = `1 xit describe.only`; +exports[`DESCRIBE.ONLY xit 2`] = `2 xit describe.only`; +exports[`DESCRIBE.ONLY xtest 1`] = `1 xtest describe.only`; +exports[`DESCRIBE.ONLY xtest 2`] = `2 xtest describe.only`; +exports[`DESCRIBE.SKIP fit 1`] = `1 fit describe.skip`; +exports[`DESCRIBE.SKIP fit 2`] = `2 fit describe.skip`; +exports[`DESCRIBE.SKIP it 1`] = `1 it describe.skip`; +exports[`DESCRIBE.SKIP it 2`] = `2 it describe.skip`; +exports[`DESCRIBE.SKIP it.only 1`] = `1 it.only describe.skip`; +exports[`DESCRIBE.SKIP it.only 2`] = `2 it.only describe.skip`; +exports[`DESCRIBE.SKIP it.skip 1`] = `1 it.skip describe.skip`; +exports[`DESCRIBE.SKIP it.skip 2`] = `2 it.skip describe.skip`; +exports[`DESCRIBE.SKIP test 1`] = `1 test describe.skip`; +exports[`DESCRIBE.SKIP test 2`] = `2 test describe.skip`; +exports[`DESCRIBE.SKIP test.only 1`] = `1 test.only describe.skip`; +exports[`DESCRIBE.SKIP test.only 2`] = `2 test.only describe.skip`; +exports[`DESCRIBE.SKIP test.skip 1`] = `1 test.skip describe.skip`; +exports[`DESCRIBE.SKIP test.skip 2`] = `2 test.skip describe.skip`; +exports[`DESCRIBE.SKIP xit 1`] = `1 xit describe.skip`; +exports[`DESCRIBE.SKIP xit 2`] = `2 xit describe.skip`; +exports[`DESCRIBE.SKIP xtest 1`] = `1 xtest describe.skip`; +exports[`DESCRIBE.SKIP xtest 2`] = `2 xtest describe.skip`; +exports[`FDESCRIBE fit 1`] = `1 fit fdescribe`; +exports[`FDESCRIBE fit 2`] = `2 fit fdescribe`; +exports[`FDESCRIBE it 1`] = `1 it fdescribe`; +exports[`FDESCRIBE it 2`] = `2 it fdescribe`; +exports[`FDESCRIBE it.only 1`] = `1 it.only fdescribe`; +exports[`FDESCRIBE it.only 2`] = `2 it.only fdescribe`; +exports[`FDESCRIBE it.skip 1`] = `1 it.skip fdescribe`; +exports[`FDESCRIBE it.skip 2`] = `2 it.skip fdescribe`; +exports[`FDESCRIBE test 1`] = `1 test fdescribe`; +exports[`FDESCRIBE test 2`] = `2 test fdescribe`; +exports[`FDESCRIBE test.only 1`] = `1 test.only fdescribe`; +exports[`FDESCRIBE test.only 2`] = `2 test.only fdescribe`; +exports[`FDESCRIBE test.skip 1`] = `1 test.skip fdescribe`; +exports[`FDESCRIBE test.skip 2`] = `2 test.skip fdescribe`; +exports[`FDESCRIBE xit 1`] = `1 xit fdescribe`; +exports[`FDESCRIBE xit 2`] = `2 xit fdescribe`; +exports[`FDESCRIBE xtest 1`] = `1 xtest fdescribe`; +exports[`FDESCRIBE xtest 2`] = `2 xtest fdescribe`; +exports[`XDESCRIBE fit 1`] = `1 fit xdescribe`; +exports[`XDESCRIBE fit 2`] = `2 fit xdescribe`; +exports[`XDESCRIBE it 1`] = `1 it xdescribe`; +exports[`XDESCRIBE it 2`] = `2 it xdescribe`; +exports[`XDESCRIBE it.only 1`] = `1 it.only xdescribe`; +exports[`XDESCRIBE it.only 2`] = `2 it.only xdescribe`; +exports[`XDESCRIBE it.skip 1`] = `1 it.skip xdescribe`; +exports[`XDESCRIBE it.skip 2`] = `2 it.skip xdescribe`; +exports[`XDESCRIBE test 1`] = `1 test xdescribe`; +exports[`XDESCRIBE test 2`] = `2 test xdescribe`; +exports[`XDESCRIBE test.only 1`] = `1 test.only xdescribe`; +exports[`XDESCRIBE test.only 2`] = `2 test.only xdescribe`; +exports[`XDESCRIBE test.skip 1`] = `1 test.skip xdescribe`; +exports[`XDESCRIBE test.skip 2`] = `2 test.skip xdescribe`; +exports[`XDESCRIBE xit 1`] = `1 xit xdescribe`; +exports[`XDESCRIBE xit 2`] = `2 xit xdescribe`; +exports[`XDESCRIBE xtest 1`] = `1 xtest xdescribe`; +exports[`XDESCRIBE xtest 2`] = `2 xtest xdescribe`; diff --git a/packages/jest-editor-support/src/__tests__/fixtures/snapshots/__snapshots__/nested.example.snap b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/__snapshots__/nested.example.snap new file mode 100644 index 000000000000..ee8a6ffce3a2 --- /dev/null +++ b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/__snapshots__/nested.example.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`outer describe outer it inner describe inner it 1`] = `first nested`; +exports[`outer describe outer it inner describe inner it 2`] = `second nested`; diff --git a/packages/jest-editor-support/src/__tests__/fixtures/snapshots/__snapshots__/nodescribe.example.snap b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/__snapshots__/nodescribe.example.snap new file mode 100644 index 000000000000..36680c31ce0c --- /dev/null +++ b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/__snapshots__/nodescribe.example.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`test fit 1`]=`fit 1`; +exports[`test fit 2`]=`fit 2`; +exports[`test it 1`]=`it 1`; +exports[`test it 2`]=`it 2`; +exports[`test it.only 1`]=`it.only 1`; +exports[`test it.only 2`]=`it.only 2`; +exports[`test it.skip 1`]=`it.skip 1`; +exports[`test it.skip 2`]=`it.skip 2`; +exports[`test test 1`]=`test 1`; +exports[`test test 2`]=`test 2`; +exports[`test test.only 1`]=`test.only 1`; +exports[`test test.only 2`]=`test.only 2`; +exports[`test test.skip 1`]=`test.skip 1`; +exports[`test test.skip 2`]=`test.skip 2`; +exports[`test xit 1`]=`xit 1`; +exports[`test xit 2`]=`xit 2`; +exports[`test xtest 1`]=`xtest 1`; +exports[`test xtest 2`]=`xtest 2`; diff --git a/packages/jest-editor-support/src/__tests__/fixtures/snapshots/describe.example b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/describe.example new file mode 100644 index 000000000000..5380757ef2e8 --- /dev/null +++ b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/describe.example @@ -0,0 +1,194 @@ +describe('DESCRIBE', () => { + fit('fit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it('it', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it.only('it.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it.skip('it.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test('test', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test.only('test.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test.skip('test.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + xit('xit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + xtest('xtest', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) +}) + +describe.only('DESCRIBE.ONLY', () => { + fit('fit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it('it', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it.only('it.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it.skip('it.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test('test', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test.only('test.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test.skip('test.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + xit('xit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + xtest('xtest', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) +}) + +describe.skip('DESCRIBE.SKIP', () => { + fit('fit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it('it', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it.only('it.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it.skip('it.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test('test', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test.only('test.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test.skip('test.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + xit('xit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + xtest('xtest', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) +}) + +fdescribe('FDESCRIBE', () => { + fit('fit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it('it', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it.only('it.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it.skip('it.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test('test', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test.only('test.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test.skip('test.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + xit('xit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + xtest('xtest', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) +}) + +xdescribe('XDESCRIBE', () => { + fit('fit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it('it', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it.only('it.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + it.skip('it.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test('test', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test.only('test.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + test.skip('test.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + xit('xit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + xtest('xtest', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) +}) diff --git a/packages/jest-editor-support/src/__tests__/fixtures/snapshots/nested.example b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/nested.example new file mode 100644 index 000000000000..260bd5a556a4 --- /dev/null +++ b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/nested.example @@ -0,0 +1,10 @@ +describe('outer describe', () => { + it('outer it', () => { + describe('inner describe', () => { + it('inner it', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); + }) + }) + }) +}) diff --git a/packages/jest-editor-support/src/__tests__/fixtures/snapshots/nodescribe.example b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/nodescribe.example new file mode 100644 index 000000000000..90634fdc7560 --- /dev/null +++ b/packages/jest-editor-support/src/__tests__/fixtures/snapshots/nodescribe.example @@ -0,0 +1,36 @@ +fit('fit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); +}) +it('it', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); +}) +it.only('it.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); +}) +it.skip('it.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); +}) +test('test', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); +}) +test.only('test.only', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); +}) +test.skip('test.skip', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); +}) +xit('xit', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); +}) +xtest('xtest', () => { + expect(fake).toMatchSnapshot(); + expect(fake).toMatchSnapshot(); +}) diff --git a/packages/jest-editor-support/src/index.js b/packages/jest-editor-support/src/index.js index db2b32dd2c33..146f57f90b6e 100644 --- a/packages/jest-editor-support/src/index.js +++ b/packages/jest-editor-support/src/index.js @@ -12,6 +12,7 @@ import * as Process from './Process'; import ProjectWorkspace from './project_workspace'; import Runner from './Runner'; import Settings from './Settings'; +import Snapshot from './Snapshot'; import {Expect, ItBlock, Node} from './parsers/parser_nodes'; import {parse} from './parsers/babylon_parser'; import TestReconciler from './test_reconciler'; @@ -24,6 +25,7 @@ module.exports = { ProjectWorkspace, Runner, Settings, + Snapshot, TestReconciler, parse, }; diff --git a/packages/jest-editor-support/src/parsers/babylon_parser.js b/packages/jest-editor-support/src/parsers/babylon_parser.js index 314d9b28335b..9e3c38fe982d 100644 --- a/packages/jest-editor-support/src/parsers/babylon_parser.js +++ b/packages/jest-editor-support/src/parsers/babylon_parser.js @@ -11,20 +11,24 @@ import {readFileSync} from 'fs'; import {parse as babylonParse} from 'babylon'; import {Expect, ItBlock} from './parser_nodes'; +import type {File as BabylonFile} from 'babylon'; export type BabylonParserResult = { expects: Array, itBlocks: Array, }; +export const getASTfor = (file: string): BabylonFile => { + const data = readFileSync(file).toString(); + const config = {plugins: ['*'], sourceType: 'module'}; + return babylonParse(data, config); +}; + export const parse = (file: string): BabylonParserResult => { const itBlocks: ItBlock[] = []; const expects: Expect[] = []; - const data = readFileSync(file).toString(); - - const config = {plugins: ['*'], sourceType: 'module'}; - const ast = babylonParse(data, config); + const ast = getASTfor(file); // An `it`/`test` was found in the AST // So take the AST node and create an object for us diff --git a/packages/jest-snapshot/src/index.js b/packages/jest-snapshot/src/index.js index 3d723f365128..bd59c992baa5 100644 --- a/packages/jest-snapshot/src/index.js +++ b/packages/jest-snapshot/src/index.js @@ -22,13 +22,13 @@ import { } from 'jest-matcher-utils'; import SnapshotState from './State'; import {addSerializer, getSerializers} from './plugins'; -import {SNAPSHOT_EXTENSION} from './utils'; +import * as utils from './utils'; const fileExists = (filePath: Path, hasteFS: HasteFS): boolean => hasteFS.exists(filePath) || fs.existsSync(filePath); const cleanup = (hasteFS: HasteFS, update: SnapshotUpdateState) => { - const pattern = '\\.' + SNAPSHOT_EXTENSION + '$'; + const pattern = '\\.' + utils.SNAPSHOT_EXTENSION + '$'; const files = hasteFS.matchFiles(pattern); const filesRemoved = files .filter( @@ -37,7 +37,7 @@ const cleanup = (hasteFS: HasteFS, update: SnapshotUpdateState) => { path.resolve( path.dirname(snapshotFile), '..', - path.basename(snapshotFile, '.' + SNAPSHOT_EXTENSION), + path.basename(snapshotFile, '.' + utils.SNAPSHOT_EXTENSION), ), hasteFS, ), @@ -148,11 +148,12 @@ const toThrowErrorMatchingSnapshot = function(received: any, expected: void) { }; module.exports = { - EXTENSION: SNAPSHOT_EXTENSION, + EXTENSION: utils.SNAPSHOT_EXTENSION, SnapshotState, addSerializer, cleanup, getSerializers, toMatchSnapshot, toThrowErrorMatchingSnapshot, + utils, }; diff --git a/yarn.lock b/yarn.lock index 59fcae6047ef..1f68c5565c1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -908,7 +908,7 @@ babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.18.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-traverse@^6.26.0: +babel-traverse@^6.14.1, babel-traverse@^6.18.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: