UI: Upgrade Ember data 5.3.2 (and upgrade minor versions of ember-source and ember-cli) (#28798)

* upgrade ember-data 5.3.2, uninstall legacy compat, upgrade ember-cli, ember-source

* use query instead of findAll for auth methods, update tests

* set mutableId for kmip

* show generated private key data before transitioning to details

* update kv metadata test

* remove deprecated methods from path help service

* add changelog, update readme version matrix

* remove toggle template helper
This commit is contained in:
claire bontempo
2024-10-30 09:10:22 -07:00
committed by GitHub
parent cc62bf2ac2
commit 17d29f983c
22 changed files with 705 additions and 620 deletions

3
changelog/28798.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:change
ui: Upgrade Ember data to v5.3.2 (and minor upgrade of ember-cli, ember-source to v5.8.0)
```

View File

@@ -24,20 +24,19 @@
This README outlines the details of collaborating on this Ember application.
## Ember CLI Version Upgrade Matrix
## Ember Version Upgrade Matrix
| Vault Version | Ember Version |
| ------------- | ------------- |
| 1.17.x | 5.4.2 |
| 1.15.x | 4.12.0 |
| 1.14.x | 4.4.0 |
| 1.13.x | 4.4.0 |
| 1.12.x | 3.28.5 |
| 1.11.x | 3.28.5 |
| 1.10.x | 3.28.5 |
| 1.9.x | 3.22.0 |
| 1.8.x | 3.22.0 |
| 1.7.x | 3.11.0 |
Respective versions for `ember-cli`, `ember-source` and `ember-data` for each version of Vault that contains an upgrade.
| Vault Version | Ember CLI | Ember Source | Ember Data |
| ------------- | --------- | ------------ | ---------- |
| 1.19.x | 5.8.0 | 5.8.0 | 5.3.2 |
| 1.17.x | 5.4.2 | 5.4.0 | 4.12.4 |
| 1.15.x | 4.12.1 | 4.12.0 | 4.11.3 |
| 1.13.x | 4.4.0 | 4.4.4 | 4.5.0 |
| 1.11.x | 3.28.5 | 3.28.10 | 3.28.6 |
| 1.10.x | 3.24.0 | 3.24.7 | 3.24.0 |
| 1.9.x | 3.22.0 | 3.22.0 | 3.22.0 |
## Prerequisites

View File

@@ -23,26 +23,21 @@ export default ApplicationAdapter.extend({
const isUnauthenticated = snapshotRecordArray?.adapterOptions?.unauthenticated;
// sys/internal/ui/mounts returns the actual value of the system TTL
// instead of '0' which just indicates the mount is using system defaults
const useMountsEndpoint = snapshotRecordArray?.adapterOptions?.useMountsEndpoint;
if (isUnauthenticated || useMountsEndpoint) {
if (isUnauthenticated) {
const url = `/${this.urlPrefix()}/internal/ui/mounts`;
return this.ajax(url, 'GET', {
unauthenticated: isUnauthenticated,
unauthenticated: true,
})
.then((result) => {
return {
data: result.data.auth,
};
})
.catch((e) => {
if (isUnauthenticated) return { data: {} };
if (e instanceof AdapterError) {
set(e, 'policyPath', 'sys/internal/ui/mounts');
}
throw e;
.catch(() => {
return { data: {} };
});
}
// if authenticated, findAll will use GET sys/auth instead
return this.ajax(this.url(), 'GET').catch((e) => {
if (e instanceof AdapterError) {
set(e, 'policyPath', 'sys/auth');
@@ -51,6 +46,25 @@ export default ApplicationAdapter.extend({
});
},
// findAll makes a network request and supplements the ember-data store with what the API returns.
// after upgrading to ember-data 5.3.2 the store was becoming cluttered with outdated records, so
// use query to refresh the store with each request. this is ideal for list views
query() {
const url = `/${this.urlPrefix()}/internal/ui/mounts`;
return this.ajax(url, 'GET')
.then((result) => {
return {
data: result.data.auth,
};
})
.catch((e) => {
if (e instanceof AdapterError) {
set(e, 'policyPath', 'sys/internal/ui/mounts');
}
throw e;
});
},
createRecord(store, type, snapshot) {
const serializer = store.serializerFor(type.modelName);
const data = serializer.serialize(snapshot);

View File

@@ -16,9 +16,18 @@ export default BaseAdapter.extend({
return this._url(...arguments);
},
urlForCreateRecord(modelName, snapshot) {
return this._url(snapshot.id, modelName, snapshot);
const id = snapshot.record.mutableId;
return this._url(id, modelName, snapshot);
},
urlForUpdateRecord() {
return this._url(...arguments);
},
createRecord(store, type, snapshot) {
return this._super(...arguments).then(() => {
// saving returns a 204, return object with id to please ember-data...
const id = snapshot.record.mutableId;
return { id };
});
},
});

View File

@@ -64,6 +64,9 @@ export default Component.extend({
),
actions: {
handleToggle(e) {
set(this.key, 'enterAsText', e.target.checked);
},
pickedFile(e) {
const { files } = e.target;
if (!files.length) {

View File

@@ -15,28 +15,26 @@ export default Route.extend({
model(params) {
const { path } = params;
return this.store
.findAll('auth-method', { adapterOptions: { useMountsEndpoint: true } })
.then((modelArray) => {
const model = modelArray.find((m) => m.id === path);
if (!model) {
const error = new AdapterError();
set(error, 'httpStatus', 404);
throw error;
}
const supportManaged = supportedManagedAuthBackends();
if (!supportManaged.includes(model.methodType)) {
// do not fetch path-help for unmanaged auth types
model.set('paths', {
apiPath: model.apiPath,
paths: [],
});
return model;
}
return this.pathHelp.getPaths(model.apiPath, path).then((paths) => {
model.set('paths', paths);
return model;
return this.store.query('auth-method', {}).then((modelArray) => {
const model = modelArray.find((m) => m.id === path);
if (!model) {
const error = new AdapterError();
set(error, 'httpStatus', 404);
throw error;
}
const supportManaged = supportedManagedAuthBackends();
if (!supportManaged.includes(model.methodType)) {
// do not fetch path-help for unmanaged auth types
model.set('paths', {
apiPath: model.apiPath,
paths: [],
});
return model;
}
return this.pathHelp.getPaths(model.apiPath, path).then((paths) => {
model.set('paths', paths);
return model;
});
});
},
});

View File

@@ -19,6 +19,6 @@ export default class VaultClusterAccessMethodsRoute extends Route {
};
model() {
return this.store.findAll('auth-method');
return this.store.query('auth-method', {});
}
}

View File

@@ -86,7 +86,7 @@ export default Route.extend(UnloadModelRoute, {
// if you haven't saved a config, the API 404s, so create one here to edit and return it
if (e.httpStatus === 404) {
config = this.store.createRecord(modelType, {
id: backend.id,
mutableId: backend.id,
});
config.set('backend', backend);

View File

@@ -49,13 +49,6 @@ export default class PathHelpService extends Service {
// bust cache in EmberData's model lookup
delete store._modelFactoryCache[modelType];
// bust cache in schema service
const schemas = store.getSchemaDefinitionService?.();
if (schemas) {
delete schemas._relationshipsDefCache[modelType];
delete schemas._attributesDefCache[modelType];
}
}
/**

View File

@@ -23,7 +23,7 @@
name={{concat "useText-" this.elementId}}
class="toggle is-success is-small"
checked={{this.key.enterAsText}}
onchange={{action (toggle "enterAsText" this.key)}}
onchange={{action "handleToggle"}}
/>
<label for={{concat "useText-" this.elementId}} class="has-text-weight-bold is-size-8">
Enter as text

View File

@@ -17,7 +17,7 @@ export default Route.extend({
return this.store.findRecord('kmip/config', this.secretMountPath.currentPath).catch((err) => {
if (err.httpStatus === 404) {
const model = this.store.createRecord('kmip/config');
model.set('id', this.secretMountPath.currentPath);
model.set('mutableId', this.secretMountPath.currentPath);
return model;
} else {
throw err;

View File

@@ -3,62 +3,71 @@
SPDX-License-Identifier: BUSL-1.1
~}}
<form {{on "submit" (perform this.save)}}>
<div class="box is-sideless is-fullwidth is-marginless">
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" />
<NamespaceReminder @mode={{if @model.isNew "generate" "update"}} @noun="PKI key" />
{{#if @model.isNew}}
{{#each @model.formFieldGroups as |fieldGroup|}}
{{#each-in fieldGroup as |group fields|}}
{{#if (eq group "Key parameters")}}
<PkiKeyParameters @model={{@model}} @fields={{fields}} @modelValidations={{this.modelValidations}} />
{{else}}
{{#each fields as |attr|}}
<FormField
data-test-field={{attr}}
@attr={{attr}}
@model={{@model}}
@modelValidations={{this.modelValidations}}
@showHelpText={{false}}
/>
{{/each}}
{{/if}}
{{/each-in}}
{{/each}}
{{else}}
{{! only key name is edit-able }}
{{#let (find-by "name" "keyName" @model.formFields) as |keyName|}}
<FormField data-test-field={{keyName}} @attr={{keyName}} @model={{@model}} @showHelpText={{false}} />
{{/let}}
{{#let (find-by "name" "keyType" @model.formFields) as |keyType|}}
<ReadonlyFormField @attr={{keyType}} @value={{@model.keyType}} />
{{/let}}
{{/if}}
</div>
<Hds::ButtonSet class="has-top-padding-s">
<Hds::Button
@text={{if @model.isNew "Generate key" "Edit key"}}
@icon={{if this.save.isRunning "loading"}}
type="submit"
disabled={{this.save.isRunning}}
data-test-save
/>
<Hds::Button
@text="Cancel"
@color="secondary"
disabled={{this.save.isRunning}}
{{on "click" @onCancel}}
data-test-cancel
/>
</Hds::ButtonSet>
{{#if this.invalidFormAlert}}
<div class="control">
<AlertInline
@type="danger"
class="has-top-padding-s"
@message={{this.invalidFormAlert}}
data-test-pki-key-validation-error
/>
{{! private_key is only available after initial save }}
{{#if this.generatedKey.privateKey}}
<Page::PkiKeyDetails
@key={{this.generatedKey}}
@canDelete={{this.generatedKey.canDelete}}
@canEdit={{this.generatedKey.canEdit}}
/>
{{else}}
<form {{on "submit" (perform this.save)}}>
<div class="box is-sideless is-fullwidth is-marginless">
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" />
<NamespaceReminder @mode={{if @model.isNew "generate" "update"}} @noun="PKI key" />
{{#if @model.isNew}}
{{#each @model.formFieldGroups as |fieldGroup|}}
{{#each-in fieldGroup as |group fields|}}
{{#if (eq group "Key parameters")}}
<PkiKeyParameters @model={{@model}} @fields={{fields}} @modelValidations={{this.modelValidations}} />
{{else}}
{{#each fields as |attr|}}
<FormField
data-test-field={{attr}}
@attr={{attr}}
@model={{@model}}
@modelValidations={{this.modelValidations}}
@showHelpText={{false}}
/>
{{/each}}
{{/if}}
{{/each-in}}
{{/each}}
{{else}}
{{! only key name is edit-able }}
{{#let (find-by "name" "keyName" @model.formFields) as |keyName|}}
<FormField data-test-field={{keyName}} @attr={{keyName}} @model={{@model}} @showHelpText={{false}} />
{{/let}}
{{#let (find-by "name" "keyType" @model.formFields) as |keyType|}}
<ReadonlyFormField @attr={{keyType}} @value={{@model.keyType}} />
{{/let}}
{{/if}}
</div>
{{/if}}
</form>
<Hds::ButtonSet class="has-top-padding-s">
<Hds::Button
@text={{if @model.isNew "Generate key" "Edit key"}}
@icon={{if this.save.isRunning "loading"}}
type="submit"
disabled={{this.save.isRunning}}
data-test-save
/>
<Hds::Button
@text="Cancel"
@color="secondary"
disabled={{this.save.isRunning}}
{{on "click" @onCancel}}
data-test-cancel
/>
</Hds::ButtonSet>
{{#if this.invalidFormAlert}}
<div class="control">
<AlertInline
@type="danger"
class="has-top-padding-s"
@message={{this.invalidFormAlert}}
data-test-pki-key-validation-error
/>
</div>
{{/if}}
</form>
{{/if}}

View File

@@ -39,6 +39,8 @@ export default class PkiKeyForm extends Component<Args> {
@tracked invalidFormAlert = '';
@tracked modelValidations: ValidationMap | null = null;
@tracked generatedKey: PkiKeyModel | null = null;
@task
@waitFor
*save(event: Event) {
@@ -51,11 +53,15 @@ export default class PkiKeyForm extends Component<Args> {
this.invalidFormAlert = invalidFormMessage;
}
if (!isValid && isNew) return;
yield this.args.model.save({ adapterOptions: { import: false } });
this.generatedKey = yield this.args.model.save({ adapterOptions: { import: false } });
this.flashMessages.success(
`Successfully ${isNew ? 'generated' : 'updated'} key${keyName ? ` ${keyName}.` : '.'}`
);
this.args.onSave();
// only transition to details if there is no private_key data to display
if (!this.generatedKey?.privateKey) {
this.args.onSave();
}
} catch (error) {
this.errorBanner = errorMessage(error);
this.invalidFormAlert = 'There was an error submitting this form.';

View File

@@ -36,4 +36,10 @@ export default class PkiRolesCreateRoute extends Route {
{ label: 'create' },
];
}
willTransition() {
// after upgrading to Ember Data 5.3.2 we saw duplicate records in the store after creating and saving a new role
// it's unclear why this ghost record is persisting, manually unloading refreshes the store
this.store.unloadAll('pki/role');
}
}

View File

@@ -66,7 +66,6 @@
"@babel/preset-env": "^7.24.6",
"@babel/preset-typescript": "^7.24.6",
"@docfy/ember": "^0.8.5",
"@ember-data/legacy-compat": "~4.12.4",
"@ember/legacy-built-in-components": "^0.4.1",
"@ember/optional-features": "^2.0.0",
"@ember/render-modifiers": "^1.0.2",
@@ -106,7 +105,7 @@
"dompurify": "^3.0.2",
"ember-a11y-testing": "^7.0.1",
"ember-basic-dropdown": "^8.0.4",
"ember-cli": "~5.4.2",
"ember-cli": "~5.8.0",
"ember-cli-babel": "^8.2.0",
"ember-cli-clean-css": "^3.0.0",
"ember-cli-content-security-policy": "2.0.3",
@@ -123,7 +122,7 @@
"ember-cli-terser": "^4.0.2",
"ember-composable-helpers": "5.0.0",
"ember-concurrency": "^4.0.2",
"ember-data": "~4.12.4",
"ember-data": "~5.3.2",
"ember-engines": "0.8.23",
"ember-exam": "^9.0.0",
"ember-inflector": "4.0.2",
@@ -138,7 +137,7 @@
"ember-responsive": "5.0.0",
"ember-service-worker": "meirish/ember-service-worker#configurable-scope",
"ember-sinon-qunit": "^7.4.0",
"ember-source": "~5.4.0",
"ember-source": "~5.8.0",
"ember-style-modifier": "^4.1.0",
"ember-svg-jar": "2.4.4",
"ember-template-lint": "^6.0.0",

View File

@@ -3,22 +3,17 @@
* SPDX-License-Identifier: BUSL-1.1
*/
import { currentRouteName, click } from '@ember/test-helpers';
import { currentRouteName, click, find, findAll, visit } from '@ember/test-helpers';
import { clickTrigger } from 'ember-power-select/test-support/helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { create } from 'ember-cli-page-object';
import page from 'vault/tests/pages/access/methods';
import authEnable from 'vault/tests/pages/settings/auth/enable';
import authPage from 'vault/tests/pages/auth';
import ss from 'vault/tests/pages/components/search-select';
import consoleClass from 'vault/tests/pages/components/console/ui-panel';
import { v4 as uuidv4 } from 'uuid';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { mountAuthCmd, runCmd } from 'vault/tests/helpers/commands';
import { login } from 'vault/tests/helpers/auth/auth-helpers';
const consoleComponent = create(consoleClass);
const searchSelect = create(ss);
const { searchSelect } = GENERAL;
module('Acceptance | auth-methods list view', function (hooks) {
setupApplicationTest(hooks);
@@ -26,14 +21,13 @@ module('Acceptance | auth-methods list view', function (hooks) {
hooks.beforeEach(function () {
this.uid = uuidv4();
return authPage.login();
return login();
});
test('it navigates to auth method', async function (assert) {
await page.visit();
await visit('/vault/access/');
assert.strictEqual(currentRouteName(), 'vault.cluster.access.methods', 'navigates to the correct route');
assert.ok(page.methodsLink.isActive, 'the first link is active');
assert.strictEqual(page.methodsLink.text, 'Authentication Methods');
assert.dom('[data-test-sidebar-nav-link="Authentication Methods"]').hasClass('active');
});
test('it filters by name and auth type', async function (assert) {
@@ -41,50 +35,52 @@ module('Acceptance | auth-methods list view', function (hooks) {
const authPath1 = `userpass-1-${this.uid}`;
const authPath2 = `userpass-2-${this.uid}`;
const type = 'userpass';
await authEnable.visit();
await authEnable.enable(type, authPath1);
await authEnable.visit();
await authEnable.enable(type, authPath2);
await page.visit();
// filter by auth type
await visit('/vault/settings/auth/enable');
await runCmd(mountAuthCmd(type, authPath1));
await visit('/vault/settings/auth/enable');
await runCmd(mountAuthCmd(type, authPath2));
await visit('/vault/access/');
// filter by auth type
await clickTrigger('#filter-by-auth-type');
await searchSelect.options.objectAt(0).click();
const rows = document.querySelectorAll('[data-test-auth-backend-link]');
await click(searchSelect.option(searchSelect.optionIndex(type)));
let rows = findAll('[data-test-auth-backend-link]');
const rowsUserpass = Array.from(rows).filter((row) => row.innerText.includes('userpass'));
assert.strictEqual(rows.length, rowsUserpass.length, 'all rows returned are userpass');
// filter by name
await clickTrigger('#filter-by-auth-name');
const firstItemToSelect = searchSelect.options.objectAt(0).text;
await searchSelect.options.objectAt(0).click();
const singleRow = document.querySelectorAll('[data-test-auth-backend-link]');
await click(searchSelect.option());
const selectedItem = find(`#filter-by-auth-name ${searchSelect.selectedOption()}`).innerText;
const singleRow = findAll('[data-test-auth-backend-link]');
assert.strictEqual(singleRow.length, 1, 'returns only one row');
assert.dom(singleRow[0]).includesText(firstItemToSelect, 'shows the filtered by auth name');
// clear filter by engine name
await searchSelect.deleteButtons.objectAt(1).click();
const rowsAgain = document.querySelectorAll('[data-test-auth-backend-link]');
assert.ok(rowsAgain.length > 1, 'filter has been removed');
assert.dom(singleRow[0]).includesText(selectedItem, 'shows the filtered by auth name');
// clear filter by name
await click(`#filter-by-auth-name ${searchSelect.removeSelected}`);
rows = findAll('[data-test-auth-backend-link]');
assert.true(rows.length > 1, 'filter has been removed');
// cleanup
await consoleComponent.runCommands([`delete sys/auth/${authPath1}`]);
await consoleComponent.runCommands([`delete sys/auth/${authPath2}`]);
await runCmd(`delete sys/auth/${authPath1}`);
await runCmd(`delete sys/auth/${authPath2}`);
});
test('it should show all methods in list view', async function (assert) {
this.server.get('/sys/auth', () => ({
this.server.get('/sys/internal/ui/mounts', () => ({
data: {
'token/': { accessor: 'auth_token_263b8b4e', type: 'token' },
'userpass/': { accessor: 'auth_userpass_87aca1f8', type: 'userpass' },
auth: {
'token/': { accessor: 'auth_token_263b8b4e', type: 'token' },
'userpass/': { accessor: 'auth_userpass_87aca1f8', type: 'userpass' },
},
},
}));
await page.visit();
await visit('/vault/access/');
assert.dom('[data-test-auth-backend-link]').exists({ count: 2 }, 'All auth methods appear in list view');
await authEnable.visit();
await visit('/vault/settings/auth/enable');
await click('[data-test-sidebar-nav-link="OIDC Provider"]');
await page.visit();
await visit('/vault/access/');
assert
.dom('[data-test-auth-backend-link]')
.exists({ count: 2 }, 'All auth methods appear in list view after navigating back');

View File

@@ -307,11 +307,15 @@ module('Acceptance | pki workflow', function (hooks) {
await visit(`/vault/secrets/${this.mountPath}/pki/keys`);
await click(PKI_KEYS.generateKey);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/create`);
await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(GENERAL.inputByAttr('type'), 'exported'); // exported keys generated private_key data
await fillIn(GENERAL.inputByAttr('keyType'), 'rsa');
await click(GENERAL.saveButton);
keyId = find(GENERAL.infoRowValue('Key ID')).textContent?.trim();
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`);
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/keys/create`,
'it does not transition to details private_key data exists'
);
assert
.dom(PKI_KEYS.nextStepsAlert)

View File

@@ -3,15 +3,14 @@
* SPDX-License-Identifier: BUSL-1.1
*/
import { click, currentRouteName, settled } from '@ember/test-helpers';
import { click, currentRouteName, fillIn, visit } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { v4 as uuidv4 } from 'uuid';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import page from 'vault/tests/pages/settings/auth/enable';
import listPage from 'vault/tests/pages/access/methods';
import { login } from 'vault/tests/helpers/auth/auth-helpers';
import { deleteAuthCmd, runCmd } from 'vault/tests/helpers/commands';
import { SECRET_ENGINE_SELECTORS as SES } from 'vault/tests/helpers/secret-engine/secret-engine-selectors';
module('Acceptance | settings/auth/enable', function (hooks) {
setupApplicationTest(hooks);
@@ -25,30 +24,34 @@ module('Acceptance | settings/auth/enable', function (hooks) {
// always force the new mount to the top of the list
const path = `aaa-approle-${this.uid}`;
const type = 'approle';
await page.visit();
await visit('/vault/settings/auth/enable');
assert.strictEqual(currentRouteName(), 'vault.cluster.settings.auth.enable');
await page.enable(type, path);
await settled();
assert.strictEqual(
page.flash.latestMessage,
`Successfully mounted the ${type} auth method at ${path}.`,
'success flash shows'
);
await click(SES.mountType(type));
await fillIn(GENERAL.inputByAttr('path'), path);
await click(SES.mountSubmit);
assert
.dom(GENERAL.latestFlashContent)
.hasText(`Successfully mounted the ${type} auth method at ${path}.`);
assert.strictEqual(
currentRouteName(),
'vault.cluster.settings.auth.configure.section',
'redirects to the auth config page'
);
await listPage.visit();
assert.ok(listPage.findLinkById(path), 'mount is present in the list');
await visit('/vault/access/');
assert.dom(`[data-test-auth-backend-link=${path}]`).exists('mount is present in the list');
// cleanup
await runCmd(deleteAuthCmd(path));
});
test('it renders default config details', async function (assert) {
const path = `approle-config-${this.uid}`;
const type = 'approle';
await page.visit();
await page.enable(type, path);
await visit('/vault/settings/auth/enable');
await click(SES.mountType(type));
await fillIn(GENERAL.inputByAttr('path'), path);
await click(SES.mountSubmit);
// the config details is updated to query mount details from sys/internal/ui/mounts
// but we still want these forms to continue using sys/auth which returns 0 for default ttl values
// check tune form (right after enabling)
@@ -64,5 +67,8 @@ module('Acceptance | settings/auth/enable', function (hooks) {
await click('[data-test-configure-link]');
assert.dom(GENERAL.toggleInput('Default Lease TTL')).isNotChecked('default lease ttl is still unset');
assert.dom(GENERAL.toggleInput('Max Lease TTL')).isNotChecked('max lease ttl is still unset');
// cleanup
await runCmd(deleteAuthCmd(path));
});
});

View File

@@ -1,24 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { create, attribute, visitable, collection, hasClass, text } from 'ember-cli-page-object';
export default create({
visit: visitable('/vault/access/'),
methodsLink: {
isActive: hasClass('active'),
text: text(),
scope: '[data-test-sidebar-nav-link="Authentication Methods"]',
},
backendLinks: collection('[data-test-auth-backend-link]', {
path: text('[data-test-path]'),
id: attribute('data-test-id', '[data-test-path]'),
}),
findLinkById(id) {
return this.backendLinks.filterBy('id', id)[0];
},
});

View File

@@ -54,7 +54,7 @@ module('Unit | Adapter | auth method', function (hooks) {
await this.store.findAll('auth-method', { adapterOptions: { unauthenticated: true } });
});
test('findAll makes request to correct endpoint when useMountsEndpoint is true', async function (assert) {
test('query makes request to correct endpoint ', async function (assert) {
assert.expect(1);
this.server.get('sys/internal/ui/mounts', () => {
@@ -62,6 +62,6 @@ module('Unit | Adapter | auth method', function (hooks) {
return this.mockResponse;
});
await this.store.findAll('auth-method', { adapterOptions: { useMountsEndpoint: true } });
await this.store.query('auth-method', {});
});
});

View File

@@ -182,7 +182,7 @@ module('Unit | Adapter | kv/metadata', function (hooks) {
let record = await this.store.peekRecord('kv/metadata', data.id);
await record.destroyRecord();
assert.true(record.isDestroyed, 'record is destroyed');
assert.true(record.isDeleted, 'record is deleted');
record = await this.store.peekRecord('kv/metadata', this.id);
assert.strictEqual(record, null, 'record is no longer in store');
});

File diff suppressed because it is too large Load Diff