mirror of
https://github.com/hashicorp/vault.git
synced 2026-05-05 04:16:31 +02:00
* dismisses wizards in ember tests * clears localStorage for tests that require intro pages * fixes version assertions in reduced disclosure tests * adds a wait for file upload in snapshots recovery test Co-authored-by: Jordan Reimer <zofskeez@gmail.com>
242 lines
11 KiB
JavaScript
242 lines
11 KiB
JavaScript
/**
|
|
* Copyright IBM Corp. 2016, 2025
|
|
* SPDX-License-Identifier: BUSL-1.1
|
|
*/
|
|
|
|
import { module, test } from 'qunit';
|
|
import { setupRenderingTest } from 'vault/tests/helpers';
|
|
import { click, fillIn, render } from '@ember/test-helpers';
|
|
import { hbs } from 'ember-cli-htmlbars';
|
|
import { setupMirage } from 'ember-cli-mirage/test-support';
|
|
import sinon from 'sinon';
|
|
import { GENERAL } from 'vault/tests/helpers/general-selectors';
|
|
|
|
const SELECTORS = {
|
|
content: '[data-test-content]',
|
|
guidedStart: '[data-test-guided-start]',
|
|
stepTitle: '[data-test-step-title]',
|
|
tree: '[data-test-tree]',
|
|
intro: '[data-test-intro]',
|
|
inputRow: (index) => (index ? `[data-test-input-row="${index}"]` : '[data-test-input-row]'),
|
|
};
|
|
|
|
module('Integration | Component | page/namespaces | Namespace Wizard', function (hooks) {
|
|
setupRenderingTest(hooks);
|
|
setupMirage(hooks);
|
|
|
|
hooks.beforeEach(function () {
|
|
// clear local storage to reset dismissed wizard state
|
|
localStorage.clear();
|
|
|
|
this.refreshSpy = sinon.spy();
|
|
this.flexiblePolicyCompleteSpy = sinon.spy();
|
|
this.wizardService = this.owner.lookup('service:wizard');
|
|
|
|
this.renderComponent = () => {
|
|
return render(hbs`
|
|
<Wizard::Namespaces::NamespaceWizard
|
|
@isIntroModal={{false}}
|
|
@onFlexiblePolicyComplete={{this.flexiblePolicyCompleteSpy}}
|
|
@onRefresh={{this.refreshSpy}}
|
|
/>
|
|
`);
|
|
};
|
|
});
|
|
|
|
test('it shows wizard when no namespaces exist', async function (assert) {
|
|
await this.renderComponent();
|
|
assert.dom(SELECTORS.intro).exists('Wizard intro is rendered');
|
|
});
|
|
|
|
test('it progresses through wizard steps with strict policy', async function (assert) {
|
|
await this.renderComponent();
|
|
await click(GENERAL.button('Guided start'));
|
|
|
|
// Step 1: Choose security policy
|
|
assert.dom(GENERAL.button('Next')).isDisabled('Next button disabled with no policy choice');
|
|
await click(GENERAL.radioByAttr('strict'));
|
|
assert.dom(GENERAL.button('Next')).isNotDisabled('Next button enabled after policy selection');
|
|
await click(GENERAL.button('Next'));
|
|
|
|
// Step 2: Add namespace data
|
|
assert.dom(SELECTORS.stepTitle).hasText('Map out your namespaces');
|
|
assert.dom(GENERAL.button('Next')).isDisabled('Next button disabled with no namespace data');
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('global-0')}`, 'global');
|
|
await click(GENERAL.button('Next'));
|
|
|
|
// Step 3: Choose implementation method
|
|
assert.dom(SELECTORS.stepTitle).hasText('Choose your implementation method');
|
|
assert.dom(GENERAL.copyButton).exists('Copy button exists for code snippets');
|
|
});
|
|
|
|
test('it skips step 2 with flexible policy', async function (assert) {
|
|
await this.renderComponent();
|
|
await click(GENERAL.button('Guided start'));
|
|
|
|
// Step 1: Choose flexible policy
|
|
await click(GENERAL.radioByAttr('flexible'));
|
|
await click(GENERAL.button('Next'));
|
|
|
|
// Should skip directly to step 3 (final step)
|
|
assert.dom(SELECTORS.stepTitle).hasText(`No action needed, you're all set.`);
|
|
assert.dom(GENERAL.button('identities')).exists('Link to identities exists');
|
|
assert.dom(GENERAL.button('Done')).exists('Done button exists for flexible policy');
|
|
});
|
|
|
|
test('it shows different code snippets per creation method option', async function (assert) {
|
|
await this.renderComponent();
|
|
await click(GENERAL.button('Guided start'));
|
|
await click(GENERAL.radioByAttr('strict'));
|
|
await click(GENERAL.button('Next'));
|
|
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('global-0')}`, 'global');
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('org-0')}`, 'org1');
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('project-0')}`, 'proj1');
|
|
await click(GENERAL.button('Next'));
|
|
|
|
// Assert code snippet changes
|
|
assert.dom(GENERAL.radioCardByAttr('Terraform automation')).exists('Terraform option exists');
|
|
assert
|
|
.dom(GENERAL.fieldByAttr('terraform'))
|
|
.hasTextContaining(`variable "global_child_namespaces"`, 'shows terraform code snippet by default');
|
|
|
|
await click(GENERAL.radioCardByAttr('API/CLI'));
|
|
assert
|
|
.dom(GENERAL.fieldByAttr('api'))
|
|
.hasTextContaining(`curl`, 'shows API code snippet by default for API/CLI radio card');
|
|
await click(GENERAL.hdsTab('cli'));
|
|
assert
|
|
.dom(GENERAL.fieldByAttr('cli'))
|
|
.hasTextContaining(`vault namespace create`, 'shows CLI code snippet by for CLI tab');
|
|
|
|
await click(GENERAL.radioCardByAttr('Vault UI workflow'));
|
|
assert.dom(GENERAL.fieldByAttr('terraform')).doesNotExist();
|
|
assert.dom(GENERAL.fieldByAttr('api')).doesNotExist();
|
|
assert.dom(GENERAL.fieldByAttr('cli')).doesNotExist();
|
|
});
|
|
|
|
test('it allows adding and removing blocks, org, and project inputs', async function (assert) {
|
|
await this.renderComponent();
|
|
await click(GENERAL.button('Guided start'));
|
|
await click(GENERAL.radioByAttr('strict'));
|
|
await click(GENERAL.button('Next'));
|
|
|
|
// Test adding and removing a second namespace block
|
|
await click(GENERAL.button('add namespace'));
|
|
assert.dom(`${SELECTORS.inputRow(1)}`).exists('Second input block exists');
|
|
await click(`${SELECTORS.inputRow(1)} ${GENERAL.button('delete namespace')}`);
|
|
assert.dom(`${SELECTORS.inputRow(1)}`).doesNotExist('Second input block was removed');
|
|
|
|
// Test adding and removing project input
|
|
await click(`${SELECTORS.inputRow(0)} ${GENERAL.button('add project')}`);
|
|
assert
|
|
.dom(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('project-1')}`)
|
|
.exists('Second project input was added');
|
|
await click(`${SELECTORS.inputRow(0)} ${GENERAL.button('delete project')}`);
|
|
assert
|
|
.dom(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('project-1')}`)
|
|
.doesNotExist('Second project input was removed');
|
|
|
|
// Test adding and removing org input
|
|
await click(`${SELECTORS.inputRow(0)} ${GENERAL.button('add org')}`);
|
|
assert
|
|
.dom(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('org-1')}`)
|
|
.exists('Second org input was added');
|
|
await click(`${SELECTORS.inputRow(0)} ${GENERAL.button('delete org')}`);
|
|
assert
|
|
.dom(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('org-1')}`)
|
|
.doesNotExist('Second org input was removed');
|
|
});
|
|
|
|
test('it dismisses from the intro page', async function (assert) {
|
|
await this.renderComponent();
|
|
|
|
assert.false(this.wizardService.isDismissed('namespace'), 'Wizard is not dismissed initially');
|
|
|
|
await click(GENERAL.button('Skip'));
|
|
|
|
assert.true(this.wizardService.isDismissed('namespace'), 'Wizard was marked as dismissed in service');
|
|
assert.true(this.refreshSpy.calledOnce, 'onRefresh callback was called');
|
|
});
|
|
|
|
test('it dismisses from the Guided start', async function (assert) {
|
|
await this.renderComponent();
|
|
await click(GENERAL.button('Guided start'));
|
|
|
|
assert.false(this.wizardService.isDismissed('namespace'), 'Wizard is not dismissed initially');
|
|
|
|
await click(GENERAL.button('Exit'));
|
|
|
|
assert.true(this.wizardService.isDismissed('namespace'), 'Wizard was marked as dismissed in service');
|
|
assert.true(this.refreshSpy.calledOnce, 'onRefresh callback was called');
|
|
});
|
|
|
|
test('it dismisses after completing flexible policy flow', async function (assert) {
|
|
await this.renderComponent();
|
|
await click(GENERAL.button('Guided start'));
|
|
await click(GENERAL.radioByAttr('flexible'));
|
|
await click(GENERAL.button('Next'));
|
|
|
|
assert.false(this.wizardService.isDismissed('namespace'), 'Wizard not dismissed before clicking Done');
|
|
|
|
await click(GENERAL.button('Done'));
|
|
|
|
assert.true(this.wizardService.isDismissed('namespace'), 'Wizard was marked as dismissed after Done');
|
|
assert.true(this.refreshSpy.calledOnce, 'onRefresh callback was called');
|
|
assert.true(this.flexiblePolicyCompleteSpy.calledOnce, 'flexiblePolicyComplete callback was called');
|
|
});
|
|
|
|
test('it shows tree chart only when there are multiple globals, orgs, or projects', async function (assert) {
|
|
await this.renderComponent();
|
|
await click(GENERAL.button('Guided start'));
|
|
await click(GENERAL.radioByAttr('strict'));
|
|
await click(GENERAL.button('Next'));
|
|
|
|
// Initially with only one global and one org/project, tree should not show
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('global-0')}`, 'global1');
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('org-0')}`, 'org1');
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('project-0')}`, 'proj1');
|
|
assert.dom(SELECTORS.tree).doesNotExist('Tree chart hidden with single global, org, and project');
|
|
|
|
// Add a second global namespace - tree should now show
|
|
await click(GENERAL.button('add namespace'));
|
|
await fillIn(`${SELECTORS.inputRow(1)} ${GENERAL.inputByAttr('global-1')}`, 'global2');
|
|
assert.dom(SELECTORS.tree).exists('Tree chart shows with multiple globals');
|
|
|
|
// Remove second global - tree is hidden again
|
|
await click(`${SELECTORS.inputRow(1)} ${GENERAL.button('delete namespace')}`);
|
|
assert.dom(SELECTORS.tree).doesNotExist('Tree chart hidden after removing second global');
|
|
|
|
// Add a second org - tree should show
|
|
await click(`${SELECTORS.inputRow(0)} ${GENERAL.button('add org')}`);
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('org-1')}`, 'org2');
|
|
assert.dom(SELECTORS.tree).exists('Tree chart shows with multiple orgs');
|
|
|
|
// Add empty global - tree show not show empty global
|
|
await click(GENERAL.button('add namespace'));
|
|
assert.dom(`${SELECTORS.tree} .nodes > g`).exists({ count: 5 }, 'Only renders non-empty input nodes');
|
|
await click(`${SELECTORS.inputRow(1)} ${GENERAL.button('delete namespace')}`);
|
|
|
|
// Remove second org - tree is hidden again
|
|
await click(`${SELECTORS.inputRow(0)} ${GENERAL.button('delete org')}`);
|
|
assert.dom(SELECTORS.tree).doesNotExist('Tree chart hidden after removing second org');
|
|
|
|
// Add a second project - tree should show
|
|
await click(`${SELECTORS.inputRow(0)} ${GENERAL.button('add project')}`);
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('project-1')}`, 'project2');
|
|
assert.dom(SELECTORS.tree).exists('Tree chart shows with multiple projects');
|
|
|
|
// Clear global - tree is hidden
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('global-0')}`, '');
|
|
assert.dom(SELECTORS.tree).doesNotExist('Tree chart hidden after clearing parent global');
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('global-0')}`, 'global1');
|
|
assert.dom(SELECTORS.tree).exists('Tree chart is rendered');
|
|
|
|
// Clear org - tree is hidden
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('org-0')}`, '');
|
|
assert.dom(SELECTORS.tree).doesNotExist('Tree chart hidden after clearing parent org');
|
|
await fillIn(`${SELECTORS.inputRow(0)} ${GENERAL.inputByAttr('org-0')}`, 'org1');
|
|
assert.dom(SELECTORS.tree).exists('Tree chart is rendered');
|
|
});
|
|
});
|