diff options
| author | seanhelvey <sean.helvey@gmail.com> | 2024-12-13 11:56:53 -0800 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2026-01-22 21:12:23 -0500 |
| commit | b1ffa9a9d78b0c2c5ad6ed5a1d84e380d5cfd010 (patch) | |
| tree | 0fcfd9b90c788e21e58cb9249f4119062b8bfc4e /js_tests | |
| parent | 3851601b2e080df34fb9227fe5d2fd43af604263 (diff) | |
Fixed #13883 -- Rendered named choice groups with <optgroup> in FilteredSelectMultiple.
This patch adds support for <optgroup>s in FilteredSelectMultiple widgets.
When a popup returns a new object, if the source field contains optgroup
choices, the optgroup is now also included in the response data.
Additionally, this adds error handling for invalid source_model parameters
to prevent crashes and display user-friendly error messages instead.
Co-authored-by: Michael McLarnon <mmclar@gmail.com>
Diffstat (limited to 'js_tests')
| -rw-r--r-- | js_tests/admin/SelectBox.test.js | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/js_tests/admin/SelectBox.test.js b/js_tests/admin/SelectBox.test.js index 7d127b5d59..4915ba6b9b 100644 --- a/js_tests/admin/SelectBox.test.js +++ b/js_tests/admin/SelectBox.test.js @@ -45,3 +45,163 @@ QUnit.test('preserve scroll position', function(assert) { assert.equal(toSelectBox.options.length, selectedOptions.length); assert.notEqual(fromSelectBox.scrollTop, 0); }); + +QUnit.test('retain optgroups', function(assert) { + const $ = django.jQuery; + $('<select id="id"></select>').appendTo('#qunit-fixture'); + const grp = $('<optgroup label="group one">').appendTo('#id'); + $('<option value="0">A</option>').appendTo(grp); + $('</optgroup>').appendTo('#id'); + $('<option value="1">B</option>').appendTo('#id'); + SelectBox.init('id'); + SelectBox.redisplay('id'); + assert.equal($('#id option').length, 2); + assert.equal($('#id optgroup').length, 1); +}); + +QUnit.test('sort optgroups', function(assert) { + const $ = django.jQuery; + $('<select id="id"></select>').appendTo('#qunit-fixture'); + // Add optgroups in non-alphabetical order + const grp2 = $('<optgroup label="Group B">').appendTo('#id'); + $('<option value="3">Item 3</option>').appendTo(grp2); + $('<option value="4">Item 4</option>').appendTo(grp2); + const grp1 = $('<optgroup label="Group A">').appendTo('#id'); + $('<option value="1">Item 1</option>').appendTo(grp1); + $('<option value="2">Item 2</option>').appendTo(grp1); + + SelectBox.init('id'); + + // Verify cache is sorted by group then by item + assert.equal(SelectBox.cache.id.length, 4); + assert.equal(SelectBox.cache.id[0].group, 'Group A'); + assert.equal(SelectBox.cache.id[0].text, 'Item 1'); + assert.equal(SelectBox.cache.id[1].group, 'Group A'); + assert.equal(SelectBox.cache.id[1].text, 'Item 2'); + assert.equal(SelectBox.cache.id[2].group, 'Group B'); + assert.equal(SelectBox.cache.id[2].text, 'Item 3'); + assert.equal(SelectBox.cache.id[3].group, 'Group B'); + assert.equal(SelectBox.cache.id[3].text, 'Item 4'); +}); + +QUnit.test('do not sort when no optgroups', function(assert) { + const $ = django.jQuery; + $('<select id="id"></select>').appendTo('#qunit-fixture'); + // Add options in non-alphabetical order + $('<option value="3">Zebra</option>').appendTo('#id'); + $('<option value="1">Apple</option>').appendTo('#id'); + $('<option value="2">Banana</option>').appendTo('#id'); + + SelectBox.init('id'); + + // Verify cache preserves original order (not sorted) + assert.equal(SelectBox.cache.id.length, 3); + assert.equal(SelectBox.cache.id[0].text, 'Zebra'); + assert.equal(SelectBox.cache.id[1].text, 'Apple'); + assert.equal(SelectBox.cache.id[2].text, 'Banana'); +}); + +QUnit.test('move with optgroups sorts', function(assert) { + const $ = django.jQuery; + $('<select id="from_id"></select>').appendTo('#qunit-fixture'); + $('<select id="to_id"></select>').appendTo('#qunit-fixture'); + + // Add options with optgroups to from_id in non-alphabetical order + const grp2 = $('<optgroup label="Group B">').appendTo('#from_id'); + $('<option value="2">Item 2</option>').appendTo(grp2); + const grp1 = $('<optgroup label="Group A">').appendTo('#from_id'); + $('<option value="1">Item 1</option>').appendTo(grp1); + + SelectBox.init('from_id'); + SelectBox.init('to_id'); + + // Select and move item + document.getElementById('from_id').options[0].selected = true; + SelectBox.move('from_id', 'to_id'); + + // Verify to_id cache is sorted (even though we only added one item) + assert.equal(SelectBox.cache.to_id.length, 1); + assert.equal(SelectBox.cache.to_id[0].group, 'Group B'); + assert.equal(SelectBox.cache.to_id[0].text, 'Item 2'); +}); + +QUnit.test('move without optgroups does not sort', function(assert) { + const $ = django.jQuery; + $('<select id="from_id"></select>').appendTo('#qunit-fixture'); + $('<select id="to_id"></select>').appendTo('#qunit-fixture'); + + // Add options without optgroups in non-alphabetical order + $('<option value="3">Zebra</option>').appendTo('#from_id'); + $('<option value="1">Apple</option>').appendTo('#from_id'); + + SelectBox.init('from_id'); + SelectBox.init('to_id'); + + // Select and move first item (Zebra) + document.getElementById('from_id').options[0].selected = true; + SelectBox.move('from_id', 'to_id'); + + // Verify to_id cache preserves order (not sorted) + assert.equal(SelectBox.cache.to_id.length, 1); + assert.equal(SelectBox.cache.to_id[0].text, 'Zebra'); + + // Move second item (Apple) + document.getElementById('from_id').options[0].selected = true; + SelectBox.move('from_id', 'to_id'); + + // Verify items are in order they were added, not alphabetical + assert.equal(SelectBox.cache.to_id.length, 2); + assert.equal(SelectBox.cache.to_id[0].text, 'Zebra'); + assert.equal(SelectBox.cache.to_id[1].text, 'Apple'); +}); + +QUnit.test('move_all with optgroups sorts', function(assert) { + const $ = django.jQuery; + $('<select id="from_id"></select>').appendTo('#qunit-fixture'); + $('<select id="to_id"></select>').appendTo('#qunit-fixture'); + + // Add options with optgroups in non-alphabetical order + const grp2 = $('<optgroup label="Group B">').appendTo('#from_id'); + $('<option value="3">Zebra</option>').appendTo(grp2); + const grp1 = $('<optgroup label="Group A">').appendTo('#from_id'); + $('<option value="1">Apple</option>').appendTo(grp1); + $('<option value="2">Banana</option>').appendTo(grp1); + + SelectBox.init('from_id'); + SelectBox.init('to_id'); + + // Move all items + SelectBox.move_all('from_id', 'to_id'); + + // Verify to_id cache is sorted by group + assert.equal(SelectBox.cache.to_id.length, 3); + assert.equal(SelectBox.cache.to_id[0].group, 'Group A'); + assert.equal(SelectBox.cache.to_id[0].text, 'Apple'); + assert.equal(SelectBox.cache.to_id[1].group, 'Group A'); + assert.equal(SelectBox.cache.to_id[1].text, 'Banana'); + assert.equal(SelectBox.cache.to_id[2].group, 'Group B'); + assert.equal(SelectBox.cache.to_id[2].text, 'Zebra'); +}); + +QUnit.test('move_all without optgroups does not sort', function(assert) { + const $ = django.jQuery; + $('<select id="from_id"></select>').appendTo('#qunit-fixture'); + $('<select id="to_id"></select>').appendTo('#qunit-fixture'); + + // Add options without optgroups in non-alphabetical order + $('<option value="3">Zebra</option>').appendTo('#from_id'); + $('<option value="1">Apple</option>').appendTo('#from_id'); + $('<option value="2">Banana</option>').appendTo('#from_id'); + + SelectBox.init('from_id'); + SelectBox.init('to_id'); + + // Move all items + SelectBox.move_all('from_id', 'to_id'); + + // Verify to_id cache preserves original order (not sorted) + assert.equal(SelectBox.cache.to_id.length, 3); + assert.equal(SelectBox.cache.to_id[0].text, 'Zebra'); + assert.equal(SelectBox.cache.to_id[1].text, 'Apple'); + assert.equal(SelectBox.cache.to_id[2].text, 'Banana'); +}); |
