Skip to content

Commit

Permalink
comments on the pr
Browse files Browse the repository at this point in the history
  • Loading branch information
Cristian Carlesso committed Mar 21, 2017
1 parent 7972ae6 commit b007791
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 98 deletions.
130 changes: 59 additions & 71 deletions packages/jest-editor-support/src/Snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

const fs = require('fs');
const traverse = require('babel-traverse').default;
const {getASTfor} = require('./parsers/BabylonParser');
const {utils} = require('jest-snapshot');

type Node = any;
Expand All @@ -23,47 +24,48 @@ type SnapshotMetadata = {
content?: string,
};

// create a lookup table from an array.
const lookupFromArray = array => array.reduce(
(table: any, prop) => {
table[prop] = true;
return table;
const describeVariants = Object.assign(
(Object.create(null): {[string]: boolean}),
{
describe: true,
fdescribe: true,
xdescribe: true,
},
Object.create(null)
);

const describeVariants = lookupFromArray([
'describe',
'fdescribe',
'xdescribe',
]);
const base = lookupFromArray(['describe', 'it', 'test']);
const decorators = lookupFromArray(['only', 'skip']);
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,
lookupFromArray(['xtest', 'xit', 'fit'])
Object.assign((Object.create(null): {[string]: boolean}), {
xtest: true,
xit: true,
fit: true,
}),
);

const isValidMemberExpression = node => (
node.object && base[node.object.name] &&
node.property && decorators[node.property.name]
);
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 isDescribe = node =>
describeVariants[node.name] ||
(isValidMemberExpression(node) && node.object.name === 'describe');

const isValidParent = parent => (
const isValidParent = parent =>
parent.callee &&
(
validParents[parent.callee.name] ||
isValidMemberExpression(parent.callee)
)
);
(validParents[parent.callee.name] || isValidMemberExpression(parent.callee));

const getArrayOfParents = path => {
const result = [];
Expand All @@ -73,20 +75,19 @@ const getArrayOfParents = path => {
parent = parent.parentPath;
}
return result;
}
};

const buildname: (
toMatchSnapshot: Node,
const buildName: (
snapshotNode: Node,
parents: Array<Node>,
position: number,
) => string = (toMatchSnapshot, parents, position) => {

) => 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
// If `it` or `test` exists without a surrounding `describe`
// then `test ` is prepended to the snapshot fullName.
describeLess = 'test ';
}

Expand All @@ -95,56 +96,43 @@ const buildname: (

module.exports = class Snapshot {
_parser: Function;
_parserOptions: any;

constructor(parser: any, parserOptions: any) {
this._parser = parser || require('babylon').parse;
this._parserOptions = parserOptions || {
plugins: [
'jsx', 'flow', 'objectRestSpread', 'classProperties',
],
sourceType: 'module',
};
_matchers: Array<string>;
constructor(parser: any, customMatchers?: Array<string>) {
this._parser = parser || getASTfor;
this._matchers = ['toMatchSnapshot', 'toThrowErrorMatchingSnapshot'].concat(
customMatchers || [],
);
}

getMetadata(filePath: string): Array<SnapshotMetadata> {
const fileContent = fs.readFileSync(filePath, 'utf8');

const fileNode = this._parser(fileContent, this._parserOptions);

const fileNode = this._parser(filePath);
const state = {
found: [],
};
const tocheck = {
found: []
};

const Visitors = {
Identifier(path, state) {
if (path.node.name === 'toMatchSnapshot') {
state.found.push({node: path.node, parents: getArrayOfParents(path)})
Identifier(path, state, matchers) {
if (matchers.includes(path.node.name)) {
state.found.push({node: path.node, parents: getArrayOfParents(path)});
}
}
}
},
};

traverse(fileNode, {
enter: function(path) {
enter: path => {
const visitor = Visitors[path.node.type];
if (visitor != null) {
visitor(path, state);
visitor(path, state, this._matchers);
}
}
},
});

let lastParent = null;
let count = 1;

const snapshotPath = utils.getSnapshotPath(filePath);
const snapshots = utils.getSnapshotData(snapshotPath, false).data;
let lastParent = null;
let count = 1;

return state.found.map((toMatchSnapshot, index) => {

const parents = toMatchSnapshot.parents.filter(isValidParent);
return state.found.map((snapshotNode, index) => {
const parents = snapshotNode.parents.filter(isValidParent);
const innerAssertion = parents[parents.length - 1];

if (lastParent !== innerAssertion) {
Expand All @@ -157,15 +145,15 @@ module.exports = class Snapshot {
count: count++,
exists: false,
name: '',
node: toMatchSnapshot.node,
node: snapshotNode.node,
};

if (!innerAssertion || isDescribe(innerAssertion.callee)) {
// an expectation inside a describe never get executed.
// An expectation inside describe never gets executed.
return result;
}

result.name = buildname(toMatchSnapshot, parents, result.count);
result.name = buildName(snapshotNode, parents, result.count);

if (snapshots[result.name]) {
result.exists = true;
Expand Down
60 changes: 38 additions & 22 deletions packages/jest-editor-support/src/__tests__/Snapshot-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@ 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',
'fit',
'it',
'it.only',
'it.skip',
'test',
'test.only',
'test.skip',
'xit',
'xtest',
];

const expectations = Object.create(null);
Expand All @@ -41,28 +48,38 @@ test('nodescribe.example', () => {
});

expect(
Object.keys(expectations).map(key => expectations[key]).filter(
expectation => !expectation.checked
).length
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',
'describe',
'describe.only',
'describe.skip',
'fdescribe',
'xdescribe',
];
const allAssertion = [
'fit', 'it', 'it.only', 'it.skip', 'test',
'test.only', 'test.skip', 'xit', 'xtest',
'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,
Expand All @@ -81,15 +98,14 @@ test('describe.example', () => {

results.forEach(result => {
const check = expectations[result.name];
if(!check) console.log(result)
check.checked = (
result.content === `${check.number} ${check.assertion} ${check.describe}`
);
if (!check) console.log(result);
check.checked = result.content ===
`${check.number} ${check.assertion} ${check.describe}`;
});
expect(
Object.keys(expectations).map(key => expectations[key]).filter(
expectation => !expectation.checked
).length
Object.keys(expectations)
.map(key => expectations[key])
.filter(expectation => !expectation.checked).length,
).toBe(0);
});

Expand All @@ -100,14 +116,14 @@ test('nested.example', () => {
expect(results[1].content).toBe('second nested');

expect(results[0].name).toBe(
'outer describe outer it inner describe inner it 1'
'outer describe outer it inner describe inner it 1',
);
expect(results[1].name).toBe(
'outer describe outer it inner describe inner it 2'
'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});
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});
});
2 changes: 2 additions & 0 deletions packages/jest-editor-support/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const Process = require('./Process');
const ProjectWorkspace = require('./ProjectWorkspace');
const Runner = require('./Runner');
const Settings = require('./Settings');
const Snapshot = require('./Snapshot');
const {Expect, ItBlock, Node} = require('./parsers/ParserNodes');
const {parse} = require('./parsers/BabylonParser');
const TestReconciler = require('./TestReconciler');
Expand All @@ -26,6 +27,7 @@ module.exports = {
ProjectWorkspace,
Runner,
Settings,
Snapshot,
TestReconciler,
parse,
};
14 changes: 9 additions & 5 deletions packages/jest-editor-support/src/parsers/BabylonParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,7 @@ const getBabelRC = (filename, {useCache}) => {
return cache[directory] || '';
};

const parse = (file: string) => {
const itBlocks: ItBlock[] = [];
const expects: Expect[] = [];

const getASTfor = (file: string) => {
const data = readFileSync(file).toString();
const babelRC = getBabelRC(file, {useCache: true});
const babel = JSON.parse(babelRC);
Expand All @@ -56,7 +53,13 @@ const parse = (file: string) => {
: ['*'];

const config = {plugins, sourceType: 'module'};
const ast = babylon.parse(data, config);
return babylon.parse(data, config);
};

const parse = (file: string) => {
const itBlocks: ItBlock[] = [];
const expects: Expect[] = [];
const ast = getASTfor(file);

// An `it`/`test` was found in the AST
// So take the AST node and create an object for us
Expand Down Expand Up @@ -189,4 +192,5 @@ const parse = (file: string) => {

module.exports = {
parse,
getASTfor,
};

0 comments on commit b007791

Please sign in to comment.