* fix: 🐛 actions not displaying for templates in grants editor * fix: 🐛 invalid ids check * fix: 🐛 update check for ids type * test: 💍 fix broken strings * test: 💍 fix test case * test: 💍 remove log
281 lines
8.3 KiB
JavaScript
281 lines
8.3 KiB
JavaScript
/**
|
|
* Copyright IBM Corp. 2021, 2026
|
|
* SPDX-License-Identifier: BUSL-1.1
|
|
*/
|
|
|
|
import { module, test } from 'qunit';
|
|
import { setupRenderingTest } from 'admin/tests/helpers';
|
|
import { setupIntl } from 'ember-intl/test-support';
|
|
import { setupMirage } from 'admin/tests/helpers/mirage';
|
|
import { render } from '@ember/test-helpers';
|
|
import { hbs } from 'ember-cli-htmlbars';
|
|
import * as commonSelectors from 'admin/tests/helpers/selectors';
|
|
|
|
const GRANT_ACTIONS_TABLE = '[data-test-grant-actions-table]';
|
|
const GRANT_ACTIONS_EMPTY_STATE = '[data-test-grant-actions-empty-state]';
|
|
const GRANT_ACTIONS_NO_TYPE_DETECTED =
|
|
'[data-test-grant-actions-no-type-detected]';
|
|
const GRANT_ACTIONS_INVALID_ID_OR_TYPE =
|
|
'[data-test-grant-actions-invalid-id-or-type]';
|
|
|
|
module('Integration | Component | grant-actions/index', function (hooks) {
|
|
setupRenderingTest(hooks);
|
|
setupMirage(hooks);
|
|
setupIntl(hooks, 'en-us');
|
|
|
|
hooks.beforeEach(async function () {
|
|
const response = await fetch('/grants-schema.json');
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch grants schema: ${response.status}`);
|
|
}
|
|
|
|
const grantsSchemaData = await response.json();
|
|
this.grantsSchema = grantsSchemaData;
|
|
});
|
|
|
|
test('it renders the actions relevant to the current grant line', async function (assert) {
|
|
this.grantString = 'ids=hcst_1234567890;type=host-set';
|
|
|
|
await render(hbs`
|
|
<GrantActions
|
|
@grantsSchema={{this.grantsSchema}}
|
|
@grantString={{this.grantString}}
|
|
/>
|
|
`);
|
|
|
|
assert.dom(GRANT_ACTIONS_TABLE).isVisible();
|
|
assert.dom(commonSelectors.TABLE_ROWS).isVisible({ count: 8 });
|
|
|
|
const rowData = [
|
|
...this.element.querySelectorAll(commonSelectors.TABLE_ROWS),
|
|
].map((row) => {
|
|
const [name, description] = [...row.querySelectorAll('td')].map((cell) =>
|
|
cell.textContent.trim(),
|
|
);
|
|
return { name, description };
|
|
});
|
|
|
|
assert.deepEqual(
|
|
rowData.map(({ name }) => name),
|
|
[
|
|
'add-hosts',
|
|
'create',
|
|
'delete',
|
|
'list',
|
|
'read',
|
|
'remove-hosts',
|
|
'set-hosts',
|
|
'update',
|
|
],
|
|
);
|
|
|
|
assert.deepEqual(rowData[0], {
|
|
name: 'add-hosts',
|
|
description: 'Add hosts to a host set',
|
|
});
|
|
assert.deepEqual(rowData[1], {
|
|
name: 'create',
|
|
description: 'Create a new host-set',
|
|
});
|
|
assert.deepEqual(rowData.at(-1), {
|
|
name: 'update',
|
|
description: 'Update a host-set',
|
|
});
|
|
|
|
assert.dom(GRANT_ACTIONS_EMPTY_STATE).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_NO_TYPE_DETECTED).doesNotExist();
|
|
});
|
|
|
|
test('it renders relevant actions for template IDs', async function (assert) {
|
|
this.grantString = 'ids={{.User.Id}}';
|
|
|
|
await render(hbs`
|
|
<GrantActions
|
|
@grantsSchema={{this.grantsSchema}}
|
|
@grantString={{this.grantString}}
|
|
/>
|
|
`);
|
|
|
|
assert.dom(GRANT_ACTIONS_TABLE).isVisible();
|
|
assert.dom(commonSelectors.TABLE_ROWS).isVisible({ count: 7 });
|
|
|
|
const rowData = [
|
|
...this.element.querySelectorAll(commonSelectors.TABLE_ROWS),
|
|
].map((row) => {
|
|
const [name, description] = [...row.querySelectorAll('td')].map((cell) =>
|
|
cell.textContent.trim(),
|
|
);
|
|
return { name, description };
|
|
});
|
|
|
|
assert.deepEqual(
|
|
rowData.map(({ name }) => name),
|
|
[
|
|
'add-accounts',
|
|
'delete',
|
|
'list-resolvable-aliases',
|
|
'read',
|
|
'remove-accounts',
|
|
'set-accounts',
|
|
'update',
|
|
],
|
|
);
|
|
|
|
assert.deepEqual(rowData[0], {
|
|
name: 'add-accounts',
|
|
description: 'Add accounts to a user',
|
|
});
|
|
assert.deepEqual(rowData[1], {
|
|
name: 'delete',
|
|
description: 'Delete a user',
|
|
});
|
|
assert.deepEqual(rowData.at(-1), {
|
|
name: 'update',
|
|
description: 'Update a user',
|
|
});
|
|
|
|
assert.dom(GRANT_ACTIONS_EMPTY_STATE).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_NO_TYPE_DETECTED).doesNotExist();
|
|
});
|
|
|
|
test('it renders the no resource type detected state when the current line has no detectable type', async function (assert) {
|
|
this.grantString = 'output_fields=*';
|
|
|
|
await render(hbs`
|
|
<GrantActions
|
|
@grantsSchema={{this.grantsSchema}}
|
|
@grantString={{this.grantString}}
|
|
/>
|
|
`);
|
|
|
|
assert.dom(GRANT_ACTIONS_TABLE).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_INVALID_ID_OR_TYPE).doesNotExist();
|
|
assert
|
|
.dom(GRANT_ACTIONS_NO_TYPE_DETECTED)
|
|
.hasText('No resource type detected.');
|
|
assert.dom(GRANT_ACTIONS_EMPTY_STATE).doesNotExist();
|
|
});
|
|
|
|
test('it renders the invalid ID and type state for an unknown type', async function (assert) {
|
|
this.grantString = 'type=not-a-real-type;actions=';
|
|
|
|
await render(hbs`
|
|
<GrantActions
|
|
@grantsSchema={{this.grantsSchema}}
|
|
@grantString={{this.grantString}}
|
|
/>
|
|
`);
|
|
|
|
assert.dom(GRANT_ACTIONS_TABLE).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_NO_TYPE_DETECTED).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_EMPTY_STATE).doesNotExist();
|
|
assert
|
|
.dom(GRANT_ACTIONS_INVALID_ID_OR_TYPE)
|
|
.hasText('Invalid ID and type. No actions available.');
|
|
});
|
|
|
|
test('it renders the invalid ID and type state for an unknown ID', async function (assert) {
|
|
this.grantString = 'ids=bad_123;actions=';
|
|
|
|
await render(hbs`
|
|
<GrantActions
|
|
@grantsSchema={{this.grantsSchema}}
|
|
@grantString={{this.grantString}}
|
|
/>
|
|
`);
|
|
|
|
assert.dom(GRANT_ACTIONS_TABLE).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_NO_TYPE_DETECTED).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_EMPTY_STATE).doesNotExist();
|
|
assert
|
|
.dom(GRANT_ACTIONS_INVALID_ID_OR_TYPE)
|
|
.hasText('Invalid ID and type. No actions available.');
|
|
});
|
|
|
|
test('it keeps the no suggestions state when a type is known but no actions apply', async function (assert) {
|
|
this.grantString = 'type=host;actions=';
|
|
|
|
await render(hbs`
|
|
<GrantActions
|
|
@grantsSchema={{this.grantsSchema}}
|
|
@grantString={{this.grantString}}
|
|
/>
|
|
`);
|
|
|
|
assert.dom(GRANT_ACTIONS_TABLE).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_INVALID_ID_OR_TYPE).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_NO_TYPE_DETECTED).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_EMPTY_STATE).hasText('No suggestions');
|
|
});
|
|
|
|
test('it renders the no-type-detected state for an empty grant string', async function (assert) {
|
|
this.grantString = '';
|
|
|
|
await render(hbs`
|
|
<GrantActions
|
|
@grantsSchema={{this.grantsSchema}}
|
|
@grantString={{this.grantString}}
|
|
/>
|
|
`);
|
|
|
|
assert.dom(GRANT_ACTIONS_TABLE).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_INVALID_ID_OR_TYPE).doesNotExist();
|
|
assert
|
|
.dom(GRANT_ACTIONS_NO_TYPE_DETECTED)
|
|
.hasText('No resource type detected.');
|
|
assert.dom(GRANT_ACTIONS_EMPTY_STATE).doesNotExist();
|
|
});
|
|
|
|
test('it renders the invalid state for a pinned id paired with its own type instead of a child type', async function (assert) {
|
|
this.grantString = 'ids=hcst_1234567890;type=host-catalog';
|
|
|
|
await render(hbs`
|
|
<GrantActions
|
|
@grantsSchema={{this.grantsSchema}}
|
|
@grantString={{this.grantString}}
|
|
/>
|
|
`);
|
|
|
|
assert.dom(GRANT_ACTIONS_TABLE).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_NO_TYPE_DETECTED).doesNotExist();
|
|
assert.dom(GRANT_ACTIONS_EMPTY_STATE).doesNotExist();
|
|
assert
|
|
.dom(GRANT_ACTIONS_INVALID_ID_OR_TYPE)
|
|
.hasText('Invalid ID and type. No actions available.');
|
|
});
|
|
|
|
test('it renders only CRUDL actions with fallback descriptions when type is wildcard', async function (assert) {
|
|
this.grantString = 'ids=*;type=*';
|
|
|
|
await render(hbs`
|
|
<GrantActions
|
|
@grantsSchema={{this.grantsSchema}}
|
|
@grantString={{this.grantString}}
|
|
/>
|
|
`);
|
|
|
|
assert.dom(GRANT_ACTIONS_TABLE).isVisible();
|
|
|
|
const rows = [...this.element.querySelectorAll(commonSelectors.TABLE_ROWS)];
|
|
const rowNames = rows.map((row) =>
|
|
row.querySelector('td')?.textContent.trim(),
|
|
);
|
|
|
|
assert.deepEqual(
|
|
rowNames,
|
|
['create', 'delete', 'list', 'read', 'update'],
|
|
'only CRUDL actions are shown for wildcard grants',
|
|
);
|
|
|
|
const createRow = rows.find(
|
|
(row) => row.querySelector('td')?.textContent.trim() === 'create',
|
|
);
|
|
assert.strictEqual(
|
|
createRow.querySelectorAll('td')[1].textContent.trim(),
|
|
'Creates resources',
|
|
'description falls back to generic when no resource type is detected',
|
|
);
|
|
});
|
|
});
|