chore: 🤖 migrate host catalog and host set list wrapper fields to key value (#3276)
This commit is contained in:
1 parent
4e2b779d96
commit
0e223ded8f
26 files changed
+512
-388
No files matched your search
@@ -97,9 +97,7 @@ module('Acceptance | host-catalogs | host sets | create', function (hooks) {
|
||||
const name = 'aws host set';
|
||||
await fillIn(commonSelectors.FIELD_NAME, name);
|
||||
await fillIn(selectors.FIELD_PREFERRED_ENDPOINT, 'endpoint');
|
||||
await click(selectors.FIELD_PREFERRED_ENDPOINT_ADD_BTN);
|
||||
await fillIn(selectors.FIELD_FILTERS, 'filter_test');
|
||||
await click(selectors.FIELD_FILTERS_ADD_BTN);
|
||||
|
||||
await fillIn(selectors.FIELD_SYNC_INTERVAL, 10);
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
@@ -128,7 +126,6 @@ module('Acceptance | host-catalogs | host sets | create', function (hooks) {
|
||||
const name = 'azure host set';
|
||||
await fillIn(commonSelectors.FIELD_NAME, name);
|
||||
await fillIn(selectors.FIELD_PREFERRED_ENDPOINT, 'endpoint');
|
||||
await click(selectors.FIELD_PREFERRED_ENDPOINT_ADD_BTN);
|
||||
await fillIn(selectors.FIELD_AZURE_FILTER, 'filter');
|
||||
await fillIn(selectors.FIELD_SYNC_INTERVAL, 10);
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
@@ -157,9 +154,7 @@ module('Acceptance | host-catalogs | host sets | create', function (hooks) {
|
||||
const name = 'gcp host set';
|
||||
await fillIn(commonSelectors.FIELD_NAME, name);
|
||||
await fillIn(selectors.FIELD_PREFERRED_ENDPOINT, 'endpoint');
|
||||
await click(selectors.FIELD_PREFERRED_ENDPOINT_ADD_BTN);
|
||||
await fillIn(selectors.FIELD_FILTERS, 'filter_test');
|
||||
await click(selectors.FIELD_FILTERS_ADD_BTN);
|
||||
|
||||
await fillIn(selectors.FIELD_SYNC_INTERVAL, 10);
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
|
||||
@@ -3,17 +3,18 @@
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
export const FIELD_PREFERRED_ENDPOINT = '[name=preferred_endpoints] input';
|
||||
export const FIELD_PREFERRED_ENDPOINT =
|
||||
'[name=preferred_endpoints] [data-test-value-input]';
|
||||
export const FIELD_PREFERRED_ENDPOINT_ADD_BTN =
|
||||
'[name=preferred_endpoints] button';
|
||||
'[name=preferred_endpoints] [data-test-add-button]';
|
||||
export const FIELD_PREFERRED_ENDPOINT_DELETE_BTN =
|
||||
'[name=preferred_endpoints] [data-test-remove-button]';
|
||||
export const FIELD_FILTERS = '[name=filters] input';
|
||||
export const FIELD_FILTERS_ADD_BTN = '[name=filters] button';
|
||||
'[name=preferred_endpoints] [data-test-delete-button]';
|
||||
export const FIELD_FILTERS = '[name=filters] [data-test-value-input]';
|
||||
export const FIELD_FILTERS_ADD_BTN = '[name=filters] [data-test-add-button]';
|
||||
export const FIELD_SYNC_INTERVAL = '[name=sync_interval_seconds]';
|
||||
export const FIELD_AZURE_FILTER = '[name=filter]';
|
||||
export const FIELD_FILTERS_REMOVE_BTN =
|
||||
'[name=filters] [data-test-remove-button]';
|
||||
'[name=filters] [data-test-delete-button]';
|
||||
|
||||
export const MANAGE_DROPDOWN_HOST_CATALOG =
|
||||
'[data-test-manage-host-catalogs-dropdown] button';
|
||||
|
||||
@@ -172,7 +172,6 @@ module('Acceptance | host-catalogs | host sets | update', function (hooks) {
|
||||
);
|
||||
|
||||
await fillIn(selectors.FIELD_PREFERRED_ENDPOINT, mockEndpoint);
|
||||
await click(selectors.FIELD_PREFERRED_ENDPOINT_ADD_BTN);
|
||||
|
||||
const filterList = await Promise.all(
|
||||
findAll(selectors.FIELD_FILTERS_REMOVE_BTN),
|
||||
@@ -184,7 +183,6 @@ module('Acceptance | host-catalogs | host sets | update', function (hooks) {
|
||||
assert.strictEqual(findAll(selectors.FIELD_FILTERS_REMOVE_BTN).length, 0);
|
||||
|
||||
await fillIn(selectors.FIELD_FILTERS, mockFilter);
|
||||
await click(selectors.FIELD_FILTERS_ADD_BTN);
|
||||
await fillIn(selectors.FIELD_SYNC_INTERVAL, 10);
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
|
||||
@@ -216,7 +214,6 @@ module('Acceptance | host-catalogs | host sets | update', function (hooks) {
|
||||
);
|
||||
|
||||
await fillIn(selectors.FIELD_PREFERRED_ENDPOINT, mockEndpoint);
|
||||
await click(selectors.FIELD_PREFERRED_ENDPOINT_ADD_BTN);
|
||||
await fillIn(selectors.FIELD_AZURE_FILTER, 'filter');
|
||||
await fillIn(selectors.FIELD_SYNC_INTERVAL, 10);
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
@@ -247,7 +244,6 @@ module('Acceptance | host-catalogs | host sets | update', function (hooks) {
|
||||
);
|
||||
|
||||
await fillIn(selectors.FIELD_PREFERRED_ENDPOINT, 'sample endpoint');
|
||||
await click(selectors.FIELD_PREFERRED_ENDPOINT_ADD_BTN);
|
||||
|
||||
// Remove all the filters
|
||||
const filterList = await Promise.all(
|
||||
@@ -260,7 +256,6 @@ module('Acceptance | host-catalogs | host sets | update', function (hooks) {
|
||||
assert.strictEqual(findAll(selectors.FIELD_FILTERS_REMOVE_BTN).length, 0);
|
||||
|
||||
await fillIn(selectors.FIELD_FILTERS, 'sample filters');
|
||||
await click(selectors.FIELD_FILTERS_ADD_BTN);
|
||||
await fillIn(selectors.FIELD_SYNC_INTERVAL, 10);
|
||||
await click(commonSelectors.SAVE_BTN);
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
const getValueInputs = () => findAll('[data-test-value-input]');
|
||||
const getDeleteButtons = () => findAll('[data-test-delete-button]');
|
||||
|
||||
test('it renders with default empty row', async function (assert) {
|
||||
test('it renders with default and provided data', async function (assert) {
|
||||
// Default empty row
|
||||
this.set('data', [{ key: '', value: '' }]);
|
||||
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue @data={{this.data}}>
|
||||
<:row as |R|>
|
||||
@@ -43,14 +43,12 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
assert.dom('[data-test-value-input]').exists();
|
||||
assert.dom('[data-test-add-button]').exists();
|
||||
assert.dom('[data-test-delete-button]').doesNotExist();
|
||||
});
|
||||
|
||||
test('it renders with provided data', async function (assert) {
|
||||
// Provided data
|
||||
this.set('data', [
|
||||
{ key: 'env', value: 'production' },
|
||||
{ key: 'region', value: 'us-east-1' },
|
||||
]);
|
||||
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue
|
||||
@data={{this.data}}
|
||||
@@ -72,13 +70,10 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
</:footer>
|
||||
</Form::Field::KeyValue>
|
||||
`);
|
||||
|
||||
const keyInputs = getKeyInputs();
|
||||
const valueInputs = getValueInputs();
|
||||
|
||||
assert.strictEqual(keyInputs.length, 2);
|
||||
assert.strictEqual(valueInputs.length, 2);
|
||||
|
||||
assert.dom(keyInputs[0]).hasValue('env');
|
||||
assert.dom(keyInputs[1]).hasValue('region');
|
||||
assert.dom(valueInputs[0]).hasValue('production');
|
||||
@@ -87,7 +82,7 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
assert.dom('.hds-form-helper-text ').hasText('Test helper text');
|
||||
});
|
||||
|
||||
test('it adds new rows', async function (assert) {
|
||||
test('it adds new rows using custom handlers', async function (assert) {
|
||||
this.set('data', [{ key: '', value: '' }]);
|
||||
this.set('onAdd', () => {
|
||||
this.data.push({ key: '', value: '' });
|
||||
@@ -107,7 +102,7 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
<F.TextInput data-test-value-input @value={{R.rowData.value}} {{on 'input' (fn R.updateRow 'value')}} />
|
||||
</R.Field>
|
||||
{{#if R.canDelete}}
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
{{/if}}
|
||||
</:row>
|
||||
<:footer as |F|>
|
||||
@@ -117,89 +112,22 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
`);
|
||||
|
||||
assert.strictEqual(getKeyInputs().length, 1, 'Initially has one row');
|
||||
|
||||
await click('[data-test-add-button]');
|
||||
|
||||
assert.strictEqual(
|
||||
getKeyInputs().length,
|
||||
2,
|
||||
'After clicking add, has two rows',
|
||||
);
|
||||
assert.strictEqual(getValueInputs().length, 2);
|
||||
|
||||
// Fill in the second row
|
||||
await fillIn(getKeyInputs()[1], 'test-key');
|
||||
await fillIn(getValueInputs()[1], 'test-value');
|
||||
|
||||
// Check that the data was updated
|
||||
assert.strictEqual(this.data.length, 2);
|
||||
assert.strictEqual(this.data[1].key, 'test-key');
|
||||
assert.strictEqual(this.data[1].value, 'test-value');
|
||||
});
|
||||
|
||||
test('it removes rows', async function (assert) {
|
||||
this.set('data', [
|
||||
{ key: 'key1', value: 'value1' },
|
||||
{ key: 'key2', value: 'value2' },
|
||||
]);
|
||||
this.set('onRemove', (rowData) => {
|
||||
// Remove the row from the data array
|
||||
let newData = this.data.filter((item) => item !== rowData);
|
||||
// Ensure at least one empty row remains
|
||||
if (newData.length === 0) {
|
||||
newData = [{ key: '', value: '' }];
|
||||
}
|
||||
this.set('data', newData);
|
||||
});
|
||||
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue @data={{this.data}} @onRemove={{this.onRemove}}>
|
||||
<:row as |R|>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-key-input @value={{R.rowData.key}} {{on 'input' (fn R.updateRow 'key')}} />
|
||||
</R.Field>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-value-input @value={{R.rowData.value}} {{on 'input' (fn R.updateRow 'value')}} />
|
||||
</R.Field>
|
||||
{{#if R.canDelete}}
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
{{/if}}
|
||||
</:row>
|
||||
<:footer as |F|>
|
||||
<F.AddRowButton />
|
||||
</:footer>
|
||||
</Form::Field::KeyValue>
|
||||
`);
|
||||
|
||||
assert.strictEqual(getKeyInputs().length, 2, 'Initially has two rows');
|
||||
|
||||
// Remove first row
|
||||
await click(getDeleteButtons()[0]);
|
||||
|
||||
assert.strictEqual(
|
||||
getKeyInputs().length,
|
||||
1,
|
||||
'After removing first row, has one row',
|
||||
);
|
||||
assert.dom('[data-test-key-input]').hasValue('key2');
|
||||
assert.dom('[data-test-value-input]').hasValue('value2');
|
||||
|
||||
// Remove second row - should ensure at least one empty row remains
|
||||
await click(getDeleteButtons()[0]);
|
||||
|
||||
assert.strictEqual(
|
||||
getKeyInputs().length,
|
||||
1,
|
||||
'After removing all rows, still has one empty row',
|
||||
);
|
||||
assert
|
||||
.dom('[data-test-key-input]')
|
||||
.hasValue('', 'The remaining row has empty key');
|
||||
assert
|
||||
.dom('[data-test-value-input]')
|
||||
.hasValue('', 'The remaining row has empty value');
|
||||
});
|
||||
|
||||
test('it handles different field types', async function (assert) {
|
||||
this.set('data', [{ key: 'k', value: 'v', id: 1 }]);
|
||||
|
||||
@@ -282,6 +210,7 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
{ message: 'Value must be unique' },
|
||||
]);
|
||||
|
||||
// With errors
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue @data={{this.data}} @errors={{this.errors}}>
|
||||
<:row as |R|>
|
||||
@@ -300,18 +229,15 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
</:footer>
|
||||
</Form::Field::KeyValue>
|
||||
`);
|
||||
|
||||
assert.dom('[data-test-error-message]').exists().hasText('Key is required');
|
||||
assert
|
||||
.dom('[data-test-error-message]:nth-child(2)')
|
||||
.hasText('Value must be unique');
|
||||
});
|
||||
|
||||
test('it does not show error messages when no errors are provided', async function (assert) {
|
||||
this.set('data', [{ key: '', value: '' }]);
|
||||
|
||||
// Without errors
|
||||
this.set('errors', undefined);
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue @data={{this.data}}>
|
||||
<Form::Field::KeyValue @data={{this.data}} @errors={{this.errors}}>
|
||||
<:row as |R|>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-key-input @value={{R.rowData.key}} />
|
||||
@@ -328,11 +254,10 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
</:footer>
|
||||
</Form::Field::KeyValue>
|
||||
`);
|
||||
|
||||
assert.dom('[data-test-error-message]').doesNotExist();
|
||||
});
|
||||
|
||||
test('it updates both key and value fields', async function (assert) {
|
||||
test('it updates both key and value fields using custom handlers', async function (assert) {
|
||||
this.set('data', [{ key: '', value: '' }]);
|
||||
this.set('onUpdate', (rowData, property, { target: { value } }) => {
|
||||
rowData[property] = value;
|
||||
@@ -393,4 +318,174 @@ module('Integration | Component | form/field/key-value', function (hooks) {
|
||||
|
||||
assert.strictEqual(getDeleteButtons().length, 3);
|
||||
});
|
||||
|
||||
test('custom handlers take precedence over default handlers', async function (assert) {
|
||||
const model = {
|
||||
tags: [{ key: '', value: '' }],
|
||||
};
|
||||
this.set('model', model);
|
||||
|
||||
this.set('onAdd', () => {
|
||||
model.tags.push({ key: 'custom', value: 'custom' });
|
||||
this.set('model', { ...model, tags: [...model.tags] });
|
||||
});
|
||||
|
||||
this.set('onRemove', (rowData) => {
|
||||
model.tags = model.tags.filter((item) => item !== rowData);
|
||||
this.set('model', { ...model, tags: [...model.tags] });
|
||||
});
|
||||
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue
|
||||
@model={{this.model}}
|
||||
@name="tags"
|
||||
@properties={{array 'key' 'value'}}
|
||||
@data={{this.model.tags}}
|
||||
@onAdd={{this.onAdd}}
|
||||
@onRemove={{this.onRemove}}
|
||||
@onUpdate={{this.onUpdate}}>
|
||||
<:row as |R|>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-key-input @value={{R.rowData.key}} {{on 'input' (fn R.updateRow 'key')}} />
|
||||
</R.Field>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-value-input @value={{R.rowData.value}} {{on 'input' (fn R.updateRow 'value')}} />
|
||||
</R.Field>
|
||||
{{#if R.canDelete}}
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
{{/if}}
|
||||
</:row>
|
||||
</Form::Field::KeyValue>
|
||||
`);
|
||||
|
||||
// Test custom add handler takes precedence
|
||||
await click('[data-test-add-button]');
|
||||
|
||||
assert.strictEqual(model.tags.length, 2);
|
||||
assert.strictEqual(model.tags[1].key, 'custom');
|
||||
assert.strictEqual(model.tags[1].value, 'custom');
|
||||
|
||||
// Test custom update handler takes precedence
|
||||
await fillIn(getKeyInputs()[0], 'test');
|
||||
|
||||
// Test custom remove handler takes precedence
|
||||
await click(getDeleteButtons()[0]);
|
||||
|
||||
assert.strictEqual(model.tags.length, 1);
|
||||
assert.strictEqual(model.tags[0].key, 'custom');
|
||||
});
|
||||
|
||||
test('it adds row using default handler (model/name/properties)', async function (assert) {
|
||||
const model = { tags: [{ key: 'a', value: 'b' }] };
|
||||
this.set('model', model);
|
||||
this.set('properties', ['key', 'value']);
|
||||
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue
|
||||
@model={{this.model}}
|
||||
@name="tags"
|
||||
@properties={{this.properties}}
|
||||
@data={{this.model.tags}}>
|
||||
<:row as |R|>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-key-input @value={{R.rowData.key}} />
|
||||
</R.Field>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-value-input @value={{R.rowData.value}} />
|
||||
</R.Field>
|
||||
{{#if R.canDelete}}
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
{{/if}}
|
||||
</:row>
|
||||
<:footer as |F|>
|
||||
<F.AddRowButton />
|
||||
</:footer>
|
||||
</Form::Field::KeyValue>
|
||||
`);
|
||||
|
||||
assert.strictEqual(model.tags.length, 1);
|
||||
|
||||
await click('[data-test-add-button]');
|
||||
|
||||
assert.strictEqual(model.tags.length, 2);
|
||||
|
||||
assert.deepEqual(model.tags[1], { key: '', value: '' });
|
||||
});
|
||||
|
||||
test('it removes row using default handler (model/name)', async function (assert) {
|
||||
const model = {
|
||||
tags: [
|
||||
{ key: 'a', value: 'b' },
|
||||
{ key: 'c', value: 'd' },
|
||||
],
|
||||
};
|
||||
this.set('model', model);
|
||||
this.set('properties', ['key', 'value']);
|
||||
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue
|
||||
@model={{this.model}}
|
||||
@name="tags"
|
||||
@properties={{this.properties}}
|
||||
@data={{this.model.tags}}>
|
||||
<:row as |R|>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-key-input @value={{R.rowData.key}} />
|
||||
</R.Field>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-value-input @value={{R.rowData.value}} />
|
||||
</R.Field>
|
||||
{{#if R.canDelete}}
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
{{/if}}
|
||||
</:row>
|
||||
<:footer as |F|>
|
||||
<F.AddRowButton />
|
||||
</:footer>
|
||||
</Form::Field::KeyValue>
|
||||
`);
|
||||
|
||||
assert.strictEqual(model.tags.length, 2);
|
||||
|
||||
await click(getDeleteButtons()[0]);
|
||||
|
||||
assert.strictEqual(model.tags.length, 1);
|
||||
|
||||
assert.deepEqual(model.tags[0], { key: 'c', value: 'd' });
|
||||
});
|
||||
|
||||
test('it updates row using default handler (model/name)', async function (assert) {
|
||||
const model = { tags: [{ key: '', value: '' }] };
|
||||
this.set('model', model);
|
||||
this.set('properties', ['key', 'value']);
|
||||
|
||||
await render(hbs`
|
||||
<Form::Field::KeyValue
|
||||
@model={{this.model}}
|
||||
@name="tags"
|
||||
@properties={{this.properties}}
|
||||
@data={{this.model.tags}}>
|
||||
<:row as |R|>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-key-input @value={{R.rowData.key}} {{on 'input' (fn R.updateRow 'key')}} />
|
||||
</R.Field>
|
||||
<R.Field as |F|>
|
||||
<F.TextInput data-test-value-input @value={{R.rowData.value}} {{on 'input' (fn R.updateRow 'value')}} />
|
||||
</R.Field>
|
||||
{{#if R.canDelete}}
|
||||
<R.DeleteRowButton data-test-delete-button @onClick={{R.removeRow}} />
|
||||
{{/if}}
|
||||
</:row>
|
||||
<:footer as |F|>
|
||||
<F.AddRowButton />
|
||||
</:footer>
|
||||
</Form::Field::KeyValue>
|
||||
`);
|
||||
|
||||
await fillIn('[data-test-key-input]', 'updated-key');
|
||||
await fillIn('[data-test-value-input]', 'updated-value');
|
||||
|
||||
assert.strictEqual(model.tags[0].key, 'updated-key');
|
||||
assert.strictEqual(model.tags[0].value, 'updated-value');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user