Skip to content
This repository has been archived by the owner on Aug 13, 2023. It is now read-only.

Commit

Permalink
Add and use method to test a package's exported values
Browse files Browse the repository at this point in the history
Cherry pick changes to `psammead-test-helpers` from the POC PR - #224
  • Loading branch information
Phil Lee committed Jan 4, 2019
1 parent fc55cdc commit b0a8c0b
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 2 deletions.
1 change: 1 addition & 0 deletions packages/utilities/psammead-test-helpers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

| Version | Description |
|---------|-------------|
| 0.3.0 | [PR#224](https://github.com/BBC-News/psammead/pull/224) Adds a helper method for testing package export values and uses it to test its own exports. |
| 0.2.1 | [PR#255](https://github.com/BBC-News/psammead/pull/255) Bumps package version to fix what appears to be an erroneously-published version. |
| 0.1.2 | [PR#212](https://github.com/BBC-News/psammead/pull/212) Update package description and README. |
| 0.1.1 | [PR#173](https://github.com/BBC-News/psammead/pull/173) Update PRs welcome link |
Expand Down
3 changes: 3 additions & 0 deletions packages/utilities/psammead-test-helpers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This package provides a collection of helper methods for implementing Jest snaps
| shallowRender | component | Shallow renders the component using react-test-renderer and returns the render output |
| shouldShallowMatchSnapshot | title, component | Shallow renders the component using react-test-renderer and asserts that it matches the given snapshot, which will be saved in the `__snapshots__` directory. The first argument `title` is the title for the test. |
| isNull | title, component | Renders the component using react-test-renderer, converts it to JSON and asserts that it is null. The first argument `title` is the title for the test. |
| testUtilityPackages | actualExports, expectedExports, utilityName | Validates an imported utility package's exported values against an object of key-value pairs in the form `{ name_of_export: 'type of export' }`, e.g. `{ shouldMatchSnapshot: 'function' }`. |

## Installation

Expand All @@ -34,6 +35,8 @@ There is currently a plan to migrate from `react-test-renderer` to `enzyme` as i

## Contributing

When **adding** a new export to this utility package the [export tests](https://github.com/BBC-News/psammead/blob/5d7395fd60bd8d73796d5a23775b4b5b36db1445/packages/utilities/psammead-test-helpers/index.test.jsx#L8-L14) also need to be updated and the export should be adding to the [README](https://github.com/BBC-News/psammead/tree/5d7395fd60bd8d73796d5a23775b4b5b36db1445/packages/utilities/psammead-test-helpers#exported-functions). When **removing** an exisiting export from this utility package the [export tests](https://github.com/BBC-News/psammead/blob/5d7395fd60bd8d73796d5a23775b4b5b36db1445/packages/utilities/psammead-test-helpers/index.test.jsx#L8-L14) need to be updated, the export should be removed from the [README](https://github.com/BBC-News/psammead/tree/5d7395fd60bd8d73796d5a23775b4b5b36db1445/packages/utilities/psammead-test-helpers#exported-functions) and the package version requires a major change (EG: 1.2.1 -> 2.0.0) as this would be considered a breaking change due to functionality being removed.

Psammead is completely open source. We are grateful for any contributions, whether they be new components, bug fixes or general improvements. Please see our primary contributing guide which can be found at [the root of the Psammead respository](https://github.com/BBC-News/psammead/blob/latest/CONTRIBUTING.md).

### [Code of Conduct](https://github.com/BBC-News/psammead/blob/latest/CODE_OF_CONDUCT.md)
Expand Down
106 changes: 106 additions & 0 deletions packages/utilities/psammead-test-helpers/index.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import * as testHelpers from '.';
import * as testHelpersFromSrc from './src/index';

const testHelpersExpectedExports = {
shouldMatchSnapshot: 'function',
shallowRender: 'function',
shouldShallowMatchSnapshot: 'function',
isNull: 'function',
testUtilityPackages: 'function',
};

const expectedExports = { testHelpers: testHelpersExpectedExports };

const actualExports = { testHelpers };

const actualExportsFromSrc = { testHelpers: testHelpersFromSrc };

const ensureErrorWhenMissingExport = testHelperMethod => {
// missing export in the expected
const actualWithAll = { utility: { foo: {}, bar: {} } };
const expectedMissing = { utility: { bar: {} } };

expect(() => {
testHelperMethod(actualWithAll, expectedMissing, 'testing');
}).toThrowError(
"Missing value 'foo' in the expected export for 'testing/utility'.",
);

// missing export in the actual
const actualMissing = { utility: { foo: {} } };
const expectedWithAll = { utility: { bar: {}, foo: {} } };

expect(() => {
testHelperMethod(actualMissing, expectedWithAll, 'testing');
}).toThrowError(
"Missing value 'bar' in the actual export for 'testing/utility'.",
);
};

const ensureErrorWhenMissingFileDefinition = testHelperMethod => {
// missing export in the expected
const actualWithAll = {
utilityOne: { key: {} },
utilityTwo: { key: {} },
};
const expectedMissing = {
utilityOne: { key: {} },
};

expect(() => {
testHelperMethod(actualWithAll, expectedMissing, 'testing');
}).toThrowError(
"Missing value 'utilityTwo' in the expected utilities for 'testing'.",
);

// missing export in the actual
const actualMissing = {
utilityOne: { key: {} },
};
const expectedWithAll = {
utilityOne: { key: {} },
utilityTwo: { key: {} },
};

expect(() => {
testHelperMethod(actualMissing, expectedWithAll, 'testing');
}).toThrowError(
"Missing value 'utilityTwo' in the actual utilities for 'testing'.",
);
};

describe('Psammead test helpers', () => {
it('should test all the utility exports exist and are the correct type', () => {
testHelpers.testUtilityPackages(
actualExports,
expectedExports,
'psammead-test-helpers',
);
});

it('should test all the utility exports exist and are the correct type when coming from src/', () => {
testHelpers.testUtilityPackages(
actualExportsFromSrc,
expectedExports,
'psammead-test-helpers',
);
});

it('should error if expectedExport is missing an export compared to the actual export', () => {
ensureErrorWhenMissingExport(testHelpers.testUtilityPackages);
});

it('should error if expectedExport is missing an export compared to the actual export when coming from /src', () => {
ensureErrorWhenMissingExport(testHelpersFromSrc.testUtilityPackages);
});

it('should error if file definition is missing in the expectation', () => {
ensureErrorWhenMissingFileDefinition(testHelpers.testUtilityPackages);
});

it('should error if file definition is missing in the expectation when coming from /src', () => {
ensureErrorWhenMissingFileDefinition(
testHelpersFromSrc.testUtilityPackages,
);
});
});
2 changes: 1 addition & 1 deletion packages/utilities/psammead-test-helpers/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/utilities/psammead-test-helpers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bbc/psammead-test-helpers",
"version": "0.2.1",
"version": "0.3.0",
"main": "dist/index.js",
"description": "A collection of helper methods for implementing Jest snapshot tests for styled-components, required by many Psammead components.",
"repository": {
Expand Down
67 changes: 67 additions & 0 deletions packages/utilities/psammead-test-helpers/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,70 @@ export const isNull = (title, component) => {
expect(tree).toBeNull();
});
};

const errorIfMissingKey = (keys, object, message) => {
keys.forEach(key => {
if (!(key in object)) {
throw new Error(`Missing value '${key}' in ${message}.`);
}
});
};

const checkKeysExistInBothObjects = (object1, object2, message1, message2) => {
const object1Keys = Object.keys(object1);
const object2Keys = Object.keys(object2);

errorIfMissingKey(object1Keys, object2, message2);
errorIfMissingKey(object2Keys, object1, message1);
};

const checkTypesOfExports = (
actualExportsByName,
actualExports,
expectedExports,
utilityName,
) => {
actualExportsByName.forEach(actualExportName => {
const actualExportValue = actualExports[utilityName][actualExportName];
const expectedExport = expectedExports[utilityName][actualExportName];
const typeCheck = typeof actualExportValue === expectedExport; // eslint-disable-line valid-typeof

// if this fails it is likely that an export is missing from the unit test expectation
expect(typeCheck).toBe(true);
});
};

export const testUtilityPackages = (
actualExports,
expectedExports,
packageName,
) => {
const actualUtilities = Object.keys(actualExports);

// check if the actual exported file has defined expected values to match and that the expected values are actually exported
checkKeysExistInBothObjects(
actualExports,
expectedExports,
`the actual utilities for '${packageName}'`,
`the expected utilities for '${packageName}'`,
);

actualUtilities.forEach(utilityName => {
const actualExportsByName = Object.keys(actualExports[utilityName]);

// check if each of the actual exported consts have an expected value to match and that the expected values are actually exported
checkKeysExistInBothObjects(
actualExports[utilityName],
expectedExports[utilityName],
`the actual export for '${packageName}/${utilityName}'`,
`the expected export for '${packageName}/${utilityName}'`,
);

checkTypesOfExports(
actualExportsByName,
actualExports,
expectedExports,
utilityName,
);
});
};

0 comments on commit b0a8c0b

Please sign in to comment.