diff --git a/jest.config.js b/jest.config.js index b51f6e5..4b8dd5d 100644 --- a/jest.config.js +++ b/jest.config.js @@ -55,20 +55,27 @@ module.exports = { '!src/testUtils/**/*', ], moduleNameMapper: { - '@assets/(.*)': '/src/assets/$1', - '@assets': '/src/assets', - '@screens': '/src/screens', - '@services': '/src/services', - '@screens/(.*)': '/src/screens/$1', - '@data': '/src/data', - '@hooks': '/src/hooks', - '@store/slice': '/src/store/slice', - '@store': '/src/store', - '@selectors': '/src/store/selectors', - '@components': '/src/components', - '@localization': '/src/localization', - '@providers': '/src/providers', - '@router': '/src/router', + '^@assets/(.*)$': '/src/assets/$1', + '^@assets$': '/src/assets', + '^@screens/(.*)$': '/src/screens/$1', + '^@screens$': '/src/screens', + '^@services/(.*)$': '/src/services/$1', + '^@services$': '/src/services', + '^@data/(.*)$': '/src/data/$1', + '^@data$': '/src/data', + '^@hooks/(.*)$': '/src/hooks/$1', + '^@hooks$': '/src/hooks', + '^@store/slice$': '/src/store/slice', + '^@store$': '/src/store', + '^@selectors$': '/src/store/selectors', + '^@components/(.*)$': '/src/components/$1', + '^@components$': '/src/components', + '^@localization/(.*)$': '/src/localization/$1', + '^@localization$': '/src/localization', + '^@providers/(.*)$': '/src/providers/$1', + '^@providers$': '/src/providers', + '^@router/(.*)$': '/src/router/$1', + '^@router$': '/src/router', '^.+.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', }, diff --git a/jest.js b/jest.js index 4a3647c..d3c307f 100644 --- a/jest.js +++ b/jest.js @@ -53,4 +53,12 @@ global.ResizeObserver = class ResizeObserver { disconnect = jest.fn(); }; - +global.IntersectionObserver = class IntersectionObserver { + root = null; + rootMargin = ''; + thresholds = []; + observe = jest.fn(); + unobserve = jest.fn(); + disconnect = jest.fn(); + takeRecords = jest.fn().mockReturnValue([]); +}; diff --git a/src/assets/icons/Common/CheckIcon.tsx b/src/assets/icons/Common/CheckIcon.tsx new file mode 100644 index 0000000..77fd79f --- /dev/null +++ b/src/assets/icons/Common/CheckIcon.tsx @@ -0,0 +1,19 @@ +import { SVGProps } from 'react'; + +const CheckIcon = (props: SVGProps) => ( + + + +); + +export default CheckIcon; diff --git a/src/assets/icons/Common/CodeChefIcon.tsx b/src/assets/icons/Common/CodeChefIcon.tsx new file mode 100644 index 0000000..62804c1 --- /dev/null +++ b/src/assets/icons/Common/CodeChefIcon.tsx @@ -0,0 +1,18 @@ +import { SVGProps } from 'react'; + +const CodeChefIcon = ({ + fill = 'currentColor', + ...props +}: SVGProps) => ( + + + +); + +export default CodeChefIcon; diff --git a/src/assets/icons/Common/CodeforcesIcon.tsx b/src/assets/icons/Common/CodeforcesIcon.tsx new file mode 100644 index 0000000..f7fa832 --- /dev/null +++ b/src/assets/icons/Common/CodeforcesIcon.tsx @@ -0,0 +1,28 @@ +import { SVGProps } from 'react'; + +const CodeforcesIcon = ({ + fill, + ...props +}: SVGProps) => ( + + + + + +); + +export default CodeforcesIcon; diff --git a/src/assets/icons/Common/CopyIcon.tsx b/src/assets/icons/Common/CopyIcon.tsx new file mode 100644 index 0000000..f4093b4 --- /dev/null +++ b/src/assets/icons/Common/CopyIcon.tsx @@ -0,0 +1,20 @@ +import { SVGProps } from 'react'; + +const CopyIcon = (props: SVGProps) => ( + + + + +); + +export default CopyIcon; diff --git a/src/assets/icons/Common/__tests__/Common.test.tsx b/src/assets/icons/Common/__tests__/Common.test.tsx index 7ed5872..5679b4d 100644 --- a/src/assets/icons/Common/__tests__/Common.test.tsx +++ b/src/assets/icons/Common/__tests__/Common.test.tsx @@ -2,6 +2,10 @@ import { render } from '@testing-library/react'; import { SearchIcon } from '../Search'; import { ThreeDIcon } from '../3D'; import { TwoDIcon } from '../2D'; +import CodeChefIcon from '../CodeChefIcon'; +import CodeforcesIcon from '../CodeforcesIcon'; +import CopyIcon from '../CopyIcon'; +import CheckIcon from '../CheckIcon'; describe('Common Icon', () => { it(' `SearchIcon` renders correctly', () => { @@ -21,4 +25,28 @@ describe('Common Icon', () => { expect(container).toMatchSnapshot(); }); + + it(' `CodeChefIcon` renders correctly', () => { + const { container } = render(); + + expect(container).toMatchSnapshot(); + }); + + it(' `CodeforcesIcon` renders correctly', () => { + const { container } = render(); + + expect(container).toMatchSnapshot(); + }); + + it(' `CopyIcon` renders correctly', () => { + const { container } = render(); + + expect(container).toMatchSnapshot(); + }); + + it(' `CheckIcon` renders correctly', () => { + const { container } = render(); + + expect(container).toMatchSnapshot(); + }); }); diff --git a/src/assets/icons/Common/__tests__/__snapshots__/Common.test.tsx.snap b/src/assets/icons/Common/__tests__/__snapshots__/Common.test.tsx.snap index 1c96e2f..374b22c 100644 --- a/src/assets/icons/Common/__tests__/__snapshots__/Common.test.tsx.snap +++ b/src/assets/icons/Common/__tests__/__snapshots__/Common.test.tsx.snap @@ -1,5 +1,89 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Common Icon \`CheckIcon\` renders correctly 1`] = ` +
+ + + +
+`; + +exports[`Common Icon \`CodeChefIcon\` renders correctly 1`] = ` +
+ + + +
+`; + +exports[`Common Icon \`CodeforcesIcon\` renders correctly 1`] = ` +
+ + + + + +
+`; + +exports[`Common Icon \`CopyIcon\` renders correctly 1`] = ` +
+ + + + +
+`; + exports[`Common Icon \`SearchIcon\` renders correctly 1`] = `
{ @@ -44,7 +46,8 @@ const LinkButton = ({ fontWeight={'300'} borderRadius={0} overflow={'clip'} - px={2} + px={px ?? { base: 1, sm: 1.5, md: 2 }} + minW={minW ?? 'auto'} maxHeight={'7'} _hover={{ color: 'violet' }} borderBottom={withUnderline ? '1px solid white' : 'none'} diff --git a/src/components/Button/LinkButton/types.ts b/src/components/Button/LinkButton/types.ts index 45c3182..1b4ac02 100644 --- a/src/components/Button/LinkButton/types.ts +++ b/src/components/Button/LinkButton/types.ts @@ -6,5 +6,7 @@ export type LinkButtonProps = { withArrow?: boolean; href?: string; fontSize?: BoxProps['fontSize']; + px?: BoxProps['px']; + minW?: BoxProps['minW']; onClick?: (target: string) => void; }; diff --git a/src/components/CardComponent/CardExport.tsx b/src/components/CardComponent/CardExport.tsx index 8230bbc..4134f2e 100644 --- a/src/components/CardComponent/CardExport.tsx +++ b/src/components/CardComponent/CardExport.tsx @@ -2,8 +2,8 @@ import { useRef, useState } from 'react'; import { useCursor } from '../Cursor'; import { CardBasic } from './Card'; import { CardExportProps } from './types'; -import { Box, Button, HStack, Text, Wrap } from '@chakra-ui/react'; -import { Chip, Language } from '../Chip'; +import { Box, Button, Flex, HStack, Text, Wrap } from '@chakra-ui/react'; +import { Chip } from '../Chip'; import { Link } from 'react-router-dom'; import { PROJECT_NAME_ICON_MAP } from '@assets'; import { Status } from '@data'; @@ -122,11 +122,12 @@ const Card = ({ )} - @@ -141,10 +142,20 @@ const Card = ({ > {titleText} - + )} -
); diff --git a/src/components/CardComponent/__tests__/CardExport.test.tsx b/src/components/CardComponent/__tests__/CardExport.test.tsx new file mode 100644 index 0000000..535bcc1 --- /dev/null +++ b/src/components/CardComponent/__tests__/CardExport.test.tsx @@ -0,0 +1,51 @@ +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { MemoryRouter } from 'react-router-dom'; +import Card from '../CardExport'; +import { Language } from '../../Chip'; +import { Status } from '@data'; + +jest.mock('../../Cursor', () => ({ + useCursor: () => ({ + setCursorInsets: jest.fn(), + }), +})); + +describe('Card (CardExport)', () => { + const defaultProps = { + titleText: 'Portfolio Site', + chips: [Language.typescript, Language.react], + centerText: 'PF', + icon: 'portfolio', + description: 'A personal portfolio website showcasing projects and blogs.', + link: 'https://example.com', + npmLink: 'https://npmjs.com/package/test', + status: Status.LIVE, + }; + + it('should render the card with title, description, and Know More button', () => { + render( + + + , + ); + + expect(screen.getByText('Portfolio Site')).toBeInTheDocument(); + expect(screen.getByText(defaultProps.description)).toBeInTheDocument(); + + const knowMoreBtn = screen.getByRole('link', { name: /know more/i }); + expect(knowMoreBtn).toBeInTheDocument(); + expect(knowMoreBtn).toHaveAttribute('href', '/projects/portfolio'); + }); + + it('should render live status badge and npm link when provided', () => { + render( + + + , + ); + + expect(screen.getByText(Status.LIVE)).toBeInTheDocument(); + expect(screen.getByText('NPM')).toBeInTheDocument(); + }); +}); diff --git a/src/components/Chip/Chip.tsx b/src/components/Chip/Chip.tsx index 880a83a..c1de92b 100644 --- a/src/components/Chip/Chip.tsx +++ b/src/components/Chip/Chip.tsx @@ -101,16 +101,16 @@ export const ChipMap: Record< title: 'Tauri', Icon: (props: SVGProps) => , }, - [Skills.more]: { - title: 'More...', - Icon: (_props: SVGProps) => <>, - }, }; const Chip = ({ type, size = 'md' }: ChipProps) => { const isMd = size === 'md'; const isSm = size === 'sm'; - const { title, Icon } = ChipMap[type]; + const chip = ChipMap[type] || { + title: type, + Icon: () => null, + }; + const { title, Icon } = chip; return ( { '0 6px 16px 0 rgba(0, 0, 0, 0.25), inset 0 1px 1px 0 rgba(255, 255, 255, 0.1)', }} > - {type !== Skills.more && ( - - )} + @@ -36,9 +36,14 @@ const Marquee = ({
Test container
Test container
Test container
Test container
@@ -33,206 +37,246 @@ exports[`Marquee should render the Marquee component 1`] = ` exports[`Marquee should render the Marquee component 2`] = `
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
@@ -243,206 +287,246 @@ exports[`Marquee should render the Marquee component 2`] = ` exports[`Marquee should render the Marquee component with horizontal direction 1`] = `
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
@@ -453,206 +537,246 @@ exports[`Marquee should render the Marquee component with horizontal direction 1 exports[`Marquee should render the Marquee component with reverse false 1`] = `
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
@@ -663,206 +787,246 @@ exports[`Marquee should render the Marquee component with reverse false 1`] = ` exports[`Marquee should render the Marquee component with vertical direction 1`] = `
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
@@ -873,206 +1037,246 @@ exports[`Marquee should render the Marquee component with vertical direction 1`] exports[`Marquee should render the Marquee component without hover 1`] = `
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
Test container
diff --git a/src/components/animateModal/AnimatedModal.tsx b/src/components/animateModal/AnimatedModal.tsx index e76a3c0..4ae4c3f 100644 --- a/src/components/animateModal/AnimatedModal.tsx +++ b/src/components/animateModal/AnimatedModal.tsx @@ -39,7 +39,7 @@ export function Modal({ children }: { children: ReactNode }) { export const ModalTrigger = ({ children, - className, + className = '', }: { children: ReactNode; className?: string; @@ -47,10 +47,7 @@ export const ModalTrigger = ({ const { setOpen } = useModal(); return (