diff --git a/package.json b/package.json index fccb0aebe9..ffc6372b55 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,10 @@ "build": "vite build", "lint": "eslint", "serve": "vite preview", - "start": "vite" + "start": "vite", + "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage" }, "dependencies": { "@coreui/chartjs": "^4.1.0", @@ -39,6 +42,9 @@ "simplebar-react": "^3.3.2" }, "devDependencies": { + "@testing-library/dom": "^10.0.0", + "@testing-library/jest-dom": "^6.4.2", + "@testing-library/react": "^16.0.0", "@vitejs/plugin-react": "^5.1.2", "autoprefixer": "^10.4.23", "eslint": "^9.39.2", @@ -47,9 +53,11 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.0.1", "globals": "^16.5.0", + "jsdom": "^24.0.0", "postcss": "^8.5.6", "prettier": "3.7.4", "sass": "^1.97.0", - "vite": "^7.3.0" + "vite": "^7.3.0", + "vitest": "^1.3.1" } } diff --git a/src/components/AppFooter.test.jsx b/src/components/AppFooter.test.jsx new file mode 100644 index 0000000000..c846a8c076 --- /dev/null +++ b/src/components/AppFooter.test.jsx @@ -0,0 +1,33 @@ +import { describe, it, expect } from 'vitest' +import { render, screen } from '@testing-library/react' +import AppFooter from './AppFooter' + +describe('AppFooter', () => { + it('renders without crashing', () => { + render() + expect(screen.getByText('CoreUI')).toBeInTheDocument() + }) + + it('displays the copyright text', () => { + render() + expect(screen.getByText(/2025 creativeLabs/)).toBeInTheDocument() + }) + + it('contains CoreUI link with correct href', () => { + render() + const coreUILink = screen.getByRole('link', { name: 'CoreUI' }) + expect(coreUILink).toHaveAttribute('href', 'https://coreui.io') + expect(coreUILink).toHaveAttribute('target', '_blank') + }) + + it('contains CoreUI React Admin link', () => { + render() + const adminLink = screen.getByRole('link', { name: /CoreUI React Admin/ }) + expect(adminLink).toHaveAttribute('href', 'https://coreui.io/react') + }) + + it('displays "Powered by" text', () => { + render() + expect(screen.getByText('Powered by')).toBeInTheDocument() + }) +}) diff --git a/src/store.test.js b/src/store.test.js new file mode 100644 index 0000000000..116b3f22ce --- /dev/null +++ b/src/store.test.js @@ -0,0 +1,38 @@ +import { describe, it, expect } from 'vitest' +import store from './store' + +describe('Redux Store', () => { + it('has correct initial state', () => { + const state = store.getState() + expect(state).toEqual({ + sidebarShow: true, + theme: 'light', + }) + }) + + it('handles set action to update sidebarShow', () => { + store.dispatch({ type: 'set', sidebarShow: false }) + const state = store.getState() + expect(state.sidebarShow).toBe(false) + }) + + it('handles set action to update theme', () => { + store.dispatch({ type: 'set', theme: 'dark' }) + const state = store.getState() + expect(state.theme).toBe('dark') + }) + + it('handles set action with multiple properties', () => { + store.dispatch({ type: 'set', sidebarShow: true, theme: 'light' }) + const state = store.getState() + expect(state.sidebarShow).toBe(true) + expect(state.theme).toBe('light') + }) + + it('returns current state for unknown action types', () => { + const stateBefore = store.getState() + store.dispatch({ type: 'UNKNOWN_ACTION' }) + const stateAfter = store.getState() + expect(stateAfter).toEqual(stateBefore) + }) +}) diff --git a/src/test/setup.js b/src/test/setup.js new file mode 100644 index 0000000000..c44951a680 --- /dev/null +++ b/src/test/setup.js @@ -0,0 +1 @@ +import '@testing-library/jest-dom' diff --git a/vitest.config.mjs b/vitest.config.mjs new file mode 100644 index 0000000000..ab0a8c7234 --- /dev/null +++ b/vitest.config.mjs @@ -0,0 +1,32 @@ +import { defineConfig } from 'vitest/config' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], + esbuild: { + loader: 'jsx', + include: /src\/.*\.jsx?$/, + exclude: [], + }, + optimizeDeps: { + esbuildOptions: { + loader: { + '.js': 'jsx', + }, + }, + }, + test: { + globals: true, + environment: 'jsdom', + setupFiles: ['./src/test/setup.js'], + include: ['src/**/*.{test,spec}.{js,jsx}'], + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html'], + exclude: [ + 'node_modules/', + 'src/test/', + ], + }, + }, +})