Skip to content

Commit c21b464

Browse files
committed
test: Cover search by condition translations
1 parent 0c8b5bb commit c21b464

File tree

2 files changed

+190
-4
lines changed

2 files changed

+190
-4
lines changed
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import {
2+
translateBooleanValue,
3+
translateColumnFilterToSearchCondition,
4+
translateNumberComparator,
5+
translateStringSearchType,
6+
translateStringSearchValue,
7+
} from '@/features/instance/operations/queries/getSearchByConditions';
8+
import type { InstanceAttribute } from '@/lib/api.patch';
9+
import { describe, expect, it } from 'vitest';
10+
11+
function attr(type?: InstanceAttribute['type']): InstanceAttribute {
12+
return { attribute: 'col', type };
13+
}
14+
15+
describe('translateStringSearchType', () => {
16+
it('returns equals when both anchors are present', () => {
17+
expect(translateStringSearchType(true, true, attr('String'))).toBe('equals');
18+
});
19+
20+
it('returns starts_with when only start anchor is present', () => {
21+
expect(translateStringSearchType(true, false, attr('String'))).toBe('starts_with');
22+
});
23+
24+
it('returns ends_with when only end anchor is present', () => {
25+
expect(translateStringSearchType(false, true, attr('String'))).toBe('ends_with');
26+
});
27+
28+
it('returns equals for ID type when no anchors', () => {
29+
expect(translateStringSearchType(false, false, attr('ID'))).toBe('equals');
30+
});
31+
32+
it('defaults to starts_with when no anchors and non-ID', () => {
33+
expect(translateStringSearchType(false, false, attr('String'))).toBe('starts_with');
34+
expect(translateStringSearchType(false, false, attr('Date'))).toBe('starts_with');
35+
});
36+
});
37+
38+
describe('translateStringSearchValue', () => {
39+
it('strips both anchors', () => {
40+
expect(translateStringSearchValue(true, true, '^foo$')).toBe('foo');
41+
});
42+
it('strips start anchor only', () => {
43+
expect(translateStringSearchValue(true, false, '^foo')).toBe('foo');
44+
});
45+
it('strips end anchor only', () => {
46+
expect(translateStringSearchValue(false, true, 'foo$')).toBe('foo');
47+
});
48+
it('returns as-is with no anchors', () => {
49+
expect(translateStringSearchValue(false, false, 'foo')).toBe('foo');
50+
});
51+
});
52+
53+
describe('translateNumberComparator', () => {
54+
it('maps > to greater_than', () => {
55+
expect(translateNumberComparator('>')).toBe('greater_than');
56+
});
57+
it('maps >= to greater_than_equal', () => {
58+
expect(translateNumberComparator('>=')).toBe('greater_than_equal');
59+
});
60+
it('maps < to less_than', () => {
61+
expect(translateNumberComparator('<')).toBe('less_than');
62+
});
63+
it('maps <= to less_than_equal', () => {
64+
expect(translateNumberComparator('<=')).toBe('less_than_equal');
65+
});
66+
it('defaults to equals for = and undefined', () => {
67+
expect(translateNumberComparator('=')).toBe('equals');
68+
expect(translateNumberComparator(undefined)).toBe('equals');
69+
});
70+
});
71+
72+
describe('translateBooleanValue', () => {
73+
it('recognizes truthy variants (case-insensitive)', () => {
74+
const truthy = ['true', 'Yes', 'OK', 'Yup', '1', 'Si', 'bet', 'TrU'];
75+
for (const v of truthy) {
76+
expect(translateBooleanValue(v)).toBe(true);
77+
}
78+
});
79+
it('returns false for non-matching values', () => {
80+
const falsy = ['false', 'no', '0', 'nah', 'maybe', 'foo', '', 'truth'];
81+
for (const v of falsy) {
82+
expect(translateBooleanValue(v)).toBe(false);
83+
}
84+
});
85+
});
86+
87+
describe('translateColumnFilterToSearchCondition', () => {
88+
it('handles String attribute with anchors', () => {
89+
expect(
90+
translateColumnFilterToSearchCondition('name', '^foo$', attr('String')),
91+
).toEqual({
92+
search_attribute: 'name',
93+
search_type: 'equals',
94+
search_value: 'foo',
95+
});
96+
97+
expect(
98+
translateColumnFilterToSearchCondition('name', 'bar$', attr('String')),
99+
).toEqual({
100+
search_attribute: 'name',
101+
search_type: 'ends_with',
102+
search_value: 'bar',
103+
});
104+
105+
expect(
106+
translateColumnFilterToSearchCondition('name', 'baz', attr('String')),
107+
).toEqual({
108+
search_attribute: 'name',
109+
search_type: 'starts_with',
110+
search_value: 'baz',
111+
});
112+
});
113+
114+
it('forces equals for ID when no anchors', () => {
115+
expect(
116+
translateColumnFilterToSearchCondition('id', 'abc123', attr('ID')),
117+
).toEqual({
118+
search_attribute: 'id',
119+
search_type: 'equals',
120+
search_value: 'abc123',
121+
});
122+
});
123+
124+
it('parses numeric types and comparators', () => {
125+
expect(
126+
translateColumnFilterToSearchCondition('age', '>=10', attr('Int')),
127+
).toEqual({
128+
search_attribute: 'age',
129+
search_type: 'greater_than_equal',
130+
search_value: 10,
131+
});
132+
133+
expect(
134+
translateColumnFilterToSearchCondition('score', '<=3.14', attr('Float')),
135+
).toEqual({
136+
search_attribute: 'score',
137+
search_type: 'less_than_equal',
138+
search_value: 3.14,
139+
});
140+
141+
// No comparator defaults to equals
142+
expect(
143+
translateColumnFilterToSearchCondition('count', '42', attr('Int')),
144+
).toEqual({
145+
search_attribute: 'count',
146+
search_type: 'equals',
147+
search_value: 42,
148+
});
149+
});
150+
151+
it('parses booleans with accepted truthy values', () => {
152+
expect(
153+
translateColumnFilterToSearchCondition('active', 'Yes', attr('Boolean')),
154+
).toEqual({
155+
search_attribute: 'active',
156+
search_type: 'equals',
157+
search_value: true,
158+
});
159+
160+
expect(
161+
translateColumnFilterToSearchCondition('active', 'no', attr('Boolean')),
162+
).toEqual({
163+
search_attribute: 'active',
164+
search_type: 'equals',
165+
search_value: false,
166+
});
167+
});
168+
169+
it('falls back to equals for unknown or undefined attribute types', () => {
170+
expect(
171+
translateColumnFilterToSearchCondition('misc', 'value', attr('Bytes')),
172+
).toEqual({
173+
search_attribute: 'misc',
174+
search_type: 'equals',
175+
search_value: 'value',
176+
});
177+
178+
expect(
179+
translateColumnFilterToSearchCondition('misc', 'value', undefined),
180+
).toEqual({
181+
search_attribute: 'misc',
182+
search_type: 'equals',
183+
search_value: 'value',
184+
});
185+
});
186+
});

src/features/instance/operations/queries/getSearchByConditions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export function translateColumnFilterToSearchCondition(key: string, value: strin
127127
}
128128
}
129129

130-
function translateStringSearchType(anchorStart: boolean, anchorEnd: boolean, attribute: InstanceAttribute): Comparator {
130+
export function translateStringSearchType(anchorStart: boolean, anchorEnd: boolean, attribute: InstanceAttribute): Comparator {
131131
if (anchorStart && anchorEnd) {
132132
return 'equals';
133133
}
@@ -143,7 +143,7 @@ function translateStringSearchType(anchorStart: boolean, anchorEnd: boolean, att
143143
return 'starts_with';
144144
}
145145

146-
function translateStringSearchValue(anchorStart: boolean, anchorEnd: boolean, value: string) {
146+
export function translateStringSearchValue(anchorStart: boolean, anchorEnd: boolean, value: string) {
147147
if (anchorStart && anchorEnd) {
148148
return value.slice(1, -1);
149149
}
@@ -156,7 +156,7 @@ function translateStringSearchValue(anchorStart: boolean, anchorEnd: boolean, va
156156
return value;
157157
}
158158

159-
function translateNumberComparator(comparator: string | undefined): Comparator {
159+
export function translateNumberComparator(comparator: string | undefined): Comparator {
160160
switch (comparator) {
161161
case '>':
162162
return 'greater_than';
@@ -176,7 +176,7 @@ const acceptedOKValues = [
176176
'true', 'yes', 'ok', 'yup', '1', 'si', 'bet', 'tru',
177177
];
178178

179-
function translateBooleanValue(value: string): boolean {
179+
export function translateBooleanValue(value: string): boolean {
180180
const lowerValue = value.toLowerCase();
181181
return acceptedOKValues.includes(lowerValue);
182182
}

0 commit comments

Comments
 (0)