codeant-ai-for-open-source[bot] commented on code in PR #38470:
URL: https://github.com/apache/superset/pull/38470#discussion_r2936446667
##########
superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx:
##########
@@ -1249,3 +1284,387 @@ test('resets dependent filter to first item when value
does not exist in data',
);
});
});
+
+test('renders text input instead of dropdown when operatorType is ILIKE
contains', () => {
+ jest.useFakeTimers();
+ const setDataMaskMock = jest.fn();
+ const props = buildSelectFilterProps({
+ formData: { operatorType: SelectFilterOperatorType.Contains },
+ filterState: { value: undefined },
+ setDataMask: setDataMaskMock,
+ });
+
+ render(<SelectFilterPlugin {...props} />, {
+ useRedux: true,
+ initialState: {
+ nativeFilters: {
+ filters: { 'test-filter': { name: 'Test Filter' } },
+ },
+ dataMask: {
+ 'test-filter': {
+ extraFormData: {},
+ filterState: { value: undefined },
+ },
+ },
+ },
+ });
+
+ expect(screen.queryByRole('combobox')).not.toBeInTheDocument();
+ expect(
+ screen.getByPlaceholderText('Type to search (contains)...'),
+ ).toBeInTheDocument();
+});
+
+test('renders text input with starts-with placeholder', () => {
+ jest.useFakeTimers();
+ const setDataMaskMock = jest.fn();
+ const props = buildSelectFilterProps({
+ formData: { operatorType: SelectFilterOperatorType.StartsWith },
+ filterState: { value: undefined },
+ setDataMask: setDataMaskMock,
+ });
+
+ render(<SelectFilterPlugin {...props} />, {
+ useRedux: true,
+ initialState: {
+ nativeFilters: {
+ filters: { 'test-filter': { name: 'Test Filter' } },
+ },
+ dataMask: {
+ 'test-filter': {
+ extraFormData: {},
+ filterState: { value: undefined },
+ },
+ },
+ },
+ });
+
+ expect(
+ screen.getByPlaceholderText('Type to search (starts with)...'),
+ ).toBeInTheDocument();
+});
+
+test('typing in LIKE input calls setDataMask with ILIKE Contains payload',
async () => {
+ jest.useFakeTimers();
+ const setDataMaskMock = jest.fn();
+ const props = buildSelectFilterProps({
+ formData: { operatorType: SelectFilterOperatorType.Contains },
+ filterState: { value: undefined },
+ setDataMask: setDataMaskMock,
+ });
+
+ render(<SelectFilterPlugin {...props} />, {
+ useRedux: true,
+ initialState: {
+ nativeFilters: {
+ filters: { 'test-filter': { name: 'Test Filter' } },
+ },
+ dataMask: {
+ 'test-filter': {
+ extraFormData: {},
+ filterState: { value: undefined },
+ },
+ },
+ },
+ });
+
+ setDataMaskMock.mockClear();
+ const input = screen.getByPlaceholderText('Type to search (contains)...');
+ fireEvent.change(input, { target: { value: 'Jen' } });
+ act(() => {
+ jest.advanceTimersByTime(500);
+ });
+
+ expect(setDataMaskMock).toHaveBeenCalledWith(
+ expect.objectContaining({
+ extraFormData: {
+ filters: [
+ {
+ col: 'gender',
+ op: 'ILIKE',
+ val: '%Jen%',
+ },
+ ],
+ },
+ }),
+ );
+});
+
+test('typing in LIKE input with inverse selection calls setDataMask with NOT
ILIKE payload', async () => {
+ jest.useFakeTimers();
+ const setDataMaskMock = jest.fn();
+ const props = buildSelectFilterProps({
+ formData: {
+ operatorType: SelectFilterOperatorType.Contains,
+ inverseSelection: true,
+ },
+ filterState: { value: undefined },
+ setDataMask: setDataMaskMock,
+ });
+
+ render(<SelectFilterPlugin {...props} />, {
+ useRedux: true,
+ initialState: {
+ nativeFilters: {
+ filters: { 'test-filter': { name: 'Test Filter' } },
+ },
+ dataMask: {
+ 'test-filter': {
+ extraFormData: {},
+ filterState: { value: undefined },
+ },
+ },
+ },
+ });
+
+ setDataMaskMock.mockClear();
+ const input = screen.getByPlaceholderText('Type to search (contains)...');
+ fireEvent.change(input, { target: { value: 'Jen' } });
+ act(() => {
+ jest.advanceTimersByTime(500);
+ });
+
+ expect(setDataMaskMock).toHaveBeenCalledWith(
+ expect.objectContaining({
+ extraFormData: {
+ filters: [
+ {
+ col: 'gender',
+ op: 'NOT ILIKE',
+ val: '%Jen%',
+ },
+ ],
+ },
+ }),
+ );
+});
+
+test('clear-all resets LIKE input value and calls setDataMask with empty
state', async () => {
+ jest.useFakeTimers();
+ const setDataMaskMock = jest.fn();
+ const likeProps = buildSelectFilterProps({
+ formData: { operatorType: SelectFilterOperatorType.Contains },
+ filterState: { value: ['Jen'] },
+ setDataMask: setDataMaskMock,
+ });
+
+ const reduxState = {
+ useRedux: true,
+ initialState: {
+ nativeFilters: {
+ filters: { 'test-filter': { name: 'Test Filter' } },
+ },
+ dataMask: {
+ 'test-filter': {
+ extraFormData: {
+ filters: [{ col: 'gender', op: 'ILIKE', val: '%Jen%' }],
+ },
+ filterState: { value: ['Jen'] },
+ },
+ },
+ },
+ };
+
+ const { rerender } = render(
+ <SelectFilterPlugin {...likeProps} />,
+ reduxState,
+ );
+
+ const input = screen.getByPlaceholderText('Type to search (contains)...');
+ expect(input).toHaveValue('Jen');
+
+ setDataMaskMock.mockClear();
+
+ rerender(
+ <SelectFilterPlugin
+ {...likeProps}
+ clearAllTrigger={{ 'test-filter': true }}
+ />,
+ );
+
+ await waitFor(() => {
+ expect(input).toHaveValue('');
+ });
+
+ await waitFor(() => {
+ expect(setDataMaskMock).toHaveBeenCalledWith(
+ expect.objectContaining({
+ filterState: expect.objectContaining({
+ value: null,
+ }),
+ }),
+ );
+ });
+
+ act(() => {
+ jest.advanceTimersByTime(500);
+ });
+
+ expect(setDataMaskMock).not.toHaveBeenCalled();
Review Comment:
**Suggestion:** This assertion is logically impossible after the preceding
`waitFor` already verified that `setDataMaskMock` was called, so the test will
fail even when behavior is correct. Capture the call count before flushing
timers and assert it does not increase, which validates that no extra debounced
call fires. [logic error]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ⚠️ Jest suite fails for SelectFilterPlugin clear-all scenario.
- ❌ Frontend CI blocked by deterministic failing assertion.
```
</details>
```suggestion
const callsBeforeDebounceFlush = setDataMaskMock.mock.calls.length;
act(() => {
jest.advanceTimersByTime(500);
});
expect(setDataMaskMock).toHaveBeenCalledTimes(callsBeforeDebounceFlush);
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Run the focused Jest test in
`superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx`
(test name:
`clear-all resets LIKE input value and calls setDataMask with empty state`).
2. In that test, `setDataMaskMock.mockClear()` is called, then `rerender(...
clearAllTrigger={{ 'test-filter': true }})` triggers the clear-all flow
(`SelectFilterPlugin.test.tsx:1476-1487` in final file state).
3. The test explicitly waits for `setDataMaskMock` to be called with
`filterState.value:
null` via `await waitFor(...toHaveBeenCalledWith...)`
(`SelectFilterPlugin.test.tsx:1490-1497`), proving at least one call already
happened.
4. Immediately after timer flush (`SelectFilterPlugin.test.tsx:1499-1501`),
the assertion
`expect(setDataMaskMock).not.toHaveBeenCalled()`
(`SelectFilterPlugin.test.tsx:1503`)
fails deterministically because prior steps already required a call.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:**
superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx
**Line:** 1499:1503
**Comment:**
*Logic Error: This assertion is logically impossible after the
preceding `waitFor` already verified that `setDataMaskMock` was called, so the
test will fail even when behavior is correct. Capture the call count before
flushing timers and assert it does not increase, which validates that no extra
debounced call fires.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38470&comment_hash=3147852f6095d33fc7bfd1cfb2c5c1682b5ad00853dfea7eee07e6424743d195&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38470&comment_hash=3147852f6095d33fc7bfd1cfb2c5c1682b5ad00853dfea7eee07e6424743d195&reaction=dislike'>👎</a>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]