Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require an example path for custom snapshot resolver consistency check #7356

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,6 @@ The path to a module that can resolve test<->snapshot path. This config option l
Example snapshot resolver module:

```js
// my-snapshot-resolver-module
module.exports = {
// resolves from test to snapshot path
resolveSnapshotPath: (testPath, snapshotExtension) =>
Expand All @@ -676,6 +675,9 @@ module.exports = {
snapshotFilePath
.replace('__snapshots__', '__tests__')
.slice(0, -snapshotExtension.length),

// Example test path, used for preflight concistency check of the implementation above
testPathForConsistencyCheck: 'some/__tests__/example.test.js',
};
```

Expand Down
2 changes: 2 additions & 0 deletions e2e/snapshot-resolver/customSnapshotResolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ module.exports = {
snapshotFilePath
.replace('__snapshots__', '__tests__')
.slice(0, -snapshotExtension.length),

testPathForConsistencyCheck: 'foo/__tests__/bar.test.js',
};
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`malformed custom resolver in project config inconsistent functions throws 1`] = `"<bold>Custom snapshot resolver functions must transform paths consistently, i.e. expects resolveTestPath(resolveSnapshotPath('some-path/__tests__/snapshot_resolver.test.js')) === some-path/__SPECS__/snapshot_resolver.test.js</>"`;
exports[`malformed custom resolver in project config inconsistent functions throws 1`] = `"<bold>Custom snapshot resolver functions must transform paths consistently, i.e. expects resolveTestPath(resolveSnapshotPath('foo/__tests__/bar.test.js')) === foo/__SPECS__/bar.test.js</>"`;

exports[`malformed custom resolver in project config missing resolveSnapshotPath throws 1`] = `
"<bold>Custom snapshot resolver must implement a \`resolveSnapshotPath\` function.</>
"<bold>Custom snapshot resolver must implement a \`resolveSnapshotPath\` as a function.</>
Documentation: https://facebook.github.io/jest/docs/en/configuration.html#snapshotResolver"
`;

exports[`malformed custom resolver in project config missing resolveTestPath throws 1`] = `
"<bold>Custom snapshot resolver must implement a \`resolveTestPath\` function.</>
"<bold>Custom snapshot resolver must implement a \`resolveTestPath\` as a function.</>
Documentation: https://facebook.github.io/jest/docs/en/configuration.html#snapshotResolver"
`;

exports[`malformed custom resolver in project config missing testPathForConsistencyCheck throws 1`] = `
"<bold>Custom snapshot resolver must implement a \`testPathForConsistencyCheck\` as a string.</>
Documentation: https://facebook.github.io/jest/docs/en/configuration.html#snapshotResolver"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ module.exports = {
snapshotFilePath
.replace('__snapshots__', '__SPECS__')
.slice(0, -snapshotExtension.length),

testPathForConsistencyCheck: 'foo/__tests__/bar.test.js',
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

module.exports = {
resolveTestPath: () => {},
testPathForConsistencyCheck: 'foo/__tests__/bar.test.js',
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

module.exports = {
resolveSnapshotPath: () => {},
testPathForConsistencyCheck: 'foo/__tests__/bar.test.js',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.

module.exports = {
resolveSnapshotPath: (testPath, snapshotExtension) => {},
resolveTestPath: (snapshotFilePath, snapshotExtension) => {},
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ module.exports = {
snapshotFilePath
.replace('__snapshots__', '__tests__')
.slice(0, -snapshotExtension.length),

testPathForConsistencyCheck: 'foo/__tests__/bar.test.js',
};
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ describe('malformed custom resolver in project config', () => {
}).toThrowErrorMatchingSnapshot();
});

it('missing testPathForConsistencyCheck throws ', () => {
const projectConfig = newProjectConfig(
'customSnapshotResolver-missing-test-path-for-consistency-check.js',
);
expect(() => {
buildSnapshotResolver(projectConfig);
}).toThrowErrorMatchingSnapshot();
});

it('inconsistent functions throws ', () => {
const projectConfig = newProjectConfig(
'customSnapshotResolver-inconsistent-fns.js',
Expand Down
72 changes: 42 additions & 30 deletions packages/jest-snapshot/src/snapshot_resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,68 +25,80 @@ export const buildSnapshotResolver = (
function createSnapshotResolver(snapshotResolverPath: ?Path): SnapshotResolver {
return typeof snapshotResolverPath === 'string'
? createCustomSnapshotResolver(snapshotResolverPath)
: {
resolveSnapshotPath: (testPath: Path) =>
path.join(
path.join(path.dirname(testPath), '__snapshots__'),
path.basename(testPath) + DOT_EXTENSION,
),
: createDefaultSnapshotResolver();
}

function createDefaultSnapshotResolver() {
return {
resolveSnapshotPath: (testPath: Path) =>
path.join(
path.join(path.dirname(testPath), '__snapshots__'),
path.basename(testPath) + DOT_EXTENSION,
),

resolveTestPath: (snapshotPath: Path) =>
path.resolve(
path.dirname(snapshotPath),
'..',
path.basename(snapshotPath, DOT_EXTENSION),
),

resolveTestPath: (snapshotPath: Path) =>
path.resolve(
path.dirname(snapshotPath),
'..',
path.basename(snapshotPath, DOT_EXTENSION),
),
};
testPathForConsistencyCheck: path.posix.join(
'consistency_check',
'__tests__',
'example.test.js',
),
};
}

function createCustomSnapshotResolver(
snapshotResolverPath: Path,
): SnapshotResolver {
const custom = (require(snapshotResolverPath): SnapshotResolver);

if (typeof custom.resolveSnapshotPath !== 'function') {
throw new TypeError(mustImplement('resolveSnapshotPath'));
}
if (typeof custom.resolveTestPath !== 'function') {
throw new TypeError(mustImplement('resolveTestPath'));
}
[
['resolveSnapshotPath', 'function'],
['resolveTestPath', 'function'],
['testPathForConsistencyCheck', 'string'],
].forEach(([propName, requiredType]) => {
if (typeof custom[propName] !== requiredType) {
throw new TypeError(mustImplement(propName, requiredType));
}
});

const customResolver = {
resolveSnapshotPath: testPath =>
custom.resolveSnapshotPath(testPath, DOT_EXTENSION),
resolveTestPath: snapshotPath =>
custom.resolveTestPath(snapshotPath, DOT_EXTENSION),
testPathForConsistencyCheck: custom.testPathForConsistencyCheck,
};

verifyConsistentTransformations(customResolver);

return customResolver;
}

function mustImplement(functionName: string) {
function mustImplement(propName: string, requiredType: string) {
return (
chalk.bold(
`Custom snapshot resolver must implement a \`${functionName}\` function.`,
`Custom snapshot resolver must implement a \`${propName}\` as a ${requiredType}.`,
) +
'\nDocumentation: https://facebook.github.io/jest/docs/en/configuration.html#snapshotResolver'
);
}

function verifyConsistentTransformations(custom: SnapshotResolver) {
const fakeTestPath = path.posix.join(
'some-path',
'__tests__',
'snapshot_resolver.test.js',
);
const transformedPath = custom.resolveTestPath(
custom.resolveSnapshotPath(fakeTestPath),
const resolvedSnapshotPath = custom.resolveSnapshotPath(
custom.testPathForConsistencyCheck,
);
if (transformedPath !== fakeTestPath) {
const resolvedTestPath = custom.resolveTestPath(resolvedSnapshotPath);
if (resolvedTestPath !== custom.testPathForConsistencyCheck) {
throw new Error(
chalk.bold(
`Custom snapshot resolver functions must transform paths consistently, i.e. expects resolveTestPath(resolveSnapshotPath('${fakeTestPath}')) === ${transformedPath}`,
`Custom snapshot resolver functions must transform paths consistently, i.e. expects resolveTestPath(resolveSnapshotPath('${
custom.testPathForConsistencyCheck
}')) === ${resolvedTestPath}`,
),
);
}
Expand Down
1 change: 1 addition & 0 deletions types/SnapshotResolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import type {Path} from './Config';

export type SnapshotResolver = {|
testPathForConsistencyCheck: string,
resolveSnapshotPath(testPath: Path): Path,
resoveTestPath(snapshotPath: Path): Path,
|};