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
2 changes: 1 addition & 1 deletion src/OptionList/Column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ export default function Column<OptionType extends DefaultOptionType = DefaultOpt
/>
)}
<div className={`${menuItemPrefixCls}-content`}>
{optionRender ? optionRender(option) : label}
{optionRender && value !== '__EMPTY__' ? optionRender(option) : label}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While this correctly fixes the bug, using the magic string __EMPTY__ makes the code less maintainable and more brittle. This string is also used in src/OptionList/List.tsx but is not shared. It would be better to define it as an exported constant in a shared location (e.g., alongside FIX_LABEL in this file) and use the constant in both places. This ensures consistency and makes the code easier to understand and refactor in the future.

Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a magic sentinel value ('__EMPTY__') here to bypass optionRender can unintentionally disable optionRender for real options whose value happens to equal '__EMPTY__' (since value comes from user data). This also duplicates the sentinel string from OptionList/List.tsx, making it easy to drift.

Prefer detecting the injected "not found" placeholder via an internal marker (e.g., check whether option[FIX_LABEL] is defined / owned) or centralize the sentinel as a shared constant exported from a single module so normal user options aren’t affected.

Copilot uses AI. Check for mistakes.
</div>
{!isLoading && expandIcon && !isMergedLeaf && (
<div className={`${menuItemPrefixCls}-expand-icon`}>{expandIcon}</div>
Expand Down
66 changes: 65 additions & 1 deletion tests/search.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { fireEvent, render } from '@testing-library/react';
import KeyCode from '@rc-component/util/lib/KeyCode';
import { resetWarned } from '@rc-component/util/lib/warning';
import React from 'react';
import Cascader from '../src';
import Cascader, { type DefaultOptionType } from '../src';
import { optionsForActiveMenuItems } from './demoOptions';
import { expectOpen, doSearch, keyDown } from './util';

Expand Down Expand Up @@ -444,4 +444,68 @@ describe('Cascader.Search', () => {
fireEvent.click(document.querySelector('.rc-cascader-checkbox') as HTMLElement);
expect(inputNode).toHaveValue('little');
});

it('should display notFoundContent when search has no results with optionRender', () => {
const { container } = render(
<Cascader
options={options}
open
showSearch
optionRender={option => `${option.label} - custom render`}
notFoundContent="未找到相关内容"
/>,
);

// Search for something that doesn't exist
doSearch(container, 'nonexistent');
const itemList = container.querySelectorAll('.rc-cascader-menu-item');
expect(itemList).toHaveLength(1);
// Should display notFoundContent, not use optionRender
expect(itemList[0].textContent).toEqual('未找到相关内容');
expect(itemList[0].querySelector('.rc-cascader-menu-item-content')?.textContent).toEqual(
'未找到相关内容',
);
});

it('should use optionRender for search results when both optionRender and notFoundContent are provided', () => {
const { container } = render(
<Cascader
options={options}
open
showSearch
optionRender={option => `${option.label} - custom render`}
notFoundContent="未找到相关内容"
/>,
);

// Search for something that exists
doSearch(container, 'toy');
const itemList = container.querySelectorAll('.rc-cascader-menu-item');
expect(itemList.length).toBeGreaterThan(0);

// Should use optionRender for actual options
const firstItemContent = itemList[0].querySelector('.rc-cascader-menu-item-content');
expect(firstItemContent?.textContent).toContain('custom render');
expect(firstItemContent?.textContent).not.toEqual('未找到相关内容');
});

it('should display notFoundContent when options array is empty with optionRender', () => {
const { container } = render(
<Cascader
options={[] as DefaultOptionType[]}
open
showSearch
optionRender={option => `${option.label} - custom render`}
notFoundContent="空列表"
/>,
);

const itemList = container.querySelectorAll('.rc-cascader-menu-item');
expect(itemList).toHaveLength(1);
// Should display notFoundContent, not use optionRender
expect(itemList[0].textContent).toEqual('空列表');
expect(itemList[0].querySelector('.rc-cascader-menu-item-content')?.textContent).toEqual(
'空列表',
);
});
});
Loading