diff --git a/src/components/@atoms/ExpandableSection/ExpandableSection.test.tsx b/src/components/@atoms/ExpandableSection/ExpandableSection.test.tsx
new file mode 100644
index 000000000..bd4dd4910
--- /dev/null
+++ b/src/components/@atoms/ExpandableSection/ExpandableSection.test.tsx
@@ -0,0 +1,14 @@
+import { render, screen, userEvent} from '@app/test-utils'
+import { ExpandableSection } from './ExpandableSection'
+
+describe('ExpandableSection', () => {
+ it('should expand and close when header is clicked', async () => {
+ render(CONTENT)
+ const header = screen.getByRole('button', { name: /Test/i })
+ expect(screen.getByText('CONTENT')).not.toBeVisible()
+ await userEvent.click(header)
+ expect(screen.getByText('CONTENT')).toBeVisible()
+ await userEvent.click(header)
+ expect(screen.getByText('CONTENT')).not.toBeVisible()
+ })
+})
\ No newline at end of file
diff --git a/src/components/@atoms/PseudoActionButton/PseudoActionButton.test.tsx b/src/components/@atoms/PseudoActionButton/PseudoActionButton.test.tsx
new file mode 100644
index 000000000..c54104f37
--- /dev/null
+++ b/src/components/@atoms/PseudoActionButton/PseudoActionButton.test.tsx
@@ -0,0 +1,43 @@
+import { act, render, screen, userEvent, waitFor} from '@app/test-utils'
+import { PseudoActionButton } from './PseudoActionButton'
+
+beforeAll(() => {
+ jest.useFakeTimers()
+})
+
+afterAll(() => {
+ jest.useRealTimers()
+})
+
+describe('PseudoActionButton', () => {
+ it('should show loading state when clicked and reset after timeout has been run', async () => {
+ const testIcon =
+ render(Test)
+ const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime})
+ const button = screen.getByRole('button', { name: /Test/i })
+ const icon = screen.getByTestId('icon')
+ expect(icon).toBeVisible()
+ await user.click(button)
+ expect(icon).not.toBeVisible()
+ act(() => {
+ jest.runAllTimers()
+ })
+ await waitFor(() => {
+ expect(screen.getByTestId('icon')).toBeVisible()
+ })
+ })
+
+ it('should maintain loading state if loading is set to true', async () => {
+ const testIcon =
+ render(Test)
+ const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime})
+ const button = screen.getByRole('button', { name: /Test/i })
+ expect(screen.queryByTestId('icon')).toEqual(null)
+ await user.click(button)
+ expect(screen.queryByTestId('icon')).toEqual(null)
+ act(() => {
+ jest.runAllTimers()
+ })
+ expect(screen.queryByTestId('icon')).toEqual(null)
+ })
+})
\ No newline at end of file
diff --git a/src/components/@atoms/PseudoActionButton/PseudoActionButton.tsx b/src/components/@atoms/PseudoActionButton/PseudoActionButton.tsx
index 267bd52c6..beb66c1ba 100644
--- a/src/components/@atoms/PseudoActionButton/PseudoActionButton.tsx
+++ b/src/components/@atoms/PseudoActionButton/PseudoActionButton.tsx
@@ -1,20 +1,27 @@
-import { ComponentProps, useEffect, useState } from 'react'
+import { ComponentProps, useEffect, useRef, useState } from 'react'
import { Button } from '@ensdomains/thorin'
-type Props = ComponentProps
+type Props = { timeout?: number } & ComponentProps
-export const PseudoActionButton = ({ loading, onClick, ...props }: Props) => {
+export const PseudoActionButton = ({ loading, onClick, timeout = 3000, ...props }: Props) => {
const [pseudoLoading, setPseudoLoading] = useState(false)
+
+ const timerRef = useRef | null>(null)
useEffect(() => {
- if (pseudoLoading) setTimeout(() => setPseudoLoading(false), 5000)
- }, [pseudoLoading, setPseudoLoading])
+ return () => {
+ if (timerRef.current) clearTimeout(timerRef.current)
+ }
+ }, [])
+
return (