From 05c80f5991c7819126767c041c39455f699c7882 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Fri, 22 Mar 2019 11:28:48 +0000 Subject: [PATCH 01/22] Bump helmet from 3.15.1 to 3.16.0 in /backend Bumps [helmet](https://github.com/helmetjs/helmet) from 3.15.1 to 3.16.0. - [Release notes](https://github.com/helmetjs/helmet/releases) - [Changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md) - [Commits](https://github.com/helmetjs/helmet/compare/v3.15.1...v3.16.0) Signed-off-by: dependabot[bot] --- backend/package.json | 2 +- backend/yarn.lock | 30 ++++++++++++++++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/backend/package.json b/backend/package.json index 2833f3e18..6c6a9a495 100644 --- a/backend/package.json +++ b/backend/package.json @@ -58,7 +58,7 @@ "graphql-shield": "~5.3.1", "graphql-tag": "~2.10.1", "graphql-yoga": "~1.17.4", - "helmet": "~3.15.1", + "helmet": "~3.16.0", "jsonwebtoken": "~8.5.1", "linkifyjs": "~2.1.8", "lodash": "~4.17.11", diff --git a/backend/yarn.lock b/backend/yarn.lock index 7341dbc83..8507dac9b 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -4011,10 +4011,10 @@ helmet-csp@2.7.1: dasherize "2.0.0" platform "1.3.5" -helmet@~3.15.1: - version "3.15.1" - resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.15.1.tgz#2c80d1a59138b6f23929605afca4b1c88b3298ec" - integrity sha512-hgoNe/sjKlKNvJ3g9Gz149H14BjMMWOCmW/DTXl7IfyKGtIK37GePwZrHNfr4aPXdKVyXcTj26RgRFbPKDy9lw== +helmet@~3.16.0: + version "3.16.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.16.0.tgz#7df41a4bfe4c83d90147c1e30d70893f92a9d97c" + integrity sha512-rsTKRogc5OYGlvSHuq5QsmOsOzF6uDoMqpfh+Np8r23+QxDq+SUx90Rf8HyIKQVl7H6NswZEwfcykinbAeZ6UQ== dependencies: depd "2.0.0" dns-prefetch-control "0.1.0" @@ -4026,8 +4026,8 @@ helmet@~3.15.1: helmet-csp "2.7.1" hide-powered-by "1.0.0" hpkp "2.0.0" - hsts "2.1.0" - ienoopen "1.0.0" + hsts "2.2.0" + ienoopen "1.1.0" nocache "2.0.0" referrer-policy "1.1.0" x-xss-protection "1.1.0" @@ -4064,10 +4064,12 @@ hpkp@2.0.0: resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672" integrity sha1-EOFCJk52IVpdMMROxD3mTe5tFnI= -hsts@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.1.0.tgz#cbd6c918a2385fee1dd5680bfb2b3a194c0121cc" - integrity sha512-zXhh/DqgrTXJ7erTN6Fh5k/xjMhDGXCqdYN3wvxUvGUQvnxcFfUd8E+6vLg/nk3ss1TYMb+DhRl25fYABioTvA== +hsts@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.2.0.tgz#09119d42f7a8587035d027dda4522366fe75d964" + integrity sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ== + dependencies: + depd "2.0.0" html-encoding-sniffer@^1.0.2: version "1.0.2" @@ -4142,10 +4144,10 @@ ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== -ienoopen@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.0.0.tgz#346a428f474aac8f50cf3784ea2d0f16f62bda6b" - integrity sha1-NGpCj0dKrI9QzzeE6i0PFvYr2ms= +ienoopen@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.1.0.tgz#411e5d530c982287dbdc3bb31e7a9c9e32630974" + integrity sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ== ignore-by-default@^1.0.1: version "1.0.1" From e676a8fa1d30d585ea217d3f1e0767bccc1a844c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Fri, 22 Mar 2019 14:51:22 +0000 Subject: [PATCH 02/22] Bump @babel/core from 7.3.4 to 7.4.0 in /backend Bumps [@babel/core](https://github.com/babel/babel) from 7.3.4 to 7.4.0. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md) - [Commits](https://github.com/babel/babel/compare/v7.3.4...v7.4.0) Signed-off-by: dependabot[bot] --- backend/package.json | 2 +- backend/yarn.lock | 136 +++++++++---------------------------------- 2 files changed, 28 insertions(+), 110 deletions(-) diff --git a/backend/package.json b/backend/package.json index 2833f3e18..0f6430849 100644 --- a/backend/package.json +++ b/backend/package.json @@ -76,7 +76,7 @@ }, "devDependencies": { "@babel/cli": "~7.2.3", - "@babel/core": "~7.3.4", + "@babel/core": "~7.4.0", "@babel/node": "~7.2.2", "@babel/plugin-proposal-throw-expressions": "^7.2.0", "@babel/preset-env": "~7.4.2", diff --git a/backend/yarn.lock b/backend/yarn.lock index 7341dbc83..cd2efc741 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -38,18 +38,18 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/core@^7.1.0": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.3.tgz#d090d157b7c5060d05a05acaebc048bd2b037947" - integrity sha512-w445QGI2qd0E0GlSnq6huRZWPMmQGCp5gd5ZWS4hagn0EiwzxD5QMFkpchyusAyVC1n27OKXzQ0/88aVU9n4xQ== +"@babel/core@^7.1.0", "@babel/core@~7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.0.tgz#248fd6874b7d755010bfe61f557461d4f446d9e9" + integrity sha512-Dzl7U0/T69DFOTwqz/FJdnOSWS57NpjNfCwMKHABr589Lg8uX1RrlBIJ7L5Dubt/xkLsx0xH5EBFzlBVes1ayA== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.3.3" - "@babel/helpers" "^7.2.0" - "@babel/parser" "^7.3.3" - "@babel/template" "^7.2.2" - "@babel/traverse" "^7.2.2" - "@babel/types" "^7.3.3" + "@babel/generator" "^7.4.0" + "@babel/helpers" "^7.4.0" + "@babel/parser" "^7.4.0" + "@babel/template" "^7.4.0" + "@babel/traverse" "^7.4.0" + "@babel/types" "^7.4.0" convert-source-map "^1.1.0" debug "^4.1.0" json5 "^2.1.0" @@ -58,49 +58,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@~7.3.4": - version "7.3.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b" - integrity sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.3.4" - "@babel/helpers" "^7.2.0" - "@babel/parser" "^7.3.4" - "@babel/template" "^7.2.2" - "@babel/traverse" "^7.3.4" - "@babel/types" "^7.3.4" - convert-source-map "^1.1.0" - debug "^4.1.0" - json5 "^2.1.0" - lodash "^4.17.11" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.0.0", "@babel/generator@^7.2.2", "@babel/generator@^7.3.3": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.3.tgz#185962ade59a52e00ca2bdfcfd1d58e528d4e39e" - integrity sha512-aEADYwRRZjJyMnKN7llGIlircxTCofm3dtV5pmY6ob18MSIuipHpA2yZWkPlycwu5HJcx/pADS3zssd8eY7/6A== - dependencies: - "@babel/types" "^7.3.3" - jsesc "^2.5.1" - lodash "^4.17.11" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.3.4": - version "7.3.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e" - integrity sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg== - dependencies: - "@babel/types" "^7.3.4" - jsesc "^2.5.1" - lodash "^4.17.11" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.4.0": +"@babel/generator@^7.0.0", "@babel/generator@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.0.tgz#c230e79589ae7a729fd4631b9ded4dc220418196" integrity sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ== @@ -283,14 +241,14 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.2.0" -"@babel/helpers@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.2.0.tgz#8335f3140f3144270dc63c4732a4f8b0a50b7a21" - integrity sha512-Fr07N+ea0dMcMN8nFpuK6dUIT7/ivt9yKQdEEnjVS83tG2pHwPi03gYmk/tyuwONnZ+sY+GFFPlWGgCtW1hF9A== +"@babel/helpers@^7.4.0": + version "7.4.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.2.tgz#3bdfa46a552ca77ef5a0f8551be5f0845ae989be" + integrity sha512-gQR1eQeroDzFBikhrCccm5Gs2xBjZ57DNjGbqTaHo911IpmSxflOQWMAHPw/TXk8L3isv7s9lYzUkexOeTQUYg== dependencies: - "@babel/template" "^7.1.2" - "@babel/traverse" "^7.1.5" - "@babel/types" "^7.2.0" + "@babel/template" "^7.4.0" + "@babel/traverse" "^7.4.0" + "@babel/types" "^7.4.0" "@babel/highlight@^7.0.0": version "7.0.0" @@ -312,17 +270,7 @@ lodash "^4.17.10" v8flags "^3.1.1" -"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3", "@babel/parser@^7.3.3": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.3.tgz#092d450db02bdb6ccb1ca8ffd47d8774a91aef87" - integrity sha512-xsH1CJoln2r74hR+y7cg2B5JCPaTh+Hd+EbBRk9nWGSNspuo6krjhX0Om6RnRQuIvFq8wVXCLKH3kwKDYhanSg== - -"@babel/parser@^7.1.0", "@babel/parser@^7.3.4": - version "7.3.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c" - integrity sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ== - -"@babel/parser@^7.4.0": +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.0": version "7.4.2" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.2.tgz#b4521a400cb5a871eab3890787b4bc1326d38d91" integrity sha512-9fJTDipQFvlfSVdD/JBtkiY0br9BtfvW2R8wo6CX/Ej2eMuV0gWPk1M67Mt3eggQvBqYW1FCEk8BN7WvGm/g5g== @@ -720,46 +668,16 @@ dependencies: regenerator-runtime "^0.13.2" -"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" - integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g== +"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.0.tgz#12474e9c077bae585c5d835a95c0b0b790c25c8b" + integrity sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.2.2" - "@babel/types" "^7.2.2" + "@babel/parser" "^7.4.0" + "@babel/types" "^7.4.0" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" - integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.2.2" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.2.3" - "@babel/types" "^7.2.2" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.10" - -"@babel/traverse@^7.3.4": - version "7.3.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06" - integrity sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.3.4" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.3.4" - "@babel/types" "^7.3.4" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.11" - -"@babel/traverse@^7.4.0": +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.0.tgz#14006967dd1d2b3494cdd650c686db9daf0ddada" integrity sha512-/DtIHKfyg2bBKnIN+BItaIlEg5pjAnzHOIQe5w+rHAw/rg9g0V7T4rqPX8BJPfW11kt3koyjAnTNwCzb28Y1PA== @@ -774,7 +692,7 @@ globals "^11.1.0" lodash "^4.17.11" -"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.3.4", "@babel/types@^7.4.0": +"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.0.tgz#670724f77d24cce6cc7d8cf64599d511d164894c" integrity sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA== From a900435d58296680fb7384a63011d51c7d8edfaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Wed, 13 Mar 2019 17:44:07 +0100 Subject: [PATCH 03/22] Sketch ChangePassword component + spec --- components/ChangePassword.spec.js | 72 +++++++++++++++++++++++++++++++ components/ChangePassword.vue | 2 + 2 files changed, 74 insertions(+) create mode 100644 components/ChangePassword.spec.js create mode 100644 components/ChangePassword.vue diff --git a/components/ChangePassword.spec.js b/components/ChangePassword.spec.js new file mode 100644 index 000000000..fda0e3f42 --- /dev/null +++ b/components/ChangePassword.spec.js @@ -0,0 +1,72 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils' +import ChangePassword from './ChangePassword.vue' +import Vue from 'vue' +import Styleguide from '@human-connection/styleguide' + +const localVue = createLocalVue() + +localVue.use(Styleguide) + +describe('ChangePassword.vue', () => { + let store + let mocks + let wrapper + + beforeEach(() => { + mocks = { + $apollo: { + mutate: jest.fn().mockResolvedValue() + } + } + }) + + describe('shallowMount', () => { + const Wrapper = () => { + return shallowMount(ChangePassword, { mocks, localVue }) + } + + it.todo('renders') + + describe('validations', () => { + it.todo('is disabled') + + describe('old password and new password', () => { + describe('match', () => { + it.todo('invalid') + it.todo('displays a warning') + }) + }) + + describe('new password and confirmation', () => { + describe('mismatch', () => { + it.todo('invalid') + it.todo('displays a warning') + }) + + describe('match', () => { + describe('and old password mismatch', () => { + it.todo('valid') + }) + + describe('clicked', () => { + it.todo('sets loading') + }) + }) + }) + }) + + describe('given valid input', () => { + describe('click on submit button', () => { + it.todo('calls changePassword mutation') + + describe('mutation resolves', () => { + it.todo('calls auth/SET_TOKEN with response') + }) + + describe('mutation rejects', () => { + it.todo('displays error message') + }) + }) + }) + }) +}) diff --git a/components/ChangePassword.vue b/components/ChangePassword.vue new file mode 100644 index 000000000..6beff5199 --- /dev/null +++ b/components/ChangePassword.vue @@ -0,0 +1,2 @@ + From 51a1678a38448923f6f10e4df82df760c15ab482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Wed, 13 Mar 2019 17:56:55 +0100 Subject: [PATCH 04/22] [ChangePassword] Implement disabled property --- components/ChangePassword.spec.js | 13 +++++++++++-- components/ChangePassword.vue | 11 +++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/components/ChangePassword.spec.js b/components/ChangePassword.spec.js index fda0e3f42..36ad3fdce 100644 --- a/components/ChangePassword.spec.js +++ b/components/ChangePassword.spec.js @@ -21,14 +21,23 @@ describe('ChangePassword.vue', () => { }) describe('shallowMount', () => { + let wrapper const Wrapper = () => { return shallowMount(ChangePassword, { mocks, localVue }) } - it.todo('renders') + beforeEach(() => { + wrapper = Wrapper() + }) + + it('renders', () => { + expect(wrapper.is('div')).toBe(true) + }) describe('validations', () => { - it.todo('is disabled') + it('invalid', () => { + expect(wrapper.vm.disabled).toBe(true) + }) describe('old password and new password', () => { describe('match', () => { diff --git a/components/ChangePassword.vue b/components/ChangePassword.vue index 6beff5199..9ef85b3de 100644 --- a/components/ChangePassword.vue +++ b/components/ChangePassword.vue @@ -1,2 +1,13 @@ + + From e0432b2fd9e3b662979842a181227c540ee9cca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Wed, 13 Mar 2019 18:56:34 +0100 Subject: [PATCH 05/22] Styleguide blocks development cc @appinteractive We're trying to cross-validate two form fields and don't know how. We (ie. @kachulio1, @aonomike, myself) gave up after we discovered https://github.com/Human-Connection/Nitro-Styleguide/issues/46 --- components/ChangePassword.spec.js | 29 ++++++++++++---- components/ChangePassword.vue | 54 +++++++++++++++++++++++++++++- webapp/pages/settings/security.vue | 8 ++--- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/components/ChangePassword.spec.js b/components/ChangePassword.spec.js index 36ad3fdce..a6be60880 100644 --- a/components/ChangePassword.spec.js +++ b/components/ChangePassword.spec.js @@ -1,4 +1,4 @@ -import { shallowMount, createLocalVue } from '@vue/test-utils' +import { mount, createLocalVue } from '@vue/test-utils' import ChangePassword from './ChangePassword.vue' import Vue from 'vue' import Styleguide from '@human-connection/styleguide' @@ -14,24 +14,25 @@ describe('ChangePassword.vue', () => { beforeEach(() => { mocks = { + $t: jest.fn(), $apollo: { mutate: jest.fn().mockResolvedValue() } } }) - describe('shallowMount', () => { + describe('mount', () => { let wrapper const Wrapper = () => { - return shallowMount(ChangePassword, { mocks, localVue }) + return mount(ChangePassword, { mocks, localVue }) } beforeEach(() => { wrapper = Wrapper() }) - it('renders', () => { - expect(wrapper.is('div')).toBe(true) + it('renders three input fields', () => { + expect(wrapper.findAll('input')).toHaveLength(3) }) describe('validations', () => { @@ -41,8 +42,22 @@ describe('ChangePassword.vue', () => { describe('old password and new password', () => { describe('match', () => { - it.todo('invalid') - it.todo('displays a warning') + beforeEach(() => { + wrapper.find('input#oldPassword').setValue('some secret') + wrapper.find('input#newPassword').setValue('some secret') + }) + + it('invalid', () => { + expect(wrapper.vm.disabled).toBe(true) + }) + + it.skip('displays a warning', () => { + const calls = mocks.$t.mock.calls + const expected = [ + ['change-password.validations.old-and-new-password-match'] + ] + expect(calls).toEqual(expect.arrayContaining(expected)) + }) }) }) diff --git a/components/ChangePassword.vue b/components/ChangePassword.vue index 9ef85b3de..0a3510091 100644 --- a/components/ChangePassword.vue +++ b/components/ChangePassword.vue @@ -1,13 +1,65 @@ diff --git a/webapp/pages/settings/security.vue b/webapp/pages/settings/security.vue index 937aac9dd..376f104e5 100644 --- a/webapp/pages/settings/security.vue +++ b/webapp/pages/settings/security.vue @@ -1,18 +1,16 @@ From eb2552c9a902699495ff7d0b148480dee7763c04 Mon Sep 17 00:00:00 2001 From: Matt Rider Date: Wed, 13 Mar 2019 19:23:24 -0300 Subject: [PATCH 06/22] Add cypress test, update variables - change to confirmPassword to be more consistent with oldPassword, newPassword - change to validate, $t is used for a function for translation --- components/ChangePassword.spec.js | 4 +-- components/ChangePassword.vue | 8 +++--- cypress/integration/ChangePassword.feature | 14 +++++++++++ cypress/integration/common/settings.js | 29 ++++++++++++++++++++++ 4 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 cypress/integration/ChangePassword.feature diff --git a/components/ChangePassword.spec.js b/components/ChangePassword.spec.js index a6be60880..3b8e6791b 100644 --- a/components/ChangePassword.spec.js +++ b/components/ChangePassword.spec.js @@ -14,7 +14,7 @@ describe('ChangePassword.vue', () => { beforeEach(() => { mocks = { - $t: jest.fn(), + validate: jest.fn(), $apollo: { mutate: jest.fn().mockResolvedValue() } @@ -52,7 +52,7 @@ describe('ChangePassword.vue', () => { }) it.skip('displays a warning', () => { - const calls = mocks.$t.mock.calls + const calls = mocks.validate.mock.calls const expected = [ ['change-password.validations.old-and-new-password-match'] ] diff --git a/components/ChangePassword.vue b/components/ChangePassword.vue index 0a3510091..f6e5237a0 100644 --- a/components/ChangePassword.vue +++ b/components/ChangePassword.vue @@ -19,8 +19,8 @@ label="Your new password" /> @@ -41,12 +41,12 @@ export default { formData: { oldPassword: '', newPassword: '', - passwordConfirmation: '' + confirmPassword: '' }, formSchema: { oldPassword: { required: true }, newPassword: { required: true }, - passwordConfirmation: { required: true } + confirmPassword: { required: true } }, disabled: true } diff --git a/cypress/integration/ChangePassword.feature b/cypress/integration/ChangePassword.feature new file mode 100644 index 000000000..cecfaeb84 --- /dev/null +++ b/cypress/integration/ChangePassword.feature @@ -0,0 +1,14 @@ +Feature: Change password + As a user + I want to change my password in my settings + Because this is a basic security feature, e.g. if I exposed my password by accident + + Background: + Given I have a user account + And I am logged in + And I am on the "settings" page + + Scenario: Change my password + Given I click on the "Security" link + Then I should be on the "Security" settings page + And I should be able to change my password \ No newline at end of file diff --git a/cypress/integration/common/settings.js b/cypress/integration/common/settings.js index 3aa6022a8..9bf620024 100644 --- a/cypress/integration/common/settings.js +++ b/cypress/integration/common/settings.js @@ -61,3 +61,32 @@ Then( 'I can see my new name {string} when I click on my profile picture in the top right', name => matchNameInUserMenu(name) ) + +When('I click on the {string} link', link => { + cy.get('a') + .contains(link) + .click() +}) + +Then('I should be on the {string} settings page', page => { + const pathname = `/settings/${page.toLowerCase()}` + cy.location() + .should(loc => { + expect(loc.pathname).to.eq(pathname) + }) + .get('h3') + .should('contain', page) +}) + +Then('I should be able to change my password', () => { + cy.get('input[id=oldPassword]') + .type('1234') + .get('input[id=newPassword]') + .type('12345') + .get('input[id=confirmPassword]') + .type('12345') + .get('button') + .contains('Submit') + .get('.iziToast-message') + .should('contain', 'Password updated successfully.') +}) From 26ab3b9bbe79a4d63677a1c47ce9c8ae7a1a3f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Fri, 22 Mar 2019 16:03:34 +0100 Subject: [PATCH 07/22] Oops, moved the components to a wrong folder --- {components => webapp/components}/ChangePassword.spec.js | 0 {components => webapp/components}/ChangePassword.vue | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {components => webapp/components}/ChangePassword.spec.js (100%) rename {components => webapp/components}/ChangePassword.vue (100%) diff --git a/components/ChangePassword.spec.js b/webapp/components/ChangePassword.spec.js similarity index 100% rename from components/ChangePassword.spec.js rename to webapp/components/ChangePassword.spec.js diff --git a/components/ChangePassword.vue b/webapp/components/ChangePassword.vue similarity index 100% rename from components/ChangePassword.vue rename to webapp/components/ChangePassword.vue From 8827add1c7271051e2c94f51c303aa87670b5e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Fri, 22 Mar 2019 20:01:01 +0100 Subject: [PATCH 08/22] Improve :cucumber: *must* fail if not implemented cc @mattwr18 --- cypress/integration/ChangePassword.feature | 14 ------- cypress/integration/common/settings.js | 29 ------------- cypress/integration/common/steps.js | 42 ++++++++++++++++++- .../settings/ChangePassword.feature | 31 ++++++++++++++ 4 files changed, 72 insertions(+), 44 deletions(-) delete mode 100644 cypress/integration/ChangePassword.feature create mode 100644 cypress/integration/settings/ChangePassword.feature diff --git a/cypress/integration/ChangePassword.feature b/cypress/integration/ChangePassword.feature deleted file mode 100644 index cecfaeb84..000000000 --- a/cypress/integration/ChangePassword.feature +++ /dev/null @@ -1,14 +0,0 @@ -Feature: Change password - As a user - I want to change my password in my settings - Because this is a basic security feature, e.g. if I exposed my password by accident - - Background: - Given I have a user account - And I am logged in - And I am on the "settings" page - - Scenario: Change my password - Given I click on the "Security" link - Then I should be on the "Security" settings page - And I should be able to change my password \ No newline at end of file diff --git a/cypress/integration/common/settings.js b/cypress/integration/common/settings.js index 9bf620024..3aa6022a8 100644 --- a/cypress/integration/common/settings.js +++ b/cypress/integration/common/settings.js @@ -61,32 +61,3 @@ Then( 'I can see my new name {string} when I click on my profile picture in the top right', name => matchNameInUserMenu(name) ) - -When('I click on the {string} link', link => { - cy.get('a') - .contains(link) - .click() -}) - -Then('I should be on the {string} settings page', page => { - const pathname = `/settings/${page.toLowerCase()}` - cy.location() - .should(loc => { - expect(loc.pathname).to.eq(pathname) - }) - .get('h3') - .should('contain', page) -}) - -Then('I should be able to change my password', () => { - cy.get('input[id=oldPassword]') - .type('1234') - .get('input[id=newPassword]') - .type('12345') - .get('input[id=confirmPassword]') - .type('12345') - .get('button') - .contains('Submit') - .get('.iziToast-message') - .should('contain', 'Password updated successfully.') -}) diff --git a/cypress/integration/common/steps.js b/cypress/integration/common/steps.js index eeb3a49d3..726aca86c 100644 --- a/cypress/integration/common/steps.js +++ b/cypress/integration/common/steps.js @@ -5,7 +5,7 @@ import { getLangByName } from '../../support/helpers' let lastPost = {} -const loginCredentials = { +let loginCredentials = { email: 'peterpan@example.org', password: '1234' } @@ -244,3 +244,43 @@ Then( cy.get('.error').should('contain', message) } ) + +Given('my user account has the following login credentials:', table => { + loginCredentials = { + ...loginCredentials, + ...table.hashes()[0] + } + cy.factory().create('User', { + ...loginCredentials + }) +}) + +When('I fill the password form with:', table => { + table = table.rowsHash() + cy.get('input[id=oldPassword]') + .type(table['Your old password']) + .get('input[id=newPassword]') + .type(table['Your new passsword']) + .get('input[id=confirmPassword]') + .type(table['Confirm new password']) +}) + +When('submit the form', () => { + cy.get('form').submit() +}) + +Then('I cannot login anymore with password {string}', password => { + cy.login({ + ...loginCredentials, + ...{password} + }) + cy.get('.iziToast-wrapper').should('contain', "Incorrect email or password") +}) + +Then('I can login successfully with password {string}', password => { + cy.login({ + ...loginCredentials, + ...{password} + }) + cy.get('.iziToast-wrapper').should('contain', "You are logged in!") +}) diff --git a/cypress/integration/settings/ChangePassword.feature b/cypress/integration/settings/ChangePassword.feature new file mode 100644 index 000000000..936bbed74 --- /dev/null +++ b/cypress/integration/settings/ChangePassword.feature @@ -0,0 +1,31 @@ +Feature: Change password + As a user + I want to change my password in my settings + For security, e.g. if I exposed my password by accident + + Login via email and password is a well-known authentication procedure and you + can assure to the server that you are who you claim to be. Either if you + exposed your password by acccident and you want to invalidate the exposed + password or just out of an good habit, you want to change your password. + + Background: + Given my user account has the following login credentials: + | email | passsword | + | user@example.org | 1234 | + And I am logged in + + Scenario: Change my password + Given I am on the "settings" page + And I click on "Security" + When I fill the password form with: + | Your old password | 1234 | + | Your new passsword | 12345 | + | Confirm new password | 12345 | + And submit the form + And I see a success message: + """ + Password updated successfully + """ + And I log out through the menu in the top right corner + Then I cannot login anymore with password "1234" + But I can login successfully with password "12345" From 22367417de9eeb892685e9b2074361befd0c6714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Sat, 23 Mar 2019 01:37:36 +0100 Subject: [PATCH 09/22] Implement component test --- webapp/components/ChangePassword.spec.js | 70 ++++++++++++++++++++++-- webapp/components/ChangePassword.vue | 38 +++++++++---- webapp/locales/de.json | 6 +- webapp/locales/en.json | 6 +- 4 files changed, 102 insertions(+), 18 deletions(-) diff --git a/webapp/components/ChangePassword.spec.js b/webapp/components/ChangePassword.spec.js index 3b8e6791b..98a66da72 100644 --- a/webapp/components/ChangePassword.spec.js +++ b/webapp/components/ChangePassword.spec.js @@ -8,15 +8,25 @@ const localVue = createLocalVue() localVue.use(Styleguide) describe('ChangePassword.vue', () => { - let store let mocks let wrapper beforeEach(() => { mocks = { validate: jest.fn(), + $toast: { + error: jest.fn(), + success: jest.fn() + }, + $t: jest.fn(), + $store: { + commit: jest.fn() + }, $apollo: { - mutate: jest.fn().mockResolvedValue() + mutate: jest + .fn() + .mockRejectedValue({ message: 'Ouch!' }) + .mockResolvedValueOnce({ data: { changePassword: 'NEWTOKEN' } }) } } }) @@ -80,15 +90,63 @@ describe('ChangePassword.vue', () => { }) describe('given valid input', () => { - describe('click on submit button', () => { - it.todo('calls changePassword mutation') + beforeEach(() => { + wrapper.find('input#oldPassword').setValue('supersecret') + wrapper.find('input#newPassword').setValue('superdupersecret') + wrapper.find('input#confirmPassword').setValue('superdupersecret') + }) + + describe('submit form', () => { + beforeEach(() => { + wrapper.find('form').trigger('submit') + }) + + it('calls changePassword mutation', () => { + expect(mocks.$apollo.mutate).toHaveBeenCalled() + }) + + it('passes form data as variables', () => { + expect(mocks.$apollo.mutate.mock.calls[0][0]).toEqual( + expect.objectContaining({ + variables: { + oldPassword: 'supersecret', + newPassword: 'superdupersecret', + confirmPassword: 'superdupersecret' + } + }) + ) + }) describe('mutation resolves', () => { - it.todo('calls auth/SET_TOKEN with response') + beforeEach(() => { + mocks.$apollo.mutate = jest.fn().mockResolvedValue() + wrapper = Wrapper() + }) + + it('calls auth/SET_TOKEN with response', () => { + expect(mocks.$store.commit).toHaveBeenCalledWith( + 'auth/SET_TOKEN', + 'NEWTOKEN' + ) + }) + + it('displays success message', () => { + expect(mocks.$t).toHaveBeenCalledWith( + 'settings.security.change-password.success' + ) + expect(mocks.$toast.success).toHaveBeenCalled() + }) }) describe('mutation rejects', () => { - it.todo('displays error message') + beforeEach(() => { + // second call will reject + wrapper.find('form').trigger('submit') + }) + + it('displays error message', () => { + expect(mocks.$toast.error).toHaveBeenCalledWith('Ouch!') + }) }) }) }) diff --git a/webapp/components/ChangePassword.vue b/webapp/components/ChangePassword.vue index f6e5237a0..dc8cc09da 100644 --- a/webapp/components/ChangePassword.vue +++ b/webapp/components/ChangePassword.vue @@ -3,7 +3,6 @@ v-model="formData" :schema="formSchema" @submit="handleSubmit" - @input="validate" > @@ -34,6 +36,8 @@