1
0
mirror of synced 2026-10-23 07:08:55 +03:00

Fix the parameter value dropdown keeping stale options when the parameter name is changed. #9630 (#10579)

This commit is contained in:
Dave Page
2026-10-15 10:37:52 +01:00
parent 5063c76a06
commit 72ab768b94
2 changed files with 79 additions and 0 deletions

View File

@@ -107,6 +107,9 @@ export default class VariableSchema extends BaseUISchema {
label: val,
value: val
}: val)),
/* The select keeps its loaded options until this changes, so switching
the name between two enum variables must force a reload. */
optionsReloadBasis: variable.value,
controlProps: {
placeholder: this.getPlaceHolderMsg(variable)
}

View File

@@ -8,6 +8,7 @@
//////////////////////////////////////////////////////////////
import { fireEvent, screen, waitFor } from '@testing-library/react';
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
import VariableSchema, {getNodeVariableSchema} from '../../../pgadmin/browser/server_groups/servers/static/js/variable.ui';
import * as nodeAjax from '../../../pgadmin/browser/static/js/node_ajax';
@@ -64,6 +65,16 @@ describe('VariableSchema', ()=>{
expect(schemaObj.getValueFieldProps({vartype: 'enum', enumvals: []})).toEqual(expect.objectContaining({
cell: 'select',
}));
expect(schemaObj.getValueFieldProps({
value: 'sslnegotiation', vartype: 'enum', enumvals: ['postgres', 'direct'],
})).toEqual(expect.objectContaining({
cell: 'select',
optionsReloadBasis: 'sslnegotiation',
options: [
{label: 'postgres', value: 'postgres'},
{label: 'direct', value: 'direct'},
],
}));
expect(schemaObj.getValueFieldProps({vartype: 'integer'})).toEqual(expect.objectContaining({
cell: 'int',
}));
@@ -79,6 +90,71 @@ describe('VariableSchema', ()=>{
expect(schemaObj.getValueFieldProps({})).toBe('');
});
it('value options follow a change of enum variable name', async ()=>{
const varOptions = [{
value: 'sslmode', label: 'sslmode', vartype: 'enum',
enumvals: ['prefer', 'require'],
}, {
value: 'sslnegotiation', label: 'sslnegotiation', vartype: 'enum',
enumvals: ['postgres', 'direct'],
}];
let varCollObj = new MockSchema(
()=>new VariableSchema(varOptions, null, null, ['name', 'value'])
);
const {ctrl, user} = await getCreateView(varCollObj);
await user.click(ctrl.container.querySelector('[data-test="add-row"]'));
const rowSelects = ()=>ctrl.container.querySelectorAll(
'[data-test="data-table-row"] input[role="combobox"]'
);
const hiddenVal = (name)=>ctrl.container.querySelector(
`[data-test="data-table-row"] input[type="hidden"][name="${name}"]`
)?.value;
/* Allow for slow CI runners re-rendering the grid row. */
const waitOpts = {timeout: 10000};
/* Open the select from the keyboard and wait for an option to show. A
freshly mounted select can drop the first open request on slow runners,
so it is re-sent, a bounded number of times, whilst no menu is shown. */
const findOption = async (selectIdx, label)=>{
for(let attempt = 0; attempt < 5; attempt++) {
if(screen.queryAllByRole('option').length == 0) {
const input = rowSelects()[selectIdx];
fireEvent.focus(input);
fireEvent.keyDown(input, {key: 'ArrowDown', keyCode: 40});
}
try {
return await screen.findByRole('option', {name: label}, {timeout: 2000});
} catch {
/* Not shown yet; retry. */
}
}
throw new Error(`Option '${label}' not shown; options: ${
screen.queryAllByRole('option').map((o)=>o.textContent).join(', ')
}`);
};
const closeMenu = ()=>{
fireEvent.keyDown(rowSelects()[1], {key: 'Escape', keyCode: 27});
};
const pickName = async (label)=>{
await user.click(await findOption(0, label));
await waitFor(()=>{
expect(hiddenVal('name')).toBe(label);
expect(hiddenVal('value')).toBe('');
expect(rowSelects().length).toBe(2);
}, waitOpts);
};
await waitFor(()=>expect(rowSelects().length).toBeGreaterThan(0), waitOpts);
await pickName('sslmode');
expect(await findOption(1, 'require')).toBeInTheDocument();
closeMenu();
await waitFor(()=>expect(screen.queryAllByRole('option')).toHaveLength(0), waitOpts);
await pickName('sslnegotiation');
expect(await findOption(1, 'direct')).toBeInTheDocument();
expect(screen.queryByRole('option', {name: 'require'})).not.toBeInTheDocument();
}, 30000);
it('variable collection', async ()=>{
jest.spyOn(nodeAjax, 'getNodeAjaxOptions').mockReturnValue([]);
jest.spyOn(nodeAjax, 'getNodeListByName').mockReturnValue([]);