UI: Test reorganization (#26340)

This commit is contained in:
Chelsea Shaw 2024-04-10 17:01:35 -05:00 committed by GitHub
parent 71758f4def
commit 82eda875dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
181 changed files with 3075 additions and 3216 deletions

View File

@ -90,7 +90,7 @@ const ENTERPRISE_AUTH_METHODS = [
]; ];
export function supportedAuthBackends() { export function supportedAuthBackends() {
return SUPPORTED_AUTH_BACKENDS; return [...SUPPORTED_AUTH_BACKENDS];
} }
export function allSupportedAuthBackends() { export function allSupportedAuthBackends() {

View File

@ -8,7 +8,7 @@ import { formatISO } from 'date-fns';
import { formatByMonths, formatByNamespace, destructureClientCounts } from 'core/utils/client-count-utils'; import { formatByMonths, formatByNamespace, destructureClientCounts } from 'core/utils/client-count-utils';
import timestamp from 'core/utils/timestamp'; import timestamp from 'core/utils/timestamp';
// see tests/helpers/clients for sample API response (ACTIVITY_RESPONSE_STUB) // see tests/helpers/clients/client-count-helpers for sample API response (ACTIVITY_RESPONSE_STUB)
// and transformed by_namespace and by_month examples (SERIALIZED_ACTIVITY_RESPONSE) // and transformed by_namespace and by_month examples (SERIALIZED_ACTIVITY_RESPONSE)
export default class ActivitySerializer extends ApplicationSerializer { export default class ActivitySerializer extends ApplicationSerializer {
normalizeResponse(store, primaryModelClass, payload, id, requestType) { normalizeResponse(store, primaryModelClass, payload, id, requestType) {

35
ui/docs/tests.md Normal file
View File

@ -0,0 +1,35 @@
# Test Helpers Organization
Our test are constantly evolving, but here's a general overview of how we set up and organize tests.
## Folder organization
### /acceptance
Acceptance tests should test the overall workflows and navigation within Vault. When possible, they should use the real API instead of mocked so that breaking changes from the backend can be caught. Reasons you may opt to use a mocked backend instead of the real one:
- Using the real backend would cause instability in concurrently-running tests (eg. seal/unseal flow)
- There isn't a way to set up a 3rd party dependency that the backend needs to run correctly (Database Secrets Engine, Sync Secrets)
### /helpers
Shared helpers such as selectors, common interactions, WebREPL commands, and API response stubs live in this folder. When selectors are only used for a single test, they should be defined on the same file where they are used for the test. Once the selectors are being used for multiple tests, they should be moved to this folder so they can be defined in a single place and shared to wherever they are needed.
Often we will need a set of selectors for "workflow" tests, or acceptance tests that navigate through an area of the app. For these, the helpers should be organized as such:
- `/helpers/<area>/<area>-selectors.ts` - exports selector consts (never default) for each page -- eg. for PKI we would have PKI_OVERVIEW, PKI_ROLE, etc.
- `/helpers/<area>/<area>-helpers.js` - exports methods and consts which are otherwise helpful in the tests -- eg. example API responses, common interactions (eg. writeVersionedSecret for KV v2)
Whenever possible we should try to use the general selectors exported from `/helpers/general-selectors.ts`.
### integration
Integration tests are most often used to test specific components out of context from the rest of the app. Be sure to mock anything that the component needs to work correctly -- for example, if the component has a certain behavior in enterprise than community edition, in your tests for each scenario it should not assume that the underlying Vault binary is in one state or the other, and mock the enterprise/community state in all the scenarios. The exports in `helpers/stubs.js` might be helpful for these tests, particularly when the component uses a model which fetches capabilities.
### pages
[DEPRECATED] This file should be removed in favor of selectors within the "helpers" folder. We are moving away from ember-page-object selectors toward simple strings
### unit
Unit tests are most often used to test utils, adapters, serializers, routes, and services functionality.

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-engine-page-title> <h1 class="title is-3" data-test-page-title>
{{this.title}} {{this.title}}
</h1> </h1>
</p.levelLeft> </p.levelLeft>
@ -85,14 +85,10 @@
@onComplete={{transition-to "vault.cluster.secrets.backend.pki.overview"}} @onComplete={{transition-to "vault.cluster.secrets.backend.pki.overview"}}
/> />
{{else}} {{else}}
<EmptyState <EmptyState @title="Choose an option" @message="To see configuration options, choose your desired output above." />
@title="Choose an option"
@message="To see configuration options, choose your desired output above."
data-test-configuration-empty-state
/>
<hr class="has-background-gray-100" /> <hr class="has-background-gray-100" />
<Hds::ButtonSet> <Hds::ButtonSet>
<Hds::Button @text="Done" disabled={{true}} data-test-pki-config-save /> <Hds::Button @text="Done" disabled={{true}} data-test-save />
<Hds::Button @text="Cancel" @color="secondary" {{on "click" @onCancel}} data-test-pki-config-cancel /> <Hds::Button @text="Cancel" @color="secondary" {{on "click" @onCancel}} data-test-cancel />
</Hds::ButtonSet> </Hds::ButtonSet>
{{/if}} {{/if}}

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-page-title> <h1 class="title is-3" data-test-page-title>
{{this.title}} {{this.title}}
</h1> </h1>
</p.levelLeft> </p.levelLeft>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-page-title> <h1 class="title is-3" data-test-page-title>
{{this.title}} {{this.title}}
</h1> </h1>
</p.levelLeft> </p.levelLeft>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-page-title> <h1 class="title is-3" data-test-page-title>
{{this.title}} {{this.title}}
</h1> </h1>
</p.levelLeft> </p.levelLeft>

View File

@ -95,7 +95,7 @@
@text="Details" @text="Details"
@route="issuers.issuer.details" @route="issuers.issuer.details"
@model={{pkiIssuer.id}} @model={{pkiIssuer.id}}
data-test-popup-menu-details data-test-pki-issuer-details
/> />
<dd.Interactive @text="Edit" @route="issuers.issuer.edit" @model={{pkiIssuer.id}} /> <dd.Interactive @text="Edit" @route="issuers.issuer.edit" @model={{pkiIssuer.id}} />
</Hds::Dropdown> </Hds::Dropdown>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-page-title> <h1 class="title is-3" data-test-page-title>
{{if @newRootModel.id "View Issuer Certificate" "Generate New Root"}} {{if @newRootModel.id "View Issuer Certificate" "Generate New Root"}}
</h1> </h1>
</p.levelLeft> </p.levelLeft>
@ -166,8 +166,8 @@
<hr class="has-background-gray-100" /> <hr class="has-background-gray-100" />
<Hds::ButtonSet> <Hds::ButtonSet>
<Hds::Button @text="Done" type="submit" data-test-pki-rotate-root-save /> <Hds::Button @text="Done" type="submit" data-test-save />
<Hds::Button @text="Cancel" @color="secondary" {{on "click" @onCancel}} data-test-pki-rotate-root-cancel /> <Hds::Button @text="Cancel" @color="secondary" {{on "click" @onCancel}} data-test-cancel />
</Hds::ButtonSet> </Hds::ButtonSet>
{{#if this.invalidFormAlert}} {{#if this.invalidFormAlert}}
<div class="control"> <div class="control">

View File

@ -97,8 +97,8 @@
<hr class="has-background-gray-100" /> <hr class="has-background-gray-100" />
<Hds::ButtonSet> <Hds::ButtonSet>
<Hds::Button @text="Done" type="submit" data-test-pki-generate-root-save /> <Hds::Button @text="Done" type="submit" data-test-save />
<Hds::Button @text="Cancel" @color="secondary" {{on "click" @onCancel}} data-test-pki-generate-root-cancel /> <Hds::Button @text="Cancel" @color="secondary" {{on "click" @onCancel}} data-test-cancel />
</Hds::ButtonSet> </Hds::ButtonSet>
{{#if this.invalidFormAlert}} {{#if this.invalidFormAlert}}
<div class="control"> <div class="control">

View File

@ -93,14 +93,14 @@
@icon={{if this.submit.isRunning "loading"}} @icon={{if this.submit.isRunning "loading"}}
type="submit" type="submit"
disabled={{this.submit.isRunning}} disabled={{this.submit.isRunning}}
data-test-cross-sign-submit data-test-save
/> />
<Hds::Button <Hds::Button
@text="Cancel" @text="Cancel"
@color="secondary" @color="secondary"
@route="issuers.issuer.details" @route="issuers.issuer.details"
disabled={{this.submit.isRunning}} disabled={{this.submit.isRunning}}
data-test-cross-sign-cancel data-test-cancel
/> />
</Hds::ButtonSet> </Hds::ButtonSet>
</form> </form>

View File

@ -41,14 +41,14 @@
@icon={{if this.save.isRunning "loading"}} @icon={{if this.save.isRunning "loading"}}
type="submit" type="submit"
disabled={{this.save.isRunning}} disabled={{this.save.isRunning}}
data-test-pki-key-save data-test-save
/> />
<Hds::Button <Hds::Button
@text="Cancel" @text="Cancel"
@color="secondary" @color="secondary"
disabled={{this.save.isRunning}} disabled={{this.save.isRunning}}
{{on "click" @onCancel}} {{on "click" @onCancel}}
data-test-pki-key-cancel data-test-cancel
/> />
</Hds::ButtonSet> </Hds::ButtonSet>
{{#if this.invalidFormAlert}} {{#if this.invalidFormAlert}}

View File

@ -30,7 +30,7 @@
@color="secondary" @color="secondary"
disabled={{this.submitForm.isRunning}} disabled={{this.submitForm.isRunning}}
{{on "click" this.cancel}} {{on "click" this.cancel}}
data-test-pki-key-cancel data-test-cancel
/> />
</Hds::ButtonSet> </Hds::ButtonSet>
{{#if this.invalidFormAlert}} {{#if this.invalidFormAlert}}

View File

@ -124,14 +124,14 @@
@icon={{if this.save.isRunning "loading"}} @icon={{if this.save.isRunning "loading"}}
type="submit" type="submit"
disabled={{this.save.isRunning}} disabled={{this.save.isRunning}}
data-test-pki-role-save data-test-save
/> />
<Hds::Button <Hds::Button
@text="Cancel" @text="Cancel"
@color="secondary" @color="secondary"
disabled={{this.save.isRunning}} disabled={{this.save.isRunning}}
{{on "click" @onCancel}} {{on "click" @onCancel}}
data-test-pki-role-cancel data-test-cancel
/> />
</Hds::ButtonSet> </Hds::ButtonSet>
{{#if this.modelValidations.targets.errors}} {{#if this.modelValidations.targets.errors}}

View File

@ -31,14 +31,14 @@
@icon={{if this.save.isRunning "loading"}} @icon={{if this.save.isRunning "loading"}}
type="submit" type="submit"
disabled={{this.save.isRunning}} disabled={{this.save.isRunning}}
data-test-pki-generate-button data-test-save
/> />
<Hds::Button <Hds::Button
@text="Cancel" @text="Cancel"
@color="secondary" @color="secondary"
disabled={{this.save.isRunning}} disabled={{this.save.isRunning}}
{{on "click" this.cancel}} {{on "click" this.cancel}}
data-test-pki-generate-cancel data-test-cancel
/> />
</Hds::ButtonSet> </Hds::ButtonSet>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-issuer-page-title> <h1 class="title is-3" data-test-page-title>
Cross-Sign Issuers Cross-Sign Issuers
</h1> </h1>
</p.levelLeft> </p.levelLeft>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-issuer-page-title> <h1 class="title is-3" data-test-page-title>
<Icon @name="file-text" @size="24" class="has-text-grey-light" /> <Icon @name="file-text" @size="24" class="has-text-grey-light" />
View Issuer Certificate View Issuer Certificate
</h1> </h1>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-issuer-page-title> <h1 class="title is-3" data-test-page-title>
Update Issuer Update Issuer
</h1> </h1>
</p.levelLeft> </p.levelLeft>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-issuer-page-title> <h1 class="title is-3" data-test-page-title>
<Icon @name="file-text" @size="24" class="has-text-grey-light" /> <Icon @name="file-text" @size="24" class="has-text-grey-light" />
Sign Intermediate Sign Intermediate
</h1> </h1>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-key-details-title> <h1 class="title is-3" data-test-page-title>
<Icon @name="certificate" @size="24" class="has-text-grey-light" /> <Icon @name="certificate" @size="24" class="has-text-grey-light" />
View Key View Key
</h1> </h1>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-key-details-title> <h1 class="title is-3" data-test-page-title>
<Icon @name="certificate" @size="24" class="has-text-grey-light" /> <Icon @name="certificate" @size="24" class="has-text-grey-light" />
Edit Key Edit Key
</h1> </h1>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-role-page-title> <h1 class="title is-3" data-test-page-title>
Create a PKI Role Create a PKI Role
</h1> </h1>
</p.levelLeft> </p.levelLeft>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-role-page-title> <h1 class="title is-3" data-test-page-title>
<Icon @name="file-text" @size="24" class="has-text-grey-light" /> <Icon @name="file-text" @size="24" class="has-text-grey-light" />
PKI Role PKI Role
<code>{{this.model.name}}</code> <code>{{this.model.name}}</code>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-role-page-title> <h1 class="title is-3" data-test-page-title>
Edit Role Edit Role
</h1> </h1>
</p.levelLeft> </p.levelLeft>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-role-page-title> <h1 class="title is-3" data-test-page-title>
<Icon @name="certificate" @size="24" class="has-text-grey-light" /> <Icon @name="certificate" @size="24" class="has-text-grey-light" />
{{if this.hasSubmitted "View Generated Certificate" "Generate Certificate"}} {{if this.hasSubmitted "View Generated Certificate" "Generate Certificate"}}
</h1> </h1>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} /> <Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top> </p.top>
<p.levelLeft> <p.levelLeft>
<h1 class="title is-3" data-test-pki-role-page-title> <h1 class="title is-3" data-test-page-title>
<Icon @name="certificate" @size="24" class="has-text-grey-light" /> <Icon @name="certificate" @size="24" class="has-text-grey-light" />
{{if this.hasSubmitted "View Signed Certificate" "Sign Certificate"}} {{if this.hasSubmitted "View Signed Certificate" "Sign Certificate"}}
</h1> </h1>

View File

@ -9,7 +9,7 @@ import { setupApplicationTest } from 'ember-qunit';
import page from 'vault/tests/pages/access/identity/index'; import page from 'vault/tests/pages/access/identity/index';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { runCmd } from 'vault/tests/helpers/commands'; import { runCmd } from 'vault/tests/helpers/commands';
import { SELECTORS as GENERAL } from 'vault/tests/helpers/general-selectors'; import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
const SELECTORS = { const SELECTORS = {

View File

@ -73,109 +73,95 @@ module('Acceptance | auth backend list', function (hooks) {
assert.dom(SELECTORS.listItem).hasText(this.user1, 'user1 exists in the list'); assert.dom(SELECTORS.listItem).hasText(this.user1, 'user1 exists in the list');
}); });
test('auth methods are linkable and link to correct view', async function (assert) { module('auth methods are linkable and link to correct view', function (hooks) {
assert.expect(45); hooks.beforeEach(async function () {
const uid = uuidv4(); this.uid = uuidv4();
await visit('/vault/access'); await visit('/vault/access');
});
const supportManaged = supportedManagedAuthBackends();
// Test all auth methods, not just those you can log in with // Test all auth methods, not just those you can log in with
const backends = methods().map((backend) => backend.type); methods()
assert.deepEqual( .map((backend) => backend.type)
backends, .forEach((type) => {
[ test(`${type} auth method`, async function (assert) {
'alicloud', const supportManaged = supportedManagedAuthBackends();
'approle', const path = type === 'token' ? 'token' : `auth-list-${type}-${this.uid}`;
'aws', if (type !== 'token') {
'azure', await enablePage.enable(type, path);
'gcp', }
'github', await settled();
'jwt', await visit('/vault/access');
'oidc',
'kubernetes', // check popup menu
'ldap', const itemCount = type === 'token' ? 2 : 3;
'okta', await click(`[data-test-auth-backend-link="${path}"] [data-test-popup-menu-trigger]`);
'radius', assert
'cert', .dom('.hds-dropdown-list-item')
'userpass', .exists({ count: itemCount }, `shows ${itemCount} dropdown items for ${type}`);
],
'non-enterprise auth methods are available' // all auth methods should be linkable
); await click(`[data-test-auth-backend-link="${path}"]`);
for (const type of backends) { if (!supportManaged.includes(type)) {
const path = type === 'token' ? 'token' : `auth-list-${type}-${uid}`; assert.dom('[data-test-auth-section-tab]').exists({ count: 1 });
if (type !== 'token') { assert
await enablePage.enable(type, path); .dom('[data-test-auth-section-tab]')
} .hasText('Configuration', `only shows configuration tab for ${type} auth method`);
assert.dom('[data-test-doc-link] .doc-link').exists(`includes doc link for ${type} auth method`);
} else {
let expectedTabs = 2;
if (type === 'ldap' || type === 'okta') {
expectedTabs = 3;
}
assert
.dom('[data-test-auth-section-tab]')
.exists({ count: expectedTabs }, `has management tabs for ${type} auth method`);
}
if (type !== 'token') {
// cleanup method
await runCmd(deleteAuthCmd(path));
}
});
});
});
module('enterprise', function () {
test('ent-only auth methods are linkable and link to correct view', async function (assert) {
assert.expect(3);
const uid = uuidv4();
await visit('/vault/access');
// Only SAML is enterprise-only for now
const type = 'saml';
const path = `auth-list-${type}-${uid}`;
await enablePage.enable(type, path);
await settled(); await settled();
await visit('/vault/access'); await visit('/vault/access');
// check popup menu
const itemCount = type === 'token' ? 2 : 3;
await click(`[data-test-auth-backend-link="${path}"] [data-test-popup-menu-trigger]`);
assert
.dom('.hds-dropdown-list-item')
.exists({ count: itemCount }, `shows ${itemCount} dropdown items for ${type}`);
// all auth methods should be linkable // all auth methods should be linkable
await click(`[data-test-auth-backend-link="${path}"]`); await click(`[data-test-auth-backend-link="${path}"]`);
if (!supportManaged.includes(type)) { assert.dom('[data-test-auth-section-tab]').exists({ count: 1 });
assert.dom('[data-test-auth-section-tab]').exists({ count: 1 }); assert
assert .dom('[data-test-auth-section-tab]')
.dom('[data-test-auth-section-tab]') .hasText('Configuration', `only shows configuration tab for ${type} auth method`);
.hasText('Configuration', `only shows configuration tab for ${type} auth method`); assert.dom('[data-test-doc-link] .doc-link').exists(`includes doc link for ${type} auth method`);
assert.dom('[data-test-doc-link] .doc-link').exists(`includes doc link for ${type} auth method`); await runCmd(deleteAuthCmd(path));
} else { });
let expectedTabs = 2;
if (type == 'ldap' || type === 'okta') {
expectedTabs = 3;
}
assert
.dom('[data-test-auth-section-tab]')
.exists({ count: expectedTabs }, `has management tabs for ${type} auth method`);
}
if (type !== 'token') {
// cleanup method
await runCmd(deleteAuthCmd(path));
}
}
});
test('enterprise: auth methods are linkable and link to correct view', async function (assert) { test('token config within namespace', async function (assert) {
assert.expect(3); const ns = 'ns-wxyz';
const uid = uuidv4(); await runCmd(createNS(ns), false);
await visit('/vault/access'); await settled();
await authPage.loginNs(ns);
// Only SAML is enterprise-only for now // go directly to token configure route
const type = 'saml'; await visit('/vault/settings/auth/configure/token/options');
const path = `auth-list-${type}-${uid}`; await fillIn('[data-test-input="description"]', 'My custom description');
await enablePage.enable(type, path); await click('[data-test-save-config="true"]');
await settled(); assert.strictEqual(currentURL(), '/vault/access', 'successfully saves and navigates away');
await visit('/vault/access'); await click('[data-test-auth-backend-link="token"]');
assert
// all auth methods should be linkable .dom('[data-test-row-value="Description"]')
await click(`[data-test-auth-backend-link="${path}"]`); .hasText('My custom description', 'description was saved');
assert.dom('[data-test-auth-section-tab]').exists({ count: 1 }); await runCmd(`delete sys/namespaces/${ns}`);
assert });
.dom('[data-test-auth-section-tab]')
.hasText('Configuration', `only shows configuration tab for ${type} auth method`);
assert.dom('[data-test-doc-link] .doc-link').exists(`includes doc link for ${type} auth method`);
await runCmd(deleteAuthCmd(path));
});
test('enterprise: token config within namespace', async function (assert) {
const ns = 'ns-wxyz';
await runCmd(createNS(ns), false);
await settled();
await authPage.loginNs(ns);
// go directly to token configure route
await visit('/vault/settings/auth/configure/token/options');
await fillIn('[data-test-input="description"]', 'My custom description');
await click('[data-test-save-config="true"]');
assert.strictEqual(currentURL(), '/vault/access', 'successfully saves and navigates away');
await click('[data-test-auth-backend-link="token"]');
assert
.dom('[data-test-row-value="Description"]')
.hasText('My custom description', 'description was saved');
await runCmd(`delete sys/namespaces/${ns}`);
}); });
}); });

View File

@ -3,35 +3,21 @@
* SPDX-License-Identifier: BUSL-1.1 * SPDX-License-Identifier: BUSL-1.1
*/ */
/* eslint qunit/no-conditional-assertions: "warn" */
import { module, test } from 'qunit'; import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit'; import { setupApplicationTest } from 'ember-qunit';
import sinon from 'sinon';
import { click, currentURL, visit, waitUntil, find } from '@ember/test-helpers'; import { click, currentURL, visit, waitUntil, find } from '@ember/test-helpers';
import { supportedAuthBackends } from 'vault/helpers/supported-auth-backends'; import { supportedAuthBackends } from 'vault/helpers/supported-auth-backends';
import authForm from '../pages/components/auth-form'; import authForm from '../pages/components/auth-form';
import jwtForm from '../pages/components/auth-jwt'; import jwtForm from '../pages/components/auth-jwt';
import { create } from 'ember-cli-page-object'; import { create } from 'ember-cli-page-object';
import apiStub from 'vault/tests/helpers/noop-all-api-requests'; import { setupMirage } from 'ember-cli-mirage/test-support';
const component = create(authForm); const component = create(authForm);
const jwtComponent = create(jwtForm); const jwtComponent = create(jwtForm);
module('Acceptance | auth', function (hooks) { module('Acceptance | auth', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(function () {
this.clock = sinon.useFakeTimers({
now: Date.now(),
shouldAdvanceTime: true,
});
this.server = apiStub({ usePassthrough: true });
});
hooks.afterEach(function () {
this.clock.restore();
this.server.shutdown();
});
test('auth query params', async function (assert) { test('auth query params', async function (assert) {
const backends = supportedAuthBackends(); const backends = supportedAuthBackends();
@ -55,53 +41,102 @@ module('Acceptance | auth', function (hooks) {
assert.strictEqual(component.tokenValue, '', 'it clears the token value when toggling methods'); assert.strictEqual(component.tokenValue, '', 'it clears the token value when toggling methods');
}); });
test('it sends the right attributes when authenticating', async function (assert) { module('it sends the right attributes when authenticating', function (hooks) {
assert.expect(8); hooks.beforeEach(function () {
const backends = supportedAuthBackends(); this.assertReq = () => {};
await visit('/vault/auth'); this.server.get('/auth/token/lookup-self', (schema, req) => {
for (const backend of backends.reverse()) { this.assertReq(req);
await component.selectMethod(backend.type); req.passthrough();
if (backend.type === 'github') { });
await component.token('token'); this.server.post('/auth/github/login', (schema, req) => {
} // This one is for github only
if (backend.type === 'jwt' || backend.type === 'oidc') { this.assertReq(req);
await jwtComponent.role('test'); req.passthrough();
} });
await component.login(); this.server.post('/auth/:mount/oidc/auth_url', (schema, req) => {
const lastRequest = this.server.passthroughRequests[this.server.passthroughRequests.length - 1]; // For JWT and OIDC
const body = JSON.parse(lastRequest.requestBody); this.assertReq(req);
req.passthrough();
});
this.server.post('/auth/:mount/login/:username', (schema, req) => {
this.assertReq(req);
req.passthrough();
});
this.expected = {
token: {
included: 'X-Vault-Token',
url: '/v1/auth/token/lookup-self',
},
userpass: {
included: 'password',
url: '/v1/auth/userpass/login/null',
},
ldap: {
included: 'password',
url: '/v1/auth/ldap/login/null',
},
okta: {
included: 'password',
url: '/v1/auth/okta/login/null',
},
jwt: {
included: 'role',
url: '/v1/auth/jwt/oidc/auth_url',
},
oidc: {
included: 'role',
url: '/v1/auth/oidc/oidc/auth_url',
},
radius: {
included: 'password',
url: '/v1/auth/radius/login/null',
},
github: {
included: 'token',
url: '/v1/auth/github/login',
},
};
});
let keys; for (const backend of supportedAuthBackends().reverse()) {
let included; test(`for ${backend.type}`, async function (assert) {
if (backend.type === 'token') { const { type } = backend;
keys = lastRequest.requestHeaders; const isOidc = ['jwt', 'oidc'].includes(type);
included = 'x-vault-token'; // OIDC types make 3 requests, each time the role changes
} else if (backend.type === 'github') { assert.expect(isOidc ? 6 : 2);
keys = body; this.assertReq = (req) => {
included = 'token'; const body = type === 'token' ? req.requestHeaders : JSON.parse(req.requestBody);
} else if (backend.type === 'jwt' || backend.type === 'oidc') { const { included, url } = this.expected[type];
const authReq = this.server.passthroughRequests[this.server.passthroughRequests.length - 2]; assert.true(Object.keys(body).includes(included), `${type} includes ${included}`);
keys = JSON.parse(authReq.requestBody); assert.strictEqual(req.url, url, `${type} calls the correct URL`);
included = 'role'; };
} else { await visit('/vault/auth');
keys = body; await component.selectMethod(type);
included = 'password'; if (type === 'github') {
} await component.token('token');
assert.ok(Object.keys(keys).includes(included), `${backend.type} includes ${included}`); }
if (isOidc) {
await jwtComponent.role('test');
}
await component.login();
});
} }
}); });
test('it shows the push notification warning after submit', async function (assert) { test('it shows the push notification warning after submit', async function (assert) {
assert.expect(1); assert.expect(1);
this.server.get('/v1/auth/token/lookup-self', async () => { this.server.get(
assert.ok( '/auth/token/lookup-self',
await waitUntil(() => find('[data-test-auth-message="push"]')), async () => {
'shows push notification message' assert.ok(
); await waitUntil(() => find('[data-test-auth-message="push"]')),
return [204, { 'Content-Type': 'application/json' }, JSON.stringify({})]; 'shows push notification message'
}); );
return {};
},
{ timing: 1000 }
);
await visit('/vault/auth'); await visit('/vault/auth');
await component.selectMethod('token'); await component.selectMethod('token');
await click('[data-test-auth-submit]'); await click('[data-test-auth-submit]');

View File

@ -10,7 +10,8 @@ import clientsHandler, { STATIC_NOW } from 'vault/mirage/handlers/clients';
import sinon from 'sinon'; import sinon from 'sinon';
import { visit, click, currentURL } from '@ember/test-helpers'; import { visit, click, currentURL } from '@ember/test-helpers';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { SELECTORS as ts } from 'vault/tests/helpers/clients'; import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { CLIENT_COUNT } from 'vault/tests/helpers/clients/client-count-selectors';
import timestamp from 'core/utils/timestamp'; import timestamp from 'core/utils/timestamp';
module('Acceptance | clients | counts', function (hooks) { module('Acceptance | clients | counts', function (hooks) {
@ -36,8 +37,8 @@ module('Acceptance | clients | counts', function (hooks) {
this.owner.lookup('service:version').type = 'community'; this.owner.lookup('service:version').type = 'community';
await visit('/vault/clients/counts/overview'); await visit('/vault/clients/counts/overview');
assert.dom(ts.emptyStateTitle).hasText('No data received'); assert.dom(GENERAL.emptyStateTitle).hasText('No data received');
assert.dom(ts.emptyStateMessage).hasText('Select a start date above to query client count data.'); assert.dom(GENERAL.emptyStateMessage).hasText('Select a start date above to query client count data.');
}); });
test('it should redirect to counts overview route for transitions to parent', async function (assert) { test('it should redirect to counts overview route for transitions to parent', async function (assert) {
@ -47,19 +48,19 @@ module('Acceptance | clients | counts', function (hooks) {
test('it should persist filter query params between child routes', async function (assert) { test('it should persist filter query params between child routes', async function (assert) {
await visit('/vault/clients/counts/overview'); await visit('/vault/clients/counts/overview');
await click(ts.rangeDropdown); await click(CLIENT_COUNT.rangeDropdown);
await click(ts.currentBillingPeriod); await click(CLIENT_COUNT.currentBillingPeriod);
const timeQueryRegex = /end_time=\d+&start_time=\d+/g; const timeQueryRegex = /end_time=\d+&start_time=\d+/g;
assert.ok(currentURL().match(timeQueryRegex).length, 'Start and end times added as query params'); assert.ok(currentURL().match(timeQueryRegex).length, 'Start and end times added as query params');
await click(ts.tab('token')); await click(GENERAL.tab('token'));
assert.ok( assert.ok(
currentURL().match(timeQueryRegex).length, currentURL().match(timeQueryRegex).length,
'Start and end times persist through child route change' 'Start and end times persist through child route change'
); );
await click(ts.navLink('Dashboard')); await click(GENERAL.navLink('Dashboard'));
await click(ts.navLink('Client Count')); await click(GENERAL.navLink('Client Count'));
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
'/vault/clients/counts/overview', '/vault/clients/counts/overview',

View File

@ -11,7 +11,8 @@ import sinon from 'sinon';
import { visit, click, findAll, settled } from '@ember/test-helpers'; import { visit, click, findAll, settled } from '@ember/test-helpers';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { ARRAY_OF_MONTHS } from 'core/utils/date-formatters'; import { ARRAY_OF_MONTHS } from 'core/utils/date-formatters';
import { SELECTORS } from 'vault/tests/helpers/clients'; import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { CLIENT_COUNT } from 'vault/tests/helpers/clients/client-count-selectors';
import { create } from 'ember-cli-page-object'; import { create } from 'ember-cli-page-object';
import { clickTrigger } from 'ember-power-select/test-support/helpers'; import { clickTrigger } from 'ember-power-select/test-support/helpers';
import { formatNumber } from 'core/helpers/format-number'; import { formatNumber } from 'core/helpers/format-number';
@ -40,24 +41,24 @@ module('Acceptance | clients | overview', function (hooks) {
}); });
test('it should render the correct tabs', async function (assert) { test('it should render the correct tabs', async function (assert) {
assert.dom(SELECTORS.tab('overview')).exists(); assert.dom(GENERAL.tab('overview')).exists();
assert.dom(SELECTORS.tab('token')).exists(); assert.dom(GENERAL.tab('token')).exists();
assert.dom(SELECTORS.tab('config')).exists(); assert.dom(GENERAL.tab('config')).exists();
}); });
test('it should render charts', async function (assert) { test('it should render charts', async function (assert) {
assert assert
.dom(SELECTORS.counts.startMonth) .dom(CLIENT_COUNT.counts.startMonth)
.hasText('July 2023', 'billing start month is correctly parsed from license'); .hasText('July 2023', 'billing start month is correctly parsed from license');
assert assert
.dom(SELECTORS.rangeDropdown) .dom(CLIENT_COUNT.rangeDropdown)
.hasText('Jul 2023 - Jan 2024', 'Date range shows dates correctly parsed activity response'); .hasText('Jul 2023 - Jan 2024', 'Date range shows dates correctly parsed activity response');
assert.dom(SELECTORS.attributionBlock).exists('Shows attribution area'); assert.dom(CLIENT_COUNT.attributionBlock).exists('Shows attribution area');
assert assert
.dom(SELECTORS.charts.chart('running total')) .dom(CLIENT_COUNT.charts.chart('running total'))
.exists('Shows running totals with monthly breakdown charts'); .exists('Shows running totals with monthly breakdown charts');
assert assert
.dom(SELECTORS.charts.line.xAxisLabel) .dom(CLIENT_COUNT.charts.line.xAxisLabel)
.hasText('7/23', 'x-axis labels start with billing start date'); .hasText('7/23', 'x-axis labels start with billing start date');
assert.strictEqual( assert.strictEqual(
findAll('[data-test-line-chart="plot-point"]').length, findAll('[data-test-line-chart="plot-point"]').length,
@ -68,17 +69,17 @@ module('Acceptance | clients | overview', function (hooks) {
test('it should update charts when querying date ranges', async function (assert) { test('it should update charts when querying date ranges', async function (assert) {
// query for single, historical month with no new counts (July 2023) // query for single, historical month with no new counts (July 2023)
await click(SELECTORS.rangeDropdown); await click(CLIENT_COUNT.rangeDropdown);
await click('[data-test-show-calendar]'); await click('[data-test-show-calendar]');
await click('[data-test-previous-year]'); await click('[data-test-previous-year]');
await click(`[data-test-calendar-month=${ARRAY_OF_MONTHS[LICENSE_START.getMonth()]}]`); await click(`[data-test-calendar-month=${ARRAY_OF_MONTHS[LICENSE_START.getMonth()]}]`);
assert assert
.dom(SELECTORS.runningTotalMonthStats) .dom(CLIENT_COUNT.runningTotalMonthStats)
.doesNotExist('running total single month stat boxes do not show'); .doesNotExist('running total single month stat boxes do not show');
assert assert
.dom(SELECTORS.charts.chart('running total')) .dom(CLIENT_COUNT.charts.chart('running total'))
.doesNotExist('running total month over month charts do not show'); .doesNotExist('running total month over month charts do not show');
assert.dom(SELECTORS.attributionBlock).exists('attribution area shows'); assert.dom(CLIENT_COUNT.attributionBlock).exists('attribution area shows');
assert assert
.dom('[data-test-chart-container="new-clients"] [data-test-component="empty-state"]') .dom('[data-test-chart-container="new-clients"] [data-test-component="empty-state"]')
.exists('new client attribution has empty state'); .exists('new client attribution has empty state');
@ -88,22 +89,22 @@ module('Acceptance | clients | overview', function (hooks) {
assert.dom('[data-test-chart-container="total-clients"]').exists('total client attribution chart shows'); assert.dom('[data-test-chart-container="total-clients"]').exists('total client attribution chart shows');
// reset to billing period // reset to billing period
await click(SELECTORS.rangeDropdown); await click(CLIENT_COUNT.rangeDropdown);
await click('[data-test-current-billing-period]'); await click('[data-test-current-billing-period]');
// change billing start to month/year of upgrade to 1.10 // change billing start to month/year of upgrade to 1.10
await click(SELECTORS.counts.startEdit); await click(CLIENT_COUNT.counts.startEdit);
await click(SELECTORS.monthDropdown); await click(CLIENT_COUNT.monthDropdown);
await click(`[data-test-dropdown-month="${ARRAY_OF_MONTHS[UPGRADE_DATE.getMonth()]}"]`); await click(`[data-test-dropdown-month="${ARRAY_OF_MONTHS[UPGRADE_DATE.getMonth()]}"]`);
await click(SELECTORS.yearDropdown); await click(CLIENT_COUNT.yearDropdown);
await click(`[data-test-dropdown-year="${UPGRADE_DATE.getFullYear()}"]`); await click(`[data-test-dropdown-year="${UPGRADE_DATE.getFullYear()}"]`);
await click('[data-test-date-dropdown-submit]'); await click('[data-test-date-dropdown-submit]');
assert.dom(SELECTORS.attributionBlock).exists('Shows attribution area'); assert.dom(CLIENT_COUNT.attributionBlock).exists('Shows attribution area');
assert assert
.dom(SELECTORS.charts.chart('running total')) .dom(CLIENT_COUNT.charts.chart('running total'))
.exists('Shows running totals with monthly breakdown charts'); .exists('Shows running totals with monthly breakdown charts');
assert assert
.dom(SELECTORS.charts.line.xAxisLabel) .dom(CLIENT_COUNT.charts.line.xAxisLabel)
.hasText('9/23', 'x-axis labels start with queried start month (upgrade date)'); .hasText('9/23', 'x-axis labels start with queried start month (upgrade date)');
assert.strictEqual( assert.strictEqual(
findAll('[data-test-line-chart="plot-point"]').length, findAll('[data-test-line-chart="plot-point"]').length,
@ -112,50 +113,50 @@ module('Acceptance | clients | overview', function (hooks) {
); );
// query for single, historical month (upgrade month) // query for single, historical month (upgrade month)
await click(SELECTORS.rangeDropdown); await click(CLIENT_COUNT.rangeDropdown);
await click('[data-test-show-calendar]'); await click('[data-test-show-calendar]');
assert.dom('[data-test-display-year]').hasText('2024'); assert.dom('[data-test-display-year]').hasText('2024');
await click('[data-test-previous-year]'); await click('[data-test-previous-year]');
await click('[data-test-calendar-month="September"]'); await click('[data-test-calendar-month="September"]');
assert.dom(SELECTORS.runningTotalMonthStats).exists('running total single month stat boxes show'); assert.dom(CLIENT_COUNT.runningTotalMonthStats).exists('running total single month stat boxes show');
assert assert
.dom(SELECTORS.charts.chart('running total')) .dom(CLIENT_COUNT.charts.chart('running total'))
.doesNotExist('running total month over month charts do not show'); .doesNotExist('running total month over month charts do not show');
assert.dom(SELECTORS.attributionBlock).exists('attribution area shows'); assert.dom(CLIENT_COUNT.attributionBlock).exists('attribution area shows');
assert.dom('[data-test-chart-container="new-clients"]').exists('new client attribution chart shows'); assert.dom('[data-test-chart-container="new-clients"]').exists('new client attribution chart shows');
assert.dom('[data-test-chart-container="total-clients"]').exists('total client attribution chart shows'); assert.dom('[data-test-chart-container="total-clients"]').exists('total client attribution chart shows');
// query historical date range (from September 2023 to December 2023) // query historical date range (from September 2023 to December 2023)
await click(SELECTORS.rangeDropdown); await click(CLIENT_COUNT.rangeDropdown);
await click('[data-test-show-calendar]'); await click('[data-test-show-calendar]');
await click('[data-test-calendar-month="December"]'); await click('[data-test-calendar-month="December"]');
assert.dom(SELECTORS.attributionBlock).exists('Shows attribution area'); assert.dom(CLIENT_COUNT.attributionBlock).exists('Shows attribution area');
assert assert
.dom(SELECTORS.charts.chart('running total')) .dom(CLIENT_COUNT.charts.chart('running total'))
.exists('Shows running totals with monthly breakdown charts'); .exists('Shows running totals with monthly breakdown charts');
assert.strictEqual( assert.strictEqual(
findAll('[data-test-line-chart="plot-point"]').length, findAll('[data-test-line-chart="plot-point"]').length,
4, 4,
'line chart plots 4 points to match query' 'line chart plots 4 points to match query'
); );
const xAxisLabels = findAll(SELECTORS.charts.line.xAxisLabel); const xAxisLabels = findAll(CLIENT_COUNT.charts.line.xAxisLabel);
assert assert
.dom(xAxisLabels[xAxisLabels.length - 1]) .dom(xAxisLabels[xAxisLabels.length - 1])
.hasText('12/23', 'x-axis labels end with queried end month'); .hasText('12/23', 'x-axis labels end with queried end month');
// reset to billing period // reset to billing period
await click(SELECTORS.rangeDropdown); await click(CLIENT_COUNT.rangeDropdown);
await click('[data-test-current-billing-period]'); await click('[data-test-current-billing-period]');
// query month older than count start date // query month older than count start date
await click(SELECTORS.counts.startEdit); await click(CLIENT_COUNT.counts.startEdit);
await click(SELECTORS.monthDropdown); await click(CLIENT_COUNT.monthDropdown);
await click(`[data-test-dropdown-month="${ARRAY_OF_MONTHS[LICENSE_START.getMonth()]}"]`); await click(`[data-test-dropdown-month="${ARRAY_OF_MONTHS[LICENSE_START.getMonth()]}"]`);
await click(SELECTORS.yearDropdown); await click(CLIENT_COUNT.yearDropdown);
await click(`[data-test-dropdown-year="${LICENSE_START.getFullYear() - 3}"]`); await click(`[data-test-dropdown-year="${LICENSE_START.getFullYear() - 3}"]`);
await click('[data-test-date-dropdown-submit]'); await click('[data-test-date-dropdown-submit]');
assert assert
.dom(SELECTORS.counts.startDiscrepancy) .dom(CLIENT_COUNT.counts.startDiscrepancy)
.hasTextContaining( .hasTextContaining(
'You requested data from July 2020. We only have data from January 2023, and that is what is being shown here.', 'You requested data from July 2020. We only have data from January 2023, and that is what is being shown here.',
'warning banner displays that date queried was prior to count start date' 'warning banner displays that date queried was prior to count start date'
@ -164,9 +165,9 @@ module('Acceptance | clients | overview', function (hooks) {
test('totals filter correctly with full data', async function (assert) { test('totals filter correctly with full data', async function (assert) {
assert assert
.dom(SELECTORS.charts.chart('running total')) .dom(CLIENT_COUNT.charts.chart('running total'))
.exists('Shows running totals with monthly breakdown charts'); .exists('Shows running totals with monthly breakdown charts');
assert.dom(SELECTORS.attributionBlock).exists('Shows attribution area'); assert.dom(CLIENT_COUNT.attributionBlock).exists('Shows attribution area');
const response = await this.store.peekRecord('clients/activity', 'some-activity-id'); const response = await this.store.peekRecord('clients/activity', 'some-activity-id');
// FILTER BY NAMESPACE // FILTER BY NAMESPACE
@ -176,19 +177,19 @@ module('Acceptance | clients | overview', function (hooks) {
const topNamespace = response.byNamespace[0]; const topNamespace = response.byNamespace[0];
const topMount = topNamespace.mounts[0]; const topMount = topNamespace.mounts[0];
assert.dom(SELECTORS.selectedNs).hasText(topNamespace.label, 'selects top namespace'); assert.dom(CLIENT_COUNT.selectedNs).hasText(topNamespace.label, 'selects top namespace');
assert.dom('[data-test-top-attribution]').includesText('Top auth method'); assert.dom('[data-test-top-attribution]').includesText('Top auth method');
assert assert
.dom(SELECTORS.charts.statTextValue('Entity clients')) .dom(CLIENT_COUNT.charts.statTextValue('Entity clients'))
.includesText(`${formatNumber([topNamespace.entity_clients])}`, 'total entity clients is accurate'); .includesText(`${formatNumber([topNamespace.entity_clients])}`, 'total entity clients is accurate');
assert assert
.dom(SELECTORS.charts.statTextValue('Non-entity clients')) .dom(CLIENT_COUNT.charts.statTextValue('Non-entity clients'))
.includesText( .includesText(
`${formatNumber([topNamespace.non_entity_clients])}`, `${formatNumber([topNamespace.non_entity_clients])}`,
'total non-entity clients is accurate' 'total non-entity clients is accurate'
); );
assert assert
.dom(SELECTORS.charts.statTextValue('Secrets sync clients')) .dom(CLIENT_COUNT.charts.statTextValue('Secrets sync clients'))
.includesText(`${formatNumber([topNamespace.secret_syncs])}`, 'total sync clients is accurate'); .includesText(`${formatNumber([topNamespace.secret_syncs])}`, 'total sync clients is accurate');
assert assert
.dom('[data-test-attribution-clients] p') .dom('[data-test-attribution-clients] p')
@ -200,35 +201,35 @@ module('Acceptance | clients | overview', function (hooks) {
await settled(); await settled();
assert.ok(true, 'Filter by first auth method'); assert.ok(true, 'Filter by first auth method');
assert.dom(SELECTORS.selectedAuthMount).hasText(topMount.label, 'selects top mount'); assert.dom(CLIENT_COUNT.selectedAuthMount).hasText(topMount.label, 'selects top mount');
assert assert
.dom(SELECTORS.charts.statTextValue('Entity clients')) .dom(CLIENT_COUNT.charts.statTextValue('Entity clients'))
.includesText(`${formatNumber([topMount.entity_clients])}`, 'total entity clients is accurate'); .includesText(`${formatNumber([topMount.entity_clients])}`, 'total entity clients is accurate');
assert assert
.dom(SELECTORS.charts.statTextValue('Non-entity clients')) .dom(CLIENT_COUNT.charts.statTextValue('Non-entity clients'))
.includesText(`${formatNumber([topMount.non_entity_clients])}`, 'total non-entity clients is accurate'); .includesText(`${formatNumber([topMount.non_entity_clients])}`, 'total non-entity clients is accurate');
assert assert
.dom(SELECTORS.charts.statTextValue('Secrets sync clients')) .dom(CLIENT_COUNT.charts.statTextValue('Secrets sync clients'))
.includesText(`${formatNumber([topMount.secret_syncs])}`, 'total sync clients is accurate'); .includesText(`${formatNumber([topMount.secret_syncs])}`, 'total sync clients is accurate');
assert.dom(SELECTORS.attributionBlock).doesNotExist('Does not show attribution block'); assert.dom(CLIENT_COUNT.attributionBlock).doesNotExist('Does not show attribution block');
await click('#namespace-search-select [data-test-selected-list-button="delete"]'); await click('#namespace-search-select [data-test-selected-list-button="delete"]');
assert.ok(true, 'Remove namespace filter without first removing auth method filter'); assert.ok(true, 'Remove namespace filter without first removing auth method filter');
assert.dom('[data-test-top-attribution]').includesText('Top namespace'); assert.dom('[data-test-top-attribution]').includesText('Top namespace');
assert assert
.dom(SELECTORS.charts.statTextValue('Entity clients')) .dom(CLIENT_COUNT.charts.statTextValue('Entity clients'))
.hasTextContaining( .hasTextContaining(
`${formatNumber([response.total.entity_clients])}`, `${formatNumber([response.total.entity_clients])}`,
'total entity clients is back to unfiltered value' 'total entity clients is back to unfiltered value'
); );
assert assert
.dom(SELECTORS.charts.statTextValue('Non-entity clients')) .dom(CLIENT_COUNT.charts.statTextValue('Non-entity clients'))
.hasTextContaining( .hasTextContaining(
`${formatNumber([formatNumber([response.total.non_entity_clients])])}`, `${formatNumber([formatNumber([response.total.non_entity_clients])])}`,
'total non-entity clients is back to unfiltered value' 'total non-entity clients is back to unfiltered value'
); );
assert assert
.dom(SELECTORS.charts.statTextValue('Secrets sync clients')) .dom(CLIENT_COUNT.charts.statTextValue('Secrets sync clients'))
.hasTextContaining( .hasTextContaining(
`${formatNumber([formatNumber([response.total.secret_syncs])])}`, `${formatNumber([formatNumber([response.total.secret_syncs])])}`,
'total sync clients is back to unfiltered value' 'total sync clients is back to unfiltered value'
@ -270,19 +271,19 @@ module('Acceptance | clients | overview | sync in license, activated', function
}); });
test('it should render the correct tabs', async function (assert) { test('it should render the correct tabs', async function (assert) {
assert.dom(SELECTORS.tab('sync')).exists(); assert.dom(GENERAL.tab('sync')).exists();
}); });
test('it should show secrets sync data in overview and tab', async function (assert) { test('it should show secrets sync data in overview and tab', async function (assert) {
assert assert
.dom(SELECTORS.charts.statTextValue('Secrets sync clients')) .dom(CLIENT_COUNT.charts.statTextValue('Secrets sync clients'))
.exists('shows secret sync data on overview'); .exists('shows secret sync data on overview');
await click(SELECTORS.tab('sync')); await click(GENERAL.tab('sync'));
assert.dom(SELECTORS.tab('sync')).hasClass('active'); assert.dom(GENERAL.tab('sync')).hasClass('active');
assert.dom(SELECTORS.emptyStateTitle).doesNotExist(); assert.dom(GENERAL.emptyStateTitle).doesNotExist();
assert assert
.dom(SELECTORS.charts.chart('Secrets sync usage')) .dom(CLIENT_COUNT.charts.chart('Secrets sync usage'))
.exists('chart is shown because feature is active and has data'); .exists('chart is shown because feature is active and has data');
}); });
}); });
@ -300,12 +301,12 @@ module('Acceptance | clients | overview | sync in license, not activated', funct
}); });
test('it should show the secrets sync tab', async function (assert) { test('it should show the secrets sync tab', async function (assert) {
assert.dom(SELECTORS.tab('sync')).exists('sync tab is shown because feature is in license'); assert.dom(GENERAL.tab('sync')).exists('sync tab is shown because feature is in license');
}); });
test('it should hide secrets sync charts', async function (assert) { test('it should hide secrets sync charts', async function (assert) {
assert assert
.dom(SELECTORS.charts.chart('Secrets sync usage')) .dom(CLIENT_COUNT.charts.chart('Secrets sync usage'))
.doesNotExist('chart is hidden because feature is not activated'); .doesNotExist('chart is hidden because feature is not activated');
assert.dom('[data-test-stat-text="secret-syncs"]').doesNotExist(); assert.dom('[data-test-stat-text="secret-syncs"]').doesNotExist();
@ -326,11 +327,11 @@ module('Acceptance | clients | overview | sync not in license', function (hooks)
}); });
test('it should hide the secrets sync tab', async function (assert) { test('it should hide the secrets sync tab', async function (assert) {
assert.dom(SELECTORS.tab('sync')).doesNotExist(); assert.dom(GENERAL.tab('sync')).doesNotExist();
}); });
test('it should hide secrets sync charts', async function (assert) { test('it should hide secrets sync charts', async function (assert) {
assert.dom(SELECTORS.charts.chart('Secrets sync usage')).doesNotExist(); assert.dom(CLIENT_COUNT.charts.chart('Secrets sync usage')).doesNotExist();
assert.dom('[data-test-stat-text="secret-syncs"]').doesNotExist(); assert.dom('[data-test-stat-text="secret-syncs"]').doesNotExist();
}); });

View File

@ -12,7 +12,8 @@ import { visit, click, currentURL } from '@ember/test-helpers';
import sinon from 'sinon'; import sinon from 'sinon';
import timestamp from 'core/utils/timestamp'; import timestamp from 'core/utils/timestamp';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { SELECTORS } from 'vault/tests/helpers/clients'; import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { CLIENT_COUNT } from 'vault/tests/helpers/clients/client-count-selectors';
module('Acceptance | clients | sync | activated', function (hooks) { module('Acceptance | clients | sync | activated', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@ -35,9 +36,11 @@ module('Acceptance | clients | sync | activated', function (hooks) {
test('it should render charts when secrets sync is activated', async function (assert) { test('it should render charts when secrets sync is activated', async function (assert) {
syncHandler(this.server); syncHandler(this.server);
assert.dom(SELECTORS.charts.chart('Secrets sync usage')).exists('Secrets sync usage chart is rendered'); assert
assert.dom(SELECTORS.syncTab.total).exists('Total sync clients chart is rendered'); .dom(CLIENT_COUNT.charts.chart('Secrets sync usage'))
assert.dom(SELECTORS.emptyStateTitle).doesNotExist(); .exists('Secrets sync usage chart is rendered');
assert.dom(CLIENT_COUNT.syncTab.total).exists('Total sync clients chart is rendered');
assert.dom(GENERAL.emptyStateTitle).doesNotExist();
}); });
}); });
@ -84,9 +87,9 @@ module('Acceptance | clients | sync | not activated', function (hooks) {
}; };
}); });
assert.dom(SELECTORS.emptyStateTitle).exists('Shows empty state when secrets-sync is not activated'); assert.dom(GENERAL.emptyStateTitle).exists('Shows empty state when secrets-sync is not activated');
await click(`${SELECTORS.emptyStateActions} .hds-link-standalone`); await click(`${GENERAL.emptyStateActions} .hds-link-standalone`);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
'/vault/sync/secrets/overview', '/vault/sync/secrets/overview',

View File

@ -6,13 +6,14 @@
import { module, test } from 'qunit'; import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit'; import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support'; import { setupMirage } from 'ember-cli-mirage/test-support';
import { click, visit, fillIn, currentRouteName } from '@ember/test-helpers'; import { click, visit, fillIn, currentRouteName, currentURL } from '@ember/test-helpers';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import logout from 'vault/tests/pages/logout'; import logout from 'vault/tests/pages/logout';
import { format, addDays, startOfDay } from 'date-fns'; import { format, addDays, startOfDay } from 'date-fns';
import { datetimeLocalStringFormat } from 'core/utils/date-formatters'; import { datetimeLocalStringFormat } from 'core/utils/date-formatters';
import { PAGE } from 'vault/tests/helpers/config-ui/message-selectors'; import { CUSTOM_MESSAGES } from 'vault/tests/helpers/config-ui/message-selectors';
import { clickTrigger } from 'ember-power-select/test-support/helpers'; import { clickTrigger } from 'ember-power-select/test-support/helpers';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
module('Acceptance | Community | config-ui/messages', function (hooks) { module('Acceptance | Community | config-ui/messages', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@ -48,7 +49,7 @@ module('Acceptance | Community | config-ui/messages', function (hooks) {
test('it should hide the sidebar settings section on community', async function (assert) { test('it should hide the sidebar settings section on community', async function (assert) {
assert.expect(1); assert.expect(1);
assert.dom(PAGE.navLink).doesNotExist(); assert.dom(CUSTOM_MESSAGES.navLink).doesNotExist();
}); });
}); });
@ -57,40 +58,44 @@ module('Acceptance | Enterprise | config-ui/message', function (hooks) {
setupMirage(hooks); setupMirage(hooks);
hooks.beforeEach(async function () { hooks.beforeEach(async function () {
this.messageDetailId = () => {
return currentURL().match(/messages\/(.*)\/details/)[1];
};
this.createMessage = async (messageType = 'banner', endTime = '2023-12-12', authenticated = true) => { this.createMessage = async (messageType = 'banner', endTime = '2023-12-12', authenticated = true) => {
await click(PAGE.navLink); await click(CUSTOM_MESSAGES.navLink);
if (authenticated) { if (authenticated) {
await click(PAGE.tab('After user logs in')); await click(CUSTOM_MESSAGES.tab('After user logs in'));
await click(PAGE.button('create message'));
} else { } else {
await click(PAGE.tab('On login page')); await click(CUSTOM_MESSAGES.tab('On login page'));
await click(PAGE.button('create message'));
} }
await click(CUSTOM_MESSAGES.button('create message'));
await visit(`vault/config-ui/messages?authenticated=${authenticated}`); await fillIn(CUSTOM_MESSAGES.input('title'), 'Awesome custom message title');
await click(PAGE.button('create message')); await click(CUSTOM_MESSAGES.radio(messageType));
await fillIn(PAGE.input('title'), 'Awesome custom message title');
await click(PAGE.radio(messageType));
await fillIn( await fillIn(
PAGE.input('message'), CUSTOM_MESSAGES.input('message'),
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.' 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.'
); );
await fillIn( await fillIn(
PAGE.input('startTime'), CUSTOM_MESSAGES.input('startTime'),
format(addDays(startOfDay(new Date('2023-12-12')), 1), datetimeLocalStringFormat) format(addDays(startOfDay(new Date('2023-12-12')), 1), datetimeLocalStringFormat)
); );
if (endTime) { if (endTime) {
await click('#specificDate'); await click('#specificDate');
await fillIn( await fillIn(
PAGE.input('endTime'), CUSTOM_MESSAGES.input('endTime'),
format(addDays(startOfDay(new Date('2023-12-12')), 10), datetimeLocalStringFormat) format(addDays(startOfDay(new Date('2023-12-12')), 10), datetimeLocalStringFormat)
); );
} }
await fillIn('[data-test-kv-key="0"]', 'Learn more'); await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com'); await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('create-message')); await click(CUSTOM_MESSAGES.button('create-message'));
};
this.deleteMessage = async (id) => {
await visit(`vault/config-ui/messages/${id}/details`);
await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(GENERAL.confirmButton);
}; };
this.server.get('/sys/health', function () { this.server.get('/sys/health', function () {
return { return {
@ -120,25 +125,25 @@ module('Acceptance | Enterprise | config-ui/message', function (hooks) {
}); });
test('it should show an empty state when no messages are created', async function (assert) { test('it should show an empty state when no messages are created', async function (assert) {
assert.expect(4); assert.expect(4);
await click(PAGE.navLink); await click(CUSTOM_MESSAGES.navLink);
assert.dom('[data-test-component="empty-state"]').exists(); assert.dom('[data-test-component="empty-state"]').exists();
assert.dom(PAGE.emptyStateTitle).hasText('No messages yet'); assert.dom(GENERAL.emptyStateTitle).hasText('No messages yet');
await click(PAGE.tab('On login page')); await click(CUSTOM_MESSAGES.tab('On login page'));
assert.dom('[data-test-component="empty-state"]').exists(); assert.dom('[data-test-component="empty-state"]').exists();
assert.dom(PAGE.emptyStateTitle).hasText('No messages yet'); assert.dom(GENERAL.emptyStateTitle).hasText('No messages yet');
}); });
module('Authenticated messages', function () { module('Authenticated messages', function () {
test('it should create, edit, view, and delete a message', async function (assert) { test('it should create, edit, view, and delete a message', async function (assert) {
assert.expect(3); assert.expect(3);
await this.createMessage(); await this.createMessage();
assert.dom(PAGE.title).hasText('Awesome custom message title', 'on the details screen'); assert.dom(GENERAL.title).hasText('Awesome custom message title', 'on the details screen');
await click('[data-test-link="edit"]'); await click('[data-test-link="edit"]');
await fillIn(PAGE.input('title'), 'Edited custom message title'); await fillIn(CUSTOM_MESSAGES.input('title'), 'Edited custom message title');
await click(PAGE.button('create-message')); await click(CUSTOM_MESSAGES.button('create-message'));
assert.dom(PAGE.title).hasText('Edited custom message title'); assert.dom(GENERAL.title).hasText('Edited custom message title');
await click(PAGE.confirmActionButton('Delete message')); await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(PAGE.confirmButton); await click(GENERAL.confirmButton);
assert.strictEqual( assert.strictEqual(
currentRouteName(), currentRouteName(),
'vault.cluster.config-ui.messages.index', 'vault.cluster.config-ui.messages.index',
@ -149,23 +154,24 @@ module('Acceptance | Enterprise | config-ui/message', function (hooks) {
test('it should show multiple messages modal', async function (assert) { test('it should show multiple messages modal', async function (assert) {
assert.expect(4); assert.expect(4);
await this.createMessage('modal', null); await this.createMessage('modal', null);
assert.dom(PAGE.title).hasText('Awesome custom message title'); assert.dom(GENERAL.title).hasText('Awesome custom message title');
await this.createMessage('modal', null); await this.createMessage('modal', null);
assert.dom(PAGE.modal('multiple modal messages')).exists(); assert.dom(CUSTOM_MESSAGES.modal('multiple modal messages')).exists();
assert assert
.dom(PAGE.modalTitle('Warning: more than one modal')) .dom(CUSTOM_MESSAGES.modalTitle('Warning: more than one modal'))
.hasText('Warning: more than one modal after the user logs in'); .hasText('Warning: more than one modal after the user logs in');
await click(PAGE.modalButton('cancel')); await click(CUSTOM_MESSAGES.modalButton('cancel'));
await visit('vault/config-ui/messages'); await visit('vault/config-ui/messages');
await click(PAGE.listItem('Awesome custom message title')); await click(CUSTOM_MESSAGES.listItem('Awesome custom message title'));
await click(PAGE.confirmActionButton('Delete message')); await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(PAGE.confirmButton); await click(GENERAL.confirmButton);
assert.dom('[data-test-component="empty-state"]').exists('Message was deleted'); assert.dom('[data-test-component="empty-state"]').exists('Message was deleted');
}); });
test('it should filter by type and status', async function (assert) { test('it should filter by type and status', async function (assert) {
assert.expect(6);
await this.createMessage('banner', null); await this.createMessage('banner', null);
const msg1 = this.messageDetailId();
await this.createMessage('banner'); await this.createMessage('banner');
const msg2 = this.messageDetailId();
await visit('vault/config-ui/messages'); await visit('vault/config-ui/messages');
// check number of messages with status filters // check number of messages with status filters
@ -192,49 +198,44 @@ module('Acceptance | Enterprise | config-ui/message', function (hooks) {
assert.dom('.linked-block').exists({ count: 2 }, 'no filters selected'); assert.dom('.linked-block').exists({ count: 2 }, 'no filters selected');
// clean up custom messages // clean up custom messages
await click(PAGE.listItem('Awesome custom message title')); await this.deleteMessage(msg1);
await click(PAGE.confirmActionButton('Delete message')); await this.deleteMessage(msg2);
await click(PAGE.confirmButton);
await click(PAGE.listItem('Awesome custom message title'));
await click(PAGE.confirmActionButton('Delete message'));
await click(PAGE.confirmButton);
assert.dom('[data-test-component="empty-state"]').exists('Message was deleted');
}); });
test('it should display preview a message when all required fields are filled out', async function (assert) { test('it should display preview a message when all required fields are filled out', async function (assert) {
assert.expect(2); assert.expect(2);
await click(PAGE.navLink); await click(CUSTOM_MESSAGES.navLink);
await click(PAGE.tab('After user logs in')); await click(CUSTOM_MESSAGES.tab('After user logs in'));
await click(PAGE.button('create message')); await click(CUSTOM_MESSAGES.button('create message'));
await fillIn(PAGE.input('title'), 'Awesome custom message title'); await fillIn(CUSTOM_MESSAGES.input('title'), 'Awesome custom message title');
await click(PAGE.radio('banner')); await click(CUSTOM_MESSAGES.radio('banner'));
await fillIn( await fillIn(
PAGE.input('message'), CUSTOM_MESSAGES.input('message'),
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.' 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.'
); );
await fillIn('[data-test-kv-key="0"]', 'Learn more'); await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com'); await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('preview')); await click(CUSTOM_MESSAGES.button('preview'));
assert.dom(PAGE.modal('preview image')).exists(); assert.dom(CUSTOM_MESSAGES.modal('preview image')).exists();
await click(PAGE.modalButton('Close')); await click(CUSTOM_MESSAGES.modalButton('Close'));
await click(PAGE.radio('modal')); await click(CUSTOM_MESSAGES.radio('modal'));
await click(PAGE.button('preview')); await click(CUSTOM_MESSAGES.button('preview'));
assert.dom(PAGE.modal('preview modal')).exists(); assert.dom(CUSTOM_MESSAGES.modal('preview modal')).exists();
}); });
test('it should not display preview a message when all required fields are not filled out', async function (assert) { test('it should not display preview a message when all required fields are not filled out', async function (assert) {
assert.expect(2); assert.expect(2);
await click(PAGE.navLink); await click(CUSTOM_MESSAGES.navLink);
await click(PAGE.tab('After user logs in')); await click(CUSTOM_MESSAGES.tab('After user logs in'));
await click(PAGE.button('create message')); await click(CUSTOM_MESSAGES.button('create message'));
await click(PAGE.radio('banner')); await click(CUSTOM_MESSAGES.radio('banner'));
await fillIn( await fillIn(
PAGE.input('message'), CUSTOM_MESSAGES.input('message'),
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.' 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.'
); );
await fillIn('[data-test-kv-key="0"]', 'Learn more'); await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com'); await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('preview')); await click(CUSTOM_MESSAGES.button('preview'));
assert.dom(PAGE.modal('preview image')).doesNotExist(); assert.dom(CUSTOM_MESSAGES.modal('preview image')).doesNotExist();
assert.dom(PAGE.input('title')).hasClass('has-error-border'); assert.dom(CUSTOM_MESSAGES.input('title')).hasClass('has-error-border');
}); });
}); });
@ -242,13 +243,13 @@ module('Acceptance | Enterprise | config-ui/message', function (hooks) {
test('it should create, edit, view, and delete a message', async function (assert) { test('it should create, edit, view, and delete a message', async function (assert) {
assert.expect(3); assert.expect(3);
await this.createMessage('banner', null, false); await this.createMessage('banner', null, false);
assert.dom(PAGE.title).hasText('Awesome custom message title', 'on the details screen'); assert.dom(GENERAL.title).hasText('Awesome custom message title', 'on the details screen');
await click('[data-test-link="edit"]'); await click('[data-test-link="edit"]');
await fillIn(PAGE.input('title'), 'Edited custom message title'); await fillIn(CUSTOM_MESSAGES.input('title'), 'Edited custom message title');
await click(PAGE.button('create-message')); await click(CUSTOM_MESSAGES.button('create-message'));
assert.dom(PAGE.title).hasText('Edited custom message title'); assert.dom(GENERAL.title).hasText('Edited custom message title');
await click(PAGE.confirmActionButton('Delete message')); await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(PAGE.confirmButton); await click(GENERAL.confirmButton);
assert.strictEqual( assert.strictEqual(
currentRouteName(), currentRouteName(),
'vault.cluster.config-ui.messages.index', 'vault.cluster.config-ui.messages.index',
@ -258,65 +259,65 @@ module('Acceptance | Enterprise | config-ui/message', function (hooks) {
test('it should show multiple messages modal', async function (assert) { test('it should show multiple messages modal', async function (assert) {
assert.expect(4); assert.expect(4);
await this.createMessage('modal', null, false); await this.createMessage('modal', null, false);
assert.dom(PAGE.title).hasText('Awesome custom message title'); assert.dom(GENERAL.title).hasText('Awesome custom message title');
await this.createMessage('modal', null, false); await this.createMessage('modal', null, false);
assert.dom(PAGE.modal('multiple modal messages')).exists(); assert.dom(CUSTOM_MESSAGES.modal('multiple modal messages')).exists();
assert assert
.dom(PAGE.modalTitle('Warning: more than one modal')) .dom(CUSTOM_MESSAGES.modalTitle('Warning: more than one modal'))
.hasText('Warning: more than one modal on the login page'); .hasText('Warning: more than one modal on the login page');
await click(PAGE.modalButton('cancel')); await click(CUSTOM_MESSAGES.modalButton('cancel'));
await visit('vault/config-ui/messages?authenticated=false'); await visit('vault/config-ui/messages?authenticated=false');
await click(PAGE.listItem('Awesome custom message title')); await click(CUSTOM_MESSAGES.listItem('Awesome custom message title'));
await click(PAGE.confirmActionButton('Delete message')); await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(PAGE.confirmButton); await click(GENERAL.confirmButton);
assert.dom('[data-test-component="empty-state"]').exists('Message was deleted'); assert.dom('[data-test-component="empty-state"]').exists('Message was deleted');
}); });
test('it should show info message on create and edit form', async function (assert) { test('it should show info message on create and edit form', async function (assert) {
assert.expect(1); assert.expect(1);
await click(PAGE.navLink); await click(CUSTOM_MESSAGES.navLink);
await click(PAGE.tab('On login page')); await click(CUSTOM_MESSAGES.tab('On login page'));
await click(PAGE.button('create message')); await click(CUSTOM_MESSAGES.button('create message'));
assert assert
.dom(PAGE.unauthCreateFormInfo) .dom(CUSTOM_MESSAGES.unauthCreateFormInfo)
.hasText( .hasText(
'Note: Do not include sensitive information in this message since users are unauthenticated at this stage.' 'Note: Do not include sensitive information in this message since users are unauthenticated at this stage.'
); );
}); });
test('it should display preview a message when all required fields are filled out', async function (assert) { test('it should display preview a message when all required fields are filled out', async function (assert) {
assert.expect(2); assert.expect(2);
await click(PAGE.navLink); await click(CUSTOM_MESSAGES.navLink);
await click(PAGE.tab('On login page')); await click(CUSTOM_MESSAGES.tab('On login page'));
await click(PAGE.button('create message')); await click(CUSTOM_MESSAGES.button('create message'));
await fillIn(PAGE.input('title'), 'Awesome custom message title'); await fillIn(CUSTOM_MESSAGES.input('title'), 'Awesome custom message title');
await click(PAGE.radio('banner')); await click(CUSTOM_MESSAGES.radio('banner'));
await fillIn( await fillIn(
PAGE.input('message'), CUSTOM_MESSAGES.input('message'),
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.' 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.'
); );
await fillIn('[data-test-kv-key="0"]', 'Learn more'); await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com'); await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('preview')); await click(CUSTOM_MESSAGES.button('preview'));
assert.dom(PAGE.modal('preview image')).exists(); assert.dom(CUSTOM_MESSAGES.modal('preview image')).exists();
await click(PAGE.modalButton('Close')); await click(CUSTOM_MESSAGES.modalButton('Close'));
await click(PAGE.radio('modal')); await click(CUSTOM_MESSAGES.radio('modal'));
await click(PAGE.button('preview')); await click(CUSTOM_MESSAGES.button('preview'));
assert.dom(PAGE.modal('preview modal')).exists(); assert.dom(CUSTOM_MESSAGES.modal('preview modal')).exists();
}); });
test('it should not display preview a message when all required fields are not filled out', async function (assert) { test('it should not display preview a message when all required fields are not filled out', async function (assert) {
assert.expect(2); assert.expect(2);
await click(PAGE.navLink); await click(CUSTOM_MESSAGES.navLink);
await click(PAGE.tab('On login page')); await click(CUSTOM_MESSAGES.tab('On login page'));
await click(PAGE.button('create message')); await click(CUSTOM_MESSAGES.button('create message'));
await click(PAGE.radio('banner')); await click(CUSTOM_MESSAGES.radio('banner'));
await fillIn( await fillIn(
PAGE.input('message'), CUSTOM_MESSAGES.input('message'),
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.' 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.'
); );
await fillIn('[data-test-kv-key="0"]', 'Learn more'); await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com'); await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('preview')); await click(CUSTOM_MESSAGES.button('preview'));
assert.dom(PAGE.modal('preview image')).doesNotExist(); assert.dom(CUSTOM_MESSAGES.modal('preview image')).doesNotExist();
assert.dom(PAGE.input('title')).hasClass('has-error-border'); assert.dom(CUSTOM_MESSAGES.input('title')).hasClass('has-error-border');
}); });
}); });
}); });

View File

@ -6,7 +6,8 @@
import { module, test } from 'qunit'; import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit'; import { setupApplicationTest } from 'ember-qunit';
import { click, visit, fillIn, currentRouteName } from '@ember/test-helpers'; import { click, visit, fillIn, currentRouteName } from '@ember/test-helpers';
import { PAGE } from 'vault/tests/helpers/config-ui/message-selectors'; import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { CUSTOM_MESSAGES } from 'vault/tests/helpers/config-ui/message-selectors';
import { setupMirage } from 'ember-cli-mirage/test-support'; import { setupMirage } from 'ember-cli-mirage/test-support';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
@ -68,14 +69,14 @@ module('Acceptance | auth custom messages auth tests', function (hooks) {
await visit('/vault/auth'); await visit('/vault/auth');
const modalId = 'some-awesome-id-1'; const modalId = 'some-awesome-id-1';
const alertId = 'some-awesome-id-2'; const alertId = 'some-awesome-id-2';
assert.dom(PAGE.modal(modalId)).exists(); assert.dom(CUSTOM_MESSAGES.modal(modalId)).exists();
assert.dom(PAGE.modalTitle(modalId)).hasText('Modal title'); assert.dom(CUSTOM_MESSAGES.modalTitle(modalId)).hasText('Modal title');
assert.dom(PAGE.modalBody(modalId)).exists(); assert.dom(CUSTOM_MESSAGES.modalBody(modalId)).exists();
assert.dom(PAGE.modalBody(modalId)).hasText('here is a cool message'); assert.dom(CUSTOM_MESSAGES.modalBody(modalId)).hasText('here is a cool message');
await click(PAGE.modalButton(modalId)); await click(CUSTOM_MESSAGES.modalButton(modalId));
assert.dom(PAGE.alertTitle(alertId)).hasText('Banner title'); assert.dom(CUSTOM_MESSAGES.alertTitle(alertId)).hasText('Banner title');
assert.dom(PAGE.alertDescription(alertId)).hasText('hello world hello wolrd'); assert.dom(CUSTOM_MESSAGES.alertDescription(alertId)).hasText('hello world hello wolrd');
assert.dom(PAGE.alertAction('link')).hasText('some alert link'); assert.dom(CUSTOM_MESSAGES.alertAction('link')).hasText('some alert link');
}); });
test('it shows the multiple modal messages', async function (assert) { test('it shows the multiple modal messages', async function (assert) {
const modalIdOne = 'some-awesome-id-2'; const modalIdOne = 'some-awesome-id-2';
@ -89,16 +90,16 @@ module('Acceptance | auth custom messages auth tests', function (hooks) {
return unauthenticatedMessageResponse; return unauthenticatedMessageResponse;
}); });
await visit('/vault/auth'); await visit('/vault/auth');
assert.dom(PAGE.modal(modalIdOne)).exists(); assert.dom(CUSTOM_MESSAGES.modal(modalIdOne)).exists();
assert.dom(PAGE.modalTitle(modalIdOne)).hasText('Modal title 1'); assert.dom(CUSTOM_MESSAGES.modalTitle(modalIdOne)).hasText('Modal title 1');
assert.dom(PAGE.modalBody(modalIdOne)).exists(); assert.dom(CUSTOM_MESSAGES.modalBody(modalIdOne)).exists();
assert.dom(PAGE.modalBody(modalIdOne)).hasText('hello world hello wolrd some alert link'); assert.dom(CUSTOM_MESSAGES.modalBody(modalIdOne)).hasText('hello world hello wolrd some alert link');
await click(PAGE.modalButton(modalIdOne)); await click(CUSTOM_MESSAGES.modalButton(modalIdOne));
assert.dom(PAGE.modal(modalIdTwo)).exists(); assert.dom(CUSTOM_MESSAGES.modal(modalIdTwo)).exists();
assert.dom(PAGE.modalTitle(modalIdTwo)).hasText('Modal title 2'); assert.dom(CUSTOM_MESSAGES.modalTitle(modalIdTwo)).hasText('Modal title 2');
assert.dom(PAGE.modalBody(modalIdTwo)).exists(); assert.dom(CUSTOM_MESSAGES.modalBody(modalIdTwo)).exists();
assert.dom(PAGE.modalBody(modalIdTwo)).hasText('here is a cool message'); assert.dom(CUSTOM_MESSAGES.modalBody(modalIdTwo)).hasText('here is a cool message');
await click(PAGE.modalButton(modalIdTwo)); await click(CUSTOM_MESSAGES.modalButton(modalIdTwo));
}); });
test('it shows the multiple banner messages', async function (assert) { test('it shows the multiple banner messages', async function (assert) {
const bannerIdOne = 'some-awesome-id-2'; const bannerIdOne = 'some-awesome-id-2';
@ -112,11 +113,11 @@ module('Acceptance | auth custom messages auth tests', function (hooks) {
return unauthenticatedMessageResponse; return unauthenticatedMessageResponse;
}); });
await visit('/vault/auth'); await visit('/vault/auth');
assert.dom(PAGE.alertTitle(bannerIdOne)).hasText('Banner title 1'); assert.dom(CUSTOM_MESSAGES.alertTitle(bannerIdOne)).hasText('Banner title 1');
assert.dom(PAGE.alertDescription(bannerIdOne)).hasText('hello world hello wolrd'); assert.dom(CUSTOM_MESSAGES.alertDescription(bannerIdOne)).hasText('hello world hello wolrd');
assert.dom(PAGE.alertTitle(bannerIdTwo)).hasText('Banner title 2'); assert.dom(CUSTOM_MESSAGES.alertTitle(bannerIdTwo)).hasText('Banner title 2');
assert.dom(PAGE.alertDescription(bannerIdTwo)).hasText('here is a cool message'); assert.dom(CUSTOM_MESSAGES.alertDescription(bannerIdTwo)).hasText('here is a cool message');
assert.dom(PAGE.alertAction('link')).hasText('some alert link'); assert.dom(CUSTOM_MESSAGES.alertAction('link')).hasText('some alert link');
}); });
}); });
@ -124,29 +125,29 @@ module('Acceptance | auth custom messages auth tests', function (hooks) {
assert.expect(4); assert.expect(4);
await authPage.login(); await authPage.login();
await visit('vault/config-ui/messages'); await visit('vault/config-ui/messages');
await click(PAGE.button('create message')); await click(CUSTOM_MESSAGES.button('create message'));
await fillIn(PAGE.input('title'), 'Awesome custom message title'); await fillIn(CUSTOM_MESSAGES.input('title'), 'Awesome custom message title');
await click(PAGE.radio('banner')); await click(CUSTOM_MESSAGES.radio('banner'));
await fillIn( await fillIn(
PAGE.input('message'), CUSTOM_MESSAGES.input('message'),
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.' 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Pulvinar mattis nunc sed blandit libero volutpat sed cras ornare.'
); );
await fillIn( await fillIn(
PAGE.input('startTime'), CUSTOM_MESSAGES.input('startTime'),
format(addDays(startOfDay(new Date('2023-12-12')), 1), datetimeLocalStringFormat) format(addDays(startOfDay(new Date('2023-12-12')), 1), datetimeLocalStringFormat)
); );
await fillIn('[data-test-kv-key="0"]', 'Learn more'); await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com'); await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('create-message')); await click(CUSTOM_MESSAGES.button('create-message'));
assert.dom(PAGE.title).hasText('Awesome custom message title', 'on the details screen'); assert.dom(GENERAL.title).hasText('Awesome custom message title', 'on the details screen');
assert.dom('.hds-alert').exists('active custom message displays on authenticated.'); assert.dom('.hds-alert').exists('active custom message displays on authenticated.');
await runCmd(createNS('world'), false); await runCmd(createNS('world'), false);
await visit('vault/config-ui/messages'); await visit('vault/config-ui/messages');
assert.dom('.hds-alert').exists('active custom message displays on namespace authenticated.'); assert.dom('.hds-alert').exists('active custom message displays on namespace authenticated.');
await click(PAGE.listItem('Awesome custom message title')); await click(CUSTOM_MESSAGES.listItem('Awesome custom message title'));
await click(PAGE.confirmActionButton('Delete message')); await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(PAGE.confirmButton); await click(GENERAL.confirmButton);
assert.strictEqual( assert.strictEqual(
currentRouteName(), currentRouteName(),
'vault.cluster.config-ui.messages.index', 'vault.cluster.config-ui.messages.index',

View File

@ -27,8 +27,8 @@ import connectionPage from 'vault/tests/pages/secrets/backend/database/connectio
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { runCmd, deleteEngineCmd, createNS } from 'vault/tests/helpers/commands'; import { runCmd, deleteEngineCmd, createNS } from 'vault/tests/helpers/commands';
import { SELECTORS } from 'vault/tests/helpers/components/dashboard/dashboard-selectors'; import { DASHBOARD } from 'vault/tests/helpers/components/dashboard/dashboard-selectors';
import { PAGE } from 'vault/tests/helpers/config-ui/message-selectors'; import { CUSTOM_MESSAGES } from 'vault/tests/helpers/config-ui/message-selectors';
const authenticatedMessageResponse = { const authenticatedMessageResponse = {
request_id: '664fbad0-fcd8-9023-4c5b-81a7962e9f4b', request_id: '664fbad0-fcd8-9023-4c5b-81a7962e9f4b',
@ -87,7 +87,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
? `Vault ${version.versionDisplay} root` ? `Vault ${version.versionDisplay} root`
: `Vault ${version.versionDisplay}`; : `Vault ${version.versionDisplay}`;
assert.dom(SELECTORS.cardHeader('Vault version')).hasText(versionText); assert.dom(DASHBOARD.cardHeader('Vault version')).hasText(versionText);
}); });
module('secrets engines card', function (hooks) { module('secrets engines card', function (hooks) {
@ -100,7 +100,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
await mountSecrets.enable('pki', 'pki'); await mountSecrets.enable('pki', 'pki');
await settled(); await settled();
await visit('/vault/dashboard'); await visit('/vault/dashboard');
assert.dom(SELECTORS.cardHeader('Secrets engines')).hasText('Secrets engines'); assert.dom(DASHBOARD.cardHeader('Secrets engines')).hasText('Secrets engines');
// cleanup engine mount // cleanup engine mount
await runCmd(deleteEngineCmd('pki')); await runCmd(deleteEngineCmd('pki'));
}); });
@ -221,26 +221,26 @@ module('Acceptance | landing page dashboard', function (hooks) {
await visit('/vault/dashboard'); await visit('/vault/dashboard');
const version = this.owner.lookup('service:version'); const version = this.owner.lookup('service:version');
assert.true(version.isEnterprise, 'vault is enterprise'); assert.true(version.isEnterprise, 'vault is enterprise');
assert.dom(SELECTORS.cardName('configuration-details')).exists(); assert.dom(DASHBOARD.cardName('configuration-details')).exists();
await runCmd(createNS('world'), false); await runCmd(createNS('world'), false);
await visit('/vault/dashboard?namespace=world'); await visit('/vault/dashboard?namespace=world');
assert.dom(SELECTORS.cardName('configuration-details')).doesNotExist(); assert.dom(DASHBOARD.cardName('configuration-details')).doesNotExist();
}); });
test('shows the configuration details card', async function (assert) { test('shows the configuration details card', async function (assert) {
assert.expect(8); assert.expect(8);
await authPage.login(); await authPage.login();
await visit('/vault/dashboard'); await visit('/vault/dashboard');
assert.dom(SELECTORS.cardHeader('configuration')).hasText('Configuration details'); assert.dom(DASHBOARD.cardHeader('configuration')).hasText('Configuration details');
assert assert
.dom(SELECTORS.vaultConfigurationCard.configDetailsField('api_addr')) .dom(DASHBOARD.vaultConfigurationCard.configDetailsField('api_addr'))
.hasText('http://127.0.0.1:8200'); .hasText('http://127.0.0.1:8200');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('default_lease_ttl')).hasText('0'); assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('default_lease_ttl')).hasText('0');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('max_lease_ttl')).hasText('2 days'); assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('max_lease_ttl')).hasText('2 days');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('tls')).hasText('Disabled'); // tls_disable=true assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('tls')).hasText('Disabled'); // tls_disable=true
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('log_format')).hasText('None'); assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('log_format')).hasText('None');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('log_level')).hasText('debug'); assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('log_level')).hasText('debug');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('type')).hasText('raft'); assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('type')).hasText('raft');
}); });
test('it should show tls as enabled if tls_disable, tls_cert_file and tls_key_file are in the config', async function (assert) { test('it should show tls as enabled if tls_disable, tls_cert_file and tls_key_file are in the config', async function (assert) {
@ -251,7 +251,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
await authPage.login(); await authPage.login();
await visit('/vault/dashboard'); await visit('/vault/dashboard');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('tls')).hasText('Enabled'); assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('tls')).hasText('Enabled');
}); });
test('it should show tls as enabled if only cert and key exist in config', async function (assert) { test('it should show tls as enabled if only cert and key exist in config', async function (assert) {
@ -261,7 +261,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
this.data.listeners[0].config.tls_key_file = './key.pem'; this.data.listeners[0].config.tls_key_file = './key.pem';
await authPage.login(); await authPage.login();
await visit('/vault/dashboard'); await visit('/vault/dashboard');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('tls')).hasText('Enabled'); assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('tls')).hasText('Enabled');
}); });
test('it should show tls as disabled if there is no tls information in the config', async function (assert) { test('it should show tls as disabled if there is no tls information in the config', async function (assert) {
@ -269,7 +269,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
this.data.listeners = []; this.data.listeners = [];
await authPage.login(); await authPage.login();
await visit('/vault/dashboard'); await visit('/vault/dashboard');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('tls')).hasText('Disabled'); assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('tls')).hasText('Disabled');
}); });
}); });
@ -280,7 +280,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
test('shows the default state of the quick actions card', async function (assert) { test('shows the default state of the quick actions card', async function (assert) {
assert.expect(1); assert.expect(1);
assert.dom(SELECTORS.emptyState('no-mount-selected')).exists(); assert.dom(DASHBOARD.emptyState('no-mount-selected')).exists();
}); });
test('shows the correct actions and links associated with pki', async function (assert) { test('shows the correct actions and links associated with pki', async function (assert) {
@ -297,25 +297,25 @@ module('Acceptance | landing page dashboard', function (hooks) {
await runCmd([`write ${backend}/root/generate/internal issuer_name="Hashicorp" common_name="Hello"`]); await runCmd([`write ${backend}/root/generate/internal issuer_name="Hashicorp" common_name="Hello"`]);
await settled(); await settled();
await visit('/vault/dashboard'); await visit('/vault/dashboard');
await selectChoose(SELECTORS.searchSelect('secrets-engines'), backend); await selectChoose(DASHBOARD.searchSelect('secrets-engines'), backend);
await fillIn(SELECTORS.selectEl, 'Issue certificate'); await fillIn(DASHBOARD.selectEl, 'Issue certificate');
assert.dom(SELECTORS.emptyState('quick-actions')).doesNotExist(); assert.dom(DASHBOARD.emptyState('quick-actions')).doesNotExist();
assert.dom(SELECTORS.subtitle('param')).hasText('Role to use'); assert.dom(DASHBOARD.subtitle('param')).hasText('Role to use');
await selectChoose(SELECTORS.searchSelect('params'), 'some-role'); await selectChoose(DASHBOARD.searchSelect('params'), 'some-role');
assert.dom(SELECTORS.actionButton('Issue leaf certificate')).exists({ count: 1 }); assert.dom(DASHBOARD.actionButton('Issue leaf certificate')).exists({ count: 1 });
await click(SELECTORS.actionButton('Issue leaf certificate')); await click(DASHBOARD.actionButton('Issue leaf certificate'));
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.roles.role.generate'); assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.roles.role.generate');
await visit('/vault/dashboard'); await visit('/vault/dashboard');
await selectChoose(SELECTORS.searchSelect('secrets-engines'), backend); await selectChoose(DASHBOARD.searchSelect('secrets-engines'), backend);
await fillIn(SELECTORS.selectEl, 'View certificate'); await fillIn(DASHBOARD.selectEl, 'View certificate');
assert.dom(SELECTORS.emptyState('quick-actions')).doesNotExist(); assert.dom(DASHBOARD.emptyState('quick-actions')).doesNotExist();
assert.dom(SELECTORS.subtitle('param')).hasText('Certificate serial number'); assert.dom(DASHBOARD.subtitle('param')).hasText('Certificate serial number');
assert.dom(SELECTORS.actionButton('View certificate')).exists({ count: 1 }); assert.dom(DASHBOARD.actionButton('View certificate')).exists({ count: 1 });
await selectChoose(SELECTORS.searchSelect('params'), '.ember-power-select-option', 0); await selectChoose(DASHBOARD.searchSelect('params'), '.ember-power-select-option', 0);
await click(SELECTORS.actionButton('View certificate')); await click(DASHBOARD.actionButton('View certificate'));
assert.strictEqual( assert.strictEqual(
currentRouteName(), currentRouteName(),
'vault.cluster.secrets.backend.pki.certificates.certificate.details' 'vault.cluster.secrets.backend.pki.certificates.certificate.details'
@ -323,13 +323,13 @@ module('Acceptance | landing page dashboard', function (hooks) {
await visit('/vault/dashboard'); await visit('/vault/dashboard');
await selectChoose(SELECTORS.searchSelect('secrets-engines'), backend); await selectChoose(DASHBOARD.searchSelect('secrets-engines'), backend);
await fillIn(SELECTORS.selectEl, 'View issuer'); await fillIn(DASHBOARD.selectEl, 'View issuer');
assert.dom(SELECTORS.emptyState('quick-actions')).doesNotExist(); assert.dom(DASHBOARD.emptyState('quick-actions')).doesNotExist();
assert.dom(SELECTORS.subtitle('param')).hasText('Issuer'); assert.dom(DASHBOARD.subtitle('param')).hasText('Issuer');
assert.dom(SELECTORS.actionButton('View issuer')).exists({ count: 1 }); assert.dom(DASHBOARD.actionButton('View issuer')).exists({ count: 1 });
await selectChoose(SELECTORS.searchSelect('params'), '.ember-power-select-option', 0); await selectChoose(DASHBOARD.searchSelect('params'), '.ember-power-select-option', 0);
await click(SELECTORS.actionButton('View issuer')); await click(DASHBOARD.actionButton('View issuer'));
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.issuers.issuer.details'); assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.issuers.issuer.details');
// cleanup engine mount // cleanup engine mount
@ -362,13 +362,13 @@ module('Acceptance | landing page dashboard', function (hooks) {
]); ]);
await settled(); await settled();
await visit('/vault/dashboard'); await visit('/vault/dashboard');
await selectChoose(SELECTORS.searchSelect('secrets-engines'), databaseBackend); await selectChoose(DASHBOARD.searchSelect('secrets-engines'), databaseBackend);
await fillIn(SELECTORS.selectEl, 'Generate credentials for database'); await fillIn(DASHBOARD.selectEl, 'Generate credentials for database');
assert.dom(SELECTORS.emptyState('quick-actions')).doesNotExist(); assert.dom(DASHBOARD.emptyState('quick-actions')).doesNotExist();
assert.dom(SELECTORS.subtitle('param')).hasText('Role to use'); assert.dom(DASHBOARD.subtitle('param')).hasText('Role to use');
assert.dom(SELECTORS.actionButton('Generate credentials')).exists({ count: 1 }); assert.dom(DASHBOARD.actionButton('Generate credentials')).exists({ count: 1 });
await selectChoose(SELECTORS.searchSelect('params'), '.ember-power-select-option', 0); await selectChoose(DASHBOARD.searchSelect('params'), '.ember-power-select-option', 0);
await click(SELECTORS.actionButton('Generate credentials')); await click(DASHBOARD.actionButton('Generate credentials'));
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.credentials'); assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.credentials');
await runCmd(deleteEngineCmd(databaseBackend)); await runCmd(deleteEngineCmd(databaseBackend));
}); });
@ -401,7 +401,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
const version = this.owner.lookup('service:version'); const version = this.owner.lookup('service:version');
assert.true(version.isEnterprise, 'version is enterprise'); assert.true(version.isEnterprise, 'version is enterprise');
assert.strictEqual(currentURL(), '/vault/dashboard'); assert.strictEqual(currentURL(), '/vault/dashboard');
assert.dom(SELECTORS.cardName('client-count')).exists(); assert.dom(DASHBOARD.cardName('client-count')).exists();
const response = await this.store.peekRecord('clients/activity', 'some-activity-id'); const response = await this.store.peekRecord('clients/activity', 'some-activity-id');
assert.dom('[data-test-client-count-title]').hasText('Client count'); assert.dom('[data-test-client-count-title]').hasText('Client count');
assert.dom('[data-test-stat-text="total-clients"] .stat-label').hasText('Total'); assert.dom('[data-test-stat-text="total-clients"] .stat-label').hasText('Total');
@ -433,12 +433,12 @@ module('Acceptance | landing page dashboard', function (hooks) {
await visit('/vault/dashboard'); await visit('/vault/dashboard');
const version = this.owner.lookup('service:version'); const version = this.owner.lookup('service:version');
assert.true(version.isEnterprise, 'vault is enterprise'); assert.true(version.isEnterprise, 'vault is enterprise');
assert.dom(SELECTORS.emptyState('replication')).exists(); assert.dom(DASHBOARD.emptyState('replication')).exists();
assert.dom(SELECTORS.emptyStateTitle('replication')).hasText('Replication not set up'); assert.dom(DASHBOARD.emptyStateTitle('replication')).hasText('Replication not set up');
assert assert
.dom(SELECTORS.emptyStateMessage('replication')) .dom(DASHBOARD.emptyStateMessage('replication'))
.hasText('Data will be listed here. Enable a primary replication cluster to get started.'); .hasText('Data will be listed here. Enable a primary replication cluster to get started.');
assert.dom(SELECTORS.emptyStateActions('replication')).hasText('Enable replication'); assert.dom(DASHBOARD.emptyStateActions('replication')).hasText('Enable replication');
}); });
test('hides the replication card on a non-root namespace enterprise version', async function (assert) { test('hides the replication card on a non-root namespace enterprise version', async function (assert) {
@ -446,10 +446,10 @@ module('Acceptance | landing page dashboard', function (hooks) {
await visit('/vault/dashboard'); await visit('/vault/dashboard');
const version = this.owner.lookup('service:version'); const version = this.owner.lookup('service:version');
assert.true(version.isEnterprise, 'vault is enterprise'); assert.true(version.isEnterprise, 'vault is enterprise');
assert.dom(SELECTORS.cardName('replication')).exists(); assert.dom(DASHBOARD.cardName('replication')).exists();
await runCmd(createNS('blah'), false); await runCmd(createNS('blah'), false);
await visit('/vault/dashboard?namespace=blah'); await visit('/vault/dashboard?namespace=blah');
assert.dom(SELECTORS.cardName('replication')).doesNotExist(); assert.dom(DASHBOARD.cardName('replication')).doesNotExist();
}); });
test('it should show replication status if both dr and performance replication are enabled as features in enterprise', async function (assert) { test('it should show replication status if both dr and performance replication are enabled as features in enterprise', async function (assert) {
@ -467,12 +467,12 @@ module('Acceptance | landing page dashboard', function (hooks) {
'details dashboard is shown' 'details dashboard is shown'
); );
await visit('/vault/dashboard'); await visit('/vault/dashboard');
assert.dom(SELECTORS.title('DR primary')).hasText('DR primary'); assert.dom(DASHBOARD.title('DR primary')).hasText('DR primary');
assert.dom(SELECTORS.tooltipTitle('DR primary')).hasText('not set up'); assert.dom(DASHBOARD.tooltipTitle('DR primary')).hasText('not set up');
assert.dom(SELECTORS.tooltipIcon('dr-perf', 'DR primary', 'x-circle')).exists(); assert.dom(DASHBOARD.tooltipIcon('dr-perf', 'DR primary', 'x-circle')).exists();
assert.dom(SELECTORS.title('Performance primary')).hasText('Performance primary'); assert.dom(DASHBOARD.title('Performance primary')).hasText('Performance primary');
assert.dom(SELECTORS.tooltipTitle('Performance primary')).hasText('running'); assert.dom(DASHBOARD.tooltipTitle('Performance primary')).hasText('running');
assert.dom(SELECTORS.tooltipIcon('dr-perf', 'Performance primary', 'check-circle')).exists(); assert.dom(DASHBOARD.tooltipIcon('dr-perf', 'Performance primary', 'check-circle')).exists();
}); });
}); });
@ -489,14 +489,14 @@ module('Acceptance | landing page dashboard', function (hooks) {
await visit('/vault/dashboard'); await visit('/vault/dashboard');
const modalId = 'some-awesome-id-1'; const modalId = 'some-awesome-id-1';
const alertId = 'some-awesome-id-2'; const alertId = 'some-awesome-id-2';
assert.dom(PAGE.modal(modalId)).exists(); assert.dom(CUSTOM_MESSAGES.modal(modalId)).exists();
assert.dom(PAGE.modalTitle(modalId)).hasText('Modal title'); assert.dom(CUSTOM_MESSAGES.modalTitle(modalId)).hasText('Modal title');
assert.dom(PAGE.modalBody(modalId)).exists(); assert.dom(CUSTOM_MESSAGES.modalBody(modalId)).exists();
assert.dom(PAGE.modalBody(modalId)).hasText('here is a cool message'); assert.dom(CUSTOM_MESSAGES.modalBody(modalId)).hasText('here is a cool message');
await click(PAGE.modalButton(modalId)); await click(CUSTOM_MESSAGES.modalButton(modalId));
assert.dom(PAGE.alertTitle(alertId)).hasText('Banner title'); assert.dom(CUSTOM_MESSAGES.alertTitle(alertId)).hasText('Banner title');
assert.dom(PAGE.alertDescription(alertId)).hasText('hello world hello wolrd'); assert.dom(CUSTOM_MESSAGES.alertDescription(alertId)).hasText('hello world hello wolrd');
assert.dom(PAGE.alertAction('link')).hasText('some link title'); assert.dom(CUSTOM_MESSAGES.alertAction('link')).hasText('some link title');
}); });
test('it shows the multiple modal messages', async function (assert) { test('it shows the multiple modal messages', async function (assert) {
assert.expect(8); assert.expect(8);
@ -511,16 +511,16 @@ module('Acceptance | landing page dashboard', function (hooks) {
return authenticatedMessageResponse; return authenticatedMessageResponse;
}); });
await visit('/vault/dashboard'); await visit('/vault/dashboard');
assert.dom(PAGE.modal(modalIdOne)).exists(); assert.dom(CUSTOM_MESSAGES.modal(modalIdOne)).exists();
assert.dom(PAGE.modalTitle(modalIdOne)).hasText('Modal title 1'); assert.dom(CUSTOM_MESSAGES.modalTitle(modalIdOne)).hasText('Modal title 1');
assert.dom(PAGE.modalBody(modalIdOne)).exists(); assert.dom(CUSTOM_MESSAGES.modalBody(modalIdOne)).exists();
assert.dom(PAGE.modalBody(modalIdOne)).hasText('hello world hello wolrd some link title'); assert.dom(CUSTOM_MESSAGES.modalBody(modalIdOne)).hasText('hello world hello wolrd some link title');
await click(PAGE.modalButton(modalIdOne)); await click(CUSTOM_MESSAGES.modalButton(modalIdOne));
assert.dom(PAGE.modal(modalIdTwo)).exists(); assert.dom(CUSTOM_MESSAGES.modal(modalIdTwo)).exists();
assert.dom(PAGE.modalTitle(modalIdTwo)).hasText('Modal title 2'); assert.dom(CUSTOM_MESSAGES.modalTitle(modalIdTwo)).hasText('Modal title 2');
assert.dom(PAGE.modalBody(modalIdTwo)).exists(); assert.dom(CUSTOM_MESSAGES.modalBody(modalIdTwo)).exists();
assert.dom(PAGE.modalBody(modalIdTwo)).hasText('here is a cool message'); assert.dom(CUSTOM_MESSAGES.modalBody(modalIdTwo)).hasText('here is a cool message');
await click(PAGE.modalButton(modalIdTwo)); await click(CUSTOM_MESSAGES.modalButton(modalIdTwo));
}); });
test('it shows the multiple banner messages', async function (assert) { test('it shows the multiple banner messages', async function (assert) {
assert.expect(5); assert.expect(5);
@ -535,11 +535,11 @@ module('Acceptance | landing page dashboard', function (hooks) {
return authenticatedMessageResponse; return authenticatedMessageResponse;
}); });
await visit('/vault/dashboard'); await visit('/vault/dashboard');
assert.dom(PAGE.alertTitle(bannerIdOne)).hasText('Banner title 1'); assert.dom(CUSTOM_MESSAGES.alertTitle(bannerIdOne)).hasText('Banner title 1');
assert.dom(PAGE.alertDescription(bannerIdOne)).hasText('hello world hello wolrd'); assert.dom(CUSTOM_MESSAGES.alertDescription(bannerIdOne)).hasText('hello world hello wolrd');
assert.dom(PAGE.alertAction('link')).hasText('some link title'); assert.dom(CUSTOM_MESSAGES.alertAction('link')).hasText('some link title');
assert.dom(PAGE.alertTitle(bannerIdTwo)).hasText('Banner title 2'); assert.dom(CUSTOM_MESSAGES.alertTitle(bannerIdTwo)).hasText('Banner title 2');
assert.dom(PAGE.alertDescription(bannerIdTwo)).hasText('here is a cool message'); assert.dom(CUSTOM_MESSAGES.alertDescription(bannerIdTwo)).hasText('here is a cool message');
}); });
}); });
}); });

View File

@ -69,7 +69,7 @@ module('Acceptance | oidc auth method', function (hooks) {
later(() => { later(() => {
window.postMessage(buildMessage().data, window.origin); window.postMessage(buildMessage().data, window.origin);
cancelTimers(); cancelTimers();
}, 50); }, 100);
await click('[data-test-auth-submit]'); await click('[data-test-auth-submit]');
}); });

View File

@ -17,11 +17,11 @@ import {
OIDC_BASE_URL, // -> '/vault/access/oidc' OIDC_BASE_URL, // -> '/vault/access/oidc'
SELECTORS, SELECTORS,
clearRecord, clearRecord,
overrideCapabilities,
overrideMirageResponse,
ASSIGNMENT_LIST_RESPONSE, ASSIGNMENT_LIST_RESPONSE,
ASSIGNMENT_DATA_RESPONSE, ASSIGNMENT_DATA_RESPONSE,
} from 'vault/tests/helpers/oidc-config'; } from 'vault/tests/helpers/oidc-config';
import { capabilitiesStub, overrideResponse } from 'vault/tests/helpers/stubs';
const searchSelect = create(ss); const searchSelect = create(ss);
const flashMessage = create(fm); const flashMessage = create(fm);
@ -51,7 +51,7 @@ module('Acceptance | oidc-config clients and assignments', function (hooks) {
test('it renders empty state when no clients are configured', async function (assert) { test('it renders empty state when no clients are configured', async function (assert) {
assert.expect(5); assert.expect(5);
this.server.get('/identity/oidc/client', () => overrideMirageResponse(404)); this.server.get('/identity/oidc/client', () => overrideResponse(404));
await visit(OIDC_BASE_URL); await visit(OIDC_BASE_URL);
assert.strictEqual(currentURL(), '/vault/access/oidc'); assert.strictEqual(currentURL(), '/vault/access/oidc');
@ -277,10 +277,10 @@ module('Acceptance | oidc-config clients and assignments', function (hooks) {
test('it navigates to and from an assignment from the list view', async function (assert) { test('it navigates to and from an assignment from the list view', async function (assert) {
assert.expect(6); assert.expect(6);
this.server.get('/identity/oidc/assignment', () => this.server.get('/identity/oidc/assignment', () =>
overrideMirageResponse(null, ASSIGNMENT_LIST_RESPONSE) overrideResponse(200, { data: ASSIGNMENT_LIST_RESPONSE })
); );
this.server.get('/identity/oidc/assignment/test-assignment', () => this.server.get('/identity/oidc/assignment/test-assignment', () =>
overrideMirageResponse(null, ASSIGNMENT_DATA_RESPONSE) overrideResponse(200, { data: ASSIGNMENT_DATA_RESPONSE })
); );
await visit(OIDC_BASE_URL + '/assignments'); await visit(OIDC_BASE_URL + '/assignments');
assert assert
@ -327,13 +327,13 @@ module('Acceptance | oidc-config clients and assignments', function (hooks) {
test('it hides assignment delete and edit when no permission', async function (assert) { test('it hides assignment delete and edit when no permission', async function (assert) {
assert.expect(5); assert.expect(5);
this.server.get('/identity/oidc/assignment', () => this.server.get('/identity/oidc/assignment', () =>
overrideMirageResponse(null, ASSIGNMENT_LIST_RESPONSE) overrideResponse(null, { data: ASSIGNMENT_LIST_RESPONSE })
); );
this.server.get('/identity/oidc/assignment/test-assignment', () => this.server.get('/identity/oidc/assignment/test-assignment', () =>
overrideMirageResponse(null, ASSIGNMENT_DATA_RESPONSE) overrideResponse(null, { data: ASSIGNMENT_DATA_RESPONSE })
); );
this.server.post('/sys/capabilities-self', () => this.server.post('/sys/capabilities-self', () =>
overrideCapabilities(OIDC_BASE_URL + '/assignment/test-assignment', ['read']) capabilitiesStub(OIDC_BASE_URL + '/assignment/test-assignment', ['read'])
); );
await visit(OIDC_BASE_URL + '/assignments'); await visit(OIDC_BASE_URL + '/assignments');

View File

@ -17,11 +17,10 @@ import {
OIDC_BASE_URL, // -> '/vault/access/oidc' OIDC_BASE_URL, // -> '/vault/access/oidc'
SELECTORS, SELECTORS,
clearRecord, clearRecord,
overrideCapabilities,
overrideMirageResponse,
CLIENT_LIST_RESPONSE, CLIENT_LIST_RESPONSE,
CLIENT_DATA_RESPONSE, CLIENT_DATA_RESPONSE,
} from 'vault/tests/helpers/oidc-config'; } from 'vault/tests/helpers/oidc-config';
import { capabilitiesStub, overrideResponse } from 'vault/tests/helpers/stubs';
const searchSelect = create(ss); const searchSelect = create(ss);
const flashMessage = create(fm); const flashMessage = create(fm);
@ -177,7 +176,7 @@ module('Acceptance | oidc-config clients and keys', function (hooks) {
test('it creates, rotates and deletes a key', async function (assert) { test('it creates, rotates and deletes a key', async function (assert) {
assert.expect(10); assert.expect(10);
// mock client list so OIDC url does not redirect to landing page // mock client list so OIDC url does not redirect to landing page
this.server.get('/identity/oidc/client', () => overrideMirageResponse(null, CLIENT_LIST_RESPONSE)); this.server.get('/identity/oidc/client', () => overrideResponse(null, { data: CLIENT_LIST_RESPONSE }));
this.server.post('/identity/oidc/key/test-key/rotate', (schema, req) => { this.server.post('/identity/oidc/key/test-key/rotate', (schema, req) => {
const json = JSON.parse(req.requestBody); const json = JSON.parse(req.requestBody);
assert.strictEqual(json.verification_ttl, 86400, 'request made with correct args to accurate endpoint'); assert.strictEqual(json.verification_ttl, 86400, 'request made with correct args to accurate endpoint');
@ -240,9 +239,9 @@ module('Acceptance | oidc-config clients and keys', function (hooks) {
test('it renders client details and providers', async function (assert) { test('it renders client details and providers', async function (assert) {
assert.expect(8); assert.expect(8);
this.server.get('/identity/oidc/client', () => overrideMirageResponse(null, CLIENT_LIST_RESPONSE)); this.server.get('/identity/oidc/client', () => overrideResponse(null, { data: CLIENT_LIST_RESPONSE }));
this.server.get('/identity/oidc/client/test-app', () => this.server.get('/identity/oidc/client/test-app', () =>
overrideMirageResponse(null, CLIENT_DATA_RESPONSE) overrideResponse(null, { data: CLIENT_DATA_RESPONSE })
); );
await visit(OIDC_BASE_URL); await visit(OIDC_BASE_URL);
await click('[data-test-oidc-client-linked-block]'); await click('[data-test-oidc-client-linked-block]');
@ -264,12 +263,12 @@ module('Acceptance | oidc-config clients and keys', function (hooks) {
test('it hides delete and edit client when no permission', async function (assert) { test('it hides delete and edit client when no permission', async function (assert) {
assert.expect(5); assert.expect(5);
this.server.get('/identity/oidc/client', () => overrideMirageResponse(null, CLIENT_LIST_RESPONSE)); this.server.get('/identity/oidc/client', () => overrideResponse(null, { data: CLIENT_LIST_RESPONSE }));
this.server.get('/identity/oidc/client/test-app', () => this.server.get('/identity/oidc/client/test-app', () =>
overrideMirageResponse(null, CLIENT_DATA_RESPONSE) overrideResponse(null, { data: CLIENT_DATA_RESPONSE })
); );
this.server.post('/sys/capabilities-self', () => this.server.post('/sys/capabilities-self', () =>
overrideCapabilities(OIDC_BASE_URL + '/client/test-app', ['read']) capabilitiesStub(OIDC_BASE_URL + '/client/test-app', ['read'])
); );
await visit(OIDC_BASE_URL); await visit(OIDC_BASE_URL);
@ -283,17 +282,19 @@ module('Acceptance | oidc-config clients and keys', function (hooks) {
test('it hides delete and edit key when no permission', async function (assert) { test('it hides delete and edit key when no permission', async function (assert) {
assert.expect(4); assert.expect(4);
this.server.get('/identity/oidc/keys', () => overrideMirageResponse(null, { keys: ['test-key'] })); this.server.get('/identity/oidc/keys', () => overrideResponse(null, { data: { keys: ['test-key'] } }));
this.server.get('/identity/oidc/key/test-key', () => this.server.get('/identity/oidc/key/test-key', () =>
overrideMirageResponse(null, { overrideResponse(null, {
algorithm: 'RS256', data: {
allowed_client_ids: ['*'], algorithm: 'RS256',
rotation_period: 86400, allowed_client_ids: ['*'],
verification_ttl: 86400, rotation_period: 86400,
verification_ttl: 86400,
},
}) })
); );
this.server.post('/sys/capabilities-self', () => this.server.post('/sys/capabilities-self', () =>
overrideCapabilities(OIDC_BASE_URL + '/key/test-key', ['read']) capabilitiesStub(OIDC_BASE_URL + '/key/test-key', ['read'])
); );
await visit(OIDC_BASE_URL + '/keys'); await visit(OIDC_BASE_URL + '/keys');

View File

@ -22,9 +22,8 @@ import {
PROVIDER_LIST_RESPONSE, PROVIDER_LIST_RESPONSE,
PROVIDER_DATA_RESPONSE, PROVIDER_DATA_RESPONSE,
clearRecord, clearRecord,
overrideCapabilities,
overrideMirageResponse,
} from 'vault/tests/helpers/oidc-config'; } from 'vault/tests/helpers/oidc-config';
import { capabilitiesStub, overrideResponse } from 'vault/tests/helpers/stubs';
const searchSelect = create(ss); const searchSelect = create(ss);
const flashMessage = create(fm); const flashMessage = create(fm);
@ -38,14 +37,14 @@ module('Acceptance | oidc-config providers and scopes', function (hooks) {
oidcConfigHandlers(this.server); oidcConfigHandlers(this.server);
this.store = this.owner.lookup('service:store'); this.store = this.owner.lookup('service:store');
// mock client list so OIDC BASE URL does not redirect to landing call-to-action image // mock client list so OIDC BASE URL does not redirect to landing call-to-action image
this.server.get('/identity/oidc/client', () => overrideMirageResponse(null, CLIENT_LIST_RESPONSE)); this.server.get('/identity/oidc/client', () => overrideResponse(null, { data: CLIENT_LIST_RESPONSE }));
return authPage.login(); return authPage.login();
}); });
// LIST SCOPES EMPTY // LIST SCOPES EMPTY
test('it navigates to scopes list view and renders empty state when no scopes are configured', async function (assert) { test('it navigates to scopes list view and renders empty state when no scopes are configured', async function (assert) {
assert.expect(4); assert.expect(4);
this.server.get('/identity/oidc/scope', () => overrideMirageResponse(404)); this.server.get('/identity/oidc/scope', () => overrideResponse(404));
await visit(OIDC_BASE_URL); await visit(OIDC_BASE_URL);
await click('[data-test-tab="scopes"]'); await click('[data-test-tab="scopes"]');
assert.strictEqual(currentURL(), '/vault/access/oidc/scopes'); assert.strictEqual(currentURL(), '/vault/access/oidc/scopes');
@ -64,9 +63,9 @@ module('Acceptance | oidc-config providers and scopes', function (hooks) {
// LIST SCOPE EXIST // LIST SCOPE EXIST
test('it renders scope list when scopes exist', async function (assert) { test('it renders scope list when scopes exist', async function (assert) {
assert.expect(11); assert.expect(11);
this.server.get('/identity/oidc/scope', () => overrideMirageResponse(null, SCOPE_LIST_RESPONSE)); this.server.get('/identity/oidc/scope', () => overrideResponse(null, { data: SCOPE_LIST_RESPONSE }));
this.server.get('/identity/oidc/scope/test-scope', () => this.server.get('/identity/oidc/scope/test-scope', () =>
overrideMirageResponse(null, SCOPE_DATA_RESPONSE) overrideResponse(null, { data: SCOPE_DATA_RESPONSE })
); );
await visit(OIDC_BASE_URL + '/scopes'); await visit(OIDC_BASE_URL + '/scopes');
assert.strictEqual( assert.strictEqual(
@ -125,13 +124,15 @@ module('Acceptance | oidc-config providers and scopes', function (hooks) {
// ERROR DELETING SCOPE // ERROR DELETING SCOPE
test('it throws error when trying to delete when scope is currently being associated with any provider', async function (assert) { test('it throws error when trying to delete when scope is currently being associated with any provider', async function (assert) {
assert.expect(3); assert.expect(3);
this.server.get('/identity/oidc/scope', () => overrideMirageResponse(null, SCOPE_LIST_RESPONSE)); this.server.get('/identity/oidc/scope', () => overrideResponse(null, { data: SCOPE_LIST_RESPONSE }));
this.server.get('/identity/oidc/scope/test-scope', () => this.server.get('/identity/oidc/scope/test-scope', () =>
overrideMirageResponse(null, SCOPE_DATA_RESPONSE) overrideResponse(null, { data: SCOPE_DATA_RESPONSE })
);
this.server.get('/identity/oidc/provider', () =>
overrideResponse(null, { data: PROVIDER_LIST_RESPONSE })
); );
this.server.get('/identity/oidc/provider', () => overrideMirageResponse(null, PROVIDER_LIST_RESPONSE));
this.server.get('/identity/oidc/provider/test-provider', () => { this.server.get('/identity/oidc/provider/test-provider', () => {
overrideMirageResponse(null, PROVIDER_DATA_RESPONSE); overrideResponse(null, { data: PROVIDER_DATA_RESPONSE });
}); });
// throw error when trying to delete test-scope since it is associated to test-provider // throw error when trying to delete test-scope since it is associated to test-provider
this.server.delete( this.server.delete(
@ -376,17 +377,19 @@ module('Acceptance | oidc-config providers and scopes', function (hooks) {
test('it hides delete and edit for a provider when no permission', async function (assert) { test('it hides delete and edit for a provider when no permission', async function (assert) {
assert.expect(3); assert.expect(3);
this.server.get('/identity/oidc/providers', () => this.server.get('/identity/oidc/providers', () =>
overrideMirageResponse(null, { providers: ['test-provider'] }) overrideResponse(null, { data: { providers: ['test-provider'] } })
); );
this.server.get('/identity/oidc/provider/test-provider', () => this.server.get('/identity/oidc/provider/test-provider', () =>
overrideMirageResponse(null, { overrideResponse(null, {
allowed_client_ids: ['*'], data: {
issuer: 'http://127.0.0.1:8200/v1/identity/oidc/provider/test-provider', allowed_client_ids: ['*'],
scopes_supported: ['test-scope'], issuer: 'http://127.0.0.1:8200/v1/identity/oidc/provider/test-provider',
scopes_supported: ['test-scope'],
},
}) })
); );
this.server.post('/sys/capabilities-self', () => this.server.post('/sys/capabilities-self', () =>
overrideCapabilities(OIDC_BASE_URL + '/provider/test-provider', ['read']) capabilitiesStub(OIDC_BASE_URL + '/provider/test-provider', ['read'])
); );
await visit(OIDC_BASE_URL + '/providers'); await visit(OIDC_BASE_URL + '/providers');

View File

@ -7,7 +7,8 @@ import { module, test } from 'qunit';
import { setupApplicationTest } from 'vault/tests/helpers'; import { setupApplicationTest } from 'vault/tests/helpers';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { deleteAuthCmd, deleteEngineCmd, mountAuthCmd, mountEngineCmd, runCmd } from '../helpers/commands'; import { deleteAuthCmd, deleteEngineCmd, mountAuthCmd, mountEngineCmd, runCmd } from '../helpers/commands';
import { authEngineHelper, secretEngineHelper } from '../helpers/openapi/test-helpers'; import expectedSecretAttrs from 'vault/tests/helpers/openapi/expected-secret-attrs';
import expectedAuthAttrs from 'vault/tests/helpers/openapi/expected-auth-attrs';
/** /**
* This set of tests is for ensuring that backend changes to the OpenAPI spec * This set of tests is for ensuring that backend changes to the OpenAPI spec
@ -56,3 +57,52 @@ module('Acceptance | OpenAPI provides expected attributes enterprise', function
} }
); );
}); });
function secretEngineHelper(test, secretEngine) {
const engineData = expectedSecretAttrs[secretEngine];
if (!engineData)
throw new Error(`No engine attributes found in secret-model-attributes for ${secretEngine}`);
const modelNames = Object.keys(engineData);
// A given secret engine might have multiple models that are openApi driven
modelNames.forEach((modelName) => {
test(`${modelName} model getProps returns correct attributes`, async function (assert) {
const model = this.store.createRecord(modelName, {});
const helpUrl = model.getHelpUrl(this.backend);
const result = await this.pathHelp.getProps(helpUrl, this.backend);
const expected = engineData[modelName];
assert.deepEqual(result, expected, `getProps returns expected attributes for ${modelName}`);
});
});
}
function authEngineHelper(test, authBackend) {
const authData = expectedAuthAttrs[authBackend];
if (!authData) throw new Error(`No auth attributes found in auth-model-attributes for ${authBackend}`);
const itemNames = Object.keys(authData);
itemNames.forEach((itemName) => {
if (itemName.startsWith('auth-config/')) {
// Config test doesn't need to instantiate a new model
test(`${itemName} model`, async function (assert) {
const model = this.store.createRecord(itemName, {});
const helpUrl = model.getHelpUrl(this.mount);
const result = await this.pathHelp.getProps(helpUrl, this.mount);
const expected = authData[itemName];
assert.deepEqual(result, expected, `getProps returns expected attributes for ${itemName}`);
});
} else {
test.skip(`generated-${itemName}-${authBackend} model`, async function (assert) {
const modelName = `generated-${itemName}-${authBackend}`;
// Generated items need to instantiate the model first via getNewModel
await this.pathHelp.getNewModel(modelName, this.mount, `auth/${this.mount}/`, itemName);
const model = this.store.createRecord(modelName, {});
// Generated items don't have this method -- helpUrl is calculated in path-help.js line 101
const helpUrl = model.getHelpUrl(this.mount);
const result = await this.pathHelp.getProps(helpUrl, this.mount);
const expected = authData[modelName];
assert.deepEqual(result, expected, `getProps returns expected attributes for ${modelName}`);
});
}
});
}

View File

@ -13,8 +13,11 @@ import authPage from 'vault/tests/pages/auth';
import logout from 'vault/tests/pages/logout'; import logout from 'vault/tests/pages/logout';
import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { runCmd } from 'vault/tests/helpers/commands'; import { runCmd } from 'vault/tests/helpers/commands';
import { SELECTORS as S } from 'vault/tests/helpers/pki/workflow'; import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { issuerPemBundle } from 'vault/tests/helpers/pki/values'; import { CERTIFICATES } from 'vault/tests/helpers/pki/pki-helpers';
import { PKI_CONFIGURE_CREATE, PKI_GENERATE_ROOT } from 'vault/tests/helpers/pki/pki-selectors';
const { issuerPemBundle } = CERTIFICATES;
module('Acceptance | pki action forms test', function (hooks) { module('Acceptance | pki action forms test', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@ -46,28 +49,28 @@ module('Acceptance | pki action forms test', function (hooks) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
await click(S.emptyStateLink); await click(`${GENERAL.emptyStateActions} a`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`);
assert.dom(S.configuration.title).hasText('Configure PKI'); assert.dom(GENERAL.title).hasText('Configure PKI');
assert.dom(S.configuration.emptyState).exists({ count: 1 }, 'Shows empty state by default'); assert.dom(GENERAL.emptyStateTitle).exists({ count: 1 }, 'Shows empty state by default');
await click(S.configuration.optionByKey('import')); await click(PKI_CONFIGURE_CREATE.optionByKey('import'));
assert.dom(S.configuration.emptyState).doesNotExist(); assert.dom(GENERAL.emptyStateTitle).doesNotExist();
// Submit before filling out form shows an error // Submit before filling out form shows an error
await click('[data-test-pki-import-pem-bundle]'); await click(PKI_CONFIGURE_CREATE.importSubmit);
assert.dom(S.configuration.importError).hasText('Error please upload your PEM bundle'); assert.dom(GENERAL.messageError).hasText('Error please upload your PEM bundle');
// Fill in form data // Fill in form data
await click('[data-test-text-toggle]'); await click('[data-test-text-toggle]');
await fillIn('[data-test-text-file-textarea]', this.pemBundle); await fillIn('[data-test-text-file-textarea]', this.pemBundle);
await click('[data-test-pki-import-pem-bundle]'); await click(PKI_CONFIGURE_CREATE.importSubmit);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration/create`, `/vault/secrets/${this.mountPath}/pki/configuration/create`,
'stays on page on success' 'stays on page on success'
); );
assert.dom(S.configuration.title).hasText('View imported items'); assert.dom(GENERAL.title).hasText('View imported items');
assert.dom(S.configuration.importForm).doesNotExist('import form is hidden after save'); assert.dom(PKI_CONFIGURE_CREATE.importForm).doesNotExist('import form is hidden after save');
assert.dom(S.configuration.importMapping).exists('import mapping is shown after save'); assert.dom(PKI_CONFIGURE_CREATE.importMapping).exists('import mapping is shown after save');
await click('[data-test-done]'); await click('[data-test-done]');
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
@ -91,22 +94,24 @@ module('Acceptance | pki action forms test', function (hooks) {
}); });
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`); await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
await click(S.configuration.optionByKey('import')); await click(PKI_CONFIGURE_CREATE.optionByKey('import'));
assert.dom(S.configuration.importForm).exists('import form is shown save'); assert.dom(PKI_CONFIGURE_CREATE.importForm).exists('import form is shown save');
await click('[data-test-text-toggle]'); await click('[data-test-text-toggle]');
await fillIn('[data-test-text-file-textarea]', this.pemBundle); await fillIn('[data-test-text-file-textarea]', this.pemBundle);
await click('[data-test-pki-import-pem-bundle]'); await click(PKI_CONFIGURE_CREATE.importSubmit);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration/create`, `/vault/secrets/${this.mountPath}/pki/configuration/create`,
'stays on page on success' 'stays on page on success'
); );
assert.dom(S.configuration.title).hasText('View imported items'); assert.dom(GENERAL.title).hasText('View imported items');
assert.dom(S.configuration.importForm).doesNotExist('import form is hidden after save'); assert.dom(PKI_CONFIGURE_CREATE.importForm).doesNotExist('import form is hidden after save');
assert.dom(S.configuration.importMapping).exists('import mapping is shown after save'); assert.dom(PKI_CONFIGURE_CREATE.importMapping).exists('import mapping is shown after save');
assert.dom(S.configuration.importedIssuer).hasText('my-imported-issuer', 'Issuer value is displayed'); assert
assert.dom(S.configuration.importedKey).hasText('my-imported-key', 'Key value is displayed'); .dom(PKI_CONFIGURE_CREATE.importedIssuer)
.hasText('my-imported-issuer', 'Issuer value is displayed');
assert.dom(PKI_CONFIGURE_CREATE.importedKey).hasText('my-imported-key', 'Key value is displayed');
await click('[data-test-done]'); await click('[data-test-done]');
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
@ -130,16 +135,18 @@ module('Acceptance | pki action forms test', function (hooks) {
}); });
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`); await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
await click(S.configuration.optionByKey('import')); await click(PKI_CONFIGURE_CREATE.optionByKey('import'));
assert.dom(S.configuration.importForm).exists('import form is shown save'); assert.dom(PKI_CONFIGURE_CREATE.importForm).exists('import form is shown save');
await click('[data-test-text-toggle]'); await click('[data-test-text-toggle]');
await fillIn('[data-test-text-file-textarea]', this.pemBundle); await fillIn('[data-test-text-file-textarea]', this.pemBundle);
await click('[data-test-pki-import-pem-bundle]'); await click(PKI_CONFIGURE_CREATE.importSubmit);
assert.dom(S.configuration.importForm).doesNotExist('import form is hidden after save'); assert.dom(PKI_CONFIGURE_CREATE.importForm).doesNotExist('import form is hidden after save');
assert.dom(S.configuration.importMapping).exists('import mapping is shown after save'); assert.dom(PKI_CONFIGURE_CREATE.importMapping).exists('import mapping is shown after save');
assert.dom(S.configuration.importedIssuer).hasText('my-imported-issuer', 'Issuer value is displayed'); assert
assert.dom(S.configuration.importedKey).hasText('None', 'Shows placeholder value for key'); .dom(PKI_CONFIGURE_CREATE.importedIssuer)
.hasText('my-imported-issuer', 'Issuer value is displayed');
assert.dom(PKI_CONFIGURE_CREATE.importedKey).hasText('None', 'Shows placeholder value for key');
}); });
test('shows None for imported items if nothing new imported', async function (assert) { test('shows None for imported items if nothing new imported', async function (assert) {
this.server.post(`${this.mountPath}/config/ca`, () => { this.server.post(`${this.mountPath}/config/ca`, () => {
@ -154,16 +161,16 @@ module('Acceptance | pki action forms test', function (hooks) {
}); });
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`); await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
await click(S.configuration.optionByKey('import')); await click(PKI_CONFIGURE_CREATE.optionByKey('import'));
assert.dom(S.configuration.importForm).exists('import form is shown save'); assert.dom(PKI_CONFIGURE_CREATE.importForm).exists('import form is shown save');
await click('[data-test-text-toggle]'); await click('[data-test-text-toggle]');
await fillIn('[data-test-text-file-textarea]', this.pemBundle); await fillIn('[data-test-text-file-textarea]', this.pemBundle);
await click('[data-test-pki-import-pem-bundle]'); await click(PKI_CONFIGURE_CREATE.importSubmit);
assert.dom(S.configuration.importForm).doesNotExist('import form is hidden after save'); assert.dom(PKI_CONFIGURE_CREATE.importForm).doesNotExist('import form is hidden after save');
assert.dom(S.configuration.importMapping).exists('import mapping is shown after save'); assert.dom(PKI_CONFIGURE_CREATE.importMapping).exists('import mapping is shown after save');
assert.dom(S.configuration.importedIssuer).hasText('None', 'Shows placeholder value for issuer'); assert.dom(PKI_CONFIGURE_CREATE.importedIssuer).hasText('None', 'Shows placeholder value for issuer');
assert.dom(S.configuration.importedKey).hasText('None', 'Shows placeholder value for key'); assert.dom(PKI_CONFIGURE_CREATE.importedKey).hasText('None', 'Shows placeholder value for key');
}); });
}); });
@ -175,73 +182,73 @@ module('Acceptance | pki action forms test', function (hooks) {
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
await click(S.emptyStateLink); await click(`${GENERAL.emptyStateActions} a`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`);
assert.dom(S.configuration.title).hasText('Configure PKI'); assert.dom(GENERAL.title).hasText('Configure PKI');
assert.dom(S.configuration.emptyState).exists({ count: 1 }, 'Shows empty state by default'); assert.dom(GENERAL.emptyStateTitle).exists({ count: 1 }, 'Shows empty state by default');
await click(S.configuration.optionByKey('generate-root')); await click(PKI_CONFIGURE_CREATE.optionByKey('generate-root'));
assert.dom(S.configuration.emptyState).doesNotExist(); assert.dom(GENERAL.emptyStateTitle).doesNotExist();
// The URLs section is populated based on params returned from OpenAPI. This test will break when // The URLs section is populated based on params returned from OpenAPI. This test will break when
// the backend adds fields. We should update the count accordingly. // the backend adds fields. We should update the count accordingly.
assert.dom(S.configuration.urlField).exists({ count: 4 }); assert.dom(PKI_GENERATE_ROOT.urlField).exists({ count: 4 });
// Fill in form // Fill in form
await fillIn(S.configuration.typeField, 'internal'); await fillIn(GENERAL.inputByAttr('type'), 'internal');
await typeIn(S.configuration.inputByName('commonName'), commonName); await typeIn(GENERAL.inputByAttr('commonName'), commonName);
await typeIn(S.configuration.inputByName('issuerName'), issuerName); await typeIn(GENERAL.inputByAttr('issuerName'), issuerName);
await click(S.configuration.keyParamsGroupToggle); await click(PKI_GENERATE_ROOT.keyParamsGroupToggle);
await typeIn(S.configuration.inputByName('keyName'), keyName); await typeIn(GENERAL.inputByAttr('keyName'), keyName);
await click(S.configuration.generateRootSave); await click(GENERAL.saveButton);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration/create`, `/vault/secrets/${this.mountPath}/pki/configuration/create`,
'stays on page on success' 'stays on page on success'
); );
assert.dom(S.configuration.title).hasText('View Root Certificate'); assert.dom(GENERAL.title).hasText('View Root Certificate');
assert.dom(S.configuration.nextStepsBanner).doesNotExist('no private key warning'); assert.dom(PKI_CONFIGURE_CREATE.nextStepsBanner).doesNotExist('no private key warning');
assert.dom(S.configuration.title).hasText('View Root Certificate', 'Updates title on page'); assert.dom(GENERAL.title).hasText('View Root Certificate', 'Updates title on page');
assert.dom(S.configuration.saved.certificate).exists('Copyable certificate exists'); assert.dom(PKI_GENERATE_ROOT.saved.certificate).exists('Copyable certificate exists');
assert.dom(S.configuration.saved.issuerName).hasText(issuerName); assert.dom(PKI_GENERATE_ROOT.saved.issuerName).hasText(issuerName);
assert.dom(S.configuration.saved.issuerLink).exists('Issuer link exists'); assert.dom(PKI_GENERATE_ROOT.saved.issuerLink).exists('Issuer link exists');
assert.dom(S.configuration.saved.keyLink).exists('Key link exists'); assert.dom(PKI_GENERATE_ROOT.saved.keyLink).exists('Key link exists');
assert.dom(S.configuration.saved.keyName).hasText(keyName); assert.dom(PKI_GENERATE_ROOT.saved.keyName).hasText(keyName);
assert.dom('[data-test-done]').exists('Done button exists'); assert.dom('[data-test-done]').exists('Done button exists');
// Check that linked issuer has correct common name // Check that linked issuer has correct common name
await click(S.configuration.saved.issuerLink); await click(PKI_GENERATE_ROOT.saved.issuerLink);
assert.dom(S.issuerDetails.valueByName('Common name')).hasText(commonName); assert.dom(GENERAL.infoRowValue('Common name')).hasText(commonName);
}); });
test('type=exported', async function (assert) { test('type=exported', async function (assert) {
const commonName = 'my-exported-name'; const commonName = 'my-exported-name';
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`); await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
await click(S.configuration.optionByKey('generate-root')); await click(PKI_CONFIGURE_CREATE.optionByKey('generate-root'));
// Fill in form // Fill in form
await fillIn(S.configuration.typeField, 'exported'); await fillIn(GENERAL.inputByAttr('type'), 'exported');
await typeIn(S.configuration.inputByName('commonName'), commonName); await typeIn(GENERAL.inputByAttr('commonName'), commonName);
await click(S.configuration.generateRootSave); await click(GENERAL.saveButton);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration/create`, `/vault/secrets/${this.mountPath}/pki/configuration/create`,
'stays on page on success' 'stays on page on success'
); );
assert.dom(S.configuration.title).hasText('View Root Certificate'); assert.dom(GENERAL.title).hasText('View Root Certificate');
assert assert
.dom(S.configuration.nextStepsBanner) .dom(PKI_CONFIGURE_CREATE.nextStepsBanner)
.hasText('Next steps The private_key is only available once. Make sure you copy and save it now.'); .hasText('Next steps The private_key is only available once. Make sure you copy and save it now.');
assert.dom(S.configuration.title).hasText('View Root Certificate', 'Updates title on page'); assert.dom(GENERAL.title).hasText('View Root Certificate', 'Updates title on page');
assert.dom(S.configuration.saved.certificate).exists('Copyable certificate exists'); assert.dom(PKI_GENERATE_ROOT.saved.certificate).exists('Copyable certificate exists');
assert assert
.dom(S.configuration.saved.issuerName) .dom(PKI_GENERATE_ROOT.saved.issuerName)
.doesNotExist('Issuer name not shown because it was not named'); .doesNotExist('Issuer name not shown because it was not named');
assert.dom(S.configuration.saved.issuerLink).exists('Issuer link exists'); assert.dom(PKI_GENERATE_ROOT.saved.issuerLink).exists('Issuer link exists');
assert.dom(S.configuration.saved.keyLink).exists('Key link exists'); assert.dom(PKI_GENERATE_ROOT.saved.keyLink).exists('Key link exists');
assert.dom(S.configuration.saved.privateKey).exists('Copyable private key exists'); assert.dom(PKI_GENERATE_ROOT.saved.privateKey).exists('Copyable private key exists');
assert.dom(S.configuration.saved.keyName).doesNotExist('Key name not shown because it was not named'); assert.dom(PKI_GENERATE_ROOT.saved.keyName).doesNotExist('Key name not shown because it was not named');
assert.dom('[data-test-done]').exists('Done button exists'); assert.dom('[data-test-done]').exists('Done button exists');
// Check that linked issuer has correct common name // Check that linked issuer has correct common name
await click(S.configuration.saved.issuerLink); await click(PKI_GENERATE_ROOT.saved.issuerLink);
assert.dom(S.issuerDetails.valueByName('Common name')).hasText(commonName); assert.dom(GENERAL.infoRowValue('Common name')).hasText(commonName);
}); });
}); });
@ -249,14 +256,14 @@ module('Acceptance | pki action forms test', function (hooks) {
test('happy path', async function (assert) { test('happy path', async function (assert) {
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(S.emptyStateLink); await click(`${GENERAL.emptyStateActions} a`);
assert.dom(S.configuration.title).hasText('Configure PKI'); assert.dom(GENERAL.title).hasText('Configure PKI');
await click(S.configuration.optionByKey('generate-csr')); await click(PKI_CONFIGURE_CREATE.optionByKey('generate-csr'));
await fillIn(S.configuration.typeField, 'internal'); await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(S.configuration.inputByName('commonName'), 'my-common-name'); await fillIn(GENERAL.inputByAttr('commonName'), 'my-common-name');
await click('[data-test-save]'); await click('[data-test-save]');
assert.dom(S.configuration.title).hasText('View Generated CSR'); assert.dom(GENERAL.title).hasText('View Generated CSR');
await assert.dom(S.configuration.csrDetails).exists('renders CSR details after save'); await assert.dom(PKI_CONFIGURE_CREATE.csrDetails).exists('renders CSR details after save');
await click('[data-test-done]'); await click('[data-test-done]');
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
@ -267,19 +274,19 @@ module('Acceptance | pki action forms test', function (hooks) {
test('type = exported', async function (assert) { test('type = exported', async function (assert) {
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(S.emptyStateLink); await click(`${GENERAL.emptyStateActions} a`);
await click(S.configuration.optionByKey('generate-csr')); await click(PKI_CONFIGURE_CREATE.optionByKey('generate-csr'));
await fillIn(S.configuration.typeField, 'exported'); await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(S.configuration.inputByName('commonName'), 'my-common-name'); await fillIn(GENERAL.inputByAttr('commonName'), 'my-common-name');
await click('[data-test-save]'); await click('[data-test-save]');
await assert.dom(S.configuration.csrDetails).exists('renders CSR details after save'); await assert.dom(PKI_CONFIGURE_CREATE.csrDetails).exists('renders CSR details after save');
assert.dom(S.configuration.title).hasText('View Generated CSR'); assert.dom(GENERAL.title).hasText('View Generated CSR');
assert assert
.dom('[data-test-next-steps-csr]') .dom('[data-test-next-steps-csr]')
.hasText( .hasText(
'Next steps Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount. The private_key is only available once. Make sure you copy and save it now.' 'Next steps Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount. The private_key is only available once. Make sure you copy and save it now.'
); );
assert.dom(S.configuration.saved.privateKey).exists('Copyable private key exists'); assert.dom(PKI_GENERATE_ROOT.saved.privateKey).exists('Copyable private key exists');
await click('[data-test-done]'); await click('[data-test-done]');
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),

View File

@ -14,9 +14,16 @@ import authPage from 'vault/tests/pages/auth';
import logout from 'vault/tests/pages/logout'; import logout from 'vault/tests/pages/logout';
import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { runCmd } from 'vault/tests/helpers/commands'; import { runCmd } from 'vault/tests/helpers/commands';
import { SELECTORS } from 'vault/tests/helpers/pki/workflow'; import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { issuerPemBundle } from 'vault/tests/helpers/pki/values'; import { CERTIFICATES } from 'vault/tests/helpers/pki/pki-helpers';
import {
PKI_CONFIGURE_CREATE,
PKI_DELETE_ALL_ISSUERS,
PKI_GENERATE_ROOT,
PKI_ISSUER_LIST,
} from 'vault/tests/helpers/pki/pki-selectors';
const { issuerPemBundle } = CERTIFICATES;
module('Acceptance | pki configuration test', function (hooks) { module('Acceptance | pki configuration test', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@ -43,68 +50,66 @@ module('Acceptance | pki configuration test', function (hooks) {
test('it shows the delete all issuers modal', async function (assert) { test('it shows the delete all issuers modal', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/configuration`); await visit(`/vault/secrets/${this.mountPath}/pki/configuration`);
await click(SELECTORS.configuration.configureButton); await click(PKI_CONFIGURE_CREATE.configureButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`);
await settled(); await settled();
await click(SELECTORS.configuration.generateRootOption); await click(PKI_CONFIGURE_CREATE.generateRootOption);
await fillIn(SELECTORS.configuration.typeField, 'exported'); await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(SELECTORS.configuration.generateRootCommonNameField, 'issuer-common-0'); await fillIn(GENERAL.inputByAttr('commonName'), 'issuer-common-0');
await fillIn(SELECTORS.configuration.generateRootIssuerNameField, 'issuer-0'); await fillIn(GENERAL.inputByAttr('issuerName'), 'issuer-0');
await click(SELECTORS.configuration.generateRootSave); await click(GENERAL.saveButton);
await click(SELECTORS.configuration.doneButton); await click(PKI_CONFIGURE_CREATE.doneButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
await settled(); await settled();
await click(SELECTORS.configTab); await click(GENERAL.secretTab('Configuration'));
await settled(); await settled();
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`);
await click(SELECTORS.configuration.issuerLink); await click(PKI_DELETE_ALL_ISSUERS.issuerLink);
await settled(); await settled();
await waitFor(SELECTORS.configuration.deleteAllIssuerModal, { timeout: 5000 }); await waitFor(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal, { timeout: 5000 });
assert.dom(SELECTORS.configuration.deleteAllIssuerModal).exists(); assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).exists();
await fillIn(SELECTORS.configuration.deleteAllIssuerInput, 'delete-all'); await fillIn(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerInput, 'delete-all');
await click(SELECTORS.configuration.deleteAllIssuerButton); await click(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerButton);
await settled(); await settled();
await waitUntil(() => !find(SELECTORS.configuration.deleteAllIssuerModal)); await waitUntil(() => !find(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal));
assert.dom(SELECTORS.configuration.deleteAllIssuerModal).doesNotExist(); assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).doesNotExist();
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`);
}); });
test('it shows the correct empty state message if certificates exists after delete all issuers', async function (assert) { test('it shows the correct empty state message if certificates exists after delete all issuers', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/configuration`); await visit(`/vault/secrets/${this.mountPath}/pki/configuration`);
await click(SELECTORS.configuration.configureButton); await click(PKI_CONFIGURE_CREATE.configureButton);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration/create`, `/vault/secrets/${this.mountPath}/pki/configuration/create`,
'goes to pki configure page' 'goes to pki configure page'
); );
await click(SELECTORS.configuration.generateRootOption); await click(PKI_CONFIGURE_CREATE.generateRootOption);
await fillIn(SELECTORS.configuration.typeField, 'exported'); await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(SELECTORS.configuration.generateRootCommonNameField, 'issuer-common-0'); await fillIn(GENERAL.inputByAttr('commonName'), 'issuer-common-0');
await fillIn(SELECTORS.configuration.generateRootIssuerNameField, 'issuer-0'); await fillIn(GENERAL.inputByAttr('issuerName'), 'issuer-0');
await click(SELECTORS.configuration.generateRootSave); await click(GENERAL.saveButton);
await click(SELECTORS.configuration.doneButton); await click(PKI_CONFIGURE_CREATE.doneButton);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/overview`, `/vault/secrets/${this.mountPath}/pki/overview`,
'goes to overview page' 'goes to overview page'
); );
await click(SELECTORS.configTab); await click(GENERAL.secretTab('Configuration'));
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration`, `/vault/secrets/${this.mountPath}/pki/configuration`,
'goes to configuration page' 'goes to configuration page'
); );
await click(SELECTORS.configuration.issuerLink); await click(PKI_DELETE_ALL_ISSUERS.issuerLink);
await waitFor(SELECTORS.configuration.deleteAllIssuerModal); await waitFor(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal);
assert.dom(SELECTORS.configuration.deleteAllIssuerModal).exists(); assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).exists();
await fillIn(SELECTORS.configuration.deleteAllIssuerInput, 'delete-all'); await fillIn(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerInput, 'delete-all');
await click(SELECTORS.configuration.deleteAllIssuerButton); await click(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerButton);
await waitUntil(() => !find(SELECTORS.configuration.deleteAllIssuerModal)); await waitUntil(() => !find(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal));
assert assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).doesNotExist('delete all issuers modal closes');
.dom(SELECTORS.configuration.deleteAllIssuerModal)
.doesNotExist('delete all issuers modal closes');
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration`, `/vault/secrets/${this.mountPath}/pki/configuration`,
@ -119,7 +124,7 @@ module('Acceptance | pki configuration test', function (hooks) {
'goes to overview page' 'goes to overview page'
); );
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText( .hasText(
"This PKI mount hasn't yet been configured with a certificate issuer. There are existing certificates. Use the CLI to perform any operations with them until an issuer is configured." "This PKI mount hasn't yet been configured with a certificate issuer. There are existing certificates. Use the CLI to perform any operations with them until an issuer is configured."
); );
@ -127,25 +132,25 @@ module('Acceptance | pki configuration test', function (hooks) {
await visit(`/vault/secrets/${this.mountPath}/pki/roles`); await visit(`/vault/secrets/${this.mountPath}/pki/roles`);
await settled(); await settled();
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText("This PKI mount hasn't yet been configured with a certificate issuer."); .hasText("This PKI mount hasn't yet been configured with a certificate issuer.");
await visit(`/vault/secrets/${this.mountPath}/pki/issuers`); await visit(`/vault/secrets/${this.mountPath}/pki/issuers`);
await settled(); await settled();
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText("This PKI mount hasn't yet been configured with a certificate issuer."); .hasText("This PKI mount hasn't yet been configured with a certificate issuer.");
await visit(`/vault/secrets/${this.mountPath}/pki/keys`); await visit(`/vault/secrets/${this.mountPath}/pki/keys`);
await settled(); await settled();
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText("This PKI mount hasn't yet been configured with a certificate issuer."); .hasText("This PKI mount hasn't yet been configured with a certificate issuer.");
await visit(`/vault/secrets/${this.mountPath}/pki/certificates`); await visit(`/vault/secrets/${this.mountPath}/pki/certificates`);
await settled(); await settled();
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText( .hasText(
"This PKI mount hasn't yet been configured with a certificate issuer. There are existing certificates. Use the CLI to perform any operations with them until an issuer is configured." "This PKI mount hasn't yet been configured with a certificate issuer. There are existing certificates. Use the CLI to perform any operations with them until an issuer is configured."
); );
@ -155,14 +160,14 @@ module('Acceptance | pki configuration test', function (hooks) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
// Configure PKI // Configure PKI
await visit(`/vault/secrets/${this.mountPath}/pki/configuration`); await visit(`/vault/secrets/${this.mountPath}/pki/configuration`);
await click(SELECTORS.configuration.configureButton); await click(PKI_CONFIGURE_CREATE.configureButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`);
await click(SELECTORS.configuration.generateRootOption); await click(PKI_CONFIGURE_CREATE.generateRootOption);
await fillIn(SELECTORS.configuration.typeField, 'exported'); await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(SELECTORS.configuration.generateRootCommonNameField, 'issuer-common-0'); await fillIn(GENERAL.inputByAttr('commonName'), 'issuer-common-0');
await fillIn(SELECTORS.configuration.generateRootIssuerNameField, 'issuer-0'); await fillIn(GENERAL.inputByAttr('issuerName'), 'issuer-0');
await click(SELECTORS.configuration.generateRootSave); await click(GENERAL.saveButton);
await click(SELECTORS.configuration.doneButton); await click(PKI_CONFIGURE_CREATE.doneButton);
// Create role and root CA" // Create role and root CA"
await runCmd([ await runCmd([
`write ${this.mountPath}/roles/some-role \ `write ${this.mountPath}/roles/some-role \
@ -173,23 +178,23 @@ module('Acceptance | pki configuration test', function (hooks) {
]); ]);
await runCmd([`write ${this.mountPath}/root/generate/internal common_name="Hashicorp Test"`]); await runCmd([`write ${this.mountPath}/root/generate/internal common_name="Hashicorp Test"`]);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.configTab); await click(GENERAL.secretTab('Configuration'));
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`);
await click(SELECTORS.configuration.issuerLink); await click(PKI_DELETE_ALL_ISSUERS.issuerLink);
await waitFor(SELECTORS.configuration.deleteAllIssuerModal); await waitFor(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal);
assert.dom(SELECTORS.configuration.deleteAllIssuerModal).exists(); assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).exists();
await fillIn(SELECTORS.configuration.deleteAllIssuerInput, 'delete-all'); await fillIn(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerInput, 'delete-all');
await click(SELECTORS.configuration.deleteAllIssuerButton); await click(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerButton);
await settled(); await settled();
await waitUntil(() => !find(SELECTORS.configuration.deleteAllIssuerModal)); await waitUntil(() => !find(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal));
assert.dom(SELECTORS.configuration.deleteAllIssuerModal).doesNotExist(); assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).doesNotExist();
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`);
await settled(); await settled();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await settled(); await settled();
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText( .hasText(
"This PKI mount hasn't yet been configured with a certificate issuer. There are existing roles and certificates. Use the CLI to perform any operations with them until an issuer is configured." "This PKI mount hasn't yet been configured with a certificate issuer. There are existing roles and certificates. Use the CLI to perform any operations with them until an issuer is configured."
); );
@ -197,7 +202,7 @@ module('Acceptance | pki configuration test', function (hooks) {
await visit(`/vault/secrets/${this.mountPath}/pki/roles`); await visit(`/vault/secrets/${this.mountPath}/pki/roles`);
await settled(); await settled();
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText( .hasText(
"This PKI mount hasn't yet been configured with a certificate issuer. There are existing roles. Use the CLI to perform any operations with them until an issuer is configured." "This PKI mount hasn't yet been configured with a certificate issuer. There are existing roles. Use the CLI to perform any operations with them until an issuer is configured."
); );
@ -205,19 +210,19 @@ module('Acceptance | pki configuration test', function (hooks) {
await visit(`/vault/secrets/${this.mountPath}/pki/issuers`); await visit(`/vault/secrets/${this.mountPath}/pki/issuers`);
await settled(); await settled();
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText("This PKI mount hasn't yet been configured with a certificate issuer."); .hasText("This PKI mount hasn't yet been configured with a certificate issuer.");
await visit(`/vault/secrets/${this.mountPath}/pki/keys`); await visit(`/vault/secrets/${this.mountPath}/pki/keys`);
await settled(); await settled();
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText("This PKI mount hasn't yet been configured with a certificate issuer."); .hasText("This PKI mount hasn't yet been configured with a certificate issuer.");
await visit(`/vault/secrets/${this.mountPath}/pki/certificates`); await visit(`/vault/secrets/${this.mountPath}/pki/certificates`);
await settled(); await settled();
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText( .hasText(
"This PKI mount hasn't yet been configured with a certificate issuer. There are existing certificates. Use the CLI to perform any operations with them until an issuer is configured." "This PKI mount hasn't yet been configured with a certificate issuer. There are existing certificates. Use the CLI to perform any operations with them until an issuer is configured."
); );
@ -228,24 +233,24 @@ module('Acceptance | pki configuration test', function (hooks) {
assert.expect(4); assert.expect(4);
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
await click(SELECTORS.generateIssuerDropdown); await click(PKI_ISSUER_LIST.generateIssuerDropdown);
await click(SELECTORS.generateIssuerRoot); await click(PKI_ISSUER_LIST.generateIssuerRoot);
await fillIn(SELECTORS.configuration.inputByName('type'), 'internal'); await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-certificate'); await fillIn(GENERAL.inputByAttr('commonName'), 'my-certificate');
await click(SELECTORS.configuration.keyParamsGroupToggle); await click(PKI_GENERATE_ROOT.keyParamsGroupToggle);
await fillIn(SELECTORS.configuration.inputByName('keyType'), 'ed25519'); await fillIn(GENERAL.inputByAttr('keyType'), 'ed25519');
await click(SELECTORS.configuration.generateRootSave); await click(GENERAL.saveButton);
const issuerId = find(SELECTORS.configuration.saved.issuerLink).innerHTML; const issuerId = find(PKI_GENERATE_ROOT.saved.issuerLink).innerHTML;
await visit(`/vault/secrets/${this.mountPath}/pki/issuers`); await visit(`/vault/secrets/${this.mountPath}/pki/issuers`);
assert.dom(SELECTORS.issuerListItem(issuerId)).exists(); assert.dom(PKI_ISSUER_LIST.issuerListItem(issuerId)).exists();
assert assert
.dom('[data-test-common-name="0"]') .dom('[data-test-common-name="0"]')
.hasText('my-certificate', 'parses certificate metadata in the list view'); .hasText('my-certificate', 'parses certificate metadata in the list view');
await click(SELECTORS.issuerListItem(issuerId)); await click(PKI_ISSUER_LIST.issuerListItem(issuerId));
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/details`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/details`);
assert.dom(SELECTORS.configuration.saved.commonName).exists('renders issuer details'); assert.dom(PKI_GENERATE_ROOT.saved.commonName).exists('renders issuer details');
}); });
}); });
}); });

View File

@ -11,8 +11,14 @@ import { v4 as uuidv4 } from 'uuid';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { runCmd } from 'vault/tests/helpers/commands'; import { runCmd } from 'vault/tests/helpers/commands';
import { SELECTORS } from 'vault/tests/helpers/pki/pki-issuer-cross-sign';
import { verifyCertificates } from 'vault/utils/parse-pki-cert'; import { verifyCertificates } from 'vault/utils/parse-pki-cert';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import {
PKI_CONFIGURE_CREATE,
PKI_CROSS_SIGN,
PKI_ISSUER_DETAILS,
} from 'vault/tests/helpers/pki/pki-selectors';
module('Acceptance | pki/pki cross sign', function (hooks) { module('Acceptance | pki/pki cross sign', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@ -43,48 +49,48 @@ module('Acceptance | pki/pki cross sign', function (hooks) {
test('it cross-signs an issuer', async function (assert) { test('it cross-signs an issuer', async function (assert) {
// configure parent and intermediate mounts to make them cross-signable // configure parent and intermediate mounts to make them cross-signable
await visit(`/vault/secrets/${this.intMountPath}/pki/configuration/create`); await visit(`/vault/secrets/${this.intMountPath}/pki/configuration/create`);
await click(SELECTORS.configure.optionByKey('generate-csr')); await click(PKI_CONFIGURE_CREATE.optionByKey('generate-csr'));
await fillIn(SELECTORS.inputByName('type'), 'internal'); await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(SELECTORS.inputByName('commonName'), 'Short-Lived Int R1'); await fillIn(GENERAL.inputByAttr('commonName'), 'Short-Lived Int R1');
await click('[data-test-save]'); await click('[data-test-save]');
const csr = find(SELECTORS.copyButton('CSR')).getAttribute('data-test-copy-button'); const csr = find(PKI_CROSS_SIGN.copyButton('CSR')).getAttribute('data-test-copy-button');
await visit(`vault/secrets/${this.parentMountPath}/pki/issuers/${this.oldParentIssuerName}/sign`); await visit(`vault/secrets/${this.parentMountPath}/pki/issuers/${this.oldParentIssuerName}/sign`);
await fillIn(SELECTORS.inputByName('csr'), csr); await fillIn(GENERAL.inputByAttr('csr'), csr);
await fillIn(SELECTORS.inputByName('format'), 'pem_bundle'); await fillIn(GENERAL.inputByAttr('format'), 'pem_bundle');
await click('[data-test-pki-sign-intermediate-save]'); await click('[data-test-pki-sign-intermediate-save]');
const pemBundle = find(SELECTORS.copyButton('CA Chain')) const pemBundle = find(PKI_CROSS_SIGN.copyButton('CA Chain'))
.getAttribute('data-test-copy-button') .getAttribute('data-test-copy-button')
.replace(/,/, '\n'); .replace(/,/, '\n');
await visit(`vault/secrets/${this.intMountPath}/pki/configuration/create`); await visit(`vault/secrets/${this.intMountPath}/pki/configuration/create`);
await click(SELECTORS.configure.optionByKey('import')); await click(PKI_CONFIGURE_CREATE.optionByKey('import'));
await click('[data-test-text-toggle]'); await click('[data-test-text-toggle]');
await fillIn('[data-test-text-file-textarea]', pemBundle); await fillIn('[data-test-text-file-textarea]', pemBundle);
await click(SELECTORS.configure.importSubmit); await click(PKI_CONFIGURE_CREATE.importSubmit);
await visit(`vault/secrets/${this.intMountPath}/pki/issuers`); await visit(`vault/secrets/${this.intMountPath}/pki/issuers`);
await click('[data-test-is-default]'); await click('[data-test-is-default]');
// name default issuer of intermediate // name default issuer of intermediate
const oldIntIssuerId = find(SELECTORS.rowValue('Issuer ID')).innerText; const oldIntIssuerId = find(PKI_CROSS_SIGN.rowValue('Issuer ID')).innerText;
const oldIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-test-copy-button'); const oldIntCert = find(PKI_CROSS_SIGN.copyButton('Certificate')).getAttribute('data-test-copy-button');
await click(SELECTORS.details.configure); await click(PKI_ISSUER_DETAILS.configure);
await fillIn(SELECTORS.inputByName('issuerName'), this.intIssuerName); await fillIn(GENERAL.inputByAttr('issuerName'), this.intIssuerName);
await click('[data-test-save]'); await click('[data-test-save]');
// perform cross-sign // perform cross-sign
await visit(`vault/secrets/${this.parentMountPath}/pki/issuers/${this.parentIssuerName}/cross-sign`); await visit(`vault/secrets/${this.parentMountPath}/pki/issuers/${this.parentIssuerName}/cross-sign`);
await fillIn(SELECTORS.objectListInput('intermediateMount'), this.intMountPath); await fillIn(PKI_CROSS_SIGN.objectListInput('intermediateMount'), this.intMountPath);
await fillIn(SELECTORS.objectListInput('intermediateIssuer'), this.intIssuerName); await fillIn(PKI_CROSS_SIGN.objectListInput('intermediateIssuer'), this.intIssuerName);
await fillIn(SELECTORS.objectListInput('newCrossSignedIssuer'), this.newlySignedIssuer); await fillIn(PKI_CROSS_SIGN.objectListInput('newCrossSignedIssuer'), this.newlySignedIssuer);
await click(SELECTORS.submitButton); await click(GENERAL.saveButton);
assert assert
.dom(`${SELECTORS.signedIssuerCol('intermediateMount')} a`) .dom(`${PKI_CROSS_SIGN.signedIssuerCol('intermediateMount')} a`)
.hasAttribute('href', `/ui/vault/secrets/${this.intMountPath}/pki/overview`); .hasAttribute('href', `/ui/vault/secrets/${this.intMountPath}/pki/overview`);
assert assert
.dom(`${SELECTORS.signedIssuerCol('intermediateIssuer')} a`) .dom(`${PKI_CROSS_SIGN.signedIssuerCol('intermediateIssuer')} a`)
.hasAttribute('href', `/ui/vault/secrets/${this.intMountPath}/pki/issuers/${oldIntIssuerId}/details`); .hasAttribute('href', `/ui/vault/secrets/${this.intMountPath}/pki/issuers/${oldIntIssuerId}/details`);
// get certificate data of newly signed issuer // get certificate data of newly signed issuer
await click(`${SELECTORS.signedIssuerCol('newCrossSignedIssuer')} a`); await click(`${PKI_CROSS_SIGN.signedIssuerCol('newCrossSignedIssuer')} a`);
const newIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-test-copy-button'); const newIntCert = find(PKI_CROSS_SIGN.copyButton('Certificate')).getAttribute('data-test-copy-button');
// verify cross-sign was accurate by creating a role to issue a leaf certificate // verify cross-sign was accurate by creating a role to issue a leaf certificate
const myRole = 'some-role'; const myRole = 'some-role';
@ -95,10 +101,10 @@ module('Acceptance | pki/pki cross sign', function (hooks) {
max_ttl="720h"`, max_ttl="720h"`,
]); ]);
await visit(`vault/secrets/${this.intMountPath}/pki/roles/${myRole}/generate`); await visit(`vault/secrets/${this.intMountPath}/pki/roles/${myRole}/generate`);
await fillIn(SELECTORS.inputByName('commonName'), 'my-leaf'); await fillIn(GENERAL.inputByAttr('commonName'), 'my-leaf');
await fillIn('[data-test-ttl-value="TTL"]', '3600'); await fillIn('[data-test-ttl-value="TTL"]', '3600');
await click('[data-test-pki-generate-button]'); await click(GENERAL.saveButton);
const myLeafCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-test-copy-button'); const myLeafCert = find(PKI_CROSS_SIGN.copyButton('Certificate')).getAttribute('data-test-copy-button');
// see comments in utils/parse-pki-cert.js for step-by-step explanation of of verifyCertificates method // see comments in utils/parse-pki-cert.js for step-by-step explanation of of verifyCertificates method
assert.true( assert.true(

View File

@ -12,10 +12,19 @@ import logout from 'vault/tests/pages/logout';
import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { click, currentURL, fillIn, visit } from '@ember/test-helpers'; import { click, currentURL, fillIn, visit } from '@ember/test-helpers';
import { runCmd } from 'vault/tests/helpers/commands'; import { runCmd } from 'vault/tests/helpers/commands';
import { SELECTORS } from 'vault/tests/helpers/pki/workflow'; import { GENERAL } from 'vault/tests/helpers/general-selectors';
import {
PKI_CONFIGURE_CREATE,
PKI_ISSUER_DETAILS,
PKI_ISSUER_LIST,
PKI_KEYS,
PKI_ROLE_DETAILS,
} from 'vault/tests/helpers/pki/pki-selectors';
const OVERVIEW_BREADCRUMB = '[data-test-breadcrumbs] li:nth-of-type(2) > a';
/** /**
* This test module should test that dirty route models are cleaned up when the user leaves the page * This test module should test that dirty route models are cleaned up when
* the user leaves the page via cancel or breadcrumb navigation
*/ */
module('Acceptance | pki engine route cleanup test', function (hooks) { module('Acceptance | pki engine route cleanup test', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@ -42,7 +51,7 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let configs, urls, config; let configs, urls, config;
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.emptyStateLink); await click(`${GENERAL.emptyStateActions} a`);
configs = this.store.peekAll('pki/action'); configs = this.store.peekAll('pki/action');
urls = this.store.peekRecord('pki/config/urls', this.mountPath); urls = this.store.peekRecord('pki/config/urls', this.mountPath);
config = configs.at(0); config = configs.at(0);
@ -51,13 +60,13 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
assert.true(config.hasDirtyAttributes, 'Config model is dirty'); assert.true(config.hasDirtyAttributes, 'Config model is dirty');
// Cancel button rolls it back // Cancel button rolls it back
await click(SELECTORS.configuration.cancelButton); await click(GENERAL.cancelButton);
configs = this.store.peekAll('pki/action'); configs = this.store.peekAll('pki/action');
urls = this.store.peekRecord('pki/config/urls', this.mountPath); urls = this.store.peekRecord('pki/config/urls', this.mountPath);
assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel'); assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel');
assert.strictEqual(urls.id, this.mountPath, 'Urls still exists on exit'); assert.strictEqual(urls.id, this.mountPath, 'Urls still exists on exit');
await click(SELECTORS.emptyStateLink); await click(`${GENERAL.emptyStateActions} a`);
configs = this.store.peekAll('pki/action'); configs = this.store.peekAll('pki/action');
urls = this.store.peekRecord('pki/config/urls', this.mountPath); urls = this.store.peekRecord('pki/config/urls', this.mountPath);
config = configs.at(0); config = configs.at(0);
@ -66,7 +75,7 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
assert.true(config.hasDirtyAttributes, 'Config model is dirty'); assert.true(config.hasDirtyAttributes, 'Config model is dirty');
// Exit page via link rolls it back // Exit page via link rolls it back
await click(SELECTORS.overviewBreadcrumb); await click(OVERVIEW_BREADCRUMB);
configs = this.store.peekAll('pki/action'); configs = this.store.peekAll('pki/action');
urls = this.store.peekRecord('pki/config/urls', this.mountPath); urls = this.store.peekRecord('pki/config/urls', this.mountPath);
assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel'); assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel');
@ -79,11 +88,11 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
await authPage.login(); await authPage.login();
// Configure PKI // Configure PKI
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.emptyStateLink); await click(`${GENERAL.emptyStateActions} a`);
await click(SELECTORS.configuration.optionByKey('generate-root')); await click(PKI_CONFIGURE_CREATE.optionByKey('generate-root'));
await fillIn(SELECTORS.configuration.typeField, 'internal'); await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-root-cert'); await fillIn(GENERAL.inputByAttr('commonName'), 'my-root-cert');
await click(SELECTORS.configuration.generateRootSave); await click(GENERAL.saveButton);
await logout.visit(); await logout.visit();
}); });
@ -92,15 +101,15 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
await authPage.login(); await authPage.login();
// Create PKI // Create PKI
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.rolesTab); await click(GENERAL.secretTab('Roles'));
roles = this.store.peekAll('pki/role'); roles = this.store.peekAll('pki/role');
assert.strictEqual(roles.length, 0, 'No roles exist yet'); assert.strictEqual(roles.length, 0, 'No roles exist yet');
await click(SELECTORS.createRoleLink); await click(PKI_ROLE_DETAILS.createRoleLink);
roles = this.store.peekAll('pki/role'); roles = this.store.peekAll('pki/role');
const role = roles.at(0); const role = roles.at(0);
assert.strictEqual(roles.length, 1, 'New role exists'); assert.strictEqual(roles.length, 1, 'New role exists');
assert.true(role.isNew, 'Role is new model'); assert.true(role.isNew, 'Role is new model');
await click(SELECTORS.roleForm.roleCancelButton); await click(GENERAL.cancelButton);
roles = this.store.peekAll('pki/role'); roles = this.store.peekAll('pki/role');
assert.strictEqual(roles.length, 0, 'Role is removed from store'); assert.strictEqual(roles.length, 0, 'Role is removed from store');
}); });
@ -109,15 +118,15 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
await authPage.login(); await authPage.login();
// Create PKI // Create PKI
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.rolesTab); await click(GENERAL.secretTab('Roles'));
roles = this.store.peekAll('pki/role'); roles = this.store.peekAll('pki/role');
assert.strictEqual(roles.length, 0, 'No roles exist yet'); assert.strictEqual(roles.length, 0, 'No roles exist yet');
await click(SELECTORS.createRoleLink); await click(PKI_ROLE_DETAILS.createRoleLink);
roles = this.store.peekAll('pki/role'); roles = this.store.peekAll('pki/role');
const role = roles.at(0); const role = roles.at(0);
assert.strictEqual(roles.length, 1, 'New role exists'); assert.strictEqual(roles.length, 1, 'New role exists');
assert.true(role.isNew, 'Role is new model'); assert.true(role.isNew, 'Role is new model');
await click(SELECTORS.overviewBreadcrumb); await click(OVERVIEW_BREADCRUMB);
roles = this.store.peekAll('pki/role'); roles = this.store.peekAll('pki/role');
assert.strictEqual(roles.length, 0, 'Role is removed from store'); assert.strictEqual(roles.length, 0, 'Role is removed from store');
}); });
@ -127,38 +136,38 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
await authPage.login(); await authPage.login();
// Create PKI // Create PKI
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.rolesTab); await click(GENERAL.secretTab('Roles'));
roles = this.store.peekAll('pki/role'); roles = this.store.peekAll('pki/role');
assert.strictEqual(roles.length, 0, 'No roles exist yet'); assert.strictEqual(roles.length, 0, 'No roles exist yet');
await click(SELECTORS.createRoleLink); await click(PKI_ROLE_DETAILS.createRoleLink);
await fillIn(SELECTORS.roleForm.roleName, roleId); await fillIn(GENERAL.inputByAttr('name'), roleId);
await click(SELECTORS.roleForm.roleCreateButton); await click(GENERAL.saveButton);
assert.dom('[data-test-value-div="Role name"]').hasText(roleId, 'Shows correct role after create'); assert.dom(GENERAL.infoRowValue('Role name')).hasText(roleId, 'Shows correct role after create');
roles = this.store.peekAll('pki/role'); roles = this.store.peekAll('pki/role');
role = roles.at(0); role = roles.at(0);
assert.strictEqual(roles.length, 1, 'Role is created'); assert.strictEqual(roles.length, 1, 'Role is created');
assert.false(role.hasDirtyAttributes, 'Role no longer has dirty attributes'); assert.false(role.hasDirtyAttributes, 'Role no longer has dirty attributes');
// Edit role // Edit role
await click(SELECTORS.editRoleLink); await click(PKI_ROLE_DETAILS.editRoleLink);
await click(SELECTORS.roleForm.issuerRefToggle); await click(GENERAL.ttl.toggle('issuerRef-toggle'));
await fillIn(SELECTORS.roleForm.issuerRefSelect, 'foobar'); await fillIn(GENERAL.selectByAttr('issuerRef'), 'foobar');
role = this.store.peekRecord('pki/role', roleId); role = this.store.peekRecord('pki/role', roleId);
assert.true(role.hasDirtyAttributes, 'Role has dirty attrs'); assert.true(role.hasDirtyAttributes, 'Role has dirty attrs');
// Exit page via cancel button // Exit page via cancel button
await click(SELECTORS.roleForm.roleCancelButton); await click(GENERAL.cancelButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/${roleId}/details`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/${roleId}/details`);
role = this.store.peekRecord('pki/role', roleId); role = this.store.peekRecord('pki/role', roleId);
assert.false(role.hasDirtyAttributes, 'Role dirty attrs have been rolled back'); assert.false(role.hasDirtyAttributes, 'Role dirty attrs have been rolled back');
// Edit again // Edit again
await click(SELECTORS.editRoleLink); await click(PKI_ROLE_DETAILS.editRoleLink);
await click(SELECTORS.roleForm.issuerRefToggle); await click(GENERAL.ttl.toggle('issuerRef-toggle'));
await fillIn(SELECTORS.roleForm.issuerRefSelect, 'foobar2'); await fillIn(GENERAL.selectByAttr('issuerRef'), 'foobar2');
role = this.store.peekRecord('pki/role', roleId); role = this.store.peekRecord('pki/role', roleId);
assert.true(role.hasDirtyAttributes, 'Role has dirty attrs'); assert.true(role.hasDirtyAttributes, 'Role has dirty attrs');
// Exit page via breadcrumbs // Exit page via breadcrumbs
await click(SELECTORS.overviewBreadcrumb); await click(OVERVIEW_BREADCRUMB);
role = this.store.peekRecord('pki/role', roleId); role = this.store.peekRecord('pki/role', roleId);
assert.false(role.hasDirtyAttributes, 'Role dirty attrs have been rolled back'); assert.false(role.hasDirtyAttributes, 'Role dirty attrs have been rolled back');
}); });
@ -169,10 +178,10 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let issuers; let issuers;
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
issuers = this.store.peekAll('pki/issuer'); issuers = this.store.peekAll('pki/issuer');
assert.strictEqual(issuers.length, 0, 'No issuer models exist yet'); assert.strictEqual(issuers.length, 0, 'No issuer models exist yet');
await click(SELECTORS.importIssuerLink); await click(PKI_ISSUER_LIST.importIssuerLink);
issuers = this.store.peekAll('pki/action'); issuers = this.store.peekAll('pki/action');
assert.strictEqual(issuers.length, 1, 'Action model created'); assert.strictEqual(issuers.length, 1, 'Action model created');
const issuer = issuers.at(0); const issuer = issuers.at(0);
@ -188,17 +197,17 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let issuers; let issuers;
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
issuers = this.store.peekAll('pki/issuer'); issuers = this.store.peekAll('pki/issuer');
assert.strictEqual(issuers.length, 0, 'No issuers exist yet'); assert.strictEqual(issuers.length, 0, 'No issuers exist yet');
await click(SELECTORS.importIssuerLink); await click(PKI_ISSUER_LIST.importIssuerLink);
issuers = this.store.peekAll('pki/action'); issuers = this.store.peekAll('pki/action');
assert.strictEqual(issuers.length, 1, 'Action model created'); assert.strictEqual(issuers.length, 1, 'Action model created');
const issuer = issuers.at(0); const issuer = issuers.at(0);
assert.true(issuer.hasDirtyAttributes, 'Action model has dirty attrs'); assert.true(issuer.hasDirtyAttributes, 'Action model has dirty attrs');
assert.true(issuer.isNew, 'Action model is new'); assert.true(issuer.isNew, 'Action model is new');
// Exit // Exit
await click(SELECTORS.overviewBreadcrumb); await click(OVERVIEW_BREADCRUMB);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
issuers = this.store.peekAll('pki/action'); issuers = this.store.peekAll('pki/action');
assert.strictEqual(issuers.length, 0, 'Issuer is removed from store'); assert.strictEqual(issuers.length, 0, 'Issuer is removed from store');
@ -207,11 +216,11 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let actions; let actions;
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'No actions exist yet'); assert.strictEqual(actions.length, 0, 'No actions exist yet');
await click(SELECTORS.generateIssuerDropdown); await click(PKI_ISSUER_LIST.generateIssuerDropdown);
await click(SELECTORS.generateIssuerRoot); await click(PKI_ISSUER_LIST.generateIssuerRoot);
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 1, 'Action model for generate-root created'); assert.strictEqual(actions.length, 1, 'Action model for generate-root created');
const action = actions.at(0); const action = actions.at(0);
@ -219,7 +228,7 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
assert.true(action.isNew, 'Action is new'); assert.true(action.isNew, 'Action is new');
assert.strictEqual(action.actionType, 'generate-root', 'Action type is correct'); assert.strictEqual(action.actionType, 'generate-root', 'Action type is correct');
// Exit // Exit
await click(SELECTORS.configuration.generateRootCancel); await click(GENERAL.cancelButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`);
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'Action is removed from store'); assert.strictEqual(actions.length, 0, 'Action is removed from store');
@ -228,11 +237,11 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let actions; let actions;
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'No actions exist yet'); assert.strictEqual(actions.length, 0, 'No actions exist yet');
await click(SELECTORS.generateIssuerDropdown); await click(PKI_ISSUER_LIST.generateIssuerDropdown);
await click(SELECTORS.generateIssuerRoot); await click(PKI_ISSUER_LIST.generateIssuerRoot);
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 1, 'Action model for generate-root created'); assert.strictEqual(actions.length, 1, 'Action model for generate-root created');
const action = actions.at(0); const action = actions.at(0);
@ -240,7 +249,7 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
assert.true(action.isNew, 'Action is new'); assert.true(action.isNew, 'Action is new');
assert.strictEqual(action.actionType, 'generate-root'); assert.strictEqual(action.actionType, 'generate-root');
// Exit // Exit
await click(SELECTORS.overviewBreadcrumb); await click(OVERVIEW_BREADCRUMB);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'Action is removed from store'); assert.strictEqual(actions.length, 0, 'Action is removed from store');
@ -249,11 +258,11 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let actions; let actions;
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'No actions exist yet'); assert.strictEqual(actions.length, 0, 'No actions exist yet');
await await click(SELECTORS.generateIssuerDropdown); await await click(PKI_ISSUER_LIST.generateIssuerDropdown);
await click(SELECTORS.generateIssuerIntermediate); await click(PKI_ISSUER_LIST.generateIssuerIntermediate);
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 1, 'Action model for generate-csr created'); assert.strictEqual(actions.length, 1, 'Action model for generate-csr created');
const action = actions.at(0); const action = actions.at(0);
@ -270,11 +279,11 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let actions; let actions;
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'No actions exist yet'); assert.strictEqual(actions.length, 0, 'No actions exist yet');
await click(SELECTORS.generateIssuerDropdown); await click(PKI_ISSUER_LIST.generateIssuerDropdown);
await click(SELECTORS.generateIssuerIntermediate); await click(PKI_ISSUER_LIST.generateIssuerIntermediate);
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 1, 'Action model for generate-csr created'); assert.strictEqual(actions.length, 1, 'Action model for generate-csr created');
const action = actions.at(0); const action = actions.at(0);
@ -282,7 +291,7 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
assert.true(action.isNew, 'Action is new'); assert.true(action.isNew, 'Action is new');
assert.strictEqual(action.actionType, 'generate-csr'); assert.strictEqual(action.actionType, 'generate-csr');
// Exit // Exit
await click(SELECTORS.overviewBreadcrumb); await click(OVERVIEW_BREADCRUMB);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
actions = this.store.peekAll('pki/action'); actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'Action is removed from store'); assert.strictEqual(actions.length, 0, 'Action is removed from store');
@ -291,11 +300,11 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let issuers, issuer; let issuers, issuer;
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.emptyStateLink); await click(`${GENERAL.emptyStateActions} a`);
await click(SELECTORS.configuration.optionByKey('generate-root')); await click(PKI_CONFIGURE_CREATE.optionByKey('generate-root'));
await fillIn(SELECTORS.configuration.typeField, 'internal'); await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-root-cert'); await fillIn(GENERAL.inputByAttr('commonName'), 'my-root-cert');
await click(SELECTORS.configuration.generateRootSave); await click(GENERAL.saveButton);
// Go to list view so we fetch all the issuers // Go to list view so we fetch all the issuers
await visit(`/vault/secrets/${this.mountPath}/pki/issuers`); await visit(`/vault/secrets/${this.mountPath}/pki/issuers`);
@ -303,12 +312,12 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
const issuerId = issuers.at(0).id; const issuerId = issuers.at(0).id;
assert.strictEqual(issuers.length, 1, 'Issuer exists on model in list'); assert.strictEqual(issuers.length, 1, 'Issuer exists on model in list');
await visit(`/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/details`); await visit(`/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/details`);
await click(SELECTORS.issuerDetails.configure); await click(PKI_ISSUER_DETAILS.configure);
issuer = this.store.peekRecord('pki/issuer', issuerId); issuer = this.store.peekRecord('pki/issuer', issuerId);
assert.false(issuer.hasDirtyAttributes, 'Model not dirty'); assert.false(issuer.hasDirtyAttributes, 'Model not dirty');
await fillIn('[data-test-input="issuerName"]', 'foobar'); await fillIn('[data-test-input="issuerName"]', 'foobar');
assert.true(issuer.hasDirtyAttributes, 'Model is dirty'); assert.true(issuer.hasDirtyAttributes, 'Model is dirty');
await click(SELECTORS.overviewBreadcrumb); await click(OVERVIEW_BREADCRUMB);
issuers = this.store.peekAll('pki/issuer'); issuers = this.store.peekAll('pki/issuer');
assert.strictEqual(issuers.length, 1, 'Issuer exists on model in overview'); assert.strictEqual(issuers.length, 1, 'Issuer exists on model in overview');
issuer = this.store.peekRecord('pki/issuer', issuerId); issuer = this.store.peekRecord('pki/issuer', issuerId);
@ -321,42 +330,42 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
await authPage.login(); await authPage.login();
// Configure PKI -- key creation not allowed unless configured // Configure PKI -- key creation not allowed unless configured
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.emptyStateLink); await click(`${GENERAL.emptyStateActions} a`);
await click(SELECTORS.configuration.optionByKey('generate-root')); await click(PKI_CONFIGURE_CREATE.optionByKey('generate-root'));
await fillIn(SELECTORS.configuration.typeField, 'internal'); await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-root-cert'); await fillIn(GENERAL.inputByAttr('commonName'), 'my-root-cert');
await click(SELECTORS.configuration.generateRootSave); await click(GENERAL.saveButton);
await logout.visit(); await logout.visit();
}); });
test('create key exit', async function (assert) { test('create key exit', async function (assert) {
let keys, key; let keys, key;
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.keysTab); await click(GENERAL.secretTab('Keys'));
keys = this.store.peekAll('pki/key'); keys = this.store.peekAll('pki/key');
const configKeyId = keys.at(0).id; const configKeyId = keys.at(0).id;
assert.strictEqual(keys.length, 1, 'One key exists from config'); assert.strictEqual(keys.length, 1, 'One key exists from config');
// Create key // Create key
await click(SELECTORS.keyPages.generateKey); await click(PKI_KEYS.generateKey);
keys = this.store.peekAll('pki/key'); keys = this.store.peekAll('pki/key');
key = keys.at(1); key = keys.at(1);
assert.strictEqual(keys.length, 2, 'New key exists'); assert.strictEqual(keys.length, 2, 'New key exists');
assert.true(key.isNew, 'Role is new model'); assert.true(key.isNew, 'Role is new model');
// Exit // Exit
await click(SELECTORS.keyForm.keyCancelButton); await click(GENERAL.cancelButton);
keys = this.store.peekAll('pki/key'); keys = this.store.peekAll('pki/key');
assert.strictEqual(keys.length, 1, 'Second key is removed from store'); assert.strictEqual(keys.length, 1, 'Second key is removed from store');
assert.strictEqual(keys.at(0).id, configKeyId); assert.strictEqual(keys.at(0).id, configKeyId);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`, 'url is correct'); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`, 'url is correct');
// Create again // Create again
await click(SELECTORS.keyPages.generateKey); await click(PKI_KEYS.generateKey);
assert.strictEqual(keys.length, 2, 'New key exists'); assert.strictEqual(keys.length, 2, 'New key exists');
keys = this.store.peekAll('pki/key'); keys = this.store.peekAll('pki/key');
key = keys.at(1); key = keys.at(1);
assert.true(key.isNew, 'Key is new model'); assert.true(key.isNew, 'Key is new model');
// Exit // Exit
await click(SELECTORS.overviewBreadcrumb); await click(OVERVIEW_BREADCRUMB);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`, 'url is correct'); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`, 'url is correct');
keys = this.store.peekAll('pki/key'); keys = this.store.peekAll('pki/key');
assert.strictEqual(keys.length, 1, 'Key is removed from store'); assert.strictEqual(keys.length, 1, 'Key is removed from store');
@ -365,19 +374,19 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let keys, key; let keys, key;
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.keysTab); await click(GENERAL.secretTab('Keys'));
keys = this.store.peekAll('pki/key'); keys = this.store.peekAll('pki/key');
assert.strictEqual(keys.length, 1, 'One key from config exists'); assert.strictEqual(keys.length, 1, 'One key from config exists');
assert.dom('.list-item-row').exists({ count: 1 }, 'single row for key'); assert.dom('.list-item-row').exists({ count: 1 }, 'single row for key');
await click('.list-item-row'); await click('.list-item-row');
// Edit // Edit
await click(SELECTORS.keyPages.keyEditLink); await click(PKI_KEYS.keyEditLink);
await fillIn(SELECTORS.keyForm.keyNameInput, 'foobar'); await fillIn(GENERAL.inputByAttr('keyName'), 'foobar');
keys = this.store.peekAll('pki/key'); keys = this.store.peekAll('pki/key');
key = keys.at(0); key = keys.at(0);
assert.true(key.hasDirtyAttributes, 'Key model is dirty'); assert.true(key.hasDirtyAttributes, 'Key model is dirty');
// Exit // Exit
await click(SELECTORS.keyForm.keyCancelButton); await click(GENERAL.cancelButton);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/keys/${key.id}/details`, `/vault/secrets/${this.mountPath}/pki/keys/${key.id}/details`,
@ -388,14 +397,14 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
assert.false(key.hasDirtyAttributes, 'Key dirty attrs have been rolled back'); assert.false(key.hasDirtyAttributes, 'Key dirty attrs have been rolled back');
// Edit again // Edit again
await click(SELECTORS.keyPages.keyEditLink); await click(PKI_KEYS.keyEditLink);
await fillIn(SELECTORS.keyForm.keyNameInput, 'foobar'); await fillIn(GENERAL.inputByAttr('keyName'), 'foobar');
keys = this.store.peekAll('pki/key'); keys = this.store.peekAll('pki/key');
key = keys.at(0); key = keys.at(0);
assert.true(key.hasDirtyAttributes, 'Key model is dirty'); assert.true(key.hasDirtyAttributes, 'Key model is dirty');
// Exit via breadcrumb // Exit via breadcrumb
await click(SELECTORS.overviewBreadcrumb); await click(OVERVIEW_BREADCRUMB);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`, 'url is correct'); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`, 'url is correct');
keys = this.store.peekAll('pki/key'); keys = this.store.peekAll('pki/key');
assert.strictEqual(keys.length, 1, 'Key list has 1'); assert.strictEqual(keys.length, 1, 'Key list has 1');

View File

@ -11,14 +11,23 @@ import authPage from 'vault/tests/pages/auth';
import logout from 'vault/tests/pages/logout'; import logout from 'vault/tests/pages/logout';
import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { click, currentURL, fillIn, find, isSettled, visit } from '@ember/test-helpers'; import { click, currentURL, fillIn, find, isSettled, visit } from '@ember/test-helpers';
import { SELECTORS } from 'vault/tests/helpers/pki/workflow'; import { adminPolicy, readerPolicy, updatePolicy } from 'vault/tests/helpers/pki/policy-generator';
import { adminPolicy, readerPolicy, updatePolicy } from 'vault/tests/helpers/policy-generator/pki';
import { clearRecords } from 'vault/tests/helpers/pki/pki-run-commands';
import { runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands'; import { runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands';
import { unsupportedPem } from 'vault/tests/helpers/pki/values';
import { create } from 'ember-cli-page-object'; import { create } from 'ember-cli-page-object';
import flashMessage from 'vault/tests/pages/components/flash-message'; import flashMessage from 'vault/tests/pages/components/flash-message';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { CERTIFICATES, clearRecords } from 'vault/tests/helpers/pki/pki-helpers';
import {
PKI_CONFIGURE_CREATE,
PKI_CONFIG_EDIT,
PKI_ISSUER_DETAILS,
PKI_ISSUER_LIST,
PKI_KEYS,
PKI_ROLE_DETAILS,
} from 'vault/tests/helpers/pki/pki-selectors';
const flash = create(flashMessage); const flash = create(flashMessage);
const { unsupportedPem } = CERTIFICATES;
/** /**
* This test module should test the PKI workflow, including: * This test module should test the PKI workflow, including:
* - link between pages and confirm that the url is as expected * - link between pages and confirm that the url is as expected
@ -59,14 +68,14 @@ module('Acceptance | pki workflow', function (hooks) {
const assertEmptyState = (assert, resource) => { const assertEmptyState = (assert, resource) => {
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/${resource}`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/${resource}`);
assert assert
.dom(SELECTORS.emptyStateTitle) .dom(GENERAL.emptyStateTitle)
.hasText( .hasText(
'PKI not configured', 'PKI not configured',
`${resource} index renders correct empty state title when PKI not configured` `${resource} index renders correct empty state title when PKI not configured`
); );
assert.dom(SELECTORS.emptyStateLink).hasText('Configure PKI'); assert.dom(GENERAL.emptyStateActions).hasText('Configure PKI');
assert assert
.dom(SELECTORS.emptyStateMessage) .dom(GENERAL.emptyStateMessage)
.hasText( .hasText(
`This PKI mount hasn't yet been configured with a certificate issuer.`, `This PKI mount hasn't yet been configured with a certificate issuer.`,
`${resource} index empty state message correct when PKI not configured` `${resource} index empty state message correct when PKI not configured`
@ -76,17 +85,17 @@ module('Acceptance | pki workflow', function (hooks) {
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.rolesTab); await click(GENERAL.secretTab('Roles'));
assertEmptyState(assert, 'roles'); assertEmptyState(assert, 'roles');
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
assertEmptyState(assert, 'issuers'); assertEmptyState(assert, 'issuers');
await click(SELECTORS.certsTab); await click(GENERAL.secretTab('Certificates'));
assertEmptyState(assert, 'certificates'); assertEmptyState(assert, 'certificates');
await click(SELECTORS.keysTab); await click(GENERAL.secretTab('Keys'));
assertEmptyState(assert, 'keys'); assertEmptyState(assert, 'keys');
await click(SELECTORS.tidyTab); await click(GENERAL.secretTab('Tidy'));
assertEmptyState(assert, 'tidy'); assertEmptyState(assert, 'tidy');
}); });
}); });
@ -121,32 +130,32 @@ module('Acceptance | pki workflow', function (hooks) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesTab).exists('Roles tab is present'); assert.dom(GENERAL.secretTab('Roles')).exists('Roles tab is present');
await click(SELECTORS.rolesTab); await click(GENERAL.secretTab('Roles'));
assert.dom(SELECTORS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered'); assert.dom(PKI_ROLE_DETAILS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered');
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`);
assert.dom('.linked-block').exists({ count: 1 }, 'One role is in list'); assert.dom('.linked-block').exists({ count: 1 }, 'One role is in list');
await click('.linked-block'); await click('.linked-block');
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/details`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/details`);
assert.dom(SELECTORS.generateCertLink).exists('Generate cert link is shown'); assert.dom(PKI_ROLE_DETAILS.generateCertLink).exists('Generate cert link is shown');
await click(SELECTORS.generateCertLink); await click(PKI_ROLE_DETAILS.generateCertLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/generate`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/generate`);
// Go back to details and test all the links // Go back to details and test all the links
await visit(`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`); await visit(`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`);
assert.dom(SELECTORS.signCertLink).exists('Sign cert link is shown'); assert.dom(PKI_ROLE_DETAILS.signCertLink).exists('Sign cert link is shown');
await click(SELECTORS.signCertLink); await click(PKI_ROLE_DETAILS.signCertLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/sign`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/sign`);
await visit(`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`); await visit(`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`);
assert.dom(SELECTORS.editRoleLink).exists('Edit link is shown'); assert.dom(PKI_ROLE_DETAILS.editRoleLink).exists('Edit link is shown');
await click(SELECTORS.editRoleLink); await click(PKI_ROLE_DETAILS.editRoleLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/edit`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/edit`);
await visit(`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`); await visit(`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`);
assert.dom(SELECTORS.deleteRoleButton).exists('Delete role button is shown'); assert.dom(PKI_ROLE_DETAILS.deleteRoleButton).exists('Delete role button is shown');
await click(SELECTORS.deleteRoleButton); await click(PKI_ROLE_DETAILS.deleteRoleButton);
await click('[data-test-confirm-button]'); await click('[data-test-confirm-button]');
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
@ -158,52 +167,52 @@ module('Acceptance | pki workflow', function (hooks) {
test('it does not show toolbar items the user does not have permission to see', async function (assert) { test('it does not show toolbar items the user does not have permission to see', async function (assert) {
await authPage.login(this.pkiRoleReader); await authPage.login(this.pkiRoleReader);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesTab).exists('Roles tab is present'); assert.dom(GENERAL.secretTab('Roles')).exists('Roles tab is present');
await click(SELECTORS.rolesTab); await click(GENERAL.secretTab('Roles'));
assert.dom(SELECTORS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered'); assert.dom(PKI_ROLE_DETAILS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered');
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`);
assert.dom('.linked-block').exists({ count: 1 }, 'One role is in list'); assert.dom('.linked-block').exists({ count: 1 }, 'One role is in list');
await click('.linked-block'); await click('.linked-block');
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/details`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/details`);
assert.dom(SELECTORS.deleteRoleButton).doesNotExist('Delete role button is not shown'); assert.dom(PKI_ROLE_DETAILS.deleteRoleButton).doesNotExist('Delete role button is not shown');
assert.dom(SELECTORS.generateCertLink).doesNotExist('Generate cert link is not shown'); assert.dom(PKI_ROLE_DETAILS.generateCertLink).doesNotExist('Generate cert link is not shown');
assert.dom(SELECTORS.signCertLink).doesNotExist('Sign cert link is not shown'); assert.dom(PKI_ROLE_DETAILS.signCertLink).doesNotExist('Sign cert link is not shown');
assert.dom(SELECTORS.editRoleLink).doesNotExist('Edit link is not shown'); assert.dom(PKI_ROLE_DETAILS.editRoleLink).doesNotExist('Edit link is not shown');
}); });
test('it shows correct toolbar items for the user policy', async function (assert) { test('it shows correct toolbar items for the user policy', async function (assert) {
await authPage.login(this.pkiRoleEditor); await authPage.login(this.pkiRoleEditor);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesTab).exists('Roles tab is present'); assert.dom(GENERAL.secretTab('Roles')).exists('Roles tab is present');
await click(SELECTORS.rolesTab); await click(GENERAL.secretTab('Roles'));
assert.dom(SELECTORS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered'); assert.dom(PKI_ROLE_DETAILS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered');
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`);
assert.dom('.linked-block').exists({ count: 1 }, 'One role is in list'); assert.dom('.linked-block').exists({ count: 1 }, 'One role is in list');
await click('.linked-block'); await click('.linked-block');
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/details`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/details`);
assert.dom(SELECTORS.deleteRoleButton).doesNotExist('Delete role button is not shown'); assert.dom(PKI_ROLE_DETAILS.deleteRoleButton).doesNotExist('Delete role button is not shown');
assert.dom(SELECTORS.generateCertLink).exists('Generate cert link is shown'); assert.dom(PKI_ROLE_DETAILS.generateCertLink).exists('Generate cert link is shown');
assert.dom(SELECTORS.signCertLink).exists('Sign cert link is shown'); assert.dom(PKI_ROLE_DETAILS.signCertLink).exists('Sign cert link is shown');
assert.dom(SELECTORS.editRoleLink).exists('Edit link is shown'); assert.dom(PKI_ROLE_DETAILS.editRoleLink).exists('Edit link is shown');
await click(SELECTORS.editRoleLink); await click(PKI_ROLE_DETAILS.editRoleLink);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/roles/some-role/edit`, `/vault/secrets/${this.mountPath}/pki/roles/some-role/edit`,
'Links to edit view' 'Links to edit view'
); );
await click(SELECTORS.roleForm.roleCancelButton); await click(GENERAL.cancelButton);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`, `/vault/secrets/${this.mountPath}/pki/roles/some-role/details`,
'Cancel from edit goes to details' 'Cancel from edit goes to details'
); );
await click(SELECTORS.generateCertLink); await click(PKI_ROLE_DETAILS.generateCertLink);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/roles/some-role/generate`, `/vault/secrets/${this.mountPath}/pki/roles/some-role/generate`,
'Generate cert button goes to generate page' 'Generate cert button goes to generate page'
); );
await click(SELECTORS.generateCertForm.cancelButton); await click(GENERAL.cancelButton);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`, `/vault/secrets/${this.mountPath}/pki/roles/some-role/details`,
@ -216,25 +225,25 @@ module('Acceptance | pki workflow', function (hooks) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.emptyState).doesNotExist(); assert.dom(GENERAL.emptyStateTitle).doesNotExist();
await click(SELECTORS.rolesTab); await click(GENERAL.secretTab('Roles'));
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`);
await click(SELECTORS.createRoleLink); await click(PKI_ROLE_DETAILS.createRoleLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/create`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/create`);
assert.dom(SELECTORS.breadcrumbContainer).exists({ count: 1 }, 'breadcrumbs are rendered'); assert.dom(GENERAL.breadcrumbs).exists({ count: 1 }, 'breadcrumbs are rendered');
assert.dom(SELECTORS.breadcrumbs).exists({ count: 4 }, 'Shows 4 breadcrumbs'); assert.dom(GENERAL.breadcrumb).exists({ count: 4 }, 'Shows 4 breadcrumbs');
assert.dom(SELECTORS.pageTitle).hasText('Create a PKI Role'); assert.dom(GENERAL.title).hasText('Create a PKI Role');
await fillIn(SELECTORS.roleForm.roleName, roleName); await fillIn(GENERAL.inputByAttr('name'), roleName);
await click(SELECTORS.roleForm.roleCreateButton); await click(GENERAL.saveButton);
assert.strictEqual( assert.strictEqual(
flash.latestMessage, flash.latestMessage,
`Successfully created the role ${roleName}.`, `Successfully created the role ${roleName}.`,
'renders success flash upon creation' 'renders success flash upon creation'
); );
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/${roleName}/details`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/${roleName}/details`);
assert.dom(SELECTORS.breadcrumbs).exists({ count: 4 }, 'Shows 4 breadcrumbs'); assert.dom(GENERAL.breadcrumb).exists({ count: 4 }, 'Shows 4 breadcrumbs');
assert.dom(SELECTORS.pageTitle).hasText(`PKI Role ${roleName}`); assert.dom(GENERAL.title).hasText(`PKI Role ${roleName}`);
}); });
}); });
@ -257,61 +266,61 @@ module('Acceptance | pki workflow', function (hooks) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.keysTab); await click(GENERAL.secretTab('Keys'));
// index page // index page
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`);
assert assert
.dom(SELECTORS.keyPages.importKey) .dom(PKI_KEYS.importKey)
.hasAttribute( .hasAttribute(
'href', 'href',
`/ui/vault/secrets/${this.mountPath}/pki/keys/import`, `/ui/vault/secrets/${this.mountPath}/pki/keys/import`,
'import link renders with correct url' 'import link renders with correct url'
); );
let keyId = find(SELECTORS.keyPages.keyId).innerText; let keyId = find(PKI_KEYS.keyId).innerText;
assert.dom('.linked-block').exists({ count: 1 }, 'One key is in list'); assert.dom('.linked-block').exists({ count: 1 }, 'One key is in list');
await click('.linked-block'); await click('.linked-block');
// details page // details page
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`);
assert.dom(SELECTORS.keyPages.downloadButton).doesNotExist('does not download button for private key'); assert.dom(PKI_KEYS.downloadButton).doesNotExist('does not download button for private key');
// edit page // edit page
await click(SELECTORS.keyPages.keyEditLink); await click(PKI_KEYS.keyEditLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/edit`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/edit`);
await click(SELECTORS.keyForm.keyCancelButton); await click(GENERAL.cancelButton);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`, `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`,
'navigates back to details on cancel' 'navigates back to details on cancel'
); );
await visit(`/vault/secrets/${this.mountPath}/pki/keys/${keyId}/edit`); await visit(`/vault/secrets/${this.mountPath}/pki/keys/${keyId}/edit`);
await fillIn(SELECTORS.keyForm.keyNameInput, 'test-key'); await fillIn(GENERAL.inputByAttr('keyName'), 'test-key');
await click(SELECTORS.keyForm.keyCreateButton); await click(GENERAL.saveButton);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`, `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`,
'navigates to details after save' 'navigates to details after save'
); );
assert.dom(SELECTORS.keyPages.keyNameValue).hasText('test-key', 'updates key name'); assert.dom(GENERAL.infoRowValue('Key name')).hasText('test-key', 'updates key name');
// key generate and delete navigation // key generate and delete navigation
await visit(`/vault/secrets/${this.mountPath}/pki/keys`); await visit(`/vault/secrets/${this.mountPath}/pki/keys`);
await click(SELECTORS.keyPages.generateKey); await click(PKI_KEYS.generateKey);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/create`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/create`);
await fillIn(SELECTORS.keyForm.typeInput, 'exported'); await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(SELECTORS.keyForm.keyTypeInput, 'rsa'); await fillIn(GENERAL.inputByAttr('keyType'), 'rsa');
await click(SELECTORS.keyForm.keyCreateButton); await click(GENERAL.saveButton);
keyId = find(SELECTORS.keyPages.keyIdValue).innerText; 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/${keyId}/details`);
assert assert
.dom(SELECTORS.keyPages.nextStepsAlert) .dom(PKI_KEYS.nextStepsAlert)
.hasText( .hasText(
'Next steps This private key material will only be available once. Copy or download it now.', 'Next steps This private key material will only be available once. Copy or download it now.',
'renders banner to save private key' 'renders banner to save private key'
); );
assert.dom(SELECTORS.keyPages.downloadButton).exists('renders download button'); assert.dom(PKI_KEYS.downloadButton).exists('renders download button');
await click(SELECTORS.keyPages.keyDeleteButton); await click(PKI_KEYS.keyDeleteButton);
await click(SELECTORS.keyPages.confirmDelete); await click(GENERAL.confirmButton);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/keys`, `/vault/secrets/${this.mountPath}/pki/keys`,
@ -322,41 +331,39 @@ module('Acceptance | pki workflow', function (hooks) {
test('it hides correct actions for user with read policy', async function (assert) { test('it hides correct actions for user with read policy', async function (assert) {
await authPage.login(this.pkiKeyReader); await authPage.login(this.pkiKeyReader);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.keysTab); await click(GENERAL.secretTab('Keys'));
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`);
await isSettled(); await isSettled();
assert.dom(SELECTORS.keyPages.importKey).doesNotExist(); assert.dom(PKI_KEYS.importKey).doesNotExist();
assert.dom(SELECTORS.keyPages.generateKey).doesNotExist(); assert.dom(PKI_KEYS.generateKey).doesNotExist();
assert.dom('.linked-block').exists({ count: 1 }, 'One key is in list'); assert.dom('.linked-block').exists({ count: 1 }, 'One key is in list');
const keyId = find(SELECTORS.keyPages.keyId).innerText; const keyId = find(PKI_KEYS.keyId).innerText;
await click(SELECTORS.keyPages.popupMenuTrigger); await click(GENERAL.menuTrigger);
assert.dom(SELECTORS.keyPages.popupMenuEdit).doesNotExist('popup menu edit link is not shown'); assert.dom(PKI_KEYS.popupMenuEdit).doesNotExist('popup menu edit link is not shown');
await click(SELECTORS.keyPages.popupMenuDetails); await click(PKI_KEYS.popupMenuDetails);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`);
assert.dom(SELECTORS.keyPages.keyDeleteButton).doesNotExist('Delete key button is not shown'); assert.dom(PKI_KEYS.keyDeleteButton).doesNotExist('Delete key button is not shown');
assert.dom(SELECTORS.keyPages.keyEditLink).doesNotExist('Edit key button does not render'); assert.dom(PKI_KEYS.keyEditLink).doesNotExist('Edit key button does not render');
}); });
test('it shows correct toolbar items for the user with update policy', async function (assert) { test('it shows correct toolbar items for the user with update policy', async function (assert) {
await authPage.login(this.pkiKeyEditor); await authPage.login(this.pkiKeyEditor);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.keysTab); await click(GENERAL.secretTab('Keys'));
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`);
await isSettled(); await isSettled();
assert.dom(SELECTORS.keyPages.importKey).exists('import action exists'); assert.dom(PKI_KEYS.importKey).exists('import action exists');
assert.dom(SELECTORS.keyPages.generateKey).exists('generate action exists'); assert.dom(PKI_KEYS.generateKey).exists('generate action exists');
assert.dom('.linked-block').exists({ count: 1 }, 'One key is in list'); assert.dom('.linked-block').exists({ count: 1 }, 'One key is in list');
const keyId = find(SELECTORS.keyPages.keyId).innerText; const keyId = find(PKI_KEYS.keyId).innerText;
await click(SELECTORS.keyPages.popupMenuTrigger); await click(GENERAL.menuTrigger);
assert assert.dom(PKI_KEYS.popupMenuEdit).doesNotHaveClass('disabled', 'popup menu edit link is not disabled');
.dom(SELECTORS.keyPages.popupMenuEdit)
.doesNotHaveClass('disabled', 'popup menu edit link is not disabled');
await click('.linked-block'); await click('.linked-block');
assert.dom(SELECTORS.keyPages.keyDeleteButton).doesNotExist('Delete key button is not shown'); assert.dom(PKI_KEYS.keyDeleteButton).doesNotExist('Delete key button is not shown');
await click(SELECTORS.keyPages.keyEditLink); await click(PKI_KEYS.keyEditLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/edit`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/edit`);
assert.dom(SELECTORS.keyPages.title).hasText('Edit Key'); assert.dom(GENERAL.title).hasText('Edit Key');
await click(SELECTORS.keyForm.keyCancelButton); await click(GENERAL.cancelButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`);
}); });
}); });
@ -374,25 +381,23 @@ module('Acceptance | pki workflow', function (hooks) {
clearRecords(this.store); clearRecords(this.store);
}); });
test('lists the correct issuer metadata info', async function (assert) { test('lists the correct issuer metadata info', async function (assert) {
assert.expect(6);
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.issuersTab).exists('Issuers tab is present'); assert.dom(GENERAL.secretTab('Issuers')).exists();
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`);
assert.dom('.linked-block').exists({ count: 1 }, 'One issuer is in list'); assert.dom('.linked-block').exists({ count: 1 });
assert.dom('[data-test-is-root-tag="0"]').hasText('root'); assert.dom('[data-test-is-root-tag="0"]').hasText('root');
assert.dom('[data-test-serial-number="0"]').exists({ count: 1 }, 'displays serial number tag'); assert.dom('[data-test-serial-number="0"]').exists({ count: 1 });
assert.dom('[data-test-common-name="0"]').exists({ count: 1 }, 'displays cert common name tag'); assert.dom('[data-test-common-name="0"]').exists({ count: 1 });
}); });
test('lists the correct issuer metadata info when user has only read permission', async function (assert) { test('lists the correct issuer metadata info when user has only read permission', async function (assert) {
assert.expect(2);
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
await click(SELECTORS.issuerPopupMenu); await click(GENERAL.menuTrigger);
await click(SELECTORS.issuerPopupDetails); await click(PKI_ISSUER_LIST.issuerPopupDetails);
const issuerId = find(SELECTORS.issuerDetails.valueByName('Issuer ID')).innerText; const issuerId = find(PKI_ISSUER_DETAILS.valueByName('Issuer ID')).innerText;
const pki_issuer_denied_policy = ` const pki_issuer_denied_policy = `
path "${this.mountPath}/*" { path "${this.mountPath}/*" {
capabilities = ["create", "read", "update", "delete", "list"] capabilities = ["create", "read", "update", "delete", "list"]
@ -407,7 +412,7 @@ module('Acceptance | pki workflow', function (hooks) {
await logout.visit(); await logout.visit();
await authPage.login(this.token); await authPage.login(this.token);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
assert.dom('[data-test-serial-number="0"]').exists({ count: 1 }, 'displays serial number tag'); assert.dom('[data-test-serial-number="0"]').exists({ count: 1 }, 'displays serial number tag');
assert.dom('[data-test-common-name="0"]').doesNotExist('does not display cert common name tag'); assert.dom('[data-test-common-name="0"]').doesNotExist('does not display cert common name tag');
}); });
@ -416,8 +421,8 @@ module('Acceptance | pki workflow', function (hooks) {
assert.expect(13); assert.expect(13);
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.issuersTab).exists('Issuers tab is present'); assert.dom(GENERAL.secretTab('Issuers')).exists('Issuers tab is present');
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`);
assert.dom('.linked-block').exists({ count: 1 }, 'One issuer is in list'); assert.dom('.linked-block').exists({ count: 1 }, 'One issuer is in list');
await click('.linked-block'); await click('.linked-block');
@ -425,45 +430,45 @@ module('Acceptance | pki workflow', function (hooks) {
currentURL().match(`/vault/secrets/${this.mountPath}/pki/issuers/.+/details`), currentURL().match(`/vault/secrets/${this.mountPath}/pki/issuers/.+/details`),
`/vault/secrets/${this.mountPath}/pki/issuers/my-issuer/details` `/vault/secrets/${this.mountPath}/pki/issuers/my-issuer/details`
); );
assert.dom(SELECTORS.issuerDetails.title).hasText('View Issuer Certificate'); assert.dom(GENERAL.title).hasText('View Issuer Certificate');
['Certificate', 'CA Chain', 'Common name', 'Issuer name', 'Issuer ID', 'Default key ID'].forEach( ['Certificate', 'CA Chain', 'Common name', 'Issuer name', 'Issuer ID', 'Default key ID'].forEach(
(label) => { (label) => {
assert assert
.dom(`${SELECTORS.issuerDetails.defaultGroup} ${SELECTORS.issuerDetails.valueByName(label)}`) .dom(`${PKI_ISSUER_DETAILS.defaultGroup} ${PKI_ISSUER_DETAILS.valueByName(label)}`)
.exists({ count: 1 }, `${label} value rendered`); .exists({ count: 1 }, `${label} value rendered`);
} }
); );
assert assert
.dom(`${SELECTORS.issuerDetails.urlsGroup} ${SELECTORS.issuerDetails.row}`) .dom(`${PKI_ISSUER_DETAILS.urlsGroup} ${PKI_ISSUER_DETAILS.row}`)
.exists({ count: 3 }, 'Renders 3 info table items under URLs group'); .exists({ count: 3 }, 'Renders 3 info table items under URLs group');
assert.dom(SELECTORS.issuerDetails.groupTitle).exists({ count: 1 }, 'only 1 group title rendered'); assert.dom(PKI_ISSUER_DETAILS.groupTitle).exists({ count: 1 }, 'only 1 group title rendered');
}); });
test('toolbar links navigate to expected routes', async function (assert) { test('toolbar links navigate to expected routes', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab); await click(GENERAL.secretTab('Issuers'));
await click(SELECTORS.issuerPopupMenu); await click(GENERAL.menuTrigger);
await click(SELECTORS.issuerPopupDetails); await click(PKI_ISSUER_LIST.issuerPopupDetails);
const issuerId = find(SELECTORS.issuerDetails.valueByName('Issuer ID')).innerText; const issuerId = find(PKI_ISSUER_DETAILS.valueByName('Issuer ID')).innerText;
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/details`, `/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/details`,
'it navigates to details route' 'it navigates to details route'
); );
assert assert
.dom(SELECTORS.issuerDetails.crossSign) .dom(PKI_ISSUER_DETAILS.crossSign)
.hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/cross-sign`); .hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/cross-sign`);
assert assert
.dom(SELECTORS.issuerDetails.signIntermediate) .dom(PKI_ISSUER_DETAILS.signIntermediate)
.hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/sign`); .hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/sign`);
assert assert
.dom(SELECTORS.issuerDetails.configure) .dom(PKI_ISSUER_DETAILS.configure)
.hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/edit`); .hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/edit`);
await click(SELECTORS.issuerDetails.rotateRoot); await click(PKI_ISSUER_DETAILS.rotateRoot);
assert.dom(SELECTORS.issuerDetails.rotateModal).exists('rotate root modal opens'); assert.dom(PKI_ISSUER_DETAILS.rotateModal).exists('rotate root modal opens');
await click(SELECTORS.issuerDetails.rotateModalGenerate); await click(PKI_ISSUER_DETAILS.rotateModalGenerate);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
`/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/rotate-root`, `/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/rotate-root`,
@ -484,12 +489,12 @@ module('Acceptance | pki workflow', function (hooks) {
test('it renders a warning banner when parent issuer has unsupported OIDs', async function (assert) { test('it renders a warning banner when parent issuer has unsupported OIDs', async function (assert) {
await authPage.login(); await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`); await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
await click(SELECTORS.configuration.optionByKey('import')); await click(PKI_CONFIGURE_CREATE.optionByKey('import'));
await click('[data-test-text-toggle]'); await click('[data-test-text-toggle]');
await fillIn('[data-test-text-file-textarea]', unsupportedPem); await fillIn('[data-test-text-file-textarea]', unsupportedPem);
await click(SELECTORS.configuration.importSubmit); await click(PKI_CONFIGURE_CREATE.importSubmit);
const issuerId = find(SELECTORS.configuration.importedIssuer).innerText; const issuerId = find(PKI_CONFIGURE_CREATE.importedIssuer).innerText;
await click(`${SELECTORS.configuration.importedIssuer} a`); await click(`${PKI_CONFIGURE_CREATE.importedIssuer} a`);
// navigating directly to route because the rotate button is not visible for non-root issuers // navigating directly to route because the rotate button is not visible for non-root issuers
// but we're just testing that route model was parsed and passed as expected // but we're just testing that route model was parsed and passed as expected
@ -502,7 +507,7 @@ module('Acceptance | pki workflow', function (hooks) {
); );
assert.dom('[data-test-input="commonName"]').hasValue('fancy-cert-unsupported-subj-and-ext-oids'); assert.dom('[data-test-input="commonName"]').hasValue('fancy-cert-unsupported-subj-and-ext-oids');
await fillIn('[data-test-input="issuerName"]', 'existing-issuer'); await fillIn('[data-test-input="issuerName"]', 'existing-issuer');
await click('[data-test-pki-rotate-root-save]'); await click(GENERAL.saveButton);
assert assert
.dom('[data-test-rotate-error]') .dom('[data-test-rotate-error]')
.hasText('Error issuer name already in use', 'it renders error banner'); .hasText('Error issuer name already in use', 'it renders error banner');
@ -527,18 +532,18 @@ module('Acceptance | pki workflow', function (hooks) {
await authPage.login(this.mixedConfigCapabilities); await authPage.login(this.mixedConfigCapabilities);
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/edit`); await visit(`/vault/secrets/${this.mountPath}/pki/configuration/edit`);
assert assert
.dom(`${SELECTORS.configEdit.configEditSection} [data-test-component="empty-state"]`) .dom(`${PKI_CONFIG_EDIT.configEditSection} [data-test-component="empty-state"]`)
.hasText( .hasText(
`You do not have permission to set this mount's the cluster config Ask your administrator if you think you should have access to: POST /${this.mountPath}/config/cluster` `You do not have permission to set this mount's the cluster config Ask your administrator if you think you should have access to: POST /${this.mountPath}/config/cluster`
); );
assert.dom(SELECTORS.configEdit.acmeEditSection).exists(); assert.dom(PKI_CONFIG_EDIT.acmeEditSection).exists();
assert.dom(SELECTORS.configEdit.urlsEditSection).exists(); assert.dom(PKI_CONFIG_EDIT.urlsEditSection).exists();
assert.dom(SELECTORS.configEdit.crlEditSection).exists(); assert.dom(PKI_CONFIG_EDIT.crlEditSection).exists();
assert.dom(`${SELECTORS.acmeEditSection} [data-test-component="empty-state"]`).doesNotExist(); assert.dom(`${PKI_CONFIG_EDIT.acmeEditSection} [data-test-component="empty-state"]`).doesNotExist();
assert.dom(`${SELECTORS.urlsEditSection} [data-test-component="empty-state"]`).doesNotExist(); assert.dom(`${PKI_CONFIG_EDIT.urlsEditSection} [data-test-component="empty-state"]`).doesNotExist();
assert.dom(`${SELECTORS.crlEditSection} [data-test-component="empty-state"]`).doesNotExist(); assert.dom(`${PKI_CONFIG_EDIT.crlEditSection} [data-test-component="empty-state"]`).doesNotExist();
await click(SELECTORS.configEdit.crlToggleInput('expiry')); await click(PKI_CONFIG_EDIT.crlToggleInput('expiry'));
await click(SELECTORS.configEdit.saveButton); await click(PKI_CONFIG_EDIT.saveButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`);
assert assert
.dom('[data-test-value-div="CRL building"]') .dom('[data-test-value-div="CRL building"]')

View File

@ -11,9 +11,9 @@ import authPage from 'vault/tests/pages/auth';
import logout from 'vault/tests/pages/logout'; import logout from 'vault/tests/pages/logout';
import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { click, currentURL, currentRouteName, visit } from '@ember/test-helpers'; import { click, currentURL, currentRouteName, visit } from '@ember/test-helpers';
import { SELECTORS } from 'vault/tests/helpers/pki/overview';
import { clearRecords } from 'vault/tests/helpers/pki/pki-run-commands';
import { runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands'; import { runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands';
import { clearRecords } from 'vault/tests/helpers/pki/pki-helpers';
import { PKI_OVERVIEW } from 'vault/tests/helpers/pki/pki-selectors';
module('Acceptance | pki overview', function (hooks) { module('Acceptance | pki overview', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@ -59,9 +59,9 @@ module('Acceptance | pki overview', function (hooks) {
test('navigates to view issuers when link is clicked on issuer card', async function (assert) { test('navigates to view issuers when link is clicked on issuer card', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.issuersCardTitle).hasText('Issuers'); assert.dom(PKI_OVERVIEW.issuersCardTitle).hasText('Issuers');
assert.dom(SELECTORS.issuersCardOverviewNum).hasText('1'); assert.dom(PKI_OVERVIEW.issuersCardOverviewNum).hasText('1');
await click(SELECTORS.issuersCardLink); await click(PKI_OVERVIEW.issuersCardLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
}); });
@ -69,9 +69,9 @@ module('Acceptance | pki overview', function (hooks) {
test('navigates to view roles when link is clicked on roles card', async function (assert) { test('navigates to view roles when link is clicked on roles card', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesCardTitle).hasText('Roles'); assert.dom(PKI_OVERVIEW.rolesCardTitle).hasText('Roles');
assert.dom(SELECTORS.rolesCardOverviewNum).hasText('0'); assert.dom(PKI_OVERVIEW.rolesCardOverviewNum).hasText('0');
await click(SELECTORS.rolesCardLink); await click(PKI_OVERVIEW.rolesCardLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`);
await runCmd([ await runCmd([
`write ${this.mountPath}/roles/some-role \ `write ${this.mountPath}/roles/some-role \
@ -81,14 +81,14 @@ module('Acceptance | pki overview', function (hooks) {
max_ttl="720h"`, max_ttl="720h"`,
]); ]);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesCardOverviewNum).hasText('1'); assert.dom(PKI_OVERVIEW.rolesCardOverviewNum).hasText('1');
}); });
test('hides roles card if user does not have permissions', async function (assert) { test('hides roles card if user does not have permissions', async function (assert) {
await authPage.login(this.pkiIssuersList); await authPage.login(this.pkiIssuersList);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesCardTitle).doesNotExist('Roles card does not exist'); assert.dom(PKI_OVERVIEW.rolesCardTitle).doesNotExist('Roles card does not exist');
assert.dom(SELECTORS.issuersCardTitle).exists('Issuers card exists'); assert.dom(PKI_OVERVIEW.issuersCardTitle).exists('Issuers card exists');
}); });
test('navigates to generate certificate page for Issue Certificates card', async function (assert) { test('navigates to generate certificate page for Issue Certificates card', async function (assert) {
@ -101,18 +101,18 @@ module('Acceptance | pki overview', function (hooks) {
max_ttl="720h"`, max_ttl="720h"`,
]); ]);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issueCertificatePowerSearch); await click(PKI_OVERVIEW.issueCertificatePowerSearch);
await click(SELECTORS.firstPowerSelectOption); await click(PKI_OVERVIEW.firstPowerSelectOption);
await click(SELECTORS.issueCertificateButton); await click(PKI_OVERVIEW.issueCertificateButton);
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.roles.role.generate'); assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.roles.role.generate');
}); });
test('navigates to certificate details page for View Certificates card', async function (assert) { test('navigates to certificate details page for View Certificates card', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.viewCertificatePowerSearch); await click(PKI_OVERVIEW.viewCertificatePowerSearch);
await click(SELECTORS.firstPowerSelectOption); await click(PKI_OVERVIEW.firstPowerSelectOption);
await click(SELECTORS.viewCertificateButton); await click(PKI_OVERVIEW.viewCertificateButton);
assert.strictEqual( assert.strictEqual(
currentRouteName(), currentRouteName(),
'vault.cluster.secrets.backend.pki.certificates.certificate.details' 'vault.cluster.secrets.backend.pki.certificates.certificate.details'
@ -122,9 +122,9 @@ module('Acceptance | pki overview', function (hooks) {
test('navigates to issuer details page for View Issuer card', async function (assert) { test('navigates to issuer details page for View Issuer card', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`); await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.viewIssuerPowerSearch); await click(PKI_OVERVIEW.viewIssuerPowerSearch);
await click(SELECTORS.firstPowerSelectOption); await click(PKI_OVERVIEW.firstPowerSelectOption);
await click(SELECTORS.viewIssuerButton); await click(PKI_OVERVIEW.viewIssuerButton);
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.issuers.issuer.details'); assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.issuers.issuer.details');
}); });
}); });

View File

@ -14,7 +14,8 @@ import authPage from 'vault/tests/pages/auth';
import logout from 'vault/tests/pages/logout'; import logout from 'vault/tests/pages/logout';
import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { runCmd } from 'vault/tests/helpers/commands'; import { runCmd } from 'vault/tests/helpers/commands';
import { SELECTORS } from 'vault/tests/helpers/pki/page/pki-tidy'; import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { PKI_TIDY, PKI_TIDY_FORM } from 'vault/tests/helpers/pki/pki-selectors';
module('Acceptance | pki tidy', function (hooks) { module('Acceptance | pki tidy', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@ -42,20 +43,20 @@ module('Acceptance | pki tidy', function (hooks) {
test('it configures a manual tidy operation and shows its details and tidy states', async function (assert) { test('it configures a manual tidy operation and shows its details and tidy states', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`); await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
await click(SELECTORS.tidyEmptyStateConfigure); await click(PKI_TIDY.tidyEmptyStateConfigure);
assert.dom(SELECTORS.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists'); assert.dom(PKI_TIDY.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
assert.dom(SELECTORS.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists'); assert.dom(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists');
assert assert
.dom(SELECTORS.tidyConfigureModal.tidyModalManualButton) .dom(PKI_TIDY.tidyConfigureModal.tidyModalManualButton)
.exists('Configure manual tidy button exists'); .exists('Configure manual tidy button exists');
await click(SELECTORS.tidyConfigureModal.tidyModalManualButton); await click(PKI_TIDY.tidyConfigureModal.tidyModalManualButton);
assert.dom(SELECTORS.tidyForm.tidyFormName('manual')).exists('Manual tidy form exists'); assert.dom(PKI_TIDY_FORM.tidyFormName('manual')).exists('Manual tidy form exists');
await click(SELECTORS.tidyForm.inputByAttr('tidyCertStore')); await click(PKI_TIDY_FORM.inputByAttr('tidyCertStore'));
await fillIn(SELECTORS.tidyForm.tidyPauseDuration, '10'); await fillIn(PKI_TIDY_FORM.tidyPauseDuration, '10');
await click(SELECTORS.tidyForm.tidySave); await click(PKI_TIDY_FORM.tidySave);
await click(SELECTORS.cancelTidyAction); await click(PKI_TIDY.cancelTidyAction);
assert.dom(SELECTORS.cancelTidyModalBackground).exists('Confirm cancel tidy modal exits'); assert.dom(PKI_TIDY.cancelTidyModalBackground).exists('Confirm cancel tidy modal exits');
await click(SELECTORS.tidyConfigureModal.tidyModalCancelButton); await click(PKI_TIDY.tidyConfigureModal.tidyModalCancelButton);
// we can't properly test the background refresh fetching of tidy status in testing // we can't properly test the background refresh fetching of tidy status in testing
this.server.get(`${this.mountPath}/tidy-status`, () => { this.server.get(`${this.mountPath}/tidy-status`, () => {
return { return {
@ -103,77 +104,75 @@ module('Acceptance | pki tidy', function (hooks) {
}); });
await visit(`/vault/secrets/${this.mountPath}/pki/configuration`); await visit(`/vault/secrets/${this.mountPath}/pki/configuration`);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`); await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
assert.dom(SELECTORS.hdsAlertTitle).hasText('Tidy operation cancelled'); assert.dom(PKI_TIDY.hdsAlertTitle).hasText('Tidy operation cancelled');
assert assert
.dom(SELECTORS.hdsAlertDescription) .dom(PKI_TIDY.hdsAlertDescription)
.hasText( .hasText(
'Your tidy operation has been cancelled. If this was a mistake configure and run another tidy operation.' 'Your tidy operation has been cancelled. If this was a mistake configure and run another tidy operation.'
); );
assert.dom(SELECTORS.alertUpdatedAt).exists(); assert.dom(PKI_TIDY.alertUpdatedAt).exists();
}); });
test('it configures an auto tidy operation and shows its details', async function (assert) { test('it configures an auto tidy operation and shows its details', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`); await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
await click(SELECTORS.tidyEmptyStateConfigure); await click(PKI_TIDY.tidyEmptyStateConfigure);
assert.dom(SELECTORS.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists'); assert.dom(PKI_TIDY.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
assert.dom(SELECTORS.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists'); assert.dom(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists');
assert assert
.dom(SELECTORS.tidyConfigureModal.tidyModalManualButton) .dom(PKI_TIDY.tidyConfigureModal.tidyModalManualButton)
.exists('Configure manual tidy button exists'); .exists('Configure manual tidy button exists');
await click(SELECTORS.tidyConfigureModal.tidyModalAutoButton); await click(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton);
assert.dom(SELECTORS.tidyForm.tidyFormName('auto')).exists('Auto tidy form exists'); assert.dom(PKI_TIDY_FORM.tidyFormName('auto')).exists('Auto tidy form exists');
await click(SELECTORS.tidyForm.tidyCancel); await click(PKI_TIDY_FORM.tidyCancel);
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.tidy.index'); assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.tidy.index');
await click(SELECTORS.tidyEmptyStateConfigure); await click(PKI_TIDY.tidyEmptyStateConfigure);
await click(SELECTORS.tidyConfigureModal.tidyModalAutoButton); await click(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton);
assert.dom(SELECTORS.tidyForm.tidyFormName('auto')).exists('Auto tidy form exists'); assert.dom(PKI_TIDY_FORM.tidyFormName('auto')).exists('Auto tidy form exists');
await click(SELECTORS.tidyForm.toggleLabel('Automatic tidy disabled')); await click(PKI_TIDY_FORM.toggleLabel('Automatic tidy disabled'));
assert assert
.dom(SELECTORS.tidyForm.tidySectionHeader('ACME operations')) .dom(PKI_TIDY_FORM.tidySectionHeader('ACME operations'))
.exists('Auto tidy form enabled shows ACME operations field'); .exists('Auto tidy form enabled shows ACME operations field');
await click(SELECTORS.tidyForm.inputByAttr('tidyCertStore')); await click(PKI_TIDY_FORM.inputByAttr('tidyCertStore'));
await click(SELECTORS.tidyForm.tidySave); await click(PKI_TIDY_FORM.tidySave);
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.tidy.auto.index'); assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.tidy.auto.index');
await click(SELECTORS.tidyForm.editAutoTidyButton); await click(PKI_TIDY_FORM.editAutoTidyButton);
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.tidy.auto.configure'); assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.tidy.auto.configure');
await click(SELECTORS.tidyForm.inputByAttr('tidyRevokedCerts')); await click(PKI_TIDY_FORM.inputByAttr('tidyRevokedCerts'));
await click(SELECTORS.tidyForm.tidySave); await click(PKI_TIDY_FORM.tidySave);
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.tidy.auto.index'); assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.tidy.auto.index');
}); });
test('it opens a tidy modal when the user clicks on the tidy toolbar action', async function (assert) { test('it opens a tidy modal when the user clicks on the tidy toolbar action', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`); await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
await click(SELECTORS.tidyConfigureModal.tidyOptionsModal); await click(PKI_TIDY.tidyConfigureModal.tidyOptionsModal);
assert.dom(SELECTORS.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists'); assert.dom(PKI_TIDY.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
assert.dom(SELECTORS.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists'); assert.dom(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists');
assert assert
.dom(SELECTORS.tidyConfigureModal.tidyModalManualButton) .dom(PKI_TIDY.tidyConfigureModal.tidyModalManualButton)
.exists('Configure manual tidy button exists'); .exists('Configure manual tidy button exists');
await click(SELECTORS.tidyConfigureModal.tidyModalCancelButton); await click(PKI_TIDY.tidyConfigureModal.tidyModalCancelButton);
assert.dom(SELECTORS.tidyEmptyState).exists(); assert.dom(GENERAL.emptyStateTitle).exists();
}); });
test('it should show correct toolbar action depending on whether auto tidy is enabled', async function (assert) { test('it should show correct toolbar action depending on whether auto tidy is enabled', async function (assert) {
await authPage.login(this.pkiAdminToken); await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`); await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
assert assert
.dom(SELECTORS.tidyConfigureModal.tidyOptionsModal) .dom(PKI_TIDY.tidyConfigureModal.tidyOptionsModal)
.exists('Configure tidy modal options button exists'); .exists('Configure tidy modal options button exists');
await click(SELECTORS.tidyConfigureModal.tidyOptionsModal); await click(PKI_TIDY.tidyConfigureModal.tidyOptionsModal);
assert.dom(SELECTORS.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists'); assert.dom(PKI_TIDY.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
await click(SELECTORS.tidyConfigureModal.tidyModalAutoButton); await click(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton);
await click(SELECTORS.tidyForm.toggleLabel('Automatic tidy disabled')); await click(PKI_TIDY_FORM.toggleLabel('Automatic tidy disabled'));
await click(SELECTORS.tidyForm.inputByAttr('tidyCertStore')); await click(PKI_TIDY_FORM.inputByAttr('tidyCertStore'));
await click(SELECTORS.tidyForm.inputByAttr('tidyRevokedCerts')); await click(PKI_TIDY_FORM.inputByAttr('tidyRevokedCerts'));
await click(SELECTORS.tidyForm.tidySave); await click(PKI_TIDY_FORM.tidySave);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`); await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
assert assert
.dom(SELECTORS.manualTidyToolbar) .dom(PKI_TIDY.manualTidyToolbar)
.exists('Manual tidy toolbar action exists if auto tidy is configured'); .exists('Manual tidy toolbar action exists if auto tidy is configured');
assert assert.dom(PKI_TIDY.autoTidyToolbar).exists('Auto tidy toolbar action exists if auto tidy is configured');
.dom(SELECTORS.autoTidyToolbar)
.exists('Auto tidy toolbar action exists if auto tidy is configured');
}); });
}); });

View File

@ -10,7 +10,6 @@ import {
fillIn, fillIn,
visit, visit,
click, click,
find,
waitFor, waitFor,
waitUntil, waitUntil,
} from '@ember/test-helpers'; } from '@ember/test-helpers';
@ -20,6 +19,7 @@ import { v4 as uuidv4 } from 'uuid';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { runCmd } from 'vault/tests/helpers/commands'; import { runCmd } from 'vault/tests/helpers/commands';
import codemirror from 'vault/tests/helpers/codemirror';
const SELECT = { const SELECT = {
policyByName: (name) => `[data-test-policy-link="${name}"]`, policyByName: (name) => `[data-test-policy-link="${name}"]`,
@ -86,7 +86,7 @@ module('Acceptance | policies/acl', function (hooks) {
await click(SELECT.createLink); await click(SELECT.createLink);
await fillIn(SELECT.nameInput, policyName); await fillIn(SELECT.nameInput, policyName);
find('.CodeMirror').CodeMirror.setValue(policyString); codemirror().setValue(policyString);
await click(SELECT.save); await click(SELECT.save);
assert.strictEqual( assert.strictEqual(
currentURL(), currentURL(),
@ -110,7 +110,7 @@ module('Acceptance | policies/acl', function (hooks) {
assert assert
.dom(SELECT.createError) .dom(SELECT.createError)
.hasText(`Error 'policy' parameter not supplied or empty`, 'renders error message on save'); .hasText(`Error 'policy' parameter not supplied or empty`, 'renders error message on save');
find('.CodeMirror').CodeMirror.setValue(policyString); codemirror().setValue(policyString);
await click(SELECT.save); await click(SELECT.save);
await waitUntil(() => currentURL() === `/vault/policy/acl/${encodeURIComponent(policyLower)}`); await waitUntil(() => currentURL() === `/vault/policy/acl/${encodeURIComponent(policyLower)}`);

View File

@ -12,7 +12,7 @@ import { createTokenCmd, runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/
import { pollCluster } from 'vault/tests/helpers/poll-cluster'; import { pollCluster } from 'vault/tests/helpers/poll-cluster';
import VAULT_KEYS from 'vault/tests/helpers/vault-keys'; import VAULT_KEYS from 'vault/tests/helpers/vault-keys';
import reducedDisclosureHandlers from 'vault/mirage/handlers/reduced-disclosure'; import reducedDisclosureHandlers from 'vault/mirage/handlers/reduced-disclosure';
import { overrideResponse } from 'vault/tests/helpers/clients'; import { overrideResponse } from 'vault/tests/helpers/stubs';
const { unsealKeys } = VAULT_KEYS; const { unsealKeys } = VAULT_KEYS;
const SELECTORS = { const SELECTORS = {

View File

@ -13,7 +13,7 @@ import editPage from 'vault/tests/pages/secrets/backend/kv/edit-secret';
import showPage from 'vault/tests/pages/secrets/backend/kv/show'; import showPage from 'vault/tests/pages/secrets/backend/kv/show';
import listPage from 'vault/tests/pages/secrets/backend/list'; import listPage from 'vault/tests/pages/secrets/backend/list';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import assertSecretWrap from 'vault/tests/helpers/secret-edit-toolbar'; import { assertSecretWrap } from 'vault/tests/helpers/components/secret-edit-toolbar';
module('Acceptance | secrets/cubbyhole/create', function (hooks) { module('Acceptance | secrets/cubbyhole/create', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);

View File

@ -17,8 +17,7 @@ import { writeSecret } from 'vault/tests/helpers/kv/kv-run-commands';
import { PAGE } from 'vault/tests/helpers/kv/kv-selectors'; import { PAGE } from 'vault/tests/helpers/kv/kv-selectors';
import { create } from 'ember-cli-page-object'; import { create } from 'ember-cli-page-object';
import { deleteEngineCmd, runCmd } from 'vault/tests/helpers/commands';
import apiStub from 'vault/tests/helpers/noop-all-api-requests';
const cli = create(consolePanel); const cli = create(consolePanel);
@ -27,14 +26,9 @@ module('Acceptance | secrets/generic/create', function (hooks) {
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.uid = uuidv4(); this.uid = uuidv4();
this.server = apiStub({ usePassthrough: true });
return authPage.login(); return authPage.login();
}); });
hooks.afterEach(function () {
this.server.shutdown();
});
test('it creates and can view a secret with the generic backend', async function (assert) { test('it creates and can view a secret with the generic backend', async function (assert) {
const path = `generic-${this.uid}`; const path = `generic-${this.uid}`;
const kvPath = `generic-kv-${this.uid}`; const kvPath = `generic-kv-${this.uid}`;
@ -55,6 +49,10 @@ module('Acceptance | secrets/generic/create', function (hooks) {
'redirects to the show page' 'redirects to the show page'
); );
assert.ok(showPage.editIsPresent, 'shows the edit button'); assert.ok(showPage.editIsPresent, 'shows the edit button');
// Clean up
await runCmd(deleteEngineCmd(path));
await runCmd(deleteEngineCmd(kvPath));
}); });
test('upgrading generic to version 2 lists all existing secrets, and CRUD continues to work', async function (assert) { test('upgrading generic to version 2 lists all existing secrets, and CRUD continues to work', async function (assert) {
@ -78,5 +76,8 @@ module('Acceptance | secrets/generic/create', function (hooks) {
assert.dom(PAGE.list.item(secret.path)).exists('lists both records'); assert.dom(PAGE.list.item(secret.path)).exists('lists both records');
}); });
assert.dom(PAGE.list.item()).exists({ count: 2 }, 'lists only the two secrets'); assert.dom(PAGE.list.item()).exists({ count: 2 }, 'lists only the two secrets');
// Clean up
await runCmd(deleteEngineCmd(path));
}); });
}); });

View File

@ -11,7 +11,8 @@ import kubernetesHandlers from 'vault/mirage/handlers/kubernetes';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { visit, click, currentRouteName } from '@ember/test-helpers'; import { visit, click, currentRouteName } from '@ember/test-helpers';
import { selectChoose } from 'ember-power-select/test-support'; import { selectChoose } from 'ember-power-select/test-support';
import { SELECTORS } from 'vault/tests/helpers/kubernetes/overview'; import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { KUBERNETES_OVERVIEW } from 'vault/tests/helpers/kubernetes/kubernetes-selectors';
module('Acceptance | kubernetes | overview', function (hooks) { module('Acceptance | kubernetes | overview', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@ -34,7 +35,7 @@ module('Acceptance | kubernetes | overview', function (hooks) {
test('it should transition to configuration page during empty state', async function (assert) { test('it should transition to configuration page during empty state', async function (assert) {
assert.expect(1); assert.expect(1);
await this.visitOverview(); await this.visitOverview();
await click('[data-test-component="empty-state"] a'); await click(`${GENERAL.emptyStateActions} a`);
this.validateRoute(assert, 'configure', 'Transitions to Configure route on click'); this.validateRoute(assert, 'configure', 'Transitions to Configure route on click');
}); });
@ -42,7 +43,7 @@ module('Acceptance | kubernetes | overview', function (hooks) {
assert.expect(1); assert.expect(1);
this.createScenario(); this.createScenario();
await this.visitOverview(); await this.visitOverview();
await click(SELECTORS.rolesCardLink); await click(KUBERNETES_OVERVIEW.rolesCardLink);
this.validateRoute(assert, 'roles.index', 'Transitions to roles route on View Roles click'); this.validateRoute(assert, 'roles.index', 'Transitions to roles route on View Roles click');
}); });
@ -50,7 +51,7 @@ module('Acceptance | kubernetes | overview', function (hooks) {
assert.expect(1); assert.expect(1);
this.createScenario(false); this.createScenario(false);
await this.visitOverview(); await this.visitOverview();
await click(SELECTORS.rolesCardLink); await click(KUBERNETES_OVERVIEW.rolesCardLink);
this.validateRoute(assert, 'roles.create', 'Transitions to roles route on Create Roles click'); this.validateRoute(assert, 'roles.create', 'Transitions to roles route on Create Roles click');
}); });
@ -59,7 +60,7 @@ module('Acceptance | kubernetes | overview', function (hooks) {
await this.createScenario(); await this.createScenario();
await this.visitOverview(); await this.visitOverview();
await selectChoose('.search-select', 'role-0'); await selectChoose('.search-select', 'role-0');
await click('[data-test-generate-credential-button]'); await click(KUBERNETES_OVERVIEW.generateCredentialsCardButton);
this.validateRoute(assert, 'roles.role.credentials', 'Transitions to roles route on Generate click'); this.validateRoute(assert, 'roles.role.credentials', 'Transitions to roles route on Generate click');
}); });
}); });

View File

@ -10,7 +10,7 @@ import { click, currentURL, fillIn, typeIn, visit } from '@ember/test-helpers';
import { setupApplicationTest } from 'vault/tests/helpers'; import { setupApplicationTest } from 'vault/tests/helpers';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { deleteEngineCmd, mountEngineCmd, runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands'; import { deleteEngineCmd, mountEngineCmd, runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands';
import { personas } from 'vault/tests/helpers/policy-generator/kv'; import { personas } from 'vault/tests/helpers/kv/policy-generator';
import { clearRecords, writeVersionedSecret } from 'vault/tests/helpers/kv/kv-run-commands'; import { clearRecords, writeVersionedSecret } from 'vault/tests/helpers/kv/kv-run-commands';
import { FORM, PAGE } from 'vault/tests/helpers/kv/kv-selectors'; import { FORM, PAGE } from 'vault/tests/helpers/kv/kv-selectors';
import { grantAccessForWrite, setupControlGroup } from 'vault/tests/helpers/control-groups'; import { grantAccessForWrite, setupControlGroup } from 'vault/tests/helpers/control-groups';

View File

@ -8,7 +8,7 @@ import { v4 as uuidv4 } from 'uuid';
import { setupApplicationTest } from 'vault/tests/helpers'; import { setupApplicationTest } from 'vault/tests/helpers';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { deleteEngineCmd, mountEngineCmd, runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands'; import { deleteEngineCmd, mountEngineCmd, runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands';
import { personas } from 'vault/tests/helpers/policy-generator/kv'; import { personas } from 'vault/tests/helpers/kv/policy-generator';
import { import {
clearRecords, clearRecords,
deleteLatestCmd, deleteLatestCmd,

View File

@ -21,7 +21,7 @@ import {
destroyVersionsPolicy, destroyVersionsPolicy,
metadataListPolicy, metadataListPolicy,
metadataPolicy, metadataPolicy,
} from 'vault/tests/helpers/policy-generator/kv'; } from 'vault/tests/helpers/kv/policy-generator';
import { clearRecords, writeSecret, writeVersionedSecret } from 'vault/tests/helpers/kv/kv-run-commands'; import { clearRecords, writeSecret, writeVersionedSecret } from 'vault/tests/helpers/kv/kv-run-commands';
import { FORM, PAGE } from 'vault/tests/helpers/kv/kv-selectors'; import { FORM, PAGE } from 'vault/tests/helpers/kv/kv-selectors';
import codemirror from 'vault/tests/helpers/codemirror'; import codemirror from 'vault/tests/helpers/codemirror';

View File

@ -16,7 +16,7 @@ import {
createTokenCmd, createTokenCmd,
tokenWithPolicyCmd, tokenWithPolicyCmd,
} from 'vault/tests/helpers/commands'; } from 'vault/tests/helpers/commands';
import { personas } from 'vault/tests/helpers/policy-generator/kv'; import { personas } from 'vault/tests/helpers/kv/policy-generator';
import { import {
addSecretMetadataCmd, addSecretMetadataCmd,
clearRecords, clearRecords,

View File

@ -8,7 +8,7 @@ import { v4 as uuidv4 } from 'uuid';
import { setupApplicationTest } from 'vault/tests/helpers'; import { setupApplicationTest } from 'vault/tests/helpers';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { deleteEngineCmd, mountEngineCmd, runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands'; import { deleteEngineCmd, mountEngineCmd, runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands';
import { personas } from 'vault/tests/helpers/policy-generator/kv'; import { personas } from 'vault/tests/helpers/kv/policy-generator';
import { import {
clearRecords, clearRecords,
deleteVersionCmd, deleteVersionCmd,

View File

@ -18,6 +18,7 @@ import logout from 'vault/tests/pages/logout';
import { writeSecret, writeVersionedSecret } from 'vault/tests/helpers/kv/kv-run-commands'; import { writeSecret, writeVersionedSecret } from 'vault/tests/helpers/kv/kv-run-commands';
import { runCmd } from 'vault/tests/helpers/commands'; import { runCmd } from 'vault/tests/helpers/commands';
import { PAGE } from 'vault/tests/helpers/kv/kv-selectors'; import { PAGE } from 'vault/tests/helpers/kv/kv-selectors';
import codemirror from 'vault/tests/helpers/codemirror';
const deleteEngine = async function (enginePath, assert) { const deleteEngine = async function (enginePath, assert) {
await logout.visit(); await logout.visit();
@ -329,8 +330,7 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
await listPage.visitRoot({ backend: this.backend }); await listPage.visitRoot({ backend: this.backend });
await listPage.create(); await listPage.create();
await editPage.path(secretPath).toggleJSON(); await editPage.path(secretPath).toggleJSON();
const instance = document.querySelector('.CodeMirror').CodeMirror; codemirror().setValue(content);
instance.setValue(content);
await editPage.save(); await editPage.save();
assert.strictEqual( assert.strictEqual(
@ -339,9 +339,8 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
'redirects to the show page' 'redirects to the show page'
); );
assert.ok(showPage.editIsPresent, 'shows the edit button'); assert.ok(showPage.editIsPresent, 'shows the edit button');
const savedInstance = document.querySelector('.CodeMirror').CodeMirror;
assert.strictEqual( assert.strictEqual(
savedInstance.options.value, codemirror().options.value,
JSON.stringify({ bar: 'boo', foo: 'fa' }, null, 2), JSON.stringify({ bar: 'boo', foo: 'fa' }, null, 2),
'saves the content' 'saves the content'
); );

View File

@ -10,7 +10,7 @@ import ldapMirageScenario from 'vault/mirage/scenarios/ldap';
import ldapHandlers from 'vault/mirage/handlers/ldap'; import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { click } from '@ember/test-helpers'; import { click } from '@ember/test-helpers';
import { isURL, visitURL } from 'vault/tests/helpers/ldap'; import { isURL, visitURL } from 'vault/tests/helpers/ldap/ldap-helpers';
module('Acceptance | ldap | libraries', function (hooks) { module('Acceptance | ldap | libraries', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);

View File

@ -11,7 +11,7 @@ import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { click, fillIn, visit } from '@ember/test-helpers'; import { click, fillIn, visit } from '@ember/test-helpers';
import { selectChoose } from 'ember-power-select/test-support'; import { selectChoose } from 'ember-power-select/test-support';
import { isURL, visitURL } from 'vault/tests/helpers/ldap'; import { isURL, visitURL } from 'vault/tests/helpers/ldap/ldap-helpers';
module('Acceptance | ldap | overview', function (hooks) { module('Acceptance | ldap | overview', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);

View File

@ -10,7 +10,7 @@ import ldapMirageScenario from 'vault/mirage/scenarios/ldap';
import ldapHandlers from 'vault/mirage/handlers/ldap'; import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { click, fillIn } from '@ember/test-helpers'; import { click, fillIn } from '@ember/test-helpers';
import { isURL, visitURL } from 'vault/tests/helpers/ldap'; import { isURL, visitURL } from 'vault/tests/helpers/ldap/ldap-helpers';
module('Acceptance | ldap | roles', function (hooks) { module('Acceptance | ldap | roles', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);

View File

@ -5,6 +5,7 @@
import { module, test } from 'qunit'; import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit'; import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { create } from 'ember-cli-page-object'; import { create } from 'ember-cli-page-object';
import { fillIn } from '@ember/test-helpers'; import { fillIn } from '@ember/test-helpers';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
@ -12,7 +13,6 @@ import { v4 as uuidv4 } from 'uuid';
import enablePage from 'vault/tests/pages/settings/auth/enable'; import enablePage from 'vault/tests/pages/settings/auth/enable';
import page from 'vault/tests/pages/settings/auth/configure/section'; import page from 'vault/tests/pages/settings/auth/configure/section';
import indexPage from 'vault/tests/pages/settings/auth/configure/index'; import indexPage from 'vault/tests/pages/settings/auth/configure/index';
import apiStub from 'vault/tests/helpers/noop-all-api-requests';
import consolePanel from 'vault/tests/pages/components/console/ui-panel'; import consolePanel from 'vault/tests/pages/components/console/ui-panel';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
@ -20,18 +20,24 @@ const cli = create(consolePanel);
module('Acceptance | settings/auth/configure/section', function (hooks) { module('Acceptance | settings/auth/configure/section', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(function () { hooks.beforeEach(function () {
this.uid = uuidv4(); this.uid = uuidv4();
this.server = apiStub({ usePassthrough: true });
return authPage.login(); return authPage.login();
}); });
hooks.afterEach(function () {
this.server.shutdown();
});
test('it can save options', async function (assert) { test('it can save options', async function (assert) {
assert.expect(6);
this.server.post(`/sys/mounts/auth/:path/tune`, function (schema, request) {
const body = JSON.parse(request.requestBody);
const keys = Object.keys(body);
assert.strictEqual(body.token_type, 'batch', 'passes new token type');
assert.true(keys.includes('default_lease_ttl'), 'passes default_lease_ttl on tune');
assert.true(keys.includes('max_lease_ttl'), 'passes max_lease_ttl on tune');
assert.true(keys.includes('description'), 'passes updated description on tune');
request.passthrough();
});
const path = `approle-save-${this.uid}`; const path = `approle-save-${this.uid}`;
const type = 'approle'; const type = 'approle';
const section = 'options'; const section = 'options';
@ -48,16 +54,6 @@ module('Acceptance | settings/auth/configure/section', function (hooks) {
`The configuration was saved successfully.`, `The configuration was saved successfully.`,
'success flash shows' 'success flash shows'
); );
const tuneRequest = this.server.passthroughRequests.filterBy(
'url',
`/v1/sys/mounts/auth/${path}/tune`
)[0];
const keys = Object.keys(JSON.parse(tuneRequest.requestBody));
const token_type = JSON.parse(tuneRequest.requestBody).token_type;
assert.strictEqual(token_type, 'batch', 'passes new token type');
assert.ok(keys.includes('default_lease_ttl'), 'passes default_lease_ttl on tune');
assert.ok(keys.includes('max_lease_ttl'), 'passes max_lease_ttl on tune');
assert.ok(keys.includes('description'), 'passes updated description on tune');
}); });
for (const type of ['aws', 'azure', 'gcp', 'github', 'kubernetes']) { for (const type of ['aws', 'azure', 'gcp', 'github', 'kubernetes']) {

View File

@ -3,13 +3,24 @@
* SPDX-License-Identifier: BUSL-1.1 * SPDX-License-Identifier: BUSL-1.1
*/ */
import { click, fillIn, find, findAll, currentURL, visit, settled, waitUntil } from '@ember/test-helpers'; import {
click,
fillIn,
find,
findAll,
currentURL,
visit,
settled,
waitUntil,
waitFor,
} from '@ember/test-helpers';
import Pretender from 'pretender'; import Pretender from 'pretender';
import { module, test } from 'qunit'; import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit'; import { setupApplicationTest } from 'ember-qunit';
import { toolsActions } from 'vault/helpers/tools-actions'; import { toolsActions } from 'vault/helpers/tools-actions';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { capitalize } from '@ember/string'; import { capitalize } from '@ember/string';
import codemirror from 'vault/tests/helpers/codemirror';
module('Acceptance | tools', function (hooks) { module('Acceptance | tools', function (hooks) {
setupApplicationTest(hooks); setupApplicationTest(hooks);
@ -48,8 +59,8 @@ module('Acceptance | tools', function (hooks) {
assert.dom(`[data-test-sidebar-nav-link="${capitalize(action)}"]`).exists(`${action} link renders`); assert.dom(`[data-test-sidebar-nav-link="${capitalize(action)}"]`).exists(`${action} link renders`);
}); });
const { CodeMirror } = await waitUntil(() => find('.CodeMirror')); await waitFor('.CodeMirror');
CodeMirror.setValue(DATA_TO_WRAP); codemirror().setValue(DATA_TO_WRAP);
// wrap // wrap
await click('[data-test-tools-submit]'); await click('[data-test-tools-submit]');
@ -86,16 +97,20 @@ module('Acceptance | tools', function (hooks) {
await fillIn('[data-test-tools-input="wrapping-token"]', tokenStore.get()); await fillIn('[data-test-tools-input="wrapping-token"]', tokenStore.get());
await click('[data-test-tools-submit]'); await click('[data-test-tools-submit]');
await waitFor('.CodeMirror');
assert.deepEqual( assert.deepEqual(
JSON.parse(CodeMirror.getValue()), JSON.parse(codemirror().getValue()),
JSON.parse(DATA_TO_WRAP), JSON.parse(DATA_TO_WRAP),
'unwrapped data equals input data' 'unwrapped data equals input data'
); );
const buttonDetails = await waitUntil(() => find('[data-test-button-details]')); await waitUntil(() => find('[data-test-button-details]'));
await click(buttonDetails); await click('[data-test-button-details]');
await click('[data-test-button-data]'); await click('[data-test-button-data]');
assert.dom('.CodeMirror').exists(); assert.deepEqual(
JSON.parse(codemirror().getValue()),
JSON.parse(DATA_TO_WRAP),
'data tab still has unwrapped data'
);
//random //random
await click('[data-test-sidebar-nav-link="Random"]'); await click('[data-test-sidebar-nav-link="Random"]');
@ -160,7 +175,7 @@ module('Acceptance | tools', function (hooks) {
await click('[data-test-tools-submit]'); await click('[data-test-tools-submit]');
assert.deepEqual( assert.deepEqual(
JSON.parse(findAll('.CodeMirror')[0].CodeMirror.getValue()), JSON.parse(codemirror().getValue()),
AUTH_RESPONSE.auth, AUTH_RESPONSE.auth,
'unwrapped data equals input data' 'unwrapped data equals input data'
); );

View File

@ -11,6 +11,7 @@ import { v4 as uuidv4 } from 'uuid';
import { encodeString } from 'vault/utils/b64'; import { encodeString } from 'vault/utils/b64';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { deleteEngineCmd, mountEngineCmd, runCmd } from 'vault/tests/helpers/commands'; import { deleteEngineCmd, mountEngineCmd, runCmd } from 'vault/tests/helpers/commands';
import codemirror from 'vault/tests/helpers/codemirror';
const SELECTORS = { const SELECTORS = {
secretLink: '[data-test-secret-link]', secretLink: '[data-test-secret-link]',
@ -150,7 +151,7 @@ const testConvergentEncryption = async function (assert, keyName) {
for (const testCase of tests) { for (const testCase of tests) {
await click('[data-test-transit-action-link="encrypt"]'); await click('[data-test-transit-action-link="encrypt"]');
find('#plaintext-control .CodeMirror').CodeMirror.setValue(testCase.plaintext); codemirror('#plaintext-control').setValue(testCase.plaintext);
await fillIn('[data-test-transit-input="context"]', testCase.context); await fillIn('[data-test-transit-input="context"]', testCase.context);
if (!testCase.encodePlaintext) { if (!testCase.encodePlaintext) {
@ -160,7 +161,7 @@ const testConvergentEncryption = async function (assert, keyName) {
if (testCase.encodeContext) { if (testCase.encodeContext) {
await click('[data-test-transit-b64-toggle="context"]'); await click('[data-test-transit-b64-toggle="context"]');
} }
assert.dom('[data-test-encrypt-modal]').doesNotExist(`${name}: is not open before encrypt`); assert.dom('[data-test-encrypt-modal]').doesNotExist(`${keyName}: is not open before encrypt`);
await click('[data-test-button-encrypt]'); await click('[data-test-button-encrypt]');
if (testCase.assertAfterEncrypt) { if (testCase.assertAfterEncrypt) {
@ -171,14 +172,15 @@ const testConvergentEncryption = async function (assert, keyName) {
const copiedCiphertext = find('[data-test-encrypted-value="ciphertext"]').innerText; const copiedCiphertext = find('[data-test-encrypted-value="ciphertext"]').innerText;
await click('dialog button'); await click('dialog button');
assert.dom('dialog.hds-modal').doesNotExist(`${name}: Modal closes after background clicked`); assert.dom('dialog.hds-modal').doesNotExist(`${keyName}: Modal closes after background clicked`);
await click('[data-test-transit-action-link="decrypt"]'); await click('[data-test-transit-action-link="decrypt"]');
if (testCase.assertBeforeDecrypt) { if (testCase.assertBeforeDecrypt) {
await settled(); await settled();
testCase.assertBeforeDecrypt(keyName); testCase.assertBeforeDecrypt(keyName);
} }
find('#ciphertext-control .CodeMirror').CodeMirror.setValue(copiedCiphertext);
codemirror('#ciphertext-control').setValue(copiedCiphertext);
await click('[data-test-button-decrypt]'); await click('[data-test-button-decrypt]');
if (testCase.assertAfterDecrypt) { if (testCase.assertAfterDecrypt) {
@ -188,7 +190,7 @@ const testConvergentEncryption = async function (assert, keyName) {
await click('dialog button'); await click('dialog button');
assert.dom('dialog.hds-modal').doesNotExist(`${name}: Modal closes after background clicked`); assert.dom('dialog.hds-modal').doesNotExist(`${keyName}: Modal closes after background clicked`);
} }
}; };

View File

@ -11,7 +11,7 @@ import { setupMirage } from 'ember-cli-mirage/test-support';
import VAULT_KEYS from 'vault/tests/helpers/vault-keys'; import VAULT_KEYS from 'vault/tests/helpers/vault-keys';
import authPage from 'vault/tests/pages/auth'; import authPage from 'vault/tests/pages/auth';
import { pollCluster } from 'vault/tests/helpers/poll-cluster'; import { pollCluster } from 'vault/tests/helpers/poll-cluster';
import { overrideResponse } from 'vault/tests/helpers/clients'; import { overrideResponse } from 'vault/tests/helpers/stubs';
const { unsealKeys } = VAULT_KEYS; const { unsealKeys } = VAULT_KEYS;

View File

@ -3,131 +3,14 @@
* SPDX-License-Identifier: BUSL-1.1 * SPDX-License-Identifier: BUSL-1.1
*/ */
import { Response } from 'miragejs';
import { SELECTORS as GENERAL } from 'vault/tests/helpers/general-selectors';
import { click } from '@ember/test-helpers'; import { click } from '@ember/test-helpers';
import { LICENSE_START } from 'vault/mirage/handlers/clients'; import { LICENSE_START } from 'vault/mirage/handlers/clients';
import { addMonths } from 'date-fns'; import { addMonths } from 'date-fns';
import { CLIENT_COUNT } from './client-count-selectors';
/** Scenarios
Config off, no data
Config on, no data
Config on, with data
Filtering (data with mounts)
Filtering (data without mounts)
Filtering (data without mounts)
* -- HISTORY ONLY --
Filtering different date ranges (hist only)
Upgrade warning
No permissions for license
Version
queries available
queries unavailable
License start date this month
*/
export const SELECTORS = {
...GENERAL,
counts: {
startLabel: '[data-test-counts-start-label]',
description: '[data-test-counts-description]',
startMonth: '[data-test-counts-start-month]',
startEdit: '[data-test-counts-start-edit]',
startDropdown: '[data-test-counts-start-dropdown]',
configDisabled: '[data-test-counts-disabled]',
namespaces: '[data-test-counts-namespaces]',
mountPaths: '[data-test-counts-auth-mounts]',
startDiscrepancy: '[data-test-counts-start-discrepancy]',
},
tokenTab: {
entity: '[data-test-monthly-new-entity]',
nonentity: '[data-test-monthly-new-nonentity]',
legend: '[data-test-monthly-new-legend]',
},
syncTab: {
total: '[data-test-total-sync-clients]',
average: '[data-test-average-sync-clients]',
},
charts: {
chart: (title) => `[data-test-chart="${title}"]`, // newer lineal charts
statTextValue: (label) =>
label ? `[data-test-stat-text-container="${label}"] .stat-value` : '[data-test-stat-text-container]',
legend: '[data-test-chart-container-legend]',
legendLabel: (nth) => `.legend-label:nth-child(${nth * 2})`, // nth * 2 accounts for dots in legend
timestamp: '[data-test-chart-container-timestamp]',
dataBar: '[data-test-vertical-bar]',
xAxisLabel: '[data-test-x-axis] text',
// selectors for old d3 charts
verticalBar: '[data-test-vertical-bar-chart]',
lineChart: '[data-test-line-chart]',
bar: {
xAxisLabel: '[data-test-vertical-chart="x-axis-labels"] text',
dataBar: '[data-test-vertical-chart="data-bar"]',
},
line: {
xAxisLabel: '[data-test-line-chart] [data-test-x-axis] text',
plotPoint: '[data-test-line-chart="plot-point"]',
},
},
usageStats: '[data-test-usage-stats]',
dateDisplay: '[data-test-date-display]',
attributionBlock: '[data-test-clients-attribution]',
filterBar: '[data-test-clients-filter-bar]',
rangeDropdown: '[data-test-calendar-widget-trigger]',
monthDropdown: '[data-test-toggle-month]',
yearDropdown: '[data-test-toggle-year]',
currentBillingPeriod: '[data-test-current-billing-period]',
dateDropdownSubmit: '[data-test-date-dropdown-submit]',
runningTotalMonthStats: '[data-test-running-total="single-month-stats"]',
runningTotalMonthlyCharts: '[data-test-running-total="monthly-charts"]',
selectedAuthMount: 'div#auth-method-search-select [data-test-selected-option] div',
selectedNs: 'div#namespace-search-select [data-test-selected-option] div',
upgradeWarning: '[data-test-clients-upgrade-warning]',
};
export const CHART_ELEMENTS = {
entityClientDataBars: '[data-test-group="entity_clients"]',
nonEntityDataBars: '[data-test-group="non_entity_clients"]',
yLabels: '[data-test-group="y-labels"]',
actionBars: '[data-test-group="action-bars"]',
labelActionBars: '[data-test-group="label-action-bars"]',
totalValues: '[data-test-group="total-values"]',
};
export function sendResponse(data, httpStatus = 200) {
if (httpStatus === 403) {
return [
httpStatus,
{ 'Content-Type': 'application/json' },
JSON.stringify({ errors: ['permission denied'] }),
];
}
if (httpStatus === 204) {
// /activity endpoint returns 204 when no data, while
// /activity/monthly returns 200 with zero values on data
return [httpStatus, { 'Content-Type': 'application/json' }];
}
return [httpStatus, { 'Content-Type': 'application/json' }, JSON.stringify(data)];
}
export function overrideResponse(httpStatus, data) {
if (httpStatus === 403) {
return new Response(
403,
{ 'Content-Type': 'application/json' },
JSON.stringify({ errors: ['permission denied'] })
);
}
// /activity endpoint returns 204 when no data, while
// /activity/monthly returns 200 with zero values on data
if (httpStatus === 204) {
return new Response(204, { 'Content-Type': 'application/json' });
}
return new Response(200, { 'Content-Type': 'application/json' }, JSON.stringify(data));
}
export async function dateDropdownSelect(month, year) { export async function dateDropdownSelect(month, year) {
const { dateDropdown, counts } = SELECTORS; const { dateDropdown, counts } = CLIENT_COUNT;
await click(counts.startEdit); await click(counts.startEdit);
await click(dateDropdown.toggleMonth); await click(dateDropdown.toggleMonth);
await click(dateDropdown.selectMonth(month)); await click(dateDropdown.selectMonth(month));

View File

@ -0,0 +1,87 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
// TODO: separate nested into distinct exported consts
export const CLIENT_COUNT = {
counts: {
startLabel: '[data-test-counts-start-label]',
description: '[data-test-counts-description]',
startMonth: '[data-test-counts-start-month]',
startEdit: '[data-test-counts-start-edit]',
startDropdown: '[data-test-counts-start-dropdown]',
configDisabled: '[data-test-counts-disabled]',
namespaces: '[data-test-counts-namespaces]',
mountPaths: '[data-test-counts-auth-mounts]',
startDiscrepancy: '[data-test-counts-start-discrepancy]',
},
tokenTab: {
entity: '[data-test-monthly-new-entity]',
nonentity: '[data-test-monthly-new-nonentity]',
legend: '[data-test-monthly-new-legend]',
},
syncTab: {
total: '[data-test-total-sync-clients]',
average: '[data-test-average-sync-clients]',
},
charts: {
chart: (title: string) => `[data-test-chart="${title}"]`, // newer lineal charts
statTextValue: (label: string) =>
label ? `[data-test-stat-text-container="${label}"] .stat-value` : '[data-test-stat-text-container]',
legend: '[data-test-chart-container-legend]',
legendLabel: (nth: number) => `.legend-label:nth-child(${nth * 2})`, // nth * 2 accounts for dots in legend
timestamp: '[data-test-chart-container-timestamp]',
dataBar: '[data-test-vertical-bar]',
xAxisLabel: '[data-test-x-axis] text',
// selectors for old d3 charts
verticalBar: '[data-test-vertical-bar-chart]',
lineChart: '[data-test-line-chart]',
bar: {
xAxisLabel: '[data-test-vertical-chart="x-axis-labels"] text',
dataBar: '[data-test-vertical-chart="data-bar"]',
},
line: {
xAxisLabel: '[data-test-line-chart] [data-test-x-axis] text',
plotPoint: '[data-test-line-chart="plot-point"]',
},
},
usageStats: '[data-test-usage-stats]',
dateDisplay: '[data-test-date-display]',
attributionBlock: '[data-test-clients-attribution]',
filterBar: '[data-test-clients-filter-bar]',
rangeDropdown: '[data-test-calendar-widget-trigger]',
monthDropdown: '[data-test-toggle-month]',
yearDropdown: '[data-test-toggle-year]',
currentBillingPeriod: '[data-test-current-billing-period]',
dateDropdown: {
toggleMonth: '[data-test-toggle-month]',
toggleYear: '[data-test-toggle-year]',
selectMonth: (month: string) => `[data-test-dropdown-month="${month}"]`,
selectYear: (year: string) => `[data-test-dropdown-year="${year}"]`,
submit: '[data-test-date-dropdown-submit]',
},
calendarWidget: {
trigger: '[data-test-calendar-widget-trigger]',
currentMonth: '[data-test-current-month]',
currentBillingPeriod: '[data-test-current-billing-period]',
customEndMonth: '[data-test-show-calendar]',
previousYear: '[data-test-previous-year]',
nextYear: '[data-test-next-year]',
calendarMonth: (month: string) => `[data-test-calendar-month="${month}"]`,
},
runningTotalMonthStats: '[data-test-running-total="single-month-stats"]',
runningTotalMonthlyCharts: '[data-test-running-total="monthly-charts"]',
selectedAuthMount: 'div#auth-method-search-select [data-test-selected-option] div',
selectedNs: 'div#namespace-search-select [data-test-selected-option] div',
upgradeWarning: '[data-test-clients-upgrade-warning]',
};
export const CHART_ELEMENTS = {
entityClientDataBars: '[data-test-group="entity_clients"]',
nonEntityDataBars: '[data-test-group="non_entity_clients"]',
yLabels: '[data-test-group="y-labels"]',
actionBars: '[data-test-group="action-bars"]',
labelActionBars: '[data-test-group="label-action-bars"]',
totalValues: '[data-test-group="total-values"]',
};

View File

@ -5,22 +5,22 @@
/* /*
returns an instance of CodeMirror, see docs for callable functions https://codemirror.net/5/doc/manual.html#api_constructor returns an instance of CodeMirror, see docs for callable functions https://codemirror.net/5/doc/manual.html#api_constructor
If you are targeting a specific CodeMirror instance, pass the selector of the parent element as an argument.
sample use: sample use:
import codemirror from 'vault/tests/helpers/codemirror'; import codemirror from 'vault/tests/helpers/codemirror';
test('it renders initial value', function (assert) { test('it renders initial value', function (assert) {
// General use
assert.strictEqual(codemirror.getValue(), 'some value') assert.strictEqual(codemirror().getValue(), 'some other value')
// Specific selector
codemirror('#my-control').setValue('some value');
assert.strictEqual(codemirror('#my-control').getValue(), 'some value')
)} )}
*/ */
export default function (parent) {
const invariant = (truthy, error) => { const selector = parent ? `${parent} .CodeMirror` : '.CodeMirror';
if (!truthy) throw new Error(error); const element = document.querySelector(selector);
};
export default function () {
const element = document.querySelector('.CodeMirror');
invariant(element, `Selector '.CodeMirror' matched no elements`); invariant(element, `Selector '.CodeMirror' matched no elements`);
const cm = element.CodeMirror; const cm = element.CodeMirror;
@ -28,3 +28,7 @@ export default function () {
return cm; return cm;
} }
const invariant = (truthy, error) => {
if (!truthy) throw new Error(error);
};

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: BUSL-1.1 * SPDX-License-Identifier: BUSL-1.1
*/ */
export const SELECTORS = { export const DASHBOARD = {
cardName: (name) => `[data-test-card="${name}"]`, cardName: (name) => `[data-test-card="${name}"]`,
emptyState: (name) => `[data-test-empty-state="${name}"]`, emptyState: (name) => `[data-test-empty-state="${name}"]`,
emptyStateTitle: (name) => `[data-test-empty-state="${name}"] [data-test-empty-state-title]`, emptyStateTitle: (name) => `[data-test-empty-state="${name}"] [data-test-empty-state-title]`,

View File

@ -8,7 +8,7 @@ const SELECTORS = {
dropdown: '[data-test-copy-menu-trigger]', dropdown: '[data-test-copy-menu-trigger]',
wrapButton: '[data-test-wrap-button]', wrapButton: '[data-test-wrap-button]',
}; };
export default async function assertSecretWrap(assert, server, path) { export async function assertSecretWrap(assert, server, path) {
server.get(path, () => { server.get(path, () => {
assert.ok(true, `request made to ${path} when wrapping secret`); assert.ok(true, `request made to ${path} when wrapping secret`);
}); });

View File

@ -6,6 +6,14 @@
import { allFeatures } from 'vault/helpers/all-features'; import { allFeatures } from 'vault/helpers/all-features';
import sinon from 'sinon'; import sinon from 'sinon';
/**
* Sets up the necessary shared test context for testing sidebar nav components
* @param {TestContext.owner} owner eg this.owner from within a test
* @param {boolean} isEnterprise [default false]
* @param {boolean} setCluster [default false] if true, will set the current cluster to one with replication & raft
* @param {string[]} features if not passed, defaults to all features
* @returns {hasNavPermission: sinon.SinonStub, features: string[]}
*/
export const stubFeaturesAndPermissions = (owner, isEnterprise = false, setCluster = false, features) => { export const stubFeaturesAndPermissions = (owner, isEnterprise = false, setCluster = false, features) => {
const permissions = owner.lookup('service:permissions'); const permissions = owner.lookup('service:permissions');
const hasNavPermission = sinon.stub(permissions, 'hasNavPermission'); const hasNavPermission = sinon.stub(permissions, 'hasNavPermission');

View File

@ -3,17 +3,15 @@
* SPDX-License-Identifier: BUSL-1.1 * SPDX-License-Identifier: BUSL-1.1
*/ */
const selectors = { export const TTL_PICKER = {
ttlFormGroup: '[data-test-ttl-inputs]', ttlFormGroup: '[data-test-ttl-inputs]',
toggle: '[data-test-ttl-toggle]', toggle: '[data-test-ttl-toggle]',
toggleByLabel: (label) => `[data-test-ttl-toggle="${label}"]`, toggleByLabel: (label: string) => `[data-test-ttl-toggle="${label}"]`,
label: '[data-test-ttl-form-label]', label: '[data-test-ttl-form-label]',
subtext: '[data-test-ttl-form-subtext]', subtext: '[data-test-ttl-form-subtext]',
tooltipTrigger: `[data-test-tooltip-trigger]`, tooltipTrigger: `[data-test-tooltip-trigger]`,
ttlValue: '[data-test-ttl-value]', ttlValue: '[data-test-ttl-value]',
ttlUnit: '[data-test-select="ttl-unit"]', ttlUnit: '[data-test-select="ttl-unit"]',
valueInputByLabel: (label) => `[data-test-ttl-value="${label}"]`, valueInputByLabel: (label: string) => `[data-test-ttl-value="${label}"]`,
unitInputByLabel: (label) => `[data-test-ttl-unit="${label}"] [data-test-select="ttl-unit"]`, unitInputByLabel: (label: string) => `[data-test-ttl-unit="${label}"] [data-test-select="ttl-unit"]`,
}; };
export default selectors;

View File

@ -1,31 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { SELECTORS as GENERAL } from 'vault/tests/helpers/general-selectors';
export const PAGE = {
// General selectors that are common between pages
...GENERAL,
inlineErrorMessage: `[data-test-inline-error-message]`,
unauthCreateFormInfo: '[data-test-unauth-info]',
navLink: '[data-test-sidebar-nav-link="Custom Messages"]',
radio: (radioName) => `[data-test-radio="${radioName}"]`,
field: (fieldName) => `[data-test-field="${fieldName}"]`,
input: (input) => `[data-test-input="${input}"]`,
button: (buttonName) => `[data-test-button="${buttonName}"]`,
fieldValidation: (fieldName) => `[data-test-field-validation="${fieldName}"]`,
modal: (name) => `[data-test-modal="${name}"]`,
modalTitle: (title) => `[data-test-modal-title="${title}"]`,
modalBody: (name) => `[data-test-modal-body="${name}"]`,
modalButton: (name) => `[data-test-modal-button="${name}"]`,
alert: (name) => `data-test-custom-alert=${name}`,
alertTitle: (name) => `[data-test-custom-alert-title="${name}"]`,
alertDescription: (name) => `[data-test-custom-alert-description="${name}"]`,
alertAction: (name) => `[data-test-custom-alert-action="${name}"]`,
badge: (name) => `[data-test-badge="${name}"]`,
tab: (name) => `[data-test-custom-messages-tab="${name}"]`,
confirmActionButton: (name) => `[data-test-confirm-action="${name}"]`,
listItem: (name) => `[data-test-list-item="${name}"]`,
};

View File

@ -0,0 +1,28 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export const CUSTOM_MESSAGES = {
// General selectors that are common between custom messages
inlineErrorMessage: `[data-test-inline-error-message]`,
unauthCreateFormInfo: '[data-test-unauth-info]',
navLink: '[data-test-sidebar-nav-link="Custom Messages"]',
radio: (radioName: string) => `[data-test-radio="${radioName}"]`,
field: (fieldName: string) => `[data-test-field="${fieldName}"]`,
input: (input: string) => `[data-test-input="${input}"]`,
button: (buttonName: string) => `[data-test-button="${buttonName}"]`,
fieldValidation: (fieldName: string) => `[data-test-field-validation="${fieldName}"]`,
modal: (name: string) => `[data-test-modal="${name}"]`,
modalTitle: (title: string) => `[data-test-modal-title="${title}"]`,
modalBody: (name: string) => `[data-test-modal-body="${name}"]`,
modalButton: (name: string) => `[data-test-modal-button="${name}"]`,
alert: (name: string) => `data-test-custom-alert=${name}`,
alertTitle: (name: string) => `[data-test-custom-alert-title="${name}"]`,
alertDescription: (name: string) => `[data-test-custom-alert-description="${name}"]`,
alertAction: (name: string) => `[data-test-custom-alert-action="${name}"]`,
badge: (name: string) => `[data-test-badge="${name}"]`,
tab: (name: string) => `[data-test-custom-messages-tab="${name}"]`,
confirmActionButton: (name: string) => `[data-test-confirm-action="${name}"]`,
listItem: (name: string) => `[data-test-list-item="${name}"]`,
};

View File

@ -1,87 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { findAll } from '@ember/test-helpers';
export const SELECTORS = {
breadcrumb: '[data-test-breadcrumbs] li',
breadcrumbAtIdx: (idx) => `[data-test-breadcrumbs] li:nth-child(${idx + 1}) a`,
breadcrumbs: '[data-test-breadcrumbs]',
breadcrumbLink: (label) => `[data-test-breadcrumb="${label}"] a`,
title: '[data-test-page-title]',
headerContainer: 'header.page-header',
icon: (name) => `[data-test-icon="${name}"]`,
tab: (name) => `[data-test-tab="${name}"]`,
filter: (name) => `[data-test-filter="${name}"]`,
filterInput: '[data-test-filter-input]',
confirmModalInput: '[data-test-confirmation-modal-input]',
confirmButton: '[data-test-confirm-button]',
confirmTrigger: '[data-test-confirm-action-trigger]',
emptyStateTitle: '[data-test-empty-state-title]',
emptyStateMessage: '[data-test-empty-state-message]',
emptyStateActions: '[data-test-empty-state-actions]',
menuTrigger: '[data-test-popup-menu-trigger]',
listItem: '[data-test-list-item-link]',
calendarWidget: {
trigger: '[data-test-calendar-widget-trigger]',
currentMonth: '[data-test-current-month]',
currentBillingPeriod: '[data-test-current-billing-period]',
customEndMonth: '[data-test-show-calendar]',
previousYear: '[data-test-previous-year]',
nextYear: '[data-test-next-year]',
calendarMonth: (month) => `[data-test-calendar-month="${month}"]`,
},
dateDropdown: {
toggleMonth: '[data-test-toggle-month]',
toggleYear: '[data-test-toggle-year]',
selectMonth: (month) => `[data-test-dropdown-month="${month}"]`,
selectYear: (year) => `[data-test-dropdown-year="${year}"]`,
submit: '[data-test-date-dropdown-submit]',
},
// FORMS
infoRowLabel: (label) => `[data-test-row-label="${label}"]`,
infoRowValue: (label) => `[data-test-value-div="${label}"]`,
inputByAttr: (attr) => `[data-test-input="${attr}"]`,
selectByAttr: (attr) => `[data-test-select="${attr}"]`,
fieldByAttr: (attr) => `[data-test-field="${attr}"]`,
enableField: (attr) => `[data-test-enable-field="${attr}"] button`,
ttl: {
toggle: (attr) => `[data-test-toggle-label="${attr}"]`,
input: (attr) => `[data-test-ttl-value="${attr}"]`,
},
validation: (attr) => `[data-test-field-validation=${attr}]`,
validationWarning: (attr) => `[data-test-validation-warning=${attr}]`,
messageError: '[data-test-message-error]',
kvObjectEditor: {
deleteRow: (idx = 0) => `[data-test-kv-delete-row="${idx}"]`,
},
searchSelect: {
options: '.ember-power-select-option',
optionIndex: (text) => findAll('.ember-power-select-options li').findIndex((e) => e.innerText === text),
option: (index = 0) => `.ember-power-select-option:nth-child(${index + 1})`,
selectedOption: (index = 0) => `[data-test-selected-option="${index}"]`,
noMatch: '.ember-power-select-option--no-matches-message',
removeSelected: '[data-test-selected-list-button="delete"]',
},
overviewCard: {
title: (title) => `[data-test-overview-card-title="${title}"]`,
description: (title) => `[data-test-overview-card-subtitle="${title}"]`,
content: (title) => `[data-test-overview-card-content="${title}"]`,
action: (title) => `[data-test-overview-card-container="${title}"] [data-test-action-text]`,
actionLink: (label) => `[data-test-action-text="${label}"]`,
},
pagination: {
next: '.hds-pagination-nav__arrow--direction-next',
prev: '.hds-pagination-nav__arrow--direction-prev',
},
kvSuggestion: {
input: '[data-test-kv-suggestion-input]',
select: '[data-test-kv-suggestion-select]',
},
navLink: (label) => `[data-test-sidebar-nav-link="${label}"]`,
cancelButton: '[data-test-cancel]',
saveButton: '[data-test-save]',
};

View File

@ -0,0 +1,75 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { findAll } from '@ember/test-helpers';
export const GENERAL = {
breadcrumb: '[data-test-breadcrumbs] li',
breadcrumbAtIdx: (idx: string) => `[data-test-breadcrumbs] li:nth-child(${idx + 1}) a`,
breadcrumbs: '[data-test-breadcrumbs]',
breadcrumbLink: (label: string) => `[data-test-breadcrumb="${label}"] a`,
title: '[data-test-page-title]',
headerContainer: 'header.page-header',
icon: (name: string) => `[data-test-icon="${name}"]`,
tab: (name: string) => `[data-test-tab="${name}"]`,
secretTab: (name: string) => `[data-test-secret-list-tab="${name}"]`,
filter: (name: string) => `[data-test-filter="${name}"]`,
filterInput: '[data-test-filter-input]',
confirmModalInput: '[data-test-confirmation-modal-input]',
confirmButton: '[data-test-confirm-button]',
confirmTrigger: '[data-test-confirm-action-trigger]',
emptyStateTitle: '[data-test-empty-state-title]',
emptyStateMessage: '[data-test-empty-state-message]',
emptyStateActions: '[data-test-empty-state-actions]',
menuTrigger: '[data-test-popup-menu-trigger]',
listItem: '[data-test-list-item-link]',
// FORMS
infoRowLabel: (label: string) => `[data-test-row-label="${label}"]`,
infoRowValue: (label: string) => `[data-test-value-div="${label}"]`,
inputByAttr: (attr: string) => `[data-test-input="${attr}"]`,
selectByAttr: (attr: string) => `[data-test-select="${attr}"]`,
checkboxByAttr: (attr: string) => `[data-test-checkbox="${attr}"]`,
fieldByAttr: (attr: string) => `[data-test-field="${attr}"]`,
enableField: (attr: string) => `[data-test-enable-field="${attr}"] button`,
ttl: {
toggle: (attr: string) => `[data-test-toggle-label="${attr}"]`,
input: (attr: string) => `[data-test-ttl-value="${attr}"]`,
},
validation: (attr: string) => `[data-test-field-validation=${attr}]`,
validationWarning: (attr: string) => `[data-test-validation-warning=${attr}]`,
messageError: '[data-test-message-error]',
kvObjectEditor: {
deleteRow: (idx = 0) => `[data-test-kv-delete-row="${idx}"]`,
},
searchSelect: {
options: '.ember-power-select-option',
optionIndex: (text: string) =>
findAll('.ember-power-select-options li').findIndex((e) => e.textContent?.trim() === text),
option: (index = 0) => `.ember-power-select-option:nth-child(${index + 1})`,
selectedOption: (index = 0) => `[data-test-selected-option="${index}"]`,
noMatch: '.ember-power-select-option--no-matches-message',
removeSelected: '[data-test-selected-list-button="delete"]',
},
overviewCard: {
title: (title: string) => `[data-test-overview-card-title="${title}"]`,
description: (title: string) => `[data-test-overview-card-subtitle="${title}"]`,
content: (title: string) => `[data-test-overview-card-content="${title}"]`,
action: (title: string) => `[data-test-overview-card-container="${title}"] [data-test-action-text]`,
actionLink: (label: string) => `[data-test-action-text="${label}"]`,
},
pagination: {
next: '.hds-pagination-nav__arrow--direction-next',
prev: '.hds-pagination-nav__arrow--direction-prev',
},
kvSuggestion: {
input: '[data-test-kv-suggestion-input]',
select: '[data-test-kv-suggestion-select]',
},
navLink: (label: string) => `[data-test-sidebar-nav-link="${label}"]`,
cancelButton: '[data-test-cancel]',
saveButton: '[data-test-save]',
};

View File

@ -3,7 +3,8 @@
* SPDX-License-Identifier: BUSL-1.1 * SPDX-License-Identifier: BUSL-1.1
*/ */
export const SELECTORS = { export const KUBERNETES_OVERVIEW = {
// Page::Overview in the kubernetes engine
rolesCardTitle: '[data-test-overview-card-title="Roles"]', rolesCardTitle: '[data-test-overview-card-title="Roles"]',
rolesCardSubTitle: '[data-test-overview-card-subtitle="Roles"]', rolesCardSubTitle: '[data-test-overview-card-subtitle="Roles"]',
rolesCardLink: '[data-test-overview-card="Roles"] a', rolesCardLink: '[data-test-overview-card="Roles"] a',
@ -11,7 +12,4 @@ export const SELECTORS = {
generateCredentialsCardTitle: '[data-test-overview-card-title="Generate credentials"]', generateCredentialsCardTitle: '[data-test-overview-card-title="Generate credentials"]',
generateCredentialsCardSubTitle: '[data-test-overview-card-subtitle="Generate credentials"]', generateCredentialsCardSubTitle: '[data-test-overview-card-subtitle="Generate credentials"]',
generateCredentialsCardButton: '[data-test-generate-credential-button]', generateCredentialsCardButton: '[data-test-generate-credential-button]',
emptyStateTitle: '.empty-state .empty-state-title',
emptyStateMessage: '.empty-state .empty-state-message',
emptyStateActionText: '.empty-state .empty-state-actions',
}; };

View File

@ -1,17 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { getContext } from '@ember/test-helpers';
export default (data) => {
const context = getContext();
const store = context.owner.lookup('service:store');
const modelName = Array.isArray(data) ? data[0].modelName : data.modelName;
const json = context.server.serializerOrRegistry.serialize(data);
store.push(json);
return Array.isArray(data)
? data.map(({ id }) => store.peekRecord(modelName, id))
: store.peekRecord(modelName, data.id);
};

View File

@ -1,23 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Pretender from 'pretender';
import { noopStub } from './stubs';
/**
* DEPRECATED prefer to use `setupMirage` along with stubs in vault/tests/helpers/stubs
*/
export default function (options = { usePassthrough: false }) {
return new Pretender(function () {
let fn = noopStub();
if (options.usePassthrough) {
fn = this.passthrough;
}
this.post('/v1/**', fn);
this.put('/v1/**', fn);
this.get('/v1/**', fn);
this.delete('/v1/**', fn || noopStub(204));
});
}

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: BUSL-1.1 * SPDX-License-Identifier: BUSL-1.1
*/ */
import { Response } from 'miragejs'; import { debug } from '@ember/debug';
export const OIDC_BASE_URL = `/vault/access/oidc`; export const OIDC_BASE_URL = `/vault/access/oidc`;
@ -57,49 +57,6 @@ export const SELECTORS = {
providerClientsTab: '[data-test-oidc-provider-clients]', providerClientsTab: '[data-test-oidc-provider-clients]',
}; };
export function overrideMirageResponse(httpStatus, data) {
if (httpStatus === 403) {
return new Response(
403,
{ 'Content-Type': 'application/json' },
JSON.stringify({ errors: ['permission denied'] })
);
}
if (httpStatus === 404) {
return new Response(404, { 'Content-Type': 'application/json' });
}
if (httpStatus === 200) {
return new Response(200, { 'Content-Type': 'application/json' }, JSON.stringify(data));
}
return {
request_id: crypto.randomUUID(),
lease_id: '',
renewable: false,
lease_duration: 0,
wrap_info: null,
warnings: null,
auth: null,
data: { ...data },
};
}
export function overrideCapabilities(requestPath, capabilitiesArray) {
// sample of capabilitiesArray: ['read', 'update']
return {
request_id: '40f7e44d-af5c-9b60-bd20-df72eb17e294',
lease_id: '',
renewable: false,
lease_duration: 0,
data: {
capabilities: capabilitiesArray,
[requestPath]: capabilitiesArray,
},
wrap_info: null,
warnings: null,
auth: null,
};
}
export async function clearRecord(store, modelType, id) { export async function clearRecord(store, modelType, id) {
await store await store
.findRecord(modelType, id) .findRecord(modelType, id)
@ -107,6 +64,7 @@ export async function clearRecord(store, modelType, id) {
deleteModelRecord(model); deleteModelRecord(model);
}) })
.catch(() => { .catch(() => {
debug(`Clearing record failed for ${modelType} with id: ${id}`);
// swallow error // swallow error
}); });
} }

View File

@ -3,6 +3,10 @@
* SPDX-License-Identifier: BUSL-1.1 * SPDX-License-Identifier: BUSL-1.1
*/ */
// The constants within this file represent the expected model attributes as parsed from OpenAPI
// if changes are made to the OpenAPI spec, that may result in changes that must be reflected
// here AND ensured to not cause breaking changes within the UI.
const userpass = { const userpass = {
user: { user: {
username: { username: {

View File

@ -1,56 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import authModelAttributes from './auth-model-attributes';
import secretModelAttributes from './secret-model-attributes';
export const secretEngineHelper = (test, secretEngine) => {
const engineData = secretModelAttributes[secretEngine];
if (!engineData)
throw new Error(`No engine attributes found in secret-model-attributes for ${secretEngine}`);
const modelNames = Object.keys(engineData);
// A given secret engine might have multiple models that are openApi driven
modelNames.forEach((modelName) => {
test(`${modelName} model getProps returns correct attributes`, async function (assert) {
const model = this.store.createRecord(modelName, {});
const helpUrl = model.getHelpUrl(this.backend);
const result = await this.pathHelp.getProps(helpUrl, this.backend);
const expected = engineData[modelName];
assert.deepEqual(result, expected, `getProps returns expected attributes for ${modelName}`);
});
});
};
export const authEngineHelper = (test, authBackend) => {
const authData = authModelAttributes[authBackend];
if (!authData) throw new Error(`No auth attributes found in auth-model-attributes for ${authBackend}`);
const itemNames = Object.keys(authData);
itemNames.forEach((itemName) => {
if (itemName.startsWith('auth-config/')) {
// Config test doesn't need to instantiate a new model
test(`${itemName} model`, async function (assert) {
const model = this.store.createRecord(itemName, {});
const helpUrl = model.getHelpUrl(this.mount);
const result = await this.pathHelp.getProps(helpUrl, this.mount);
const expected = authData[itemName];
assert.deepEqual(result, expected, `getProps returns expected attributes for ${itemName}`);
});
} else {
test.skip(`generated-${itemName}-${authBackend} model`, async function (assert) {
const modelName = `generated-${itemName}-${authBackend}`;
// Generated items need to instantiate the model first via getNewModel
await this.pathHelp.getNewModel(modelName, this.mount, `auth/${this.mount}/`, itemName);
const model = this.store.createRecord(modelName, {});
// Generated items don't have this method -- helpUrl is calculated in path-help.js line 101
const helpUrl = model.getHelpUrl(this.mount);
const result = await this.pathHelp.getProps(helpUrl, this.mount);
const expected = authData[modelName];
assert.deepEqual(result, expected, `getProps returns expected attributes for ${modelName}`);
});
}
});
};

View File

@ -0,0 +1,10 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const STANDARD_META = {
total: 2,
currentPage: 1,
pageSize: 100,
};

View File

@ -1,23 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const SELECTORS = {
caChain: '[data-test-value-div="CA chain"] [data-test-certificate-card]',
certificate: '[data-test-value-div="Certificate"] [data-test-certificate-card]',
commonName: '[data-test-row-value="Common name"]',
csr: '[data-test-value-div="CSR"] [data-test-certificate-card]',
expiryDate: '[data-test-row-value="Expiration date"]',
issueDate: '[data-test-row-value="Issue date"]',
issuingCa: '[data-test-value-div="Issuing CA"] [data-test-certificate-card]',
privateKey: '[data-test-value-div="Private key"] [data-test-certificate-card]',
revocationTime: '[data-test-row-value="Revocation time"]',
serialNumber: '[data-test-row-value="Serial number"]',
};
export const STANDARD_META = {
total: 2,
currentPage: 1,
pageSize: 100,
};

View File

@ -1,27 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const SELECTORS = {
issuersCardTitle: '[data-test-overview-card-title="Issuers"]',
issuersCardSubtitle: '[data-test-overview-card-subtitle="Issuers"]',
issuersCardLink: '[data-test-overview-card-container="Issuers"] a',
issuersCardOverviewNum: '[data-test-overview-card-container="Issuers"] h2',
rolesCardTitle: '[data-test-overview-card-title="Roles"]',
rolesCardSubtitle: '[data-test-overview-card-subtitle="Roles"]',
rolesCardLink: '[data-test-overview-card-container="Roles"] a',
rolesCardOverviewNum: '[data-test-overview-card-container="Roles"] h2',
issueCertificate: '[data-test-overview-card-title="Issue certificate"]',
issueCertificateInput: '[data-test-issue-certificate-input]',
issueCertificatePowerSearch: '[data-test-issue-certificate-input] span',
issueCertificateButton: '[data-test-issue-certificate-button]',
viewCertificate: '[data-test-overview-card-title="View certificate"]',
viewCertificateInput: '[data-test-view-certificate-input]',
viewCertificatePowerSearch: '[data-test-view-certificate-input] span',
viewCertificateButton: '[data-test-view-certificate-button]',
viewIssuerInput: '[data-test-issue-issuer-input]',
viewIssuerPowerSearch: '[data-test-issue-issuer-input] span',
viewIssuerButton: '[data-test-view-issuer-button]',
firstPowerSelectOption: '[data-option-index="0"]',
};

View File

@ -1,25 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const SELECTORS = {
errorBanner: '[data-test-config-edit-error]',
acmeEditSection: '[data-test-acme-edit-section]',
configEditSection: '[data-test-cluster-config-edit-section]',
configInput: (attr) => `[data-test-input="${attr}"]`,
stringListInput: (attr) => `[data-test-input="${attr}"] [data-test-string-list-input="0"]`,
urlsEditSection: '[data-test-urls-edit-section]',
urlFieldInput: (attr) => `[data-test-input="${attr}"] textarea`,
urlFieldLabel: (attr) => `[data-test-input="${attr}"] label`,
crlEditSection: '[data-test-crl-edit-section]',
crlToggleInput: (attr) => `[data-test-input="${attr}"] input`,
crlTtlInput: (attr) => `[data-test-ttl-value="${attr}"]`,
crlFieldLabel: (attr) => `[data-test-input="${attr}"] label`,
saveButton: '[data-test-configuration-edit-save]',
cancelButton: '[data-test-configuration-edit-cancel]',
validationAlert: '[data-test-configuration-edit-validation-alert]',
deleteButton: (attr) => `[data-test-input="${attr}"] [data-test-string-list-button="delete"]`,
groupHeader: (group) => `[data-test-crl-header="${group}"]`,
checkboxInput: (attr) => `[data-test-input="${attr}"]`,
};

View File

@ -1,26 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const SELECTORS = {
// key index
importKey: '[data-test-pki-key-import]',
generateKey: '[data-test-pki-key-generate]',
keyId: '[data-test-key="id"]',
keyName: '[data-test-key="name"]',
popupMenuTrigger: '[data-test-popup-menu-trigger]',
popupMenuDetails: '[data-test-key-menu-link="details"]',
popupMenuEdit: '[data-test-key-menu-link="edit"]',
// key details
title: '[data-test-key-details-title]',
keyIdValue: '[data-test-value-div="Key ID"]',
keyNameValue: '[data-test-value-div="Key name"]',
keyTypeValue: '[data-test-value-div="Key type"]',
keyBitsValue: '[data-test-value-div="Key bits"]',
keyDeleteButton: '[data-test-pki-key-delete]',
downloadButton: '[data-test-download-button]',
keyEditLink: '[data-test-pki-key-edit]',
confirmDelete: '[data-test-confirm-button]',
nextStepsAlert: '[data-test-pki-key-next-steps]',
};

View File

@ -1,12 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const SELECTORS = {
issuerLabel: '[data-test-row-label="Issuer"]',
noStoreValue: '[data-test-value-div="Store in storage backend"]',
keyUsageValue: '[data-test-value-div="Key usage"]',
extKeyUsageValue: '[data-test-value-div="Ext key usage"]',
customTtlValue: '[data-test-value-div="Issued certificates expire after"]',
};

View File

@ -1,18 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const SELECTORS = {
tidyFormName: (attr) => `[data-test-tidy-form="${attr}"]`,
inputByAttr: (attr) => `[data-test-input="${attr}"]`,
toggleInput: (attr) => `[data-test-input="${attr}"] input`,
intervalDuration: '[data-test-ttl-value="Automatic tidy enabled"]',
acmeAccountSafetyBuffer: '[data-test-ttl-value="Tidy ACME enabled"]',
toggleLabel: (label) => `[data-test-toggle-label="${label}"]`,
tidySectionHeader: (header) => `[data-test-tidy-header="${header}"]`,
tidySave: '[data-test-pki-tidy-button]',
tidyCancel: '[data-test-pki-tidy-cancel]',
tidyPauseDuration: '[data-test-ttl-value="Pause duration"]',
editAutoTidyButton: '[data-test-pki-edit-tidy-auto-link]',
};

View File

@ -1,30 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { SELECTORS as TIDY_FORM } from './pki-tidy-form';
export const SELECTORS = {
hdsAlertTitle: '[data-test-tidy-status-alert-title]',
hdsAlertDescription: '[data-test-tidy-status-alert-description]',
alertUpdatedAt: '[data-test-tidy-status-alert-updated-at]',
cancelTidyAction: '[data-test-cancel-tidy-action]',
hdsAlertButtonText: '[data-test-cancel-tidy-action] .hds-button__text',
timeStartedRow: '[data-test-value-div="Time started"]',
timeFinishedRow: '[data-test-value-div="Time finished"]',
cancelTidyModalBackground: '#pki-cancel-tidy-modal',
tidyEmptyStateConfigure: '[data-test-tidy-empty-state-configure]',
manualTidyToolbar: '[data-test-pki-manual-tidy-config]',
autoTidyToolbar: '[data-test-pki-auto-tidy-config]',
tidyConfigureModal: {
configureTidyModal: '#pki-tidy-modal',
tidyModalAutoButton: '[data-test-tidy-modal-auto-button]',
tidyModalManualButton: '[data-test-tidy-modal-manual-button]',
tidyModalCancelButton: '[data-test-tidy-modal-cancel-button]',
tidyOptionsModal: '[data-test-pki-tidy-options-modal]',
},
tidyEmptyState: '[data-test-component="empty-state"]',
tidyForm: {
...TIDY_FORM,
},
};

View File

@ -1,30 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { SELECTORS as GENERATE_ROOT } from './pki-generate-root';
export const SELECTORS = {
// page::pki-configure-create
breadcrumbContainer: '[data-test-breadcrumbs]',
title: '[data-test-pki-engine-page-title]',
option: '[data-test-pki-config-option]',
optionByKey: (key) => `[data-test-pki-config-option="${key}"]`,
cancelButton: '[data-test-pki-config-cancel]',
saveButton: '[data-test-pki-config-save]',
doneButton: '[data-test-done]',
configureButton: '[data-test-configure-pki-button]',
// pki-generate-root
...GENERATE_ROOT,
generateRootOption: '[data-test-pki-config-option="generate-root"]',
// pki-ca-cert-import
importForm: '[data-test-pki-import-pem-bundle-form]',
importSubmit: '[data-test-pki-import-pem-bundle]',
importSectionLabel: '[data-test-import-section-label]',
importMapping: '[data-test-imported-bundle-mapping]',
importedIssuer: '[data-test-imported-issuer]',
importedKey: '[data-test-imported-key]',
// generate-intermediate
csrDetails: '[data-test-generate-csr-result]',
};

View File

@ -1,11 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const SELECTORS = {
issuerLink: '[data-test-delete-all-issuers-link]',
deleteAllIssuerModal: '#confirmation-modal',
deleteAllIssuerInput: '[data-test-confirmation-modal-input="Delete all issuers?"]',
deleteAllIssuerButton: '[data-test-confirm-button="Delete all issuers?"]',
};

View File

@ -1,35 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const SELECTORS = {
mainSectionTitle: '[data-test-generate-root-title="Root parameters"]',
urlSectionTitle: '[data-test-generate-root-title="Issuer URLs"]',
keyParamsGroupToggle: '[data-test-toggle-group="Key parameters"]',
sanGroupToggle: '[data-test-toggle-group="Subject Alternative Name (SAN) Options"]',
additionalGroupToggle: '[data-test-toggle-group="Additional subject fields"]',
toggleGroupDescription: '[data-test-toggle-group-description]',
formField: '[data-test-field]',
typeField: '[data-test-input="type"]',
inputByName: (name) => `[data-test-input="${name}"]`,
fieldByName: (name) => `[data-test-field="${name}"]`,
generateRootSave: '[data-test-pki-generate-root-save]',
generateRootCancel: '[data-test-pki-generate-root-cancel]',
generateRootCommonNameField: '[data-test-input="commonName"]',
generateRootIssuerNameField: '[data-test-input="issuerName"]',
formInvalidError: '[data-test-pki-generate-root-validation-error]',
urlsSection: '[data-test-urls-section]',
urlField: '[data-test-urls-section] [data-test-input]',
// Shown values after save
saved: {
certificate: '[data-test-value-div="Certificate"] [data-test-certificate-card]',
commonName: '[data-test-row-value="Common name"]',
issuerName: '[data-test-row-value="Issuer name"]',
issuerLink: '[data-test-value-div="Issuer ID"] a',
keyName: '[data-test-row-value="Key name"]',
keyLink: '[data-test-value-div="Key ID"] a',
privateKey: '[data-test-value-div="Private key"] [data-test-certificate-card]',
serialNumber: '[data-test-row-value="Serial number"]',
},
};

View File

@ -0,0 +1,251 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import type StoreService from 'vault/services/store';
export const PKI_BASE_URL = `/vault/cluster/secrets/backend/pki/roles`;
// Clears pki-related data and capabilities so that admin
// capabilities from setup don't rollover
export function clearRecords(store: StoreService) {
store.unloadAll('pki/action');
store.unloadAll('pki/issuer');
store.unloadAll('pki/key');
store.unloadAll('pki/role');
store.unloadAll('pki/sign-intermediate');
store.unloadAll('pki/tidy');
store.unloadAll('pki/config/urls');
store.unloadAll('pki/config/crl');
store.unloadAll('pki/config/cluster');
store.unloadAll('pki/config/acme');
store.unloadAll('pki/certificate/generate');
store.unloadAll('pki/certificate/sign');
store.unloadAll('capabilities');
}
/**
* The following are certificate values used for testing. They are exported under the CERTIFICATES object.
*/
// Expires Jan 10, 2033
const rootPem = `-----BEGIN CERTIFICATE-----
MIIDezCCAmOgAwIBAgIUTBbQcZijQsmd0rjd6COikPsrGyowDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAxMJdGVzdC1yb290MB4XDTIzMDEyMDE3NTcxMloXDTIzMDIy
MTE3NTc0MlowFDESMBAGA1UEAxMJdGVzdC1yb290MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAlUHfvQLsocXtvwRCpTnXGzwMCD+3KKK7y1+SUCgpAD9Y
RV2xLAbqh0iK3x2WI4+Pek1Ub6dYaWczzBob6wRq9iFB72uLPpbL8yRf+tc1egmP
wwJQS9qidb1hcSi4p6x/JwOpr2v2PDqJPDoHrfaHeJgCuBGS00qUFH7oHQz9Usim
lHjIbVNF3Qa1Hq2bgwkZmRjRn3Bez/xy3YEiQ41GTicUBqY4NAGWuS1LiHyEUW81
iQ+1iGlbpuAL4H7lpKmrhv1xZXEsF9vNL6H0Y7kjjAImTQnmo+ozcArnKnwh2wmS
f/TrVnN4RRc8dvN8P8nWvVsJYK/D40yc7YMljIESKQIDAQABo4HEMIHBMA4GA1Ud
DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBT6rcf5twb19wLL
JjhPOVywd41d2jAfBgNVHSMEGDAWgBT6rcf5twb19wLLJjhPOVywd41d2jArBggr
BgEFBQcBAQQfMB0wGwYIKwYBBQUHMAKGD2Z1bmZvcmVjYXN0LmNvbTAUBgNVHREE
DTALggl0ZXN0LXJvb3QwGwYDVR0fBBQwEjAQoA6gDIYKZ29vZ2xlLmNvbTANBgkq
hkiG9w0BAQsFAAOCAQEAjG7km+QsIuW7KNY3h8YHJZhdr+tIx57k9tUR4w1+d8QI
t44FTdCYdN8n89lsFK9bONZatd0LY3qqcOARE2ni0Hg/zV9u8TTVKTKAOOx8zBd1
TnwzhXb8mssqnXK9lcECexuWf/s5lkyHjcWOuzNVI0PohrX9tGZwdzsZEgH4Y49i
o8I9DD+uBHknwByRLXSDmgggwgOYsyTg/IfYoHlLHDD3CaOpkCvUCZvM9bI7nrlx
2GByQ/WDT4ArAHcf+Z1iaSIbV6WG6QWoPsu2/WKybcuN2fznaXtJMwgRl50BUv2h
DU3c2oZTc0mPYGft6U8mVwLqfYTcEduGidTLAQPE5w==
-----END CERTIFICATE-----`;
const rootDer = `MIIDJjCCAg6gAwIBAgIUZwx170kTAaGFKeyiG3Di
GpwhKvcwDQYJKoZIhvcNAQELBQAwETEPMA0GA1UEAxMGMTExMTExMB4XDTIzMDgw
OTIxMzk0NloXDTIzMDkxMDIxNDAxNlowETEPMA0GA1UEAxMGMTExMTExMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3Hm1gjKWDdXuRLZIk3dDabbzlH+Y
2e4rklkMGlrnNqju2+7iIGZa2q8rQ4jEZ3sesSsqGHUEJ2sIG5HnRhl5yawCr9NS
uJP+3zsNueQLQDj6tEnuN0STZQuEJKc+yeept8JGAD0SGnB+THGUYf3if0D8sDT1
nHj3XihtnTG3fN62iKyx2Y95WKrVmT1MnpGjbp4HkRvrHSR8PKyq9Q6YyZkIYbfW
DH3adq6gmiJITzozaUT6efftPOVPr5LLTPKAl3BAmoc8ypM/H1IPaE1Z7ef9lV9w
gazvoJZEsc59hskTWF3ZLcWIxAjcq7u6IX2+dU/A0DmCY6GKmmcZ9W5A9wIDAQAB
o3YwdDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
b2qEtlDZl/ws00ftFQJX6bjoOckwHwYDVR0jBBgwFoAUb2qEtlDZl/ws00ftFQJX
6bjoOckwEQYDVR0RBAowCIIGMTExMTExMA0GCSqGSIb3DQEBCwUAA4IBAQAFI1H8
EOw+YcequlJp1ucCpTRArLUhH0t+l7hQAqwORGQevEP6Ml63dRrZCcke7esrpnL9
7ijKw/PjgoyrM4QS3wAYm8nDm7cZH+f//A2X6WFnvozwKdmDRkacEjMOAe/XU+qh
jdtiETEnUGVH65ulyimKitU5SHV0GNfToKnU/SFBks0bQvglIii0YwgHvSoW1++7
arCjfZqWLdRe7MHfrLpLr4gaebfxSrZfn3utgm+DsJVba3B9JnOZO+yzTiEw6UkJ
rcmZDy0x1/OaCcYHKai4RegsiQ0QrIEI+iC1N6U0PGiGf/V23eoTR0+5H6qngDz2
GzXrbHFAPQbtweCf`;
const issuerPemBundle = `
-----BEGIN CERTIFICATE-----
MIIDRTCCAi2gAwIBAgIUdKagCL6TnN5xLkwhPbNY8JEcY0YwDQYJKoZIhvcNAQEL
BQAwGzEZMBcGA1UEAxMQd3d3LnRlc3QtaW50LmNvbTAeFw0yMzAxMDkxOTA1NTBa
Fw0yMzAyMTAxOTA2MjBaMBsxGTAXBgNVBAMTEHd3dy50ZXN0LWludC5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfd5o9JfyRAXH+E1vE2U0xjSqs
A/cxDqsDXRHBnNJvzAa+7gPKXCDQZbr6chjxLXpP6Bv2/O+dZHq1fo/f6q9PDDGW
JYIluwbACpe7W1UB7q9xFkZg85yQsNYokGZlwv/AMGpFBxDwVlNGL+4fxvFTv7uF
mIlDzSIPrzByyCrqAFMNNqNwlAerDt/C6DMZae/rTGXIXsTfUpxPy21bzkeA+70I
YCV1ffK8UnAeBYNUJ+v8+XgTQ5KhRyQ+fscUkO3T2s6f3O9Q2sWxswkf2YmZB+V1
cTZ5w6hqiuFdBXz7GRnACi1/gbWbaExQTJRplArFwIHka7dqJh8tYkXDjai3AgMB
AAGjgYAwfjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
FgQU68/xXIgvsleKkuA8clK/6YslB/IwHwYDVR0jBBgwFoAU68/xXIgvsleKkuA8
clK/6YslB/IwGwYDVR0RBBQwEoIQd3d3LnRlc3QtaW50LmNvbTANBgkqhkiG9w0B
AQsFAAOCAQEAWSff0BH3SJv/XqwN/flqc1CVzOios72/IJ+KBBv0AzFCZ8wJPi+c
hH1bw7tqi01Bgh595TctogDFN1b6pjN+jrlIP4N+FF9Moj79Q+jHQMnuJomyPuI7
i07vqUcxgSmvEBBWOWS+/vxe6TfWDg18nyPf127CWQN8IHTo1f/GavX+XmRve6XT
EWoqcQshEk9i87oqCbaT7B40jgjTAd1r4Cc6P4s1fAGPt9e9eqMj13kTyVDNuCoD
FSZYalrlkASpg+c9oDQIh2MikGQINXHv/zIEHOW93siKMWeA4ni6phHtMg/p5eJt
SxnVZsSzj8QLy2uwX1AADR0QUvJzMxptyA==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAn3eaPSX8kQFx/hNbxNlNMY0qrAP3MQ6rA10RwZzSb8wGvu4D
ylwg0GW6+nIY8S16T+gb9vzvnWR6tX6P3+qvTwwxliWCJbsGwAqXu1tVAe6vcRZG
YPOckLDWKJBmZcL/wDBqRQcQ8FZTRi/uH8bxU7+7hZiJQ80iD68wcsgq6gBTDTaj
cJQHqw7fwugzGWnv60xlyF7E31KcT8ttW85HgPu9CGAldX3yvFJwHgWDVCfr/Pl4
E0OSoUckPn7HFJDt09rOn9zvUNrFsbMJH9mJmQfldXE2ecOoaorhXQV8+xkZwAot
f4G1m2hMUEyUaZQKxcCB5Gu3aiYfLWJFw42otwIDAQABAoIBADC+vZ4Ne4vTtkWl
Izsj9Y29Chs0xx3uzuWjUGcvib/0zOcWGICF8t3hCuu9btRiQ24jlFDGdnRVH5FV
E6OtuFLgdlPgOU1RQzn2wvTZcT26+VQHLBI8xVIRTBVwNmzK06Sq6AEbrNjaenAM
/KwoAuLHzAmFXAgmr0++DIA5oayPWyi5IoyFO7EoRv79Xz5LWfu5j8CKOFXmI5MT
vEVYM6Gb2xHRa2Ng0SJ4VzwC09GcXlHKRAz+CubJuncvjbcM/EryvexozKkUq4XA
KqGr9xxdZ4XDlo3Rj9S9P9JaOin0I1mwwz6p+iwMF0zr+/ldjE4oPBdB1PUgSJ7j
2CZcS1kCgYEAwIZ3UsMIXqkMlkMz/7nu2sqzV3EgQjY5QRoz98ligKg4fhYKz+K4
yXvJrRyLkwEBaPdLppCZbs4xsuuv3jiqUHV5n7sfpUA5HVKkKh6XY7jnszbqV732
iB1mQVEjzM92/amew2hDKLGQDW0nglrg6uV+bx0Lnp6Glahr8NOAyk0CgYEA1Ar3
jTqTkU+NQX7utlxx0HPVL//JH/erp/Gnq9fN8dZhK/yjwX5savUlNHpgePoXf1pE
lgi21/INQsvp7O2AUKuj96k+jBHQ0SS58AQGFv8iNDkLE57N74vCO6+Xdi1rHj/Y
7jglr00box/7SOmvb4SZz2o0jm0Ejsg2M0aBuRMCgYEAgTB6F34qOqMDgD1eQka5
QfXs/Es8E1Ihf08e+jIXuC+poOoXnUINL56ySUizXBS7pnzzNbUoUFNqxB4laF/r
4YvC7m15ocED0mpnIKBghBlK2VaLUA93xAS+XiwdcszwkuzkTUnEbyUfffL2JSHo
dZdEDTmXV3wW4Ywfyn2Sma0CgYAeNNG/FLEg6iw9QE/ROqob/+RGyjFklGunqQ0x
tbRo1xlQotTRI6leMz3xk91aXoYqZjmPBf7GFH0/Hr1cOxkkZM8e4MVAPul4Ybr7
LheP/xhoSBgD24OKtGYfCoyRETdJP98vUGBN8LYXLt8lK+UKBeHDYmXKRE156ZuP
AmRIcQKBgFvp+xMoyAsBeOlTjVDZ0mTnFh1yp8f7N3yXdHPpFShwjXjlqLmLO5RH
mZAvaH0Ux/wCfvwHhdC46jBrs9S4zLBvj3+44NYOzvz2dBWP/5MuXgzFe30h9Yd0
zUlyEaWm0jY2Ylzax8ECKRL0td2bv36vxOYtTax8MSB15szsnPJ+
-----END RSA PRIVATE KEY-----
`;
const csr = `-----BEGIN CERTIFICATE REQUEST-----
MIICdDCCAVwCAQAwDjEMMAoGA1UEAxMDbG9sMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA4Dz2b/nAP/M6bqyk5mctqqYAAcoME//xPBy0wREHuZ776Pu4
l45kDL3dPXiY8U2P9pn8WIr2KpLK6oWUfSsiG2P082bpWDL20UymkWqDhhrA4unf
ZRq68UIDbcetlLw15YKnlNdvNZ7Qr8Se8KV0YGR/wFqI7QfS6VE3lhxZWEBUayI0
egqOuDbXAcZTON1AZ92/F+WFSbc43iYdDk16XfAPFKhtvLr6zQQuzebAb7HG04Hc
GhRskixxyJ8XY6XUplfsa1HcpUXE4f1GeUvq3g6ltVCSJ0p7qI9FFjV4t+DCLVVV
LnwHUi9Vzz6i2wjMt7P6+gHR+RrOWBgRMn38fwIDAQABoCEwHwYJKoZIhvcNAQkO
MRIwEDAOBgNVHREEBzAFggNsb2wwDQYJKoZIhvcNAQELBQADggEBAAm3AHQ1ctdV
8HCrMOXGVLgI2cB1sFd6VYVxPBxIk812Y4wyO8Q6POE5VZNTIgMcSeIaFu5lgHNL
Peeb54F+zEa+OJYkcWgCAX5mY/0HoML4p2bxFTSjllSpcX7ktjq4IEIY/LRpqSgc
jgZHHRwanFfkeIOhN4Q5qJWgBPNhDAcNPE7T0M/4mxqYDqMSJvMYmC67hq1UOOug
/QVDUDJRC1C0aDw9if+DbG/bt1V6HpMQhDIEUjzfu4zG8pcag3cJpOA8JhW1hnG0
XA2ZOCA7s34/szr2FczXtIoKiYmv3UzPyO9/4mc0Q2+/nR4CG8NU9WW/XJCne9ID
elRplAzrMF4=
-----END CERTIFICATE REQUEST-----`;
const csr2 = `-----BEGIN CERTIFICATE REQUEST-----
MIIChDCCAWwCAQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCuW9C58M1wO0vdGmtLcJbbCkKyfsHJJae1j4LL
xdGqs1j9UKD66UALSzZEeMCBdtTNNzThAgYJqCSA5swqpbRf6WZ3K/X7oHbfcrHi
SAm8v/0QsJDF5Rphiy6wyggaoaHEsbSp83kYy9r+h48vFW5Dr8UvJTsp5kdRn31L
bTHr56iqOaHQbu6hDj4Ompg/0OElPH1tV2X947o8timR+L89utZzR+d8x/eeTdPl
H7TEkMEomRvt7NTRHGYRsm3Gzq4AA6PalzIxzwJrNgXfJDutNn/QwcVd5sImwYCO
GaHsOvGfc02w+Vqqva9EOEQSr6B90kA+vc30I6uSiugzV9TFAgMBAAGgKTAnBgkq
hkiG9w0BCQ4xGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEB
CwUAA4IBAQAjm6JTU7axU6TzLlXlOp7hZ4+nep2/8vvJ9EOXzL8x/qtTTizctdG9
Op70gywoUxAS2tatwa4fmW9DbA2eGiLU+Ibj/5b0Veq5DQdp1Qg3MLBP/+AcM/7m
rrgA9MhkpQahXCj4vXo6NeXYaTh6Jo/s8C9h3WxTD6ptDMiaPFcEuWcx0e3AjjH0
pe7k9/MfB2wLfQ7+5wee/tCFWZN4tk8YfjQeQA1extXYKM/f8eu3Z/wjbbMOVpwb
xst+VTY7X9T8cU/hjDEoNG677meI+W5MgiwX0rxTpoz991fqr3vp7PELYj3GMyii
D1YfvqXieNij4UrduRqCXj1m8SVZlM+X
-----END CERTIFICATE REQUEST-----`;
const componentPemBundle = `-----BEGIN CERTIFICATE-----
MIIDGjCCAgKgAwIBAgIUFvnhb2nQ8+KNS3SzjlfYDMHGIRgwDQYJKoZIhvcNAQEL
BQAwDTELMAkGA1UEAxMCZmEwHhcNMTgwMTEwMTg1NDI5WhcNMTgwMjExMTg1NDU5
WjANMQswCQYDVQQDEwJmYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN2VtBn6EMlA4aYre/xoKHxlgNDxJnfSQWfs6yF/K201qPnt4QF9AXChatbmcKVn
OaURq+XEJrGVgF/u2lSos3NRZdhWVe8o3/sOetsGxcrd0gXAieOSmkqJjp27bYdl
uY3WsxhyiPvdfS6xz39OehsK/YCB6qCzwB4eEfSKqbkvfDL9sLlAiOlaoHC9pczf
6/FANKp35UDwInSwmq5vxGbnWk9zMkh5Jq6hjOWHZnVc2J8J49PYvkIM8uiHDgOE
w71T2xM5plz6crmZnxPCOcTKIdF7NTEP2lUfiqc9lONV9X1Pi4UclLPHJf5bwTmn
JaWgbKeY+IlF61/mgxzhC7cCAwEAAaNyMHAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFLDtc6+HZN2lv60JSDAZq3+IHoq7MB8GA1Ud
IwQYMBaAFLDtc6+HZN2lv60JSDAZq3+IHoq7MA0GA1UdEQQGMASCAmZhMA0GCSqG
SIb3DQEBCwUAA4IBAQDVt6OddTV1MB0UvF5v4zL1bEB9bgXvWx35v/FdS+VGn/QP
cC2c4ZNukndyHhysUEPdqVg4+up1aXm4eKXzNmGMY/ottN2pEhVEWQyoIIA1tH0e
8Kv/bysYpHZKZuoGg5+mdlHS2p2Dh2bmYFyBLJ8vaeP83NpTs2cNHcmEvWh/D4UN
UmYDODRN4qh9xYruKJ8i89iMGQfbdcq78dCC4JwBIx3bysC8oF4lqbTYoYNVTnAi
LVqvLdHycEOMlqV0ecq8uMLhPVBalCmIlKdWNQFpXB0TQCsn95rCCdi7ZTsYk5zv
Q4raFvQrZth3Cz/X5yPTtQL78oBYrmHzoQKDFJ2z
-----END CERTIFICATE-----`;
// for parse-pki-cert tests:
// certificate contains all allowable params
const loadedCert = `-----BEGIN CERTIFICATE-----\nMIIE7TCCA9WgAwIBAgIULcrWXSz3/kG81EgBo0A4Zt+ZgkYwDQYJKoZIhvcNAQEL\nBQAwga0xDzANBgNVBAYTBkZyYW5jZTESMBAGA1UECBMJQ2hhbXBhZ25lMQ4wDAYD\nVQQHEwVQYXJpczETMBEGA1UECRMKMjM0IHNlc2FtZTEPMA0GA1UEERMGMTIzNDU2\nMQ8wDQYDVQQKEwZXaWRnZXQxEDAOBgNVBAsTB0ZpbmFuY2UxGDAWBgNVBAMTD2Nv\nbW1vbi1uYW1lLmNvbTETMBEGA1UEBRMKY2VyZWFsMTI5MjAeFw0yMzAyMDMxNzI3\nMzNaFw0yMzAzMDcxNzI4MDNaMIGtMQ8wDQYDVQQGEwZGcmFuY2UxEjAQBgNVBAgT\nCUNoYW1wYWduZTEOMAwGA1UEBxMFUGFyaXMxEzARBgNVBAkTCjIzNCBzZXNhbWUx\nDzANBgNVBBETBjEyMzQ1NjEPMA0GA1UEChMGV2lkZ2V0MRAwDgYDVQQLEwdGaW5h\nbmNlMRgwFgYDVQQDEw9jb21tb24tbmFtZS5jb20xEzARBgNVBAUTCmNlcmVhbDEy\nOTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8NO7LXHp28SzOqmQv\nns4fGogKydEklWG4JEN3pM+k9nTyEgA8DFhtSLvcqF0cqhEydw4FVU+LEUGySUer\nmM4VNl9qglFBgmYE8TNgWkUw9ZP6MNgx13I8zXTXOIDj0iwXks02x8451oPbqqdq\nXsCc4vSP7BPwQOjc0C56c54zyRC1zFm9jlh+As0QinuYcjFjVabCku6JSYc4kunh\nz7derU9cURUxB5/ja9zC7jGS8tg4XUWdUkbj1O/krEWfjQx9Kj8aEU1gFfAvW/Bd\nIqgAlHATYN6i8HDmAmdGty9zLht9wUgnAtVh3lK3939h/rI0qCLV6N/RjCC7csnz\n9I67AgMBAAGjggEBMIH+MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/\nAgERMB0GA1UdDgQWBBSSdKle0wMGy0jvPmcoDanGduhLqzAfBgNVHSMEGDAWgBSS\ndKle0wMGy0jvPmcoDanGduhLqzAuBgNVHR4BAf8EJDAioCAwDoIMZG5zbmFtZTEu\nY29tMA6CDGRzbm5hbWUyLmNvbTBoBgNVHREEYTBfoB0GCCsBBAEFCQIGoBEMD3Nv\nbWUtdXRmLXN0cmluZ4IIYWx0bmFtZTGCCGFsdG5hbWUyhwTAngEmhxASNA/SViEA\nAQCJAAAAAEUAhgh0ZXN0dXJpMYYIdGVzdHVyaTIwDQYJKoZIhvcNAQELBQADggEB\nAAQukDwIg01QLQK2MQqjePNZlJleKLMK9LiabyGqc7u4bgmX3gYIrH7uopvO5cIv\nvqxcVBATQ6ez29t5MagzDu1+vnwE8fQhRoe0sp5TRLiGSlBJf53+0Wb3vbaOT0Fx\n/FFK0f2wHqYv3h/CTxu8YxDY4DwCRTPJ2KfTvT85BXtTUlzKIp1ytALSKcz0Owoe\neQPtQUdi8UHef8uHuWbk7DftMXojXbCqtHQdS3Rrl9zyc+Ds67flb5hKEseQZRgw\ntPtAIxhjSfZPTjl/3aasCBikESdeS8IOxIXL1bGun0xWnIBBc9uRe8hpdPjZj7Eh\nIt7ucIzFep0DLWCeQrAHeqo=\n-----END CERTIFICATE-----`;
// use_pss = true
const pssTrueCert = `-----BEGIN CERTIFICATE-----\nMIIDqTCCAl2gAwIBAgIUVY2PTRZl1t/fjfyEwrG4HvGjYekwQQYJKoZIhvcNAQEK\nMDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEF\nAKIDAgEgMBoxGDAWBgNVBAMTD2NvbW1vbi1uYW1lLmNvbTAeFw0yMzAxMjEwMTA3\nNDBaFw0yMzAyMjIwMTA4MTBaMBoxGDAWBgNVBAMTD2NvbW1vbi1uYW1lLmNvbTCC\nASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANlG6DuZ4B6Tv8u8rI+pUvQv\n2E7dFCu+i1YAbEJSnuAQ9XFUG5Uf3uHB8AFrOKRBAaFdBV4hKvBpfvMj3jl93d0b\nHdHeIM+sancDwpexpLvSW4yDpbIhAnkYzbUYgZyEAJeIgq/4ufT77TCK8XIzDywD\nhXZtDJkc6w3mm6hiqEQXLKnDQTfKLK8Fbsq4OuQ4vO5VIJrVZ1gKemDs7W/9WIzp\n0iSjzcIfWnUy1Dpk+AF8HhXok8CbhHfOGgbQZ6DcXOIJeb4XarJ9sgLJNAuhdcHR\ngP0TkPiOewbBG9Ish1p3F+pkI3vjQk4cghmilAuEkMc2NCNNy6q1bwSELVQnMiMC\nAwEAAaN/MH0wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O\nBBYEFAsrMoFu6tt1pybxx9ln6w5QK/2tMB8GA1UdIwQYMBaAFAsrMoFu6tt1pybx\nx9ln6w5QK/2tMBoGA1UdEQQTMBGCD2NvbW1vbi1uYW1lLmNvbTBBBgkqhkiG9w0B\nAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQC\nAQUAogMCASADggEBAFh+PMwEmxaZR6OtfB0Uvw2vA7Oodmm3W0bYjQlEz8U+Q+JZ\ncIPa4VnRy1QALmKbPCbRApA/gcWzIwtzo1JhLtcDINg2Tl0nj4WvgpIvj0/lQNMq\nmwP7G/K4PyJTv3+y5XwVfepZAZITB0w5Sg5dLC6HP8AGVIaeb3hGNHYvPlE+pbT+\njL0xxzFjOorWoy5fxbWoVyVv9iZ4j0zRnbkYHIi3d8g56VV6Rbyw4WJt6p87lmQ8\n0wbiJTtuew/0Rpuc3PEcR9XfB5ct8bvaGGTSTwh6JQ33ohKKAKjbBNmhBDSP1thQ\n2mTkms/mbDRaTiQKHZx25TmOlLN5Ea1TSS0K6yw=\n-----END CERTIFICATE-----`;
// only has common name
const skeletonCert = `-----BEGIN CERTIFICATE-----\nMIIDQTCCAimgAwIBAgIUVQy58VgdVpAK9c8SfS31idSv6FUwDQYJKoZIhvcNAQEL\nBQAwGjEYMBYGA1UEAxMPY29tbW9uLW5hbWUuY29tMB4XDTIzMDEyMTAxMjAyOVoX\nDTIzMDIyMjAxMjA1OVowGjEYMBYGA1UEAxMPY29tbW9uLW5hbWUuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2UboO5ngHpO/y7ysj6lS9C/YTt0U\nK76LVgBsQlKe4BD1cVQblR/e4cHwAWs4pEEBoV0FXiEq8Gl+8yPeOX3d3Rsd0d4g\nz6xqdwPCl7Gku9JbjIOlsiECeRjNtRiBnIQAl4iCr/i59PvtMIrxcjMPLAOFdm0M\nmRzrDeabqGKoRBcsqcNBN8osrwVuyrg65Di87lUgmtVnWAp6YOztb/1YjOnSJKPN\nwh9adTLUOmT4AXweFeiTwJuEd84aBtBnoNxc4gl5vhdqsn2yAsk0C6F1wdGA/ROQ\n+I57BsEb0iyHWncX6mQje+NCThyCGaKUC4SQxzY0I03LqrVvBIQtVCcyIwIDAQAB\no38wfTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU\nCysygW7q23WnJvHH2WfrDlAr/a0wHwYDVR0jBBgwFoAUCysygW7q23WnJvHH2Wfr\nDlAr/a0wGgYDVR0RBBMwEYIPY29tbW9uLW5hbWUuY29tMA0GCSqGSIb3DQEBCwUA\nA4IBAQDPco+FIHXczf0HTwFAmIVu4HKaeIwDsVPxoUqqWEix8AyCsB5uqpKZasby\nedlrdBohM4dnoV+VmV0de04y95sdo3Ot60hm/czLog3tHg4o7AmfA7saS+5hCL1M\nCJWqoJHRFo0hOWJHpLJRWz5DqRZWspASoVozLOYyjRD+tNBjO5hK4FtaG6eri38t\nOpTt7sdInVODlntpNuuCVprPpHGj4kPOcViQULoFQq5fwyadpdjqSXmEGlt0to5Y\nMbTb4Jhj0HywgO53BUUmMzzY9idXh/8A7ThrM5LtqhxaYHLVhyeo+5e0mgiXKp+n\nQ8Uh4TNNTCvOUlAHycZNaxYTlEPn\n-----END CERTIFICATE-----`;
// contains unsupported subject and extension OIDs
const unsupportedOids = `-----BEGIN CERTIFICATE-----\nMIIEjDCCA3SgAwIBAgIUD4EeORgh/i+ZZFOk8KsGKQPWsoIwDQYJKoZIhvcNAQEL\nBQAwgZIxMTAvBgNVBAMMKGZhbmN5LWNlcnQtdW5zdXBwb3J0ZWQtc3Viai1hbmQt\nZXh0LW9pZHMxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZLYW5zYXMxDzANBgNVBAcM\nBlRvcGVrYTESMBAGA1UECgwJQWNtZSwgSW5jMRowGAYJKoZIhvcNAQkBFgtmb29A\nYmFyLmNvbTAeFw0yMzAxMjMxODQ3MjNaFw0zMzAxMjAxODQ3MjNaMIGSMTEwLwYD\nVQQDDChmYW5jeS1jZXJ0LXVuc3VwcG9ydGVkLXN1YmotYW5kLWV4dC1vaWRzMQsw\nCQYDVQQGEwJVUzEPMA0GA1UECAwGS2Fuc2FzMQ8wDQYDVQQHDAZUb3Bla2ExEjAQ\nBgNVBAoMCUFjbWUsIEluYzEaMBgGCSqGSIb3DQEJARYLZm9vQGJhci5jb20wggEi\nMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDyYH5qS7krfZ2tA5uZsY2qXbTb\ntGNG1BsyDhZ/qqVlQybjDsHJZwNUbpfhBcCLaKyAwH1R9n54NOOOn6bYgfKWTgy3\nL7224YDAqYe7Y/GPjgI2MRvRfn6t2xzQxtJ0l0k8LeyNcwhiqYLQyOOfDdc127fm\nW40r2nmhLpH0i9e2I/YP1HQ+ldVgVBqeUTntgVSBfrQF56v9mAcvvHEa5sdHqmX4\nJ2lhWTnx9jqb7NZxCem76BlX1Gt5TpP3Ym2ZFVQI9fuPK4O8JVhk1KBCmIgR3Ft+\nPpFUs/c41EMunKJNzveYrInSDScaC6voIJpK23nMAiM1HckLfUUc/4UojD+VAgMB\nAAGjgdcwgdQwHQYDVR0OBBYEFH7tt4enejKTZtYjUKUUx6PXyzlgMB8GA1UdIwQY\nMBaAFH7tt4enejKTZtYjUKUUx6PXyzlgMA4GA1UdDwEB/wQEAwIFoDAgBgNVHSUB\nAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBCjBM\nBgNVHREERTBDhwTAngEmhgx1cmlTdXBwb3J0ZWSCEWRucy1OYW1lU3VwcG9ydGVk\noBoGAyoDBKATDBFleGFtcGxlIG90aGVybmFtZTANBgkqhkiG9w0BAQsFAAOCAQEA\nP6ckVJgbcJue+MK3RVDuG+Mh7dl89ynC7NwpQFRjLVZQuoMHZT/dcLlVeFejVXu5\nR+IPLmQU6NV7JAmy4zGap8awf12QTy3g410ecrSF94WWlu8bPoekfUnnP+kfzLPH\nCUAkRKxWDSRKX5C8cMMxacVBBaBIayuusLcHkHmxLLDw34PFzyz61gtZOJq7JYnD\nhU9YsNh6bCDmnBDBsDMOI7h8lBRQwTiWVoSD9YNVvFiY29YvFbJQGdh+pmBtf7E+\n1B/0t5NbvqlQSbhMM0QgYFhuCxr3BGNob7kRjgW4i+oh+Nc5ptA5q70QMaYudqRS\nd8SYWhRdxmH3qcHNPcR1iw==\n-----END CERTIFICATE-----`;
// unsupportedPem is same cert as above, formatted differently
const unsupportedPem = `
-----BEGIN CERTIFICATE-----
MIIEjDCCA3SgAwIBAgIUD4EeORgh/i+ZZFOk8KsGKQPWsoIwDQYJKoZIhvcNAQEL
BQAwgZIxMTAvBgNVBAMMKGZhbmN5LWNlcnQtdW5zdXBwb3J0ZWQtc3Viai1hbmQt
ZXh0LW9pZHMxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZLYW5zYXMxDzANBgNVBAcM
BlRvcGVrYTESMBAGA1UECgwJQWNtZSwgSW5jMRowGAYJKoZIhvcNAQkBFgtmb29A
YmFyLmNvbTAeFw0yMzAxMjMxODQ3MjNaFw0zMzAxMjAxODQ3MjNaMIGSMTEwLwYD
VQQDDChmYW5jeS1jZXJ0LXVuc3VwcG9ydGVkLXN1YmotYW5kLWV4dC1vaWRzMQsw
CQYDVQQGEwJVUzEPMA0GA1UECAwGS2Fuc2FzMQ8wDQYDVQQHDAZUb3Bla2ExEjAQ
BgNVBAoMCUFjbWUsIEluYzEaMBgGCSqGSIb3DQEJARYLZm9vQGJhci5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDyYH5qS7krfZ2tA5uZsY2qXbTb
tGNG1BsyDhZ/qqVlQybjDsHJZwNUbpfhBcCLaKyAwH1R9n54NOOOn6bYgfKWTgy3
L7224YDAqYe7Y/GPjgI2MRvRfn6t2xzQxtJ0l0k8LeyNcwhiqYLQyOOfDdc127fm
W40r2nmhLpH0i9e2I/YP1HQ+ldVgVBqeUTntgVSBfrQF56v9mAcvvHEa5sdHqmX4
J2lhWTnx9jqb7NZxCem76BlX1Gt5TpP3Ym2ZFVQI9fuPK4O8JVhk1KBCmIgR3Ft+
PpFUs/c41EMunKJNzveYrInSDScaC6voIJpK23nMAiM1HckLfUUc/4UojD+VAgMB
AAGjgdcwgdQwHQYDVR0OBBYEFH7tt4enejKTZtYjUKUUx6PXyzlgMB8GA1UdIwQY
MBaAFH7tt4enejKTZtYjUKUUx6PXyzlgMA4GA1UdDwEB/wQEAwIFoDAgBgNVHSUB
Af8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBCjBM
BgNVHREERTBDhwTAngEmhgx1cmlTdXBwb3J0ZWSCEWRucy1OYW1lU3VwcG9ydGVk
oBoGAyoDBKATDBFleGFtcGxlIG90aGVybmFtZTANBgkqhkiG9w0BAQsFAAOCAQEA
P6ckVJgbcJue+MK3RVDuG+Mh7dl89ynC7NwpQFRjLVZQuoMHZT/dcLlVeFejVXu5
R+IPLmQU6NV7JAmy4zGap8awf12QTy3g410ecrSF94WWlu8bPoekfUnnP+kfzLPH
CUAkRKxWDSRKX5C8cMMxacVBBaBIayuusLcHkHmxLLDw34PFzyz61gtZOJq7JYnD
hU9YsNh6bCDmnBDBsDMOI7h8lBRQwTiWVoSD9YNVvFiY29YvFbJQGdh+pmBtf7E+
1B/0t5NbvqlQSbhMM0QgYFhuCxr3BGNob7kRjgW4i+oh+Nc5ptA5q70QMaYudqRS
d8SYWhRdxmH3qcHNPcR1iw==
-----END CERTIFICATE-----`;
const certWithoutCN = `-----BEGIN CERTIFICATE-----\nMIIDUDCCAjigAwIBAgIUEUpM5i7XMd/imZkR9XvonMaqPyYwDQYJKoZIhvcNAQEL\nBQAwHDEaMBgGCSqGSIb3DQEJARYLZm9vQGJhci5jb20wHhcNMjMwMTIzMjMyODEw\nWhcNMzMwMTIwMjMyODEwWjAcMRowGAYJKoZIhvcNAQkBFgtmb29AYmFyLmNvbTCC\nASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPGSdeqLICZcoUzxk88F8Tp+\nVNI+mS74L8pHyb9ZNZfeXPo0E9L5pi+KKI7rkxAtBGUecG1ENSxDDK9p6XZhWHSU\nZ6bdjOsjcIlfiM+1hhtDclIVxIDnz2Jt1/Vmnm8DXwdwVATWiFLTnfm288deNwsT\npl0ehAR3BadkZvteC6t+giEw/4qm1/FP53GEBOQeUWJDZRvtL37rdx4joFv3cR4w\nV0dukOjc5AGXtIOorO145OSZj8s7RsW3pfGcFUcOg7/flDxfK1UqFflQa7veLvKa\nWE/fOMyB/711QjSkTuQ5Rw3Rf9Fr2pqVJQgElTIW1SKaX5EJTB9mtGB34UqUXtsC\nAwEAAaOBiTCBhjAdBgNVHQ4EFgQUyhFP/fm+798mErPD5VQvEaAZQrswHwYDVR0j\nBBgwFoAUyhFP/fm+798mErPD5VQvEaAZQrswDgYDVR0PAQH/BAQDAgWgMCAGA1Ud\nJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEK\nMA0GCSqGSIb3DQEBCwUAA4IBAQCishzVkhuSAtqxgsZdYzBs3GpakGIio5zReW27\n6dk96hYCbbe4K3DtcFbRD1B8t6aTJlHxkFRaOWErSXu9WP3fUhIDNRE64Qsrg1zk\n3Km430qBlorXmTp6xhYHQfY5bn5rT2YY7AmaYIlIFxRhod43i5GDbBP+e+d/vTqR\nv1AJflYofeR4LeATP64B6a4R+QQVoxI43+pyH3ka+nRHwJBR9h8SMtJoqBy7x9pl\nYlBDa8lSn05doA3+e03VIzitvBBWI4oX1XB0tShSLk6YJXayIwe0ZNVvfYLIRKCp\nb4DUwChYzG/FwFSssUAqzVFhu3i+uU3Z47bsLVm0R5m7hLiZ\n-----END CERTIFICATE-----`;
// CROSS-SIGNING:
const newCSR = {
common_name: 'Short-Lived Int R1',
csr: `-----BEGIN CERTIFICATE REQUEST-----\nMIICYjCCAUoCAQAwHTEbMBkGA1UEAxMSU2hvcnQtTGl2ZWQgSW50IFIxMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqsvFU7lzt06n1w6BL+Waf9zd+Z3G\n90Kv0HAksoLaWYinhkxNIUTU8ar9HLa2WV4EoJbNq91Hn+jFc2SYEXtRV+jm0kEh\nz4C4AoQ4D0s83JcYNssiNbVA04wa5ovD0iA/pzwVz8TnJSfAAuZ3vXFlyIbQ3ESo\nzt9hGjo/JOpoBh67E7xkuzw4lnC2rXGHdh9pk1Di+wqREnKU4nuhDLnTC/LL+Mkm\n07F1aMAW3Z/PWFmmsDJHMhZnaYo2LGCwU4A0U1ED0XpwflobVbkzZDmCXOPEI8UX\nG6VcL36zWnzEQnlZKN91MAa+s0E4z40KHKVSblSkjYD1K6n0y787ic2mDwIDAQAB\noAAwDQYJKoZIhvcNAQELBQADggEBAFQtiJaRfaQS3jHr7aFeszB/JmDRQiOoML3g\nhA3EcVd2rvDjiqikwD9EFdLTJyYJfb+9yiKDJqB7Fw2GPSrFxrd+jC9qZRI3VEWK\n8VdflLbruc1FcqJcE/0z2hWa11eud1bMLq8U6AfxNHL4r4ukrp2D5elrdsrDnhZj\nwMi3FtEFd4RZVaWZYVmWcQTeH7Zz/LYwkVDgBuvC+SOCaNNo/dCurkAAoxw8obBj\n1FS2F/3oHQxMui8vS8j6sMWMPZ5D3Q0xSC3HBUNoI2ZC77Mxn9yfj6ianUXKOOlf\nQMRaPBVajxZm9ovV64QKr+7HK7W7U/fNEqvoKBUDCqEuWmSsxMk=\n-----END CERTIFICATE REQUEST-----`,
};
const oldParentIssuerCert = `-----BEGIN CERTIFICATE-----\nMIIDKzCCAhOgAwIBAgIUMCEF+bzBC4NQIWjE1sv/RbnYfUgwDQYJKoZIhvcNAQEL\nBQAwHTEbMBkGA1UEAxMSTG9uZy1MaXZlZCBSb290IFgxMB4XDTIzMDEyNTAwMjQz\nM1oXDTIzMDIyNjAwMjUwM1owHTEbMBkGA1UEAxMSTG9uZy1MaXZlZCBSb290IFgx\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0zrpJvjWcBV49Eor+zfh\nGW40xH6PcPSpzWGCCFiMPFwKrBSjuGRwwkLsXU7u2P15jIV/IU2kPS+WOW+EIe0x\ns5X2SoujZGOmM6du/6HIo9lz9yjb5G1SHdv/e65Q45QWb6wQcuO4axffvPzmAU9L\nQcunEF4g3rCz4cHYumi0osybbwR45z+8owNhykdbu7AwV0Cyz3C/lT1wxDxbFr0Y\n1NEjQ8AF4oRzqkmGoLp6ixDxp8zMpOlKWWYem1mx0RbqlwLP7khiS5YKi8+j8aog\nOhHA/W4i+ihrBzkv4GtOSdkhJz5qacifydUXtJ7SmvYs9Fi+hFgw61sw23ywbr3+\nywIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\nHQ4EFgQUQsdYFMtsNMYNDIhZHMd77kcLLi8wHwYDVR0jBBgwFoAUQsdYFMtsNMYN\nDIhZHMd77kcLLi8wDQYJKoZIhvcNAQELBQADggEBAFNKTnNUzjZGHpXVK9Go8k/i\nVMNBktjGp58z+EN32TJnq/tOW1eVswUmq71S3R16Iho4XZDZVchuK+zhqSwlAmgM\no1vs6L5IJ0rVZcLZpysxFtawlbA362zBOX0F7tqStdEeBWaXw6J+MQ26xAPgHjXo\nc3fqqNWGbrOPt1uFoXWD+0Bg8M90a7OT0ijubh/PcuCe1yF9G2BqRQruB05gZiHl\n0NGbUka1ntD/lxYfLeSnp+FHJVDrcAHwPhKQS8HHr/ZBjKEGY8In+JIi/KBV/M8b\nGeW2k5odl6r2UIR6PWSei1WKKHe09WzO7rGJaN6uKLP14c0nSF3/q+AQY3m+tPY=\n-----END CERTIFICATE-----\n`;
const parentIssuerCert = `-----BEGIN CERTIFICATE-----\nMIIDKzCCAhOgAwIBAgIUBxLeuD3K0hF5dGpaEgZqytTN3lswDQYJKoZIhvcNAQEL\nBQAwHTEbMBkGA1UEAxMSTG9uZy1MaXZlZCBSb290IFgyMB4XDTIzMDEyNTAwMjQz\nM1oXDTIzMDIyNjAwMjUwM1owHTEbMBkGA1UEAxMSTG9uZy1MaXZlZCBSb290IFgy\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuqkwN4m5dFLwFi0iYs4r\nTO4HWzloF4yCOaNfVksh1cOafVu9vjFwOWgHZFe6h8BOn6biKdFtvGTyIzlMHe5t\nyFmec9pfjX243bH9Ev4n2RTMKs818g9LdoZT6SI7DxHEu3yuHBg9TM87+GB+dA1V\nkRsK5hgtNCSMdgFSljM169sYbNilpk8M7O2hr+AmgRi0c1nUEPCe4JAr0Zv8iweJ\ntFRVHiQJXD9WIVxaWVxqWFsHoXseZS7H76RSdf4jNfENmBguHZMAPhtqlc/pMan8\nu0IJETWjWENn+WYC7DnnfQtNqyebU2LdT3oKO8tELqITygjT2tCS1Zavmsy69VY0\nYwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\nHQ4EFgQUxgchIBo+1F++IFW0F586I5QDFGYwHwYDVR0jBBgwFoAUxgchIBo+1F++\nIFW0F586I5QDFGYwDQYJKoZIhvcNAQELBQADggEBAI6DdnW8q/FqGqk/Y0k7iUrZ\nYkfMRlss6uBTzLev53eXqFIJ3+EFVfV+ohDEedlYYm2QCELzQcJSR7Q2I22PQj8X\nTO0yqk6LOCMv/4yiDhF4D+haiDU4joq5GX1dpFdlNSQ5fJmnLKu8HYbOhbwUo4ns\n4yGzIMulZR1Zqf/HGEOCYPDQ0ZHucmHn7uGhmV+kgYGoKVEZ8XxfmyNPKuwTAUHL\nfInPJZtbxXTVmiWWy3iraeI4XcUvaD0JtVnsVphYrqrSZ60DjgFsjiyenxePGHXf\nYXV9HIS6OXlvWhJKlSINOTv9fAa+e+JtK7frdvxJNHoTG34PiGXfOV2swTvLJQo=\n-----END CERTIFICATE-----\n`;
const intIssuerCert = `-----BEGIN CERTIFICATE-----\nMIIDKzCCAhOgAwIBAgIUPt5VyO6gyA4hVaMkdpNyBlP+I64wDQYJKoZIhvcNAQEL\nBQAwHTEbMBkGA1UEAxMSTG9uZy1MaXZlZCBSb290IFgxMB4XDTIzMDEyNTAwMjQz\nM1oXDTIzMDIyNjAwMjUwM1owHTEbMBkGA1UEAxMSU2hvcnQtTGl2ZWQgSW50IFIx\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqsvFU7lzt06n1w6BL+Wa\nf9zd+Z3G90Kv0HAksoLaWYinhkxNIUTU8ar9HLa2WV4EoJbNq91Hn+jFc2SYEXtR\nV+jm0kEhz4C4AoQ4D0s83JcYNssiNbVA04wa5ovD0iA/pzwVz8TnJSfAAuZ3vXFl\nyIbQ3ESozt9hGjo/JOpoBh67E7xkuzw4lnC2rXGHdh9pk1Di+wqREnKU4nuhDLnT\nC/LL+Mkm07F1aMAW3Z/PWFmmsDJHMhZnaYo2LGCwU4A0U1ED0XpwflobVbkzZDmC\nXOPEI8UXG6VcL36zWnzEQnlZKN91MAa+s0E4z40KHKVSblSkjYD1K6n0y787ic2m\nDwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\nHQ4EFgQUkBK+oGpo5DNj2pCKoUE08WFOxQUwHwYDVR0jBBgwFoAUQsdYFMtsNMYN\nDIhZHMd77kcLLi8wDQYJKoZIhvcNAQELBQADggEBAIf4Bp/NYftiN8LmQrVzPWAe\nc4Bxm/NFFtkwQEvFhndMN68MUyXa5yxAdnYAHN+fRpYPxbjoZNXjW/jx3Kjft44r\ntyNGrrkjR80TI9FbL53nN7hLtZQdizsQD0Wype4Q1JOIxYw2Wd5Hr/PVPrJZ3PGg\nwNeI5IRu/cVbVT/vkRaHqYSwpa+V2cZTaEk6h62KPaKu3ui+omoeitU6qXHOysXQ\nrdGkJl/x831sIKmN0dMiGeoJdHGAr/E2f3ijKbVPsjIxZbm2SSumldOFYWn9cNYD\nI6sizFH976Wpde/GRIvBIzJnlK3xgfy0D9AUvwKyt75PVEnshc9tlhxoSVlKaUE=\n-----END CERTIFICATE-----\n`;
const newlySignedCert = `-----BEGIN CERTIFICATE-----\nMIIDKzCCAhOgAwIBAgIUKapKK5Coau2sfIJgqA9jcC6BkWIwDQYJKoZIhvcNAQEL\nBQAwHTEbMBkGA1UEAxMSTG9uZy1MaXZlZCBSb290IFgyMB4XDTIzMDEyNTIyMjky\nNVoXDTIzMDIyNjIyMjk1NVowHTEbMBkGA1UEAxMSU2hvcnQtTGl2ZWQgSW50IFIx\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqsvFU7lzt06n1w6BL+Wa\nf9zd+Z3G90Kv0HAksoLaWYinhkxNIUTU8ar9HLa2WV4EoJbNq91Hn+jFc2SYEXtR\nV+jm0kEhz4C4AoQ4D0s83JcYNssiNbVA04wa5ovD0iA/pzwVz8TnJSfAAuZ3vXFl\nyIbQ3ESozt9hGjo/JOpoBh67E7xkuzw4lnC2rXGHdh9pk1Di+wqREnKU4nuhDLnT\nC/LL+Mkm07F1aMAW3Z/PWFmmsDJHMhZnaYo2LGCwU4A0U1ED0XpwflobVbkzZDmC\nXOPEI8UXG6VcL36zWnzEQnlZKN91MAa+s0E4z40KHKVSblSkjYD1K6n0y787ic2m\nDwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\nHQ4EFgQUkBK+oGpo5DNj2pCKoUE08WFOxQUwHwYDVR0jBBgwFoAUxgchIBo+1F++\nIFW0F586I5QDFGYwDQYJKoZIhvcNAQELBQADggEBAJaems1vgEjxgb3d1y9PYxzN\nLZbuf/+0+BCVa9k4bEsbuhXhEecFdIi2OKS6fabeoEOF97Gvqrgc+LEpNsU6lIRA\nkJ/nHe0CD2hf0aBQsGsOllYy/4QnrPlbowb4KizPknEMWdGcvfnlzzOJzo4/UuMk\nMZ9vn2GrINzfml/sLocOzP/MsPd8bBhXI2Emh2O9tJ4+zeHLhEzcM1gdNk8pp+wP\nEOks0EcN4UBkpEnDZcDTJVgp9XpWy19EEGqsxjBq6rlpIvPW8XHoH1jZSGY1KWBJ\nRGtDcGugwTxO9jYHz/a1qu4BVt5FFcb0L3IOvcr+3QCCeiJQHcVY8QRbO9M4AQk=\n-----END CERTIFICATE-----\n`;
// both certs generated with key type ed25519
const unsupportedSignatureRoot = `-----BEGIN CERTIFICATE-----\nMIIBXTCCAQ+gAwIBAgIUcp9CkzsU5Pkv2ZJO8Gp+tJrzuJYwBQYDK2VwMBIxEDAO\nBgNVBAMTB215LXJvb3QwHhcNMjMwNzE4MTYyNzQ3WhcNMjMwODE5MTYyODE3WjAS\nMRAwDgYDVQQDEwdteS1yb290MCowBQYDK2VwAyEAmZ+By07QvgAEX1HRjhltJlgK\nA8il2LYUpH0uw7f2lXCjdzB1MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD\nAQH/MB0GA1UdDgQWBBTAcYaOaiKhDmYqSe6vg/lAtYspkDAfBgNVHSMEGDAWgBTA\ncYaOaiKhDmYqSe6vg/lAtYspkDASBgNVHREECzAJggdteS1yb290MAUGAytlcANB\nAG9xXZnKNEXRyfa91hm9S80PwlwIMh4MkWetwfPBn3M74cHzDK1okANmweca4RRq\nQHDPT7shx3CuosvL2Ori/ws=\n-----END CERTIFICATE-----`;
const unsupportedSignatureInt = `-----BEGIN CERTIFICATE-----\nMIICfTCCAWWgAwIBAgIUei2XIhhsP1/ytDciEGfA1C7t/sMwDQYJKoZIhvcNAQEL\nBQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMjMwNzE4MTg1NDA3WhcNMjMw\nODE5MTg1NDM3WjASMRAwDgYDVQQDEwdpbnQtY3NyMCowBQYDK2VwAyEAa9vHnJA3\nnzA/fYiTUg8EhomjMtVp5O2c01nQRXEv72OjgcAwgb0wDgYDVR0PAQH/BAQDAgEG\nMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFGtjjUwrRGmFmYBHrUE38tSxvVM3\nMB8GA1UdIwQYMBaAFNng9+uArFyIUcD23XdvCSIfYiDPMEYGCCsGAQUFBwEBBDow\nODAZBggrBgEFBQcwAoYNaGFzaGljb3JwLmNvbTAbBggrBgEFBQcwAoYPdmF1bHRw\ncm9qZWN0LmlvMBIGA1UdEQQLMAmCB2ludC1jc3IwDQYJKoZIhvcNAQELBQADggEB\nAAOSNgZjesJG4BgLU8jQmOO7n6W8WcR+dT+ELDC1nLlEZ2BJCDSXXUX8AihIHKxn\nA9W4slABUacyJlAZo/o/wcxyfbA6PUXmHnoqEPZ3zXMwuLN/iRW7/uQvI6TIwnpH\nXETFARLmK8cfGgbhi24STkHTF4ljczkOab7sTUQTHELlo+F2gNtmgnyaBFCGUYor\nX1pkMBcBa9BWRsfhy8E+tBVVUrNNUddwzC/5nMLqT8XqENMndDoG7eeT9Ex6otZy\nzURkcq09FtcmyY2RBYkV4UzyHN7cESMIk/J33ZCNAfHaDGuOqTy5nYU5fTtjJcit\nwEcWiSesrKPCletBpuMpgiU=\n-----END CERTIFICATE-----\n`;
export const CERTIFICATES = {
rootPem,
rootDer,
issuerPemBundle,
csr,
csr2,
componentPemBundle,
loadedCert,
pssTrueCert,
skeletonCert,
unsupportedOids,
unsupportedPem,
certWithoutCN,
newCSR,
oldParentIssuerCert,
parentIssuerCert,
intIssuerCert,
newlySignedCert,
unsupportedSignatureRoot,
unsupportedSignatureInt,
};

View File

@ -1,23 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { SELECTORS as CONFIGURE } from './pki-configure-create';
import { SELECTORS as DETAILS } from './pki-issuer-details';
export const SELECTORS = {
objectListInput: (key, row = 0) => `[data-test-object-list-input="${key}-${row}"]`,
inputByName: (name) => `[data-test-input="${name}"]`,
addRow: '[data-test-object-list-add-button',
submitButton: '[data-test-cross-sign-submit]',
cancelButton: '[data-test-cross-sign-cancel]',
statusCount: '[data-test-cross-sign-status-count]',
signedIssuerRow: (row = 0) => `[data-test-info-table-row="${row}"]`,
signedIssuerCol: (attr) => `[data-test-info-table-column="${attr}"]`,
// for cross signing acceptance tests
configure: { ...CONFIGURE },
details: { ...DETAILS },
rowValue: (attr) => `[data-test-row-value="${attr}"]`,
copyButton: (attr) => `[data-test-value-div="${attr}"] [data-test-copy-button]`,
};

View File

@ -1,21 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const SELECTORS = {
configure: '[data-test-pki-issuer-configure]',
copyButtonByName: (name) => `[data-test-value-div="${name}"] [data-test-copy-button]`,
crossSign: '[data-test-pki-issuer-cross-sign]',
defaultGroup: '[data-test-details-group="default"]',
download: '[data-test-issuer-download]',
groupTitle: '[data-test-group-title]',
parsingAlertBanner: '[data-test-parsing-error-alert-banner]',
rotateModal: '#pki-rotate-root-modal',
rotateModalGenerate: '[data-test-root-rotate-step-one]',
rotateRoot: '[data-test-pki-issuer-rotate-root]',
row: '[data-test-component="info-table-row"]',
signIntermediate: '[data-test-pki-issuer-sign-int]',
urlsGroup: '[data-test-details-group="Issuer URLs"]',
valueByName: (name) => `[data-test-value-div="${name}"]`,
};

Some files were not shown because too many files have changed in this diff Show More