-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1043 from sophieturner0/unit-test-useMockSelfProf…
…ileStore [Unit Tests]: `useMockSelfProfileStore` and `StartUpModal`
- Loading branch information
Showing
2 changed files
with
320 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { renderHook } from '@testing-library/react-hooks'; | ||
import { useStores } from 'store'; | ||
import { waitFor } from '@testing-library/react'; | ||
import { user } from '__test__/__mockData__/user'; | ||
import { useMockSelfProfileStore } from './__mockStore__/useMockSelfProfileStore'; | ||
|
||
jest.mock('store'); | ||
|
||
describe('useMockSelfProfileStore', () => { | ||
const mockSetMeInfo = jest.fn(); | ||
const mockSetSelectedPerson = jest.fn(); | ||
const mockSetActivePerson = jest.fn(); | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
|
||
(useStores as jest.Mock).mockReturnValue({ | ||
ui: { | ||
setMeInfo: mockSetMeInfo, | ||
setSelectedPerson: mockSetSelectedPerson | ||
}, | ||
main: { | ||
setActivePerson: mockSetActivePerson | ||
} | ||
}); | ||
}); | ||
|
||
it('should set store values when enabled is true', () => { | ||
renderHook(() => useMockSelfProfileStore({ enabled: true })); | ||
|
||
expect(mockSetMeInfo).toHaveBeenCalledWith(user); | ||
expect(mockSetSelectedPerson).toHaveBeenCalledWith(user.id); | ||
expect(mockSetActivePerson).toHaveBeenCalledWith( | ||
expect.objectContaining({ | ||
...user, | ||
unique_name: expect.any(String), | ||
tags: [] | ||
}) | ||
); | ||
|
||
expect(mockSetMeInfo).toHaveBeenCalledTimes(1); | ||
expect(mockSetSelectedPerson).toHaveBeenCalledTimes(1); | ||
expect(mockSetActivePerson).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
it('should not set store values when enabled is false', () => { | ||
renderHook(() => useMockSelfProfileStore({ enabled: false })); | ||
|
||
expect(mockSetMeInfo).not.toHaveBeenCalled(); | ||
expect(mockSetSelectedPerson).not.toHaveBeenCalled(); | ||
expect(mockSetActivePerson).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should handle re-renders without duplicate calls', () => { | ||
const { rerender } = renderHook(() => useMockSelfProfileStore({ enabled: true })); | ||
|
||
expect(mockSetMeInfo).toHaveBeenCalledTimes(1); | ||
expect(mockSetSelectedPerson).toHaveBeenCalledTimes(1); | ||
expect(mockSetActivePerson).toHaveBeenCalledTimes(1); | ||
|
||
rerender(); | ||
|
||
expect(mockSetMeInfo).toHaveBeenCalledTimes(1); | ||
expect(mockSetSelectedPerson).toHaveBeenCalledTimes(1); | ||
expect(mockSetActivePerson).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
it('should handle enabled prop changes', () => { | ||
const { rerender } = renderHook( | ||
({ enabled }: { enabled: boolean }) => useMockSelfProfileStore({ enabled }), | ||
{ | ||
initialProps: { enabled: false } | ||
} | ||
); | ||
|
||
expect(mockSetMeInfo).not.toHaveBeenCalled(); | ||
|
||
rerender({ enabled: true }); | ||
|
||
expect(mockSetMeInfo).toHaveBeenCalledWith(user); | ||
expect(mockSetSelectedPerson).toHaveBeenCalledWith(user.id); | ||
expect(mockSetActivePerson).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should generate unique name for each call when enabled', () => { | ||
const { rerender } = renderHook( | ||
({ enabled }: { enabled: boolean }) => useMockSelfProfileStore({ enabled }), | ||
{ | ||
initialProps: { enabled: true } | ||
} | ||
); | ||
|
||
const firstCall = mockSetActivePerson.mock.calls[0][0].unique_name; | ||
|
||
rerender({ enabled: true }); | ||
|
||
waitFor(() => { | ||
const secondCall = mockSetActivePerson.mock.calls[1][0].unique_name; | ||
|
||
expect(firstCall).not.toBe(secondCall); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
import React from 'react'; | ||
import '@testing-library/jest-dom'; | ||
import { render, screen, fireEvent, waitFor, act } from '@testing-library/react'; | ||
import StartUpModal from '../StartUpModal'; | ||
import api from '../../../api'; | ||
import { useStores } from '../../../store'; | ||
|
||
jest.mock('../../../api'); | ||
jest.mock('../../../store'); | ||
jest.mock('mobx-react-lite', () => ({ | ||
observer: (component: any) => component | ||
})); | ||
|
||
const mockOpen = jest.fn(); | ||
window.open = mockOpen; | ||
|
||
describe('StartUpModal', () => { | ||
const mockCloseModal = jest.fn(); | ||
const mockSetShowSignIn = jest.fn(); | ||
const mockDataObject = 'test-data'; | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
(useStores as jest.Mock).mockReturnValue({ | ||
ui: { | ||
meInfo: null, | ||
setShowSignIn: mockSetShowSignIn | ||
} | ||
}); | ||
}); | ||
|
||
it('renders initial state (StepTwo view) correctly', () => { | ||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
waitFor(() => { | ||
expect(screen.getByTestId('step-two')).toBeInTheDocument(); | ||
expect(screen.getByText('Step 1')).toBeInTheDocument(); | ||
expect(screen.getByText('Download App')).toBeInTheDocument(); | ||
expect(screen.getByText('Android')).toBeInTheDocument(); | ||
expect(screen.getByText('IOS')).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
it('opens correct URL when Android button is clicked', () => { | ||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
fireEvent.click(screen.getByText('Android')); | ||
expect(mockOpen).toHaveBeenCalledWith( | ||
'https://play.google.com/store/apps/details?id=chat.sphinx.v2&hl=en_US', | ||
'_blank' | ||
); | ||
}); | ||
|
||
it('opens correct URL when IOS button is clicked', () => { | ||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
fireEvent.click(screen.getByText('IOS')); | ||
expect(mockOpen).toHaveBeenCalledWith('https://testflight.apple.com/join/p721ALD9', '_blank'); | ||
}); | ||
|
||
it('calls API and changes step when Reveal Connection Code is clicked', async () => { | ||
(api.get as jest.Mock).mockResolvedValueOnce({ connection_string: 'test-connection-string' }); | ||
|
||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
fireEvent.click(screen.getByText('Reveal Connection Code')); | ||
|
||
waitFor(() => { | ||
expect(api.get).toHaveBeenCalledWith('connectioncodes'); | ||
expect(screen.getByTestId('qrcode')).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
it('handles case when API returns no connection string', async () => { | ||
(api.get as jest.Mock).mockResolvedValueOnce({ connection_string: '' }); | ||
|
||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
fireEvent.click(screen.getByText('Reveal Connection Code')); | ||
|
||
waitFor(() => { | ||
expect( | ||
screen.getByText('We are out of codes to sign up! Please check again later.') | ||
).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
it('resets step when Back button is clicked in QR view', async () => { | ||
(api.get as jest.Mock).mockResolvedValueOnce({ connection_string: 'test-connection-string' }); | ||
|
||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
fireEvent.click(screen.getByText('Reveal Connection Code')); | ||
waitFor(() => { | ||
expect(screen.getByTestId('qrcode')).toBeInTheDocument(); | ||
}); | ||
|
||
fireEvent.click(screen.getByText('Back')); | ||
waitFor(() => { | ||
expect(screen.getByTestId('step-two')).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
it('calls closeModal and setShowSignIn when Sign in button is clicked', () => { | ||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
fireEvent.click(screen.getByText('Sign in')); | ||
|
||
expect(mockCloseModal).toHaveBeenCalled(); | ||
expect(mockSetShowSignIn).toHaveBeenCalledWith(true); | ||
}); | ||
|
||
it('does not call API when ui.meInfo exists', async () => { | ||
(useStores as jest.Mock).mockReturnValue({ | ||
ui: { | ||
meInfo: { some: 'data' }, | ||
setShowSignIn: mockSetShowSignIn | ||
} | ||
}); | ||
|
||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
fireEvent.click(screen.getByText('Reveal Connection Code')); | ||
waitFor(() => { | ||
expect(api.get).not.toHaveBeenCalled(); | ||
}); | ||
}); | ||
|
||
it('does not call API when connection_string already exists', async () => { | ||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
(api.get as jest.Mock).mockResolvedValueOnce({ connection_string: 'test-connection-string' }); | ||
|
||
await act(async () => { | ||
fireEvent.click(screen.getByText('Reveal Connection Code')); | ||
}); | ||
|
||
await waitFor(() => { | ||
expect(api.get).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
fireEvent.click(screen.getByText('Back')); | ||
|
||
await act(async () => { | ||
fireEvent.click(screen.getByText('Reveal Connection Code')); | ||
}); | ||
|
||
await waitFor(() => { | ||
expect(api.get).toHaveBeenCalledTimes(1); | ||
}); | ||
}); | ||
|
||
it('updates step when clicking on Android button', () => { | ||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
fireEvent.click(screen.getByText('Android')); | ||
expect(screen.getByText('Step 2')).toBeInTheDocument(); | ||
}); | ||
|
||
it('updates step when clicking on IOS button', () => { | ||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
fireEvent.click(screen.getByText('IOS')); | ||
expect(screen.getByText('Step 2')).toBeInTheDocument(); | ||
}); | ||
|
||
it('handles empty connection string response', async () => { | ||
(api.get as jest.Mock).mockResolvedValueOnce({ connection_string: '' }); | ||
|
||
render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
await act(async () => { | ||
fireEvent.click(screen.getByText('Reveal Connection Code')); | ||
}); | ||
|
||
await screen.findByText('We are out of codes to sign up! Please check again later.'); | ||
}); | ||
|
||
it('maintains step state between renders', () => { | ||
const { rerender } = render( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
fireEvent.click(screen.getByText('Android')); | ||
expect(screen.getByText('Step 2')).toBeInTheDocument(); | ||
|
||
rerender( | ||
<StartUpModal closeModal={mockCloseModal} buttonColor="primary" dataObject={mockDataObject} /> | ||
); | ||
|
||
expect(screen.getByText('Step 2')).toBeInTheDocument(); | ||
}); | ||
}); |