mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-31 11:31:07 +02:00
* add secrets sync feature to version service * fix syntax for feature in version service * UI [Sidebranch]: correctly call activation flags endpoints (#26068) * Show empty state on client count sync page if feature isn't activated (#26024) * page/sync: show empty state if sync is not activated * tests: add sync page integration tests * tests: add secrets sync acceptance tests * cleanup: remove redundant empty state selector * chore: rename to isSecretsSyncActivated * Only make POST request to activation-flags in root namespace (#26081) * Clean up around opt-in banner on non-secrets-sync views (#26039) * only show and make request to activated-features if enterprise with secrets sync feature * waiting for final badge title but hiding banner and network request based on if user has secrets-sync feature. * final copy for badge * handle dismiss erorr message, custom messaging in errors, different badge names and upsell if not on license. * add secrets sync feature to version service * nope, add to main sidebranch not in this PR * use version service directly to check for secrets sync feature * update badges to use version service directly * do not unnecessarily pass hasSecretsSyncFeature, access from version directly * last spot to update using the feature getter * cleanup landing cta logic * UI [Sidebranch]: correctly call activation flags endpoints (#26068) * small cleanups after merge * remove unused type imports * update tests * update nav link test * add test waiter for race condition on test * add waiter to fetch activation-flags * remove customer waiters and go for waitFors in test * worth a try? mirage issues? * closer? * fix issue with inconsistent asserts * adding back in in case this is the issue * revert cluster.hbs change * skip test * delete test --------- Co-authored-by: clairebontempo@gmail.com <clairebontempo@gmail.com> Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com> * Hide sync for managed vault (#26084) * [secrets sync] hide sync content from client overview (#26078) * clients/overview: hide secrets sync content if not in license * clients: remove sync tab if not in license * routes: fetch isSecretsSyncActivated at clients/counts route level * wip - hide secrets sync from overview page * tests: fix usage-stats test * more wip hiding from overview page * hide secrets sync on attribution component/modal * hide secrets sync content on running total component * fix RunningTotal class name Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> * controllers: fix type * tests: usage tests * tests: running totals tests * add s to secrets-sync * tests: running-total test cleanup --------- Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> Co-authored-by: clairebontempo@gmail.com <clairebontempo@gmail.com> * cleanup unused version service * return extra line * wip - sync tests * wip -- clients overview acceptance tests * test coverage for sync in license, activated * tests: add more robust sync-related overview tests * hide sync client charts if feature not in license --------- Co-authored-by: clairebontempo@gmail.com <clairebontempo@gmail.com> Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com> Co-authored-by: Noelle Daley <noelledaley@users.noreply.github.com> Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> Co-authored-by: Chelsea Shaw <cshaw@hashicorp.com>
188 lines
7.5 KiB
JavaScript
188 lines
7.5 KiB
JavaScript
/**
|
|
* Copyright (c) HashiCorp, Inc.
|
|
* SPDX-License-Identifier: BUSL-1.1
|
|
*/
|
|
|
|
/* eslint-disable ember/no-settled-after-test-helper */
|
|
import { module, test } from 'qunit';
|
|
import { setupRenderingTest } from 'ember-qunit';
|
|
import { setupEngine } from 'ember-engines/test-support';
|
|
import { setupMirage } from 'ember-cli-mirage/test-support';
|
|
import { render, click, settled } from '@ember/test-helpers';
|
|
import hbs from 'htmlbars-inline-precompile';
|
|
import syncScenario from 'vault/mirage/scenarios/sync';
|
|
import syncHandlers from 'vault/mirage/handlers/sync';
|
|
import { PAGE } from 'vault/tests/helpers/sync/sync-selectors';
|
|
import { Response } from 'miragejs';
|
|
import { dateFormat } from 'core/helpers/date-format';
|
|
|
|
const {
|
|
title,
|
|
breadcrumb,
|
|
tab,
|
|
overviewCard,
|
|
cta,
|
|
overview,
|
|
pagination,
|
|
emptyStateTitle,
|
|
emptyStateMessage,
|
|
} = PAGE;
|
|
|
|
module('Integration | Component | sync | Page::Overview', function (hooks) {
|
|
setupRenderingTest(hooks);
|
|
setupEngine(hooks, 'sync');
|
|
setupMirage(hooks);
|
|
|
|
hooks.beforeEach(async function () {
|
|
this.version = this.owner.lookup('service:version');
|
|
this.version.type = 'enterprise';
|
|
this.version.features = ['Secrets Sync'];
|
|
syncScenario(this.server);
|
|
syncHandlers(this.server);
|
|
|
|
const store = this.owner.lookup('service:store');
|
|
this.destinations = await store.query('sync/destination', {});
|
|
this.activatedFeatures = ['secrets-sync'];
|
|
|
|
this.renderComponent = () =>
|
|
render(
|
|
hbs`<Secrets::Page::Overview @destinations={{this.destinations}} @totalVaultSecrets={{7}} @activatedFeatures={{this.activatedFeatures}} @adapterError={{null}} />`,
|
|
{
|
|
owner: this.engine,
|
|
}
|
|
);
|
|
});
|
|
|
|
test('it should render landing cta component for enterprise with the secrets sync feature', async function (assert) {
|
|
this.destinations = [];
|
|
await this.renderComponent();
|
|
|
|
assert.dom(title).hasText('Secrets Sync', 'Page title renders');
|
|
assert.dom(cta.button).hasText('Create first destination', 'CTA action renders');
|
|
assert.dom(cta.summary).exists('CTA renders');
|
|
});
|
|
|
|
test('it should render landing cta component for community', async function (assert) {
|
|
this.version.type = 'community';
|
|
this.version.features = [];
|
|
this.destinations = [];
|
|
|
|
await this.renderComponent();
|
|
|
|
assert.dom(title).hasText('Secrets Sync Enterprise feature', 'Page title renders');
|
|
assert.dom(cta.button).doesNotExist('Create first destination button does not render');
|
|
});
|
|
|
|
test('it should render landing cta component for enterprise without the secrets sync feature', async function (assert) {
|
|
this.destinations = [];
|
|
this.version.features = [];
|
|
await this.renderComponent();
|
|
|
|
assert.dom(title).hasText('Secrets Sync Premium feature', 'Page title renders');
|
|
assert.dom(cta.button).doesNotExist('Create first destination button does not render');
|
|
assert.dom(cta.summary).exists('CTA renders');
|
|
});
|
|
|
|
test('it should render header, tabs and toolbar for overview state', async function (assert) {
|
|
await this.renderComponent();
|
|
|
|
assert.dom(title).hasText('Secrets Sync', 'Page title renders');
|
|
assert.dom(breadcrumb).exists({ count: 1 }, 'Correct number of breadcrumbs render');
|
|
assert.dom(breadcrumb).includesText('Secrets Sync', 'Top level breadcrumb renders');
|
|
assert.dom(cta.button).doesNotExist('CTA does not render');
|
|
assert.dom(tab('Overview')).hasText('Overview', 'Overview tab renders');
|
|
assert.dom(tab('Destinations')).hasText('Destinations', 'Destinations tab renders');
|
|
assert.dom(overview.createDestination).hasText('Create new destination', 'Toolbar action renders');
|
|
});
|
|
|
|
test('it should render secrets by destination table', async function (assert) {
|
|
const { icon, name, badge, total, updated, actionToggle, action } = overview.table;
|
|
const updatedDate = dateFormat(
|
|
[new Date('2023-09-20T10:51:53.961861096-04:00'), 'MMMM do yyyy, h:mm:ss a'],
|
|
{}
|
|
);
|
|
|
|
await this.renderComponent();
|
|
|
|
assert
|
|
.dom(overviewCard.title('Secrets by destination'))
|
|
.hasText('Secrets by destination', 'Overview card title renders for table');
|
|
assert.dom(icon(0)).hasAttribute('data-test-icon', 'aws-color', 'Destination icon renders');
|
|
assert.dom(name(0)).hasText('destination-aws', 'Destination name renders');
|
|
|
|
assert.dom(badge(0)).hasText('All synced', 'All synced badge renders');
|
|
assert.dom(badge(0)).hasClass('hds-badge--color-success', 'Correct color renders for All synced badge');
|
|
|
|
assert.dom(badge(1)).doesNotExist('Status badge does not render for destination with no associations');
|
|
|
|
assert.dom(badge(2)).hasText('1 Unsynced', 'Unsynced badge renders');
|
|
assert.dom(badge(2)).hasClass('hds-badge--color-neutral', 'Correct color renders for unsynced badge');
|
|
|
|
assert.dom(total(0)).hasText('1', '# of external secrets renders');
|
|
assert.dom(updated(0)).hasText(updatedDate, 'Last updated datetime renders');
|
|
|
|
assert.dom(total(1)).hasText('0', '# of external secrets renders for destination with no associations');
|
|
assert
|
|
.dom(updated(1))
|
|
.hasText('—', 'Last updated placeholder renders for destination with no associations');
|
|
|
|
await click(actionToggle(0));
|
|
assert.dom(action('sync')).hasText('Sync secrets', 'Sync action renders');
|
|
assert.dom(action('details')).hasText('View synced secrets', 'View synced secrets action renders');
|
|
});
|
|
|
|
test('it should paginate secrets by destination table', async function (assert) {
|
|
await this.renderComponent();
|
|
|
|
const { name, row } = overview.table;
|
|
assert.dom(row).exists({ count: 3 }, 'Correct number of table rows render based on page size');
|
|
assert.dom(name(0)).hasText('destination-aws', 'First destination renders on page 1');
|
|
|
|
await click(pagination.next);
|
|
await settled();
|
|
assert.dom(overview.table.row).exists({ count: 3 }, 'New items are fetched and rendered on page change');
|
|
assert.dom(name(0)).hasText('destination-gcp', 'First destination renders on page 2');
|
|
});
|
|
|
|
test('it should display empty state for secrets by destination table', async function (assert) {
|
|
this.server.get('/sys/sync/destinations/:type/:name/associations', () => {
|
|
return new Response(403, {}, { errors: ['Permission denied'] });
|
|
});
|
|
|
|
await this.renderComponent();
|
|
|
|
assert.dom(emptyStateTitle).hasText('Error fetching information', 'Empty state title renders');
|
|
assert
|
|
.dom(emptyStateMessage)
|
|
.hasText('Ensure that the policy has access to read sync associations.', 'Empty state message renders');
|
|
});
|
|
|
|
test('it should render totals cards', async function (assert) {
|
|
await this.renderComponent();
|
|
|
|
const { title, description, action, content } = overviewCard;
|
|
const cardData = [
|
|
{
|
|
cardTitle: 'Total destinations',
|
|
subText: 'The total number of connected destinations',
|
|
actionText: 'Create new',
|
|
count: '6',
|
|
},
|
|
{
|
|
cardTitle: 'Total secrets',
|
|
subText:
|
|
'The total number of secrets that have been synced from Vault. One secret will be counted as one sync client.',
|
|
actionText: 'View billing',
|
|
count: '7',
|
|
},
|
|
];
|
|
|
|
cardData.forEach(({ cardTitle, subText, actionText, count }) => {
|
|
assert.dom(title(cardTitle)).hasText(cardTitle, 'Overview card title renders');
|
|
assert.dom(description(cardTitle)).hasText(subText, 'Destinations overview card description renders');
|
|
assert.dom(content(cardTitle)).hasText(count, 'Total count renders');
|
|
assert.dom(action(cardTitle)).hasText(actionText, 'Card action renders');
|
|
});
|
|
});
|
|
});
|