From 8a3471b91629378c176e29df2b2e8658f2d3c9db Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Fri, 4 Jan 2019 18:38:49 -0500 Subject: [PATCH] Adding Jest for testing --- .eslintrc.json | 9 +- .gitignore | 3 + .gitlab-ci.yml | 19 +- jest/preprocess.js | 5 + jest/setup.js | 8 + package.json | 45 +- src/__mocks__/gatsby.js | 14 + .../Footer/__snapshots__/test.js.snap | 469 ++++++ src/components/Footer/index.js | 17 +- src/components/Footer/test.js | 20 + .../Header/__snapshots__/test.js.snap | 903 +++++++++++ src/components/Header/index.js | 18 +- src/components/Header/test.js | 27 + .../Layout/__snapshots__/test.js.snap | 395 +++++ src/components/Layout/test.js | 24 + .../Message/__snapshots__/test.js.snap | 669 ++++++++ src/components/Message/test.js | 34 + .../SentryBoundary/__snapshots__/test.js.snap | 147 ++ src/components/SentryBoundary/test.js | 35 + .../SentryError/__snapshots__/test.js.snap | 149 ++ src/components/SentryError/test.js | 42 + src/pages/404.test.js | 13 + src/pages/__snapshots__/404.test.js.snap | 121 ++ src/pages/__snapshots__/index.test.js.snap | 323 ++++ src/pages/__snapshots__/privacy.test.js.snap | 643 ++++++++ src/pages/index.test.js | 13 + src/pages/privacy.test.js | 13 + yarn.lock | 1399 ++++++++++++++++- 28 files changed, 5523 insertions(+), 54 deletions(-) create mode 100644 jest/preprocess.js create mode 100644 jest/setup.js create mode 100644 src/__mocks__/gatsby.js create mode 100644 src/components/Footer/__snapshots__/test.js.snap create mode 100644 src/components/Footer/test.js create mode 100644 src/components/Header/__snapshots__/test.js.snap create mode 100644 src/components/Header/test.js create mode 100644 src/components/Layout/__snapshots__/test.js.snap create mode 100644 src/components/Layout/test.js create mode 100644 src/components/Message/__snapshots__/test.js.snap create mode 100644 src/components/Message/test.js create mode 100644 src/components/SentryBoundary/__snapshots__/test.js.snap create mode 100644 src/components/SentryBoundary/test.js create mode 100644 src/components/SentryError/__snapshots__/test.js.snap create mode 100644 src/components/SentryError/test.js create mode 100644 src/pages/404.test.js create mode 100644 src/pages/__snapshots__/404.test.js.snap create mode 100644 src/pages/__snapshots__/index.test.js.snap create mode 100644 src/pages/__snapshots__/privacy.test.js.snap create mode 100644 src/pages/index.test.js create mode 100644 src/pages/privacy.test.js diff --git a/.eslintrc.json b/.eslintrc.json index 6d950a3..6a8dfc6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,11 +2,13 @@ "env": { "browser": true, "es6": true, - "node": true + "node": true, + "jest/globals": true }, "extends": [ "eslint:recommended", - "plugin:react/recommended" + "plugin:react/recommended", + "plugin:jest/recommended" ], "parser": "babel-eslint", "parserOptions": { @@ -17,7 +19,8 @@ "sourceType": "module" }, "plugins": [ - "react" + "react", + "jest" ], "rules": { "indent": [ diff --git a/.gitignore b/.gitignore index 3215e2a..993373b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ node_modules/ # Gatsby build files .cache/ public/ + +# Test coverage +coverage/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6ea4817..0c7bcba 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,18 +11,27 @@ cache: before_script: - yarn install -lint: +test-lint: stage: test script: - yarn test:lint +test-unit: + stage: test + coverage: '/^Statements\s*:\s*([^%]+)/' + script: + - yarn test:unit + artifacts: + paths: + - coverage/ + pages: stage: build script: - - yarn build - - gzip -k -6 $(find public/ -type f) + - yarn build + - gzip -k -6 $(find public/ -type f) artifacts: paths: - - public + - public only: - - master + - master diff --git a/jest/preprocess.js b/jest/preprocess.js new file mode 100644 index 0000000..b44d90e --- /dev/null +++ b/jest/preprocess.js @@ -0,0 +1,5 @@ +const babelOptions = { + presets: ['babel-preset-gatsby'] +}; + +module.exports = require('babel-jest').createTransformer(babelOptions); diff --git a/jest/setup.js b/jest/setup.js new file mode 100644 index 0000000..ea1c273 --- /dev/null +++ b/jest/setup.js @@ -0,0 +1,8 @@ +import Enzyme from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; + +Enzyme.configure({ adapter: new Adapter() }); + +global.___loader = { + enqueue: jest.fn() +}; diff --git a/package.json b/package.json index 7264d0f..f4bc970 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "scripts": { "start": "gatsby develop", "build": "gatsby build", - "test:lint": "eslint --ignore-path .gitignore ." + "test:lint": "eslint --ignore-path .gitignore .", + "test:unit": "jest --coverage", + "test:watch": "jest --watch" }, "browserslist": [ ">1%", @@ -28,14 +30,55 @@ } } }, + "jest": { + "clearMocks": true, + "collectCoverageFrom": [ + "src/**/*.js" + ], + "coverageReporters": [ + "text-summary", + "html" + ], + "globals": { + "__PATH_PREFIX__": "" + }, + "moduleNameMapper": { + "\\.css$": "identity-obj-proxy" + }, + "modulePaths": [ + "src", + "node_modules" + ], + "setupTestFrameworkScriptFile": "/jest/setup.js", + "testPathIgnorePatterns": [ + "node_modules", + ".cache" + ], + "transform": { + "\\.js$": "/jest/preprocess.js" + }, + "transformIgnorePatterns": [ + "node_modules/(?!(gatsby)/)" + ] + }, "dependencies": { + "@babel/core": "^7.2.2", + "babel-core": "^7.0.0-bridge.0", + "babel-jest": "^23.6.0", + "babel-preset-gatsby": "^0.1.6", + "enzyme": "^3.8.0", + "enzyme-adapter-react-16": "^1.7.1", + "enzyme-to-json": "^3.3.5", "eslint": "^5.11.1", + "eslint-plugin-jest": "^22.1.2", "eslint-plugin-react": "^7.12.1", "gatsby": "^2.0.81", "gatsby-plugin-google-analytics": "^2.0.8", "gatsby-plugin-postcss": "^2.0.2", "gatsby-plugin-react-helmet": "^3.0.5", "gatsby-plugin-sentry": "^1.0.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^23.6.0", "postcss-cssnext": "^3.1.0", "postcss-import": "^12.0.1", "prop-types": "^15.6.2", diff --git a/src/__mocks__/gatsby.js b/src/__mocks__/gatsby.js new file mode 100644 index 0000000..07c3c71 --- /dev/null +++ b/src/__mocks__/gatsby.js @@ -0,0 +1,14 @@ +const React = require('react'); +const gatsby = jest.requireActual('gatsby'); + +module.exports = { + ...gatsby, + graphql: jest.fn().mockImplementation(([query]) => query), + Link: jest.fn().mockImplementation(({ to, ...rest }) => + React.createElement('a', { + ...rest, + href: to + }) + ), + StaticQuery: jest.fn() +}; diff --git a/src/components/Footer/__snapshots__/test.js.snap b/src/components/Footer/__snapshots__/test.js.snap new file mode 100644 index 0000000..e2567a4 --- /dev/null +++ b/src/components/Footer/__snapshots__/test.js.snap @@ -0,0 +1,469 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Footer rendering implementation 1`] = ` +ShallowWrapper { + Symbol(enzyme.__root__): [Circular], + Symbol(enzyme.__unrendered__): , + Symbol(enzyme.__renderer__): Object { + "batchedUpdates": [Function], + "getNode": [Function], + "render": [Function], + "simulateError": [Function], + "simulateEvent": [Function], + "unmount": [Function], + }, + Symbol(enzyme.__node__): Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + , +
+ abc-123 +
, + ], + "className": "footer", + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ +
  • + Created by + + Jeff Avallone + +
  • , +
  • + Generated images licensed: + + Creative Commons CC-BY-3.0 License + +
  • , + ], + "className": "list", + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + "Created by ", + + Jeff Avallone + , + ], + }, + "ref": null, + "rendered": Array [ + "Created by ", + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": "Jeff Avallone", + "href": "mailto:jeff.avallone@gmail.com", + }, + "ref": null, + "rendered": "Jeff Avallone", + "type": "a", + }, + ], + "type": "li", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + "Generated images licensed: ", + + Creative Commons CC-BY-3.0 License + , + ], + }, + "ref": null, + "rendered": Array [ + "Generated images licensed: ", + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Creative Commons CC-BY-3.0 License, + "href": "http://creativecommons.org/licenses/by/3.0/", + "rel": "license external noopener noreferrer", + "target": "_blank", + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "alt": "Creative Commons CC-BY-3.0 License", + "src": "https://licensebuttons.net/l/by/3.0/80x15.png", + }, + "ref": null, + "rendered": null, + "type": "img", + }, + "type": "a", + }, + ], + "type": "li", + }, + ], + "type": "ul", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": "abc-123", + "className": "buildId", + }, + "ref": null, + "rendered": "abc-123", + "type": "div", + }, + ], + "type": "footer", + }, + Symbol(enzyme.__nodes__): Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + , +
    + abc-123 +
    , + ], + "className": "footer", + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ +
  • + Created by + + Jeff Avallone + +
  • , +
  • + Generated images licensed: + + Creative Commons CC-BY-3.0 License + +
  • , + ], + "className": "list", + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + "Created by ", + + Jeff Avallone + , + ], + }, + "ref": null, + "rendered": Array [ + "Created by ", + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": "Jeff Avallone", + "href": "mailto:jeff.avallone@gmail.com", + }, + "ref": null, + "rendered": "Jeff Avallone", + "type": "a", + }, + ], + "type": "li", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + "Generated images licensed: ", + + Creative Commons CC-BY-3.0 License + , + ], + }, + "ref": null, + "rendered": Array [ + "Generated images licensed: ", + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Creative Commons CC-BY-3.0 License, + "href": "http://creativecommons.org/licenses/by/3.0/", + "rel": "license external noopener noreferrer", + "target": "_blank", + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "alt": "Creative Commons CC-BY-3.0 License", + "src": "https://licensebuttons.net/l/by/3.0/80x15.png", + }, + "ref": null, + "rendered": null, + "type": "img", + }, + "type": "a", + }, + ], + "type": "li", + }, + ], + "type": "ul", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": "abc-123", + "className": "buildId", + }, + "ref": null, + "rendered": "abc-123", + "type": "div", + }, + ], + "type": "footer", + }, + ], + Symbol(enzyme.__options__): Object { + "adapter": ReactSixteenAdapter { + "options": Object { + "enableComponentDidUpdateOnSetState": true, + "lifecycles": Object { + "componentDidUpdate": Object { + "onSetState": true, + }, + "getDerivedStateFromProps": true, + "getSnapshotBeforeUpdate": true, + "setState": Object { + "skipsComponentDidUpdateOnNullish": true, + }, + }, + }, + }, + }, +} +`; + +exports[`Footer rendering with query 1`] = ` +ShallowWrapper { + Symbol(enzyme.__root__): [Circular], + Symbol(enzyme.__unrendered__):