Skip to content
This repository has been archived by the owner on Jun 27, 2023. It is now read-only.

Commit

Permalink
Merge pull request #143 from cfpb/603-notes-history
Browse files Browse the repository at this point in the history
Note History
  • Loading branch information
wpears authored Aug 27, 2020
2 parents fd285c3 + 441b3dd commit 6eee49d
Show file tree
Hide file tree
Showing 13 changed files with 715 additions and 7 deletions.
3 changes: 2 additions & 1 deletion cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"HH_AUTH_REALM": "hmda2",
"HH_AUTH_CLIENT_ID": "hmda2-api",
"HH_HOST": "http://localhost:3000"
}
},
"integrationFolder": "cypress/tests/"
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,21 @@ describe('HMDA Help', () => {
cy.findByLabelText("LEI").type(HH_INSTITUTION)
cy.findByText('Search institutions').click()
cy.findAllByText('Update')
.first()
.eq(1) // 2019
.click()

const successMessage = `The institution, ${HH_INSTITUTION}, has been updated.`
const nameLabelText = 'Respondent Name'
const updateButtonText = 'Update the institution'
const testName = 'Cypress Test Name Update'

const timestamp1 = Date.now()
cy.findByText("Note History").click()
cy.get('.note-list li')
.first()
.find('button .text')
.should('not.contain.text', timestamp1)

cy.findByLabelText(nameLabelText).then($name => {
const savedName = $name.attr('value')
expect($name.attr('value')).to.not.contain(testName)
Expand All @@ -49,7 +56,7 @@ describe('HMDA Help', () => {
cy.findByText(updateButtonText)
.should('not.be.enabled')
cy.findByLabelText('Notes')
.type('Cypress - Change respondent name')
.type('Cypress - Change respondent name ' + timestamp1 )
.blur()
cy.findByText(updateButtonText)
.should('be.enabled')
Expand All @@ -60,6 +67,25 @@ describe('HMDA Help', () => {
.should('exist')
.then(() => {
expect($name2.attr('value')).to.contain(testName)
// Check Note History entry correctly created
cy.wait(2000)
cy.get('.note-list li').first().as('firstNote')
cy.get('@firstNote')
.find('button .text')
.should('contain.text', timestamp1)
cy.get('@firstNote')
.find('.details tbody td')
.eq(0)
.should('contain.text', "respondent")
.should('contain.text', "name")
cy.get('@firstNote')
.find('.details tbody td')
.eq(1)
.should('contain.text', savedName)
cy.get('@firstNote')
.find('.details tbody td')
.eq(2)
.should('contain.text', testName)
})
})
})
Expand Down
108 changes: 108 additions & 0 deletions cypress/tests/unit/note_history_utils.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import * as util from '../../../src/institution/NoteHistory/utils'

const curr = {
shallow: 'diff',
nested: { value: 'diff' },
array: [2, 1],
newKey: 'diff',
}

const prev = { shallow: 'old', nested: { value: 'old' }, array: [1, 2] }

describe('#calcDiff', () => {
it('Returns null when no differences', () => {
expect(util.calcDiff(curr, curr)).to.equal(null)
expect(util.calcDiff({}, {})).to.equal(null)
expect(util.calcDiff(null, null)).to.equal(null)
})

it('Returns all diffs when one arg is null', () => {
const res_no_prev = {
shallow: { oldVal: null, newVal: 'diff' },
nested: { value: { oldVal: null, newVal: 'diff' } },
array: { oldVal: null, newVal: [2, 1] },
newKey: { oldVal: null, newVal: 'diff' },
}

expect(util.calcDiff(curr, null)).to.deep.equal(res_no_prev)

const res_no_curr = {
shallow: { oldVal: null, newVal: 'diff' },
nested: { value: { oldVal: null, newVal: 'diff' } },
array: { oldVal: null, newVal: [2, 1] },
newKey: { oldVal: null, newVal: 'diff' },
}
expect(util.calcDiff(null, curr)).to.deep.equal(res_no_curr)
})

it('Returns expected diff when given changed histories', () => {
const expected = {
shallow: { oldVal: 'old', newVal: 'diff' },
nested: { value: { oldVal: 'old', newVal: 'diff' } },
array: { oldVal: [1, 2], newVal: [2, 1] },
newKey: { oldVal: null, newVal: 'diff' },
}
expect(util.calcDiff(curr, prev)).to.deep.equal(expected)

})
})

describe('#allDiffs', () => {
it('Returns null without fields to diff', () => {
expect(util.allDiff()).to.equal(null);
expect(util.allDiff({})).to.equal(null);
})

it('Treats all fields as changed', () => {
const expected = {
shallow: { oldVal: null, newVal: 'diff' },
nested: { value: { oldVal: null, newVal: 'diff' } },
array: { oldVal: null, newVal: [2, 1] },
newKey: { oldVal: null, newVal: 'diff' },
}
expect(util.allDiff(curr)).to.deep.equal(expected);
})
})

describe('#formatHistoryDate', () => {
it('Formats valid history ID', () => {
const hID = 'FRONTENDTESTBANK9999-2019-1597866055421'
const expected = 'Wed Aug 19 2020'
expect(util.formatHistoryDate(hID)).to.equal(expected)
})

it('Returns null for invalid history ID timestamp', () => {
const hID = 'FRONTENDTESTBANK9999-2019-1597866055421-extra'
expect(util.formatHistoryDate(hID)).to.equal(null)
})
})

describe('#sortNotes', () => {
it('Sorts notes desc by id', () => {
const data = [{id: 3}, {id: 8}]
expect(data[0].id < data[1].id).to.equal(true);
const sorted = util.sortNotes(data)
expect(data[0].id < data[1].id).to.equal(false);
expect(data[1].id < data[0].id).to.equal(true);
})
})

describe('#addDiff', () => {
it('Injects diff into notes', () => {
const notes = [
{ updatedPanel: JSON.stringify(curr) },
{ updatedPanel: JSON.stringify(prev) },
]

const injected = util.addDiff(notes)

const expected = {
shallow: { oldVal: 'old', newVal: 'diff' },
nested: { value: { oldVal: 'old', newVal: 'diff' } },
array: { oldVal: [1, 2], newVal: [2, 1] },
newKey: { oldVal: null, newVal: 'diff' },
}

expect(injected[0].diff).to.deep.equal(expected);
})
})
Binary file added src/images/warning.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 90 additions & 0 deletions src/institution/NoteHistory/NoteDetails.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useEffect } from 'react'

const NoteDetails = ({ className, diff, id, isOpen }) => {
useEffect(() => {
if (isOpen) {
setTimeout(() => {
document
.getElementById(id)
.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
}, 300)
}
}, [isOpen, id])

return (
<div id={id} className={className}>
<DiffTable json={diff} />
</div>
)
}

const DiffTable = ({ json }) => {
const keys = json && Object.keys(json)
if (!keys || (keys.length === 1 && keys.indexOf('notes') === 0))
return <NoChanges />

return (
<>
<table className='diff-table'>
<DiffTableHeader />
<DiffTableBody json={json} />
</table>
<pre className='json'>{JSON.stringify(json, null, 2)}</pre>
</>
)
}

const DiffTableHeader = () => (
<thead>
<tr>
<td>Field</td>
<td>Old Value</td>
<td>New Value</td>
</tr>
</thead>
)

const DiffTableBody = ({ json }) => {
return (
<tbody>
{Object.keys(json).map((key, idx) => {
if (key === 'notes') return null
const current = json[key]

if (current && current.newVal !== undefined) {
return (
<tr key={`${key}-${idx}`}>
<td>{key}</td>
<td>{checkForNone(current.oldVal)}</td>
<td>{checkForNone(current.newVal)}</td>
</tr>
)
}
else if (typeof current !== 'string') {
return Object.keys(current).map((nestedKey, nidx) => {
const nestedCurrent = json[key][nestedKey]
return (
<tr key={`${key}-${idx}-${nidx}`}>
<td>{key} {nestedKey}</td>
<td>{checkForNone(nestedCurrent.oldVal)}</td>
<td>{checkForNone(nestedCurrent.newVal)}</td>
</tr>
)
})
}
else return null
})}
</tbody>
)
}

function checkForNone(val) {
if([null, undefined].indexOf(val) > -1) return '<none>'
return val.toString()
}

const NoChanges = ({ text = 'No Changes' }) => {
return <div className="no-changes">{text}</div>
}

export default NoteDetails
Loading

0 comments on commit 6eee49d

Please sign in to comment.