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() {
return SUPPORTED_AUTH_BACKENDS;
return [...SUPPORTED_AUTH_BACKENDS];
}
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 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)
export default class ActivitySerializer extends ApplicationSerializer {
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}} />
</p.top>
<p.levelLeft>
<h1 class="title is-3" data-test-pki-engine-page-title>
<h1 class="title is-3" data-test-page-title>
{{this.title}}
</h1>
</p.levelLeft>
@ -85,14 +85,10 @@
@onComplete={{transition-to "vault.cluster.secrets.backend.pki.overview"}}
/>
{{else}}
<EmptyState
@title="Choose an option"
@message="To see configuration options, choose your desired output above."
data-test-configuration-empty-state
/>
<EmptyState @title="Choose an option" @message="To see configuration options, choose your desired output above." />
<hr class="has-background-gray-100" />
<Hds::ButtonSet>
<Hds::Button @text="Done" disabled={{true}} data-test-pki-config-save />
<Hds::Button @text="Cancel" @color="secondary" {{on "click" @onCancel}} data-test-pki-config-cancel />
<Hds::Button @text="Done" disabled={{true}} data-test-save />
<Hds::Button @text="Cancel" @color="secondary" {{on "click" @onCancel}} data-test-cancel />
</Hds::ButtonSet>
{{/if}}

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{@breadcrumbs}} />
</p.top>
<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"}}
</h1>
</p.levelLeft>
@ -166,8 +166,8 @@
<hr class="has-background-gray-100" />
<Hds::ButtonSet>
<Hds::Button @text="Done" type="submit" data-test-pki-rotate-root-save />
<Hds::Button @text="Cancel" @color="secondary" {{on "click" @onCancel}} data-test-pki-rotate-root-cancel />
<Hds::Button @text="Done" type="submit" data-test-save />
<Hds::Button @text="Cancel" @color="secondary" {{on "click" @onCancel}} data-test-cancel />
</Hds::ButtonSet>
{{#if this.invalidFormAlert}}
<div class="control">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top>
<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
</h1>
</p.levelLeft>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top>
<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" />
View Issuer Certificate
</h1>

View File

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

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top>
<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" />
Sign Intermediate
</h1>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top>
<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" />
View Key
</h1>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top>
<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" />
Edit Key
</h1>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top>
<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
</h1>
</p.levelLeft>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top>
<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" />
PKI Role
<code>{{this.model.name}}</code>

View File

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

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top>
<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" />
{{if this.hasSubmitted "View Generated Certificate" "Generate Certificate"}}
</h1>

View File

@ -8,7 +8,7 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top>
<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" />
{{if this.hasSubmitted "View Signed Certificate" "Sign Certificate"}}
</h1>

View File

@ -9,7 +9,7 @@ import { setupApplicationTest } from 'ember-qunit';
import page from 'vault/tests/pages/access/identity/index';
import authPage from 'vault/tests/pages/auth';
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';
const SELECTORS = {

View File

@ -73,36 +73,19 @@ module('Acceptance | auth backend list', function (hooks) {
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) {
assert.expect(45);
const uid = uuidv4();
module('auth methods are linkable and link to correct view', function (hooks) {
hooks.beforeEach(async function () {
this.uid = uuidv4();
await visit('/vault/access');
});
const supportManaged = supportedManagedAuthBackends();
// Test all auth methods, not just those you can log in with
const backends = methods().map((backend) => backend.type);
assert.deepEqual(
backends,
[
'alicloud',
'approle',
'aws',
'azure',
'gcp',
'github',
'jwt',
'oidc',
'kubernetes',
'ldap',
'okta',
'radius',
'cert',
'userpass',
],
'non-enterprise auth methods are available'
);
for (const type of backends) {
const path = type === 'token' ? 'token' : `auth-list-${type}-${uid}`;
methods()
.map((backend) => backend.type)
.forEach((type) => {
test(`${type} auth method`, async function (assert) {
const supportManaged = supportedManagedAuthBackends();
const path = type === 'token' ? 'token' : `auth-list-${type}-${this.uid}`;
if (type !== 'token') {
await enablePage.enable(type, path);
}
@ -126,7 +109,7 @@ module('Acceptance | auth backend list', function (hooks) {
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') {
if (type === 'ldap' || type === 'okta') {
expectedTabs = 3;
}
assert
@ -137,10 +120,12 @@ module('Acceptance | auth backend list', function (hooks) {
// cleanup method
await runCmd(deleteAuthCmd(path));
}
}
});
});
});
test('enterprise: auth methods are linkable and link to correct view', async function (assert) {
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');
@ -162,7 +147,7 @@ module('Acceptance | auth backend list', function (hooks) {
await runCmd(deleteAuthCmd(path));
});
test('enterprise: token config within namespace', async function (assert) {
test('token config within namespace', async function (assert) {
const ns = 'ns-wxyz';
await runCmd(createNS(ns), false);
await settled();
@ -178,4 +163,5 @@ module('Acceptance | auth backend list', function (hooks) {
.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
*/
/* eslint qunit/no-conditional-assertions: "warn" */
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import sinon from 'sinon';
import { click, currentURL, visit, waitUntil, find } from '@ember/test-helpers';
import { supportedAuthBackends } from 'vault/helpers/supported-auth-backends';
import authForm from '../pages/components/auth-form';
import jwtForm from '../pages/components/auth-jwt';
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 jwtComponent = create(jwtForm);
module('Acceptance | auth', function (hooks) {
setupApplicationTest(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();
});
setupMirage(hooks);
test('auth query params', async function (assert) {
const backends = supportedAuthBackends();
@ -55,53 +41,102 @@ module('Acceptance | auth', function (hooks) {
assert.strictEqual(component.tokenValue, '', 'it clears the token value when toggling methods');
});
test('it sends the right attributes when authenticating', async function (assert) {
assert.expect(8);
const backends = supportedAuthBackends();
module('it sends the right attributes when authenticating', function (hooks) {
hooks.beforeEach(function () {
this.assertReq = () => {};
this.server.get('/auth/token/lookup-self', (schema, req) => {
this.assertReq(req);
req.passthrough();
});
this.server.post('/auth/github/login', (schema, req) => {
// This one is for github only
this.assertReq(req);
req.passthrough();
});
this.server.post('/auth/:mount/oidc/auth_url', (schema, req) => {
// For JWT and OIDC
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',
},
};
});
for (const backend of supportedAuthBackends().reverse()) {
test(`for ${backend.type}`, async function (assert) {
const { type } = backend;
const isOidc = ['jwt', 'oidc'].includes(type);
// OIDC types make 3 requests, each time the role changes
assert.expect(isOidc ? 6 : 2);
this.assertReq = (req) => {
const body = type === 'token' ? req.requestHeaders : JSON.parse(req.requestBody);
const { included, url } = this.expected[type];
assert.true(Object.keys(body).includes(included), `${type} includes ${included}`);
assert.strictEqual(req.url, url, `${type} calls the correct URL`);
};
await visit('/vault/auth');
for (const backend of backends.reverse()) {
await component.selectMethod(backend.type);
if (backend.type === 'github') {
await component.selectMethod(type);
if (type === 'github') {
await component.token('token');
}
if (backend.type === 'jwt' || backend.type === 'oidc') {
if (isOidc) {
await jwtComponent.role('test');
}
await component.login();
const lastRequest = this.server.passthroughRequests[this.server.passthroughRequests.length - 1];
const body = JSON.parse(lastRequest.requestBody);
let keys;
let included;
if (backend.type === 'token') {
keys = lastRequest.requestHeaders;
included = 'x-vault-token';
} else if (backend.type === 'github') {
keys = body;
included = 'token';
} else if (backend.type === 'jwt' || backend.type === 'oidc') {
const authReq = this.server.passthroughRequests[this.server.passthroughRequests.length - 2];
keys = JSON.parse(authReq.requestBody);
included = 'role';
} else {
keys = body;
included = 'password';
}
assert.ok(Object.keys(keys).includes(included), `${backend.type} includes ${included}`);
});
}
});
test('it shows the push notification warning after submit', async function (assert) {
assert.expect(1);
this.server.get('/v1/auth/token/lookup-self', async () => {
this.server.get(
'/auth/token/lookup-self',
async () => {
assert.ok(
await waitUntil(() => find('[data-test-auth-message="push"]')),
'shows push notification message'
);
return [204, { 'Content-Type': 'application/json' }, JSON.stringify({})];
});
return {};
},
{ timing: 1000 }
);
await visit('/vault/auth');
await component.selectMethod('token');
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 { visit, click, currentURL } from '@ember/test-helpers';
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';
module('Acceptance | clients | counts', function (hooks) {
@ -36,8 +37,8 @@ module('Acceptance | clients | counts', function (hooks) {
this.owner.lookup('service:version').type = 'community';
await visit('/vault/clients/counts/overview');
assert.dom(ts.emptyStateTitle).hasText('No data received');
assert.dom(ts.emptyStateMessage).hasText('Select a start date above to query client count data.');
assert.dom(GENERAL.emptyStateTitle).hasText('No data received');
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) {
@ -47,19 +48,19 @@ module('Acceptance | clients | counts', function (hooks) {
test('it should persist filter query params between child routes', async function (assert) {
await visit('/vault/clients/counts/overview');
await click(ts.rangeDropdown);
await click(ts.currentBillingPeriod);
await click(CLIENT_COUNT.rangeDropdown);
await click(CLIENT_COUNT.currentBillingPeriod);
const timeQueryRegex = /end_time=\d+&start_time=\d+/g;
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(
currentURL().match(timeQueryRegex).length,
'Start and end times persist through child route change'
);
await click(ts.navLink('Dashboard'));
await click(ts.navLink('Client Count'));
await click(GENERAL.navLink('Dashboard'));
await click(GENERAL.navLink('Client Count'));
assert.strictEqual(
currentURL(),
'/vault/clients/counts/overview',

View File

@ -11,7 +11,8 @@ import sinon from 'sinon';
import { visit, click, findAll, settled } from '@ember/test-helpers';
import authPage from 'vault/tests/pages/auth';
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 { clickTrigger } from 'ember-power-select/test-support/helpers';
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) {
assert.dom(SELECTORS.tab('overview')).exists();
assert.dom(SELECTORS.tab('token')).exists();
assert.dom(SELECTORS.tab('config')).exists();
assert.dom(GENERAL.tab('overview')).exists();
assert.dom(GENERAL.tab('token')).exists();
assert.dom(GENERAL.tab('config')).exists();
});
test('it should render charts', async function (assert) {
assert
.dom(SELECTORS.counts.startMonth)
.dom(CLIENT_COUNT.counts.startMonth)
.hasText('July 2023', 'billing start month is correctly parsed from license');
assert
.dom(SELECTORS.rangeDropdown)
.dom(CLIENT_COUNT.rangeDropdown)
.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
.dom(SELECTORS.charts.chart('running total'))
.dom(CLIENT_COUNT.charts.chart('running total'))
.exists('Shows running totals with monthly breakdown charts');
assert
.dom(SELECTORS.charts.line.xAxisLabel)
.dom(CLIENT_COUNT.charts.line.xAxisLabel)
.hasText('7/23', 'x-axis labels start with billing start date');
assert.strictEqual(
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) {
// 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-previous-year]');
await click(`[data-test-calendar-month=${ARRAY_OF_MONTHS[LICENSE_START.getMonth()]}]`);
assert
.dom(SELECTORS.runningTotalMonthStats)
.dom(CLIENT_COUNT.runningTotalMonthStats)
.doesNotExist('running total single month stat boxes do not show');
assert
.dom(SELECTORS.charts.chart('running total'))
.dom(CLIENT_COUNT.charts.chart('running total'))
.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"] [data-test-component="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');
// reset to billing period
await click(SELECTORS.rangeDropdown);
await click(CLIENT_COUNT.rangeDropdown);
await click('[data-test-current-billing-period]');
// change billing start to month/year of upgrade to 1.10
await click(SELECTORS.counts.startEdit);
await click(SELECTORS.monthDropdown);
await click(CLIENT_COUNT.counts.startEdit);
await click(CLIENT_COUNT.monthDropdown);
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-date-dropdown-submit]');
assert.dom(SELECTORS.attributionBlock).exists('Shows attribution area');
assert.dom(CLIENT_COUNT.attributionBlock).exists('Shows attribution area');
assert
.dom(SELECTORS.charts.chart('running total'))
.dom(CLIENT_COUNT.charts.chart('running total'))
.exists('Shows running totals with monthly breakdown charts');
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)');
assert.strictEqual(
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)
await click(SELECTORS.rangeDropdown);
await click(CLIENT_COUNT.rangeDropdown);
await click('[data-test-show-calendar]');
assert.dom('[data-test-display-year]').hasText('2024');
await click('[data-test-previous-year]');
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
.dom(SELECTORS.charts.chart('running total'))
.dom(CLIENT_COUNT.charts.chart('running total'))
.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="total-clients"]').exists('total client attribution chart shows');
// 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-calendar-month="December"]');
assert.dom(SELECTORS.attributionBlock).exists('Shows attribution area');
assert.dom(CLIENT_COUNT.attributionBlock).exists('Shows attribution area');
assert
.dom(SELECTORS.charts.chart('running total'))
.dom(CLIENT_COUNT.charts.chart('running total'))
.exists('Shows running totals with monthly breakdown charts');
assert.strictEqual(
findAll('[data-test-line-chart="plot-point"]').length,
4,
'line chart plots 4 points to match query'
);
const xAxisLabels = findAll(SELECTORS.charts.line.xAxisLabel);
const xAxisLabels = findAll(CLIENT_COUNT.charts.line.xAxisLabel);
assert
.dom(xAxisLabels[xAxisLabels.length - 1])
.hasText('12/23', 'x-axis labels end with queried end month');
// reset to billing period
await click(SELECTORS.rangeDropdown);
await click(CLIENT_COUNT.rangeDropdown);
await click('[data-test-current-billing-period]');
// query month older than count start date
await click(SELECTORS.counts.startEdit);
await click(SELECTORS.monthDropdown);
await click(CLIENT_COUNT.counts.startEdit);
await click(CLIENT_COUNT.monthDropdown);
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-date-dropdown-submit]');
assert
.dom(SELECTORS.counts.startDiscrepancy)
.dom(CLIENT_COUNT.counts.startDiscrepancy)
.hasTextContaining(
'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'
@ -164,9 +165,9 @@ module('Acceptance | clients | overview', function (hooks) {
test('totals filter correctly with full data', async function (assert) {
assert
.dom(SELECTORS.charts.chart('running total'))
.dom(CLIENT_COUNT.charts.chart('running total'))
.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');
// FILTER BY NAMESPACE
@ -176,19 +177,19 @@ module('Acceptance | clients | overview', function (hooks) {
const topNamespace = response.byNamespace[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(SELECTORS.charts.statTextValue('Entity clients'))
.dom(CLIENT_COUNT.charts.statTextValue('Entity clients'))
.includesText(`${formatNumber([topNamespace.entity_clients])}`, 'total entity clients is accurate');
assert
.dom(SELECTORS.charts.statTextValue('Non-entity clients'))
.dom(CLIENT_COUNT.charts.statTextValue('Non-entity clients'))
.includesText(
`${formatNumber([topNamespace.non_entity_clients])}`,
'total non-entity clients is accurate'
);
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');
assert
.dom('[data-test-attribution-clients] p')
@ -200,35 +201,35 @@ module('Acceptance | clients | overview', function (hooks) {
await settled();
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
.dom(SELECTORS.charts.statTextValue('Entity clients'))
.dom(CLIENT_COUNT.charts.statTextValue('Entity clients'))
.includesText(`${formatNumber([topMount.entity_clients])}`, 'total entity clients is accurate');
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');
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');
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"]');
assert.ok(true, 'Remove namespace filter without first removing auth method filter');
assert.dom('[data-test-top-attribution]').includesText('Top namespace');
assert
.dom(SELECTORS.charts.statTextValue('Entity clients'))
.dom(CLIENT_COUNT.charts.statTextValue('Entity clients'))
.hasTextContaining(
`${formatNumber([response.total.entity_clients])}`,
'total entity clients is back to unfiltered value'
);
assert
.dom(SELECTORS.charts.statTextValue('Non-entity clients'))
.dom(CLIENT_COUNT.charts.statTextValue('Non-entity clients'))
.hasTextContaining(
`${formatNumber([formatNumber([response.total.non_entity_clients])])}`,
'total non-entity clients is back to unfiltered value'
);
assert
.dom(SELECTORS.charts.statTextValue('Secrets sync clients'))
.dom(CLIENT_COUNT.charts.statTextValue('Secrets sync clients'))
.hasTextContaining(
`${formatNumber([formatNumber([response.total.secret_syncs])])}`,
'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) {
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) {
assert
.dom(SELECTORS.charts.statTextValue('Secrets sync clients'))
.dom(CLIENT_COUNT.charts.statTextValue('Secrets sync clients'))
.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(SELECTORS.emptyStateTitle).doesNotExist();
assert.dom(GENERAL.tab('sync')).hasClass('active');
assert.dom(GENERAL.emptyStateTitle).doesNotExist();
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');
});
});
@ -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) {
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) {
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');
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) {
assert.dom(SELECTORS.tab('sync')).doesNotExist();
assert.dom(GENERAL.tab('sync')).doesNotExist();
});
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();
});

View File

@ -12,7 +12,8 @@ import { visit, click, currentURL } from '@ember/test-helpers';
import sinon from 'sinon';
import timestamp from 'core/utils/timestamp';
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) {
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) {
syncHandler(this.server);
assert.dom(SELECTORS.charts.chart('Secrets sync usage')).exists('Secrets sync usage chart is rendered');
assert.dom(SELECTORS.syncTab.total).exists('Total sync clients chart is rendered');
assert.dom(SELECTORS.emptyStateTitle).doesNotExist();
assert
.dom(CLIENT_COUNT.charts.chart('Secrets sync usage'))
.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(
currentURL(),
'/vault/sync/secrets/overview',

View File

@ -6,13 +6,14 @@
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
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 logout from 'vault/tests/pages/logout';
import { format, addDays, startOfDay } from 'date-fns';
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 { GENERAL } from 'vault/tests/helpers/general-selectors';
module('Acceptance | Community | config-ui/messages', function (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) {
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);
hooks.beforeEach(async function () {
this.messageDetailId = () => {
return currentURL().match(/messages\/(.*)\/details/)[1];
};
this.createMessage = async (messageType = 'banner', endTime = '2023-12-12', authenticated = true) => {
await click(PAGE.navLink);
await click(CUSTOM_MESSAGES.navLink);
if (authenticated) {
await click(PAGE.tab('After user logs in'));
await click(PAGE.button('create message'));
await click(CUSTOM_MESSAGES.tab('After user logs in'));
} else {
await click(PAGE.tab('On login page'));
await click(PAGE.button('create message'));
await click(CUSTOM_MESSAGES.tab('On login page'));
}
await click(CUSTOM_MESSAGES.button('create message'));
await visit(`vault/config-ui/messages?authenticated=${authenticated}`);
await click(PAGE.button('create message'));
await fillIn(PAGE.input('title'), 'Awesome custom message title');
await click(PAGE.radio(messageType));
await fillIn(CUSTOM_MESSAGES.input('title'), 'Awesome custom message title');
await click(CUSTOM_MESSAGES.radio(messageType));
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.'
);
await fillIn(
PAGE.input('startTime'),
CUSTOM_MESSAGES.input('startTime'),
format(addDays(startOfDay(new Date('2023-12-12')), 1), datetimeLocalStringFormat)
);
if (endTime) {
await click('#specificDate');
await fillIn(
PAGE.input('endTime'),
CUSTOM_MESSAGES.input('endTime'),
format(addDays(startOfDay(new Date('2023-12-12')), 10), datetimeLocalStringFormat)
);
}
await fillIn('[data-test-kv-key="0"]', 'Learn more');
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 () {
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) {
assert.expect(4);
await click(PAGE.navLink);
await click(CUSTOM_MESSAGES.navLink);
assert.dom('[data-test-component="empty-state"]').exists();
assert.dom(PAGE.emptyStateTitle).hasText('No messages yet');
await click(PAGE.tab('On login page'));
assert.dom(GENERAL.emptyStateTitle).hasText('No messages yet');
await click(CUSTOM_MESSAGES.tab('On login page'));
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 () {
test('it should create, edit, view, and delete a message', async function (assert) {
assert.expect(3);
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 fillIn(PAGE.input('title'), 'Edited custom message title');
await click(PAGE.button('create-message'));
assert.dom(PAGE.title).hasText('Edited custom message title');
await click(PAGE.confirmActionButton('Delete message'));
await click(PAGE.confirmButton);
await fillIn(CUSTOM_MESSAGES.input('title'), 'Edited custom message title');
await click(CUSTOM_MESSAGES.button('create-message'));
assert.dom(GENERAL.title).hasText('Edited custom message title');
await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(GENERAL.confirmButton);
assert.strictEqual(
currentRouteName(),
'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) {
assert.expect(4);
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);
assert.dom(PAGE.modal('multiple modal messages')).exists();
assert.dom(CUSTOM_MESSAGES.modal('multiple modal messages')).exists();
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');
await click(PAGE.modalButton('cancel'));
await click(CUSTOM_MESSAGES.modalButton('cancel'));
await visit('vault/config-ui/messages');
await click(PAGE.listItem('Awesome custom message title'));
await click(PAGE.confirmActionButton('Delete message'));
await click(PAGE.confirmButton);
await click(CUSTOM_MESSAGES.listItem('Awesome custom message title'));
await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(GENERAL.confirmButton);
assert.dom('[data-test-component="empty-state"]').exists('Message was deleted');
});
test('it should filter by type and status', async function (assert) {
assert.expect(6);
await this.createMessage('banner', null);
const msg1 = this.messageDetailId();
await this.createMessage('banner');
const msg2 = this.messageDetailId();
await visit('vault/config-ui/messages');
// 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');
// clean up custom messages
await click(PAGE.listItem('Awesome custom message title'));
await click(PAGE.confirmActionButton('Delete message'));
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');
await this.deleteMessage(msg1);
await this.deleteMessage(msg2);
});
test('it should display preview a message when all required fields are filled out', async function (assert) {
assert.expect(2);
await click(PAGE.navLink);
await click(PAGE.tab('After user logs in'));
await click(PAGE.button('create message'));
await fillIn(PAGE.input('title'), 'Awesome custom message title');
await click(PAGE.radio('banner'));
await click(CUSTOM_MESSAGES.navLink);
await click(CUSTOM_MESSAGES.tab('After user logs in'));
await click(CUSTOM_MESSAGES.button('create message'));
await fillIn(CUSTOM_MESSAGES.input('title'), 'Awesome custom message title');
await click(CUSTOM_MESSAGES.radio('banner'));
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.'
);
await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('preview'));
assert.dom(PAGE.modal('preview image')).exists();
await click(PAGE.modalButton('Close'));
await click(PAGE.radio('modal'));
await click(PAGE.button('preview'));
assert.dom(PAGE.modal('preview modal')).exists();
await click(CUSTOM_MESSAGES.button('preview'));
assert.dom(CUSTOM_MESSAGES.modal('preview image')).exists();
await click(CUSTOM_MESSAGES.modalButton('Close'));
await click(CUSTOM_MESSAGES.radio('modal'));
await click(CUSTOM_MESSAGES.button('preview'));
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) {
assert.expect(2);
await click(PAGE.navLink);
await click(PAGE.tab('After user logs in'));
await click(PAGE.button('create message'));
await click(PAGE.radio('banner'));
await click(CUSTOM_MESSAGES.navLink);
await click(CUSTOM_MESSAGES.tab('After user logs in'));
await click(CUSTOM_MESSAGES.button('create message'));
await click(CUSTOM_MESSAGES.radio('banner'));
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.'
);
await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('preview'));
assert.dom(PAGE.modal('preview image')).doesNotExist();
assert.dom(PAGE.input('title')).hasClass('has-error-border');
await click(CUSTOM_MESSAGES.button('preview'));
assert.dom(CUSTOM_MESSAGES.modal('preview image')).doesNotExist();
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) {
assert.expect(3);
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 fillIn(PAGE.input('title'), 'Edited custom message title');
await click(PAGE.button('create-message'));
assert.dom(PAGE.title).hasText('Edited custom message title');
await click(PAGE.confirmActionButton('Delete message'));
await click(PAGE.confirmButton);
await fillIn(CUSTOM_MESSAGES.input('title'), 'Edited custom message title');
await click(CUSTOM_MESSAGES.button('create-message'));
assert.dom(GENERAL.title).hasText('Edited custom message title');
await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(GENERAL.confirmButton);
assert.strictEqual(
currentRouteName(),
'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) {
assert.expect(4);
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);
assert.dom(PAGE.modal('multiple modal messages')).exists();
assert.dom(CUSTOM_MESSAGES.modal('multiple modal messages')).exists();
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');
await click(PAGE.modalButton('cancel'));
await click(CUSTOM_MESSAGES.modalButton('cancel'));
await visit('vault/config-ui/messages?authenticated=false');
await click(PAGE.listItem('Awesome custom message title'));
await click(PAGE.confirmActionButton('Delete message'));
await click(PAGE.confirmButton);
await click(CUSTOM_MESSAGES.listItem('Awesome custom message title'));
await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(GENERAL.confirmButton);
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) {
assert.expect(1);
await click(PAGE.navLink);
await click(PAGE.tab('On login page'));
await click(PAGE.button('create message'));
await click(CUSTOM_MESSAGES.navLink);
await click(CUSTOM_MESSAGES.tab('On login page'));
await click(CUSTOM_MESSAGES.button('create message'));
assert
.dom(PAGE.unauthCreateFormInfo)
.dom(CUSTOM_MESSAGES.unauthCreateFormInfo)
.hasText(
'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) {
assert.expect(2);
await click(PAGE.navLink);
await click(PAGE.tab('On login page'));
await click(PAGE.button('create message'));
await fillIn(PAGE.input('title'), 'Awesome custom message title');
await click(PAGE.radio('banner'));
await click(CUSTOM_MESSAGES.navLink);
await click(CUSTOM_MESSAGES.tab('On login page'));
await click(CUSTOM_MESSAGES.button('create message'));
await fillIn(CUSTOM_MESSAGES.input('title'), 'Awesome custom message title');
await click(CUSTOM_MESSAGES.radio('banner'));
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.'
);
await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('preview'));
assert.dom(PAGE.modal('preview image')).exists();
await click(PAGE.modalButton('Close'));
await click(PAGE.radio('modal'));
await click(PAGE.button('preview'));
assert.dom(PAGE.modal('preview modal')).exists();
await click(CUSTOM_MESSAGES.button('preview'));
assert.dom(CUSTOM_MESSAGES.modal('preview image')).exists();
await click(CUSTOM_MESSAGES.modalButton('Close'));
await click(CUSTOM_MESSAGES.radio('modal'));
await click(CUSTOM_MESSAGES.button('preview'));
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) {
assert.expect(2);
await click(PAGE.navLink);
await click(PAGE.tab('On login page'));
await click(PAGE.button('create message'));
await click(PAGE.radio('banner'));
await click(CUSTOM_MESSAGES.navLink);
await click(CUSTOM_MESSAGES.tab('On login page'));
await click(CUSTOM_MESSAGES.button('create message'));
await click(CUSTOM_MESSAGES.radio('banner'));
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.'
);
await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('preview'));
assert.dom(PAGE.modal('preview image')).doesNotExist();
assert.dom(PAGE.input('title')).hasClass('has-error-border');
await click(CUSTOM_MESSAGES.button('preview'));
assert.dom(CUSTOM_MESSAGES.modal('preview image')).doesNotExist();
assert.dom(CUSTOM_MESSAGES.input('title')).hasClass('has-error-border');
});
});
});

View File

@ -6,7 +6,8 @@
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
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 authPage from 'vault/tests/pages/auth';
@ -68,14 +69,14 @@ module('Acceptance | auth custom messages auth tests', function (hooks) {
await visit('/vault/auth');
const modalId = 'some-awesome-id-1';
const alertId = 'some-awesome-id-2';
assert.dom(PAGE.modal(modalId)).exists();
assert.dom(PAGE.modalTitle(modalId)).hasText('Modal title');
assert.dom(PAGE.modalBody(modalId)).exists();
assert.dom(PAGE.modalBody(modalId)).hasText('here is a cool message');
await click(PAGE.modalButton(modalId));
assert.dom(PAGE.alertTitle(alertId)).hasText('Banner title');
assert.dom(PAGE.alertDescription(alertId)).hasText('hello world hello wolrd');
assert.dom(PAGE.alertAction('link')).hasText('some alert link');
assert.dom(CUSTOM_MESSAGES.modal(modalId)).exists();
assert.dom(CUSTOM_MESSAGES.modalTitle(modalId)).hasText('Modal title');
assert.dom(CUSTOM_MESSAGES.modalBody(modalId)).exists();
assert.dom(CUSTOM_MESSAGES.modalBody(modalId)).hasText('here is a cool message');
await click(CUSTOM_MESSAGES.modalButton(modalId));
assert.dom(CUSTOM_MESSAGES.alertTitle(alertId)).hasText('Banner title');
assert.dom(CUSTOM_MESSAGES.alertDescription(alertId)).hasText('hello world hello wolrd');
assert.dom(CUSTOM_MESSAGES.alertAction('link')).hasText('some alert link');
});
test('it shows the multiple modal messages', async function (assert) {
const modalIdOne = 'some-awesome-id-2';
@ -89,16 +90,16 @@ module('Acceptance | auth custom messages auth tests', function (hooks) {
return unauthenticatedMessageResponse;
});
await visit('/vault/auth');
assert.dom(PAGE.modal(modalIdOne)).exists();
assert.dom(PAGE.modalTitle(modalIdOne)).hasText('Modal title 1');
assert.dom(PAGE.modalBody(modalIdOne)).exists();
assert.dom(PAGE.modalBody(modalIdOne)).hasText('hello world hello wolrd some alert link');
await click(PAGE.modalButton(modalIdOne));
assert.dom(PAGE.modal(modalIdTwo)).exists();
assert.dom(PAGE.modalTitle(modalIdTwo)).hasText('Modal title 2');
assert.dom(PAGE.modalBody(modalIdTwo)).exists();
assert.dom(PAGE.modalBody(modalIdTwo)).hasText('here is a cool message');
await click(PAGE.modalButton(modalIdTwo));
assert.dom(CUSTOM_MESSAGES.modal(modalIdOne)).exists();
assert.dom(CUSTOM_MESSAGES.modalTitle(modalIdOne)).hasText('Modal title 1');
assert.dom(CUSTOM_MESSAGES.modalBody(modalIdOne)).exists();
assert.dom(CUSTOM_MESSAGES.modalBody(modalIdOne)).hasText('hello world hello wolrd some alert link');
await click(CUSTOM_MESSAGES.modalButton(modalIdOne));
assert.dom(CUSTOM_MESSAGES.modal(modalIdTwo)).exists();
assert.dom(CUSTOM_MESSAGES.modalTitle(modalIdTwo)).hasText('Modal title 2');
assert.dom(CUSTOM_MESSAGES.modalBody(modalIdTwo)).exists();
assert.dom(CUSTOM_MESSAGES.modalBody(modalIdTwo)).hasText('here is a cool message');
await click(CUSTOM_MESSAGES.modalButton(modalIdTwo));
});
test('it shows the multiple banner messages', async function (assert) {
const bannerIdOne = 'some-awesome-id-2';
@ -112,11 +113,11 @@ module('Acceptance | auth custom messages auth tests', function (hooks) {
return unauthenticatedMessageResponse;
});
await visit('/vault/auth');
assert.dom(PAGE.alertTitle(bannerIdOne)).hasText('Banner title 1');
assert.dom(PAGE.alertDescription(bannerIdOne)).hasText('hello world hello wolrd');
assert.dom(PAGE.alertTitle(bannerIdTwo)).hasText('Banner title 2');
assert.dom(PAGE.alertDescription(bannerIdTwo)).hasText('here is a cool message');
assert.dom(PAGE.alertAction('link')).hasText('some alert link');
assert.dom(CUSTOM_MESSAGES.alertTitle(bannerIdOne)).hasText('Banner title 1');
assert.dom(CUSTOM_MESSAGES.alertDescription(bannerIdOne)).hasText('hello world hello wolrd');
assert.dom(CUSTOM_MESSAGES.alertTitle(bannerIdTwo)).hasText('Banner title 2');
assert.dom(CUSTOM_MESSAGES.alertDescription(bannerIdTwo)).hasText('here is a cool message');
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);
await authPage.login();
await visit('vault/config-ui/messages');
await click(PAGE.button('create message'));
await fillIn(PAGE.input('title'), 'Awesome custom message title');
await click(PAGE.radio('banner'));
await click(CUSTOM_MESSAGES.button('create message'));
await fillIn(CUSTOM_MESSAGES.input('title'), 'Awesome custom message title');
await click(CUSTOM_MESSAGES.radio('banner'));
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.'
);
await fillIn(
PAGE.input('startTime'),
CUSTOM_MESSAGES.input('startTime'),
format(addDays(startOfDay(new Date('2023-12-12')), 1), datetimeLocalStringFormat)
);
await fillIn('[data-test-kv-key="0"]', 'Learn more');
await fillIn('[data-test-kv-value="0"]', 'www.learn.com');
await click(PAGE.button('create-message'));
assert.dom(PAGE.title).hasText('Awesome custom message title', 'on the details screen');
await click(CUSTOM_MESSAGES.button('create-message'));
assert.dom(GENERAL.title).hasText('Awesome custom message title', 'on the details screen');
assert.dom('.hds-alert').exists('active custom message displays on authenticated.');
await runCmd(createNS('world'), false);
await visit('vault/config-ui/messages');
assert.dom('.hds-alert').exists('active custom message displays on namespace authenticated.');
await click(PAGE.listItem('Awesome custom message title'));
await click(PAGE.confirmActionButton('Delete message'));
await click(PAGE.confirmButton);
await click(CUSTOM_MESSAGES.listItem('Awesome custom message title'));
await click(CUSTOM_MESSAGES.confirmActionButton('Delete message'));
await click(GENERAL.confirmButton);
assert.strictEqual(
currentRouteName(),
'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 { runCmd, deleteEngineCmd, createNS } from 'vault/tests/helpers/commands';
import { SELECTORS } from 'vault/tests/helpers/components/dashboard/dashboard-selectors';
import { PAGE } from 'vault/tests/helpers/config-ui/message-selectors';
import { DASHBOARD } from 'vault/tests/helpers/components/dashboard/dashboard-selectors';
import { CUSTOM_MESSAGES } from 'vault/tests/helpers/config-ui/message-selectors';
const authenticatedMessageResponse = {
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}`;
assert.dom(SELECTORS.cardHeader('Vault version')).hasText(versionText);
assert.dom(DASHBOARD.cardHeader('Vault version')).hasText(versionText);
});
module('secrets engines card', function (hooks) {
@ -100,7 +100,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
await mountSecrets.enable('pki', 'pki');
await settled();
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
await runCmd(deleteEngineCmd('pki'));
});
@ -221,26 +221,26 @@ module('Acceptance | landing page dashboard', function (hooks) {
await visit('/vault/dashboard');
const version = this.owner.lookup('service:version');
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 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) {
assert.expect(8);
await authPage.login();
await visit('/vault/dashboard');
assert.dom(SELECTORS.cardHeader('configuration')).hasText('Configuration details');
assert.dom(DASHBOARD.cardHeader('configuration')).hasText('Configuration details');
assert
.dom(SELECTORS.vaultConfigurationCard.configDetailsField('api_addr'))
.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('api_addr'))
.hasText('http://127.0.0.1:8200');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('default_lease_ttl')).hasText('0');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('max_lease_ttl')).hasText('2 days');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('tls')).hasText('Disabled'); // tls_disable=true
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('log_format')).hasText('None');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('log_level')).hasText('debug');
assert.dom(SELECTORS.vaultConfigurationCard.configDetailsField('type')).hasText('raft');
assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('default_lease_ttl')).hasText('0');
assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('max_lease_ttl')).hasText('2 days');
assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('tls')).hasText('Disabled'); // tls_disable=true
assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('log_format')).hasText('None');
assert.dom(DASHBOARD.vaultConfigurationCard.configDetailsField('log_level')).hasText('debug');
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) {
@ -251,7 +251,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
await authPage.login();
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) {
@ -261,7 +261,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
this.data.listeners[0].config.tls_key_file = './key.pem';
await authPage.login();
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) {
@ -269,7 +269,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
this.data.listeners = [];
await authPage.login();
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) {
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) {
@ -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 settled();
await visit('/vault/dashboard');
await selectChoose(SELECTORS.searchSelect('secrets-engines'), backend);
await fillIn(SELECTORS.selectEl, 'Issue certificate');
assert.dom(SELECTORS.emptyState('quick-actions')).doesNotExist();
assert.dom(SELECTORS.subtitle('param')).hasText('Role to use');
await selectChoose(DASHBOARD.searchSelect('secrets-engines'), backend);
await fillIn(DASHBOARD.selectEl, 'Issue certificate');
assert.dom(DASHBOARD.emptyState('quick-actions')).doesNotExist();
assert.dom(DASHBOARD.subtitle('param')).hasText('Role to use');
await selectChoose(SELECTORS.searchSelect('params'), 'some-role');
assert.dom(SELECTORS.actionButton('Issue leaf certificate')).exists({ count: 1 });
await click(SELECTORS.actionButton('Issue leaf certificate'));
await selectChoose(DASHBOARD.searchSelect('params'), 'some-role');
assert.dom(DASHBOARD.actionButton('Issue leaf certificate')).exists({ count: 1 });
await click(DASHBOARD.actionButton('Issue leaf certificate'));
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.roles.role.generate');
await visit('/vault/dashboard');
await selectChoose(SELECTORS.searchSelect('secrets-engines'), backend);
await fillIn(SELECTORS.selectEl, 'View certificate');
assert.dom(SELECTORS.emptyState('quick-actions')).doesNotExist();
assert.dom(SELECTORS.subtitle('param')).hasText('Certificate serial number');
assert.dom(SELECTORS.actionButton('View certificate')).exists({ count: 1 });
await selectChoose(SELECTORS.searchSelect('params'), '.ember-power-select-option', 0);
await click(SELECTORS.actionButton('View certificate'));
await selectChoose(DASHBOARD.searchSelect('secrets-engines'), backend);
await fillIn(DASHBOARD.selectEl, 'View certificate');
assert.dom(DASHBOARD.emptyState('quick-actions')).doesNotExist();
assert.dom(DASHBOARD.subtitle('param')).hasText('Certificate serial number');
assert.dom(DASHBOARD.actionButton('View certificate')).exists({ count: 1 });
await selectChoose(DASHBOARD.searchSelect('params'), '.ember-power-select-option', 0);
await click(DASHBOARD.actionButton('View certificate'));
assert.strictEqual(
currentRouteName(),
'vault.cluster.secrets.backend.pki.certificates.certificate.details'
@ -323,13 +323,13 @@ module('Acceptance | landing page dashboard', function (hooks) {
await visit('/vault/dashboard');
await selectChoose(SELECTORS.searchSelect('secrets-engines'), backend);
await fillIn(SELECTORS.selectEl, 'View issuer');
assert.dom(SELECTORS.emptyState('quick-actions')).doesNotExist();
assert.dom(SELECTORS.subtitle('param')).hasText('Issuer');
assert.dom(SELECTORS.actionButton('View issuer')).exists({ count: 1 });
await selectChoose(SELECTORS.searchSelect('params'), '.ember-power-select-option', 0);
await click(SELECTORS.actionButton('View issuer'));
await selectChoose(DASHBOARD.searchSelect('secrets-engines'), backend);
await fillIn(DASHBOARD.selectEl, 'View issuer');
assert.dom(DASHBOARD.emptyState('quick-actions')).doesNotExist();
assert.dom(DASHBOARD.subtitle('param')).hasText('Issuer');
assert.dom(DASHBOARD.actionButton('View issuer')).exists({ count: 1 });
await selectChoose(DASHBOARD.searchSelect('params'), '.ember-power-select-option', 0);
await click(DASHBOARD.actionButton('View issuer'));
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.issuers.issuer.details');
// cleanup engine mount
@ -362,13 +362,13 @@ module('Acceptance | landing page dashboard', function (hooks) {
]);
await settled();
await visit('/vault/dashboard');
await selectChoose(SELECTORS.searchSelect('secrets-engines'), databaseBackend);
await fillIn(SELECTORS.selectEl, 'Generate credentials for database');
assert.dom(SELECTORS.emptyState('quick-actions')).doesNotExist();
assert.dom(SELECTORS.subtitle('param')).hasText('Role to use');
assert.dom(SELECTORS.actionButton('Generate credentials')).exists({ count: 1 });
await selectChoose(SELECTORS.searchSelect('params'), '.ember-power-select-option', 0);
await click(SELECTORS.actionButton('Generate credentials'));
await selectChoose(DASHBOARD.searchSelect('secrets-engines'), databaseBackend);
await fillIn(DASHBOARD.selectEl, 'Generate credentials for database');
assert.dom(DASHBOARD.emptyState('quick-actions')).doesNotExist();
assert.dom(DASHBOARD.subtitle('param')).hasText('Role to use');
assert.dom(DASHBOARD.actionButton('Generate credentials')).exists({ count: 1 });
await selectChoose(DASHBOARD.searchSelect('params'), '.ember-power-select-option', 0);
await click(DASHBOARD.actionButton('Generate credentials'));
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.credentials');
await runCmd(deleteEngineCmd(databaseBackend));
});
@ -401,7 +401,7 @@ module('Acceptance | landing page dashboard', function (hooks) {
const version = this.owner.lookup('service:version');
assert.true(version.isEnterprise, 'version is enterprise');
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');
assert.dom('[data-test-client-count-title]').hasText('Client count');
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');
const version = this.owner.lookup('service:version');
assert.true(version.isEnterprise, 'vault is enterprise');
assert.dom(SELECTORS.emptyState('replication')).exists();
assert.dom(SELECTORS.emptyStateTitle('replication')).hasText('Replication not set up');
assert.dom(DASHBOARD.emptyState('replication')).exists();
assert.dom(DASHBOARD.emptyStateTitle('replication')).hasText('Replication not set up');
assert
.dom(SELECTORS.emptyStateMessage('replication'))
.dom(DASHBOARD.emptyStateMessage('replication'))
.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) {
@ -446,10 +446,10 @@ module('Acceptance | landing page dashboard', function (hooks) {
await visit('/vault/dashboard');
const version = this.owner.lookup('service:version');
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 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) {
@ -467,12 +467,12 @@ module('Acceptance | landing page dashboard', function (hooks) {
'details dashboard is shown'
);
await visit('/vault/dashboard');
assert.dom(SELECTORS.title('DR primary')).hasText('DR primary');
assert.dom(SELECTORS.tooltipTitle('DR primary')).hasText('not set up');
assert.dom(SELECTORS.tooltipIcon('dr-perf', 'DR primary', 'x-circle')).exists();
assert.dom(SELECTORS.title('Performance primary')).hasText('Performance primary');
assert.dom(SELECTORS.tooltipTitle('Performance primary')).hasText('running');
assert.dom(SELECTORS.tooltipIcon('dr-perf', 'Performance primary', 'check-circle')).exists();
assert.dom(DASHBOARD.title('DR primary')).hasText('DR primary');
assert.dom(DASHBOARD.tooltipTitle('DR primary')).hasText('not set up');
assert.dom(DASHBOARD.tooltipIcon('dr-perf', 'DR primary', 'x-circle')).exists();
assert.dom(DASHBOARD.title('Performance primary')).hasText('Performance primary');
assert.dom(DASHBOARD.tooltipTitle('Performance primary')).hasText('running');
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');
const modalId = 'some-awesome-id-1';
const alertId = 'some-awesome-id-2';
assert.dom(PAGE.modal(modalId)).exists();
assert.dom(PAGE.modalTitle(modalId)).hasText('Modal title');
assert.dom(PAGE.modalBody(modalId)).exists();
assert.dom(PAGE.modalBody(modalId)).hasText('here is a cool message');
await click(PAGE.modalButton(modalId));
assert.dom(PAGE.alertTitle(alertId)).hasText('Banner title');
assert.dom(PAGE.alertDescription(alertId)).hasText('hello world hello wolrd');
assert.dom(PAGE.alertAction('link')).hasText('some link title');
assert.dom(CUSTOM_MESSAGES.modal(modalId)).exists();
assert.dom(CUSTOM_MESSAGES.modalTitle(modalId)).hasText('Modal title');
assert.dom(CUSTOM_MESSAGES.modalBody(modalId)).exists();
assert.dom(CUSTOM_MESSAGES.modalBody(modalId)).hasText('here is a cool message');
await click(CUSTOM_MESSAGES.modalButton(modalId));
assert.dom(CUSTOM_MESSAGES.alertTitle(alertId)).hasText('Banner title');
assert.dom(CUSTOM_MESSAGES.alertDescription(alertId)).hasText('hello world hello wolrd');
assert.dom(CUSTOM_MESSAGES.alertAction('link')).hasText('some link title');
});
test('it shows the multiple modal messages', async function (assert) {
assert.expect(8);
@ -511,16 +511,16 @@ module('Acceptance | landing page dashboard', function (hooks) {
return authenticatedMessageResponse;
});
await visit('/vault/dashboard');
assert.dom(PAGE.modal(modalIdOne)).exists();
assert.dom(PAGE.modalTitle(modalIdOne)).hasText('Modal title 1');
assert.dom(PAGE.modalBody(modalIdOne)).exists();
assert.dom(PAGE.modalBody(modalIdOne)).hasText('hello world hello wolrd some link title');
await click(PAGE.modalButton(modalIdOne));
assert.dom(PAGE.modal(modalIdTwo)).exists();
assert.dom(PAGE.modalTitle(modalIdTwo)).hasText('Modal title 2');
assert.dom(PAGE.modalBody(modalIdTwo)).exists();
assert.dom(PAGE.modalBody(modalIdTwo)).hasText('here is a cool message');
await click(PAGE.modalButton(modalIdTwo));
assert.dom(CUSTOM_MESSAGES.modal(modalIdOne)).exists();
assert.dom(CUSTOM_MESSAGES.modalTitle(modalIdOne)).hasText('Modal title 1');
assert.dom(CUSTOM_MESSAGES.modalBody(modalIdOne)).exists();
assert.dom(CUSTOM_MESSAGES.modalBody(modalIdOne)).hasText('hello world hello wolrd some link title');
await click(CUSTOM_MESSAGES.modalButton(modalIdOne));
assert.dom(CUSTOM_MESSAGES.modal(modalIdTwo)).exists();
assert.dom(CUSTOM_MESSAGES.modalTitle(modalIdTwo)).hasText('Modal title 2');
assert.dom(CUSTOM_MESSAGES.modalBody(modalIdTwo)).exists();
assert.dom(CUSTOM_MESSAGES.modalBody(modalIdTwo)).hasText('here is a cool message');
await click(CUSTOM_MESSAGES.modalButton(modalIdTwo));
});
test('it shows the multiple banner messages', async function (assert) {
assert.expect(5);
@ -535,11 +535,11 @@ module('Acceptance | landing page dashboard', function (hooks) {
return authenticatedMessageResponse;
});
await visit('/vault/dashboard');
assert.dom(PAGE.alertTitle(bannerIdOne)).hasText('Banner title 1');
assert.dom(PAGE.alertDescription(bannerIdOne)).hasText('hello world hello wolrd');
assert.dom(PAGE.alertAction('link')).hasText('some link title');
assert.dom(PAGE.alertTitle(bannerIdTwo)).hasText('Banner title 2');
assert.dom(PAGE.alertDescription(bannerIdTwo)).hasText('here is a cool message');
assert.dom(CUSTOM_MESSAGES.alertTitle(bannerIdOne)).hasText('Banner title 1');
assert.dom(CUSTOM_MESSAGES.alertDescription(bannerIdOne)).hasText('hello world hello wolrd');
assert.dom(CUSTOM_MESSAGES.alertAction('link')).hasText('some link title');
assert.dom(CUSTOM_MESSAGES.alertTitle(bannerIdTwo)).hasText('Banner title 2');
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(() => {
window.postMessage(buildMessage().data, window.origin);
cancelTimers();
}, 50);
}, 100);
await click('[data-test-auth-submit]');
});

View File

@ -17,11 +17,11 @@ import {
OIDC_BASE_URL, // -> '/vault/access/oidc'
SELECTORS,
clearRecord,
overrideCapabilities,
overrideMirageResponse,
ASSIGNMENT_LIST_RESPONSE,
ASSIGNMENT_DATA_RESPONSE,
} from 'vault/tests/helpers/oidc-config';
import { capabilitiesStub, overrideResponse } from 'vault/tests/helpers/stubs';
const searchSelect = create(ss);
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) {
assert.expect(5);
this.server.get('/identity/oidc/client', () => overrideMirageResponse(404));
this.server.get('/identity/oidc/client', () => overrideResponse(404));
await visit(OIDC_BASE_URL);
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) {
assert.expect(6);
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', () =>
overrideMirageResponse(null, ASSIGNMENT_DATA_RESPONSE)
overrideResponse(200, { data: ASSIGNMENT_DATA_RESPONSE })
);
await visit(OIDC_BASE_URL + '/assignments');
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) {
assert.expect(5);
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', () =>
overrideMirageResponse(null, ASSIGNMENT_DATA_RESPONSE)
overrideResponse(null, { data: ASSIGNMENT_DATA_RESPONSE })
);
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');

View File

@ -17,11 +17,10 @@ import {
OIDC_BASE_URL, // -> '/vault/access/oidc'
SELECTORS,
clearRecord,
overrideCapabilities,
overrideMirageResponse,
CLIENT_LIST_RESPONSE,
CLIENT_DATA_RESPONSE,
} from 'vault/tests/helpers/oidc-config';
import { capabilitiesStub, overrideResponse } from 'vault/tests/helpers/stubs';
const searchSelect = create(ss);
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) {
assert.expect(10);
// 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) => {
const json = JSON.parse(req.requestBody);
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) {
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', () =>
overrideMirageResponse(null, CLIENT_DATA_RESPONSE)
overrideResponse(null, { data: CLIENT_DATA_RESPONSE })
);
await visit(OIDC_BASE_URL);
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) {
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', () =>
overrideMirageResponse(null, CLIENT_DATA_RESPONSE)
overrideResponse(null, { data: CLIENT_DATA_RESPONSE })
);
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);
@ -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) {
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', () =>
overrideMirageResponse(null, {
overrideResponse(null, {
data: {
algorithm: 'RS256',
allowed_client_ids: ['*'],
rotation_period: 86400,
verification_ttl: 86400,
},
})
);
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');

View File

@ -22,9 +22,8 @@ import {
PROVIDER_LIST_RESPONSE,
PROVIDER_DATA_RESPONSE,
clearRecord,
overrideCapabilities,
overrideMirageResponse,
} from 'vault/tests/helpers/oidc-config';
import { capabilitiesStub, overrideResponse } from 'vault/tests/helpers/stubs';
const searchSelect = create(ss);
const flashMessage = create(fm);
@ -38,14 +37,14 @@ module('Acceptance | oidc-config providers and scopes', function (hooks) {
oidcConfigHandlers(this.server);
this.store = this.owner.lookup('service:store');
// 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();
});
// LIST SCOPES EMPTY
test('it navigates to scopes list view and renders empty state when no scopes are configured', async function (assert) {
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 click('[data-test-tab="scopes"]');
assert.strictEqual(currentURL(), '/vault/access/oidc/scopes');
@ -64,9 +63,9 @@ module('Acceptance | oidc-config providers and scopes', function (hooks) {
// LIST SCOPE EXIST
test('it renders scope list when scopes exist', async function (assert) {
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', () =>
overrideMirageResponse(null, SCOPE_DATA_RESPONSE)
overrideResponse(null, { data: SCOPE_DATA_RESPONSE })
);
await visit(OIDC_BASE_URL + '/scopes');
assert.strictEqual(
@ -125,13 +124,15 @@ module('Acceptance | oidc-config providers and scopes', function (hooks) {
// ERROR DELETING SCOPE
test('it throws error when trying to delete when scope is currently being associated with any provider', async function (assert) {
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', () =>
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', () => {
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
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) {
assert.expect(3);
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', () =>
overrideMirageResponse(null, {
overrideResponse(null, {
data: {
allowed_client_ids: ['*'],
issuer: 'http://127.0.0.1:8200/v1/identity/oidc/provider/test-provider',
scopes_supported: ['test-scope'],
},
})
);
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');

View File

@ -7,7 +7,8 @@ import { module, test } from 'qunit';
import { setupApplicationTest } from 'vault/tests/helpers';
import authPage from 'vault/tests/pages/auth';
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
@ -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 enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { runCmd } from 'vault/tests/helpers/commands';
import { SELECTORS as S } from 'vault/tests/helpers/pki/workflow';
import { issuerPemBundle } from 'vault/tests/helpers/pki/values';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
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) {
setupApplicationTest(hooks);
@ -46,28 +49,28 @@ module('Acceptance | pki action forms test', function (hooks) {
await authPage.login(this.pkiAdminToken);
await visit(`/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.dom(S.configuration.title).hasText('Configure PKI');
assert.dom(S.configuration.emptyState).exists({ count: 1 }, 'Shows empty state by default');
await click(S.configuration.optionByKey('import'));
assert.dom(S.configuration.emptyState).doesNotExist();
assert.dom(GENERAL.title).hasText('Configure PKI');
assert.dom(GENERAL.emptyStateTitle).exists({ count: 1 }, 'Shows empty state by default');
await click(PKI_CONFIGURE_CREATE.optionByKey('import'));
assert.dom(GENERAL.emptyStateTitle).doesNotExist();
// Submit before filling out form shows an error
await click('[data-test-pki-import-pem-bundle]');
assert.dom(S.configuration.importError).hasText('Error please upload your PEM bundle');
await click(PKI_CONFIGURE_CREATE.importSubmit);
assert.dom(GENERAL.messageError).hasText('Error please upload your PEM bundle');
// Fill in form data
await click('[data-test-text-toggle]');
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(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration/create`,
'stays on page on success'
);
assert.dom(S.configuration.title).hasText('View imported items');
assert.dom(S.configuration.importForm).doesNotExist('import form is hidden after save');
assert.dom(S.configuration.importMapping).exists('import mapping is shown after save');
assert.dom(GENERAL.title).hasText('View imported items');
assert.dom(PKI_CONFIGURE_CREATE.importForm).doesNotExist('import form is hidden after save');
assert.dom(PKI_CONFIGURE_CREATE.importMapping).exists('import mapping is shown after save');
await click('[data-test-done]');
assert.strictEqual(
currentURL(),
@ -91,22 +94,24 @@ module('Acceptance | pki action forms test', function (hooks) {
});
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
await click(S.configuration.optionByKey('import'));
assert.dom(S.configuration.importForm).exists('import form is shown save');
await click(PKI_CONFIGURE_CREATE.optionByKey('import'));
assert.dom(PKI_CONFIGURE_CREATE.importForm).exists('import form is shown save');
await click('[data-test-text-toggle]');
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(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration/create`,
'stays on page on success'
);
assert.dom(S.configuration.title).hasText('View imported items');
assert.dom(S.configuration.importForm).doesNotExist('import form is hidden after save');
assert.dom(S.configuration.importMapping).exists('import mapping is shown after save');
assert.dom(S.configuration.importedIssuer).hasText('my-imported-issuer', 'Issuer value is displayed');
assert.dom(S.configuration.importedKey).hasText('my-imported-key', 'Key value is displayed');
assert.dom(GENERAL.title).hasText('View imported items');
assert.dom(PKI_CONFIGURE_CREATE.importForm).doesNotExist('import form is hidden after save');
assert.dom(PKI_CONFIGURE_CREATE.importMapping).exists('import mapping is shown after save');
assert
.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]');
assert.strictEqual(
currentURL(),
@ -130,16 +135,18 @@ module('Acceptance | pki action forms test', function (hooks) {
});
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
await click(S.configuration.optionByKey('import'));
assert.dom(S.configuration.importForm).exists('import form is shown save');
await click(PKI_CONFIGURE_CREATE.optionByKey('import'));
assert.dom(PKI_CONFIGURE_CREATE.importForm).exists('import form is shown save');
await click('[data-test-text-toggle]');
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(S.configuration.importMapping).exists('import mapping is shown after save');
assert.dom(S.configuration.importedIssuer).hasText('my-imported-issuer', 'Issuer value is displayed');
assert.dom(S.configuration.importedKey).hasText('None', 'Shows placeholder value for key');
assert.dom(PKI_CONFIGURE_CREATE.importForm).doesNotExist('import form is hidden after save');
assert.dom(PKI_CONFIGURE_CREATE.importMapping).exists('import mapping is shown after save');
assert
.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) {
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 visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
await click(S.configuration.optionByKey('import'));
assert.dom(S.configuration.importForm).exists('import form is shown save');
await click(PKI_CONFIGURE_CREATE.optionByKey('import'));
assert.dom(PKI_CONFIGURE_CREATE.importForm).exists('import form is shown save');
await click('[data-test-text-toggle]');
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(S.configuration.importMapping).exists('import mapping is shown after save');
assert.dom(S.configuration.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.importForm).doesNotExist('import form is hidden after save');
assert.dom(PKI_CONFIGURE_CREATE.importMapping).exists('import mapping is shown after save');
assert.dom(PKI_CONFIGURE_CREATE.importedIssuer).hasText('None', 'Shows placeholder value for issuer');
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 visit(`/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.dom(S.configuration.title).hasText('Configure PKI');
assert.dom(S.configuration.emptyState).exists({ count: 1 }, 'Shows empty state by default');
await click(S.configuration.optionByKey('generate-root'));
assert.dom(S.configuration.emptyState).doesNotExist();
assert.dom(GENERAL.title).hasText('Configure PKI');
assert.dom(GENERAL.emptyStateTitle).exists({ count: 1 }, 'Shows empty state by default');
await click(PKI_CONFIGURE_CREATE.optionByKey('generate-root'));
assert.dom(GENERAL.emptyStateTitle).doesNotExist();
// 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.
assert.dom(S.configuration.urlField).exists({ count: 4 });
assert.dom(PKI_GENERATE_ROOT.urlField).exists({ count: 4 });
// Fill in form
await fillIn(S.configuration.typeField, 'internal');
await typeIn(S.configuration.inputByName('commonName'), commonName);
await typeIn(S.configuration.inputByName('issuerName'), issuerName);
await click(S.configuration.keyParamsGroupToggle);
await typeIn(S.configuration.inputByName('keyName'), keyName);
await click(S.configuration.generateRootSave);
await fillIn(GENERAL.inputByAttr('type'), 'internal');
await typeIn(GENERAL.inputByAttr('commonName'), commonName);
await typeIn(GENERAL.inputByAttr('issuerName'), issuerName);
await click(PKI_GENERATE_ROOT.keyParamsGroupToggle);
await typeIn(GENERAL.inputByAttr('keyName'), keyName);
await click(GENERAL.saveButton);
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration/create`,
'stays on page on success'
);
assert.dom(S.configuration.title).hasText('View Root Certificate');
assert.dom(S.configuration.nextStepsBanner).doesNotExist('no private key warning');
assert.dom(S.configuration.title).hasText('View Root Certificate', 'Updates title on page');
assert.dom(S.configuration.saved.certificate).exists('Copyable certificate exists');
assert.dom(S.configuration.saved.issuerName).hasText(issuerName);
assert.dom(S.configuration.saved.issuerLink).exists('Issuer link exists');
assert.dom(S.configuration.saved.keyLink).exists('Key link exists');
assert.dom(S.configuration.saved.keyName).hasText(keyName);
assert.dom(GENERAL.title).hasText('View Root Certificate');
assert.dom(PKI_CONFIGURE_CREATE.nextStepsBanner).doesNotExist('no private key warning');
assert.dom(GENERAL.title).hasText('View Root Certificate', 'Updates title on page');
assert.dom(PKI_GENERATE_ROOT.saved.certificate).exists('Copyable certificate exists');
assert.dom(PKI_GENERATE_ROOT.saved.issuerName).hasText(issuerName);
assert.dom(PKI_GENERATE_ROOT.saved.issuerLink).exists('Issuer link exists');
assert.dom(PKI_GENERATE_ROOT.saved.keyLink).exists('Key link exists');
assert.dom(PKI_GENERATE_ROOT.saved.keyName).hasText(keyName);
assert.dom('[data-test-done]').exists('Done button exists');
// Check that linked issuer has correct common name
await click(S.configuration.saved.issuerLink);
assert.dom(S.issuerDetails.valueByName('Common name')).hasText(commonName);
await click(PKI_GENERATE_ROOT.saved.issuerLink);
assert.dom(GENERAL.infoRowValue('Common name')).hasText(commonName);
});
test('type=exported', async function (assert) {
const commonName = 'my-exported-name';
await authPage.login();
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
await fillIn(S.configuration.typeField, 'exported');
await typeIn(S.configuration.inputByName('commonName'), commonName);
await click(S.configuration.generateRootSave);
await fillIn(GENERAL.inputByAttr('type'), 'exported');
await typeIn(GENERAL.inputByAttr('commonName'), commonName);
await click(GENERAL.saveButton);
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration/create`,
'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)
.dom(PKI_CONFIGURE_CREATE.nextStepsBanner)
.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(S.configuration.saved.certificate).exists('Copyable certificate exists');
assert.dom(GENERAL.title).hasText('View Root Certificate', 'Updates title on page');
assert.dom(PKI_GENERATE_ROOT.saved.certificate).exists('Copyable certificate exists');
assert
.dom(S.configuration.saved.issuerName)
.dom(PKI_GENERATE_ROOT.saved.issuerName)
.doesNotExist('Issuer name not shown because it was not named');
assert.dom(S.configuration.saved.issuerLink).exists('Issuer link exists');
assert.dom(S.configuration.saved.keyLink).exists('Key link exists');
assert.dom(S.configuration.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.issuerLink).exists('Issuer link exists');
assert.dom(PKI_GENERATE_ROOT.saved.keyLink).exists('Key link exists');
assert.dom(PKI_GENERATE_ROOT.saved.privateKey).exists('Copyable private key exists');
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');
// Check that linked issuer has correct common name
await click(S.configuration.saved.issuerLink);
assert.dom(S.issuerDetails.valueByName('Common name')).hasText(commonName);
await click(PKI_GENERATE_ROOT.saved.issuerLink);
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) {
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(S.emptyStateLink);
assert.dom(S.configuration.title).hasText('Configure PKI');
await click(S.configuration.optionByKey('generate-csr'));
await fillIn(S.configuration.typeField, 'internal');
await fillIn(S.configuration.inputByName('commonName'), 'my-common-name');
await click(`${GENERAL.emptyStateActions} a`);
assert.dom(GENERAL.title).hasText('Configure PKI');
await click(PKI_CONFIGURE_CREATE.optionByKey('generate-csr'));
await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(GENERAL.inputByAttr('commonName'), 'my-common-name');
await click('[data-test-save]');
assert.dom(S.configuration.title).hasText('View Generated CSR');
await assert.dom(S.configuration.csrDetails).exists('renders CSR details after save');
assert.dom(GENERAL.title).hasText('View Generated CSR');
await assert.dom(PKI_CONFIGURE_CREATE.csrDetails).exists('renders CSR details after save');
await click('[data-test-done]');
assert.strictEqual(
currentURL(),
@ -267,19 +274,19 @@ module('Acceptance | pki action forms test', function (hooks) {
test('type = exported', async function (assert) {
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(S.emptyStateLink);
await click(S.configuration.optionByKey('generate-csr'));
await fillIn(S.configuration.typeField, 'exported');
await fillIn(S.configuration.inputByName('commonName'), 'my-common-name');
await click(`${GENERAL.emptyStateActions} a`);
await click(PKI_CONFIGURE_CREATE.optionByKey('generate-csr'));
await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(GENERAL.inputByAttr('commonName'), 'my-common-name');
await click('[data-test-save]');
await assert.dom(S.configuration.csrDetails).exists('renders CSR details after save');
assert.dom(S.configuration.title).hasText('View Generated CSR');
await assert.dom(PKI_CONFIGURE_CREATE.csrDetails).exists('renders CSR details after save');
assert.dom(GENERAL.title).hasText('View Generated CSR');
assert
.dom('[data-test-next-steps-csr]')
.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.'
);
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]');
assert.strictEqual(
currentURL(),

View File

@ -14,9 +14,16 @@ import authPage from 'vault/tests/pages/auth';
import logout from 'vault/tests/pages/logout';
import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { runCmd } from 'vault/tests/helpers/commands';
import { SELECTORS } from 'vault/tests/helpers/pki/workflow';
import { issuerPemBundle } from 'vault/tests/helpers/pki/values';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
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) {
setupApplicationTest(hooks);
@ -43,68 +50,66 @@ module('Acceptance | pki configuration test', function (hooks) {
test('it shows the delete all issuers modal', async function (assert) {
await authPage.login(this.pkiAdminToken);
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`);
await settled();
await click(SELECTORS.configuration.generateRootOption);
await fillIn(SELECTORS.configuration.typeField, 'exported');
await fillIn(SELECTORS.configuration.generateRootCommonNameField, 'issuer-common-0');
await fillIn(SELECTORS.configuration.generateRootIssuerNameField, 'issuer-0');
await click(SELECTORS.configuration.generateRootSave);
await click(SELECTORS.configuration.doneButton);
await click(PKI_CONFIGURE_CREATE.generateRootOption);
await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(GENERAL.inputByAttr('commonName'), 'issuer-common-0');
await fillIn(GENERAL.inputByAttr('issuerName'), 'issuer-0');
await click(GENERAL.saveButton);
await click(PKI_CONFIGURE_CREATE.doneButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
await settled();
await click(SELECTORS.configTab);
await click(GENERAL.secretTab('Configuration'));
await settled();
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`);
await click(SELECTORS.configuration.issuerLink);
await click(PKI_DELETE_ALL_ISSUERS.issuerLink);
await settled();
await waitFor(SELECTORS.configuration.deleteAllIssuerModal, { timeout: 5000 });
assert.dom(SELECTORS.configuration.deleteAllIssuerModal).exists();
await fillIn(SELECTORS.configuration.deleteAllIssuerInput, 'delete-all');
await click(SELECTORS.configuration.deleteAllIssuerButton);
await waitFor(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal, { timeout: 5000 });
assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).exists();
await fillIn(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerInput, 'delete-all');
await click(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerButton);
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`);
});
test('it shows the correct empty state message if certificates exists after delete all issuers', async function (assert) {
await authPage.login(this.pkiAdminToken);
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`,
'goes to pki configure page'
);
await click(SELECTORS.configuration.generateRootOption);
await fillIn(SELECTORS.configuration.typeField, 'exported');
await fillIn(SELECTORS.configuration.generateRootCommonNameField, 'issuer-common-0');
await fillIn(SELECTORS.configuration.generateRootIssuerNameField, 'issuer-0');
await click(SELECTORS.configuration.generateRootSave);
await click(SELECTORS.configuration.doneButton);
await click(PKI_CONFIGURE_CREATE.generateRootOption);
await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(GENERAL.inputByAttr('commonName'), 'issuer-common-0');
await fillIn(GENERAL.inputByAttr('issuerName'), 'issuer-0');
await click(GENERAL.saveButton);
await click(PKI_CONFIGURE_CREATE.doneButton);
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/overview`,
'goes to overview page'
);
await click(SELECTORS.configTab);
await click(GENERAL.secretTab('Configuration'));
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration`,
'goes to configuration page'
);
await click(SELECTORS.configuration.issuerLink);
await waitFor(SELECTORS.configuration.deleteAllIssuerModal);
assert.dom(SELECTORS.configuration.deleteAllIssuerModal).exists();
await fillIn(SELECTORS.configuration.deleteAllIssuerInput, 'delete-all');
await click(SELECTORS.configuration.deleteAllIssuerButton);
await waitUntil(() => !find(SELECTORS.configuration.deleteAllIssuerModal));
assert
.dom(SELECTORS.configuration.deleteAllIssuerModal)
.doesNotExist('delete all issuers modal closes');
await click(PKI_DELETE_ALL_ISSUERS.issuerLink);
await waitFor(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal);
assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).exists();
await fillIn(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerInput, 'delete-all');
await click(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerButton);
await waitUntil(() => !find(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal));
assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).doesNotExist('delete all issuers modal closes');
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/configuration`,
@ -119,7 +124,7 @@ module('Acceptance | pki configuration test', function (hooks) {
'goes to overview page'
);
assert
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.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."
);
@ -127,25 +132,25 @@ module('Acceptance | pki configuration test', function (hooks) {
await visit(`/vault/secrets/${this.mountPath}/pki/roles`);
await settled();
assert
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.hasText("This PKI mount hasn't yet been configured with a certificate issuer.");
await visit(`/vault/secrets/${this.mountPath}/pki/issuers`);
await settled();
assert
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.hasText("This PKI mount hasn't yet been configured with a certificate issuer.");
await visit(`/vault/secrets/${this.mountPath}/pki/keys`);
await settled();
assert
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.hasText("This PKI mount hasn't yet been configured with a certificate issuer.");
await visit(`/vault/secrets/${this.mountPath}/pki/certificates`);
await settled();
assert
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.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."
);
@ -155,14 +160,14 @@ module('Acceptance | pki configuration test', function (hooks) {
await authPage.login(this.pkiAdminToken);
// Configure PKI
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`);
await click(SELECTORS.configuration.generateRootOption);
await fillIn(SELECTORS.configuration.typeField, 'exported');
await fillIn(SELECTORS.configuration.generateRootCommonNameField, 'issuer-common-0');
await fillIn(SELECTORS.configuration.generateRootIssuerNameField, 'issuer-0');
await click(SELECTORS.configuration.generateRootSave);
await click(SELECTORS.configuration.doneButton);
await click(PKI_CONFIGURE_CREATE.generateRootOption);
await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(GENERAL.inputByAttr('commonName'), 'issuer-common-0');
await fillIn(GENERAL.inputByAttr('issuerName'), 'issuer-0');
await click(GENERAL.saveButton);
await click(PKI_CONFIGURE_CREATE.doneButton);
// Create role and root CA"
await runCmd([
`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"`]);
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`);
await click(SELECTORS.configuration.issuerLink);
await waitFor(SELECTORS.configuration.deleteAllIssuerModal);
assert.dom(SELECTORS.configuration.deleteAllIssuerModal).exists();
await fillIn(SELECTORS.configuration.deleteAllIssuerInput, 'delete-all');
await click(SELECTORS.configuration.deleteAllIssuerButton);
await click(PKI_DELETE_ALL_ISSUERS.issuerLink);
await waitFor(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal);
assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).exists();
await fillIn(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerInput, 'delete-all');
await click(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerButton);
await settled();
await waitUntil(() => !find(SELECTORS.configuration.deleteAllIssuerModal));
assert.dom(SELECTORS.configuration.deleteAllIssuerModal).doesNotExist();
await waitUntil(() => !find(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal));
assert.dom(PKI_DELETE_ALL_ISSUERS.deleteAllIssuerModal).doesNotExist();
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`);
await settled();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await settled();
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
assert
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.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."
);
@ -197,7 +202,7 @@ module('Acceptance | pki configuration test', function (hooks) {
await visit(`/vault/secrets/${this.mountPath}/pki/roles`);
await settled();
assert
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.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."
);
@ -205,19 +210,19 @@ module('Acceptance | pki configuration test', function (hooks) {
await visit(`/vault/secrets/${this.mountPath}/pki/issuers`);
await settled();
assert
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.hasText("This PKI mount hasn't yet been configured with a certificate issuer.");
await visit(`/vault/secrets/${this.mountPath}/pki/keys`);
await settled();
assert
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.hasText("This PKI mount hasn't yet been configured with a certificate issuer.");
await visit(`/vault/secrets/${this.mountPath}/pki/certificates`);
await settled();
assert
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.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."
);
@ -228,24 +233,24 @@ module('Acceptance | pki configuration test', function (hooks) {
assert.expect(4);
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab);
await click(SELECTORS.generateIssuerDropdown);
await click(SELECTORS.generateIssuerRoot);
await fillIn(SELECTORS.configuration.inputByName('type'), 'internal');
await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-certificate');
await click(SELECTORS.configuration.keyParamsGroupToggle);
await fillIn(SELECTORS.configuration.inputByName('keyType'), 'ed25519');
await click(SELECTORS.configuration.generateRootSave);
await click(GENERAL.secretTab('Issuers'));
await click(PKI_ISSUER_LIST.generateIssuerDropdown);
await click(PKI_ISSUER_LIST.generateIssuerRoot);
await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(GENERAL.inputByAttr('commonName'), 'my-certificate');
await click(PKI_GENERATE_ROOT.keyParamsGroupToggle);
await fillIn(GENERAL.inputByAttr('keyType'), 'ed25519');
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`);
assert.dom(SELECTORS.issuerListItem(issuerId)).exists();
assert.dom(PKI_ISSUER_LIST.issuerListItem(issuerId)).exists();
assert
.dom('[data-test-common-name="0"]')
.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.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 enablePage from 'vault/tests/pages/settings/mount-secret-backend';
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 { 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) {
setupApplicationTest(hooks);
@ -43,48 +49,48 @@ module('Acceptance | pki/pki cross sign', function (hooks) {
test('it cross-signs an issuer', async function (assert) {
// configure parent and intermediate mounts to make them cross-signable
await visit(`/vault/secrets/${this.intMountPath}/pki/configuration/create`);
await click(SELECTORS.configure.optionByKey('generate-csr'));
await fillIn(SELECTORS.inputByName('type'), 'internal');
await fillIn(SELECTORS.inputByName('commonName'), 'Short-Lived Int R1');
await click(PKI_CONFIGURE_CREATE.optionByKey('generate-csr'));
await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(GENERAL.inputByAttr('commonName'), 'Short-Lived Int R1');
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 fillIn(SELECTORS.inputByName('csr'), csr);
await fillIn(SELECTORS.inputByName('format'), 'pem_bundle');
await fillIn(GENERAL.inputByAttr('csr'), csr);
await fillIn(GENERAL.inputByAttr('format'), 'pem_bundle');
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')
.replace(/,/, '\n');
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 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 click('[data-test-is-default]');
// name default issuer of intermediate
const oldIntIssuerId = find(SELECTORS.rowValue('Issuer ID')).innerText;
const oldIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-test-copy-button');
await click(SELECTORS.details.configure);
await fillIn(SELECTORS.inputByName('issuerName'), this.intIssuerName);
const oldIntIssuerId = find(PKI_CROSS_SIGN.rowValue('Issuer ID')).innerText;
const oldIntCert = find(PKI_CROSS_SIGN.copyButton('Certificate')).getAttribute('data-test-copy-button');
await click(PKI_ISSUER_DETAILS.configure);
await fillIn(GENERAL.inputByAttr('issuerName'), this.intIssuerName);
await click('[data-test-save]');
// perform cross-sign
await visit(`vault/secrets/${this.parentMountPath}/pki/issuers/${this.parentIssuerName}/cross-sign`);
await fillIn(SELECTORS.objectListInput('intermediateMount'), this.intMountPath);
await fillIn(SELECTORS.objectListInput('intermediateIssuer'), this.intIssuerName);
await fillIn(SELECTORS.objectListInput('newCrossSignedIssuer'), this.newlySignedIssuer);
await click(SELECTORS.submitButton);
await fillIn(PKI_CROSS_SIGN.objectListInput('intermediateMount'), this.intMountPath);
await fillIn(PKI_CROSS_SIGN.objectListInput('intermediateIssuer'), this.intIssuerName);
await fillIn(PKI_CROSS_SIGN.objectListInput('newCrossSignedIssuer'), this.newlySignedIssuer);
await click(GENERAL.saveButton);
assert
.dom(`${SELECTORS.signedIssuerCol('intermediateMount')} a`)
.dom(`${PKI_CROSS_SIGN.signedIssuerCol('intermediateMount')} a`)
.hasAttribute('href', `/ui/vault/secrets/${this.intMountPath}/pki/overview`);
assert
.dom(`${SELECTORS.signedIssuerCol('intermediateIssuer')} a`)
.dom(`${PKI_CROSS_SIGN.signedIssuerCol('intermediateIssuer')} a`)
.hasAttribute('href', `/ui/vault/secrets/${this.intMountPath}/pki/issuers/${oldIntIssuerId}/details`);
// get certificate data of newly signed issuer
await click(`${SELECTORS.signedIssuerCol('newCrossSignedIssuer')} a`);
const newIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-test-copy-button');
await click(`${PKI_CROSS_SIGN.signedIssuerCol('newCrossSignedIssuer')} a`);
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
const myRole = 'some-role';
@ -95,10 +101,10 @@ module('Acceptance | pki/pki cross sign', function (hooks) {
max_ttl="720h"`,
]);
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 click('[data-test-pki-generate-button]');
const myLeafCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-test-copy-button');
await click(GENERAL.saveButton);
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
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 { click, currentURL, fillIn, visit } from '@ember/test-helpers';
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) {
setupApplicationTest(hooks);
@ -42,7 +51,7 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let configs, urls, config;
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.emptyStateLink);
await click(`${GENERAL.emptyStateActions} a`);
configs = this.store.peekAll('pki/action');
urls = this.store.peekRecord('pki/config/urls', this.mountPath);
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');
// Cancel button rolls it back
await click(SELECTORS.configuration.cancelButton);
await click(GENERAL.cancelButton);
configs = this.store.peekAll('pki/action');
urls = this.store.peekRecord('pki/config/urls', this.mountPath);
assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel');
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');
urls = this.store.peekRecord('pki/config/urls', this.mountPath);
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');
// Exit page via link rolls it back
await click(SELECTORS.overviewBreadcrumb);
await click(OVERVIEW_BREADCRUMB);
configs = this.store.peekAll('pki/action');
urls = this.store.peekRecord('pki/config/urls', this.mountPath);
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();
// Configure PKI
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.emptyStateLink);
await click(SELECTORS.configuration.optionByKey('generate-root'));
await fillIn(SELECTORS.configuration.typeField, 'internal');
await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-root-cert');
await click(SELECTORS.configuration.generateRootSave);
await click(`${GENERAL.emptyStateActions} a`);
await click(PKI_CONFIGURE_CREATE.optionByKey('generate-root'));
await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(GENERAL.inputByAttr('commonName'), 'my-root-cert');
await click(GENERAL.saveButton);
await logout.visit();
});
@ -92,15 +101,15 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
await authPage.login();
// Create PKI
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.rolesTab);
await click(GENERAL.secretTab('Roles'));
roles = this.store.peekAll('pki/role');
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');
const role = roles.at(0);
assert.strictEqual(roles.length, 1, 'New role exists');
assert.true(role.isNew, 'Role is new model');
await click(SELECTORS.roleForm.roleCancelButton);
await click(GENERAL.cancelButton);
roles = this.store.peekAll('pki/role');
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();
// Create PKI
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.rolesTab);
await click(GENERAL.secretTab('Roles'));
roles = this.store.peekAll('pki/role');
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');
const role = roles.at(0);
assert.strictEqual(roles.length, 1, 'New role exists');
assert.true(role.isNew, 'Role is new model');
await click(SELECTORS.overviewBreadcrumb);
await click(OVERVIEW_BREADCRUMB);
roles = this.store.peekAll('pki/role');
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();
// Create PKI
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.rolesTab);
await click(GENERAL.secretTab('Roles'));
roles = this.store.peekAll('pki/role');
assert.strictEqual(roles.length, 0, 'No roles exist yet');
await click(SELECTORS.createRoleLink);
await fillIn(SELECTORS.roleForm.roleName, roleId);
await click(SELECTORS.roleForm.roleCreateButton);
assert.dom('[data-test-value-div="Role name"]').hasText(roleId, 'Shows correct role after create');
await click(PKI_ROLE_DETAILS.createRoleLink);
await fillIn(GENERAL.inputByAttr('name'), roleId);
await click(GENERAL.saveButton);
assert.dom(GENERAL.infoRowValue('Role name')).hasText(roleId, 'Shows correct role after create');
roles = this.store.peekAll('pki/role');
role = roles.at(0);
assert.strictEqual(roles.length, 1, 'Role is created');
assert.false(role.hasDirtyAttributes, 'Role no longer has dirty attributes');
// Edit role
await click(SELECTORS.editRoleLink);
await click(SELECTORS.roleForm.issuerRefToggle);
await fillIn(SELECTORS.roleForm.issuerRefSelect, 'foobar');
await click(PKI_ROLE_DETAILS.editRoleLink);
await click(GENERAL.ttl.toggle('issuerRef-toggle'));
await fillIn(GENERAL.selectByAttr('issuerRef'), 'foobar');
role = this.store.peekRecord('pki/role', roleId);
assert.true(role.hasDirtyAttributes, 'Role has dirty attrs');
// 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`);
role = this.store.peekRecord('pki/role', roleId);
assert.false(role.hasDirtyAttributes, 'Role dirty attrs have been rolled back');
// Edit again
await click(SELECTORS.editRoleLink);
await click(SELECTORS.roleForm.issuerRefToggle);
await fillIn(SELECTORS.roleForm.issuerRefSelect, 'foobar2');
await click(PKI_ROLE_DETAILS.editRoleLink);
await click(GENERAL.ttl.toggle('issuerRef-toggle'));
await fillIn(GENERAL.selectByAttr('issuerRef'), 'foobar2');
role = this.store.peekRecord('pki/role', roleId);
assert.true(role.hasDirtyAttributes, 'Role has dirty attrs');
// Exit page via breadcrumbs
await click(SELECTORS.overviewBreadcrumb);
await click(OVERVIEW_BREADCRUMB);
role = this.store.peekRecord('pki/role', roleId);
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;
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab);
await click(GENERAL.secretTab('Issuers'));
issuers = this.store.peekAll('pki/issuer');
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');
assert.strictEqual(issuers.length, 1, 'Action model created');
const issuer = issuers.at(0);
@ -188,17 +197,17 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let issuers;
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab);
await click(GENERAL.secretTab('Issuers'));
issuers = this.store.peekAll('pki/issuer');
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');
assert.strictEqual(issuers.length, 1, 'Action model created');
const issuer = issuers.at(0);
assert.true(issuer.hasDirtyAttributes, 'Action model has dirty attrs');
assert.true(issuer.isNew, 'Action model is new');
// Exit
await click(SELECTORS.overviewBreadcrumb);
await click(OVERVIEW_BREADCRUMB);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
issuers = this.store.peekAll('pki/action');
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;
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab);
await click(GENERAL.secretTab('Issuers'));
actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'No actions exist yet');
await click(SELECTORS.generateIssuerDropdown);
await click(SELECTORS.generateIssuerRoot);
await click(PKI_ISSUER_LIST.generateIssuerDropdown);
await click(PKI_ISSUER_LIST.generateIssuerRoot);
actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 1, 'Action model for generate-root created');
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.strictEqual(action.actionType, 'generate-root', 'Action type is correct');
// Exit
await click(SELECTORS.configuration.generateRootCancel);
await click(GENERAL.cancelButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`);
actions = this.store.peekAll('pki/action');
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;
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab);
await click(GENERAL.secretTab('Issuers'));
actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'No actions exist yet');
await click(SELECTORS.generateIssuerDropdown);
await click(SELECTORS.generateIssuerRoot);
await click(PKI_ISSUER_LIST.generateIssuerDropdown);
await click(PKI_ISSUER_LIST.generateIssuerRoot);
actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 1, 'Action model for generate-root created');
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.strictEqual(action.actionType, 'generate-root');
// Exit
await click(SELECTORS.overviewBreadcrumb);
await click(OVERVIEW_BREADCRUMB);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
actions = this.store.peekAll('pki/action');
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;
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab);
await click(GENERAL.secretTab('Issuers'));
actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'No actions exist yet');
await await click(SELECTORS.generateIssuerDropdown);
await click(SELECTORS.generateIssuerIntermediate);
await await click(PKI_ISSUER_LIST.generateIssuerDropdown);
await click(PKI_ISSUER_LIST.generateIssuerIntermediate);
actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 1, 'Action model for generate-csr created');
const action = actions.at(0);
@ -270,11 +279,11 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
let actions;
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab);
await click(GENERAL.secretTab('Issuers'));
actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 0, 'No actions exist yet');
await click(SELECTORS.generateIssuerDropdown);
await click(SELECTORS.generateIssuerIntermediate);
await click(PKI_ISSUER_LIST.generateIssuerDropdown);
await click(PKI_ISSUER_LIST.generateIssuerIntermediate);
actions = this.store.peekAll('pki/action');
assert.strictEqual(actions.length, 1, 'Action model for generate-csr created');
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.strictEqual(action.actionType, 'generate-csr');
// Exit
await click(SELECTORS.overviewBreadcrumb);
await click(OVERVIEW_BREADCRUMB);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
actions = this.store.peekAll('pki/action');
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;
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.emptyStateLink);
await click(SELECTORS.configuration.optionByKey('generate-root'));
await fillIn(SELECTORS.configuration.typeField, 'internal');
await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-root-cert');
await click(SELECTORS.configuration.generateRootSave);
await click(`${GENERAL.emptyStateActions} a`);
await click(PKI_CONFIGURE_CREATE.optionByKey('generate-root'));
await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(GENERAL.inputByAttr('commonName'), 'my-root-cert');
await click(GENERAL.saveButton);
// Go to list view so we fetch all the 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;
assert.strictEqual(issuers.length, 1, 'Issuer exists on model in list');
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);
assert.false(issuer.hasDirtyAttributes, 'Model not dirty');
await fillIn('[data-test-input="issuerName"]', 'foobar');
assert.true(issuer.hasDirtyAttributes, 'Model is dirty');
await click(SELECTORS.overviewBreadcrumb);
await click(OVERVIEW_BREADCRUMB);
issuers = this.store.peekAll('pki/issuer');
assert.strictEqual(issuers.length, 1, 'Issuer exists on model in overview');
issuer = this.store.peekRecord('pki/issuer', issuerId);
@ -321,42 +330,42 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
await authPage.login();
// Configure PKI -- key creation not allowed unless configured
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.emptyStateLink);
await click(SELECTORS.configuration.optionByKey('generate-root'));
await fillIn(SELECTORS.configuration.typeField, 'internal');
await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-root-cert');
await click(SELECTORS.configuration.generateRootSave);
await click(`${GENERAL.emptyStateActions} a`);
await click(PKI_CONFIGURE_CREATE.optionByKey('generate-root'));
await fillIn(GENERAL.inputByAttr('type'), 'internal');
await fillIn(GENERAL.inputByAttr('commonName'), 'my-root-cert');
await click(GENERAL.saveButton);
await logout.visit();
});
test('create key exit', async function (assert) {
let keys, key;
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.keysTab);
await click(GENERAL.secretTab('Keys'));
keys = this.store.peekAll('pki/key');
const configKeyId = keys.at(0).id;
assert.strictEqual(keys.length, 1, 'One key exists from config');
// Create key
await click(SELECTORS.keyPages.generateKey);
await click(PKI_KEYS.generateKey);
keys = this.store.peekAll('pki/key');
key = keys.at(1);
assert.strictEqual(keys.length, 2, 'New key exists');
assert.true(key.isNew, 'Role is new model');
// Exit
await click(SELECTORS.keyForm.keyCancelButton);
await click(GENERAL.cancelButton);
keys = this.store.peekAll('pki/key');
assert.strictEqual(keys.length, 1, 'Second key is removed from store');
assert.strictEqual(keys.at(0).id, configKeyId);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`, 'url is correct');
// Create again
await click(SELECTORS.keyPages.generateKey);
await click(PKI_KEYS.generateKey);
assert.strictEqual(keys.length, 2, 'New key exists');
keys = this.store.peekAll('pki/key');
key = keys.at(1);
assert.true(key.isNew, 'Key is new model');
// Exit
await click(SELECTORS.overviewBreadcrumb);
await click(OVERVIEW_BREADCRUMB);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`, 'url is correct');
keys = this.store.peekAll('pki/key');
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;
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.keysTab);
await click(GENERAL.secretTab('Keys'));
keys = this.store.peekAll('pki/key');
assert.strictEqual(keys.length, 1, 'One key from config exists');
assert.dom('.list-item-row').exists({ count: 1 }, 'single row for key');
await click('.list-item-row');
// Edit
await click(SELECTORS.keyPages.keyEditLink);
await fillIn(SELECTORS.keyForm.keyNameInput, 'foobar');
await click(PKI_KEYS.keyEditLink);
await fillIn(GENERAL.inputByAttr('keyName'), 'foobar');
keys = this.store.peekAll('pki/key');
key = keys.at(0);
assert.true(key.hasDirtyAttributes, 'Key model is dirty');
// Exit
await click(SELECTORS.keyForm.keyCancelButton);
await click(GENERAL.cancelButton);
assert.strictEqual(
currentURL(),
`/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');
// Edit again
await click(SELECTORS.keyPages.keyEditLink);
await fillIn(SELECTORS.keyForm.keyNameInput, 'foobar');
await click(PKI_KEYS.keyEditLink);
await fillIn(GENERAL.inputByAttr('keyName'), 'foobar');
keys = this.store.peekAll('pki/key');
key = keys.at(0);
assert.true(key.hasDirtyAttributes, 'Key model is dirty');
// Exit via breadcrumb
await click(SELECTORS.overviewBreadcrumb);
await click(OVERVIEW_BREADCRUMB);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`, 'url is correct');
keys = this.store.peekAll('pki/key');
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 enablePage from 'vault/tests/pages/settings/mount-secret-backend';
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/policy-generator/pki';
import { clearRecords } from 'vault/tests/helpers/pki/pki-run-commands';
import { adminPolicy, readerPolicy, updatePolicy } from 'vault/tests/helpers/pki/policy-generator';
import { runCmd, tokenWithPolicyCmd } from 'vault/tests/helpers/commands';
import { unsupportedPem } from 'vault/tests/helpers/pki/values';
import { create } from 'ember-cli-page-object';
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 { unsupportedPem } = CERTIFICATES;
/**
* This test module should test the PKI workflow, including:
* - 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) => {
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/${resource}`);
assert
.dom(SELECTORS.emptyStateTitle)
.dom(GENERAL.emptyStateTitle)
.hasText(
'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
.dom(SELECTORS.emptyStateMessage)
.dom(GENERAL.emptyStateMessage)
.hasText(
`This PKI mount hasn't yet been configured with a certificate issuer.`,
`${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`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.rolesTab);
await click(GENERAL.secretTab('Roles'));
assertEmptyState(assert, 'roles');
await click(SELECTORS.issuersTab);
await click(GENERAL.secretTab('Issuers'));
assertEmptyState(assert, 'issuers');
await click(SELECTORS.certsTab);
await click(GENERAL.secretTab('Certificates'));
assertEmptyState(assert, 'certificates');
await click(SELECTORS.keysTab);
await click(GENERAL.secretTab('Keys'));
assertEmptyState(assert, 'keys');
await click(SELECTORS.tidyTab);
await click(GENERAL.secretTab('Tidy'));
assertEmptyState(assert, 'tidy');
});
});
@ -121,32 +130,32 @@ module('Acceptance | pki workflow', function (hooks) {
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesTab).exists('Roles tab is present');
await click(SELECTORS.rolesTab);
assert.dom(SELECTORS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered');
assert.dom(GENERAL.secretTab('Roles')).exists('Roles tab is present');
await click(GENERAL.secretTab('Roles'));
assert.dom(PKI_ROLE_DETAILS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered');
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`);
assert.dom('.linked-block').exists({ count: 1 }, 'One role is in list');
await click('.linked-block');
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/details`);
assert.dom(SELECTORS.generateCertLink).exists('Generate cert link is shown');
await click(SELECTORS.generateCertLink);
assert.dom(PKI_ROLE_DETAILS.generateCertLink).exists('Generate cert link is shown');
await click(PKI_ROLE_DETAILS.generateCertLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/generate`);
// Go back to details and test all the links
await visit(`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`);
assert.dom(SELECTORS.signCertLink).exists('Sign cert link is shown');
await click(SELECTORS.signCertLink);
assert.dom(PKI_ROLE_DETAILS.signCertLink).exists('Sign cert link is shown');
await click(PKI_ROLE_DETAILS.signCertLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/sign`);
await visit(`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`);
assert.dom(SELECTORS.editRoleLink).exists('Edit link is shown');
await click(SELECTORS.editRoleLink);
assert.dom(PKI_ROLE_DETAILS.editRoleLink).exists('Edit link is shown');
await click(PKI_ROLE_DETAILS.editRoleLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/some-role/edit`);
await visit(`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`);
assert.dom(SELECTORS.deleteRoleButton).exists('Delete role button is shown');
await click(SELECTORS.deleteRoleButton);
assert.dom(PKI_ROLE_DETAILS.deleteRoleButton).exists('Delete role button is shown');
await click(PKI_ROLE_DETAILS.deleteRoleButton);
await click('[data-test-confirm-button]');
assert.strictEqual(
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) {
await authPage.login(this.pkiRoleReader);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesTab).exists('Roles tab is present');
await click(SELECTORS.rolesTab);
assert.dom(SELECTORS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered');
assert.dom(GENERAL.secretTab('Roles')).exists('Roles tab is present');
await click(GENERAL.secretTab('Roles'));
assert.dom(PKI_ROLE_DETAILS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered');
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`);
assert.dom('.linked-block').exists({ count: 1 }, 'One role is in list');
await click('.linked-block');
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(SELECTORS.generateCertLink).doesNotExist('Generate cert link is not shown');
assert.dom(SELECTORS.signCertLink).doesNotExist('Sign cert link is not shown');
assert.dom(SELECTORS.editRoleLink).doesNotExist('Edit link is not shown');
assert.dom(PKI_ROLE_DETAILS.deleteRoleButton).doesNotExist('Delete role button is not shown');
assert.dom(PKI_ROLE_DETAILS.generateCertLink).doesNotExist('Generate cert link is not shown');
assert.dom(PKI_ROLE_DETAILS.signCertLink).doesNotExist('Sign cert 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) {
await authPage.login(this.pkiRoleEditor);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesTab).exists('Roles tab is present');
await click(SELECTORS.rolesTab);
assert.dom(SELECTORS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered');
assert.dom(GENERAL.secretTab('Roles')).exists('Roles tab is present');
await click(GENERAL.secretTab('Roles'));
assert.dom(PKI_ROLE_DETAILS.createRoleLink).exists({ count: 1 }, 'Create role link is rendered');
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`);
assert.dom('.linked-block').exists({ count: 1 }, 'One role is in list');
await click('.linked-block');
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(SELECTORS.generateCertLink).exists('Generate cert link is shown');
assert.dom(SELECTORS.signCertLink).exists('Sign cert link is shown');
assert.dom(SELECTORS.editRoleLink).exists('Edit link is shown');
await click(SELECTORS.editRoleLink);
assert.dom(PKI_ROLE_DETAILS.deleteRoleButton).doesNotExist('Delete role button is not shown');
assert.dom(PKI_ROLE_DETAILS.generateCertLink).exists('Generate cert link is shown');
assert.dom(PKI_ROLE_DETAILS.signCertLink).exists('Sign cert link is shown');
assert.dom(PKI_ROLE_DETAILS.editRoleLink).exists('Edit link is shown');
await click(PKI_ROLE_DETAILS.editRoleLink);
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/roles/some-role/edit`,
'Links to edit view'
);
await click(SELECTORS.roleForm.roleCancelButton);
await click(GENERAL.cancelButton);
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/roles/some-role/details`,
'Cancel from edit goes to details'
);
await click(SELECTORS.generateCertLink);
await click(PKI_ROLE_DETAILS.generateCertLink);
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/roles/some-role/generate`,
'Generate cert button goes to generate page'
);
await click(SELECTORS.generateCertForm.cancelButton);
await click(GENERAL.cancelButton);
assert.strictEqual(
currentURL(),
`/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 visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.emptyState).doesNotExist();
await click(SELECTORS.rolesTab);
assert.dom(GENERAL.emptyStateTitle).doesNotExist();
await click(GENERAL.secretTab('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.dom(SELECTORS.breadcrumbContainer).exists({ count: 1 }, 'breadcrumbs are rendered');
assert.dom(SELECTORS.breadcrumbs).exists({ count: 4 }, 'Shows 4 breadcrumbs');
assert.dom(SELECTORS.pageTitle).hasText('Create a PKI Role');
assert.dom(GENERAL.breadcrumbs).exists({ count: 1 }, 'breadcrumbs are rendered');
assert.dom(GENERAL.breadcrumb).exists({ count: 4 }, 'Shows 4 breadcrumbs');
assert.dom(GENERAL.title).hasText('Create a PKI Role');
await fillIn(SELECTORS.roleForm.roleName, roleName);
await click(SELECTORS.roleForm.roleCreateButton);
await fillIn(GENERAL.inputByAttr('name'), roleName);
await click(GENERAL.saveButton);
assert.strictEqual(
flash.latestMessage,
`Successfully created the role ${roleName}.`,
'renders success flash upon creation'
);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/${roleName}/details`);
assert.dom(SELECTORS.breadcrumbs).exists({ count: 4 }, 'Shows 4 breadcrumbs');
assert.dom(SELECTORS.pageTitle).hasText(`PKI Role ${roleName}`);
assert.dom(GENERAL.breadcrumb).exists({ count: 4 }, 'Shows 4 breadcrumbs');
assert.dom(GENERAL.title).hasText(`PKI Role ${roleName}`);
});
});
@ -257,61 +266,61 @@ module('Acceptance | pki workflow', function (hooks) {
await authPage.login(this.pkiAdminToken);
await visit(`/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
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`);
assert
.dom(SELECTORS.keyPages.importKey)
.dom(PKI_KEYS.importKey)
.hasAttribute(
'href',
`/ui/vault/secrets/${this.mountPath}/pki/keys/import`,
'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');
await click('.linked-block');
// details page
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
await click(SELECTORS.keyPages.keyEditLink);
await click(PKI_KEYS.keyEditLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/edit`);
await click(SELECTORS.keyForm.keyCancelButton);
await click(GENERAL.cancelButton);
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`,
'navigates back to details on cancel'
);
await visit(`/vault/secrets/${this.mountPath}/pki/keys/${keyId}/edit`);
await fillIn(SELECTORS.keyForm.keyNameInput, 'test-key');
await click(SELECTORS.keyForm.keyCreateButton);
await fillIn(GENERAL.inputByAttr('keyName'), 'test-key');
await click(GENERAL.saveButton);
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`,
'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
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`);
await fillIn(SELECTORS.keyForm.typeInput, 'exported');
await fillIn(SELECTORS.keyForm.keyTypeInput, 'rsa');
await click(SELECTORS.keyForm.keyCreateButton);
keyId = find(SELECTORS.keyPages.keyIdValue).innerText;
await fillIn(GENERAL.inputByAttr('type'), 'exported');
await fillIn(GENERAL.inputByAttr('keyType'), 'rsa');
await click(GENERAL.saveButton);
keyId = find(GENERAL.infoRowValue('Key ID')).textContent?.trim();
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`);
assert
.dom(SELECTORS.keyPages.nextStepsAlert)
.dom(PKI_KEYS.nextStepsAlert)
.hasText(
'Next steps This private key material will only be available once. Copy or download it now.',
'renders banner to save private key'
);
assert.dom(SELECTORS.keyPages.downloadButton).exists('renders download button');
await click(SELECTORS.keyPages.keyDeleteButton);
await click(SELECTORS.keyPages.confirmDelete);
assert.dom(PKI_KEYS.downloadButton).exists('renders download button');
await click(PKI_KEYS.keyDeleteButton);
await click(GENERAL.confirmButton);
assert.strictEqual(
currentURL(),
`/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) {
await authPage.login(this.pkiKeyReader);
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`);
await isSettled();
assert.dom(SELECTORS.keyPages.importKey).doesNotExist();
assert.dom(SELECTORS.keyPages.generateKey).doesNotExist();
assert.dom(PKI_KEYS.importKey).doesNotExist();
assert.dom(PKI_KEYS.generateKey).doesNotExist();
assert.dom('.linked-block').exists({ count: 1 }, 'One key is in list');
const keyId = find(SELECTORS.keyPages.keyId).innerText;
await click(SELECTORS.keyPages.popupMenuTrigger);
assert.dom(SELECTORS.keyPages.popupMenuEdit).doesNotExist('popup menu edit link is not shown');
await click(SELECTORS.keyPages.popupMenuDetails);
const keyId = find(PKI_KEYS.keyId).innerText;
await click(GENERAL.menuTrigger);
assert.dom(PKI_KEYS.popupMenuEdit).doesNotExist('popup menu edit link is not shown');
await click(PKI_KEYS.popupMenuDetails);
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(SELECTORS.keyPages.keyEditLink).doesNotExist('Edit key button does not render');
assert.dom(PKI_KEYS.keyDeleteButton).doesNotExist('Delete key button is not shown');
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) {
await authPage.login(this.pkiKeyEditor);
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`);
await isSettled();
assert.dom(SELECTORS.keyPages.importKey).exists('import action exists');
assert.dom(SELECTORS.keyPages.generateKey).exists('generate action exists');
assert.dom(PKI_KEYS.importKey).exists('import action exists');
assert.dom(PKI_KEYS.generateKey).exists('generate action exists');
assert.dom('.linked-block').exists({ count: 1 }, 'One key is in list');
const keyId = find(SELECTORS.keyPages.keyId).innerText;
await click(SELECTORS.keyPages.popupMenuTrigger);
assert
.dom(SELECTORS.keyPages.popupMenuEdit)
.doesNotHaveClass('disabled', 'popup menu edit link is not disabled');
const keyId = find(PKI_KEYS.keyId).innerText;
await click(GENERAL.menuTrigger);
assert.dom(PKI_KEYS.popupMenuEdit).doesNotHaveClass('disabled', 'popup menu edit link is not disabled');
await click('.linked-block');
assert.dom(SELECTORS.keyPages.keyDeleteButton).doesNotExist('Delete key button is not shown');
await click(SELECTORS.keyPages.keyEditLink);
assert.dom(PKI_KEYS.keyDeleteButton).doesNotExist('Delete key button is not shown');
await click(PKI_KEYS.keyEditLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/edit`);
assert.dom(SELECTORS.keyPages.title).hasText('Edit Key');
await click(SELECTORS.keyForm.keyCancelButton);
assert.dom(GENERAL.title).hasText('Edit Key');
await click(GENERAL.cancelButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`);
});
});
@ -374,25 +381,23 @@ module('Acceptance | pki workflow', function (hooks) {
clearRecords(this.store);
});
test('lists the correct issuer metadata info', async function (assert) {
assert.expect(6);
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.issuersTab).exists('Issuers tab is present');
await click(SELECTORS.issuersTab);
assert.dom(GENERAL.secretTab('Issuers')).exists();
await click(GENERAL.secretTab('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-serial-number="0"]').exists({ count: 1 }, 'displays serial number tag');
assert.dom('[data-test-common-name="0"]').exists({ count: 1 }, 'displays cert common name tag');
assert.dom('[data-test-serial-number="0"]').exists({ count: 1 });
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) {
assert.expect(2);
await authPage.login();
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab);
await click(SELECTORS.issuerPopupMenu);
await click(SELECTORS.issuerPopupDetails);
const issuerId = find(SELECTORS.issuerDetails.valueByName('Issuer ID')).innerText;
await click(GENERAL.secretTab('Issuers'));
await click(GENERAL.menuTrigger);
await click(PKI_ISSUER_LIST.issuerPopupDetails);
const issuerId = find(PKI_ISSUER_DETAILS.valueByName('Issuer ID')).innerText;
const pki_issuer_denied_policy = `
path "${this.mountPath}/*" {
capabilities = ["create", "read", "update", "delete", "list"]
@ -407,7 +412,7 @@ module('Acceptance | pki workflow', function (hooks) {
await logout.visit();
await authPage.login(this.token);
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-common-name="0"]').doesNotExist('does not display cert common name tag');
});
@ -416,8 +421,8 @@ module('Acceptance | pki workflow', function (hooks) {
assert.expect(13);
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.issuersTab).exists('Issuers tab is present');
await click(SELECTORS.issuersTab);
assert.dom(GENERAL.secretTab('Issuers')).exists('Issuers tab is present');
await click(GENERAL.secretTab('Issuers'));
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`);
assert.dom('.linked-block').exists({ count: 1 }, 'One issuer is in list');
await click('.linked-block');
@ -425,45 +430,45 @@ module('Acceptance | pki workflow', function (hooks) {
currentURL().match(`/vault/secrets/${this.mountPath}/pki/issuers/.+/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(
(label) => {
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`);
}
);
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');
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) {
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issuersTab);
await click(SELECTORS.issuerPopupMenu);
await click(SELECTORS.issuerPopupDetails);
await click(GENERAL.secretTab('Issuers'));
await click(GENERAL.menuTrigger);
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(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/details`,
'it navigates to details route'
);
assert
.dom(SELECTORS.issuerDetails.crossSign)
.dom(PKI_ISSUER_DETAILS.crossSign)
.hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/cross-sign`);
assert
.dom(SELECTORS.issuerDetails.signIntermediate)
.dom(PKI_ISSUER_DETAILS.signIntermediate)
.hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/sign`);
assert
.dom(SELECTORS.issuerDetails.configure)
.dom(PKI_ISSUER_DETAILS.configure)
.hasAttribute('href', `/ui/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/edit`);
await click(SELECTORS.issuerDetails.rotateRoot);
assert.dom(SELECTORS.issuerDetails.rotateModal).exists('rotate root modal opens');
await click(SELECTORS.issuerDetails.rotateModalGenerate);
await click(PKI_ISSUER_DETAILS.rotateRoot);
assert.dom(PKI_ISSUER_DETAILS.rotateModal).exists('rotate root modal opens');
await click(PKI_ISSUER_DETAILS.rotateModalGenerate);
assert.strictEqual(
currentURL(),
`/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) {
await authPage.login();
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 fillIn('[data-test-text-file-textarea]', unsupportedPem);
await click(SELECTORS.configuration.importSubmit);
const issuerId = find(SELECTORS.configuration.importedIssuer).innerText;
await click(`${SELECTORS.configuration.importedIssuer} a`);
await click(PKI_CONFIGURE_CREATE.importSubmit);
const issuerId = find(PKI_CONFIGURE_CREATE.importedIssuer).innerText;
await click(`${PKI_CONFIGURE_CREATE.importedIssuer} a`);
// 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
@ -502,7 +507,7 @@ module('Acceptance | pki workflow', function (hooks) {
);
assert.dom('[data-test-input="commonName"]').hasValue('fancy-cert-unsupported-subj-and-ext-oids');
await fillIn('[data-test-input="issuerName"]', 'existing-issuer');
await click('[data-test-pki-rotate-root-save]');
await click(GENERAL.saveButton);
assert
.dom('[data-test-rotate-error]')
.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 visit(`/vault/secrets/${this.mountPath}/pki/configuration/edit`);
assert
.dom(`${SELECTORS.configEdit.configEditSection} [data-test-component="empty-state"]`)
.dom(`${PKI_CONFIG_EDIT.configEditSection} [data-test-component="empty-state"]`)
.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`
);
assert.dom(SELECTORS.configEdit.acmeEditSection).exists();
assert.dom(SELECTORS.configEdit.urlsEditSection).exists();
assert.dom(SELECTORS.configEdit.crlEditSection).exists();
assert.dom(`${SELECTORS.acmeEditSection} [data-test-component="empty-state"]`).doesNotExist();
assert.dom(`${SELECTORS.urlsEditSection} [data-test-component="empty-state"]`).doesNotExist();
assert.dom(`${SELECTORS.crlEditSection} [data-test-component="empty-state"]`).doesNotExist();
await click(SELECTORS.configEdit.crlToggleInput('expiry'));
await click(SELECTORS.configEdit.saveButton);
assert.dom(PKI_CONFIG_EDIT.acmeEditSection).exists();
assert.dom(PKI_CONFIG_EDIT.urlsEditSection).exists();
assert.dom(PKI_CONFIG_EDIT.crlEditSection).exists();
assert.dom(`${PKI_CONFIG_EDIT.acmeEditSection} [data-test-component="empty-state"]`).doesNotExist();
assert.dom(`${PKI_CONFIG_EDIT.urlsEditSection} [data-test-component="empty-state"]`).doesNotExist();
assert.dom(`${PKI_CONFIG_EDIT.crlEditSection} [data-test-component="empty-state"]`).doesNotExist();
await click(PKI_CONFIG_EDIT.crlToggleInput('expiry'));
await click(PKI_CONFIG_EDIT.saveButton);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration`);
assert
.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 enablePage from 'vault/tests/pages/settings/mount-secret-backend';
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 { clearRecords } from 'vault/tests/helpers/pki/pki-helpers';
import { PKI_OVERVIEW } from 'vault/tests/helpers/pki/pki-selectors';
module('Acceptance | pki overview', function (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) {
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.issuersCardTitle).hasText('Issuers');
assert.dom(SELECTORS.issuersCardOverviewNum).hasText('1');
await click(SELECTORS.issuersCardLink);
assert.dom(PKI_OVERVIEW.issuersCardTitle).hasText('Issuers');
assert.dom(PKI_OVERVIEW.issuersCardOverviewNum).hasText('1');
await click(PKI_OVERVIEW.issuersCardLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`);
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) {
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesCardTitle).hasText('Roles');
assert.dom(SELECTORS.rolesCardOverviewNum).hasText('0');
await click(SELECTORS.rolesCardLink);
assert.dom(PKI_OVERVIEW.rolesCardTitle).hasText('Roles');
assert.dom(PKI_OVERVIEW.rolesCardOverviewNum).hasText('0');
await click(PKI_OVERVIEW.rolesCardLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles`);
await runCmd([
`write ${this.mountPath}/roles/some-role \
@ -81,14 +81,14 @@ module('Acceptance | pki overview', function (hooks) {
max_ttl="720h"`,
]);
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) {
await authPage.login(this.pkiIssuersList);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
assert.dom(SELECTORS.rolesCardTitle).doesNotExist('Roles card does not exist');
assert.dom(SELECTORS.issuersCardTitle).exists('Issuers card exists');
assert.dom(PKI_OVERVIEW.rolesCardTitle).doesNotExist('Roles card does not exist');
assert.dom(PKI_OVERVIEW.issuersCardTitle).exists('Issuers card exists');
});
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"`,
]);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.issueCertificatePowerSearch);
await click(SELECTORS.firstPowerSelectOption);
await click(SELECTORS.issueCertificateButton);
await click(PKI_OVERVIEW.issueCertificatePowerSearch);
await click(PKI_OVERVIEW.firstPowerSelectOption);
await click(PKI_OVERVIEW.issueCertificateButton);
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.roles.role.generate');
});
test('navigates to certificate details page for View Certificates card', async function (assert) {
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.viewCertificatePowerSearch);
await click(SELECTORS.firstPowerSelectOption);
await click(SELECTORS.viewCertificateButton);
await click(PKI_OVERVIEW.viewCertificatePowerSearch);
await click(PKI_OVERVIEW.firstPowerSelectOption);
await click(PKI_OVERVIEW.viewCertificateButton);
assert.strictEqual(
currentRouteName(),
'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) {
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
await click(SELECTORS.viewIssuerPowerSearch);
await click(SELECTORS.firstPowerSelectOption);
await click(SELECTORS.viewIssuerButton);
await click(PKI_OVERVIEW.viewIssuerPowerSearch);
await click(PKI_OVERVIEW.firstPowerSelectOption);
await click(PKI_OVERVIEW.viewIssuerButton);
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 enablePage from 'vault/tests/pages/settings/mount-secret-backend';
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) {
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) {
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
await click(SELECTORS.tidyEmptyStateConfigure);
assert.dom(SELECTORS.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
assert.dom(SELECTORS.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists');
await click(PKI_TIDY.tidyEmptyStateConfigure);
assert.dom(PKI_TIDY.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
assert.dom(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists');
assert
.dom(SELECTORS.tidyConfigureModal.tidyModalManualButton)
.dom(PKI_TIDY.tidyConfigureModal.tidyModalManualButton)
.exists('Configure manual tidy button exists');
await click(SELECTORS.tidyConfigureModal.tidyModalManualButton);
assert.dom(SELECTORS.tidyForm.tidyFormName('manual')).exists('Manual tidy form exists');
await click(SELECTORS.tidyForm.inputByAttr('tidyCertStore'));
await fillIn(SELECTORS.tidyForm.tidyPauseDuration, '10');
await click(SELECTORS.tidyForm.tidySave);
await click(SELECTORS.cancelTidyAction);
assert.dom(SELECTORS.cancelTidyModalBackground).exists('Confirm cancel tidy modal exits');
await click(SELECTORS.tidyConfigureModal.tidyModalCancelButton);
await click(PKI_TIDY.tidyConfigureModal.tidyModalManualButton);
assert.dom(PKI_TIDY_FORM.tidyFormName('manual')).exists('Manual tidy form exists');
await click(PKI_TIDY_FORM.inputByAttr('tidyCertStore'));
await fillIn(PKI_TIDY_FORM.tidyPauseDuration, '10');
await click(PKI_TIDY_FORM.tidySave);
await click(PKI_TIDY.cancelTidyAction);
assert.dom(PKI_TIDY.cancelTidyModalBackground).exists('Confirm cancel tidy modal exits');
await click(PKI_TIDY.tidyConfigureModal.tidyModalCancelButton);
// we can't properly test the background refresh fetching of tidy status in testing
this.server.get(`${this.mountPath}/tidy-status`, () => {
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/tidy`);
assert.dom(SELECTORS.hdsAlertTitle).hasText('Tidy operation cancelled');
assert.dom(PKI_TIDY.hdsAlertTitle).hasText('Tidy operation cancelled');
assert
.dom(SELECTORS.hdsAlertDescription)
.dom(PKI_TIDY.hdsAlertDescription)
.hasText(
'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) {
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
await click(SELECTORS.tidyEmptyStateConfigure);
assert.dom(SELECTORS.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
assert.dom(SELECTORS.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists');
await click(PKI_TIDY.tidyEmptyStateConfigure);
assert.dom(PKI_TIDY.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
assert.dom(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists');
assert
.dom(SELECTORS.tidyConfigureModal.tidyModalManualButton)
.dom(PKI_TIDY.tidyConfigureModal.tidyModalManualButton)
.exists('Configure manual tidy button exists');
await click(SELECTORS.tidyConfigureModal.tidyModalAutoButton);
assert.dom(SELECTORS.tidyForm.tidyFormName('auto')).exists('Auto tidy form exists');
await click(SELECTORS.tidyForm.tidyCancel);
await click(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton);
assert.dom(PKI_TIDY_FORM.tidyFormName('auto')).exists('Auto tidy form exists');
await click(PKI_TIDY_FORM.tidyCancel);
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backend.pki.tidy.index');
await click(SELECTORS.tidyEmptyStateConfigure);
await click(SELECTORS.tidyConfigureModal.tidyModalAutoButton);
assert.dom(SELECTORS.tidyForm.tidyFormName('auto')).exists('Auto tidy form exists');
await click(SELECTORS.tidyForm.toggleLabel('Automatic tidy disabled'));
await click(PKI_TIDY.tidyEmptyStateConfigure);
await click(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton);
assert.dom(PKI_TIDY_FORM.tidyFormName('auto')).exists('Auto tidy form exists');
await click(PKI_TIDY_FORM.toggleLabel('Automatic tidy disabled'));
assert
.dom(SELECTORS.tidyForm.tidySectionHeader('ACME operations'))
.dom(PKI_TIDY_FORM.tidySectionHeader('ACME operations'))
.exists('Auto tidy form enabled shows ACME operations field');
await click(SELECTORS.tidyForm.inputByAttr('tidyCertStore'));
await click(SELECTORS.tidyForm.tidySave);
await click(PKI_TIDY_FORM.inputByAttr('tidyCertStore'));
await click(PKI_TIDY_FORM.tidySave);
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');
await click(SELECTORS.tidyForm.inputByAttr('tidyRevokedCerts'));
await click(SELECTORS.tidyForm.tidySave);
await click(PKI_TIDY_FORM.inputByAttr('tidyRevokedCerts'));
await click(PKI_TIDY_FORM.tidySave);
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) {
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
await click(SELECTORS.tidyConfigureModal.tidyOptionsModal);
assert.dom(SELECTORS.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
assert.dom(SELECTORS.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists');
await click(PKI_TIDY.tidyConfigureModal.tidyOptionsModal);
assert.dom(PKI_TIDY.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
assert.dom(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton).exists('Configure auto tidy button exists');
assert
.dom(SELECTORS.tidyConfigureModal.tidyModalManualButton)
.dom(PKI_TIDY.tidyConfigureModal.tidyModalManualButton)
.exists('Configure manual tidy button exists');
await click(SELECTORS.tidyConfigureModal.tidyModalCancelButton);
assert.dom(SELECTORS.tidyEmptyState).exists();
await click(PKI_TIDY.tidyConfigureModal.tidyModalCancelButton);
assert.dom(GENERAL.emptyStateTitle).exists();
});
test('it should show correct toolbar action depending on whether auto tidy is enabled', async function (assert) {
await authPage.login(this.pkiAdminToken);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
assert
.dom(SELECTORS.tidyConfigureModal.tidyOptionsModal)
.dom(PKI_TIDY.tidyConfigureModal.tidyOptionsModal)
.exists('Configure tidy modal options button exists');
await click(SELECTORS.tidyConfigureModal.tidyOptionsModal);
assert.dom(SELECTORS.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
await click(SELECTORS.tidyConfigureModal.tidyModalAutoButton);
await click(SELECTORS.tidyForm.toggleLabel('Automatic tidy disabled'));
await click(SELECTORS.tidyForm.inputByAttr('tidyCertStore'));
await click(SELECTORS.tidyForm.inputByAttr('tidyRevokedCerts'));
await click(SELECTORS.tidyForm.tidySave);
await click(PKI_TIDY.tidyConfigureModal.tidyOptionsModal);
assert.dom(PKI_TIDY.tidyConfigureModal.configureTidyModal).exists('Configure tidy modal exists');
await click(PKI_TIDY.tidyConfigureModal.tidyModalAutoButton);
await click(PKI_TIDY_FORM.toggleLabel('Automatic tidy disabled'));
await click(PKI_TIDY_FORM.inputByAttr('tidyCertStore'));
await click(PKI_TIDY_FORM.inputByAttr('tidyRevokedCerts'));
await click(PKI_TIDY_FORM.tidySave);
await visit(`/vault/secrets/${this.mountPath}/pki/tidy`);
assert
.dom(SELECTORS.manualTidyToolbar)
.dom(PKI_TIDY.manualTidyToolbar)
.exists('Manual tidy toolbar action exists if auto tidy is configured');
assert
.dom(SELECTORS.autoTidyToolbar)
.exists('Auto tidy toolbar action exists if auto tidy is configured');
assert.dom(PKI_TIDY.autoTidyToolbar).exists('Auto tidy toolbar action exists if auto tidy is configured');
});
});

View File

@ -10,7 +10,6 @@ import {
fillIn,
visit,
click,
find,
waitFor,
waitUntil,
} from '@ember/test-helpers';
@ -20,6 +19,7 @@ import { v4 as uuidv4 } from 'uuid';
import authPage from 'vault/tests/pages/auth';
import { runCmd } from 'vault/tests/helpers/commands';
import codemirror from 'vault/tests/helpers/codemirror';
const SELECT = {
policyByName: (name) => `[data-test-policy-link="${name}"]`,
@ -86,7 +86,7 @@ module('Acceptance | policies/acl', function (hooks) {
await click(SELECT.createLink);
await fillIn(SELECT.nameInput, policyName);
find('.CodeMirror').CodeMirror.setValue(policyString);
codemirror().setValue(policyString);
await click(SELECT.save);
assert.strictEqual(
currentURL(),
@ -110,7 +110,7 @@ module('Acceptance | policies/acl', function (hooks) {
assert
.dom(SELECT.createError)
.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 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 VAULT_KEYS from 'vault/tests/helpers/vault-keys';
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 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 listPage from 'vault/tests/pages/secrets/backend/list';
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) {
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 { create } from 'ember-cli-page-object';
import apiStub from 'vault/tests/helpers/noop-all-api-requests';
import { deleteEngineCmd, runCmd } from 'vault/tests/helpers/commands';
const cli = create(consolePanel);
@ -27,14 +26,9 @@ module('Acceptance | secrets/generic/create', function (hooks) {
hooks.beforeEach(function () {
this.uid = uuidv4();
this.server = apiStub({ usePassthrough: true });
return authPage.login();
});
hooks.afterEach(function () {
this.server.shutdown();
});
test('it creates and can view a secret with the generic backend', async function (assert) {
const path = `generic-${this.uid}`;
const kvPath = `generic-kv-${this.uid}`;
@ -55,6 +49,10 @@ module('Acceptance | secrets/generic/create', function (hooks) {
'redirects to the show page'
);
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) {
@ -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()).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 { visit, click, currentRouteName } from '@ember/test-helpers';
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) {
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) {
assert.expect(1);
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');
});
@ -42,7 +43,7 @@ module('Acceptance | kubernetes | overview', function (hooks) {
assert.expect(1);
this.createScenario();
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');
});
@ -50,7 +51,7 @@ module('Acceptance | kubernetes | overview', function (hooks) {
assert.expect(1);
this.createScenario(false);
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');
});
@ -59,7 +60,7 @@ module('Acceptance | kubernetes | overview', function (hooks) {
await this.createScenario();
await this.visitOverview();
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');
});
});

View File

@ -10,7 +10,7 @@ import { click, currentURL, fillIn, typeIn, visit } from '@ember/test-helpers';
import { setupApplicationTest } from 'vault/tests/helpers';
import authPage from 'vault/tests/pages/auth';
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 { FORM, PAGE } from 'vault/tests/helpers/kv/kv-selectors';
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 authPage from 'vault/tests/pages/auth';
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,
deleteLatestCmd,

View File

@ -21,7 +21,7 @@ import {
destroyVersionsPolicy,
metadataListPolicy,
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 { FORM, PAGE } from 'vault/tests/helpers/kv/kv-selectors';
import codemirror from 'vault/tests/helpers/codemirror';

View File

@ -16,7 +16,7 @@ import {
createTokenCmd,
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 {
addSecretMetadataCmd,
clearRecords,

View File

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

View File

@ -10,7 +10,7 @@ import ldapMirageScenario from 'vault/mirage/scenarios/ldap';
import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth';
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) {
setupApplicationTest(hooks);

View File

@ -11,7 +11,7 @@ import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth';
import { click, fillIn, visit } from '@ember/test-helpers';
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) {
setupApplicationTest(hooks);

View File

@ -10,7 +10,7 @@ import ldapMirageScenario from 'vault/mirage/scenarios/ldap';
import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth';
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) {
setupApplicationTest(hooks);

View File

@ -5,6 +5,7 @@
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { create } from 'ember-cli-page-object';
import { fillIn } from '@ember/test-helpers';
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 page from 'vault/tests/pages/settings/auth/configure/section';
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 authPage from 'vault/tests/pages/auth';
@ -20,18 +20,24 @@ const cli = create(consolePanel);
module('Acceptance | settings/auth/configure/section', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(function () {
this.uid = uuidv4();
this.server = apiStub({ usePassthrough: true });
return authPage.login();
});
hooks.afterEach(function () {
this.server.shutdown();
});
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 type = 'approle';
const section = 'options';
@ -48,16 +54,6 @@ module('Acceptance | settings/auth/configure/section', function (hooks) {
`The configuration was saved successfully.`,
'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']) {

View File

@ -3,13 +3,24 @@
* 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 { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { toolsActions } from 'vault/helpers/tools-actions';
import authPage from 'vault/tests/pages/auth';
import { capitalize } from '@ember/string';
import codemirror from 'vault/tests/helpers/codemirror';
module('Acceptance | tools', function (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`);
});
const { CodeMirror } = await waitUntil(() => find('.CodeMirror'));
CodeMirror.setValue(DATA_TO_WRAP);
await waitFor('.CodeMirror');
codemirror().setValue(DATA_TO_WRAP);
// wrap
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 click('[data-test-tools-submit]');
await waitFor('.CodeMirror');
assert.deepEqual(
JSON.parse(CodeMirror.getValue()),
JSON.parse(codemirror().getValue()),
JSON.parse(DATA_TO_WRAP),
'unwrapped data equals input data'
);
const buttonDetails = await waitUntil(() => find('[data-test-button-details]'));
await click(buttonDetails);
await waitUntil(() => find('[data-test-button-details]'));
await click('[data-test-button-details]');
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
await click('[data-test-sidebar-nav-link="Random"]');
@ -160,7 +175,7 @@ module('Acceptance | tools', function (hooks) {
await click('[data-test-tools-submit]');
assert.deepEqual(
JSON.parse(findAll('.CodeMirror')[0].CodeMirror.getValue()),
JSON.parse(codemirror().getValue()),
AUTH_RESPONSE.auth,
'unwrapped data equals input data'
);

View File

@ -11,6 +11,7 @@ import { v4 as uuidv4 } from 'uuid';
import { encodeString } from 'vault/utils/b64';
import authPage from 'vault/tests/pages/auth';
import { deleteEngineCmd, mountEngineCmd, runCmd } from 'vault/tests/helpers/commands';
import codemirror from 'vault/tests/helpers/codemirror';
const SELECTORS = {
secretLink: '[data-test-secret-link]',
@ -150,7 +151,7 @@ const testConvergentEncryption = async function (assert, keyName) {
for (const testCase of tests) {
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);
if (!testCase.encodePlaintext) {
@ -160,7 +161,7 @@ const testConvergentEncryption = async function (assert, keyName) {
if (testCase.encodeContext) {
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]');
if (testCase.assertAfterEncrypt) {
@ -171,14 +172,15 @@ const testConvergentEncryption = async function (assert, keyName) {
const copiedCiphertext = find('[data-test-encrypted-value="ciphertext"]').innerText;
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"]');
if (testCase.assertBeforeDecrypt) {
await settled();
testCase.assertBeforeDecrypt(keyName);
}
find('#ciphertext-control .CodeMirror').CodeMirror.setValue(copiedCiphertext);
codemirror('#ciphertext-control').setValue(copiedCiphertext);
await click('[data-test-button-decrypt]');
if (testCase.assertAfterDecrypt) {
@ -188,7 +190,7 @@ const testConvergentEncryption = async function (assert, keyName) {
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 authPage from 'vault/tests/pages/auth';
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;

View File

@ -3,131 +3,14 @@
* 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 { LICENSE_START } from 'vault/mirage/handlers/clients';
import { addMonths } from 'date-fns';
/** 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));
}
import { CLIENT_COUNT } from './client-count-selectors';
export async function dateDropdownSelect(month, year) {
const { dateDropdown, counts } = SELECTORS;
const { dateDropdown, counts } = CLIENT_COUNT;
await click(counts.startEdit);
await click(dateDropdown.toggleMonth);
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
If you are targeting a specific CodeMirror instance, pass the selector of the parent element as an argument.
sample use:
import codemirror from 'vault/tests/helpers/codemirror';
test('it renders initial value', function (assert) {
assert.strictEqual(codemirror.getValue(), 'some value')
// General use
assert.strictEqual(codemirror().getValue(), 'some other value')
// Specific selector
codemirror('#my-control').setValue('some value');
assert.strictEqual(codemirror('#my-control').getValue(), 'some value')
)}
*/
const invariant = (truthy, error) => {
if (!truthy) throw new Error(error);
};
export default function () {
const element = document.querySelector('.CodeMirror');
export default function (parent) {
const selector = parent ? `${parent} .CodeMirror` : '.CodeMirror';
const element = document.querySelector(selector);
invariant(element, `Selector '.CodeMirror' matched no elements`);
const cm = element.CodeMirror;
@ -28,3 +28,7 @@ export default function () {
return cm;
}
const invariant = (truthy, error) => {
if (!truthy) throw new Error(error);
};

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: BUSL-1.1
*/
export const SELECTORS = {
export const DASHBOARD = {
cardName: (name) => `[data-test-card="${name}"]`,
emptyState: (name) => `[data-test-empty-state="${name}"]`,
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]',
wrapButton: '[data-test-wrap-button]',
};
export default async function assertSecretWrap(assert, server, path) {
export async function assertSecretWrap(assert, server, path) {
server.get(path, () => {
assert.ok(true, `request made to ${path} when wrapping secret`);
});

View File

@ -6,6 +6,14 @@
import { allFeatures } from 'vault/helpers/all-features';
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) => {
const permissions = owner.lookup('service:permissions');
const hasNavPermission = sinon.stub(permissions, 'hasNavPermission');

View File

@ -3,17 +3,15 @@
* SPDX-License-Identifier: BUSL-1.1
*/
const selectors = {
export const TTL_PICKER = {
ttlFormGroup: '[data-test-ttl-inputs]',
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]',
subtext: '[data-test-ttl-form-subtext]',
tooltipTrigger: `[data-test-tooltip-trigger]`,
ttlValue: '[data-test-ttl-value]',
ttlUnit: '[data-test-select="ttl-unit"]',
valueInputByLabel: (label) => `[data-test-ttl-value="${label}"]`,
unitInputByLabel: (label) => `[data-test-ttl-unit="${label}"] [data-test-select="ttl-unit"]`,
valueInputByLabel: (label: string) => `[data-test-ttl-value="${label}"]`,
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
*/
export const SELECTORS = {
export const KUBERNETES_OVERVIEW = {
// Page::Overview in the kubernetes engine
rolesCardTitle: '[data-test-overview-card-title="Roles"]',
rolesCardSubTitle: '[data-test-overview-card-subtitle="Roles"]',
rolesCardLink: '[data-test-overview-card="Roles"] a',
@ -11,7 +12,4 @@ export const SELECTORS = {
generateCredentialsCardTitle: '[data-test-overview-card-title="Generate credentials"]',
generateCredentialsCardSubTitle: '[data-test-overview-card-subtitle="Generate credentials"]',
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
*/
import { Response } from 'miragejs';
import { debug } from '@ember/debug';
export const OIDC_BASE_URL = `/vault/access/oidc`;
@ -57,49 +57,6 @@ export const SELECTORS = {
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) {
await store
.findRecord(modelType, id)
@ -107,6 +64,7 @@ export async function clearRecord(store, modelType, id) {
deleteModelRecord(model);
})
.catch(() => {
debug(`Clearing record failed for ${modelType} with id: ${id}`);
// swallow error
});
}

View File

@ -3,6 +3,10 @@
* 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 = {
user: {
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