Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions src/utilities/Accounts-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { describe, expect, it } from 'vitest'
import { getSortedAccountsWithMembers } from 'src/utilities/Accounts'

describe('getSortedAccountsWithMembers', () => {
it('returns empty array when no accounts match members', () => {
const accounts = [{ guid: 'ACC-1', member_guid: 'MEM-999', user_name: 'Account 1' }]
const members = [{ guid: 'MEM-1', name: 'Member 1' }]

const result = getSortedAccountsWithMembers(accounts, members)

expect(result).toEqual([])
})

it('filters accounts by member guid and adds member name', () => {
const accounts = [
{ guid: 'ACC-1', member_guid: 'MEM-1', user_name: 'Checking' },
{ guid: 'ACC-2', member_guid: 'MEM-2', user_name: 'Savings' },
]
const members = [
{ guid: 'MEM-1', name: 'Bank of America' },
{ guid: 'MEM-2', name: 'Chase' },
]

const result = getSortedAccountsWithMembers(accounts, members)

expect(result).toHaveLength(2)

const checking = result.find((a) => a.guid === 'ACC-1')
const savings = result.find((a) => a.guid === 'ACC-2')

expect(checking).toEqual({
guid: 'ACC-1',
member_guid: 'MEM-1',
user_name: 'Checking',
memberName: 'Bank of America',
})
expect(savings).toEqual({
guid: 'ACC-2',
member_guid: 'MEM-2',
user_name: 'Savings',
memberName: 'Chase',
})
})

it('sorts accounts by user_name alphabetically', () => {
const accounts = [
{ guid: 'ACC-1', member_guid: 'MEM-1', user_name: 'Savings' },
{ guid: 'ACC-2', member_guid: 'MEM-1', user_name: 'Checking' },
{ guid: 'ACC-3', member_guid: 'MEM-1', user_name: 'Investment' },
]
const members = [{ guid: 'MEM-1', name: 'Bank' }]

const result = getSortedAccountsWithMembers(accounts, members)

expect(result[0].user_name).toBe('Checking')
expect(result[1].user_name).toBe('Investment')
expect(result[2].user_name).toBe('Savings')
})

it('filters out accounts without matching member', () => {
const accounts = [
{ guid: 'ACC-1', member_guid: 'MEM-1', user_name: 'Account 1' },
{ guid: 'ACC-2', member_guid: 'MEM-999', user_name: 'Account 2' },
{ guid: 'ACC-3', member_guid: 'MEM-2', user_name: 'Account 3' },
]
const members = [
{ guid: 'MEM-1', name: 'Member 1' },
{ guid: 'MEM-2', name: 'Member 2' },
]

const result = getSortedAccountsWithMembers(accounts, members)

expect(result).toHaveLength(2)
expect(result.find((a) => a.guid === 'ACC-2')).toBeUndefined()
})

it('handles empty members array', () => {
const accounts = [{ guid: 'ACC-1', member_guid: 'MEM-1', user_name: 'Account 1' }]
const members = []

const result = getSortedAccountsWithMembers(accounts, members)

expect(result).toEqual([])
})

it('handles empty accounts array', () => {
const accounts = []
const members = [{ guid: 'MEM-1', name: 'Member 1' }]

const result = getSortedAccountsWithMembers(accounts, members)

expect(result).toEqual([])
})

it('leaves memberName undefined when the matched member has no name', () => {
const accounts = [{ guid: 'ACC-1', member_guid: 'MEM-1', user_name: 'Account 1' }]
const members = [{ guid: 'MEM-1' }]

const result = getSortedAccountsWithMembers(accounts, members)

expect(result).toHaveLength(1)
expect(result[0].memberName).toBeUndefined()
})
})
22 changes: 22 additions & 0 deletions src/utilities/KeyPress-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { describe, expect, it, vi } from 'vitest'
import { preventDefaultAndStopAllPropagation } from 'src/utilities/KeyPress'

describe('preventDefaultAndStopAllPropagation', () => {
const createMockEvent = () => ({
preventDefault: vi.fn(),
stopPropagation: vi.fn(),
nativeEvent: {
stopImmediatePropagation: vi.fn(),
},
})

it('stops the event on both the synthetic and native event so global listeners do not fire', () => {
const event = createMockEvent()

preventDefaultAndStopAllPropagation(event)

expect(event.preventDefault).toHaveBeenCalledTimes(1)
expect(event.stopPropagation).toHaveBeenCalledTimes(1)
expect(event.nativeEvent.stopImmediatePropagation).toHaveBeenCalledTimes(1)
})
})
97 changes: 97 additions & 0 deletions src/utilities/Polyfill-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { describe, expect, it, beforeEach, afterEach } from 'vitest'
import { fromEntriesPolyfill } from 'src/utilities/Polyfill'

describe('fromEntriesPolyfill', () => {
let originalFromEntries

const installPolyfill = () => {
delete Object.fromEntries
fromEntriesPolyfill()
}

beforeEach(() => {
originalFromEntries = Object.fromEntries
})

afterEach(() => {
Object.fromEntries = originalFromEntries
})

it('does not override Object.fromEntries if it exists', () => {
const existingImpl = Object.fromEntries

fromEntriesPolyfill()

expect(Object.fromEntries).toBe(existingImpl)
})

it('adds Object.fromEntries if it does not exist', () => {
installPolyfill()

expect(Object.fromEntries).toBeDefined()
expect(typeof Object.fromEntries).toBe('function')
})

it('creates object from entries array when polyfilled', () => {
installPolyfill()

const entries = [
['a', 1],
['b', 2],
['c', 3],
]
const result = Object.fromEntries(entries)

expect(result).toEqual({ a: 1, b: 2, c: 3 })
})

it('handles Map entries when polyfilled', () => {
installPolyfill()

const map = new Map([
['key1', 'value1'],
['key2', 'value2'],
])
const result = Object.fromEntries(map)

expect(result).toEqual({ key1: 'value1', key2: 'value2' })
})

it('throws for non-iterable arguments when polyfilled', () => {
installPolyfill()

const expectedError = 'Object.fromEntries() requires a single iterable argument'

expect(() => Object.fromEntries(null)).toThrow(expectedError)
expect(() => Object.fromEntries(42)).toThrow(expectedError)
})

it('handles empty entries array when polyfilled', () => {
installPolyfill()

const result = Object.fromEntries([])

expect(result).toEqual({})
})

it('handles various value types when polyfilled', () => {
installPolyfill()

const entries = [
['string', 'value'],
['number', 42],
['boolean', true],
['null', null],
['object', { nested: 'object' }],
]
const result = Object.fromEntries(entries)

expect(result).toEqual({
string: 'value',
number: 42,
boolean: true,
null: null,
object: { nested: 'object' },
})
})
})
23 changes: 23 additions & 0 deletions src/utilities/ScrollToTop-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { describe, expect, it, vi } from 'vitest'
import { scrollToTop } from 'src/utilities/ScrollToTop'

describe('scrollToTop', () => {
it('scrolls the ref element into view and returns the result', () => {
const scrollIntoView = vi.fn().mockReturnValue('scrolled')
const ref = {
current: {
scrollIntoView,
},
}

const result = scrollToTop(ref)

expect(scrollIntoView).toHaveBeenCalledWith(true)
expect(result).toBe('scrolled')
})

it('does nothing and returns undefined when ref.current is not set', () => {
expect(scrollToTop({ current: null })).toBeUndefined()
expect(scrollToTop({ current: undefined })).toBeUndefined()
})
})
88 changes: 88 additions & 0 deletions src/views/consent/ConsentModal-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from 'react'
import { render, screen } from 'src/utilities/testingLibrary'
import { ConsentModal } from 'src/views/consent/ConsentModal'
import * as globalUtils from 'src/utilities/global'

vi.mock('src/utilities/global', () => ({
goToUrlLink: vi.fn(),
}))

describe('ConsentModal', () => {
const mockSetDialogIsOpen = vi.fn()
const defaultProps = {
dialogIsOpen: true,
setDialogIsOpen: mockSetDialogIsOpen,
}

beforeEach(() => {
vi.clearAllMocks()
})

describe('Rendering', () => {
it('should render the modal with its content when dialogIsOpen is true', () => {
render(<ConsentModal {...defaultProps} />)

expect(screen.getByText('Who is MX Technologies?')).toBeInTheDocument()
expect(
screen.getByText(
/MX is a trusted financial data platform that securely connects your accounts/i,
),
).toBeInTheDocument()
expect(screen.getByText('MX promise:')).toBeInTheDocument()
})

it('should render the secure, control, and private promise sections', () => {
render(<ConsentModal {...defaultProps} />)

expect(screen.getByText('Secure:')).toBeInTheDocument()
expect(
screen.getByText('Industry-standard encryption protects your data.'),
).toBeInTheDocument()
expect(screen.getByText('Control:')).toBeInTheDocument()
expect(screen.getByText('You can manage and revoke access anytime.')).toBeInTheDocument()
expect(screen.getByText('Private:')).toBeInTheDocument()
expect(
screen.getByText('Your data is never sold or shared without consent.'),
).toBeInTheDocument()
})

it('should not render the modal when dialogIsOpen is false', () => {
render(<ConsentModal {...defaultProps} dialogIsOpen={false} />)

expect(screen.queryByText('Who is MX Technologies?')).not.toBeInTheDocument()
})
})

describe('Interactions', () => {
it('should toggle dialogIsOpen when the Close button is clicked', async () => {
const { user } = render(<ConsentModal {...defaultProps} />)

await user.click(screen.getByText('Close'))

expect(mockSetDialogIsOpen).toHaveBeenCalledWith(expect.any(Function))

// The updater flips the previous open state.
const toggle = mockSetDialogIsOpen.mock.calls[0][0]
expect(toggle(true)).toBe(false)
expect(toggle(false)).toBe(true)
})

it('should toggle dialogIsOpen when the dialog is dismissed with Escape', async () => {
const { user } = render(<ConsentModal {...defaultProps} />)

expect(screen.getByRole('dialog')).toBeInTheDocument()

await user.keyboard('{Escape}')

expect(mockSetDialogIsOpen).toHaveBeenCalledWith(expect.any(Function))
})

it('should open the MX company page when Learn more is clicked', async () => {
const { user } = render(<ConsentModal {...defaultProps} />)

await user.click(screen.getByText('Learn more'))

expect(globalUtils.goToUrlLink).toHaveBeenCalledWith('https://www.mx.com/company/')
})
})
})
Loading
Loading