Skip to content

AG-10819 advanced filter - #14783

Draft
SalvatorePreviti wants to merge 11 commits into
latestfrom
AG-10819-filter-builder
Draft

AG-10819 advanced filter#14783
SalvatorePreviti wants to merge 11 commits into
latestfrom
AG-10819-filter-builder

Conversation

@SalvatorePreviti

@SalvatorePreviti SalvatorePreviti commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

AG-10819: A Custom Filter Option means the same thing wherever it is used

FIX AG-10819

FIX AG-14491

FIX AG-16738

scope net lines lines changed hunks files changed
source +878 2616 (+1747 -869) 379 52 (+1, 51 edited)
tests +5187 5467 (+5327 -140) 103 30 (+6, 24 edited)
docs +321 327 (+324 -3) 9 8 (+3, 5 edited)

Custom Filter Options (colDef.filterParams.filterOptions) work in the Advanced Filter, taking 0, 1 or 2
values, the same arities the column filter supports. The other two tickets are bugs found on the way there.

Breaking bug fixes

Both are TypeScript-only: corrections to types that were already wrong. What stops compiling is code the
declared type should never have accepted.

  1. IFilterOptionDef.predicate is required. An option without one was offered and matched no rows.
  2. type accepts a Custom Filter Option's displayKey, on ISimpleFilterModel, the nine
    *AdvancedFilterModel, and IFilterPlaceholderFunctionParams.filterOptionKey. The declared unions were
    already wrong: choosing a custom option has always stored its displayKey there, and the source cast
    as ISimpleFilterModelType to compile. Only reading type into a variable of the narrow union, or an
    exhaustive switch on it, stops compiling.

filterOptions, defaultOption and filterPlaceholder narrow only what they suggest: every value they
took before is still accepted, and a wrong one is reported at runtime instead.

What a user could notice

Everything observable in one place, each labelled with what it is.

Change What it is
A column's filterOptions containing a custom option now narrow the Advanced Filter's operators. One object entry used to disable narrowing for the whole list, so the column offered every built-in. the feature
A condition naming an option the column does not offer is cleared instead of shown as applied. bug fix
An incomplete custom option filters on nothing rather than falling through to the built-in evaluation: it neither excludes rows from an AND nor admits them to an OR. bug fix
An out-of-order inRange is no longer applied. It reached the model and hid every row; the inputs report it and the previously applied filter stands, as the Date Filter already did. bug fix
The floating filter reads its value back through numberParser instead of Number(). bug fix
A numberFormatter whose output the input cannot hold, or cannot read back as the same number, shows the plain number. Output an <input type="number"> could not hold left it blank; output it could hold but not read back, such as a formatter that rounds, was shown and then silently changed the model on the next edit. bug fix, and a display change for a lossy formatter
Three new warnings, reported when the filter is configured rather than only if a row happens to be evaluated: a listed key this filter cannot evaluate (#327), a defaultOption the list does not offer (#328, first option used), and a numberFormatter whose output cannot be read back (#326, naming the column). diagnostics only, nothing filtered changes
The existing #72 also fires for an option carrying only the removed test, and now reports on a column filtered solely through the Advanced Filter, which builds no OptionsFactory to report it. #73 is removed, having become unreachable. diagnostics only

Two degenerate hand-written models differ, neither reachable from the UI: a combined model with
conditions: [] filters on nothing rather than hiding every row under OR, and one that also needs its
filterType corrected keeps its own keys instead of collapsing to {filterType}.

The feature

A column's filterOptions are offered in the expression editor and the Builder under their displayName,
localised through their own displayKey as the column filter's dropdown label is, and evaluated with the
same predicate as the column filter. Operators resolve per column, so two columns
can reuse one displayKey for different options, and an option whose displayKey is a built-in replaces it
for that column. Suggestions carry one entry per key, as the column filter's dropdown does.

Expression syntax. An option is written under its displayName followed by as many values as it takes.
Two are comma separated, brackets optional. Each value is quoted by its Cell Data Type as for the built-ins:
number and bigint unquoted, the rest quoted. A displayKey typed in place of the displayName is
replaced by it once recognised.

[Age] Even Numbers
[Age] Between (Exclusive) (30, 40)

Builder. A two-value option renders two value pills, labelled Value From / Value To from the existing
inRangeStart/inRangeEnd locale text, and held to the same out-of-order check the column filter reports on
its inputs, and reported through that filter's own locale key: strictMaxValueValidation for number and
bigint, maxDateValidation for the date types. Changing a condition's column to one of another data type
clears the values.

Model. The Advanced Filter gains a filterTo slot, its condition model having had nowhere to put a
second value.

API added

Symbol Notes
CustomFilterOptionKey A Custom Filter Option's displayKey; string & {}
FilterOptionKey A built-in key, or a CustomFilterOptionKey
TextFilterOptionKey, ScalarFilterOptionKey The built-in keys each filter evaluates
DateFilterOptionKey, CommonFilterOptionKey The scalar keys plus the relative ranges, and the shared three
filterTo? on all nine *AdvancedFilterModel The second value, where the option takes two
filter? on BooleanAdvancedFilterModel Only a custom option uses it; the built-ins take no value

Pre-existing bugs fixed

30 of them, each covered by a test that fails on unmodified latest.

Range validation

  1. A stale range error survived a new model, Cancel, and reopening. Number and BigInt read this.state
    in a refresh() override after the base had overwritten it; Date had no refresh at all.
  2. It blocked the narrower option chosen after it. The to input's error held the condition back once
    the option no longer had a to input.
  3. A model with fewer conditions did not drop the extra ones while another condition held an error.
  4. A one-input option was held to the range rule of the value left behind: Number and BigInt compared
    from against to whatever the option.
  5. A range being fixed was discarded unless it was inRange. shouldKeepInvalidInputState matched the
    key rather than the two-value shape.
  6. The Date Filter validated the wrong pair once a condition had been dropped. Its picker callbacks
    captured a condition index, and removing one from the middle shifts every one after it.

Custom filter options

  1. A rejected option emptied the whole list, which was replaced by the one malformed entry. Invalid
    entries are skipped and the rest kept, making #73 unreachable, so it is removed.
  2. An option supplying only the removed test was still offered, and matched no rows.
  3. A built-in key and a FilterOptionDef of the same displayKey were both offered: two dropdown rows
    for one key, and selecting either highlighted the first.
  4. defaultOption was returned unchecked, leaving the dropdown on a value it does not list.
  5. getCustomOption resolved against Object.prototype, so a displayKey of toString returned an
    inherited member. The option map is a Map.
  6. numberOfInputs was not guarded, and a null entry threw on displayKey.
  7. A condition short of a value fell through to the built-in evaluation instead of filtering on nothing.
  8. A filterOptions list swapped at runtime never reached the dropdown. An option added later could not
    be chosen and one withdrawn stayed selectable, showing as another option's applied value.
  9. filterPlaceholder never saw a custom option: placeholders were not recomputed when the option
    changed, and a custom key has no locale entry, so filterOption arrived undefined.
  10. A filter option belonging to another filter type was accepted in silence (AG-16738).
  11. A malformed option went unreported on a column filtered only through the Advanced Filter, which never
    builds the OptionsFactory that reports it.

Number, BigInt and Date

  1. numberFormatter blanked both inputs, its output going into an <input type="number">. It is shown
    only where the input can hold it and read it back, and the inputs are re-rendered when a colDef refresh
    replaces the formatter or parser. Text no parser reads is left as typed, so a refresh does not empty an
    input mid-keystroke.
  2. A model summary kept the formatter it was built with, captured in the constructor while
    updateParams replaces filterParams.
  3. The floating filter read its value back with Number(), so with an allowedCharPattern a value only
    numberParser could read reached the model as NaN.
  4. The BigInt Filter never rebuilt its inputs when allowedCharPattern changed, though its own floating
    filter already did.
  5. A date column with includeTime showed an empty picker. setDate wrote 2020-01-01 into a
    datetime-local input, which the browser blanks.
  6. The Date Filter's preset-range cache never hit: expires was stored as a duration and tested as an
    absolute timestamp, re-running the relative-range function per row. Results were correct; the cost was not.

Advanced Filter

  1. An option name another option name starts with never parsed (AG-14491). Over Or Equal resolved to
    Over, silently: the editor shows the expression, getAdvancedFilterModel() returns null, and nothing
    is filtered. Reachable with no custom options by localising advancedFilterNotContains to contains not.
  2. An operator display name containing ) failed to parse, ) being a terminator. Subsumed by 24.
  3. Only the first of several expression rewrites landed. Rewriting a typed key in place shifted every
    position still to be parsed. Rewrites are queued and applied last-first, against the text as typed.
  4. The Builder's option list accepted a half-filled pair, and dropping a condition's column left a stale
    filterTo: both only looked at filter.
  5. The Builder kept the previous column's operator name where the new column offered the same key under a
    different displayName.

Other

  1. A combined model with no conditions threw: validateModel mapped over an absent array.
  2. A key pressed in a header the grid held no focus position for threw:
    AbstractHeaderCellCtrl.shouldStopEventPropagation destructured focusSvc.focusedHeader behind a !,
    though it is typed HeaderPosition | null.

Two optimisations, with no behaviour to test: the column autocomplete list was never memoised, its cache field
being assigned nowhere, so every keystroke rebuilt and re-sorted the entries; and a column's filterOptions were
classified twice per keystroke, once for the operators and once for the keys they narrow to. Both are cached per
column now, and invalidated on the column events they are built from.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Module Size Comparison

Extreme Values

🔺 Largest Increase: AllEnterpriseModule

  • Self Size: 1882.74 KB → 1891.82 KB (+9.08 KB, +0.5%)

Significant Changes (≥ 0.5KB)

Module(s) Base (KB) PR (KB) Diff (KB) Diff % Base Gzip (KB) PR Gzip (KB) Gzip Diff (KB) Gzip %
🔺 AllEnterpriseModule 1882.74 1891.82 +9.08 +0.5% 515.95 519.07 +3.12 +0.6%
🔺 AdvancedFilterModule 236.62 243.88 +7.26 +3.1% 60.72 63.08 +2.36 +3.9%
🔺 NumberFilterModule 119.45 122.48 +3.03 +2.5% 32.40 33.15 +0.75 +2.3%
🔺 ClientSideRowModelModule, TextFilterModule 113.82 116.52 +2.70 +2.4% 31.03 31.71 +0.68 +2.2%
🔺 TextFilterModule 113.81 116.51 +2.70 +2.4% 31.02 31.71 +0.69 +2.2%
🔺 BigIntFilterModule 116.50 119.01 +2.51 +2.2% 31.72 32.32 +0.60 +1.9%
🔺 CustomFilterModule, DateFilterModule, ExternalFilterModule, MultiFilterModule, NumberFilterModule, QuickFilterModule, SetFilterModule, TextFilterModule 260.74 263.21 +2.47 +0.9% 72.32 73.03 +0.71 +1.0%
🔺 DateFilterModule 125.03 127.32 +2.29 +1.8% 34.37 34.94 +0.57 +1.7%
🔺 AllCommunityModule 439.35 441.54 +2.19 +0.5% 119.17 119.95 +0.78 +0.7%
🔺 Base (no modules) 632.84 633.70 +0.86 +0.1% 178.65 178.91 +0.26 +0.1%
🔺 ValidationModule 101.65 102.24 +0.59 +0.6% 30.71 30.92 +0.21 +0.7%
📊 Full Statistics
  • Modules compared: 90
  • Modules with increases: 16
  • Modules with decreases: 22
  • Modules unchanged: 52

All Module Changes

Module(s) Base (KB) PR (KB) Diff (KB) Diff % Base Gzip (KB) PR Gzip (KB) Gzip Diff (KB) Gzip %
🔺 AllEnterpriseModule 1882.74 1891.82 +9.08 +0.5% 515.95 519.07 +3.12 +0.6%
🔺 AdvancedFilterModule 236.62 243.88 +7.26 +3.1% 60.72 63.08 +2.36 +3.9%
🔺 NumberFilterModule 119.45 122.48 +3.03 +2.5% 32.40 33.15 +0.75 +2.3%
🔺 ClientSideRowModelModule, TextFilterModule 113.82 116.52 +2.70 +2.4% 31.03 31.71 +0.68 +2.2%
🔺 TextFilterModule 113.81 116.51 +2.70 +2.4% 31.02 31.71 +0.69 +2.2%
🔺 BigIntFilterModule 116.50 119.01 +2.51 +2.2% 31.72 32.32 +0.60 +1.9%
🔺 CustomFilterModule, DateFilterModule, ExternalFilterModule, MultiFilterModule, NumberFilterModule, QuickFilterModule, SetFilterModule, TextFilterModule 260.74 263.21 +2.47 +0.9% 72.32 73.03 +0.71 +1.0%
🔺 DateFilterModule 125.03 127.32 +2.29 +1.8% 34.37 34.94 +0.57 +1.7%
🔺 AllCommunityModule 439.35 441.54 +2.19 +0.5% 119.17 119.95 +0.78 +0.7%
🔺 Base (no modules) 632.84 633.70 +0.86 +0.1% 178.65 178.91 +0.26 +0.1%
🔺 ValidationModule 101.65 102.24 +0.59 +0.6% 30.71 30.92 +0.21 +0.7%
🔺 MultiFilterModule 141.23 141.24 +0.01 +0.0% 40.61 40.58 -0.03 -0.1%
🟢 RichSelectModule 169.02 169.01 -0.01 -0.0% 48.61 48.60 -0.01 -0.0%
🟢 CustomEditorModule 86.58 86.57 -0.01 -0.0% 23.62 23.64 +0.02 +0.1%
🔺 GroupFilterModule 119.80 119.81 +0.01 +0.0% 34.74 34.75 +0.01 +0.0%
🟢 RowGroupingEditModule 80.12 80.11 -0.01 -0.0% 25.87 25.86 -0.01 -0.0%
🟢 RowGroupingPanelModule 84.09 84.08 -0.01 -0.0% 24.66 24.67 +0.01 +0.0%
🟢 TextEditorModule 90.34 90.33 -0.01 -0.0% 24.91 24.92 +0.01 +0.0%
🟢 GridStateModule 21.66 21.65 -0.01 -0.0% 5.97 6.00 +0.03 +0.5%
🟢 SparklinesModule 23.55 23.54 -0.01 -0.0% 9.18 9.18 +0.00 +0.0%
🟢 StatusBarModule 31.00 30.99 -0.01 -0.0% 10.86 10.85 -0.01 -0.1%
🟢 ViewportRowModelModule 23.50 23.49 -0.01 -0.0% 8.86 8.88 +0.02 +0.2%
🟢 CellApiModule 0.37 0.36 -0.01 -2.7% 0.10 0.11 +0.01 +10.0%
🟢 CellStyleModule 1.85 1.84 -0.01 -0.5% 0.65 0.65 +0.00 +0.0%
🟢 ClientSideRowModelApiModule 1.91 1.90 -0.01 -0.5% 0.44 0.43 -0.01 -2.3%
🟢 ScrollApiModule 0.71 0.70 -0.01 -1.4% 0.14 0.14 +0.00 +0.0%
🟢 CellSpanModule 9.35 9.34 -0.01 -0.1% 2.42 2.46 +0.04 +1.7%
🟢 FindModule 32.37 32.36 -0.01 -0.0% 11.86 11.89 +0.03 +0.3%
🟢 PaginationPageNumbersModule 59.19 59.18 -0.01 -0.0% 15.68 15.68 +0.00 +0.0%
🟢 ToolbarModule 35.58 35.57 -0.01 -0.0% 11.95 11.97 +0.02 +0.2%
🟢 DateEditorModule 93.96 93.95 -0.01 -0.0% 25.77 25.77 +0.00 +0.0%
🔺 FiltersToolPanelModule 143.52 143.53 +0.01 +0.0% 40.86 40.91 +0.05 +0.1%
🟢 IntegratedChartsModule 414.13 414.12 -0.01 -0.0% 109.40 109.44 +0.04 +0.0%
🟢 LargeTextEditorModule 88.99 88.98 -0.01 -0.0% 24.48 24.51 +0.03 +0.1%
🔺 NewFiltersToolPanelModule 197.81 197.82 +0.01 +0.0% 55.89 55.90 +0.01 +0.0%
🟢 SelectEditorModule 103.32 103.31 -0.01 -0.0% 28.25 28.24 -0.01 -0.0%
🟢 ServerSideRowModelModule 172.03 172.02 -0.01 -0.0% 49.33 49.33 +0.00 +0.0%
🔺 SetFilterModule 144.33 144.34 +0.01 +0.0% 41.60 41.60 +0.00 +0.0%

Updated: 2026-08-10T19:41:44.883Z

@SalvatorePreviti
SalvatorePreviti force-pushed the AG-10819-filter-builder branch from 3c5d7cf to e69592e Compare August 10, 2026 16:50
@SalvatorePreviti

Copy link
Copy Markdown
Contributor Author

/pr-review

@github-actions

Copy link
Copy Markdown
Contributor

Live-test this PR in Plunker

Paste these two <script> tags into a Plunker (or any vanilla-JS host) to load the UMD bundles built from this PR:

<script src="https://ag-grid.github.io/ag-grid/pr-14783/ag-grid-community.min.js"></script>
<script src="https://ag-grid.github.io/ag-grid/pr-14783/ag-grid-enterprise.min.js"></script>

Bundles are removed automatically when the PR is closed. Updated on every push.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

✅ Codex review complete; 6 issues found (P0: 0 | P1: 0 | P2: 6 | P3: 0)

View full review

AG-10819 advanced filter

PR: #14783
Author: SalvatorePreviti | Base: latest ← Head: AG-10819-filter-builder
Diff: 90 files changed, +7398 -1012

Summary

This PR adds custom filter options to Advanced Filter, including multi-operand parsing, Builder support, validation, and related filter infrastructure updates. Adds extensive behavioural coverage and test harnesses for custom filter options, validation, formatting, and floating filters.

Findings

P0: 0 | P1: 0 | P2: 6 | P3: 0

6 of 6 finding(s) also posted inline; all findings are listed below.

ℹ️ [P2] Formatter validation does not model the actual input constraints

packages/ag-grid-community/src/filter/provided/number/numberFilterUtils.ts:25

The native-input branch uses Number(formatted), which accepts values such as hexadecimal or padded strings that an HTML number input may reject. The text-input branch receives only a boolean and never checks formatted characters against allowedCharPattern. Consequently invalid formatter output can bypass the fallback, appear blank or be impossible to re-enter, and omit warning 326.

ℹ️ [P2] Floating filters bypass the new formatter fallback

packages/ag-grid-community/src/filter/provided/number/numberFilterModelFormatter.ts:11

NumberFilterModelFormatter returns numberFormatter output unconditionally, and floating filters use this formatter for their displayed value. When a native number floating-filter input cannot hold formatted text such as "1,000", it can become blank even though the main filter now falls back to the unformatted number. Apply the same round-trip validation to floating-filter formatting.

ℹ️ [P2] Changing a retained option's arity preserves stale input values

packages/ag-grid-community/src/filter/provided/simpleFilter.ts:202

During a filterOptions refresh, inputs are cleared only when the selected key disappears. If the same custom displayKey changes numberOfInputs, newly active inputs retain values previously hidden under the old definition, potentially producing an unintended filterTo value. Clear values whose slots were not active under the previous option definition.

ℹ️ [P2] Column changes can resurrect stale operands

packages/ag-grid-enterprise/src/advancedFilter/builder/conditionPillWrapperComp.ts:236

When the same custom key exists on both columns with different arities, changing columns updates numOperands and rebuilds the pills without clearing newly introduced operand slots. A stale filterTo supplied on the previous one-input model can therefore become the second operand on the new column. This path should clear slots added by the arity increase, as setOperatorKey already does.

ℹ️ [P2] Validation and console mocks leak between tests

testing/behavioural/src/filters/column-filter-custom-options.test.ts:93

This describe block only resets grids, but the text inRange test changes global development-validation settings and mocks console.warn. Those changes remain active for subsequent tests, potentially suppressing unexpected warnings and making results order-dependent. Restore mocks and reset validations in afterEach.

ℹ️ [P2] Number-filter case supplies a text-filter model

testing/behavioural/src/filters/column-filter-custom-options.test.ts:693

The parameterised test always sets filterType to "text", including for agNumberColumnFilter. The number branch therefore uses a malformed model and may pass because of filter-type handling rather than because the required second operand is absent. Use the corresponding "number" discriminator for that case.

Verdict

Assessment: correct
Confidence: 0.87

The core custom-option implementation is coherent and extensively covered, but several edge cases around formatter validation and operand reuse can expose stale or unusable filter values. The changes are broadly coherent, but two test-isolation and coverage defects weaken the reliability of the new suite.

Required Actions:

  • Validate formatter output against the actual input constraints across main and floating filters.
  • Clear newly activated operand slots when option arity changes.
  • Restore console mocks and validation settings after each affected test
  • Use the correct filterType in the parameterised number-filter case

@SalvatorePreviti
SalvatorePreviti force-pushed the AG-10819-filter-builder branch from e69592e to 7f6470c Compare August 10, 2026 17:28
@SalvatorePreviti

Copy link
Copy Markdown
Contributor Author

/pr-review

1 similar comment
@SalvatorePreviti

Copy link
Copy Markdown
Contributor Author

/pr-review

@SalvatorePreviti
SalvatorePreviti force-pushed the AG-10819-filter-builder branch 2 times, most recently from 740cd30 to 8b9b465 Compare August 10, 2026 19:36
@SalvatorePreviti

Copy link
Copy Markdown
Contributor Author

/pr-review

@sonarqubecloud

Copy link
Copy Markdown

if (formatted == null || formatted.trim() === '') {
return false;
}
return (usesTextInput ? stringToFloat(numberParser, formatted) : Number(formatted)) === value;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ [P2] Formatter validation does not model the actual input constraints

The native-input branch uses Number(formatted), which accepts values such as hexadecimal or padded strings that an HTML number input may reject. The text-input branch receives only a boolean and never checks formatted characters against allowedCharPattern. Consequently invalid formatter output can bypass the fallback, appear blank or be impossible to re-enter, and omit warning 326.


constructor(optionsFactory: OptionsFactory, filterParams: INumberFilterParams) {
super(optionsFactory, filterParams, filterParams.numberFormatter);
protected override getValueFormatter(): ((value: number | null) => string | null) | undefined {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ [P2] Floating filters bypass the new formatter fallback

NumberFilterModelFormatter returns numberFormatter output unconditionally, and floating filters use this formatter for their displayed value. When a native number floating-filter input cannot hold formatted text such as "1,000", it can become blank even though the main filter now falls back to the unformatted number. Apply the same round-trip validation to floating-filter formatting.

Comment on lines +202 to +207
eType.clearOptions();
this.putOptionsIntoDropdown(eType);
const isStillOffered = optionsFactory.hasOption(selectedType);
eType.setValue(isStillOffered ? selectedType : optionsFactory.defaultOption, true);
if (!isStillOffered) {
// Values the withdrawn option collected mean nothing to the one replacing it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ [P2] Changing a retained option's arity preserves stale input values

During a filterOptions refresh, inputs are cleared only when the selected key disappears. If the same custom displayKey changes numberOfInputs, newly active inputs retain values previously hidden under the old definition, potentially producing an unintended filterTo value. Clear values whose slots were not active under the previous option definition.

Comment on lines +236 to +237
// The kept operator can take a different number of values on this column.
this.numOperands = this.getNumOperands(this.filterModel.type);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ [P2] Column changes can resurrect stale operands

When the same custom key exists on both columns with different arities, changing columns updates numOperands and rebuilds the pills without clearing newly introduced operand slots. A stale filterTo supplied on the previous one-input model can therefore become the second operand on the new column. This path should clear slots added by the arity increase, as setOperatorKey already does.

});
afterAll(() => uninstallFilterLayoutMock());
afterEach(() => gridsManager.reset());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ [P2] Validation and console mocks leak between tests

This describe block only resets grids, but the text inRange test changes global development-validation settings and mocks console.warn. Those changes remain active for subsequent tests, potentially suppressing unexpected warnings and making results order-dependent. Restore mocks and reset validations in afterEach.


await new GridRows(api, `incomplete ${_name} model leaves every row`).check(`
ROOT id:ROOT_NODE_ID
├── LEAF id:0 athlete:"Bolt"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ [P2] Number-filter case supplies a text-filter model

The parameterised test always sets filterType to "text", including for agNumberColumnFilter. The number branch therefore uses a malformed model and may pass because of filter-type handling rather than because the required second operand is absent. Use the corresponding "number" discriminator for that case.

@SalvatorePreviti
SalvatorePreviti force-pushed the AG-10819-filter-builder branch from 8b9b465 to 4f47e9b Compare August 12, 2026 08:06
@SalvatorePreviti
SalvatorePreviti marked this pull request as draft August 28, 2026 07:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant