From 1dba0a88d4240e2549691ab4fd5329e18bfd4610 Mon Sep 17 00:00:00 2001
From: Chris <chris@chrissnijder.nl>
Date: Wed, 3 Feb 2021 01:45:57 +0100
Subject: [PATCH] Finish installing jest and addons, make a tested component.

---
 jest.setup.js                           |   1 +
 package.json                            |   4 +-
 pnpm-lock.yaml                          | 165 ++++++++++++++++++++++++
 src/components/spinner/Spinner.scss     |  23 ++++
 src/components/spinner/Spinner.test.tsx |  28 ++++
 src/components/spinner/Spinner.tsx      |  21 +++
 6 files changed, 241 insertions(+), 1 deletion(-)
 create mode 100644 src/components/spinner/Spinner.scss
 create mode 100644 src/components/spinner/Spinner.test.tsx
 create mode 100644 src/components/spinner/Spinner.tsx

diff --git a/jest.setup.js b/jest.setup.js
index e69de29..cbe7c3d 100644
--- a/jest.setup.js
+++ b/jest.setup.js
@@ -0,0 +1 @@
+import "@testing-library/jest-dom/extend-expect";
\ No newline at end of file
diff --git a/package.json b/package.json
index 7fc7c00..29c6341 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
   "scripts": {
     "start": "snowpack dev",
     "build": "snowpack build",
-    "test": "jest \"src/**/*.test.tsx\" --coverage --watchAll",
+    "test": "jest src\/ --coverage --watchAll",
     "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"",
     "lint": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\""
   },
@@ -25,12 +25,14 @@
     "@snowpack/plugin-dotenv": "^2.0.5",
     "@snowpack/plugin-react-refresh": "^2.4.0",
     "@snowpack/plugin-typescript": "^1.2.0",
+    "@testing-library/jest-dom": "^5.11.9",
     "@testing-library/react": "^11.0.0",
     "@types/jest": "^26.0.20",
     "@types/react": "^17.0.0",
     "@types/react-dom": "^17.0.0",
     "@types/snowpack-env": "^2.3.2",
     "jest-cli": "^26.6.3",
+    "jest-each": "^26.6.2",
     "prettier": "^2.0.5",
     "rxjs": "^6.6.3",
     "snowpack": "^3.0.11",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0c06b1c..154297b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -5,15 +5,19 @@ devDependencies:
   '@snowpack/app-scripts-react': 2.0.0_c39e9db791ea05e3ec4e0e74abb7a6b5
   '@snowpack/plugin-dotenv': 2.0.5
   '@snowpack/plugin-react-refresh': 2.4.0_react-dom@17.0.1+react@17.0.1
+  '@snowpack/plugin-sass': 1.3.0
   '@snowpack/plugin-typescript': 1.2.1_typescript@4.1.3
+  '@testing-library/jest-dom': 5.11.9
   '@testing-library/react': 11.2.3_react-dom@17.0.1+react@17.0.1
   '@types/jest': 26.0.20
   '@types/react': 17.0.0
   '@types/react-dom': 17.0.0
   '@types/snowpack-env': 2.3.3
   jest-cli: 26.6.3
+  jest-each: 26.6.2
   prettier: 2.2.1
   rxjs: 6.6.3
+  sass: 1.32.6
   snowpack: 3.0.11
   typescript: 4.1.3
 lockfileVersion: 5.2
@@ -1533,6 +1537,14 @@ packages:
       react-dom: '>=16.9.0'
     resolution:
       integrity: sha512-qz2BzdWa5DPK7teTRrh8/SY81mWt//NZmRUUzrQZS2I9d9St8GfSAbFgeJunpBCpPXW9QaaI7huNaoTx/+1/Ag==
+  /@snowpack/plugin-sass/1.3.0:
+    dependencies:
+      execa: 5.0.0
+      npm-run-path: 4.0.1
+      sass: 1.32.6
+    dev: true
+    resolution:
+      integrity: sha512-MbUFwISnPMKc8CY0E1qbaxIHGTn0DiPhqIbyr+BBlwI3dBYJeEGzB9eEEttmOQ9WsZgoigeQcfO9IMvNkwRNFg==
   /@snowpack/plugin-typescript/1.2.1_typescript@4.1.3:
     dependencies:
       execa: 5.0.0
@@ -1558,6 +1570,23 @@ packages:
       node: '>=10'
     resolution:
       integrity: sha512-CtrJRiSYEfbtNGtEsd78mk1n1v2TUbeABlNIcOCJdDfkN5/JTOwQEbbQpoSRxGqzcWPgStMvJ4mNolSuBRv1NA==
+  /@testing-library/jest-dom/5.11.9:
+    dependencies:
+      '@babel/runtime': 7.12.5
+      '@types/testing-library__jest-dom': 5.9.5
+      aria-query: 4.2.2
+      chalk: 3.0.0
+      css: 3.0.0
+      css.escape: 1.5.1
+      lodash: 4.17.20
+      redent: 3.0.0
+    dev: true
+    engines:
+      node: '>=8'
+      npm: '>=6'
+      yarn: '>=1'
+    resolution:
+      integrity: sha512-Mn2gnA9d1wStlAIT2NU8J15LNob0YFBVjs2aEQ3j8rsfRQo+lAs7/ui1i2TGaJjapLmuNPLTsrm+nPjmZDwpcQ==
   /@testing-library/react/11.2.3_react-dom@17.0.1+react@17.0.1:
     dependencies:
       '@babel/runtime': 7.12.5
@@ -1675,6 +1704,12 @@ packages:
     dev: true
     resolution:
       integrity: sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==
+  /@types/testing-library__jest-dom/5.9.5:
+    dependencies:
+      '@types/jest': 26.0.20
+    dev: true
+    resolution:
+      integrity: sha512-ggn3ws+yRbOHog9GxnXiEZ/35Mow6YtPZpd7Z5mKDeZS/o7zx3yAle0ov/wjhVB5QT4N2Dt+GNoGCdqkBGCajQ==
   /@types/yargs-parser/20.2.0:
     dev: true
     resolution:
@@ -1979,6 +2014,12 @@ packages:
     dev: true
     resolution:
       integrity: sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
+  /binary-extensions/2.2.0:
+    dev: true
+    engines:
+      node: '>=8'
+    resolution:
+      integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
   /brace-expansion/1.1.11:
     dependencies:
       balanced-match: 1.0.0
@@ -2105,6 +2146,15 @@ packages:
       node: '>=4'
     resolution:
       integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+  /chalk/3.0.0:
+    dependencies:
+      ansi-styles: 4.3.0
+      supports-color: 7.2.0
+    dev: true
+    engines:
+      node: '>=8'
+    resolution:
+      integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
   /chalk/4.1.0:
     dependencies:
       ansi-styles: 4.3.0
@@ -2120,6 +2170,22 @@ packages:
       node: '>=10'
     resolution:
       integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
+  /chokidar/3.5.1:
+    dependencies:
+      anymatch: 3.1.1
+      braces: 3.0.2
+      glob-parent: 5.1.1
+      is-binary-path: 2.1.0
+      is-glob: 4.0.1
+      normalize-path: 3.0.0
+      readdirp: 3.5.0
+    dev: true
+    engines:
+      node: '>= 8.10.0'
+    optionalDependencies:
+      fsevents: 2.3.1
+    resolution:
+      integrity: sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==
   /ci-info/2.0.0:
     dev: true
     resolution:
@@ -2276,6 +2342,18 @@ packages:
       node: '>= 8'
     resolution:
       integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+  /css.escape/1.5.1:
+    dev: true
+    resolution:
+      integrity: sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=
+  /css/3.0.0:
+    dependencies:
+      inherits: 2.0.4
+      source-map: 0.6.1
+      source-map-resolve: 0.6.0
+    dev: true
+    resolution:
+      integrity: sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==
   /cssom/0.3.8:
     dev: true
     resolution:
@@ -2808,6 +2886,14 @@ packages:
     dev: true
     resolution:
       integrity: sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
+  /glob-parent/5.1.1:
+    dependencies:
+      is-glob: 4.0.1
+    dev: true
+    engines:
+      node: '>= 6'
+    resolution:
+      integrity: sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
   /glob/7.1.6:
     dependencies:
       fs.realpath: 1.0.0
@@ -2983,6 +3069,12 @@ packages:
       node: '>=0.8.19'
     resolution:
       integrity: sha1-khi5srkoojixPcT7a21XbyMUU+o=
+  /indent-string/4.0.0:
+    dev: true
+    engines:
+      node: '>=8'
+    resolution:
+      integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
   /inflight/1.0.6:
     dependencies:
       once: 1.4.0
@@ -3026,6 +3118,14 @@ packages:
     dev: true
     resolution:
       integrity: sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
+  /is-binary-path/2.1.0:
+    dependencies:
+      binary-extensions: 2.2.0
+    dev: true
+    engines:
+      node: '>=8'
+    resolution:
+      integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
   /is-buffer/1.1.6:
     dev: true
     resolution:
@@ -3100,6 +3200,12 @@ packages:
       node: '>=0.10.0'
     resolution:
       integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
+  /is-extglob/2.1.1:
+    dev: true
+    engines:
+      node: '>=0.10.0'
+    resolution:
+      integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
   /is-fullwidth-code-point/3.0.0:
     dev: true
     engines:
@@ -3112,6 +3218,14 @@ packages:
       node: '>=6'
     resolution:
       integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==
+  /is-glob/4.0.1:
+    dependencies:
+      is-extglob: 2.1.1
+    dev: true
+    engines:
+      node: '>=0.10.0'
+    resolution:
+      integrity: sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
   /is-number/3.0.0:
     dependencies:
       kind-of: 3.2.2
@@ -3932,6 +4046,12 @@ packages:
       node: '>=6'
     resolution:
       integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+  /min-indent/1.0.1:
+    dev: true
+    engines:
+      node: '>=4'
+    resolution:
+      integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
   /minimatch/3.0.4:
     dependencies:
       brace-expansion: 1.1.11
@@ -4403,6 +4523,23 @@ packages:
       node: '>=8'
     resolution:
       integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
+  /readdirp/3.5.0:
+    dependencies:
+      picomatch: 2.2.2
+    dev: true
+    engines:
+      node: '>=8.10.0'
+    resolution:
+      integrity: sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
+  /redent/3.0.0:
+    dependencies:
+      indent-string: 4.0.0
+      strip-indent: 3.0.0
+    dev: true
+    engines:
+      node: '>=8'
+    resolution:
+      integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
   /regenerate-unicode-properties/8.2.0:
     dependencies:
       regenerate: 1.4.2
@@ -4640,6 +4777,15 @@ packages:
     hasBin: true
     resolution:
       integrity: sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==
+  /sass/1.32.6:
+    dependencies:
+      chokidar: 3.5.1
+    dev: true
+    engines:
+      node: '>=8.9.0'
+    hasBin: true
+    resolution:
+      integrity: sha512-1bcDHDcSqeFtMr0JXI3xc/CXX6c4p0wHHivJdru8W7waM7a1WjKMm4m/Z5sY7CbVw4Whi2Chpcw6DFfSWwGLzQ==
   /saxes/5.0.1:
     dependencies:
       xmlchars: 2.2.0
@@ -4797,6 +4943,13 @@ packages:
     dev: true
     resolution:
       integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
+  /source-map-resolve/0.6.0:
+    dependencies:
+      atob: 2.1.2
+      decode-uri-component: 0.2.0
+    dev: true
+    resolution:
+      integrity: sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==
   /source-map-support/0.5.19:
     dependencies:
       buffer-from: 1.1.1
@@ -4945,6 +5098,14 @@ packages:
       node: '>=6'
     resolution:
       integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+  /strip-indent/3.0.0:
+    dependencies:
+      min-indent: 1.0.1
+    dev: true
+    engines:
+      node: '>=8'
+    resolution:
+      integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
   /supports-color/5.5.0:
     dependencies:
       has-flag: 3.0.0
@@ -5407,16 +5568,20 @@ specifiers:
   '@snowpack/app-scripts-react': ^2.0.0
   '@snowpack/plugin-dotenv': ^2.0.5
   '@snowpack/plugin-react-refresh': ^2.4.0
+  '@snowpack/plugin-sass': ^1.3.0
   '@snowpack/plugin-typescript': ^1.2.0
+  '@testing-library/jest-dom': ^5.11.9
   '@testing-library/react': ^11.0.0
   '@types/jest': ^26.0.20
   '@types/react': ^17.0.0
   '@types/react-dom': ^17.0.0
   '@types/snowpack-env': ^2.3.2
   jest-cli: ^26.6.3
+  jest-each: ^26.6.2
   prettier: ^2.0.5
   react: ^17.0.0
   react-dom: ^17.0.0
   rxjs: ^6.6.3
+  sass: ^1.32.6
   snowpack: ^3.0.11
   typescript: ^4.0.0
diff --git a/src/components/spinner/Spinner.scss b/src/components/spinner/Spinner.scss
new file mode 100644
index 0000000..72d9273
--- /dev/null
+++ b/src/components/spinner/Spinner.scss
@@ -0,0 +1,23 @@
+@import "../../styles/colors.scss";
+$spinner-size: 1.75rem;
+$spinner-size-big: 3rem;
+
+.spinner.loading {
+  border: $spinner-size/8 solid $spinner-background;
+  border-top: $spinner-size/8 solid $spinner-color;
+  width: $spinner-size;
+  height: $spinner-size;
+  &.big {
+    border: $spinner-size-big/8 solid $spinner-background;
+    border-top: $spinner-size-big/8 solid $spinner-color;
+    width: $spinner-size-big;
+    height: $spinner-size-big;
+  }
+  border-radius: 50%;
+  animation: spin .7s linear infinite;
+}
+
+@keyframes spin {
+    0% { transform: rotate(0deg); }
+    100% { transform: rotate(360deg); }
+}
diff --git a/src/components/spinner/Spinner.test.tsx b/src/components/spinner/Spinner.test.tsx
new file mode 100644
index 0000000..9cdce02
--- /dev/null
+++ b/src/components/spinner/Spinner.test.tsx
@@ -0,0 +1,28 @@
+import * as React from 'react';
+import { render } from '@testing-library/react';
+import Spinner from './Spinner';
+const each = require("jest-each").default;
+
+describe('<Spinner>', () => {
+
+    it("renders spinning loading indicator: default", () => {
+        const { getByRole } = render(<Spinner />);
+        const spinner = getByRole("progressbar");
+        expect(spinner).toBeVisible();
+        expect(spinner).not.toHaveClass("big")
+    })
+
+    const variations = [["small", false], ["big", true]];
+    each(variations).it(`renders spinning loading indicator: %s`, (big: boolean) => {
+        const { getByRole } = render(<Spinner loading={true} big={big} />);
+        const spinner = getByRole("progressbar");
+        expect(spinner).toBeVisible();
+    })
+
+    each(variations).it(`Does not render spinning loading indicator: %s`, (big: boolean) => {
+        const { queryByRole } = render(<Spinner loading={false} big={big} />);
+        const spinners = queryByRole("progressbar");
+        expect(spinners).toBe(null);
+    });
+});
+
diff --git a/src/components/spinner/Spinner.tsx b/src/components/spinner/Spinner.tsx
new file mode 100644
index 0000000..ba280b9
--- /dev/null
+++ b/src/components/spinner/Spinner.tsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import './Spinner.scss';
+
+export interface SpinnerProps {
+    big?: boolean,
+    loading?: boolean
+}
+
+function Spinner({ big = false, loading = true }: SpinnerProps) {
+    if (!loading)
+        return (<div className="spinner"></div>)
+    const classes = ["spinner", "loading"];
+    if (big)
+        classes.push("big");
+    return (
+        <div className={classes.join(" ")} role="progressbar" aria-label="Loading"></div>
+    );
+}
+
+export default Spinner;
+
-- 
GitLab