/** * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: MPL-2.0 */ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { render, click, fillIn } from '@ember/test-helpers'; import sinon from 'sinon'; import hbs from 'htmlbars-inline-precompile'; import selectors from 'vault/tests/helpers/components/ttl-picker'; module('Integration | Component | ttl-picker', function (hooks) { setupRenderingTest(hooks); hooks.beforeEach(function () { this.set('onChange', sinon.spy()); this.set('label', 'Foobar'); }); module('without toggle', function (hooks) { hooks.beforeEach(function () { this.set('hideToggle', true); }); test('it shows correct time and value when no initialValue set', async function (assert) { await render(hbs``); assert.dom(selectors.ttlFormGroup).exists('TTL Form fields exist'); assert.dom(selectors.ttlValue).hasValue(''); assert.dom(selectors.ttlUnit).hasValue('s'); }); test('it calls the change fn with the correct values', async function (assert) { const changeSpy = sinon.spy(); this.set('onChange', changeSpy); await render(hbs` `); assert.dom(selectors.ttlUnit).hasValue('m', 'unit value shows m (minutes)'); await fillIn(selectors.ttlValue, '10'); await assert.ok(changeSpy.calledOnce, 'it calls the passed onChange'); assert.ok( changeSpy.calledWithExactly({ enabled: true, seconds: 600, timeString: '10m', goSafeTimeString: '10m', }), 'Passes the values back to onChange' ); }); test('it correctly shows initial time and unit', async function (assert) { await render(hbs` `); assert.dom(selectors.ttlUnit).hasValue('h', 'unit value initially shows as h (hours)'); assert.dom(selectors.ttlValue).hasValue('3', 'time value initially shows as 3'); }); test('it fails gracefully when initialValue is not parseable', async function (assert) { const changeSpy = sinon.spy(); this.set('onChange', changeSpy); await render(hbs` `); assert.dom(selectors.ttlValue).hasValue('', 'time value initially shows as empty'); assert.dom(selectors.ttlUnit).hasValue('s', 'unit value initially shows as s (seconds)'); assert.ok(changeSpy.notCalled, 'onChange is not called on init'); }); test('it recalculates time when unit is changed', async function (assert) { const changeSpy = sinon.spy(); this.set('onChange', changeSpy); await render(hbs` `); assert.dom(selectors.ttlUnit).hasValue('h', 'unit value initially shows as h (hours)'); assert.dom(selectors.ttlValue).hasValue('1', 'time value initially shows as 1'); await fillIn(selectors.ttlUnit, 'm'); assert.dom(selectors.ttlUnit).hasValue('m', 'unit value changed to m (minutes)'); assert.dom(selectors.ttlValue).hasValue('60', 'time value recalculates to fit unit'); assert.ok( changeSpy.calledWithExactly({ enabled: true, seconds: 3600, timeString: '60m', goSafeTimeString: '60m', }), 'Passes the values back to onChange' ); }); test('it skips recalculating time when unit is changed if time is not whole number', async function (assert) { const changeSpy = sinon.spy(); this.set('onChange', changeSpy); await render(hbs` `); assert.dom(selectors.ttlUnit).hasValue('s', 'unit value starts as s (seconds)'); assert.dom(selectors.ttlValue).hasValue('30', 'time value starts as 30'); await fillIn(selectors.ttlUnit, 'm'); assert.dom(selectors.ttlUnit).hasValue('m', 'unit value changed to m (minutes)'); assert.dom(selectors.ttlValue).hasValue('30', 'time value is still 30'); assert.ok( changeSpy.calledWithExactly({ enabled: true, seconds: 1800, timeString: '30m', goSafeTimeString: '30m', }), 'Passes the values back to onChange' ); }); test('it calls onChange on init when changeOnInit is true', async function (assert) { const changeSpy = sinon.spy(); this.set('onChange', changeSpy); await render(hbs` `); assert.ok(changeSpy.calledOnce, 'it calls the passed onChange when rendered'); assert.ok( changeSpy.calledWithExactly({ enabled: true, seconds: 600, timeString: '10m', goSafeTimeString: '10m', }), 'Passes the values back to onChange' ); }); test('it shows a label when passed', async function (assert) { this.set('label', 'My Label'); await render(hbs` `); assert.dom('[data-test-ttl-form-label]').hasText('My Label', 'Renders label correctly'); assert.dom('[data-test-ttl-form-subtext]').doesNotExist('Subtext not rendered'); assert.dom('[data-test-tooltip-trigger]').doesNotExist('Description tooltip not rendered'); }); test('it shows subtext and description when passed', async function (assert) { this.set('label', 'My Label'); await render(hbs` `); assert.dom('[data-test-ttl-form-label]').hasText('My Label', 'Renders label correctly'); assert.dom('[data-test-ttl-form-subtext]').hasText('Subtext', 'Renders subtext when present'); assert .dom('[data-test-tooltip-trigger]') .exists({ count: 1 }, 'Description tooltip icon shows when description present'); }); test('it yields in place of label if block is present', async function (assert) { this.set('label', 'My Label'); await render(hbs` Different Label `); assert.dom('[data-test-custom]').hasText('Different Label', 'custom block is rendered'); assert.dom('[data-test-ttl-form-label]').doesNotExist('Label not rendered'); }); }); module('with toggle', function () { test('it has toggle off by default', async function (assert) { await render(hbs` `); assert.dom(selectors.toggle).isNotChecked('Toggle is unchecked by default'); assert.dom(selectors.ttlFormGroup).doesNotExist('TTL Form is not rendered'); }); test('it shows time and unit inputs when initialEnabled', async function (assert) { const changeSpy = sinon.spy(); this.set('onChange', changeSpy); await render(hbs` `); assert.dom(selectors.toggle).isChecked('Toggle is checked when initialEnabled is true'); assert.dom(selectors.ttlFormGroup).exists('TTL Form is rendered'); assert.ok(changeSpy.notCalled, 'onChange not called because initialValue not parsed'); }); test('it sets initial value to initialValue', async function (assert) { await render(hbs` `); assert.dom(selectors.ttlValue).hasValue('2', 'time value is 2'); assert.dom(selectors.ttlUnit).hasValue('h', 'unit is hours'); assert.ok( this.onChange.notCalled, 'it does not call onChange after render when changeOnInit is not set' ); }); test('it passes the appropriate data to onChange when toggled on', async function (assert) { const changeSpy = sinon.spy(); this.set('onChange', changeSpy); await render(hbs` `); await click(selectors.toggle); assert.ok(changeSpy.calledOnce, 'it calls the passed onChange'); assert.ok( changeSpy.calledWith({ enabled: true, seconds: 600, timeString: '10m', goSafeTimeString: '10m', }), 'Passes the values back to onChange' ); }); test('inputs reflect initial value when toggled on', async function (assert) { await render(hbs` `); assert.dom(selectors.toggle).isNotChecked('Toggle is off'); assert.dom(selectors.ttlFormGroup).doesNotExist('TTL Form not shown on mount'); await click(selectors.toggle); assert.dom(selectors.ttlValue).hasValue('100', 'time after toggle is 100'); assert.dom(selectors.ttlUnit).hasValue('m', 'Unit is minutes after toggle'); }); test('it is enabled on init if initialEnabled is true', async function (assert) { await render(hbs` `); assert.dom(selectors.toggle).isChecked('Toggle is on'); assert.dom(selectors.ttlFormGroup).exists(); assert.dom(selectors.ttlValue).hasValue('100', 'time is shown on mount'); assert.dom(selectors.ttlUnit).hasValue('m', 'Unit is shown on mount'); await click(selectors.toggle); assert.dom(selectors.toggle).isNotChecked('Toggle is off'); assert.dom(selectors.ttlFormGroup).doesNotExist('TTL Form no longer shows after toggle'); }); test('it is enabled on init if initialEnabled evals to truthy', async function (assert) { await render(hbs` `); assert.dom(selectors.toggle).isChecked('Toggle is enabled'); assert.dom(selectors.ttlValue).hasValue('100', 'time value is shown on mount'); assert.dom(selectors.ttlUnit).hasValue('m', 'Unit matches what is passed in'); }); test('it converts days to go safe time', async function (assert) { await render(hbs` `); await click(selectors.toggle); assert.ok(this.onChange.calledOnce, 'it calls the passed onChange'); assert.ok( this.onChange.calledWith({ enabled: true, seconds: 172800, timeString: '2d', goSafeTimeString: '48h', }), 'Converts day unit to go safe time' ); }); test('it converts to the largest round unit on init', async function (assert) { await render(hbs` `); assert.dom(selectors.ttlValue).hasValue('1000', 'time value is converted'); assert.dom(selectors.ttlUnit).hasValue('m', 'unit value is m (minutes)'); }); test('it converts to the largest round unit on init when no unit provided', async function (assert) { await render(hbs` `); assert.dom(selectors.ttlValue).hasValue('1', 'time value is converted'); assert.dom(selectors.ttlUnit).hasValue('d', 'unit value is d (days)'); }); }); });