Skip to content

Commit

Permalink
Merge pull request #38 from BuidlerDAO/comp/event
Browse files Browse the repository at this point in the history
Updated test cases and css error for NModal
  • Loading branch information
zhbyak authored Feb 11, 2025
2 parents 00a1629 + 0ef1334 commit a76eaee
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 38 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "n6-ui",
"version": "1.7.1",
"version": "1.8.0",
"description": "N6 Network UI Framework",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
5 changes: 3 additions & 2 deletions src/NModal/NModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { useEffect, useRef, useState } from 'react';
import classNames from 'classnames';
import { createPortal } from 'react-dom';
import { BottomSheet } from 'react-spring-bottom-sheet';
import 'react-spring-bottom-sheet/dist/style.css';

export type NModalProps = {
zIndex?: number;
Expand Down Expand Up @@ -69,8 +68,9 @@ export default function NModal({
if (!mounted && unmountOnClose) return null;

return createPortal(
<div style={{ display: !mounted && !unmountOnClose ? 'none' : 'block' }}>
<div data-testid="modal-container" style={{ display: !mounted && !unmountOnClose ? 'none' : 'block' }}>
<div
data-testid="modal-overlay"
className={classNames(
'fixed left-0 top-0 z-[998] h-full w-full cursor-pointer bg-[white] transition-opacity duration-300',
innerOpen ? 'opacity-35' : 'opacity-0',
Expand All @@ -84,6 +84,7 @@ export default function NModal({
/>
<BottomSheet
open={innerOpen}
data-testid="modal-bottom-sheet"
onDismiss={onClose}
blocking={false}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down
23 changes: 19 additions & 4 deletions src/NSelect/NSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const NSelect: React.FC<NSelectProps> = ({

return (
<div
data-testid="nselect-container"
className={classNames(
'relative flex h-[50px] w-full cursor-pointer flex-row items-center space-x-1 rounded-[20px] bg-gray-1 px-4 text-[white]',
containerClassName,
Expand All @@ -51,16 +52,23 @@ const NSelect: React.FC<NSelectProps> = ({
{leftSide}
<span className="flex-grow-1 flex flex-shrink-0 items-center">
<NTruncatedText text={`${confirmedOption && confirmedOption.label}`} className="" />
<span className={classNames(open ? 'rotate-90' : 'rotate-0', 'ml-[10px] transition-all')}>{RightIcon}</span>
<span
data-testid="nselect-right-icon"
className={classNames(open ? 'rotate-90' : 'rotate-0', 'ml-[10px] transition-all')}
>
{RightIcon}
</span>
</span>
<NModal
data-testid="nselect-modal"
zIndex={9999}
open={open}
onClose={() => {
setTimeout(() => setOpen(false), 0);
}}
footer={
<NButtons
data-testid="nselect-confirm-button"
state={ButtonState.Primary}
className="mt-[20px]"
onClick={() => {
Expand All @@ -73,16 +81,23 @@ const NSelect: React.FC<NSelectProps> = ({
</NButtons>
}
>
<div className="h-full overflow-auto text-[white]">
<div className="border-b border-[#FFFFFF1A] pb-[20px] text-center">{title}</div>
<div data-testid="nselect-modal-content" className="h-full overflow-auto text-[white]">
<div data-testid="nselect-modal-title" className="border-b border-[#FFFFFF1A] pb-[20px] text-center">
{title}
</div>
{options.map((option) => (
<div
data-testid={`nselect-option-${option.key}`}
key={option.key}
className="flex cursor-pointer justify-between border-b border-[#FFFFFF1A] py-[10px] text-left"
onClick={() => setSelectedOption(option)}
>
{option.label}
{option.key === selectedOption?.key && <span className="text-main">{CheckIcon}</span>}
{option.key === selectedOption?.key && (
<span data-testid={`nselect-option-${option.key}-check`} className="text-main">
{CheckIcon}
</span>
)}
</div>
))}
</div>
Expand Down
42 changes: 24 additions & 18 deletions src/__tests__/NModal.test.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,44 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { render, screen, fireEvent, act } from '@testing-library/react';
import '@testing-library/jest-dom';
import { NModal } from '../NModal';

describe('NModal Component', () => {
test('renders the modal when open and calls onClose when overlay is clicked', () => {
const onCloseMock = jest.fn();
jest.mock('react-spring-bottom-sheet', () => ({
BottomSheet: function MockBottomSheet() {
return <div data-testid="modal-bottom-sheet"></div>;
},
}));

describe('NModal', () => {
test('renders modal when open', async () => {
const handleClose = jest.fn();

render(
<NModal open={true} onClose={onCloseMock} footer={<div>Footer Content</div>}>
Modal Content
<NModal zIndex={999} open={true} onClose={handleClose} unmountOnClose={true} stableHeight={0}>
Test Content
</NModal>,
);

// Check if the modal content is displayed
expect(screen.getByText('Modal Content')).toBeInTheDocument();
expect(screen.getByText('Footer Content')).toBeInTheDocument();
await act(async () => {
await new Promise((r) => setTimeout(r, 150));
});

// Simulate clicking the overlay
const overlay = screen.getByRole('button', { hidden: true });
fireEvent.click(overlay);
expect(screen.getByTestId('modal-container')).toBeInTheDocument();
expect(screen.getByTestId('modal-overlay')).toBeInTheDocument();
expect(screen.getByTestId('modal-bottom-sheet')).toBeInTheDocument();

// Ensure onClose is called
expect(onCloseMock).toHaveBeenCalled();
const overlay = screen.getByTestId('modal-overlay');
fireEvent.click(overlay);
expect(handleClose).toHaveBeenCalled();
});

test('does not render the modal when `open` is false and `unmountOnClose` is true', () => {
test('does not render when closed', () => {
render(
<NModal open={false} unmountOnClose={true}>
Modal Content
Test Content
</NModal>,
);

// Modal should not be in the DOM
expect(screen.queryByText('Modal Content')).not.toBeInTheDocument();
expect(screen.queryByTestId('modal-container')).not.toBeInTheDocument();
});
});
77 changes: 64 additions & 13 deletions src/__tests__/NSelect.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,104 @@ import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import { NSelect, SelectOptions } from '../NSelect';

// Mock the NModal and BottomSheet components
jest.mock('../NModal', () => {
return {
NModal: ({
children,
open,
footer,
}: {
children: React.ReactNode;
open: boolean;
onClose?: () => void;
footer?: React.ReactNode;
}) =>
open ? (
<div data-testid="mock-modal">
{children}
{footer}
</div>
) : null,
};
});

jest.mock('react-spring-bottom-sheet', () => ({
BottomSheet: ({ children }: { children: React.ReactNode }) => <div data-testid="mock-bottom-sheet">{children}</div>,
}));

// Sample icons for testing
const RightIcon = () => <div>Right Icon</div>;
const CheckIcon = () => <div></div>;

// Sample options for testing
const sampleOptions: SelectOptions[] = [
{ key: '1', label: 'Option 1' },
{ key: '2', label: 'Option 2' },
{ key: '3', label: 'Option 3' },
];

// Mocking the icons used in NSelect
const RightIcon = <span>Right Icon</span>;
const CheckIcon = <span></span>;

describe('NSelect Component', () => {
// Test case 1: Rendering without options
test('renders NSelect without options', () => {
render(<NSelect title="Select an option" RightIcon={RightIcon} CheckIcon={CheckIcon} />);
render(<NSelect title="Select an option" options={[]} RightIcon={<RightIcon />} CheckIcon={<CheckIcon />} />);

// Verify that the NSelect is rendered with the default state (Add a option)
// Verify that the NSelect is rendered with the default state
expect(screen.getByText('Add a')).toBeInTheDocument();
});

// Test case 2: Opening the modal when clicked
test('opens modal when clicked', () => {
render(<NSelect title="Select an option" options={sampleOptions} RightIcon={RightIcon} CheckIcon={CheckIcon} />);
render(
<NSelect title="Select an option" options={sampleOptions} RightIcon={<RightIcon />} CheckIcon={<CheckIcon />} />,
);

// Trigger a click on the select input (the component's div)
// Trigger a click on the select input
fireEvent.click(screen.getByText('Add a'));

// Check if the modal is displayed
// Check if the modal is displayed with the title and options
expect(screen.getByTestId('mock-modal')).toBeInTheDocument();
expect(screen.getByText('Select an option')).toBeInTheDocument();
expect(screen.getByText('Option 1')).toBeInTheDocument();
expect(screen.getByText('Option 2')).toBeInTheDocument();
expect(screen.getByText('Option 3')).toBeInTheDocument();
});


// Test case 3: Check if the left-side custom content is rendered
test('renders left-side custom content', () => {
render(
<NSelect
title="Select an option"
leftSide={<span>Custom Left Side</span>}
leftSide={<div>Custom Left Side</div>}
options={sampleOptions}
RightIcon={RightIcon}
CheckIcon={CheckIcon}
RightIcon={<RightIcon />}
CheckIcon={<CheckIcon />}
/>,
);
// Check if the custom left-side content is rendered
expect(screen.getByText('Custom Left Side')).toBeInTheDocument();
});

// Test case 4: Selecting an option
test('selects an option', () => {
const handleChange = jest.fn();
render(
<NSelect
title="Select an option"
options={sampleOptions}
onChange={handleChange}
RightIcon={<RightIcon />}
CheckIcon={<CheckIcon />}
/>,
);

// Open the modal
fireEvent.click(screen.getByText('Add a'));

// Select an option
fireEvent.click(screen.getByText('Option 2'));

// Check if the option is selected
expect(screen.getByText('✔')).toBeInTheDocument();
});
});
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import './styles/index.css';
import 'react-spring-bottom-sheet/dist/style.css';

export * from './NButtons';
export * from './NCommonHeader';
Expand Down

0 comments on commit a76eaee

Please sign in to comment.