Skip to content

Commit

Permalink
setup jest (2 tests) and separate jobs
Browse files Browse the repository at this point in the history
  • Loading branch information
dinakar17 committed Jul 12, 2024
1 parent 22d3800 commit 7957f81
Show file tree
Hide file tree
Showing 12 changed files with 10,082 additions and 83 deletions.
39 changes: 0 additions & 39 deletions .github/ci.yml

This file was deleted.

18 changes: 17 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
- cron: '0 0 * * 1' # Runs every Monday at midnight UTC

jobs:
lint-and-test:
lint:
runs-on: ubuntu-latest

steps:
Expand All @@ -35,5 +35,21 @@ jobs:
- name: Check for TypeScript errors
run: yarn tsc --noEmit

test:
runs-on: ubuntu-latest
needs: lint

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 20.11.1

- name: Install dependencies
run: yarn install

- name: Run tests
run: yarn test
18 changes: 0 additions & 18 deletions jest-config.js

This file was deleted.

24 changes: 24 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Config } from 'jest';
import nextJest from 'next/jest.js';

const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
});

// Add any custom config to be passed to Jest
const config: Config = {
collectCoverage: true,
coverageDirectory: 'coverage',
moduleNameMapper: { // Handle Module Path Aliases
'^@/(.*)$': '<rootDir>/$1',
'^next/router$': '<rootDir>/tests/__mocks__/router.ts',
},
coverageProvider: 'v8',
testEnvironment: 'jsdom',
// Add more setup options before each test is run
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
};

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
export default createJestConfig(config);
43 changes: 42 additions & 1 deletion jest.setup.ts
Original file line number Diff line number Diff line change
@@ -1 +1,42 @@
import '@testing-library/jest-dom/extend-expect'
import '@testing-library/jest-dom';

class IntersectionObserver {
root: Element | Document | null;
rootMargin: string;
thresholds: ReadonlyArray<number>;
callback: IntersectionObserverCallback;
options?: IntersectionObserverInit;

constructor(callback: IntersectionObserverCallback, options?: IntersectionObserverInit) {
this.callback = callback;
this.options = options;
this.root = options?.root || null;
this.rootMargin = options?.rootMargin || '0px';
this.thresholds = options?.threshold ? (Array.isArray(options.threshold) ? options.threshold : [options.threshold]) : [0];
}

observe(target: Element) {
const entry: IntersectionObserverEntry = {
time: Date.now(),
target,
isIntersecting: true,
intersectionRatio: 1,
intersectionRect: target.getBoundingClientRect(),
boundingClientRect: target.getBoundingClientRect(),
rootBounds: this.root ? (this.root as Element).getBoundingClientRect() : null,
};
this.callback([entry], this);
}

unobserve() {}

disconnect() {}

takeRecords(): IntersectionObserverEntry[] {
return [];
}
}

(global as any).IntersectionObserver = IntersectionObserver;

export {};
19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@radix-ui/react-tooltip": "^1.0.7",
"@remixicon/react": "^4.2.0",
"@tanstack/react-query": "^5.40.0",
"@testing-library/user-event": "^14.5.2",
"@tiptap/extension-placeholder": "^2.4.0",
"@tiptap/extension-underline": "^2.4.0",
"@tiptap/pm": "^2.4.0",
Expand Down Expand Up @@ -61,6 +62,9 @@
"devDependencies": {
"@faker-js/faker": "^8.4.1",
"@tailwindcss/forms": "^0.5.7",
"@testing-library/dom": "^10.3.1",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.0",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/jest": "^29.5.12",
"@types/js-cookie": "^3.0.6",
Expand All @@ -72,9 +76,13 @@
"eslint": "^8.57.0",
"eslint-config-next": "14.2.3",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jest-dom": "^5.0.2",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-testing-library": "^6.0.0",
"husky": "^9.0.11",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"lint-staged": "^15.2.2",
"msw": "^2.3.0",
"orval": "^6.29.1",
Expand All @@ -83,15 +91,8 @@
"prettier-plugin-tailwindcss": "^0.5.14",
"tailwindcss": "^3.4.1",
"tailwindcss-animate": "^1.0.7",
"ts-jest": "^29.2.2",
"ts-node": "^10.9.2",
"typescript": "^5",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"eslint-plugin-jest-dom": "^5.0.2",
"eslint-plugin-testing-library": "^6.0.0",
"jest": "^29.6.2",
"jest-environment-jsdom": "^29.6.2",
"ts-jest": "^29.1.1"
"typescript": "^5"
}
}
22 changes: 22 additions & 0 deletions src/tests/__mocks__/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// __mocks__/next/router.ts
const useRouter = () => {
return {
route: '/',
pathname: '',
query: '',
asPath: '',
push: jest.fn(),
replace: jest.fn(),
reload: jest.fn(),
back: jest.fn(),
prefetch: jest.fn().mockResolvedValue(undefined),
beforePopState: jest.fn(),
events: {
on: jest.fn(),
off: jest.fn(),
emit: jest.fn(),
},
};
};

export { useRouter };
60 changes: 60 additions & 0 deletions src/tests/__tests__/Footer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react';

import { render, screen } from '@testing-library/react';

import Footer from '@/components/Footer';

// Mock the next/link component
jest.mock('next/link', () => {
const MockLink = ({ children, href }: { children: React.ReactNode; href: string }) => {
return <a href={href}>{children}</a>;
};
MockLink.displayName = 'MockLink';
return MockLink;
});

describe('Footer', () => {
it('renders without crashing', () => {
render(<Footer />);
});

it('displays all navigation links', () => {
render(<Footer />);
const links = ['Home', 'Articles', 'Communities', 'Posts', 'About', 'Login', 'Register'];
links.forEach((link) => {
expect(screen.getByText(link)).toBeInTheDocument();
});
});

it('displays social media icons', () => {
render(<Footer />);
const socialMediaPlatforms = ['Facebook', 'Youtube', 'Instagram', 'Twitter'];
socialMediaPlatforms.forEach((platform) => {
expect(screen.getByText(platform, { selector: 'span' })).toBeInTheDocument();
});
});

it('displays copyright information', () => {
render(<Footer />);
expect(screen.getByText(/© 2023 SciCommons. All rights reserved./)).toBeInTheDocument();
});

it('displays Terms and Conditions link', () => {
render(<Footer />);
expect(screen.getByText('Terms and Conditions')).toBeInTheDocument();
});

it('displays Privacy Policy link', () => {
render(<Footer />);
expect(screen.getByText('Privacy Policy')).toBeInTheDocument();
});

it('applies correct CSS classes for light mode', () => {
render(<Footer />);
const footer = screen.getByRole('contentinfo');
expect(footer).toHaveClass('bg-gray-200');
});

// Note: Testing dark mode might require additional setup or a different approach
// as it often depends on a theme context or CSS variables
});
79 changes: 79 additions & 0 deletions src/tests/__tests__/FormInput.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from 'react';

import { render, screen } from '@testing-library/react';

import FormInput from '@/components/FormInput';

// No need to mock the tooltip components anymore

describe('FormInput', () => {
const mockRegister = jest.fn();
const mockErrors = {};

const defaultProps = {
name: 'testInput',
type: 'text',
placeholder: 'Enter text',
register: mockRegister,
requiredMessage: 'This field is required',
errors: mockErrors,
};

it('renders input field correctly', () => {
render(<FormInput {...defaultProps} />);
expect(screen.getByPlaceholderText('Enter text')).toBeInTheDocument();
});

it('renders label when provided', () => {
render(<FormInput {...defaultProps} label="Test Label" />);
expect(screen.getByText('Test Label')).toBeInTheDocument();
});

it('renders textarea when textArea prop is true', () => {
render(<FormInput {...defaultProps} textArea={true} />);
expect(screen.getByRole('textbox')).toHaveProperty('tagName', 'TEXTAREA');
});

it('applies readonly attribute when readOnly prop is true', () => {
render(<FormInput {...defaultProps} readOnly={true} />);
expect(screen.getByRole('textbox')).toHaveAttribute('readonly');
});

it('displays error message when there is an error', () => {
const errorsWithMessage = { testInput: { message: 'Error message' } };
render(<FormInput {...defaultProps} errors={errorsWithMessage} />);
expect(screen.getByText('Error message')).toBeInTheDocument();
});

it('calls register function with correct parameters', () => {
render(
<FormInput
{...defaultProps}
patternValue={/test/}
patternMessage="Invalid pattern"
minLengthValue={5}
minLengthMessage="Too short"
maxLengthValue={10}
maxLengthMessage="Too long"
/>
);
expect(mockRegister).toHaveBeenCalledWith('testInput', {
required: 'This field is required',
pattern: { value: /test/, message: 'Invalid pattern' },
minLength: { value: 5, message: 'Too short' },
maxLength: { value: 10, message: 'Too long' },
});
});

it('applies error styles when there is an error', () => {
const errorsWithMessage = { testInput: { message: 'Error message' } };
render(<FormInput {...defaultProps} errors={errorsWithMessage} />);
expect(screen.getByRole('textbox')).toHaveClass('border-red-500');
});

it('does not apply error styles when readOnly is true, even if there is an error', () => {
const errorsWithMessage = { testInput: { message: 'Error message' } };
render(<FormInput {...defaultProps} errors={errorsWithMessage} readOnly={true} />);
expect(screen.getByRole('textbox')).not.toHaveClass('border-red-500');
});
});
14 changes: 0 additions & 14 deletions src/tests/app/__tests__/page.test.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "jest.config.ts", "jest.setup.ts"],
"exclude": ["node_modules"]
}
Loading

0 comments on commit 7957f81

Please sign in to comment.