mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 17:52:32 +00:00
UI: Allow repeat data wrapping for wrap tool (#27289)
* update selectors * add tests * add tests * add explanations to true only args * allow token wrap to wrap again * update test wording * add wrap specific modules to tools acceptance test * add changelog * remove selectedAction * trim args and update tests
This commit is contained in:
3
changelog/27289.txt
Normal file
3
changelog/27289.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:improvement
|
||||
ui: Allow users to wrap inputted data again instead of resetting form
|
||||
```
|
||||
@@ -32,12 +32,12 @@ export default Component.extend(DEFAULTS, {
|
||||
flashMessages: service(),
|
||||
store: service(),
|
||||
// putting these attrs here so they don't get reset when you click back
|
||||
//random
|
||||
// random
|
||||
bytes: 32,
|
||||
//hash
|
||||
// hash
|
||||
format: 'base64',
|
||||
algorithm: 'sha2-256',
|
||||
|
||||
data: '{\n}',
|
||||
tagName: '',
|
||||
|
||||
didReceiveAttrs() {
|
||||
@@ -139,15 +139,18 @@ export default Component.extend(DEFAULTS, {
|
||||
this.reset();
|
||||
},
|
||||
|
||||
updateTtl(ttl) {
|
||||
set(this, 'wrapTTL', ttl);
|
||||
onBack(properties) {
|
||||
// only reset specific properties so user can reuse input data and repeat the action
|
||||
if (this.isDestroyed || this.isDestroying) {
|
||||
return;
|
||||
}
|
||||
properties.forEach((prop) => {
|
||||
set(this, prop, DEFAULTS[prop]);
|
||||
});
|
||||
},
|
||||
|
||||
codemirrorUpdated(val, hasErrors) {
|
||||
setProperties(this, {
|
||||
buttonDisabled: hasErrors,
|
||||
data: val,
|
||||
});
|
||||
onChange(param, value) {
|
||||
set(this, param, value);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -12,45 +12,36 @@ import { tracked } from '@glimmer/tracking';
|
||||
* ToolWrap components are components that sys/wrapping/wrap functionality. Most of the functionality is passed through as actions from the tool-actions-form and then called back with properties.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <ToolWrap
|
||||
* @errors={{@errors}}
|
||||
* @onBack={{action "onBack" (array "token")}}
|
||||
* @onChange={{action "onChange"}}
|
||||
* @onClear={{action "onClear"}}
|
||||
* @token={{token}}
|
||||
* @selectedAction="wrap"
|
||||
* @codemirrorUpdated={{action "codemirrorUpdated"}}
|
||||
* @updateTtl={{action "updateTtl"}}
|
||||
* @buttonDisabled={{buttonDisabled}}
|
||||
* @errors={{errors}}/>
|
||||
* ```
|
||||
* @param onClear {Function} - parent action that is passed through. Must be passed as {{action "onClear"}}
|
||||
* @param token=null {String} - property passed from parent to child and then passed back up to parent
|
||||
* @param selectedAction="wrap" - passed in from parent. This is the wrap action, others include hash, etc.
|
||||
* @param codemirrorUpdated {Function} - parent action that is passed through. Must be passed as {{action "codemirrorUpdated"}}.
|
||||
* @param updateTtl {Function} - parent action that is passed through. Must be passed as {{action "updateTtl"}}
|
||||
* @param buttonDisabled=false {Boolean} - false default and if there is an error on codemirror it turns to true.
|
||||
* @param error=null {Object} - errors passed from parent as default then from child back to parent.
|
||||
* @token={{@token}}
|
||||
* />
|
||||
*
|
||||
* @param {object} errors=null - errors returned if wrap fails
|
||||
* @param {function} onBack - callback that only clears specific values so the action can be repeated. Must be passed as `{{action "onBack"}}`
|
||||
* @param {function} onChange - callback that fires when inputs change and passes value and param name back to the parent
|
||||
* @param {function} onClear - callback that resets all of values to defaults. Must be passed as `{{action "onClear"}}`
|
||||
* @param {string} token=null - returned after user clicks "Wrap data", if there is a token value it displays instead of the JsonEditor
|
||||
*/
|
||||
|
||||
export default class ToolWrap extends Component {
|
||||
@tracked data = '{\n}';
|
||||
@tracked buttonDisabled = false;
|
||||
|
||||
@action
|
||||
onClear() {
|
||||
this.args.onClear();
|
||||
}
|
||||
@action
|
||||
updateTtl(evt) {
|
||||
if (!evt) return;
|
||||
const ttl = evt.enabled ? `${evt.seconds}s` : '30m';
|
||||
this.args.updateTtl(ttl);
|
||||
this.args.onChange('wrapTTL', ttl);
|
||||
}
|
||||
|
||||
@action
|
||||
codemirrorUpdated(val, codemirror) {
|
||||
codemirror.performLint();
|
||||
const hasErrors = codemirror?.state.lint.marked?.length > 0;
|
||||
this.data = val;
|
||||
this.buttonDisabled = hasErrors;
|
||||
this.args.codemirrorUpdated(val, hasErrors);
|
||||
this.args.onChange('data', val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,12 +54,11 @@
|
||||
{{else if (eq this.selectedAction "wrap")}}
|
||||
<ToolWrap
|
||||
@token={{this.token}}
|
||||
@selectedAction={{this.selectedAction}}
|
||||
@onBack={{action "onBack" (array "token")}}
|
||||
@onClear={{action "onClear"}}
|
||||
@codemirrorUpdated={{action "codemirrorUpdated"}}
|
||||
@updateTtl={{action "updateTtl"}}
|
||||
@buttonDisabled={{this.buttonDisabled}}
|
||||
@onChange={{action "onChange"}}
|
||||
@errors={{this.errors}}
|
||||
@data={{this.data}}
|
||||
/>
|
||||
{{else}}
|
||||
<EmptyState @title="Tool not available" />
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
<Hds::Button @text="Back" @color="secondary" {{on "click" this.onClear}} data-test-tools-back={{true}} />
|
||||
<Hds::Button @text="Back" @color="secondary" {{on "click" this.onClear}} data-test-button="Back" />
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
@@ -80,7 +80,7 @@
|
||||
</div>
|
||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||
<div class="control">
|
||||
<Hds::Button @text="Hash" type="submit" data-test-tools-submit="true" />
|
||||
<Hds::Button @text="Hash" type="submit" data-test-tools-submit />
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -13,12 +13,12 @@
|
||||
|
||||
{{#if (or @creation_time @creation_ttl)}}
|
||||
<div class="box is-fullwidth is-sideless is-paddingless is-marginless">
|
||||
<InfoTableRow @label="Creation path" @value={{@creation_path}} data-test-tools="token-lookup-row" />
|
||||
<InfoTableRow @label="Creation time" @value={{@creation_time}} data-test-tools="token-lookup-row" />
|
||||
<InfoTableRow @label="Creation TTL" @value={{@creation_ttl}} data-test-tools="token-lookup-row" />
|
||||
<InfoTableRow @label="Creation path" @value={{@creation_path}} />
|
||||
<InfoTableRow @label="Creation time" @value={{@creation_time}} />
|
||||
<InfoTableRow @label="Creation TTL" @value={{@creation_ttl}} />
|
||||
{{#if @expirationDate}}
|
||||
<InfoTableRow @label="Expiration date" @value={{@expirationDate}} data-test-tools="token-lookup-row" />
|
||||
<InfoTableRow @label="Expires in" @value={{date-from-now @expirationDate}} data-test-tools="token-lookup-row" />
|
||||
<InfoTableRow @label="Expiration date" @value={{@expirationDate}} />
|
||||
<InfoTableRow @label="Expires in" @value={{date-from-now @expirationDate}} />
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||
@@ -42,7 +42,7 @@
|
||||
</div>
|
||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||
<div class="control">
|
||||
<Hds::Button @text="Lookup token" type="submit" data-test-tools-submit="true" />
|
||||
<Hds::Button @text="Lookup token" type="submit" data-test-tools-submit />
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -63,7 +63,7 @@
|
||||
</div>
|
||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||
<div class="control">
|
||||
<Hds::Button @text="Generate" type="submit" data-test-tools-submit="true" />
|
||||
<Hds::Button @text="Generate" type="submit" data-test-tools-submit />
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -56,7 +56,7 @@
|
||||
</div>
|
||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||
<div class="control">
|
||||
<Hds::Button @text="Rewrap token" type="submit" data-test-tools-submit="true" />
|
||||
<Hds::Button @text="Rewrap token" type="submit" data-test-tools-submit />
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -13,8 +13,8 @@
|
||||
|
||||
{{#if @unwrap_data}}
|
||||
<Hds::Tabs as |T|>
|
||||
<T.Tab data-test-button-data>Data</T.Tab>
|
||||
<T.Tab data-test-button-details>Wrap Details</T.Tab>
|
||||
<T.Tab data-test-tab="data">Data</T.Tab>
|
||||
<T.Tab data-test-tab="details">Wrap Details</T.Tab>
|
||||
<T.Panel>
|
||||
<JsonEditor
|
||||
class="has-top-padding-m"
|
||||
@@ -75,7 +75,7 @@
|
||||
</div>
|
||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||
<div class="control">
|
||||
<Hds::Button @text="Unwrap data" type="submit" data-test-tools-submit="true" />
|
||||
<Hds::Button @text="Unwrap data" type="submit" data-test-tools-submit />
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -16,48 +16,41 @@
|
||||
<div class="field">
|
||||
<label for="wrap-info" class="is-label">Wrapped token</label>
|
||||
<div class="control">
|
||||
<Textarea
|
||||
@value={{@token}}
|
||||
readonly={{true}}
|
||||
class="textarea"
|
||||
id="wrap-info"
|
||||
name="wrap-info"
|
||||
<Hds::Copy::Snippet
|
||||
@textToCopy={{@token}}
|
||||
@color="secondary"
|
||||
data-test-tools-input="wrapping-token"
|
||||
@onError={{(fn
|
||||
(set-flash-message "Clipboard copy failed. The Clipboard API requires a secure context." "danger")
|
||||
)}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||
<div class="control">
|
||||
<Hds::Copy::Button
|
||||
@text="Copy"
|
||||
@textToCopy={{@token}}
|
||||
@onError={{(fn (set-flash-message "Clipboard copy failed. The Clipboard API requires a secure context." "danger"))}}
|
||||
class="primary"
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
<Hds::Button @text="Back" @color="secondary" {{on "click" this.onClear}} />
|
||||
</div>
|
||||
<Hds::ButtonSet>
|
||||
<Hds::Button @icon="arrow-left" @text="Back" @color="tertiary" {{on "click" @onBack}} data-test-button="Back" />
|
||||
<Hds::Button @text="Done" @color="secondary" {{on "click" @onClear}} data-test-button="Done" />
|
||||
</Hds::ButtonSet>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="box is-sideless is-fullwidth is-marginless">
|
||||
<NamespaceReminder @mode="perform" @noun={{@selectedAction}} />
|
||||
<NamespaceReminder @mode="perform" @noun="wrap" />
|
||||
<MessageError @errors={{@errors}} />
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<JsonEditor
|
||||
@title="Data to wrap"
|
||||
@subTitle="json-formatted"
|
||||
@value={{this.data}}
|
||||
@valueUpdated={{action this.codemirrorUpdated}}
|
||||
@value={{@data}}
|
||||
@valueUpdated={{this.codemirrorUpdated}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<TtlPicker
|
||||
@label="Wrap TTL"
|
||||
@initialValue="30m"
|
||||
@onChange={{action "updateTtl"}}
|
||||
@onChange={{this.updateTtl}}
|
||||
@helperTextDisabled="Vault will use the default (30m)"
|
||||
@helperTextEnabled="Wrap will expire after"
|
||||
@changeOnInit={{true}}
|
||||
@@ -65,7 +58,7 @@
|
||||
</div>
|
||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||
<div class="control">
|
||||
<Hds::Button @text="Wrap data" type="submit" data-test-tools-submit="true" disabled={{@buttonDisabled}} />
|
||||
<Hds::Button @text="Wrap data" type="submit" disabled={{this.buttonDisabled}} data-test-tools-submit />
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -21,6 +21,8 @@ import authPage from 'vault/tests/pages/auth';
|
||||
import { capitalize } from '@ember/string';
|
||||
import codemirror from 'vault/tests/helpers/codemirror';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import { GENERAL } from 'vault/tests/helpers/general-selectors';
|
||||
import { TOOLS_SELECTORS as TS } from 'vault/tests/helpers/tools-selectors';
|
||||
|
||||
module('Acceptance | tools', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
@@ -33,13 +35,6 @@ module('Acceptance | tools', function (hooks) {
|
||||
const DATA_TO_WRAP = JSON.stringify({ tools: 'tests' });
|
||||
const TOOLS_ACTIONS = toolsActions();
|
||||
|
||||
/*
|
||||
data-test-tools-input="wrapping-token"
|
||||
data-test-tools-input="rewrapped-token"
|
||||
data-test-tools="token-lookup-row"
|
||||
data-test-sidebar-nav-link=supportedAction
|
||||
*/
|
||||
|
||||
var createTokenStore = () => {
|
||||
let token;
|
||||
return {
|
||||
@@ -51,92 +46,89 @@ module('Acceptance | tools', function (hooks) {
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
test('tools functionality', async function (assert) {
|
||||
var tokenStore = createTokenStore();
|
||||
await visit('/vault/tools');
|
||||
|
||||
assert.strictEqual(currentURL(), '/vault/tools/wrap', 'forwards to the first action');
|
||||
TOOLS_ACTIONS.forEach((action) => {
|
||||
assert.dom(`[data-test-sidebar-nav-link="${capitalize(action)}"]`).exists(`${action} link renders`);
|
||||
assert.dom(GENERAL.navLink(capitalize(action))).exists(`${action} link renders`);
|
||||
});
|
||||
|
||||
await waitFor('.CodeMirror');
|
||||
codemirror().setValue(DATA_TO_WRAP);
|
||||
|
||||
// wrap
|
||||
await click('[data-test-tools-submit]');
|
||||
const wrappedToken = await waitUntil(() => find('[data-test-tools-input="wrapping-token"]'));
|
||||
tokenStore.set(wrappedToken.value);
|
||||
assert
|
||||
.dom('[data-test-tools-input="wrapping-token"]')
|
||||
.hasValue(wrappedToken.value, 'has a wrapping token');
|
||||
await click(TS.submit);
|
||||
const wrappedToken = await waitUntil(() => find(TS.toolsInput('wrapping-token')));
|
||||
tokenStore.set(wrappedToken.innerText);
|
||||
|
||||
//lookup
|
||||
await click('[data-test-sidebar-nav-link="Lookup"]');
|
||||
// lookup
|
||||
await click(GENERAL.navLink('Lookup'));
|
||||
|
||||
await fillIn('[data-test-tools-input="wrapping-token"]', tokenStore.get());
|
||||
await click('[data-test-tools-submit]');
|
||||
await waitUntil(() => findAll('[data-test-tools="token-lookup-row"]').length >= 3);
|
||||
const rows = findAll('[data-test-tools="token-lookup-row"]');
|
||||
assert.dom(rows[0]).hasText(/Creation path/, 'show creation path row');
|
||||
assert.dom(rows[1]).hasText(/Creation time/, 'show creation time row');
|
||||
assert.dom(rows[2]).hasText(/Creation TTL/, 'show creation ttl row');
|
||||
await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
|
||||
await click(TS.submit);
|
||||
await waitUntil(() => findAll('[data-test-component="info-table-row"]').length >= 3);
|
||||
assert.dom(GENERAL.infoRowValue('Creation path')).hasText('sys/wrapping/wrap', 'show creation path row');
|
||||
assert.dom(GENERAL.infoRowValue('Creation time')).exists();
|
||||
assert.dom(GENERAL.infoRowValue('Creation TTL')).hasText('1800', 'show creation ttl row');
|
||||
|
||||
//rewrap
|
||||
await click('[data-test-sidebar-nav-link="Rewrap"]');
|
||||
// rewrap
|
||||
await click(GENERAL.navLink('Rewrap'));
|
||||
|
||||
await fillIn('[data-test-tools-input="wrapping-token"]', tokenStore.get());
|
||||
await click('[data-test-tools-submit]');
|
||||
const rewrappedToken = await waitUntil(() => find('[data-test-tools-input="rewrapped-token"]'));
|
||||
await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
|
||||
await click(TS.submit);
|
||||
const rewrappedToken = await waitUntil(() => find(TS.toolsInput('rewrapped-token')));
|
||||
assert.ok(rewrappedToken.value, 'has a new re-wrapped token');
|
||||
assert.notEqual(rewrappedToken.value, tokenStore.get(), 're-wrapped token is not the wrapped token');
|
||||
tokenStore.set(rewrappedToken.value);
|
||||
await settled();
|
||||
|
||||
//unwrap
|
||||
await click('[data-test-sidebar-nav-link="Unwrap"]');
|
||||
// unwrap
|
||||
await click(GENERAL.navLink('Unwrap'));
|
||||
|
||||
await fillIn('[data-test-tools-input="wrapping-token"]', tokenStore.get());
|
||||
await click('[data-test-tools-submit]');
|
||||
await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
|
||||
await click(TS.submit);
|
||||
await waitFor('.CodeMirror');
|
||||
assert.deepEqual(
|
||||
JSON.parse(codemirror().getValue()),
|
||||
JSON.parse(DATA_TO_WRAP),
|
||||
'unwrapped data equals input data'
|
||||
);
|
||||
await waitUntil(() => find('[data-test-button-details]'));
|
||||
await click('[data-test-button-details]');
|
||||
await click('[data-test-button-data]');
|
||||
await waitUntil(() => find(TS.tab('details')));
|
||||
await click(TS.tab('details'));
|
||||
await click(TS.tab('data'));
|
||||
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"]');
|
||||
await click(GENERAL.navLink('Random'));
|
||||
|
||||
assert.dom('[data-test-tools-input="bytes"]').hasValue('32', 'defaults to 32 bytes');
|
||||
await click('[data-test-tools-submit]');
|
||||
const randomBytes = await waitUntil(() => find('[data-test-tools-input="random-bytes"]'));
|
||||
assert.dom(TS.toolsInput('bytes')).hasValue('32', 'defaults to 32 bytes');
|
||||
await click(TS.submit);
|
||||
const randomBytes = await waitUntil(() => find(TS.toolsInput('random-bytes')));
|
||||
assert.ok(randomBytes.value, 'shows the returned value of random bytes');
|
||||
|
||||
//hash
|
||||
await click('[data-test-sidebar-nav-link="Hash"]');
|
||||
// hash
|
||||
await click(GENERAL.navLink('Hash'));
|
||||
|
||||
await fillIn('[data-test-tools-input="hash-input"]', 'foo');
|
||||
await fillIn(TS.toolsInput('hash-input'), 'foo');
|
||||
await click('[data-test-transit-b64-toggle="input"]');
|
||||
|
||||
await click('[data-test-tools-submit]');
|
||||
let sumInput = await waitUntil(() => find('[data-test-tools-input="sum"]'));
|
||||
await click(TS.submit);
|
||||
let sumInput = await waitUntil(() => find(TS.toolsInput('sum')));
|
||||
assert
|
||||
.dom(sumInput)
|
||||
.hasValue('LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564=', 'hashes the data, encodes input');
|
||||
await click('[data-test-tools-back]');
|
||||
await click(TS.button('Back'));
|
||||
|
||||
await fillIn('[data-test-tools-input="hash-input"]', 'e2RhdGE6ImZvbyJ9');
|
||||
await fillIn(TS.toolsInput('hash-input'), 'e2RhdGE6ImZvbyJ9');
|
||||
|
||||
await click('[data-test-tools-submit]');
|
||||
sumInput = await waitUntil(() => find('[data-test-tools-input="sum"]'));
|
||||
await click(TS.submit);
|
||||
sumInput = await waitUntil(() => find(TS.toolsInput('sum')));
|
||||
assert
|
||||
.dom(sumInput)
|
||||
.hasValue('JmSi2Hhbgu2WYOrcOyTqqMdym7KT3sohCwAwaMonVrc=', 'hashes the data, passes b64 input through');
|
||||
@@ -168,10 +160,10 @@ module('Acceptance | tools', function (hooks) {
|
||||
await visit('/vault/tools');
|
||||
|
||||
//unwrap
|
||||
await click('[data-test-sidebar-nav-link="Unwrap"]');
|
||||
await click(GENERAL.navLink('Unwrap'));
|
||||
|
||||
await fillIn('[data-test-tools-input="wrapping-token"]', 'sometoken');
|
||||
await click('[data-test-tools-submit]');
|
||||
await fillIn(TS.toolsInput('wrapping-token'), 'sometoken');
|
||||
await click(TS.submit);
|
||||
|
||||
await waitFor('.CodeMirror');
|
||||
assert.deepEqual(
|
||||
@@ -180,4 +172,57 @@ module('Acceptance | tools', function (hooks) {
|
||||
'unwrapped data equals input data'
|
||||
);
|
||||
});
|
||||
|
||||
module('wrap', function () {
|
||||
test('it wraps data again after clicking "Back"', async function (assert) {
|
||||
const tokenStore = createTokenStore();
|
||||
await visit('/vault/tools/wrap');
|
||||
|
||||
await waitFor('.CodeMirror');
|
||||
codemirror().setValue(DATA_TO_WRAP);
|
||||
|
||||
// initial wrap
|
||||
await click(TS.submit);
|
||||
await waitUntil(() => find(TS.toolsInput('wrapping-token')));
|
||||
await click(TS.button('Back'));
|
||||
|
||||
// wrap again
|
||||
await click(TS.submit);
|
||||
const wrappedToken = await waitUntil(() => find(TS.toolsInput('wrapping-token')));
|
||||
tokenStore.set(wrappedToken.innerText);
|
||||
|
||||
// there was a bug where clicking "back" cleared the parent's data, but not the child form component
|
||||
// so when users attempted to wrap data again the payload was actually empty and unwrapping the token returned {token: ""}
|
||||
// it is user desired behavior that the form does not clear on back, and that wrapping can be immediately repeated
|
||||
// we use lookup to check our token from the second wrap returns the unwrapped data we expect
|
||||
await click(GENERAL.navLink('Lookup'));
|
||||
await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
|
||||
await click(TS.submit);
|
||||
await waitUntil(() => findAll('[data-test-component="info-table-row"]').length >= 3);
|
||||
assert.dom(GENERAL.infoRowValue('Creation TTL')).hasText('1800', 'show creation ttl row');
|
||||
});
|
||||
|
||||
test('it sends wrap ttl', async function (assert) {
|
||||
const tokenStore = createTokenStore();
|
||||
await visit('/vault/tools/wrap');
|
||||
|
||||
await waitFor('.CodeMirror');
|
||||
codemirror().setValue(DATA_TO_WRAP);
|
||||
|
||||
// update to non-default ttl
|
||||
await click(GENERAL.toggleInput('Wrap TTL'));
|
||||
await fillIn(GENERAL.ttl.input('Wrap TTL'), '20');
|
||||
|
||||
await click(TS.submit);
|
||||
const wrappedToken = await waitUntil(() => find(TS.toolsInput('wrapping-token')));
|
||||
tokenStore.set(wrappedToken.innerText);
|
||||
|
||||
// lookup to check unwrapped data is what we expect
|
||||
await click(GENERAL.navLink('Lookup'));
|
||||
await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
|
||||
await click(TS.submit);
|
||||
await waitUntil(() => findAll('[data-test-component="info-table-row"]').length >= 3);
|
||||
assert.dom(GENERAL.infoRowValue('Creation TTL')).hasText('1200', 'show creation ttl row');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
11
ui/tests/helpers/tools-selectors.ts
Normal file
11
ui/tests/helpers/tools-selectors.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
export const TOOLS_SELECTORS = {
|
||||
submit: '[data-test-tools-submit]',
|
||||
toolsInput: (attr: string) => `[data-test-tools-input="${attr}"]`,
|
||||
tab: (item: string) => `[data-test-tab="${item}"]`,
|
||||
button: (action: string) => `[data-test-button="${action}"]`,
|
||||
};
|
||||
81
ui/tests/integration/components/tools/tool-wrap-test.js
Normal file
81
ui/tests/integration/components/tools/tool-wrap-test.js
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'vault/tests/helpers';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import { click, fillIn, render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
import sinon from 'sinon';
|
||||
import { GENERAL } from 'vault/tests/helpers/general-selectors';
|
||||
import codemirror from 'vault/tests/helpers/codemirror';
|
||||
import { TOOLS_SELECTORS as TS } from 'vault/tests/helpers/tools-selectors';
|
||||
|
||||
module('Integration | Component | tools/tool-wrap', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.onBack = sinon.spy();
|
||||
this.onClear = sinon.spy();
|
||||
this.onChange = sinon.spy();
|
||||
this.data = '{\n}';
|
||||
this.renderComponent = async () => {
|
||||
await render(hbs`
|
||||
<ToolWrap
|
||||
@token={{this.token}}
|
||||
@errors={{this.errors}}
|
||||
@onClear={{this.onClear}}
|
||||
@onBack={{this.onBack}}
|
||||
@onChange={{this.onChange}}
|
||||
@data={{this.data}}
|
||||
/>`);
|
||||
};
|
||||
});
|
||||
|
||||
test('it renders defaults', async function (assert) {
|
||||
await this.renderComponent();
|
||||
|
||||
assert.dom('h1').hasText('Wrap Data', 'Title renders');
|
||||
assert.strictEqual(codemirror().getValue(' '), '{ }', 'json editor initializes with empty object');
|
||||
assert.dom(GENERAL.toggleInput('Wrap TTL')).isNotChecked('Wrap TTL defaults to unchecked');
|
||||
assert.dom(TS.submit).isEnabled();
|
||||
assert.dom(TS.toolsInput('wrapping-token')).doesNotExist();
|
||||
assert.dom(TS.button('Back')).doesNotExist();
|
||||
assert.dom(TS.button('Done')).doesNotExist();
|
||||
});
|
||||
|
||||
test('it renders token view', async function (assert) {
|
||||
this.token = 'blah.jhfel7SmsVeZwihaGiIKHGh2cy5XZWtEeEt5WmRwS1VYSTNDb1BBVUNsVFAQ3JIK';
|
||||
await this.renderComponent();
|
||||
|
||||
assert.dom('h1').hasText('Wrap Data');
|
||||
assert.dom('label').hasText('Wrapped token');
|
||||
assert.dom('.CodeMirror').doesNotExist();
|
||||
assert.dom(TS.toolsInput('wrapping-token')).hasText(this.token);
|
||||
await click(TS.button('Back'));
|
||||
assert.true(this.onBack.calledOnce, 'onBack is called');
|
||||
await click(TS.button('Done'));
|
||||
assert.true(this.onClear.calledOnce, 'onClear is called');
|
||||
});
|
||||
|
||||
test('it calls onChange for json editor', async function (assert) {
|
||||
const data = `{"foo": "bar"}`;
|
||||
await this.renderComponent();
|
||||
await codemirror().setValue(`{bad json}`);
|
||||
assert.dom(TS.submit).isDisabled('submit disables if json editor has linting errors');
|
||||
|
||||
await codemirror().setValue(data);
|
||||
assert.dom(TS.submit).isEnabled('submit reenables if json editor has no linting errors');
|
||||
assert.propEqual(this.onChange.lastCall.args, ['data', data], 'onChange is called with json data');
|
||||
});
|
||||
|
||||
test('it calls onChange for ttl picker', async function (assert) {
|
||||
await this.renderComponent();
|
||||
await click(GENERAL.toggleInput('Wrap TTL'));
|
||||
await fillIn(GENERAL.ttl.input('Wrap TTL'), '20');
|
||||
assert.propEqual(this.onChange.lastCall.args, ['wrapTTL', '1200s'], 'onChange is called with wrapTTL');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user