From f926c7d247f436958f363550674864ae8b3e8730 Mon Sep 17 00:00:00 2001 From: Tomek M Date: Wed, 16 Aug 2023 14:50:15 -0700 Subject: [PATCH] Fixed comparing empty strings with nulls and undefined (#77) If you pulled a template without the text part and immediately run the push command, the program would show a change to that template. It was happening because we were comparing undefined to empty strings when detecting the changes. * Fixed comparing empty strings with nulls and undefined * Split tests into unit and integration --- .mocharc.integration.json | 9 + .mocharc.unit.json | 7 + package-lock.json | 323 +++++-------------- package.json | 5 +- src/commands/templates/helpers.ts | 30 +- src/commands/templates/push.ts | 67 ++-- src/types/Template.ts | 16 +- test/unit/commands/templates/helpers.test.ts | 107 ++++++ 8 files changed, 261 insertions(+), 303 deletions(-) create mode 100644 .mocharc.integration.json create mode 100644 .mocharc.unit.json create mode 100644 test/unit/commands/templates/helpers.test.ts diff --git a/.mocharc.integration.json b/.mocharc.integration.json new file mode 100644 index 0000000..1f9f23a --- /dev/null +++ b/.mocharc.integration.json @@ -0,0 +1,9 @@ +{ + "diff": true, + "extension": ["test.ts"], + "require": "ts-node/register", + "spec": "test/integration", + "recursive": true, + "retries": 1, + "timeout": 10000 +} \ No newline at end of file diff --git a/.mocharc.unit.json b/.mocharc.unit.json new file mode 100644 index 0000000..a469b01 --- /dev/null +++ b/.mocharc.unit.json @@ -0,0 +1,7 @@ +{ + "diff": true, + "extension": ["test.ts"], + "require": "ts-node/register", + "spec": "test/unit", + "recursive": true +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7d958af..62f9e2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@types/watch": "^1.0.1", "chalk": "^2.4.2", "consolidate": "^0.15.1", + "debug": "^4.3.4", "directory-tree": "^2.2.3", "ejs": "^3.1.7", "express": "^4.17.1", @@ -76,23 +77,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@eslint/eslintrc/node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -102,12 +86,6 @@ "node": ">= 4" } }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@humanwhocodes/config-array": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", @@ -380,23 +358,6 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -409,12 +370,6 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -463,29 +418,6 @@ } } }, - "node_modules/@typescript-eslint/parser/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/scope-manager": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.10.0.tgz", @@ -529,29 +461,6 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/types": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.10.0.tgz", @@ -592,23 +501,6 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -621,12 +513,6 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -1397,12 +1283,19 @@ } }, "node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/deep-eql": { @@ -1597,6 +1490,15 @@ "node": ">= 0.6" } }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1782,23 +1684,6 @@ "node": ">= 8" } }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -1854,12 +1739,6 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/eslint/node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -3455,9 +3334,9 @@ } }, "node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/mute-stream": { "version": "0.0.8", @@ -4381,11 +4260,29 @@ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/socket.io-parser/node_modules/isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5007,26 +4904,11 @@ "strip-json-comments": "^3.1.1" }, "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true } } }, @@ -5274,15 +5156,6 @@ "tsutils": "^3.21.0" }, "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5292,12 +5165,6 @@ "yallist": "^4.0.0" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -5325,23 +5192,6 @@ "@typescript-eslint/types": "5.10.0", "@typescript-eslint/typescript-estree": "5.10.0", "debug": "^4.3.2" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@typescript-eslint/scope-manager": { @@ -5363,23 +5213,6 @@ "@typescript-eslint/utils": "5.10.0", "debug": "^4.3.2", "tsutils": "^3.21.0" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@typescript-eslint/types": { @@ -5403,15 +5236,6 @@ "tsutils": "^3.21.0" }, "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5421,12 +5245,6 @@ "yallist": "^4.0.0" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -5994,11 +5812,11 @@ } }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "deep-eql": { @@ -6112,6 +5930,14 @@ "version": "0.4.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } } } }, @@ -6263,15 +6089,6 @@ "which": "^2.0.1" } }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -6309,12 +6126,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -7517,9 +7328,9 @@ } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "mute-stream": { "version": "0.0.8", @@ -8167,6 +7978,16 @@ "socket.io-adapter": "~1.1.0", "socket.io-client": "2.5.0", "socket.io-parser": "~3.4.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } } }, "socket.io-adapter": { @@ -8237,6 +8058,14 @@ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, "isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", diff --git a/package.json b/package.json index 7f63909..2c23f37 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "@types/watch": "^1.0.1", "chalk": "^2.4.2", "consolidate": "^0.15.1", + "debug": "^4.3.4", "directory-tree": "^2.2.3", "ejs": "^3.1.7", "express": "^4.17.1", @@ -50,7 +51,9 @@ "scripts": { "start:dev": "watch 'npm run build' ./src ./preview", "build": "npm run clean && npm run ts && npm run syncPreview && npm run permissions", - "test": "npm run lint && npm run build && node_modules/mocha/bin/mocha --timeout 10000 --retries 1 -r ts-node/register test/**/*test.ts", + "test": "npm run lint && npm run build && npm run test:unit && npm run test:integration", + "test:unit": "mocha --config .mocharc.unit.json", + "test:integration": "mocha --config .mocharc.integration.json", "clean": "rm -r -f ./dist", "syncPreview": "cp -R ./preview ./dist/commands/templates/preview", "ts": "node_modules/.bin/tsc", diff --git a/src/commands/templates/helpers.ts b/src/commands/templates/helpers.ts index 5355499..e663f36 100644 --- a/src/commands/templates/helpers.ts +++ b/src/commands/templates/helpers.ts @@ -1,4 +1,5 @@ import { join, dirname } from 'path' +import { isEmpty } from 'lodash' import { readJsonSync, readFileSync, existsSync } from 'fs-extra' import traverse from 'traverse' import dirTree from 'directory-tree' @@ -38,7 +39,7 @@ export const findMetaFiles = (path: string): MetaFileTraverse[] => /** * Gathers the template's content and metadata based on the metadata file location */ -export const createManifestItem = (file: any): MetaFile | null => { +export const createManifestItem = (file: MetaFileTraverse): MetaFile | null => { const { path } = file // Path to meta file const rootPath = dirname(path) // Folder path const htmlPath = join(rootPath, 'content.html') // HTML path @@ -63,3 +64,30 @@ export const createManifestItem = (file: any): MetaFile | null => { return null } + +type TemplateDifference = 'html' | 'text' | 'subject' | 'name' | 'layout' +type TemplateDifferences = Set + +export function templatesDiff(t1: TemplateManifest, t2: TemplateManifest): TemplateDifferences { + const result: TemplateDifferences = new Set() + + if (!sameContent(t1.HtmlBody, t2.HtmlBody)) result.add('html') + if (!sameContent(t1.TextBody, t2.TextBody)) result.add('text') + if (t2.TemplateType === 'Standard' && !sameContent(t1.Subject, t2.Subject)) result.add('subject') + if (!sameContent(t1.Name, t2.Name)) result.add('name') + if (t2.TemplateType === 'Standard' && !sameContent(t1.LayoutTemplate, t2.LayoutTemplate)) result.add('layout') + + return result; +} + +export function sameContent(str1: string | null | undefined, str2: string | null | undefined): boolean { + if (isEmpty(str1) && isEmpty(str2)) { + return true + } + + if (isEmpty(str1) || isEmpty(str2)) { + return false + } + + return str1 === str2 +} diff --git a/src/commands/templates/push.ts b/src/commands/templates/push.ts index ed0dcff..8e77635 100644 --- a/src/commands/templates/push.ts +++ b/src/commands/templates/push.ts @@ -1,21 +1,23 @@ import chalk from 'chalk' import ora from 'ora' -import { find, cloneDeep } from 'lodash' +import { find } from 'lodash' import { prompt } from 'inquirer' import { table, getBorderCharacters } from 'table' import untildify from 'untildify' import { existsSync } from 'fs-extra' -import { createManifest } from './helpers' import { ServerClient } from 'postmark' +import { Templates } from 'postmark/dist/client/models' import { TemplateManifest, TemplatePushResults, TemplatePushReview, TemplatePushArguments, - Templates, ProcessTemplates, } from '../../types' import { pluralize, log, validateToken } from '../../utils' +import { createManifest, sameContent, templatesDiff } from './helpers' + +const debug = require('debug')('postmark-cli:templates:push'); let pushManifest: TemplateManifest[] = [] @@ -162,26 +164,24 @@ const processTemplates = (config: ProcessTemplates) => { /** * Gather template content from server to compare against local versions */ -const getTemplateContent = async (client: any, templateList: Templates, spinner: any) => { - let newList: any[] = cloneDeep(templateList.Templates) - let progress = 0 +async function getTemplateContent(client: ServerClient, templateList: Templates, spinner: ora.Ora): Promise { + const result: TemplateManifest[] = []; - for (const template of newList) { + for (const template of templateList.Templates) { spinner.text = `Comparing template: ${template.Alias}` - const response:TemplateManifest = await client.getTemplate(template.TemplateId) - newList[progress] = { - ...newList[progress], - HtmlBody: response.HtmlBody, - TextBody: response.TextBody, + const response = await client.getTemplate(template.TemplateId) + result.push({ + ...template, + Alias: response.Alias || undefined, + HtmlBody: response.HtmlBody || undefined, + TextBody: response.TextBody || undefined, Subject: response.Subject, TemplateType: response.TemplateType, - LayoutTemplate: response.LayoutTemplate, - } - - progress++ + LayoutTemplate: response.LayoutTemplate || undefined, + }) } - return newList + return result; } /** @@ -247,23 +247,12 @@ const wasModified = ( server: TemplateManifest, local: TemplateManifest ): boolean => { - const htmlModified = server.HtmlBody !== local.HtmlBody - const textModified = server.TextBody !== local.TextBody - const subjectModified = - local.TemplateType === 'Standard' ? server.Subject !== local.Subject : false - const nameModified = server.Name !== local.Name - const layoutModified = - local.TemplateType === 'Standard' - ? server.LayoutTemplate !== local.LayoutTemplate - : false - - return ( - htmlModified || - textModified || - subjectModified || - nameModified || - layoutModified - ) + const diff = templatesDiff(server, local) + const result = diff.size > 0 + + debug('Template %o was modified: %o. %o', local.Alias, result, diff) + + return result } /** @@ -299,14 +288,10 @@ const layoutUsedLabel = ( localLayout: string | null | undefined, serverLayout: string | null | undefined ): string => { - let label: string = localLayout ? localLayout : chalk.gray('None') - - // If layout template on server doesn't match local template - if (localLayout !== serverLayout) { - serverLayout = serverLayout ? serverLayout : 'None' + let label = localLayout || chalk.gray('None') - // Append old server layout to label - label += chalk.red(` ✘ ${serverLayout}`) + if (!sameContent(localLayout, serverLayout)) { + label += chalk.red(` ✘ ${serverLayout || 'None'}`) } return label diff --git a/src/types/Template.ts b/src/types/Template.ts index 9350cc0..74edf8a 100644 --- a/src/types/Template.ts +++ b/src/types/Template.ts @@ -1,3 +1,5 @@ +import { TemplateInList } from "postmark/dist/client/models" + export interface TemplateManifest { Name?: string Subject?: string @@ -18,19 +20,7 @@ export interface Template extends TemplateManifest { Alias: string } -export interface ListTemplate { - Active: boolean - TemplateId: number - Name: string - Alias?: string | null - TemplateType: string - LayoutTemplate: string | null -} -export interface Templates { - TotalCount: number - Templates: ListTemplate[] -} export interface TemplatePushResults { success: number @@ -47,7 +37,7 @@ export interface ProcessTemplatesOptions { client: any outputDir: string totalCount: number - templates: ListTemplate[] + templates: TemplateInList[] } export interface TemplateListOptions { diff --git a/test/unit/commands/templates/helpers.test.ts b/test/unit/commands/templates/helpers.test.ts new file mode 100644 index 0000000..071c009 --- /dev/null +++ b/test/unit/commands/templates/helpers.test.ts @@ -0,0 +1,107 @@ +import { expect } from "chai"; +import "mocha"; +import { templatesDiff } from "../../../../src/commands/templates/helpers"; +import { TemplateManifest } from "../../../../src/types"; + +function makeTemplateManifest(): TemplateManifest { + return { + TemplateType: "Standard", + HtmlBody: undefined, + TextBody: undefined, + Subject: undefined, + Name: undefined, + LayoutTemplate: undefined, + } +} + +describe("comparing templates", () => { + it("detects changes in html body", () => { + const t1: TemplateManifest = { + ...makeTemplateManifest() + }; + const t2: TemplateManifest = { + ...makeTemplateManifest(), + HtmlBody: "

hello

", + }; + + const diff = templatesDiff(t1, t2); + + expect(Array.from(diff)).to.eql(['html']); + }); + + it("detects changes in text body", () => { + const t1: TemplateManifest = { + ...makeTemplateManifest() + }; + const t2: TemplateManifest = { + ...makeTemplateManifest(), + TextBody: "hello", + }; + + const diff = templatesDiff(t1, t2); + + expect(Array.from(diff)).to.eql(['text']); + }); + + it("detects changes in subject", () => { + const t1: TemplateManifest = { + ...makeTemplateManifest() + }; + const t2: TemplateManifest = { + ...makeTemplateManifest(), + Subject: "hello", + }; + + const diff = templatesDiff(t1, t2); + + expect(Array.from(diff)).to.eql(['subject']); + }); + + it("detects changes in name", () => { + const t1: TemplateManifest = { + ...makeTemplateManifest() + }; + const t2: TemplateManifest = { + ...makeTemplateManifest(), + Name: "hello", + }; + + const diff = templatesDiff(t1, t2); + + expect(Array.from(diff)).to.eql(['name']); + }); + + it("detects changes in layout", () => { + const t1: TemplateManifest = { + ...makeTemplateManifest() + }; + const t2: TemplateManifest = { + ...makeTemplateManifest(), + LayoutTemplate: "hello", + }; + + const diff = templatesDiff(t1, t2); + + expect(Array.from(diff)).to.eql(['layout']); + }); + + context("when comparing empty strings with undefined values", () => { + it("doesn't detect changes", () => { + const t1: TemplateManifest = { + ...makeTemplateManifest() + }; + const t2: TemplateManifest = { + ...makeTemplateManifest(), + HtmlBody: "", + TextBody: "", + Subject: "", + Name: "", + LayoutTemplate: "", + }; + + const diff = templatesDiff(t1, t2); + + expect(Array.from(diff)).to.eql([]); + }); + }); +});