Icu 5476 refactor target model serializer and mirage (#1235)
chore: 🤖 refactor target model to support credentials
This commit is contained in:
1 parent
2cda4f639e
commit
1f0baceb5e
12 files changed
+210
-66
No files matched your search
@@ -48,17 +48,21 @@ export default class TargetModel extends GeneratedTargetModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of resolved credential library instances. Model instances
|
||||
* An array of resolved credential library and credential instances. Model instances
|
||||
* must already be loaded into the store (this method will not load unloaded
|
||||
* instances). Unresolvable instances are excluded from the array.
|
||||
* @type {[CredentialLibraryModel]}
|
||||
* @type {[CredentialLibraryModel, CredentialModel]}
|
||||
*/
|
||||
@computed('application_credential_source_ids.[]', 'store')
|
||||
get credentialLibraries() {
|
||||
get credentialSources() {
|
||||
return this.application_credential_source_ids
|
||||
.map((source) =>
|
||||
this.store.peekRecord('credential-library', source.value)
|
||||
)
|
||||
.map((source) => {
|
||||
if (source.value.startsWith('cred')) {
|
||||
return this.store.peekRecord('credential', source.value);
|
||||
} else {
|
||||
return this.store.peekRecord('credential-library', source.value);
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
@@ -150,17 +154,17 @@ export default class TargetModel extends GeneratedTargetModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds credential libraries via the `add-credential-sources` method.
|
||||
* Adds credential sources via the `add-credential-sources` method.
|
||||
* See serializer and adapter for more information.
|
||||
* @param {[string]} credentialLibraryIDs
|
||||
* @param {[string]} credentialSourceIDs
|
||||
* @param {object} options
|
||||
* @param {object} options.adapterOptions
|
||||
* @return {Promise}
|
||||
*/
|
||||
addCredentialSources(credentialLibraryIDs, options = { adapterOptions: {} }) {
|
||||
addCredentialSources(credentialSourceIDs, options = { adapterOptions: {} }) {
|
||||
const defaultAdapterOptions = {
|
||||
method: 'add-credential-sources',
|
||||
credentialLibraryIDs,
|
||||
credentialSourceIDs,
|
||||
};
|
||||
// There is no "deep merge" in ES.
|
||||
return this.save({
|
||||
@@ -173,20 +177,20 @@ export default class TargetModel extends GeneratedTargetModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete credential libraries via the `remove-credential-sources` method.
|
||||
* Delete credential libraries and credentials via the `remove-credential-sources` method.
|
||||
* See serializer and adapter for more information.
|
||||
* @param {[string]} credentialLibraryIDs
|
||||
* @param {[string]} credentialSourceIDs
|
||||
* @param {object} options
|
||||
* @param {object} options.adapterOptions
|
||||
* @return {Promise}
|
||||
*/
|
||||
removeCredentialSources(
|
||||
credentialLibraryIDs,
|
||||
credentialSourceIDs,
|
||||
options = { adapterOptions: {} }
|
||||
) {
|
||||
const defaultAdapterOptions = {
|
||||
method: 'remove-credential-sources',
|
||||
credentialLibraryIDs,
|
||||
credentialSourceIDs,
|
||||
};
|
||||
// There is no "deep merge" in ES.
|
||||
return this.save({
|
||||
@@ -199,13 +203,13 @@ export default class TargetModel extends GeneratedTargetModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a single credential library set via the `remove-credential-sources` method.
|
||||
* @param {number} credentialLibraryID
|
||||
* Delete a single credential library/credential set via the `remove-credential-sources` method.
|
||||
* @param {number} credentialSourceID
|
||||
* @param {object} options
|
||||
* @return {Promise}
|
||||
*/
|
||||
removeCredentialSource(credentialLibraryID, options) {
|
||||
return this.removeCredentialSources([credentialLibraryID], options);
|
||||
removeCredentialSource(credentialSourceID, options) {
|
||||
return this.removeCredentialSources([credentialSourceID], options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,10 +7,10 @@ export default class TargetSerializer extends ApplicationSerializer {
|
||||
* If `adapterOptions.hostSets` is set to an array of host set models,
|
||||
* the resulting target serialization should include **only host sets**
|
||||
* and the version.
|
||||
* If `adapterOptions.credentialLibraries` is set to an array of
|
||||
* credential library models, the resulting target serialization should
|
||||
* include **only credential libraries** and the version.
|
||||
* Normally, neither host sets or credential libraries are not serialized.
|
||||
* If `adapterOptions.credentialSources` is set to an array of
|
||||
* credential library and credential models, the resulting target serialization should
|
||||
* include **only credential libraries and crendentials** and the version.
|
||||
* Normally, neither host sets or credential libraries or credentials are not serialized.
|
||||
* @override
|
||||
* @param {Snapshot} snapshot
|
||||
* @return {object}
|
||||
@@ -21,7 +21,7 @@ export default class TargetSerializer extends ApplicationSerializer {
|
||||
if (hostSourceIDs) {
|
||||
serialized = this.serializeWithHostSources(snapshot, hostSourceIDs);
|
||||
}
|
||||
const credentialSourceIDs = snapshot?.adapterOptions?.credentialLibraryIDs;
|
||||
const credentialSourceIDs = snapshot?.adapterOptions?.credentialSourceIDs;
|
||||
if (credentialSourceIDs)
|
||||
serialized = this.serializeWithCredentialSources(
|
||||
snapshot,
|
||||
|
||||
@@ -464,19 +464,31 @@ export default function () {
|
||||
// If adding credential sources, push them into the array
|
||||
if (method === 'add-credential-sources') {
|
||||
updatedAttrs.credentialLibraryIds = target.credentialLibraryIds;
|
||||
updatedAttrs.credentialIds = target.credentialIds;
|
||||
attrs.applicationCredentialSourceIds.forEach((id) => {
|
||||
if (!updatedAttrs.credentialLibraryIds.includes(id)) {
|
||||
updatedAttrs.credentialLibraryIds.push(id);
|
||||
if (
|
||||
!updatedAttrs.credentialLibraryIds.includes(id) ||
|
||||
!updatedAttrs.credentialIds.includes(id)
|
||||
) {
|
||||
if (id.startsWith('cred')) {
|
||||
updatedAttrs.credentialIds.push(id);
|
||||
} else {
|
||||
updatedAttrs.credentialLibraryIds.push(id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// If deleting credential sources, filter them out of the array
|
||||
if (method === 'remove-credential-sources') {
|
||||
updatedAttrs.credentialLibraryIds = target.credentialLibraryIds;
|
||||
updatedAttrs.credentialIds = target.credentialIds;
|
||||
updatedAttrs.credentialLibraryIds =
|
||||
updatedAttrs.credentialLibraryIds.filter((id) => {
|
||||
return !attrs.applicationCredentialSourceIds.includes(id);
|
||||
});
|
||||
updatedAttrs.credentialIds = updatedAttrs.credentialIds.filter((id) => {
|
||||
return !attrs.applicationCredentialSourceIds.includes(id);
|
||||
});
|
||||
}
|
||||
return target.update(updatedAttrs);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,9 @@ export default factory.extend({
|
||||
*/
|
||||
withAssociations: trait({
|
||||
afterCreate(target, server) {
|
||||
let randomlySelectedHostSets, randomlySelectedCredentialLibraries;
|
||||
let randomlySelectedHostSets,
|
||||
randomlySelectedCredentialLibraries,
|
||||
randomlySelectedCredentials;
|
||||
randomlySelectedHostSets = server.schema.hostSets
|
||||
// BLERG: fun fact, for no reason at all, the element passed
|
||||
// into a where function is not a full model instance, as you might
|
||||
@@ -64,10 +66,13 @@ export default factory.extend({
|
||||
(credentialLibrary) => credentialLibrary.scopeId === target.scope.id
|
||||
)
|
||||
.models.filter(() => randomBoolean());
|
||||
|
||||
randomlySelectedCredentials = server.schema.credentials
|
||||
.where((credential) => credential.scopeId === target.scope.id)
|
||||
.models.filter(() => randomBoolean());
|
||||
target.update({
|
||||
hostSets: randomlySelectedHostSets,
|
||||
credentialLibraries: randomlySelectedCredentialLibraries,
|
||||
credentials: randomlySelectedCredentials,
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -5,4 +5,5 @@ export default Model.extend({
|
||||
scope: belongsTo(),
|
||||
hostSets: hasMany(),
|
||||
credentialLibraries: hasMany(),
|
||||
credentials: hasMany(),
|
||||
});
|
||||
@@ -23,8 +23,11 @@ export default ApplicationSerializer.extend({
|
||||
return { id: host_set_id, host_catalog_id };
|
||||
});
|
||||
}
|
||||
if (model.credentialLibraryIds?.length) {
|
||||
json.application_credential_source_ids = model.credentialLibraryIds;
|
||||
if (model.credentialLibraryIds?.length || model.credentialIds?.length) {
|
||||
json.application_credential_source_ids = [
|
||||
...model.credentialLibraryIds,
|
||||
...model.credentialIds,
|
||||
];
|
||||
}
|
||||
return json;
|
||||
},
|
||||
|
||||
@@ -231,7 +231,7 @@ module('Unit | Model | target', function (hooks) {
|
||||
);
|
||||
});
|
||||
|
||||
test('it has a `credentialLibraries` array of resolved model instances (if those instances are already in the store)', function (assert) {
|
||||
test('it has a `credentialSources` array of resolved model instances (if those instances are already in the store)', function (assert) {
|
||||
assert.expect(4);
|
||||
const store = this.owner.lookup('service:store');
|
||||
store.push({
|
||||
@@ -250,9 +250,9 @@ module('Unit | Model | target', function (hooks) {
|
||||
'Target has two entires in application_credential_source_ids'
|
||||
);
|
||||
assert.strictEqual(
|
||||
target.credentialLibraries.length,
|
||||
target.credentialSources.length,
|
||||
0,
|
||||
'Target has no resolved credentialLibraries because they are not loaded yet'
|
||||
'Target has no resolved credentialSources because they are not loaded yet'
|
||||
);
|
||||
store.push({
|
||||
data: {
|
||||
@@ -268,7 +268,7 @@ module('Unit | Model | target', function (hooks) {
|
||||
attributes: {},
|
||||
},
|
||||
});
|
||||
// Since `credentialLibraries` is computed on `application_credential_source_ids`,
|
||||
// Since `credentialSources` is computed on `application_credential_source_ids`,
|
||||
// not the store itself, it's necessary to do this assignment to kick-off the
|
||||
// computed update.
|
||||
/* eslint-disable no-self-assign */
|
||||
@@ -281,9 +281,9 @@ module('Unit | Model | target', function (hooks) {
|
||||
'Target has two entires in application_credential_source_ids'
|
||||
);
|
||||
assert.strictEqual(
|
||||
target.credentialLibraries.length,
|
||||
target.credentialSources.length,
|
||||
2,
|
||||
'Target has two resolved credentialLibraries'
|
||||
'Target has two resolved credentialSources'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ module('Unit | Serializer | target', function (hooks) {
|
||||
});
|
||||
});
|
||||
|
||||
test('it serializes only credential sources and version when an `adapterOptions.credentialLibraryIDs` array is passed', function (assert) {
|
||||
test('it serializes only credential sources and version when an `adapterOptions.credentialSourceIDs` array is passed', function (assert) {
|
||||
assert.expect(1);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('target');
|
||||
@@ -78,7 +78,7 @@ module('Unit | Serializer | target', function (hooks) {
|
||||
});
|
||||
const snapshot = record._createSnapshot();
|
||||
snapshot.adapterOptions = {
|
||||
credentialLibraryIDs: ['4', '5'],
|
||||
credentialSourceIDs: ['4', '5'],
|
||||
};
|
||||
const serializedRecord = serializer.serialize(snapshot);
|
||||
assert.deepEqual(serializedRecord, {
|
||||
|
||||
@@ -378,6 +378,7 @@ credential-library:
|
||||
types:
|
||||
vault: Vault
|
||||
static: Static
|
||||
username_password: Username & Password
|
||||
credential:
|
||||
title: Credential
|
||||
title_plural: Credentials
|
||||
|
||||
@@ -10,15 +10,19 @@ export default class ScopesScopeTargetsTargetCredentialSourcesRoute extends Rout
|
||||
|
||||
/**
|
||||
* Loads all credential libraries under the current target.
|
||||
* @return {Promise{[CredentialLibraryModel]}}
|
||||
* @return {Promise{[CredentialLibraryModel, CredentialModel]}}
|
||||
*/
|
||||
beforeModel() {
|
||||
const { application_credential_source_ids: sourceIDFragments } =
|
||||
this.modelFor('scopes.scope.targets.target');
|
||||
return all(
|
||||
sourceIDFragments.map(({ value }) => {
|
||||
const isStoreOrLibrary = !value.includes('cred');
|
||||
if (isStoreOrLibrary) {
|
||||
const isStatic = value.includes('cred');
|
||||
if (isStatic) {
|
||||
return this.store.findRecord('credential', value, {
|
||||
reload: true,
|
||||
});
|
||||
} else {
|
||||
return this.store.findRecord('credential-library', value, {
|
||||
reload: true,
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</page.actions>
|
||||
|
||||
<page.body>
|
||||
{{#if @model.credentialLibraries}}
|
||||
{{#if @model.credentialSources}}
|
||||
|
||||
<Rose::Table as |table|>
|
||||
<table.header as |header|>
|
||||
@@ -31,35 +31,48 @@
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.credentialLibraries as |credentialLibrary|}}
|
||||
{{#each @model.credentialSources as |credentialSource|}}
|
||||
<body.row as |row|>
|
||||
<row.headerCell>
|
||||
<LinkTo
|
||||
@route='scopes.scope.credential-stores.credential-store.credential-libraries.credential-library'
|
||||
@models={{array
|
||||
credentialLibrary.credential_store_id
|
||||
credentialLibrary.id
|
||||
}}
|
||||
>
|
||||
{{credentialLibrary.displayName}}
|
||||
</LinkTo>
|
||||
<p>{{credentialLibrary.description}}</p>
|
||||
{{#if (eq credentialSource.type 'username_password')}}
|
||||
<LinkTo
|
||||
@route='scopes.scope.credential-stores.credential-store.credentials.credential'
|
||||
@models={{array
|
||||
credentialSource.credential_store_id
|
||||
credentialSource.id
|
||||
}}
|
||||
>
|
||||
{{credentialSource.displayName}}
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
<LinkTo
|
||||
@route='scopes.scope.credential-stores.credential-store.credential-libraries.credential-library'
|
||||
@models={{array
|
||||
credentialSource.credential_store_id
|
||||
credentialSource.id
|
||||
}}
|
||||
>
|
||||
{{credentialSource.displayName}}
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
|
||||
<p>{{credentialSource.description}}</p>
|
||||
</row.headerCell>
|
||||
<row.cell>
|
||||
<Rose::Badge>{{t
|
||||
(concat
|
||||
'resources.credential-library.types.'
|
||||
credentialLibrary.type
|
||||
'resources.target.credential-source.types.'
|
||||
credentialSource.type
|
||||
)
|
||||
}}</Rose::Badge>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Copyable
|
||||
@text={{credentialLibrary.id}}
|
||||
@text={{credentialSource.id}}
|
||||
@buttonText={{t 'actions.copy-to-clipboard'}}
|
||||
@acknowledgeText={{t 'states.copied'}}
|
||||
>
|
||||
<code>{{credentialLibrary.id}}</code>
|
||||
<code>{{credentialSource.id}}</code>
|
||||
</Copyable>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
@@ -77,7 +90,7 @@
|
||||
{{on
|
||||
'click'
|
||||
(route-action
|
||||
'removeCredentialSource' @model credentialLibrary
|
||||
'removeCredentialSource' @model credentialSource
|
||||
)
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -30,6 +30,7 @@ module('Acceptance | targets | credential sources', function (hooks) {
|
||||
credentialLibraries: null,
|
||||
credentialLibrary: null,
|
||||
credentials: null,
|
||||
credential: null,
|
||||
};
|
||||
const urls = {
|
||||
globalScope: null,
|
||||
@@ -74,6 +75,7 @@ module('Acceptance | targets | credential sources', function (hooks) {
|
||||
}
|
||||
);
|
||||
instances.credentialLibrary = instances.credentialLibraries[0];
|
||||
instances.credential = instances.credentials[0];
|
||||
instances.target = this.server.create('target', {
|
||||
scope: instances.scopes.project,
|
||||
credentialLibraries: instances.credentialLibraries,
|
||||
@@ -86,6 +88,7 @@ module('Acceptance | targets | credential sources', function (hooks) {
|
||||
urls.target = `${urls.targets}/${instances.target.id}`;
|
||||
urls.credentialSources = `${urls.target}/credential-sources`;
|
||||
urls.credentialLibrary = `${urls.projectScope}/credential-stores/${instances.credentialLibrary.credentialStoreId}/credential-libraries/${instances.credentialLibrary.id}`;
|
||||
urls.credential = `${urls.projectScope}/credential-stores/${instances.credential.credentialStoreId}/credentials/${instances.credential.id}`;
|
||||
urls.addCredentialSources = `${urls.target}/add-credential-sources`;
|
||||
// Generate resource counter
|
||||
getCredentialLibraryCount = () =>
|
||||
@@ -104,7 +107,7 @@ module('Acceptance | targets | credential sources', function (hooks) {
|
||||
assert.strictEqual(findAll('tbody tr').length, getCredentialLibraryCount());
|
||||
});
|
||||
|
||||
test('can navigate to a credential library', async function (assert) {
|
||||
test('can navigate to a vault type credential library', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.credentialSources);
|
||||
await click('main tbody .rose-table-header-cell:nth-child(1) a');
|
||||
@@ -112,6 +115,18 @@ module('Acceptance | targets | credential sources', function (hooks) {
|
||||
assert.strictEqual(currentURL(), urls.credentialLibrary);
|
||||
});
|
||||
|
||||
test('can navigate to a username & password type credential', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.target.update({
|
||||
credentialLibraries: [],
|
||||
credentials: instances.credentials,
|
||||
});
|
||||
await visit(urls.credentialSources);
|
||||
await click('main tbody .rose-table-header-cell:nth-child(1) a');
|
||||
await a11yAudit();
|
||||
assert.strictEqual(currentURL(), urls.credential);
|
||||
});
|
||||
|
||||
test('visiting add credential sources', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.addCredentialSources);
|
||||
@@ -165,19 +180,46 @@ module('Acceptance | targets | credential sources', function (hooks) {
|
||||
assert.strictEqual(currentURL(), urls.credentialSources);
|
||||
});
|
||||
|
||||
test('can select and save credential sources to add', async function (assert) {
|
||||
test('can select and save a vault type credential library to add', async function (assert) {
|
||||
assert.expect(4);
|
||||
instances.target.update({ credentialLibraries: [] });
|
||||
await visit(urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, 0);
|
||||
await visit(urls.addCredentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, credentialSourceCount);
|
||||
await click('tbody label');
|
||||
await click('tbody tr:first-child label');
|
||||
await click('form [type="submit"]');
|
||||
assert.strictEqual(currentURL(), urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, 1);
|
||||
});
|
||||
|
||||
test('can select and save a username & password type credential to add', async function (assert) {
|
||||
assert.expect(4);
|
||||
instances.target.update({ credentialLibraries: [] });
|
||||
await visit(urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, 0);
|
||||
await visit(urls.addCredentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, credentialSourceCount);
|
||||
await click('tbody tr:last-child label');
|
||||
await click('form [type="submit"]');
|
||||
assert.strictEqual(currentURL(), urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, 1);
|
||||
});
|
||||
|
||||
test('can select and save both a credential-library and a credential to add', async function (assert) {
|
||||
assert.expect(4);
|
||||
instances.target.update({ credentialLibraries: [] });
|
||||
await visit(urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, 0);
|
||||
await visit(urls.addCredentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, credentialSourceCount);
|
||||
await click('tbody tr:last-child label');
|
||||
await click('tbody tr:first-child label');
|
||||
await click('form [type="submit"]');
|
||||
assert.strictEqual(currentURL(), urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, 2);
|
||||
});
|
||||
|
||||
test('cannot add credential sources without proper authorization', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.target.authorized_actions =
|
||||
@@ -201,6 +243,20 @@ module('Acceptance | targets | credential sources', function (hooks) {
|
||||
assert.strictEqual(findAll('tbody tr').length, 0);
|
||||
});
|
||||
|
||||
test('can select multiple credential sources to add and cancel', async function (assert) {
|
||||
assert.expect(4);
|
||||
instances.target.update({ credentialLibraries: [] });
|
||||
await visit(urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, 0);
|
||||
await visit(urls.addCredentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, credentialSourceCount);
|
||||
await click('tbody tr:last-child label');
|
||||
await click('tbody tr:first-child label');
|
||||
await click('form [type="button"]');
|
||||
assert.strictEqual(currentURL(), urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, 0);
|
||||
});
|
||||
|
||||
test('adding credential sources which errors displays error message', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.post('/targets/:idMethod', () => {
|
||||
@@ -217,18 +273,38 @@ module('Acceptance | targets | credential sources', function (hooks) {
|
||||
});
|
||||
instances.target.update({ credentialLibraries: [] });
|
||||
await visit(urls.addCredentialSources);
|
||||
await click('tbody label');
|
||||
await click('tbody tr:last-child label');
|
||||
await click('tbody tr:first-child label');
|
||||
await click('form [type="submit"]');
|
||||
assert.ok(find('[role="alert"]'));
|
||||
});
|
||||
|
||||
test('can remove a credential library', async function (assert) {
|
||||
assert.expect(2);
|
||||
const count = getCredentialLibraryCount();
|
||||
test('can remove a vault type credential library', async function (assert) {
|
||||
assert.expect(3);
|
||||
const credentialLibraryCount = getCredentialLibraryCount();
|
||||
const credentialCount = getCredentialCount();
|
||||
await visit(urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, count);
|
||||
assert.strictEqual(findAll('tbody tr').length, credentialLibraryCount);
|
||||
await click('tbody tr .rose-dropdown-button-danger');
|
||||
assert.strictEqual(findAll('tbody tr').length, count - 1);
|
||||
assert.strictEqual(findAll('tbody tr').length, credentialLibraryCount - 1);
|
||||
await visit(urls.addCredentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, credentialCount + 1);
|
||||
});
|
||||
|
||||
test('can remove a username & password type credential', async function (assert) {
|
||||
assert.expect(3);
|
||||
instances.target.update({
|
||||
credentialLibraries: [],
|
||||
credentials: instances.credentials,
|
||||
});
|
||||
const credentialCount = getCredentialCount();
|
||||
const credentialLibraryCount = getCredentialLibraryCount();
|
||||
await visit(urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, credentialCount);
|
||||
await click('tbody tr .rose-dropdown-button-danger');
|
||||
assert.strictEqual(findAll('tbody tr').length, credentialCount - 1);
|
||||
await visit(urls.addCredentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, credentialLibraryCount + 1);
|
||||
});
|
||||
|
||||
test('cannot remove credential libraries without proper authorization', async function (assert) {
|
||||
@@ -261,4 +337,29 @@ module('Acceptance | targets | credential sources', function (hooks) {
|
||||
await click('tbody tr .rose-dropdown-button-danger');
|
||||
assert.ok(find('[role="alert"]'));
|
||||
});
|
||||
|
||||
test('removing a target credential which errors displays error messages', async function (assert) {
|
||||
assert.expect(2);
|
||||
instances.target.update({
|
||||
credentialLibraries: [],
|
||||
credentials: instances.credentials,
|
||||
});
|
||||
this.server.post('/targets/:idMethod', () => {
|
||||
return new Response(
|
||||
400,
|
||||
{},
|
||||
{
|
||||
status: 400,
|
||||
code: 'invalid_argument',
|
||||
message: 'The request was invalid.',
|
||||
details: {},
|
||||
}
|
||||
);
|
||||
});
|
||||
const count = getCredentialCount();
|
||||
await visit(urls.credentialSources);
|
||||
assert.strictEqual(findAll('tbody tr').length, count);
|
||||
await click('tbody tr .rose-dropdown-button-danger');
|
||||
assert.ok(find('[role="alert"]'));
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user