Skip to content

Commit

Permalink
Switches to AWS Amplify for Cognito.
Browse files Browse the repository at this point in the history
closes #2336
  • Loading branch information
justinlittman committed Sep 4, 2020
1 parent 1042c2c commit 8733e60
Show file tree
Hide file tree
Showing 37 changed files with 972 additions and 742 deletions.
89 changes: 67 additions & 22 deletions __tests__/actionCreators/authenticate.test.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,83 @@
// Copyright 2019 Stanford University see LICENSE for license
import {
authenticationFailed, authenticationSucceeded, signedOut,
authenticate, signIn, signOut,
} from 'actionCreators/authenticate'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import Auth from '@aws-amplify/auth'

describe('authenticationFailed', () => {
const currentUser = { hello: 'world' }
const errInfoauthenticate = { foo: 'bar' }
jest.mock('@aws-amplify/auth')

const authResult = {
currentUser,
authenticationError: errInfoauthenticate,
}
const mockStore = configureMockStore([thunk])

it('returns the failure action', () => {
expect(authenticationFailed(authResult).type).toEqual('AUTHENTICATION_FAILURE')
describe('authenticate', () => {
describe('user already in state', () => {
it('does not authenticate', async () => {
const store = mockStore({ authenticate: { user: { username: 'havram' } } })
await store.dispatch(authenticate())
expect(store.getActions()).toEqual([])
})
})
describe('successful', () => {
it('dispatches actions to add user', async () => {
Auth.currentAuthenticatedUser.mockResolvedValue({ username: 'havram', something: 'else' })
const store = mockStore({ authenticate: { user: undefined } })
await store.dispatch(authenticate())
expect(store.getActions()).toHaveAction('SET_USER', { username: 'havram' })
})
})
describe('failure', () => {
it('dispatches actions to remove user', async () => {
Auth.currentAuthenticatedUser.mockRejectedValue()
const store = mockStore({ authenticate: { user: undefined } })
await store.dispatch(authenticate())
expect(store.getActions()).toHaveAction('REMOVE_USER')
})
})
})

describe('authenticationSucceeded', () => {
const currentUser = { hello: 'world' }
const sessionData = { foo: 'bar' }
describe('signIn', () => {
describe('successful', () => {
it('dispatches actions to add user', async () => {
Auth.signIn.mockResolvedValue({ username: 'havram', something: 'else' })
const store = mockStore()
await store.dispatch(signIn('havram', 'm&rc', 'testerrorkey'))

const authResult = {
currentUser,
currentSession: sessionData,
}
expect(Auth.signIn).toHaveBeenCalledWith('havram', 'm&rc')
expect(store.getActions()).toHaveAction('SET_USER', { username: 'havram' })
})
})
describe('failure', () => {
it('dispatches actions to remove user', async () => {
Auth.signIn.mockRejectedValue(new Error('Bad user'))
const store = mockStore()
await store.dispatch(signIn('mdewey', 'amh&rst', 'testerrorkey'))

it('returns the success action', () => {
expect(authenticationSucceeded(authResult).type).toEqual('AUTHENTICATION_SUCCESS')
expect(store.getActions()).toHaveAction('CLEAR_ERRORS', 'testerrorkey')
expect(store.getActions()).toHaveAction('ADD_ERROR', { errorKey: 'testerrorkey', error: 'Login failed: Bad user' })
expect(store.getActions()).toHaveAction('REMOVE_USER')
})
})
})

describe('signedOut', () => {
it('returns the signed out action', () => {
expect(signedOut().type).toEqual('SIGN_OUT_SUCCESS')
describe('signOut', () => {
describe('successful', () => {
it('dispatches actions to remove user', async () => {
Auth.signOut.mockResolvedValue()
const store = mockStore()
await store.dispatch(signOut())

expect(Auth.signOut).toHaveBeenCalled()
expect(store.getActions()).toHaveAction('REMOVE_USER')
})
})
describe('failure', () => {
it('does nothing', async () => {
Auth.signOut.mockRejectedValue()
const store = mockStore()
await store.dispatch(signOut())

expect(store.getActions()).toEqual([])
})
})
})
16 changes: 8 additions & 8 deletions __tests__/actionCreators/resources.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ describe('loadResource', () => {

it('dispatches actions', async () => {
const uri = 'http://localhost:3000/repository/c7db5404-7d7d-40ac-b38e-c821d2c3ae3f'
const result = await store.dispatch(loadResource('jlit', uri, 'testerrorkey'))
const result = await store.dispatch(loadResource(uri, 'testerrorkey'))
expect(result).toBe(true)

const actions = store.getActions()
Expand All @@ -223,7 +223,7 @@ describe('loadResource', () => {

it('dispatches actions', async () => {
const uri = 'http://localhost:3000/repository/c7db5404-7d7d-40ac-b38e-c821d2c3ae3f'
const result = await store.dispatch(loadResource('jlit', uri, 'testerrorkey', true))
const result = await store.dispatch(loadResource(uri, 'testerrorkey', true))
expect(result).toBe(true)

const actions = store.getActions()
Expand All @@ -241,7 +241,7 @@ describe('loadResource', () => {

it('dispatches actions', async () => {
const uri = 'http://localhost:3000/repository/c7db5404-7d7d-40ac-b38e-c821d2c3ae3f-invalid'
const result = await store.dispatch(loadResource('jlit', uri, 'testerrorkey'))
const result = await store.dispatch(loadResource(uri, 'testerrorkey'))
expect(result).toBe(false)

const actions = store.getActions()
Expand All @@ -258,7 +258,7 @@ describe('loadResource', () => {

it('dispatches actions', async () => {
// http://error is a special URI that will cause an error to be thrown.
const result = await store.dispatch(loadResource('jlit', 'http://error', 'testerrorkey'))
const result = await store.dispatch(loadResource('http://error', 'testerrorkey'))
expect(result).toBe(false)

const actions = store.getActions()
Expand Down Expand Up @@ -392,7 +392,7 @@ describe('saveNewResource', () => {
const store = mockStore(createState({ hasResourceWithLiteral: true }))
sinopiaApi.postResource = jest.fn().mockResolvedValue(uri)

await store.dispatch(saveNewResource('t9zVwg2zO', 'jpn', 'stanford', 'testerror'))
await store.dispatch(saveNewResource('t9zVwg2zO', 'stanford', 'testerror'))

const actions = store.getActions()

Expand All @@ -410,7 +410,7 @@ describe('saveNewResource', () => {
const store = mockStore(createState({ hasResourceWithLiteral: true }))
sinopiaApi.postResource.mockRejectedValue(new Error('Messed-up'))

await store.dispatch(saveNewResource('t9zVwg2zO', 'jpn', 'stanford', 'testerror'))
await store.dispatch(saveNewResource('t9zVwg2zO', 'stanford', 'testerror'))

const actions = store.getActions()

Expand All @@ -427,15 +427,15 @@ describe('saveResource', () => {
sinopiaApi.putResource = jest.fn().mockResolvedValue('t9zVwg2zO')
const store = mockStore(createState({ hasResourceWithLiteral: true }))

await store.dispatch(saveResource('t9zVwg2zO', 'jpn', 'testerror'))
await store.dispatch(saveResource('t9zVwg2zO', 'testerror'))
const actions = store.getActions()
expect(actions).toHaveAction('SAVE_RESOURCE_FINISHED')
})

it('error when trying to save existing resource', async () => {
sinopiaApi.putResource = jest.fn().mockRejectedValue(new Error('Messed-up'))
const store = mockStore(createState({ hasResourceWithLiteral: true }))
await store.dispatch(saveResource('t9zVwg2zO', 'jpn', 'testerror'))
await store.dispatch(saveResource('t9zVwg2zO', 'testerror'))
const actions = store.getActions()
expect(actions).toHaveAction('ADD_ERROR', {
errorKey: 'testerror',
Expand Down
18 changes: 18 additions & 0 deletions __tests__/components/App.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ import { fireEvent, wait, screen } from '@testing-library/react'
import { createStore, renderApp, createHistory } from 'testUtils'
import { createState } from 'stateUtils'
import Config from 'Config'
import Auth from '@aws-amplify/auth'

jest.mock('@aws-amplify/auth')

jest.spyOn(Config, 'useResourceTemplateFixtures', 'get').mockReturnValue(true)

describe('<App />', () => {
beforeEach(() => {
Auth.currentAuthenticatedUser.mockResolvedValue({ username: 'Foo McBar' })
})
it('loads languages', async () => {
const store = createStore()
renderApp(store)
Expand All @@ -31,7 +37,19 @@ describe('<App />', () => {
await screen.findByText(/sinopia_export_all/)
})

it('authenticates', () => {
const state = createState({ notAuthenticated: true })
const store = createStore(state)
renderApp(store)

expect(Auth.currentAuthenticatedUser).toHaveBeenCalled()
})

describe('when user is not authenticated', () => {
beforeEach(() => {
Auth.currentAuthenticatedUser.mockRejectedValue(new Error('Not authenticated'))
})

const state = createState({ notAuthenticated: true })
const store = createStore(state)

Expand Down
86 changes: 0 additions & 86 deletions __tests__/components/home/LoginPanel.test.js

This file was deleted.

1 change: 0 additions & 1 deletion __tests__/feature/newResourceTemplate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ global.$ = jest.fn().mockReturnValue({ popover: jest.fn() })
// This forces Sinopia server to use fixtures
jest.spyOn(Config, 'useResourceTemplateFixtures', 'get').mockReturnValue(true)


describe('creating new resource template ', () => {
it('opens the resource template for the resource', async () => {
renderApp()
Expand Down
30 changes: 6 additions & 24 deletions __tests__/feature/userAuthentication.test.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,19 @@
// Copyright 2018 Stanford University see LICENSE for license

import * as awsCognito from 'amazon-cognito-identity-js'
import {
fireEvent, screen, waitForElementToBeRemoved,
} from '@testing-library/react'

import { createState } from 'stateUtils'
import { createStore, renderApp } from 'testUtils'
import Auth from '@aws-amplify/auth'

jest.mock('amazon-cognito-identity-js')

function MockCognitoUserAuthenticationSuccess(_userData) {
this.username = 'Baz Le Quux'
this.authenticateUser = (_authnDetails, callbacks) => {
callbacks.onSuccess({ currentSession: { idToken: {} } })
}
}

function MockCognitoUserAuthenticationFailure(_userData) {
this.username = 'Baz Le Quux'
this.authenticateUser = (_authnDetails, callbacks) => {
callbacks.onFailure({
code: 'NotAuthorizedException', name: 'NotAuthorizedException', message: 'Incorrect username or password.',
})
}
}

jest.mock('@aws-amplify/auth')

describe('user authentication', () => {
Auth.signOut.mockResolvedValue()
Auth.currentAuthenticatedUser.mockRejectedValue()
it('allows a logged in user to log out and allows a new one to login', async () => {
Auth.signIn.mockResolvedValue({ username: 'Baz Le Quux' })
renderApp()
screen.getByText(/Foo McBar/) // user Foo McBar should be logged in already when using default test redux store

Expand All @@ -46,8 +31,6 @@ describe('user authentication', () => {
screen.getByText(/Sinopia Version \d+.\d+.\d+ highlights/)
screen.getByRole('link', { name: 'Sinopia help site' })

awsCognito.CognitoUser.mockImplementation(MockCognitoUserAuthenticationSuccess)

// login as a different user
fireEvent.change(screen.getByLabelText('User name'), { target: { value: '[email protected]' } })
fireEvent.change(screen.getByLabelText('Password'), { target: { value: 'Password2' } })
Expand All @@ -59,6 +42,7 @@ describe('user authentication', () => {
})

it('presents a helpful error when the user enters the wrong password', async () => {
Auth.signIn.mockRejectedValue(new Error('Incorrect username or password.'))
const state = createState({ notAuthenticated: true })
const store = createStore(state)
renderApp(store)
Expand All @@ -69,8 +53,6 @@ describe('user authentication', () => {
screen.getByText(/Sinopia Version \d+.\d+.\d+ highlights/)
screen.getByRole('link', { name: 'Sinopia help site' })

awsCognito.CognitoUser.mockImplementation(MockCognitoUserAuthenticationFailure)

// try to login
fireEvent.change(screen.getByLabelText('User name'), { target: { value: '[email protected]' } })
fireEvent.change(screen.getByLabelText('Password'), { target: { value: 'password1' } })
Expand Down
Loading

0 comments on commit 8733e60

Please sign in to comment.