From 517d727352c24c72c8f06802370af993c8ccd6dd Mon Sep 17 00:00:00 2001 From: Matt Gerega Date: Thu, 24 Aug 2023 15:42:33 -0400 Subject: [PATCH 1/6] Adding new tests --- src/types/config.test.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/types/config.test.ts diff --git a/src/types/config.test.ts b/src/types/config.test.ts new file mode 100644 index 0000000..344cd2f --- /dev/null +++ b/src/types/config.test.ts @@ -0,0 +1,35 @@ +import { isDataConfig } from "./config"; + +describe("Functions in config", function () { + describe("isDataConfig", function () { + it(`should return true for a DataConfig object`, function () { + const configTest = { + pageId: "", + componentsToIgnore: ["test", "test2"], + updateInterval: 1000 + }; + + const isConfig = isDataConfig(configTest); + + expect(isConfig).toBeTruthy(); + }); + + it(`should return false for an object that is not a DataConfig`, function () { + const configTest = { + page2: "", + componentsToIgnore: ["test", "test2"], + updateIntervalf: 1000 + }; + + const isConfig = isDataConfig(configTest); + + expect(isConfig).not.toBeTruthy(); + }); + + it(`should return false for something that isn't an object`, function () { + const isConfig = isDataConfig(undefined); + + expect(isConfig).not.toBeTruthy(); + }); + }); +}); From 247491444ee1358d4c42d543f4763fc9d8935495 Mon Sep 17 00:00:00 2001 From: Matt Gerega Date: Thu, 24 Aug 2023 17:07:07 -0400 Subject: [PATCH 2/6] adding more unit test for display values --- package-lock.json | 646 ++++++++++++++++++++++++++++++++++- package.json | 3 + src/frontend/display.test.ts | 124 +++++++ src/frontend/display.ts | 38 +-- src/frontend/testobjects.ts | 216 ++++++++++++ src/types/display.ts | 3 +- 6 files changed, 1006 insertions(+), 24 deletions(-) create mode 100644 src/frontend/display.test.ts create mode 100644 src/frontend/testobjects.ts diff --git a/package-lock.json b/package-lock.json index 130ee93..fb898c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,8 @@ "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-typescript": "^11.1.2", + "@testing-library/dom": "^9.3.1", + "@testing-library/jest-dom": "^6.1.2", "@types/jest": "^29.5.4", "@types/magicmirror-module": "^2.16.2", "@types/node-fetch": "^2.6.4", @@ -32,6 +34,7 @@ "eslint-plugin-import": "^2.28.1", "eslint-plugin-sonarjs": "^0.21.0", "husky": "^8.0.3", + "identity-obj-proxy": "^3.0.0", "jest": "^29.6.3", "jest-environment-jsdom": "^29.6.3", "jest-junit": "^16.0.0", @@ -39,7 +42,6 @@ "rollup": "^3.28.1", "rollup-plugin-scss": "^4.0.0", "sass": "^1.66.1", - "tslib": "^2.6.2", "typescript": "^5.1.6" } }, @@ -52,6 +54,12 @@ "node": ">=0.10.0" } }, + "node_modules/@adobe/css-tools": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz", + "integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==", + "dev": true + }, "node_modules/@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -2722,6 +2730,111 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@testing-library/dom": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", + "integrity": "sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.1.2.tgz", + "integrity": "sha512-NP9jl1Q2qDDtx+cqogowtQtmgD2OVs37iMSIsTv5eN5ETRkf26Kj6ugVwA93/gZzzFWQAsgkKkcftDe91BJCkQ==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.3.0", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@jest/globals": ">= 28", + "@types/jest": ">= 28", + "jest": ">= 28", + "vitest": ">= 0.32" + }, + "peerDependenciesMeta": { + "@jest/globals": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "jest": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -2731,6 +2844,12 @@ "node": ">= 10" } }, + "node_modules/@types/aria-query": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "dev": true + }, "node_modules/@types/babel__core": { "version": "7.20.1", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", @@ -3337,6 +3456,15 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", @@ -3984,6 +4112,12 @@ "node": ">= 8" } }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -4074,6 +4208,35 @@ } } }, + "node_modules/deep-equal": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", + "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.1", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4156,6 +4319,12 @@ "node": ">=6.0.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, "node_modules/domexception": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", @@ -4279,6 +4448,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-set-tostringtag": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", @@ -5245,6 +5434,12 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", + "dev": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -5407,6 +5602,18 @@ "node": ">=0.10.0" } }, + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "dev": true, + "dependencies": { + "harmony-reflect": "^1.4.6" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -5466,6 +5673,15 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5496,6 +5712,22 @@ "node": ">= 0.4" } }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-array-buffer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", @@ -5649,6 +5881,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -5731,6 +5972,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -5800,6 +6050,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -5812,6 +6071,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -6692,6 +6964,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -6713,6 +6991,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", @@ -6840,6 +7127,15 @@ "node": ">=6" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -6933,6 +7229,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -7399,6 +7711,19 @@ "node": ">=8.10.0" } }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -7841,6 +8166,18 @@ "node": ">=8" } }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -7943,6 +8280,18 @@ "node": ">=6" } }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -8117,7 +8466,9 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/type-check": { "version": "0.4.0", @@ -8461,6 +8812,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/which-typed-array": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", @@ -8620,6 +8986,12 @@ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true }, + "@adobe/css-tools": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz", + "integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==", + "dev": true + }, "@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -10529,12 +10901,87 @@ "@sinonjs/commons": "^3.0.0" } }, + "@testing-library/dom": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", + "integrity": "sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + } + } + }, + "@testing-library/jest-dom": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.1.2.tgz", + "integrity": "sha512-NP9jl1Q2qDDtx+cqogowtQtmgD2OVs37iMSIsTv5eN5ETRkf26Kj6ugVwA93/gZzzFWQAsgkKkcftDe91BJCkQ==", + "dev": true, + "requires": { + "@adobe/css-tools": "^4.3.0", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, "@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true }, + "@types/aria-query": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "dev": true + }, "@types/babel__core": { "version": "7.20.1", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", @@ -10991,6 +11438,15 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "requires": { + "deep-equal": "^2.0.5" + } + }, "array-buffer-byte-length": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", @@ -11454,6 +11910,12 @@ "which": "^2.0.1" } }, + "css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, "cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -11518,6 +11980,32 @@ "dev": true, "requires": {} }, + "deep-equal": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", + "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.1", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + } + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -11576,6 +12064,12 @@ "esutils": "^2.0.2" } }, + "dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, "domexception": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", @@ -11675,6 +12169,23 @@ "which-typed-array": "^1.1.10" } }, + "es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + } + }, "es-set-tostringtag": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", @@ -12370,6 +12881,12 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -12478,6 +12995,15 @@ "safer-buffer": ">= 2.1.2 < 3.0.0" } }, + "identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "dev": true, + "requires": { + "harmony-reflect": "^1.4.6" + } + }, "ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -12516,6 +13042,12 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -12543,6 +13075,16 @@ "side-channel": "^1.0.4" } }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "is-array-buffer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", @@ -12648,6 +13190,12 @@ "is-extglob": "^2.1.1" } }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true + }, "is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -12706,6 +13254,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true + }, "is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -12748,6 +13302,12 @@ "which-typed-array": "^1.1.11" } }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true + }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -12757,6 +13317,16 @@ "call-bind": "^1.0.2" } }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -13430,6 +14000,12 @@ "p-locate": "^5.0.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -13451,6 +14027,12 @@ "yallist": "^3.0.2" } }, + "lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true + }, "magic-string": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", @@ -13547,6 +14129,12 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -13619,6 +14207,16 @@ "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "dev": true }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -13939,6 +14537,16 @@ "picomatch": "^2.2.1" } }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -14271,6 +14879,15 @@ } } }, + "stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "requires": { + "internal-slot": "^1.0.4" + } + }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -14346,6 +14963,15 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -14478,7 +15104,9 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "type-check": { "version": "0.4.0", @@ -14717,6 +15345,18 @@ "is-symbol": "^1.0.3" } }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, "which-typed-array": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", diff --git a/package.json b/package.json index aca2e83..417901f 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,8 @@ "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-typescript": "^11.1.2", + "@testing-library/dom": "^9.3.1", + "@testing-library/jest-dom": "^6.1.2", "@types/jest": "^29.5.4", "@types/magicmirror-module": "^2.16.2", "@types/node-fetch": "^2.6.4", @@ -52,6 +54,7 @@ "eslint-plugin-import": "^2.28.1", "eslint-plugin-sonarjs": "^0.21.0", "husky": "^8.0.3", + "identity-obj-proxy": "^3.0.0", "jest": "^29.6.3", "jest-environment-jsdom": "^29.6.3", "jest-junit": "^16.0.0", diff --git a/src/frontend/display.test.ts b/src/frontend/display.test.ts new file mode 100644 index 0000000..f62f9d8 --- /dev/null +++ b/src/frontend/display.test.ts @@ -0,0 +1,124 @@ +import { AppearanceConfig } from "../types/config"; +import * as Display from "../types/display"; +import { getImpactIcon, getLoadingView, getComponentStatusIcon } from "./display"; +import { getByText } from "@testing-library/dom"; +import "@testing-library/jest-dom"; +//import * as TestObjects from "./testobjects"; + +const displayWithHeader: AppearanceConfig = { + useHeader: true, + headerText: "Test Header", + showComponents: true +}; + +const displayWithoutHeader: AppearanceConfig = { + useHeader: false, + showComponents: true +}; + +describe("Functions in display", function () { + describe("getLoadingView", function () { + it(`should return the loading view with custom header`, function () { + const container = getLoadingView(displayWithHeader); + + const title = getByText(container, displayWithHeader.headerText ?? ""); + expect(title).toHaveClass("wrapper"); + }); + + it(`should return the loading view without custom header`, function () { + const container = getLoadingView(displayWithoutHeader); + const title = getByText(container, "Status Page"); + expect(title).toHaveClass("wrapper"); + }); + }); + + describe("getImpactIcon", function () { + it(`should return minor image`, function () { + const img = getImpactIcon(Display.Impact.MINOR); + expect(img).toHaveClass("fa", "fa-fw", "fa-exclamation-triangle", "impact-minor"); + }); + + it(`should return major image`, function () { + const img = getImpactIcon(Display.Impact.MAJOR); + expect(img).toHaveClass("fa", "fa-fw", "fa-exclamation-circle", "impact-major"); + }); + + it(`should return critical image`, function () { + const img = getImpactIcon(Display.Impact.CRITICAL); + expect(img).toHaveClass("fa", "fa-fw", "fa-times-circle", "impact-critical"); + }); + + it(`should return maintenance image`, function () { + const img = getImpactIcon(Display.Impact.MAINTENANCE); + expect(img).toHaveClass("fa", "fa-fw", "fa-screwdriver-wrench", "impact-maintenance"); + }); + + it(`should return operational image`, function () { + const img = getImpactIcon(Display.Impact.NONE); + expect(img).toHaveClass("fa", "fa-fw", "fa-check-circle", "impact-none"); + }); + }); + + describe("getComponentStatusIcon", function () { + it(`should return degraded image`, function () { + const img = getComponentStatusIcon(Display.ComponentStatus.DEGRADED); + expect(img).toHaveClass("fa", "fa-fw", "fa-times-circle", "comp-status-degraded_performance"); + }); + + it(`should return maintenance image`, function () { + const img = getComponentStatusIcon(Display.ComponentStatus.MAINTENANCE); + expect(img).toHaveClass("fa", "fa-fw", "fa-screwdriver-wrench", "comp-status-under_maintenance"); + }); + + it(`should return major outage image`, function () { + const img = getComponentStatusIcon(Display.ComponentStatus.MAJOR_OUTAGE); + expect(img).toHaveClass("fa", "fa-fw", "fa-exclamation-circle", "comp-status-major_outage"); + }); + + it(`should return partial outage image`, function () { + const img = getComponentStatusIcon(Display.ComponentStatus.PARTIAL_OUTAGE); + expect(img).toHaveClass("fa", "fa-fw", "fa-exclamation-triangle", "comp-status-partial_outage"); + }); + + it(`should return operational image`, function () { + const img = getComponentStatusIcon(Display.ComponentStatus.OPERATIONAL); + expect(img).toHaveClass("fa", "fa-fw", "fa-check-circle", "comp-status-operational"); + }); + }); + + // describe("getIncidentStatusWithIcon", function () { + // it(`investigating should return search icon`, function () { + // const container = getIncidentStatusWithIcon(TestObjects.InvestigatingCriticalIncident); + // const img = getByText(container, TestObjects.InvestigatingCriticalIncident.status) + // expect(img).toHaveClass("fa", "fa-fw", "fa-search"); + // }); + + // it(`identified should return search location icon`, function () { + // const container = getIncidentStatusWithIcon(TestObjects.IdentifiedCriticalIncident); + // const img = getByText(container, TestObjects.IdentifiedCriticalIncident.status) + // expect(img).toHaveClass("fa", "fa-fw", "fa-search-location"); + // }); + + // it(`monitoring should return watchman monitoring icon`, function () { + // const container = getIncidentStatusWithIcon(TestObjects.MonitoringCriticalIncident); + // const img = getByText(container, TestObjects.MonitoringCriticalIncident.status) + // expect(img).toHaveClass("fa", "fa-fw", "fa-watchman-monitoring"); + // }); + // it(`resolved should return check icon`, function () { + // const container = getIncidentStatusWithIcon(TestObjects.ResolvedCriticalIncident); + // const img = getByText(container, TestObjects.ResolvedCriticalIncident.status) + // expect(img).toHaveClass("fa", "fa-fw", "fa-check-square"); + // }); + // it(`postmortem should return clipboard icon`, function () { + // const container = getIncidentStatusWithIcon(TestObjects.PostmortemCriticalIncident); + // const img = getByText(container, TestObjects.PostmortemCriticalIncident.status) + // expect(img).toHaveClass("fa", "fa-fw", "fa-clipboard-check"); + // }); + // it(`scheduled should return calendar icon`, function () { + // const container = getIncidentStatusWithIcon(TestObjects.InvestigatingCriticalIncident); + // const img = getByText(container, TestObjects.InvestigatingCriticalIncident.status) + // expect(img).toHaveClass("fa", "fa-fw", "fa-calendar"); + // }); + + // }); +}); diff --git a/src/frontend/display.ts b/src/frontend/display.ts index 439e59c..5cc8698 100644 --- a/src/frontend/display.ts +++ b/src/frontend/display.ts @@ -4,7 +4,7 @@ import "./display.scss"; export const getLoadingView = (config: AppearanceConfig): HTMLElement => { const wrapper = getWrapperElement(config); - wrapper.innerHTML = "Status Page"; + wrapper.innerHTML = config.useHeader && config.headerText ? config.headerText : "Status Page"; wrapper.classList.add("bright", "light", "small"); return wrapper; }; @@ -19,7 +19,7 @@ export const getSummaryView = (summaryData: Display.SummaryData, config: Appeara const text = document.createElement("span"); text.innerHTML = config.headerText ?? summaryData.title; header.appendChild(text); - header.appendChild(getImpactIcon(summaryData.indicator, "")); + header.appendChild(getImpactIcon(summaryData.indicator)); wrapper.appendChild(header); } @@ -65,7 +65,7 @@ const getIncidentCard = (incident: Display.Incident): HTMLElement => { const impactIconLabel = document.createElement("div"); impactIconLabel.classList.add("bright", "expected_delivery_label"); impactIconLabel.innerText = incident.impact; - dateWrapper.appendChild(getImpactIcon(incident.impact, "")); + dateWrapper.appendChild(getImpactIcon(incident.impact)); dateWrapper.appendChild(impactIconLabel); @@ -98,7 +98,7 @@ const getComponentCard = (component: Display.Component): HTMLElement => { card.appendChild(dataWrapper); // Status Icon - dateWrapper.appendChild(getComponentStatusIcon(component.status, "")); + dateWrapper.appendChild(getComponentStatusIcon(component.status)); const title = document.createElement("div"); title.classList.add("small", "bright", "no-wrap", "title"); @@ -128,39 +128,42 @@ const getComponentCard = (component: Display.Component): HTMLElement => { return card; }; -const getIncidentStatusWithIcon = (incident: Display.Incident) => { +export const getIncidentStatusWithIcon = (incident: Display.Incident) => { const statusDiv = document.createElement("div"); statusDiv.classList.add("xsmall", "no-wrap", "dimmed"); const icon = document.createElement("i"); let iconName = ""; switch (incident.status) { - case "investigating": + case Display.IncidentStatus.INVESTIGATING: iconName = "search"; break; - case "identified": + case Display.IncidentStatus.IDENTIFIED: iconName = "search-location"; break; - case "monitoring": + case Display.IncidentStatus.MONITORING: iconName = "watchman-monitoring"; break; - case "resolved": + case Display.IncidentStatus.RESOLVED: iconName = "check-square"; break; - case "postmortem": + case Display.IncidentStatus.POSTMORTEM: iconName = "clipboard-check"; break; + case Display.IncidentStatus.SCHEDULED: + iconName = "calendar"; + break; } icon.classList.add("fa", "fa-fw", `fa-${iconName}`); statusDiv.appendChild(icon); const span = document.createElement("span"); - span.innerText = incident.status; + span.innerText = `${incident.status.toString()}`; statusDiv.appendChild(span); return statusDiv; }; -const getComponentStatusIcon = (status: Display.ComponentStatus, iconCss?: string): HTMLElement => { +export const getComponentStatusIcon = (status: Display.ComponentStatus): HTMLElement => { let faIconName = ""; switch (status) { case Display.ComponentStatus.MAINTENANCE: @@ -182,13 +185,10 @@ const getComponentStatusIcon = (status: Display.ComponentStatus, iconCss?: strin } const icon = document.createElement("i"); icon.classList.add("fa", "fa-fw", "fa-" + faIconName, "comp-status-" + status); - if (iconCss && iconCss !== "") { - icon.classList.add(iconCss); - } return icon; }; -const getImpactIcon = (indicator: Display.Impact, iconCss: string): HTMLElement => { +export const getImpactIcon = (indicator: Display.Impact): HTMLElement => { let faIconName = ""; switch (indicator) { case Display.Impact.MAINTENANCE: @@ -207,10 +207,8 @@ const getImpactIcon = (indicator: Display.Impact, iconCss: string): HTMLElement faIconName = "check-circle"; break; } - const icon = document.createElement("i"); + const icon = document.createElement("i", {}); + icon.setAttribute("role", "img"); icon.classList.add("fa", "fa-fw", "fa-" + faIconName, "impact-" + indicator); - if (iconCss && iconCss !== "") { - icon.classList.add(iconCss); - } return icon; }; diff --git a/src/frontend/testobjects.ts b/src/frontend/testobjects.ts new file mode 100644 index 0000000..54b72c2 --- /dev/null +++ b/src/frontend/testobjects.ts @@ -0,0 +1,216 @@ +import * as Display from "../types/display"; + +const baseProps = { + componentId: "test", + started: "1h ago" +}; + +export const InvestigatingCriticalIncident: Display.Incident = { + name: "Investigating Critical Incident", + status: Display.IncidentStatus.INVESTIGATING, + impact: Display.Impact.CRITICAL, + ...baseProps +}; + +export const InvestigatingMajorIncident: Display.Incident = { + name: "Investigating Major Incident", + status: Display.IncidentStatus.INVESTIGATING, + impact: Display.Impact.MAJOR, + ...baseProps +}; + +export const InvestigatingMinorIncident: Display.Incident = { + name: "Investigating Minor Incident", + status: Display.IncidentStatus.INVESTIGATING, + impact: Display.Impact.MINOR, + ...baseProps +}; + +export const InvestigatingMaintenanceIncident: Display.Incident = { + name: "Investigating Maintenance Incident", + status: Display.IncidentStatus.INVESTIGATING, + impact: Display.Impact.MAINTENANCE, + ...baseProps +}; + +export const InvestigatingIncident: Display.Incident = { + name: "Investigating Incident", + status: Display.IncidentStatus.INVESTIGATING, + impact: Display.Impact.NONE, + ...baseProps +}; + +export const IdentifiedCriticalIncident: Display.Incident = { + name: "Identified Critical Incident", + status: Display.IncidentStatus.IDENTIFIED, + impact: Display.Impact.CRITICAL, + ...baseProps +}; + +export const IdentifiedMajorIncident: Display.Incident = { + name: "Identified Major Incident", + status: Display.IncidentStatus.IDENTIFIED, + impact: Display.Impact.MAJOR, + ...baseProps +}; + +export const IdentifiedMinorIncident: Display.Incident = { + name: "Identified Minor Incident", + status: Display.IncidentStatus.IDENTIFIED, + impact: Display.Impact.MINOR, + ...baseProps +}; + +export const IdentifiedMaintenanceIncident: Display.Incident = { + name: "Identified Maintenance Incident", + status: Display.IncidentStatus.IDENTIFIED, + impact: Display.Impact.MAINTENANCE, + ...baseProps +}; + +export const IdentifiedIncident: Display.Incident = { + name: "Identified Incident", + status: Display.IncidentStatus.IDENTIFIED, + impact: Display.Impact.NONE, + ...baseProps +}; + +export const MonitoringCriticalIncident: Display.Incident = { + name: "Monitoring Critical Incident", + status: Display.IncidentStatus.MONITORING, + impact: Display.Impact.CRITICAL, + ...baseProps +}; + +export const MonitoringMajorIncident: Display.Incident = { + name: "Monitoring Major Incident", + status: Display.IncidentStatus.MONITORING, + impact: Display.Impact.MAJOR, + ...baseProps +}; + +export const MonitoringMinorIncident: Display.Incident = { + name: "Monitoring Minor Incident", + status: Display.IncidentStatus.MONITORING, + impact: Display.Impact.MINOR, + ...baseProps +}; + +export const MonitoringMaintenanceIncident: Display.Incident = { + name: "Monitoring Maintenance Incident", + status: Display.IncidentStatus.MONITORING, + impact: Display.Impact.MAINTENANCE, + ...baseProps +}; + +export const MonitoringIncident: Display.Incident = { + name: "Monitoring Incident", + status: Display.IncidentStatus.MONITORING, + impact: Display.Impact.NONE, + ...baseProps +}; + +export const ResolvedCriticalIncident: Display.Incident = { + name: "Resolved Critical Incident", + status: Display.IncidentStatus.RESOLVED, + impact: Display.Impact.CRITICAL, + ...baseProps +}; + +export const ResolvedMajorIncident: Display.Incident = { + name: "Resolved Major Incident", + status: Display.IncidentStatus.RESOLVED, + impact: Display.Impact.MAJOR, + ...baseProps +}; + +export const ResolvedMinorIncident: Display.Incident = { + name: "Resolved Minor Incident", + status: Display.IncidentStatus.RESOLVED, + impact: Display.Impact.MINOR, + ...baseProps +}; + +export const ResolvedMaintenanceIncident: Display.Incident = { + name: "Resolved Maintenance Incident", + status: Display.IncidentStatus.RESOLVED, + impact: Display.Impact.MAINTENANCE, + ...baseProps +}; + +export const ResolvedIncident: Display.Incident = { + name: "Resolved Incident", + status: Display.IncidentStatus.RESOLVED, + impact: Display.Impact.NONE, + ...baseProps +}; + +export const ScheduledCriticalIncident: Display.Incident = { + name: "Scheduled Critical Incident", + status: Display.IncidentStatus.SCHEDULED, + impact: Display.Impact.CRITICAL, + ...baseProps +}; + +export const ScheduledMajorIncident: Display.Incident = { + name: "Scheduled Major Incident", + status: Display.IncidentStatus.SCHEDULED, + impact: Display.Impact.MAJOR, + ...baseProps +}; + +export const ScheduledMinorIncident: Display.Incident = { + name: "Scheduled Minor Incident", + status: Display.IncidentStatus.SCHEDULED, + impact: Display.Impact.MINOR, + ...baseProps +}; + +export const ScheduledMaintenanceIncident: Display.Incident = { + name: "Scheduled Maintenance Incident", + status: Display.IncidentStatus.SCHEDULED, + impact: Display.Impact.MAINTENANCE, + ...baseProps +}; + +export const ScheduledIncident: Display.Incident = { + name: "Scheduled Incident", + status: Display.IncidentStatus.SCHEDULED, + impact: Display.Impact.NONE, + ...baseProps +}; + +export const PostmortemCriticalIncident: Display.Incident = { + name: "Postmortem Critical Incident", + status: Display.IncidentStatus.POSTMORTEM, + impact: Display.Impact.CRITICAL, + ...baseProps +}; + +export const PostmortemMajorIncident: Display.Incident = { + name: "Postmortem Major Incident", + status: Display.IncidentStatus.POSTMORTEM, + impact: Display.Impact.MAJOR, + ...baseProps +}; + +export const PostmortemMinorIncident: Display.Incident = { + name: "Postmortem Minor Incident", + status: Display.IncidentStatus.POSTMORTEM, + impact: Display.Impact.MINOR, + ...baseProps +}; + +export const PostmortemMaintenanceIncident: Display.Incident = { + name: "Postmortem Maintenance Incident", + status: Display.IncidentStatus.POSTMORTEM, + impact: Display.Impact.MAINTENANCE, + ...baseProps +}; + +export const PostmortemIncident: Display.Incident = { + name: "Postmortem Incident", + status: Display.IncidentStatus.POSTMORTEM, + impact: Display.Impact.NONE, + ...baseProps +}; diff --git a/src/types/display.ts b/src/types/display.ts index fb6dede..15a1483 100644 --- a/src/types/display.ts +++ b/src/types/display.ts @@ -11,7 +11,8 @@ export enum Impact { CRITICAL = "critical", MAINTENANCE = "maintenance", MAJOR = "major", - MINOR = "minor" + MINOR = "minor", + NONE = "none" } export enum ComponentStatus { From fd690db984e500280639a547c9b982e7158c4d59 Mon Sep 17 00:00:00 2001 From: Matt Gerega Date: Thu, 24 Aug 2023 19:23:35 -0400 Subject: [PATCH 3/6] More display tests --- src/frontend/display.test.ts | 77 ++++++++++++++++++------------------ src/frontend/display.ts | 5 ++- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/frontend/display.test.ts b/src/frontend/display.test.ts index f62f9d8..f20fc42 100644 --- a/src/frontend/display.test.ts +++ b/src/frontend/display.test.ts @@ -1,9 +1,9 @@ import { AppearanceConfig } from "../types/config"; -import * as Display from "../types/display"; -import { getImpactIcon, getLoadingView, getComponentStatusIcon } from "./display"; -import { getByText } from "@testing-library/dom"; +import { getImpactIcon, getLoadingView, getComponentStatusIcon, getIncidentStatusWithIcon } from "./display"; +import { getByRole, getByText } from "@testing-library/dom"; import "@testing-library/jest-dom"; -//import * as TestObjects from "./testobjects"; +import * as TestObjects from "./testobjects"; +import * as Display from "../types/display"; const displayWithHeader: AppearanceConfig = { useHeader: true, @@ -86,39 +86,38 @@ describe("Functions in display", function () { }); }); - // describe("getIncidentStatusWithIcon", function () { - // it(`investigating should return search icon`, function () { - // const container = getIncidentStatusWithIcon(TestObjects.InvestigatingCriticalIncident); - // const img = getByText(container, TestObjects.InvestigatingCriticalIncident.status) - // expect(img).toHaveClass("fa", "fa-fw", "fa-search"); - // }); - - // it(`identified should return search location icon`, function () { - // const container = getIncidentStatusWithIcon(TestObjects.IdentifiedCriticalIncident); - // const img = getByText(container, TestObjects.IdentifiedCriticalIncident.status) - // expect(img).toHaveClass("fa", "fa-fw", "fa-search-location"); - // }); - - // it(`monitoring should return watchman monitoring icon`, function () { - // const container = getIncidentStatusWithIcon(TestObjects.MonitoringCriticalIncident); - // const img = getByText(container, TestObjects.MonitoringCriticalIncident.status) - // expect(img).toHaveClass("fa", "fa-fw", "fa-watchman-monitoring"); - // }); - // it(`resolved should return check icon`, function () { - // const container = getIncidentStatusWithIcon(TestObjects.ResolvedCriticalIncident); - // const img = getByText(container, TestObjects.ResolvedCriticalIncident.status) - // expect(img).toHaveClass("fa", "fa-fw", "fa-check-square"); - // }); - // it(`postmortem should return clipboard icon`, function () { - // const container = getIncidentStatusWithIcon(TestObjects.PostmortemCriticalIncident); - // const img = getByText(container, TestObjects.PostmortemCriticalIncident.status) - // expect(img).toHaveClass("fa", "fa-fw", "fa-clipboard-check"); - // }); - // it(`scheduled should return calendar icon`, function () { - // const container = getIncidentStatusWithIcon(TestObjects.InvestigatingCriticalIncident); - // const img = getByText(container, TestObjects.InvestigatingCriticalIncident.status) - // expect(img).toHaveClass("fa", "fa-fw", "fa-calendar"); - // }); - - // }); + describe("getIncidentStatusWithIcon", function () { + it(`investigating should return search icon`, function () { + const container = getIncidentStatusWithIcon(TestObjects.InvestigatingCriticalIncident); + const img = getByRole(container, "img"); + expect(img).toHaveClass("fa", "fa-fw", "fa-search"); + }); + + it(`identified should return search location icon`, function () { + const container = getIncidentStatusWithIcon(TestObjects.IdentifiedCriticalIncident); + const img = getByRole(container, "img"); + expect(img).toHaveClass("fa", "fa-fw", "fa-search-location"); + }); + + it(`monitoring should return watchman monitoring icon`, function () { + const container = getIncidentStatusWithIcon(TestObjects.MonitoringCriticalIncident); + const img = getByRole(container, "img"); + expect(img).toHaveClass("fa", "fa-fw", "fa-watchman-monitoring"); + }); + it(`resolved should return check icon`, function () { + const container = getIncidentStatusWithIcon(TestObjects.ResolvedCriticalIncident); + const img = getByRole(container, "img"); + expect(img).toHaveClass("fa", "fa-fw", "fa-check-square"); + }); + it(`postmortem should return clipboard icon`, function () { + const container = getIncidentStatusWithIcon(TestObjects.PostmortemCriticalIncident); + const img = getByRole(container, "img"); + expect(img).toHaveClass("fa", "fa-fw", "fa-clipboard-check"); + }); + it(`scheduled should return calendar icon`, function () { + const container = getIncidentStatusWithIcon(TestObjects.ScheduledCriticalIncident); + const img = getByRole(container, "img"); + expect(img).toHaveClass("fa", "fa-fw", "fa-calendar"); + }); + }); }); diff --git a/src/frontend/display.ts b/src/frontend/display.ts index 5cc8698..b6c8e27 100644 --- a/src/frontend/display.ts +++ b/src/frontend/display.ts @@ -85,7 +85,7 @@ const getIncidentCard = (incident: Display.Incident): HTMLElement => { return card; }; -const getComponentCard = (component: Display.Component): HTMLElement => { +export const getComponentCard = (component: Display.Component): HTMLElement => { const card = document.createElement("div"); card.classList.add("component-wrapper"); @@ -156,9 +156,10 @@ export const getIncidentStatusWithIcon = (incident: Display.Incident) => { } icon.classList.add("fa", "fa-fw", `fa-${iconName}`); + icon.setAttribute("role", "img"); statusDiv.appendChild(icon); const span = document.createElement("span"); - span.innerText = `${incident.status.toString()}`; + span.innerHTML = `${incident.status}`; statusDiv.appendChild(span); return statusDiv; }; From 3738c84aa6a335497da98a75799bf09d1b45a232 Mon Sep 17 00:00:00 2001 From: Matt Gerega Date: Thu, 24 Aug 2023 19:35:43 -0400 Subject: [PATCH 4/6] Extract mappers from service --- src/backend/statuspage-service.ts | 28 ++++------------------------ src/frontend/DtoMappers.ts | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 24 deletions(-) create mode 100644 src/frontend/DtoMappers.ts diff --git a/src/backend/statuspage-service.ts b/src/backend/statuspage-service.ts index 5712797..197e758 100644 --- a/src/backend/statuspage-service.ts +++ b/src/backend/statuspage-service.ts @@ -1,9 +1,9 @@ import fetch, { Response } from "node-fetch"; import { LogWrapper } from "../utilities/logging"; import { DataConfig } from "../types/config"; -import { formatDistanceToNow } from "date-fns"; import * as StatusPage from "../types/statuspage"; import * as Display from "../types/display"; +import { ConvertComponentToDisplay, ConvertIncidentToDisplay } from "../frontend/DtoMappers"; export class StatusPageService { pending: boolean = false; @@ -45,15 +45,8 @@ export class StatusPageService { this.logger.info("Processing data"); const incidents: Display.Incident[] = []; responseData.incidents.forEach((incident) => { - const startedAt = Date.parse(incident.started_at); if (!this.ignoreComponent(incident.components[0].id)) { - incidents.push({ - name: incident.name, - status: incident.status as Display.IncidentStatus, - impact: incident.impact as Display.Impact, - componentId: incident.components[0].id, - started: formatDistanceToNow(startedAt, {}) - }); + incidents.push(ConvertIncidentToDisplay(incident)); } }); @@ -62,22 +55,9 @@ export class StatusPageService { const components: Display.Component[] = topLevelComponents.map((topComponent) => { const childComponents = responseData.components.filter((comp) => this.inGroup(comp, topComponent.id) && !this.hasIncident(incidents, comp) && !this.ignoreComponent(comp.id)); - const childComps = childComponents.map((comp) => { - return { - id: comp.id, - name: comp.name, - description: comp.description, - status: comp.status as Display.ComponentStatus - }; - }); + const childComps = childComponents.map((comp) => ConvertComponentToDisplay(comp)); - return { - id: topComponent.id, - name: topComponent.name, - description: topComponent.description, - status: topComponent.status as Display.ComponentStatus, - children: childComps - }; + return ConvertComponentToDisplay(topComponent, childComps); }); const summaryData: Display.SummaryData = { diff --git a/src/frontend/DtoMappers.ts b/src/frontend/DtoMappers.ts new file mode 100644 index 0000000..be8a201 --- /dev/null +++ b/src/frontend/DtoMappers.ts @@ -0,0 +1,23 @@ +import * as Display from "../types/display"; +import * as StatusPage from "../types/statuspage"; +import { formatDistanceToNow } from "date-fns"; + +export const ConvertIncidentToDisplay = (incident: StatusPage.Incident): Display.Incident => { + return { + name: incident.name, + status: incident.status as Display.IncidentStatus, + impact: incident.impact as Display.Impact, + componentId: incident.components[0].id, + started: formatDistanceToNow(Date.parse(incident.started_at), {}) + }; +}; + +export const ConvertComponentToDisplay = (component: StatusPage.Component, children?: Display.Component[]): Display.Component => { + return { + id: component.id, + name: component.name, + description: component.description, + status: component.status as Display.ComponentStatus, + children: children + }; +}; From e64a8c251b34112c20ef1c61e0163a835a547c2f Mon Sep 17 00:00:00 2001 From: Matt Gerega Date: Mon, 28 Aug 2023 09:20:07 -0400 Subject: [PATCH 5/6] Renamed for consistency --- src/MMM-StatusPageIo.ts | 8 ++++---- src/{frontend => backend}/DtoMappers.ts | 4 ++-- ...spage-service.test.ts => StatusPageService.test.ts} | 6 +++--- .../{statuspage-service.ts => StatusPageService.ts} | 10 +++++----- src/frontend/{display.test.ts => Display.test.ts} | 8 ++++---- src/frontend/{display.ts => Display.ts} | 4 ++-- src/frontend/{testobjects.ts => TestObjects.ts} | 2 +- src/node_helper.ts | 10 +++++----- src/types/{config.test.ts => Config.test.ts} | 2 +- src/types/{config.ts => Config.ts} | 0 src/types/{display.ts => Display.ts} | 0 src/types/{statuspage.ts => StatusPage.ts} | 0 src/utilities/{logging.ts => LogWrapper.ts} | 0 13 files changed, 27 insertions(+), 27 deletions(-) rename src/{frontend => backend}/DtoMappers.ts (88%) rename src/backend/{statuspage-service.test.ts => StatusPageService.test.ts} (85%) rename src/backend/{statuspage-service.ts => StatusPageService.ts} (93%) rename src/frontend/{display.test.ts => Display.test.ts} (96%) rename src/frontend/{display.ts => Display.ts} (98%) rename src/frontend/{testobjects.ts => TestObjects.ts} (99%) rename src/types/{config.test.ts => Config.test.ts} (95%) rename src/types/{config.ts => Config.ts} (100%) rename src/types/{display.ts => Display.ts} (100%) rename src/types/{statuspage.ts => StatusPage.ts} (100%) rename src/utilities/{logging.ts => LogWrapper.ts} (100%) diff --git a/src/MMM-StatusPageIo.ts b/src/MMM-StatusPageIo.ts index 07cfce2..d010d54 100644 --- a/src/MMM-StatusPageIo.ts +++ b/src/MMM-StatusPageIo.ts @@ -1,8 +1,8 @@ import { ModuleNotification } from "./types/ModuleNotification"; -import { Config } from "./types/config"; -import * as Display from "./types/display"; -import { LogWrapper } from "./utilities/logging"; -import { getLoadingView, getSummaryView } from "./frontend/display"; +import { Config } from "./types/Config"; +import * as Display from "./types/Display"; +import { LogWrapper } from "./utilities/LogWrapper"; +import { getLoadingView, getSummaryView } from "./frontend/Display"; import * as Log from "logger"; Module.register("MMM-StatusPageIo", { diff --git a/src/frontend/DtoMappers.ts b/src/backend/DtoMappers.ts similarity index 88% rename from src/frontend/DtoMappers.ts rename to src/backend/DtoMappers.ts index be8a201..16d1ca4 100644 --- a/src/frontend/DtoMappers.ts +++ b/src/backend/DtoMappers.ts @@ -1,5 +1,5 @@ -import * as Display from "../types/display"; -import * as StatusPage from "../types/statuspage"; +import * as Display from "../types/Display"; +import * as StatusPage from "../types/StatusPage"; import { formatDistanceToNow } from "date-fns"; export const ConvertIncidentToDisplay = (incident: StatusPage.Incident): Display.Incident => { diff --git a/src/backend/statuspage-service.test.ts b/src/backend/StatusPageService.test.ts similarity index 85% rename from src/backend/statuspage-service.test.ts rename to src/backend/StatusPageService.test.ts index ad2127e..bbbb68c 100644 --- a/src/backend/statuspage-service.test.ts +++ b/src/backend/StatusPageService.test.ts @@ -1,8 +1,8 @@ import { Response } from "node-fetch"; -import { LogWrapper } from "../utilities/logging"; -import { StatusPageService } from "./statuspage-service"; +import { LogWrapper } from "../utilities/LogWrapper"; +import { StatusPageService } from "./StatusPageService"; -jest.mock("../utilities/logging", () => { +jest.mock("../utilities/LogWrapper", () => { return { LogWrapper: jest.fn().mockImplementation(() => { return { diff --git a/src/backend/statuspage-service.ts b/src/backend/StatusPageService.ts similarity index 93% rename from src/backend/statuspage-service.ts rename to src/backend/StatusPageService.ts index 197e758..1e69b92 100644 --- a/src/backend/statuspage-service.ts +++ b/src/backend/StatusPageService.ts @@ -1,9 +1,9 @@ import fetch, { Response } from "node-fetch"; -import { LogWrapper } from "../utilities/logging"; -import { DataConfig } from "../types/config"; -import * as StatusPage from "../types/statuspage"; -import * as Display from "../types/display"; -import { ConvertComponentToDisplay, ConvertIncidentToDisplay } from "../frontend/DtoMappers"; +import { LogWrapper } from "../utilities/LogWrapper"; +import { DataConfig } from "../types/Config"; +import * as StatusPage from "../types/StatusPage"; +import * as Display from "../types/Display"; +import { ConvertComponentToDisplay, ConvertIncidentToDisplay } from "./DtoMappers"; export class StatusPageService { pending: boolean = false; diff --git a/src/frontend/display.test.ts b/src/frontend/Display.test.ts similarity index 96% rename from src/frontend/display.test.ts rename to src/frontend/Display.test.ts index f20fc42..b9e89bd 100644 --- a/src/frontend/display.test.ts +++ b/src/frontend/Display.test.ts @@ -1,9 +1,9 @@ -import { AppearanceConfig } from "../types/config"; -import { getImpactIcon, getLoadingView, getComponentStatusIcon, getIncidentStatusWithIcon } from "./display"; +import { AppearanceConfig } from "../types/Config"; +import { getImpactIcon, getLoadingView, getComponentStatusIcon, getIncidentStatusWithIcon } from "./Display"; import { getByRole, getByText } from "@testing-library/dom"; import "@testing-library/jest-dom"; -import * as TestObjects from "./testobjects"; -import * as Display from "../types/display"; +import * as TestObjects from "./TestObjects"; +import * as Display from "../types/Display"; const displayWithHeader: AppearanceConfig = { useHeader: true, diff --git a/src/frontend/display.ts b/src/frontend/Display.ts similarity index 98% rename from src/frontend/display.ts rename to src/frontend/Display.ts index b6c8e27..f2ea766 100644 --- a/src/frontend/display.ts +++ b/src/frontend/Display.ts @@ -1,5 +1,5 @@ -import { AppearanceConfig } from "../types/config"; -import * as Display from "../types/display"; +import { AppearanceConfig } from "../types/Config"; +import * as Display from "../types/Display"; import "./display.scss"; export const getLoadingView = (config: AppearanceConfig): HTMLElement => { diff --git a/src/frontend/testobjects.ts b/src/frontend/TestObjects.ts similarity index 99% rename from src/frontend/testobjects.ts rename to src/frontend/TestObjects.ts index 54b72c2..df3555d 100644 --- a/src/frontend/testobjects.ts +++ b/src/frontend/TestObjects.ts @@ -1,4 +1,4 @@ -import * as Display from "../types/display"; +import * as Display from "../types/Display"; const baseProps = { componentId: "test", diff --git a/src/node_helper.ts b/src/node_helper.ts index 39104ea..79210ef 100644 --- a/src/node_helper.ts +++ b/src/node_helper.ts @@ -1,10 +1,10 @@ import * as Log from "logger"; import * as NodeHelper from "node_helper"; -import { LogWrapper } from "./utilities/logging"; +import { LogWrapper } from "./utilities/LogWrapper"; import { ModuleNotification } from "./types/ModuleNotification"; -import { StatusPageService } from "./backend/statuspage-service"; -import { DataConfig, isDataConfig } from "./types/config"; -import * as Display from "./types/display"; +import { StatusPageService } from "./backend/StatusPageService"; +import { DataConfig, isDataConfig } from "./types/Config"; +import * as Display from "./types/Display"; const logger = new LogWrapper("MMM-StatusPageIo", Log); @@ -12,7 +12,7 @@ module.exports = NodeHelper.create({ service: {} as StatusPageService, start: function () { - Log.info("Starting node_helper for: " + this.name); + logger.info("Starting node_helper" + this.name); }, socketNotificationReceived: function (notification, payload) { diff --git a/src/types/config.test.ts b/src/types/Config.test.ts similarity index 95% rename from src/types/config.test.ts rename to src/types/Config.test.ts index 344cd2f..d4a7754 100644 --- a/src/types/config.test.ts +++ b/src/types/Config.test.ts @@ -1,4 +1,4 @@ -import { isDataConfig } from "./config"; +import { isDataConfig } from "./Config"; describe("Functions in config", function () { describe("isDataConfig", function () { diff --git a/src/types/config.ts b/src/types/Config.ts similarity index 100% rename from src/types/config.ts rename to src/types/Config.ts diff --git a/src/types/display.ts b/src/types/Display.ts similarity index 100% rename from src/types/display.ts rename to src/types/Display.ts diff --git a/src/types/statuspage.ts b/src/types/StatusPage.ts similarity index 100% rename from src/types/statuspage.ts rename to src/types/StatusPage.ts diff --git a/src/utilities/logging.ts b/src/utilities/LogWrapper.ts similarity index 100% rename from src/utilities/logging.ts rename to src/utilities/LogWrapper.ts From dce7f35af24e0260bbb6842404c38fa4d0d478a3 Mon Sep 17 00:00:00 2001 From: Matt Gerega Date: Thu, 31 Aug 2023 07:13:10 -0400 Subject: [PATCH 6/6] Changed build pipeline --- .github/workflows/node.js.yml | 42 +++++------------------------------ 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 85fea63..489abb1 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -5,7 +5,9 @@ name: Tests on: push: - branches: [main] + # run builds on every branch, and PRs to main. + branches: + - "**" pull_request: branches: [main] @@ -19,13 +21,13 @@ jobs: steps: - name: Checkout MagicMirror repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: MichMich/MagicMirror path: MagicMirror - name: Checkout Module repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: path: MagicMirror/modules/MMM-StatusPageIo @@ -41,46 +43,14 @@ jobs: export DISPLAY=:99 npm ci - - name: Run tests - run: | - cd MagicMirror/modules/MMM-StatusPageIo - npm ci - npm run test - - scan: - runs-on: ubuntu-latest - - steps: - - name: Checkout MagicMirror repo - uses: actions/checkout@v2 - with: - repository: MichMich/MagicMirror - path: MagicMirror - - - name: Checkout Module repo - uses: actions/checkout@v2 - with: - path: MagicMirror/modules/MMM-StatusPageIo - - - name: Use Node.js 20.x - uses: actions/setup-node@v2 - with: - node-version: 20.x - - name: Install MagicMirror - run: | - cd MagicMirror - Xvfb :99 -screen 0 1024x768x16 & - export DISPLAY=:99 - npm ci - - name: Run tests run: | cd MagicMirror/modules/MMM-StatusPageIo npm install npm run test-ci - - name: SonarQube Scan uses: sonarsource/sonarcloud-github-action@master + if: ${{ matrix.node-version == '20.x' }} with: projectBaseDir: MagicMirror/modules/MMM-StatusPageIo env: