Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/private-trigger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ jobs:
continue-on-error: true

- name: Build project
run: npm run build
# SonarQube scan - ONLY on push (not PR)
run:
npm run build
# SonarQube scan - ONLY on push (not PR)
- name: SonarQube Scan
if: github.event_name == 'push'
uses: SonarSource/sonarqube-scan-action@v5.0.0
Expand All @@ -75,7 +76,7 @@ jobs:
needs: test-and-build
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
steps:
steps:
- name: Trigger public repo workflow
run: |
curl -X POST \
Expand Down
8 changes: 2 additions & 6 deletions src/components/ui/forms/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,7 @@ export interface FormHandlers {
}

export interface FormContainerProps
extends GenericAuthFormProps,
FormState,
FormHandlers {
extends GenericAuthFormProps, FormState, FormHandlers {
displayMode: 'modal' | 'fullpage';
onClose?: () => void;
className?: string;
Expand Down Expand Up @@ -152,9 +150,7 @@ export interface SocialLoginSectionProps {
}

export interface FormContentProps
extends GenericAuthFormProps,
FormState,
FormHandlers {
extends GenericAuthFormProps, FormState, FormHandlers {
onSwitchModal?: (newType: AuthModalType) => void;
loading: boolean;
isFormValid: boolean;
Expand Down
7 changes: 3 additions & 4 deletions src/components/ui/input/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ export interface CharCounterProps {
maxLength: number;
}

export interface InputBaseProps
extends React.HTMLAttributes<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
> {
export interface InputBaseProps extends React.HTMLAttributes<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
> {
// loosened ref type to support both input and textarea refs
inputRef?: React.Ref<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
Expand Down
25 changes: 25 additions & 0 deletions src/features/layout/tests/EmptySpace.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { describe, it, expect } from 'vitest';
import { render } from '@/test/test-utils';
import EmptySpace from '../components/EmptySpace';

describe('EmptySpace', () => {
it('should render without crashing', () => {
const { container } = render(<EmptySpace />);

expect(container).toBeInTheDocument();
});

it('should render a div element', () => {
const { container } = render(<EmptySpace />);
const emptySpace = container.firstChild;

expect(emptySpace).toBeInTheDocument();
});

it('should have appropriate spacing classes', () => {
const { container } = render(<EmptySpace />);
const emptySpace = container.firstChild as HTMLElement;

expect(emptySpace.className).toBeTruthy();
});
});
37 changes: 37 additions & 0 deletions src/features/layout/tests/Footer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { describe, it, expect } from 'vitest';
import { render, screen } from '@/test/test-utils';
import Footer from '../components/Footer';

describe('Footer', () => {
it('should render footer content', () => {
const { container } = render(<Footer />);

expect(container.firstChild).toBeInTheDocument();
});

it('should render copyright text', () => {
render(<Footer />);

expect(screen.getByText(/© 2025/i)).toBeInTheDocument();
});

it('should render Hankers Corp text', () => {
render(<Footer />);

expect(screen.getByText(/hankers corp/i)).toBeInTheDocument();
});

it('should have proper styling', () => {
const { container } = render(<Footer />);
const footer = container.querySelector('footer');

expect(footer).toBeInTheDocument();
});

it('should be a footer element', () => {
const { container } = render(<Footer />);
const footer = container.querySelector('footer');

expect(footer).toBeInTheDocument();
});
});
147 changes: 145 additions & 2 deletions src/features/layout/tests/LayoutWrapper.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,151 @@ import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@/test/test-utils';
import LayoutWrapper from '../components/LayoutWrapper';

it('always passes', () => {
expect(true).toBe(true);
vi.mock('../components/LeftSidebar', () => ({
default: () => <div data-testid="left-sidebar">Left Sidebar</div>,
}));

vi.mock('../components/RightSidebar', () => ({
default: () => <div data-testid="right-sidebar">Right Sidebar</div>,
}));

vi.mock('../components/MobileBottomBar', () => ({
default: () => <div data-testid="mobile-bottom-bar">Mobile Bottom Bar</div>,
}));

vi.mock('../components/GrokSummary', () => ({
default: () => <div data-testid="grok-summary">Grok Summary</div>,
}));

describe('LayoutWrapper', () => {
it('should render children content', () => {
render(
<LayoutWrapper>
<div>Test Content</div>
</LayoutWrapper>
);

expect(screen.getByText('Test Content')).toBeInTheDocument();
});

it('should render left sidebar', () => {
render(
<LayoutWrapper>
<div>Content</div>
</LayoutWrapper>
);

expect(screen.getByTestId('left-sidebar')).toBeInTheDocument();
});

it('should render right sidebar by default', () => {
render(
<LayoutWrapper>
<div>Content</div>
</LayoutWrapper>
);

expect(screen.getByTestId('right-sidebar')).toBeInTheDocument();
});

it('should have proper layout when showRightSidebar is false', () => {
const { container } = render(
<LayoutWrapper showRightSidebar={false}>
<div>Content</div>
</LayoutWrapper>
);

expect(container).toBeInTheDocument();
});

it('should render mobile bottom bar by default', () => {
render(
<LayoutWrapper>
<div>Content</div>
</LayoutWrapper>
);

expect(screen.getByTestId('mobile-bottom-bar')).toBeInTheDocument();
});

it('should hide mobile bottom bar when showMobileBottomBar is false', () => {
render(
<LayoutWrapper showMobileBottomBar={false}>
<div>Content</div>
</LayoutWrapper>
);

expect(screen.queryByTestId('mobile-bottom-bar')).not.toBeInTheDocument();
});

it('should render GrokSummary when showRightSidebar is true', () => {
render(
<LayoutWrapper showRightSidebar={true}>
<div>Content</div>
</LayoutWrapper>
);

expect(screen.getByTestId('grok-summary')).toBeInTheDocument();
});

it('should hide GrokSummary when showRightSidebar is false', () => {
render(
<LayoutWrapper showRightSidebar={false}>
<div>Content</div>
</LayoutWrapper>
);

expect(screen.queryByTestId('grok-summary')).not.toBeInTheDocument();
});

it('should pass hasSearch prop to RightSidebar', () => {
const { rerender } = render(
<LayoutWrapper hasSearch={true}>
<div>Content</div>
</LayoutWrapper>
);

expect(screen.getByTestId('right-sidebar')).toBeInTheDocument();

rerender(
<LayoutWrapper hasSearch={false}>
<div>Content</div>
</LayoutWrapper>
);

expect(screen.getByTestId('right-sidebar')).toBeInTheDocument();
});

it('should render main content area with proper styling', () => {
const { container } = render(
<LayoutWrapper>
<div>Content</div>
</LayoutWrapper>
);

const mainElement = container.querySelector('main');
expect(mainElement).toBeInTheDocument();
expect(mainElement).toHaveClass(
'flex',
'flex-1',
'flex-row',
'min-h-screen'
);
});

it('should render multiple children', () => {
render(
<LayoutWrapper>
<div>First Child</div>
<div>Second Child</div>
<div>Third Child</div>
</LayoutWrapper>
);

expect(screen.getByText('First Child')).toBeInTheDocument();
expect(screen.getByText('Second Child')).toBeInTheDocument();
expect(screen.getByText('Third Child')).toBeInTheDocument();
});
});

// vi.mock('../LeftSidebar', () => ({
Expand Down
62 changes: 57 additions & 5 deletions src/features/layout/tests/LeftSidebar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,61 @@
import { describe, it, expect, vi } from 'vitest';
// import { render, screen } from '@/test/test-utils';
// import LayoutWrapper from '../components/LayoutWrapper';
// import LeftSidebar from '../components/LeftSidebar';
it('always passes', () => {
expect(true).toBe(true);
import { render, screen } from '@/test/test-utils';
import LeftSidebar from '../components/LeftSidebar';

vi.mock('../components/MenuItems', () => ({
default: () => <div data-testid="menu-items">Menu Items</div>,
}));

vi.mock('../components/ProfileSection', () => ({
default: () => <div data-testid="profile-section">Profile Section</div>,
}));

vi.mock('../components/PostButton', () => ({
default: () => <button data-testid="post-button">Post</button>,
}));

vi.mock('../components/Logo', () => ({
default: () => <div data-testid="logo">Logo</div>,
}));

describe('LeftSidebar', () => {
it('should render logo', () => {
render(<LeftSidebar />);

expect(screen.getByTestId('sidebar-logo')).toBeInTheDocument();
});

it('should render menu items', () => {
render(<LeftSidebar />);

expect(screen.getByTestId('menu-items')).toBeInTheDocument();
});

it('should render post button', () => {
render(<LeftSidebar />);

expect(screen.getByTestId('post-button')).toBeInTheDocument();
});

it('should render profile section', () => {
render(<LeftSidebar />);

expect(screen.getByTestId('profile-section')).toBeInTheDocument();
});

it('should render as aside element', () => {
const { container } = render(<LeftSidebar />);
const aside = container.querySelector('aside');

expect(aside).toBeInTheDocument();
});

it('should have proper layout structure', () => {
const { container } = render(<LeftSidebar />);
const aside = container.querySelector('aside');

expect(aside).toHaveClass('flex', 'flex-col');
});
});

// // Mock child components
Expand Down
44 changes: 44 additions & 0 deletions src/features/layout/tests/Logo.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { describe, it, expect } from 'vitest';
import { render } from '@/test/test-utils';
import Logo from '../components/Logo';

describe('Logo', () => {
it('should render logo SVG', () => {
const { container } = render(<Logo />);
const svg = container.querySelector('svg');

expect(svg).toBeInTheDocument();
});

it('should render with proper styling', () => {
const { container } = render(<Logo />);
const div = container.querySelector('div');

expect(div).toHaveClass(
'hover:bg-gray-900',
'rounded-full',
'cursor-pointer'
);
});

it('should render SVG with correct viewBox', () => {
const { container } = render(<Logo />);
const svg = container.querySelector('svg');

expect(svg).toHaveAttribute('viewBox', '0 0 24 24');
});

it('should render SVG with white stroke', () => {
const { container } = render(<Logo />);
const svg = container.querySelector('svg');

expect(svg).toHaveAttribute('stroke', 'white');
});

it('should have path element', () => {
const { container } = render(<Logo />);
const path = container.querySelector('path');

expect(path).toBeInTheDocument();
});
});
Loading