+ {{input class="input" name="activation-token-id" id="activation-token-id" value=id data-test-replication-secondary-id=true}}
+
+
- {{#if (eq replicationMode "performance")}}
-
- {{/if}}
-
-
-
-
-
- {{#link-to "mode.secondaries" replicationMode class="button"}}
- Cancel
- {{/link-to}}
-
+
+ {{#link-to "mode.secondaries" replicationMode class="button"}}
+ Cancel
+ {{/link-to}}
- {{/if}}
+
+
+{{#if isModalActive}}
+
+
+ This token can be used to enable {{model.replicationModeForDisplay}} replication or change primaries on the secondary cluster.
+
+
Activation token
+
+
+ {{info-table-row
+ label="TTL"
+ value=ttl}}
+ {{info-table-row
+ label="Expires"
+ value=(date-format expirationDate 'MMM DD, YYYY hh:mm:ss A')}}
+
+
+
+
+
+{{/if}}
diff --git a/ui/tests/acceptance/enterprise-replication-test.js b/ui/tests/acceptance/enterprise-replication-test.js
index 97bfa9c6ab1d..cc41e50f73c6 100644
--- a/ui/tests/acceptance/enterprise-replication-test.js
+++ b/ui/tests/acceptance/enterprise-replication-test.js
@@ -4,6 +4,7 @@ import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import authPage from 'vault/tests/pages/auth';
import { pollCluster } from 'vault/tests/helpers/poll-cluster';
+import { dateFormat } from 'core/helpers/date-format';
import { create } from 'ember-cli-page-object';
import flashMessage from 'vault/tests/pages/components/flash-message';
import ss from 'vault/tests/pages/components/search-select';
@@ -17,6 +18,9 @@ const disableReplication = async (type, assert) => {
if (findAll('[data-test-replication-link="manage"]').length) {
await click('[data-test-replication-link="manage"]');
await click('[data-test-disable-replication] button');
+
+ const typeDisplay = type === 'dr' ? 'Disaster Recovery' : 'Performance';
+ await fillIn('[data-test-confirmation-modal-input="disable"]', typeDisplay);
await click('[data-test-confirm-button]');
if (assert) {
assert.equal(currentURL(), `/vault/replication`, 'redirects to the replication page');
@@ -49,6 +53,19 @@ module('Acceptance | Enterprise | replication', function(hooks) {
const mode = 'deny';
let mountPath;
+ // confirm unable to visit dr secondary details page when both replications are disabled
+ await visit('/vault/replication-dr-promote/details');
+ assert.dom('[data-test-component="empty-state"]').exists();
+ assert
+ .dom('[data-test-empty-state-title]')
+ .includesText('Disaster Recovery secondary not set up', 'shows the correct title of the empty state');
+
+ assert.equal(
+ find('[data-test-empty-state-message]').textContent.trim(),
+ 'This cluster has not been enabled as a Disaster Recovery Secondary. You can do so by enabling replication and adding a secondary from the Disaster Recovery Primary.',
+ 'renders default message specific to when no replication is enabled'
+ );
+
await visit('/vault/replication');
assert.equal(currentURL(), '/vault/replication');
@@ -58,6 +75,10 @@ module('Acceptance | Enterprise | replication', function(hooks) {
await click('[data-test-replication-enable]');
await pollCluster(this.owner);
+ await settled();
+
+ // confirm that the details dashboard shows
+ assert.dom('[data-test-replication-dashboard]').exists();
// add a secondary with a mount filter config
await click('[data-test-replication-link="secondaries"]');
@@ -71,7 +92,6 @@ module('Acceptance | Enterprise | replication', function(hooks) {
await click('[data-test-secondary-add]');
await pollCluster(this.owner);
-
// click into the added secondary's mount filter config
await click('[data-test-replication-link="secondaries"]');
await click('[data-test-popup-menu-trigger]');
@@ -104,6 +124,12 @@ module('Acceptance | Enterprise | replication', function(hooks) {
`/vault/replication/performance/secondaries`,
'redirects to the secondaries page'
);
+ // nav back to details page and confirm secondary is in the known secondaries table
+ await click('[data-test-replication-link="details"]');
+ await settled();
+ assert
+ .dom(`[data-test-secondaries=row-for-${secondaryName}]`)
+ .exists('shows a table row the recently added secondary');
// nav to DR
await visit('/vault/replication/dr');
@@ -123,6 +149,15 @@ module('Acceptance | Enterprise | replication', function(hooks) {
await click('button[type="submit"]');
await pollCluster(this.owner);
+ // empty state inside of know secondaries table
+ assert.dom('[data-test-empty-state-title]').exists();
+ assert
+ .dom('[data-test-empty-state-title]')
+ .includesText(
+ 'No known dr secondary clusters associated with this cluster',
+ 'shows the correct title of the empty state'
+ );
+
assert.ok(
find('[data-test-replication-title]').textContent.includes('Disaster Recovery'),
'it displays the replication type correctly'
@@ -136,6 +171,7 @@ module('Acceptance | Enterprise | replication', function(hooks) {
await click('[data-test-replication-link="secondaries"]');
await click('[data-test-secondary-add]');
await fillIn('[data-test-replication-secondary-id]', secondaryName);
+
await click('[data-test-secondary-add]');
await pollCluster(this.owner);
await pollCluster(this.owner);
@@ -149,7 +185,6 @@ module('Acceptance | Enterprise | replication', function(hooks) {
await visit('vault/replication/performance');
// enable perf replication
await fillIn('[data-test-replication-cluster-mode-select]', 'primary');
-
await click('[data-test-replication-enable]');
await pollCluster(this.owner);
@@ -159,6 +194,130 @@ module('Acceptance | Enterprise | replication', function(hooks) {
await click('[data-test-replication-enable]');
await pollCluster(this.owner);
await visit('/vault/replication/dr/manage');
+ await click('[data-test-demote-replication] [data-test-replication-action-trigger]');
assert.ok(findAll('[data-test-demote-warning]').length, 'displays the demotion warning');
});
+
+ test('navigating to dr secondary details page when dr secondary is not enabled', async function(assert) {
+ // enable dr replication
+
+ await visit('/vault/replication/dr');
+ await fillIn('[data-test-replication-cluster-mode-select]', 'primary');
+ await click('[data-test-replication-enable]');
+ await pollCluster(this.owner);
+ await visit('/vault/replication-dr-promote/details');
+
+ assert.dom('[data-test-component="empty-state"]').exists();
+ assert.equal(
+ find('[data-test-empty-state-message]').textContent.trim(),
+ 'This Disaster Recovery secondary has not been enabled. You can do so from the Disaster Recovery Primary.',
+ 'renders message when replication is enabled'
+ );
+ });
+
+ test('add secondary and navigate through token generation modal', async function(assert) {
+ const secondaryName = 'firstSecondary';
+ await visit('/vault/replication');
+
+ // enable perf replication
+ await click('[data-test-replication-type-select="performance"]');
+ await fillIn('[data-test-replication-cluster-mode-select]', 'primary');
+ await click('[data-test-replication-enable]');
+ await pollCluster(this.owner);
+ await settled();
+
+ // add a secondary
+ await click('[data-test-replication-link="secondaries"]');
+ await click('[data-test-secondary-add]');
+ await fillIn('[data-test-replication-secondary-id]', secondaryName);
+ await click('[data-test-secondary-add]');
+ await pollCluster(this.owner);
+
+ // checks on secondary token modal
+ assert.dom('#modal-wormhole').exists();
+ const today = new Date();
+ today.setMinutes(today.getMinutes() + 30); // add default 30 min TTL to current date to return expires
+ const dateFormatted = dateFormat([today, 'MMM DD, YYYY hh:mm:ss A']);
+ const modalDate = document.querySelector('[data-test-row-value="Expires"]').innerText;
+ // because timestamp might be off by a 1 sec due to different in exp from token vs. adding 30 min, checking the string before the seconds.
+ assert.equal(
+ dateFormatted.slice(0, 18),
+ modalDate.slice(0, 18),
+ 'shows the correct expiration date and in the correct format'
+ );
+ // click off the modal to make sure you don't just have to click on the copy-close button to copy the token
+ await click('[data-test-modal-background]');
+ await settled();
+ // confirm you were redirected to the secondaries page
+ assert.equal(
+ currentURL(),
+ `/vault/replication/performance/secondaries`,
+ 'redirects to the secondaries page'
+ );
+ assert
+ .dom('[data-test-secondary-name]')
+ .includesText(secondaryName, 'it displays the secondary in the list of secondaries');
+ });
+
+ test('render performance and dr primary and navigate to details page', async function(assert) {
+ // enable perf primary replication
+ await visit('/vault/replication');
+ await click('[data-test-replication-type-select="performance"]');
+ await fillIn('[data-test-replication-cluster-mode-select]', 'primary');
+ await click('[data-test-replication-enable]');
+ await pollCluster(this.owner);
+ await settled();
+
+ await visit('/vault/replication');
+ assert
+ .dom(`[data-test-replication-summary-card]`)
+ .doesNotExist(`does not render replication summary card when both modes are not enabled as primary`);
+
+ // enable DR primary replication
+ const enableButton = document.querySelector('.is-primary');
+
+ await click(enableButton);
+ await click('[data-test-replication-enable="true"]');
+ await pollCluster(this.owner);
+ await settled();
+
+ // navigate using breadcrumbs back to replication.index
+ await click('[data-test-replication-breadcrumb]');
+ assert
+ .dom('[data-test-replication-summary-card]')
+ .exists({ count: 2 }, 'renders two replication-summary-card components');
+
+ // navigate to details page using the "Details" link
+ await click('[data-test-manage-link="Disaster Recovery"]');
+ assert
+ .dom('[data-test-selectable-card-container="primary"]')
+ .exists('shows the correct card on the details dashboard');
+ assert.equal(currentURL(), '/vault/replication/dr');
+ });
+
+ test('render performance secondary and navigate to the details page', async function(assert) {
+ // enable perf replication
+ await visit('/vault/replication');
+ await click('[data-test-replication-type-select="performance"]');
+ await fillIn('[data-test-replication-cluster-mode-select]', 'primary');
+ await click('[data-test-replication-enable]');
+ await pollCluster(this.owner);
+ await settled();
+
+ // demote perf primary to a secondary
+ await click('[data-test-replication-link="manage"]');
+ // open demote modal
+ await click('[data-test-demote-replication] [data-test-replication-action-trigger]');
+ // enter confirmation text
+ await fillIn('[data-test-confirmation-modal-input="demote"]', 'Performance');
+ // Click confirm button
+ await click('[data-test-confirm-button="demote"]');
+ await click('[data-test-replication-link="details"]');
+ assert.dom('[data-test-replication-dashboard]').exists();
+ assert.dom('[data-test-selectable-card-container="secondary"]').exists();
+ assert.ok(
+ find('[data-test-replication-mode-display]').textContent.includes('secondary'),
+ 'it displays the cluster mode correctly'
+ );
+ });
});
diff --git a/ui/tests/integration/components/confirmation-modal-test.js b/ui/tests/integration/components/confirmation-modal-test.js
new file mode 100644
index 000000000000..88b8c3f6fbd3
--- /dev/null
+++ b/ui/tests/integration/components/confirmation-modal-test.js
@@ -0,0 +1,35 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import sinon from 'sinon';
+import { fillIn, find, render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | confirmation-modal', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders with disabled confirmation button until input matches', async function(assert) {
+ let spy = sinon.spy();
+ this.set('onConfirm', spy);
+
+ await render(hbs`
+
+
+ `);
+
+ assert.dom('[data-test-confirm-button]').isDisabled();
+ assert.equal(
+ find('[data-test-confirm-button]').textContent.trim(),
+ 'Plz Continue',
+ 'Confirm button has specified value'
+ );
+
+ await fillIn('[data-test-confirmation-modal-input="demote"]', 'Destructive Thing');
+ assert.dom('[data-test-confirm-button="demote"]').isNotDisabled();
+ });
+});
diff --git a/ui/tests/integration/components/info-table-test.js b/ui/tests/integration/components/info-table-test.js
new file mode 100644
index 000000000000..4a43476eeef0
--- /dev/null
+++ b/ui/tests/integration/components/info-table-test.js
@@ -0,0 +1,36 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+const TITLE = 'My Table';
+const HEADER = 'Cool Header';
+const ITEMS = ['https://127.0.0.1:8201', 'hello', 3];
+
+module('Integration | Enterprise | Component | InfoTable', function(hooks) {
+ setupRenderingTest(hooks);
+
+ hooks.beforeEach(function() {
+ this.set('title', TITLE);
+ this.set('header', HEADER);
+ this.set('items', ITEMS);
+ });
+
+ test('it renders', async function(assert) {
+ await render(hbs`
`);
+
+ assert.dom('[data-test-info-table]').exists();
+ assert.dom('[data-test-info-table] th').includesText(HEADER, `shows the table header`);
+
+ const rows = document.querySelectorAll('.info-table-row');
+ assert.equal(rows.length, ITEMS.length, 'renders an InfoTableRow for each item');
+
+ rows.forEach((row, i) => {
+ assert.equal(row.innerText, ITEMS[i], 'handles strings and numbers as row values');
+ });
+ });
+});
diff --git a/ui/tests/integration/components/known-secondaries-card-test.js b/ui/tests/integration/components/known-secondaries-card-test.js
new file mode 100644
index 000000000000..47e7e707bf48
--- /dev/null
+++ b/ui/tests/integration/components/known-secondaries-card-test.js
@@ -0,0 +1,68 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import engineResolverFor from 'ember-engines/test-support/engine-resolver-for';
+import hbs from 'htmlbars-inline-precompile';
+const resolver = engineResolverFor('replication');
+
+const CLUSTER = {
+ canAddSecondary: true,
+ replicationMode: 'dr',
+};
+
+const REPLICATION_ATTRS = {
+ secondaries: [
+ { node_id: 'secondary-1', api_address: 'https://stuff.com/', connection_status: 'connected' },
+ { node_id: '2nd', connection_status: 'disconnected' },
+ { node_id: '_three_', api_address: 'https://10.0.0.2:1000/', connection_status: 'connected' },
+ ],
+};
+
+module('Integration | Component | replication known-secondaries-card', function(hooks) {
+ setupRenderingTest(hooks, { resolver });
+
+ hooks.beforeEach(function() {
+ this.set('cluster', CLUSTER);
+ this.set('replicationAttrs', REPLICATION_ATTRS);
+ });
+
+ test('it renders with a table of known secondaries', async function(assert) {
+ await render(hbs`
`);
+
+ assert
+ .dom('[data-test-known-secondaries-table]')
+ .exists('shows known secondaries table when there are known secondaries');
+ assert.dom('[data-test-manage-link]').exists('shows manage link');
+ });
+
+ test('it renders an empty state if there are no known secondaries', async function(assert) {
+ const noSecondaries = {
+ secondaries: [],
+ };
+ this.set('replicationAttrs', noSecondaries);
+ await render(hbs`
`);
+
+ assert
+ .dom('[data-test-known-secondaries-table]')
+ .doesNotExist('does not show the known secondaries table');
+ assert
+ .dom('.empty-state')
+ .includesText('No known dr secondary clusters', 'has a message with the replication mode');
+ });
+
+ test('it renders an Add secondary link if user has capabilites', async function(assert) {
+ await render(hbs`
`);
+
+ assert.dom('.add-secondaries').exists();
+ });
+
+ test('it does not render an Add secondary link if user does not have capabilites', async function(assert) {
+ const noCapabilities = {
+ canAddSecondary: false,
+ };
+ this.set('cluster', noCapabilities);
+ await render(hbs`
`);
+
+ assert.dom('.add-secondaries').doesNotExist();
+ });
+});
diff --git a/ui/tests/integration/components/known-secondaries-table-test.js b/ui/tests/integration/components/known-secondaries-table-test.js
new file mode 100644
index 000000000000..41af54cfb586
--- /dev/null
+++ b/ui/tests/integration/components/known-secondaries-table-test.js
@@ -0,0 +1,60 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import engineResolverFor from 'ember-engines/test-support/engine-resolver-for';
+import hbs from 'htmlbars-inline-precompile';
+const resolver = engineResolverFor('replication');
+
+const SECONDARIES = [
+ { node_id: 'secondary-1', api_address: 'https://127.0.0.1:52304', connection_status: 'connected' },
+ { node_id: '2nd', connection_status: 'disconnected' },
+ { node_id: '_three_', api_address: 'http://127.0.0.1:8202', connection_status: 'connected' },
+];
+
+module('Integration | Component | replication known-secondaries-table', function(hooks) {
+ setupRenderingTest(hooks, { resolver });
+
+ hooks.beforeEach(function() {
+ this.set('secondaries', SECONDARIES);
+ });
+
+ test('it renders a table of known secondaries', async function(assert) {
+ await render(hbs`
`);
+
+ assert.dom('[data-test-known-secondaries-table]').exists();
+ });
+
+ test('it shows the secondary URL and connection_status', async function(assert) {
+ await render(hbs`
`);
+
+ SECONDARIES.forEach(secondary => {
+ assert.equal(
+ this.element.querySelector(`[data-test-secondaries=row-for-${secondary.node_id}]`).innerHTML.trim(),
+ secondary.node_id,
+ 'shows a table row and ID for each known secondary'
+ );
+
+ if (secondary.api_address) {
+ const expectedUrl = `${secondary.api_address}/ui/`;
+
+ assert.equal(
+ this.element.querySelector(`[data-test-secondaries=api-address-for-${secondary.node_id}]`).href,
+ expectedUrl,
+ 'renders a URL to the secondary UI'
+ );
+ } else {
+ assert.notOk(
+ this.element.querySelector(`[data-test-secondaries=api-address-for-${secondary.node_id}]`)
+ );
+ }
+
+ assert.equal(
+ this.element
+ .querySelector(`[data-test-secondaries=connection-status-for-${secondary.node_id}]`)
+ .innerHTML.trim(),
+ secondary.connection_status,
+ 'shows the connection status'
+ );
+ });
+ });
+});
diff --git a/ui/tests/integration/components/modal-test.js b/ui/tests/integration/components/modal-test.js
index e4e9ea878f23..98b3c2cf5d2e 100644
--- a/ui/tests/integration/components/modal-test.js
+++ b/ui/tests/integration/components/modal-test.js
@@ -25,5 +25,18 @@ module('Integration | Component | modal', function(hooks) {
assert.equal(this.element.textContent.trim(), 'template block text', 'renders with interior content');
assert.equal(findAll('[data-test-modal-close-button]').length, 1, 'renders close modal button');
+ assert.dom('[data-test-modal-glyph]').doesNotExist('Glyph is not rendered by default');
+ });
+
+ test('it adds the correct type class', async function(assert) {
+ await render(hbs`
+
+ template block text
+
+
+ `);
+
+ assert.dom('.modal.is-highlight').exists('Modal exists with is-highlight class');
+ assert.dom('[data-test-modal-glyph]').exists('Glyph is rendered');
});
});
diff --git a/ui/tests/integration/components/replication-action-generate-token-test.js b/ui/tests/integration/components/replication-action-generate-token-test.js
new file mode 100644
index 000000000000..a0319cdce0bd
--- /dev/null
+++ b/ui/tests/integration/components/replication-action-generate-token-test.js
@@ -0,0 +1,21 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, find } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | replication-action-generate-token', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders with the expected elements', async function(assert) {
+ await render(hbs`
+
+ {{replication-action-generate-token}}
+ `);
+ assert.equal(find('h4.title').textContent.trim(), 'Generate operation token', 'renders default title');
+ assert.equal(
+ find('[data-test-replication-action-trigger]').textContent.trim(),
+ 'Generate token',
+ 'renders default CTA'
+ );
+ });
+});
diff --git a/ui/tests/integration/components/replication-actions-test.js b/ui/tests/integration/components/replication-actions-test.js
index 309cd51d0517..192784a1b2aa 100644
--- a/ui/tests/integration/components/replication-actions-test.js
+++ b/ui/tests/integration/components/replication-actions-test.js
@@ -39,22 +39,54 @@ module('Integration | Component | replication actions', function(hooks) {
});
let testCases = [
- ['dr', 'primary', 'disable', 'Disable Replication', null, ['disable', 'primary']],
- ['performance', 'primary', 'disable', 'Disable Replication', null, ['disable', 'primary']],
- ['dr', 'secondary', 'disable', 'Disable Replication', null, ['disable', 'secondary']],
- ['performance', 'secondary', 'disable', 'Disable Replication', null, ['disable', 'secondary']],
- ['dr', 'primary', 'recover', 'Recover', null, ['recover']],
- ['performance', 'primary', 'recover', 'Recover', null, ['recover']],
- ['performance', 'secondary', 'recover', 'Recover', null, ['recover']],
+ [
+ 'dr',
+ 'primary',
+ 'disable',
+ 'Disable Replication',
+ async function() {
+ fillIn('[data-test-confirmation-modal-input]', 'Disaster Recovery');
+ },
+ ['disable', 'primary'],
+ false,
+ ],
+ [
+ 'performance',
+ 'primary',
+ 'disable',
+ 'Disable Replication',
+ async function() {
+ fillIn('[data-test-confirmation-modal-input]', 'Performance');
+ },
+ ['disable', 'primary'],
+ false,
+ ],
+ [
+ 'performance',
+ 'secondary',
+ 'disable',
+ 'Disable Replication',
+ async function() {
+ fillIn('[data-test-confirmation-modal-input]', 'Performance');
+ },
+ ['disable', 'secondary'],
+ false,
+ ],
+ ['dr', 'primary', 'recover', 'Recover', null, ['recover'], false],
+ ['performance', 'primary', 'recover', 'Recover', null, ['recover'], false],
+ ['performance', 'secondary', 'recover', 'Recover', null, ['recover'], false],
+
+ ['dr', 'primary', 'reindex', 'Reindex', null, ['reindex'], false],
+ ['performance', 'primary', 'reindex', 'Reindex', null, ['reindex'], false],
+ ['performance', 'secondary', 'reindex', 'Reindex', null, ['reindex'], false],
- ['dr', 'primary', 'reindex', 'Reindex', null, ['reindex']],
- ['performance', 'primary', 'reindex', 'Reindex', null, ['reindex']],
- ['dr', 'secondary', 'reindex', 'Reindex', null, ['reindex']],
- ['performance', 'secondary', 'reindex', 'Reindex', null, ['reindex']],
+ ['dr', 'primary', 'demote', 'Demote cluster', null, ['demote', 'primary'], false],
+ ['performance', 'primary', 'demote', 'Demote cluster', null, ['demote', 'primary'], false],
- ['dr', 'primary', 'demote', 'Demote cluster', null, ['demote', 'primary']],
- ['performance', 'primary', 'demote', 'Demote cluster', null, ['demote', 'primary']],
// we don't do dr secondary promote in this component so just test perf
+ // re-enable this test when the DR secondary disable API endpoint is fixed
+ // ['dr', 'secondary', 'disable', 'Disable Replication', null, ['disable', 'secondary'], false],
+ // ['dr', 'secondary', 'reindex', 'Reindex', null, ['reindex'], false],
[
'performance',
'secondary',
@@ -65,9 +97,8 @@ module('Integration | Component | replication actions', function(hooks) {
await blur('[name="primary_cluster_addr"]');
},
['promote', 'secondary', { primary_cluster_addr: 'cluster addr' }],
+ false,
],
-
- // don't yet update-primary for dr
[
'performance',
'secondary',
@@ -80,10 +111,19 @@ module('Integration | Component | replication actions', function(hooks) {
await blur('#primary_api_addr');
},
['update-primary', 'secondary', { token: 'token', primary_api_addr: 'addr' }],
+ false,
],
];
- for (let [replicationMode, clusterMode, action, headerText, fillInFn, expectedOnSubmit] of testCases) {
+ for (let [
+ replicationMode,
+ clusterMode,
+ action,
+ headerText,
+ fillInFn,
+ expectedOnSubmit,
+ oldVersion,
+ ] of testCases) {
test(`replication mode ${replicationMode}, cluster mode: ${clusterMode}, action: ${action}`, async function(assert) {
const testKey = `${replicationMode}-${clusterMode}-${action}`;
this.set('model', {
@@ -111,16 +151,30 @@ module('Integration | Component | replication actions', function(hooks) {
});
this.set('storeService.capabilitiesReturnVal', ['root']);
await render(
- hbs`{{replication-actions model=model replicationMode=replicationMode selectedAction=selectedAction onSubmit=(action onSubmit)}}`
+ hbs`
+
+ {{replication-actions model=model replicationMode=replicationMode selectedAction=selectedAction onSubmit=(action onSubmit)}}
+ `
);
- assert.equal(find('h4').textContent.trim(), headerText, `${testKey}: renders the correct component`);
+ let selector = oldVersion ? 'h4' : `[data-test-${action}-replication] h4`;
+ assert.equal(
+ find(selector).textContent.trim(),
+ headerText,
+ `${testKey}: renders the correct component header (${oldVersion})`
+ );
- if (typeof fillInFn === 'function') {
- await fillInFn.call(this);
+ if (oldVersion) {
+ await click('[data-test-confirm-action-trigger]');
+ await click('[data-test-confirm-button]');
+ } else {
+ await click('[data-test-replication-action-trigger]');
+ if (typeof fillInFn === 'function') {
+ await fillInFn.call(this);
+ }
+ await blur('[data-test-confirmation-modal-input]');
+ await click('[data-test-confirm-button]');
}
- await click('[data-test-confirm-action-trigger]');
- await click('[data-test-confirm-button]');
});
}
});
diff --git a/ui/tests/integration/components/replication-dashboard-test.js b/ui/tests/integration/components/replication-dashboard-test.js
new file mode 100644
index 000000000000..b1a6ff94dcd9
--- /dev/null
+++ b/ui/tests/integration/components/replication-dashboard-test.js
@@ -0,0 +1,198 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import { assign } from '@ember/polyfills';
+import hbs from 'htmlbars-inline-precompile';
+
+const REPLICATION_DETAILS = {
+ state: 'stream-wals',
+ primaryClusterAddr: 'https://127.0.0.1:8201',
+ merkleRoot: '352f6e58ba2e8ec3935e05da1d142653dc76fe17',
+ clusterId: '68999e13-a09d-b5e4-d66c-b35da566a177',
+};
+
+const IS_SYNCING = {
+ state: 'merkle-diff',
+ primaryClusterAddr: 'https://127.0.0.1:8201',
+};
+
+const IS_REINDEXING = {
+ reindex_building_progress: 26838,
+ reindex_building_total: 305443,
+ reindex_in_progress: true,
+ reindex_stage: 'building',
+ state: 'running',
+};
+
+module('Integration | Enterprise | Component | replication-dashboard', function(hooks) {
+ setupRenderingTest(hooks);
+
+ hooks.beforeEach(function() {
+ this.set('replicationDetails', REPLICATION_DETAILS);
+ this.set('clusterMode', 'secondary');
+ this.set('isSecondary', true);
+ });
+
+ test('it renders', async function(assert) {
+ await render(hbs`
`);
+
+ assert.dom('[data-test-replication-dashboard]').exists();
+ assert.dom('[data-test-table-rows').exists();
+ assert.dom('[data-test-selectable-card-container="secondary"]').exists();
+ assert.dom('[data-test-replication-doc-link]').exists();
+ assert.dom('[data-test-flash-message]').doesNotExist('no flash message is displayed on render');
+ });
+
+ test('it updates the dashboard when the replication mode has changed', async function(assert) {
+ await render(hbs`
`);
+
+ assert.dom('[data-test-selectable-card-container="secondary"]').exists();
+ assert.dom('[data-test-selectable-card-container="primary"]').doesNotExist();
+
+ this.set('clusterMode', 'primary');
+ this.set('isSecondary', false);
+
+ assert.dom('[data-test-selectable-card-container="primary"]').exists();
+ assert.dom('[data-test-selectable-card-container="secondary"]').doesNotExist();
+ });
+
+ test('it renders the primary selectable-card-container when the cluster is a primary', async function(assert) {
+ this.set('isSecondary', false);
+
+ await render(hbs`
`);
+
+ assert.dom('[data-test-selectable-card-container="primary"]').exists();
+ assert.dom('[data-test-selectable-card-container="secondary"]').doesNotExist();
+ });
+
+ test('it renders an alert banner if the dashboard is syncing', async function(assert) {
+ this.set('replicationDetails', IS_SYNCING);
+
+ await render(hbs`
`);
+
+ assert.dom('[data-test-isSyncing]').exists();
+ assert
+ .dom('[data-test-isReindexing]')
+ .doesNotExist('does not show reindexing banner if cluster is cluster is not reindexing');
+ });
+
+ test('it shows an alert banner if the cluster is reindexing', async function(assert) {
+ this.set('replicationDetails', IS_REINDEXING);
+
+ await render(hbs`
`);
+
+ assert.dom('[data-test-isReindexing]').exists();
+ assert.dom('.message-title').includesText('Building', 'shows reindexing stage if there is one');
+ assert
+ .dom('.message-title>.progress')
+ .hasValue(
+ IS_REINDEXING.reindex_building_progress,
+ 'shows the reindexing progress inside the alert banner'
+ );
+
+ const reindexingInProgress = assign({}, IS_REINDEXING, { reindex_building_progress: 27000 });
+ this.set('replicationDetails', reindexingInProgress);
+
+ assert
+ .dom('.message-title>.progress')
+ .hasValue(reindexingInProgress.reindex_building_progress, 'updates the reindexing progress');
+ });
+
+ test('it renders replication-summary-card when isSummaryDashboard', async function(assert) {
+ const replicationDetailsSummary = {
+ dr: {
+ state: 'running',
+ lastWAL: 10,
+ knownSecondaries: ['https://127.0.0.1:8201', 'https://127.0.0.1:8202'],
+ },
+ performance: {
+ state: 'running',
+ lastWAL: 20,
+ knownSecondaries: ['https://127.0.0.1:8201'],
+ },
+ };
+ this.set('replicationDetails', REPLICATION_DETAILS);
+ this.set('replicationDetailsSummary', replicationDetailsSummary);
+ this.set('isSummaryDashboard', true);
+ this.set('clusterMode', 'primary');
+ this.set('isSecondary', false);
+
+ await render(hbs`
`);
+
+ assert.dom('.summary-state').exists('it renders the summary dashboard');
+ assert
+ .dom('[data-test-summary-state]')
+ .includesText(replicationDetailsSummary.dr.state, 'shows the correct state value');
+ assert.dom('[data-test-icon]').exists('shows an icon if state is ok');
+ assert
+ .dom('[data-test-selectable-card-container-summary]')
+ .exists('it renders with the correct selectable card container');
+ assert.dom('[data-test-selectable-card-container-primary]').doesNotExist();
+ });
+
+ test('it renders replication-summary-card with an error message when the state is not OK', async function(assert) {
+ const replicationDetailsSummary = {
+ dr: {
+ state: 'shutdown',
+ lastWAL: 10,
+ knownSecondaries: ['https://127.0.0.1:8201', 'https://127.0.0.1:8202'],
+ },
+ performance: {
+ state: 'shutdown',
+ lastWAL: 20,
+ knownSecondaries: ['https://127.0.0.1:8201'],
+ },
+ };
+ this.set('replicationDetails', REPLICATION_DETAILS);
+ this.set('replicationDetailsSummary', replicationDetailsSummary);
+ this.set('isSummaryDashboard', true);
+ this.set('clusterMode', 'primary');
+ this.set('isSecondary', false);
+
+ await render(hbs`
`);
+
+ assert.dom('[data-test-error]').includesText('state', 'show correct error title');
+ assert
+ .dom('[data-test-inline-error-message]')
+ .includesText(
+ ' The cluster is shutdown. Please check your server logs.',
+ 'show correct error message'
+ );
+ });
+});
diff --git a/ui/tests/integration/components/replication-header-test.js b/ui/tests/integration/components/replication-header-test.js
new file mode 100644
index 000000000000..356b67c01b8b
--- /dev/null
+++ b/ui/tests/integration/components/replication-header-test.js
@@ -0,0 +1,64 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+const DATA = {
+ anyReplicationEnabled: true,
+ dr: {
+ mode: 'secondary',
+ rm: {
+ mode: 'dr',
+ },
+ },
+ unsealed: 'good',
+};
+
+const TITLE = 'Disaster Recovery';
+const SECONDARY_ID = '123abc';
+
+module('Integration | Enterprise | Component | replication-header', function(hooks) {
+ setupRenderingTest(hooks);
+
+ hooks.beforeEach(function() {
+ this.set('data', DATA);
+ this.set('title', TITLE);
+ this.set('isSecondary', true);
+ this.set('secondaryId', SECONDARY_ID);
+ });
+
+ test('it renders', async function(assert) {
+ await render(hbs`
`);
+
+ assert.dom('[data-test-replication-header]').exists();
+ });
+
+ test('it renders with mode and secondaryId when set', async function(assert) {
+ await render(
+ hbs`
`
+ );
+
+ assert.dom('[data-test-secondaryId]').includesText(SECONDARY_ID, `shows the correct secondaryId value`);
+ assert.dom('[data-test-mode]').includesText('secondary', `shows the correct mode value`);
+ });
+
+ test('it does not render mode or secondaryId when replication is not enabled', async function(assert) {
+ const notEnabled = { anyReplicationEnabled: false };
+ const noId = null;
+ this.set('data', notEnabled);
+ this.set('secondaryId', noId);
+
+ await render(
+ hbs`
`
+ );
+
+ assert.dom('[data-test-secondaryId]').doesNotExist();
+ assert.dom('[data-test-mode]').doesNotExist();
+ });
+
+ test('it does not show tabs when showTabs is not set', async function(assert) {
+ await render(hbs`
`);
+
+ assert.dom('[data-test-tabs]').doesNotExist();
+ });
+});
diff --git a/ui/tests/integration/components/replication-page-test.js b/ui/tests/integration/components/replication-page-test.js
new file mode 100644
index 000000000000..17b1688b93cb
--- /dev/null
+++ b/ui/tests/integration/components/replication-page-test.js
@@ -0,0 +1,38 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+const MODEL = {
+ replicationMode: 'dr',
+ replicationAttrs: {
+ mode: 'secondary',
+ clusterId: '12ab',
+ replicationDisabled: false,
+ },
+};
+
+module('Integration | Enterprise | Component | replication-page', function(hooks) {
+ setupRenderingTest(hooks);
+
+ hooks.beforeEach(function() {
+ this.set('model', MODEL);
+ });
+
+ test('it renders', async function(assert) {
+ await render(hbs`
`);
+ assert.dom('[data-test-replication-page]').exists();
+ assert.dom('[data-test-layout-loading]').doesNotExist();
+ });
+
+ test('it renders loader when either clusterId is unknown or mode is bootstrapping', async function(assert) {
+ this.set('model.replicationAttrs.clusterId', '');
+ await render(hbs`
`);
+ assert.dom('[data-test-layout-loading]').exists();
+
+ this.set('model.replicationAttrs.clusterId', '123456');
+ this.set('model.replicationAttrs.mode', 'bootstrapping');
+ await render(hbs`
`);
+ assert.dom('[data-test-layout-loading]').exists();
+ });
+});
diff --git a/ui/tests/integration/components/replication-primary-card-test.js b/ui/tests/integration/components/replication-primary-card-test.js
new file mode 100644
index 000000000000..2345657b90ae
--- /dev/null
+++ b/ui/tests/integration/components/replication-primary-card-test.js
@@ -0,0 +1,55 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import engineResolverFor from 'ember-engines/test-support/engine-resolver-for';
+import { CLUSTER_STATES } from 'core/helpers/cluster-states';
+import hbs from 'htmlbars-inline-precompile';
+const resolver = engineResolverFor('replication');
+
+module('Integration | Component | replication-primary-card', function(hooks) {
+ setupRenderingTest(hooks, { resolver });
+
+ test('it renders', async function(assert) {
+ const title = 'Last WAL';
+ const description = 'WALL-E';
+ const metric = '3000';
+
+ this.set('title', title);
+ this.set('description', description);
+ this.set('metric', metric);
+
+ await render(hbs`
+
`);
+
+ assert.dom('[data-test-hasError]').doesNotExist('shows no error for non-State cards');
+
+ assert.dom('.last-wal').includesText(title);
+ assert.dom('[data-test-description]').includesText(description);
+ assert.dom('[data-test-metric]').includesText(metric);
+ });
+
+ Object.keys(CLUSTER_STATES).forEach(state => {
+ test(`it renders a card when cluster has the ${state} state`, async function(assert) {
+ this.set('glyph', CLUSTER_STATES[state].glyph);
+ this.set('state', state);
+
+ await render(hbs`
+
`);
+
+ if (CLUSTER_STATES[state].isOk) {
+ assert.dom('[data-test-hasError]').doesNotExist();
+ assert.dom('[data-test-icon]').exists('shows an icon if state is ok');
+ } else {
+ assert.dom('[data-test-hasError]').exists('shows an error if the cluster state is not ok');
+ assert.dom('[data-test-icon]').doesNotExist('does not show an icon if state is not ok');
+ }
+ });
+ });
+});
diff --git a/ui/tests/integration/components/replication-secondary-card-test.js b/ui/tests/integration/components/replication-secondary-card-test.js
new file mode 100644
index 000000000000..e72ed15c7c9e
--- /dev/null
+++ b/ui/tests/integration/components/replication-secondary-card-test.js
@@ -0,0 +1,92 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+const TITLE = 'Status';
+
+const REPLICATION_DETAILS = {
+ state: 'stream-wals',
+ connection_state: 'ready',
+ lastRemoteWAL: 10,
+};
+
+const KNOWN_PRIMARY_CLUSTER_DETAILS = {
+ knownPrimaryClusterAddrs: ['https://127.0.0.1:8201', 'https://127.0.0.1:8202'],
+};
+
+const STATE_ERROR = {
+ state: 'idle',
+ connection_state: 'ready',
+ lastRemoteWAL: 10,
+};
+
+const CONNECTION_ERROR = {
+ state: 'stream-wals',
+ connection_state: 'transient_failure',
+ lastRemoteWAL: 10,
+};
+
+module('Integration | Enterprise | Component | replication-secondary-card', function(hooks) {
+ setupRenderingTest(hooks);
+
+ hooks.beforeEach(function() {
+ this.set('replicationDetails', REPLICATION_DETAILS);
+ this.set('title', TITLE);
+ });
+
+ test('it renders', async function(assert) {
+ await render(
+ hbs`
`
+ );
+ assert.dom('[data-test-replication-secondary-card]').exists();
+ assert.dom('[data-test-state]').includesText(REPLICATION_DETAILS.state, `shows the correct state value`);
+ assert
+ .dom('[data-test-connection]')
+ .includesText(REPLICATION_DETAILS.connection_state, `shows the correct connection value`);
+ });
+
+ test('it renders with knownPrimaryClusterAddrs set when title is not Status', async function(assert) {
+ this.set('replicationDetails', KNOWN_PRIMARY_CLUSTER_DETAILS);
+ await render(
+ hbs`
`
+ );
+ assert.dom('[data-test-info-table]').exists();
+ });
+
+ test('it renders with emptyState if no knownPrimaryClusterAddrs are set', async function(assert) {
+ this.set('replicationDetails', []);
+ await render(
+ hbs`
`
+ );
+ assert.dom('[data-test-component="empty-state"]').exists();
+ });
+
+ test('it renders tooltip with check-circle-outline when state is stream-wals', async function(assert) {
+ await render(
+ hbs`
`
+ );
+ assert.dom('[data-test-glyph]').hasClass('has-text-success', `shows success icon`);
+ });
+
+ test('it renders hasErrorMessage when state is idle', async function(assert) {
+ this.set('stateError', STATE_ERROR);
+ await render(hbs`
`);
+ assert.dom('[data-test-error]').includesText('state', 'show correct error title');
+ assert
+ .dom('[data-test-inline-error-message]')
+ .includesText('Please check your server logs.', 'show correct error message');
+ });
+
+ test('it renders hasErrorMessage when connection is transient_failure', async function(assert) {
+ this.set('connectionError', CONNECTION_ERROR);
+ await render(hbs`
`);
+ assert.dom('[data-test-error]').includesText('connection_state', 'show correct error title');
+ assert
+ .dom('[data-test-inline-error-message]')
+ .includesText(
+ 'There has been some transient failure. Your cluster will eventually switch back to connection and try to establish a connection again.',
+ 'show correct error message'
+ );
+ });
+});
diff --git a/ui/tests/integration/components/replication-summary-card-test.js b/ui/tests/integration/components/replication-summary-card-test.js
new file mode 100644
index 000000000000..3a11fac69964
--- /dev/null
+++ b/ui/tests/integration/components/replication-summary-card-test.js
@@ -0,0 +1,55 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+const TITLE = 'Disaster Recovery';
+
+const REPLICATION_DETAILS = {
+ dr: {
+ state: 'running',
+ lastWAL: 10,
+ knownSecondaries: ['https://127.0.0.1:8201', 'https://127.0.0.1:8202'],
+ },
+ performance: {
+ state: 'running',
+ lastWAL: 20,
+ knownSecondaries: ['https://127.0.0.1:8201'],
+ },
+};
+
+module('Integration | Enterprise | Component | replication-summary-card', function(hooks) {
+ setupRenderingTest(hooks);
+
+ hooks.beforeEach(function() {
+ this.set('replicationDetails', REPLICATION_DETAILS);
+ this.set('title', TITLE);
+ });
+
+ test('it renders', async function(assert) {
+ await render(hbs`
`);
+ assert.dom('[data-test-replication-summary-card]').exists();
+ assert
+ .dom('[data-test-lastWAL]')
+ .includesText(REPLICATION_DETAILS.dr.lastWAL, `shows the correct lastWAL value`);
+
+ const knownSecondaries = REPLICATION_DETAILS.dr.knownSecondaries.length;
+ assert
+ .dom('[data-test-known-secondaries]')
+ .includesText(knownSecondaries, `shows the correct computed value of the known secondaries count`);
+ });
+
+ test('it shows the correct lastWAL and knownSecondaries when title is Performance', async function(assert) {
+ await render(
+ hbs`
`
+ );
+ assert
+ .dom('[data-test-lastWAL]')
+ .includesText(REPLICATION_DETAILS.performance.lastWAL, `shows the correct lastWAL value`);
+
+ const knownSecondaries = REPLICATION_DETAILS.performance.knownSecondaries.length;
+ assert
+ .dom('[data-test-known-secondaries]')
+ .includesText(knownSecondaries, `shows the correct computed value of the known secondaries count`);
+ });
+});
diff --git a/ui/tests/integration/components/replication-table-rows-test.js b/ui/tests/integration/components/replication-table-rows-test.js
new file mode 100644
index 000000000000..be564c17f00b
--- /dev/null
+++ b/ui/tests/integration/components/replication-table-rows-test.js
@@ -0,0 +1,57 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+const REPLICATION_DETAILS = {
+ clusterId: 'b829d963-6835-33eb-a903-57376024b97a',
+ merkleRoot: 'c21c8428a0a06135cef6ae25bf8e0267ff1592a6',
+};
+
+const CLUSTER_MODE = 'primary';
+
+module('Integration | Component | replication-table-rows', function(hooks) {
+ setupRenderingTest(hooks);
+
+ hooks.beforeEach(function() {
+ this.set('replicationDetails', REPLICATION_DETAILS);
+ this.set('clusterMode', CLUSTER_MODE);
+ });
+
+ test('it renders', async function(assert) {
+ await render(
+ hbs`
`
+ );
+ assert.dom('[data-test-table-rows]').exists();
+ });
+
+ test('it renders with merkle root, mode, replication set', async function(assert) {
+ await render(
+ hbs`
`
+ );
+ assert.dom('.empty-state').doesNotExist('does not show empty state when data is found');
+
+ assert
+ .dom('[data-test-row-value="Merkle root index"]')
+ .includesText(REPLICATION_DETAILS.merkleRoot, `shows the correct Merkle Root`);
+ assert.dom('[data-test-row-value="Mode"]').includesText(CLUSTER_MODE, `shows the correct Mode`);
+ assert
+ .dom('[data-test-row-value="Replication set"]')
+ .includesText(REPLICATION_DETAILS.clusterId, `shows the correct Cluster ID`);
+ });
+
+ test('it renders unknown if values cannot be found', async function(assert) {
+ const noAttrs = {
+ clusterId: null,
+ merkleRoot: null,
+ };
+ const clusterMode = null;
+ this.set('replicationDetails', noAttrs);
+ this.set('clusterMode', clusterMode);
+ await render(
+ hbs`
`
+ );
+
+ assert.dom('[data-test-table-rows]').includesText('unknown');
+ });
+});
diff --git a/ui/tests/integration/components/shamir-modal-flow-test.js b/ui/tests/integration/components/shamir-modal-flow-test.js
new file mode 100644
index 000000000000..6a5f3d051c48
--- /dev/null
+++ b/ui/tests/integration/components/shamir-modal-flow-test.js
@@ -0,0 +1,100 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, find } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+import sinon from 'sinon';
+
+module('Integration | Component | shamir-modal-flow', function(hooks) {
+ setupRenderingTest(hooks);
+
+ hooks.beforeEach(function() {
+ this.set('isActive', true);
+ this.set('onClose', sinon.spy());
+ });
+
+ test('it renders with initial content by default', async function(assert) {
+ await render(hbs`
+
+
+ Inner content goes here
+
+ `);
+
+ assert.equal(
+ find('[data-test-shamir-modal-body]').textContent.trim(),
+ 'Inner content goes here',
+ 'Template block gets rendered'
+ );
+ assert.equal(
+ find('[data-test-shamir-modal-cancel-button]').textContent.trim(),
+ 'Cancel',
+ 'Shows cancel button'
+ );
+ });
+
+ test('Shows correct content when started', async function(assert) {
+ await render(hbs`
+
+
+ Inner content goes here
+
+ `);
+ assert.dom('[data-test-shamir-input]').exists('Asks for Master Key Portion');
+ assert.equal(
+ find('[data-test-shamir-modal-cancel-button]').textContent.trim(),
+ 'Cancel',
+ 'Shows cancel button'
+ );
+ });
+
+ test('Shows OTP when provided and flow started', async function(assert) {
+ await render(hbs`
+
+
+ Inner content goes here
+
+ `);
+ assert.equal(
+ find('[data-test-shamir-encoded-token]').textContent,
+ 'my-encoded-token',
+ 'Shows encoded token'
+ );
+ assert.equal(
+ find('[data-test-shamir-modal-cancel-button]').textContent.trim(),
+ 'Close',
+ 'Shows close button'
+ );
+ });
+ /*
+ test('DR Secondary actions', async function (assert) {
+ // DR Secondaries cannot be tested yet, but once they can
+ // we should add tests for Cancel button functionality
+ })
+ */
+});
diff --git a/ui/tests/integration/helpers/date-format-test.js b/ui/tests/integration/helpers/date-format-test.js
index 17ead5022c16..bb2fd33cc208 100644
--- a/ui/tests/integration/helpers/date-format-test.js
+++ b/ui/tests/integration/helpers/date-format-test.js
@@ -1,27 +1,37 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
-import { dateFormat } from '../../../helpers/date-format';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
module('Integration | Helper | date-format', function(hooks) {
setupRenderingTest(hooks);
- test('it is able to format a date object', function(assert) {
+ test('it is able to format a date object', async function(assert) {
let today = new Date();
- let result = dateFormat([today, 'YYYY']);
- assert.ok(typeof result === 'string');
- assert.ok(result !== 'Invalid Date', 'it is not an invalid date');
- assert.ok(Number(result) >= 2017);
+ this.set('today', today);
+
+ await render(hbs`
Date: {{date-format today "YYYY"}}
`);
+ assert
+ .dom('[data-test-date-format]')
+ .includesText(today.getFullYear(), 'it renders the date in the year format');
});
- test('it supports date timestamps', function(assert) {
+ test('it supports date timestamps', async function(assert) {
let today = new Date().getTime();
- let result = dateFormat([today, 'YYYY']);
- assert.ok(Number(result) >= 2017);
+ this.set('today', today);
+
+ await render(hbs`
{{date-format today 'hh:mm:ss'}}
`);
+ let formattedDate = document.querySelector('.date-format').innerText;
+ assert.ok(formattedDate.match(/^\d{2}:\d{2}:\d{2}$/));
});
- test('it supports date strings', function(assert) {
- let today = new Date().toString();
- let result = dateFormat([today, 'YYYY']);
- assert.ok(Number(result) >= 2017);
+ test('it supports date strings', async function(assert) {
+ let todayString = new Date().getFullYear().toString();
+ this.set('todayString', todayString);
+
+ await render(hbs`
Date: {{date-format todayString}}
`);
+ assert
+ .dom('[data-test-date-format]')
+ .includesText(todayString, 'it renders the a date if passed in as a string');
});
});