diff --git a/packages/utilities/psammead-test-helpers/CHANGELOG.md b/packages/utilities/psammead-test-helpers/CHANGELOG.md index 002bbb8a84..1a8f2cc6a4 100644 --- a/packages/utilities/psammead-test-helpers/CHANGELOG.md +++ b/packages/utilities/psammead-test-helpers/CHANGELOG.md @@ -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 | diff --git a/packages/utilities/psammead-test-helpers/README.md b/packages/utilities/psammead-test-helpers/README.md index f41ba58a09..835d722e74 100644 --- a/packages/utilities/psammead-test-helpers/README.md +++ b/packages/utilities/psammead-test-helpers/README.md @@ -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 @@ -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) diff --git a/packages/utilities/psammead-test-helpers/index.test.jsx b/packages/utilities/psammead-test-helpers/index.test.jsx new file mode 100644 index 0000000000..7e95615fd4 --- /dev/null +++ b/packages/utilities/psammead-test-helpers/index.test.jsx @@ -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, + ); + }); +}); diff --git a/packages/utilities/psammead-test-helpers/package-lock.json b/packages/utilities/psammead-test-helpers/package-lock.json index 75b611b5ee..da03f5cbca 100644 --- a/packages/utilities/psammead-test-helpers/package-lock.json +++ b/packages/utilities/psammead-test-helpers/package-lock.json @@ -1,6 +1,6 @@ { "name": "@bbc/psammead-test-helpers", - "version": "0.2.1", + "version": "0.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/utilities/psammead-test-helpers/package.json b/packages/utilities/psammead-test-helpers/package.json index eaa1dc5963..5baf1a92e2 100644 --- a/packages/utilities/psammead-test-helpers/package.json +++ b/packages/utilities/psammead-test-helpers/package.json @@ -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": { diff --git a/packages/utilities/psammead-test-helpers/src/index.js b/packages/utilities/psammead-test-helpers/src/index.js index e867f8294e..090bb077fd 100644 --- a/packages/utilities/psammead-test-helpers/src/index.js +++ b/packages/utilities/psammead-test-helpers/src/index.js @@ -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, + ); + }); +};