diff --git a/__tests__/components/Navbar.test.tsx b/__tests__/components/Navbar.test.tsx index 8ef8642..bd1253e 100644 --- a/__tests__/components/Navbar.test.tsx +++ b/__tests__/components/Navbar.test.tsx @@ -1,13 +1,15 @@ -import React from 'react'; -import Navbar from '@/components/Navbar/'; -import { render, screen, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom'; +import { fireEvent, render, screen } from '@testing-library/react'; + +import Navbar from '@/components/Navbar/'; +import React from 'react'; + describe('Navbar', () => { it('should render', () => { const { container } = render(); expect(container).toHaveTextContent('URL Shortener'); - expect(container.querySelector('a')).toHaveAttribute('href', '#'); + expect(container.querySelector('a')).toHaveAttribute('href', '/'); }); it('should have dropdown menu', () => { diff --git a/__tests__/pages/[redirect].test.tsx b/__tests__/pages/[redirect].test.tsx new file mode 100644 index 0000000..04b7908 --- /dev/null +++ b/__tests__/pages/[redirect].test.tsx @@ -0,0 +1,49 @@ +import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; + +import Redirect from '../../src/pages/[redirect]/index'; +import { useRouter } from 'next/router'; + +jest.mock('next/router', () => ({ + useRouter: jest.fn(), +})); + +describe('Redirect Component', () => { + const mockRouterPush = jest.fn(); + const mockRouterReplace = jest.fn(); + const mockRouter = { + push: mockRouterPush, + replace: mockRouterReplace, + query: { redirect: 'ffdsfds' }, + }; + + beforeEach(() => { + (useRouter as jest.Mock).mockReturnValue(mockRouter); + }); + + test('redirects to original URL on Go button click', async () => { + render(); + const goButton = screen.getByText('Go'); + await act(async () => { + fireEvent.click(goButton); + }); + expect(mockRouterPush).toHaveBeenCalled(); + }); + + test('show tooltip on Go button click', async () => { + render(); + const goButton = screen.getByText('Go'); + await act(async () => { + fireEvent.click(goButton); + }); + expect(mockRouterPush).toHaveBeenCalled(); + const tooltip = screen.getByText('The skip feature is exclusively available to Premium users.'); + expect(tooltip).toBeInTheDocument(); + }); + + test('redirects when timer reaches zero', async () => { + jest.useFakeTimers(); + render(); + act(() => jest.advanceTimersByTime(5000)); + waitFor(() => expect(mockRouterPush).toHaveBeenCalled()); + }); +}); diff --git a/__tests__/utils/fetchOriginalUrl.test.ts b/__tests__/utils/fetchOriginalUrl.test.ts new file mode 100644 index 0000000..e66545e --- /dev/null +++ b/__tests__/utils/fetchOriginalUrl.test.ts @@ -0,0 +1,39 @@ +import fetchMock from 'jest-fetch-mock'; +import fetchOriginalUrl from '../../src/utils/fetchOriginalUrl'; +import { act } from 'react-dom/test-utils'; + +fetchMock.enableMocks(); + +describe('fetchOriginalUrl', () => { + const shortUrlCode = '442d39ac'; + const originalUrl = 'https://github.com/Real-Dev-Squad/tiny-site-frontend/pull/40'; + + it('fetches and displays the original URL if the response is successful', async () => { + const responseData = { url: { OriginalUrl: originalUrl } }; + + fetchMock.mockResponse(JSON.stringify(responseData), { status: 200 }); + + await act(async () => { + const result = await fetchOriginalUrl(shortUrlCode); + expect(result).toEqual(originalUrl); + }); + }); + + it('returns null if the response is not successful', async () => { + fetchMock.mockResponse('', { status: 404 }); + + await act(async () => { + const result = await fetchOriginalUrl(shortUrlCode); + expect(result).toBeNull(); + }); + }); + + it('handles errors gracefully', async () => { + fetchMock.mockReject(new Error('Network error')); + + await act(async () => { + const result = await fetchOriginalUrl(shortUrlCode); + expect(result).toBeNull(); + }); + }); +}); diff --git a/public/assets/icons/redirect.tsx b/public/assets/icons/redirect.tsx new file mode 100644 index 0000000..5f1c95c --- /dev/null +++ b/public/assets/icons/redirect.tsx @@ -0,0 +1,7 @@ +const RedirectIcon = () => ( + + + +); + +export default RedirectIcon; diff --git a/public/assets/icons/share.tsx b/public/assets/icons/share.tsx new file mode 100644 index 0000000..4de2c52 --- /dev/null +++ b/public/assets/icons/share.tsx @@ -0,0 +1,28 @@ +const ShareIcon = () => ( + + Visit + + + + +); + +export default ShareIcon; diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx index 354a723..5128682 100644 --- a/src/components/Footer/index.tsx +++ b/src/components/Footer/index.tsx @@ -1,3 +1,4 @@ +import Link from 'next/link'; import React from 'react'; const Footer: React.FC = () => { @@ -5,14 +6,14 @@ const Footer: React.FC = () => {

The contents of this website are deployed from this{' '} - open sourced repo - +

); diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 804aceb..7bd7946 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -1,10 +1,12 @@ import React, { useEffect, useState } from 'react'; +import { TINY_API_GOOGLE_LOGIN, TINY_API_LOGOUT } from '@/constants/url'; + import Button from '@/components/Button'; -import ProfileIcon from '../ProfileIcon/ProfileIcon'; -import GoogleIcon from '../../../public/assets/icons/google'; import DownArrowIcon from '../../../public/assets/icons/downArrow'; +import GoogleIcon from '../../../public/assets/icons/google'; import IsAuthenticated from '@/hooks/isAuthenticated'; -import { TINY_API_GOOGLE_LOGIN, TINY_API_LOGOUT } from '@/constants/url'; +import Link from 'next/link'; +import ProfileIcon from '../ProfileIcon/ProfileIcon'; const Navbar: React.FC = () => { const [menuOpen, setMenuOpen] = useState(false); @@ -30,9 +32,9 @@ const Navbar: React.FC = () => { return (