diff --git a/backend/src/schema/resolvers/user_management.js b/backend/src/schema/resolvers/user_management.js
index e1528cc9e..b7584dd68 100644
--- a/backend/src/schema/resolvers/user_management.js
+++ b/backend/src/schema/resolvers/user_management.js
@@ -2,6 +2,7 @@ import encode from '../../jwt/encode'
import bcrypt from 'bcryptjs'
import { AuthenticationError } from 'apollo-server'
import { neode } from '../../bootstrap/neo4j'
+import { normalizeEmail } from 'validator'
const instance = neode()
@@ -21,6 +22,7 @@ export default {
// if (user && user.id) {
// throw new Error('Already logged in.')
// }
+ email = normalizeEmail(email)
const session = driver.session()
const result = await session.run(
`
diff --git a/backend/src/schema/resolvers/user_management.spec.js b/backend/src/schema/resolvers/user_management.spec.js
index 9d7dff2a3..df8454ebb 100644
--- a/backend/src/schema/resolvers/user_management.spec.js
+++ b/backend/src/schema/resolvers/user_management.spec.js
@@ -5,8 +5,10 @@ import { gql } from '../../helpers/jest'
import { createTestClient } from 'apollo-server-testing'
import createServer, { context } from '../../server'
import encode from '../../jwt/encode'
+import { neode as getNeode } from '../../bootstrap/neo4j'
const factory = Factory()
+const neode = getNeode()
let query
let mutate
let variables
@@ -214,6 +216,28 @@ describe('login', () => {
})
})
})
+
+ describe('normalization', () => {
+ describe('email address is a gmail address ', () => {
+ beforeEach(async () => {
+ const email = await neode.first('EmailAddress', { email: 'test@example.org' })
+ await email.update({ email: 'someuser@gmail.com' })
+ })
+
+ describe('supplied email contains dots', () => {
+ beforeEach(() => {
+ variables = { ...variables, email: 'some.user@gmail.com' }
+ })
+
+ it('normalizes email, issue #2329', async () => {
+ await respondsWith({
+ data: { login: expect.any(String) },
+ errors: undefined,
+ })
+ })
+ })
+ })
+ })
})
describe('with a valid email but incorrect password', () => {
diff --git a/webapp/components/LoginForm/LoginForm.spec.js b/webapp/components/LoginForm/LoginForm.spec.js
new file mode 100644
index 000000000..b60680f37
--- /dev/null
+++ b/webapp/components/LoginForm/LoginForm.spec.js
@@ -0,0 +1,62 @@
+import LoginForm from './LoginForm.vue'
+import Styleguide from '@human-connection/styleguide'
+import Vuex from 'vuex'
+import { config, mount, createLocalVue } from '@vue/test-utils'
+
+const localVue = createLocalVue()
+localVue.use(Vuex)
+localVue.use(Styleguide)
+
+config.stubs['nuxt-link'] = ''
+config.stubs['locale-switch'] = ''
+config.stubs['client-only'] = ''
+
+describe('LoginForm', () => {
+ let mocks
+ let propsData
+ let storeMocks
+
+ beforeEach(() => {
+ propsData = {}
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ storeMocks = {
+ getters: {
+ 'auth/pending': () => false,
+ },
+ actions: {
+ 'auth/login': jest.fn(),
+ },
+ }
+ const store = new Vuex.Store(storeMocks)
+ mocks = {
+ $t: () => {},
+ $toast: {
+ success: jest.fn(),
+ error: jest.fn(),
+ },
+ }
+ return mount(LoginForm, { mocks, localVue, propsData, store })
+ }
+
+ describe('fill in email and password and submit', () => {
+ const fillIn = (wrapper, opts = {}) => {
+ const { email = 'email@example.org', password = '1234' } = opts
+ wrapper.find('input[name="email"]').setValue(email)
+ wrapper.find('input[name="password"]').setValue(password)
+ wrapper.find('form').trigger('submit')
+ }
+
+ it('dispatches login with form data', () => {
+ fillIn(Wrapper())
+ expect(storeMocks.actions['auth/login']).toHaveBeenCalledWith(
+ expect.any(Object),
+ { email: 'email@example.org', password: '1234' },
+ undefined,
+ )
+ })
+ })
+ })
+})
diff --git a/webapp/components/LoginForm/LoginForm.vue b/webapp/components/LoginForm/LoginForm.vue
index 91693ed4b..d61a5675a 100644
--- a/webapp/components/LoginForm/LoginForm.vue
+++ b/webapp/components/LoginForm/LoginForm.vue
@@ -93,8 +93,9 @@ export default {
},
methods: {
async onSubmit() {
+ const { email, password } = this.form
try {
- await this.$store.dispatch('auth/login', { ...this.form })
+ await this.$store.dispatch('auth/login', { email, password })
this.$toast.success(this.$t('login.success'))
this.$emit('success')
} catch (err) {