mirror of
https://github.com/hashicorp/vault.git
synced 2026-05-11 07:16:28 +02:00
* use "redirect" instead of "afterModel" * fix styling of radio group buttons * remove redundant route redirect * wrap mount dropdown in loading conditional * reuse parent redirect logic, delete unused outlet * minor padding adjustments * force restart tests Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
This commit is contained in:
parent
3886debfa1
commit
0400a442c0
@ -8,9 +8,24 @@
|
||||
@subtitle="Recover lost or deleted data from a raft snapshot. Supported data includes KV v1 and Cubbyhole secrets or Database static roles."
|
||||
/>
|
||||
|
||||
{{! Currently, only a single snapshot is supported. In the future, this may change to support multiple loaded snapshots
|
||||
and a LIST view will be used then. }}
|
||||
{{#unless @model.snapshots}}
|
||||
{{#if @model.showCommunityMessage}}
|
||||
<EmptyState
|
||||
@title="Secrets Recovery is an enterprise feature"
|
||||
@icon="sync-reverse"
|
||||
@message="Secrets Recovery allows you to restore accidentally deleted or lost secrets from a snapshot. The snapshots can be provided via upload or loaded from external storage."
|
||||
>
|
||||
<Hds::Button
|
||||
@text="Learn more about upgrading"
|
||||
@color="tertiary"
|
||||
@icon="docs-link"
|
||||
@iconPosition="trailing"
|
||||
@href={{doc-link "/vault/docs/enterprise"}}
|
||||
@isHrefExternal={{true}}
|
||||
/>
|
||||
</EmptyState>
|
||||
{{else if (not @model.snapshots)}}
|
||||
{{! Currently, only a single snapshot is supported and the UI automatically redirects users to "recovery.snapshots.snapshot.manage" if one exists.
|
||||
In the future, this may change to support multiple loaded snapshots and a LIST view will be built then. }}
|
||||
{{#let (get this.emptyStateDetails this.state) as |d|}}
|
||||
<EmptyState @title={{d.title}} @icon={{d.icon}} @message={{d.message}}>
|
||||
|
||||
@ -30,4 +45,4 @@ and a LIST view will be used then. }}
|
||||
{{/if}}
|
||||
</EmptyState>
|
||||
{{/let}}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
@ -7,10 +7,8 @@ import Component from '@glimmer/component';
|
||||
import { service } from '@ember/service';
|
||||
|
||||
import type NamespaceService from 'vault/services/namespace';
|
||||
import type VersionService from 'vault/services/version';
|
||||
|
||||
enum State {
|
||||
COMMUNITY_VERSION = 'community',
|
||||
NON_ROOT_NAMESPACE = 'non-root-namespace',
|
||||
ALLOW_UPLOAD = 'default',
|
||||
CANNOT_UPLOAD = 'cannot-upload',
|
||||
@ -21,22 +19,11 @@ interface Args {
|
||||
}
|
||||
|
||||
export default class Index extends Component<Args> {
|
||||
@service declare readonly version: VersionService;
|
||||
@service declare readonly namespace: NamespaceService;
|
||||
|
||||
viewState = State;
|
||||
|
||||
emptyStateDetails = {
|
||||
[this.viewState.COMMUNITY_VERSION]: {
|
||||
title: 'Secrets Recovery is an enterprise feature',
|
||||
icon: 'sync-reverse',
|
||||
message:
|
||||
'Secrets Recovery allows you to restore accidentally deleted or lost secrets from a snapshot. The snapshots can be provided via upload or loaded from external storage.',
|
||||
buttonText: 'Learn more about upgrading',
|
||||
buttonHref: '/vault/docs/enterprise',
|
||||
buttonIcon: 'docs-link',
|
||||
buttonColor: 'tertiary',
|
||||
},
|
||||
[this.viewState.NON_ROOT_NAMESPACE]: {
|
||||
title: 'Snapshot upload is restricted',
|
||||
icon: 'sync-reverse',
|
||||
@ -70,9 +57,7 @@ export default class Index extends Component<Args> {
|
||||
get state() {
|
||||
const { canLoadSnapshot } = this.args.model;
|
||||
|
||||
if (this.version.isCommunity) {
|
||||
return this.viewState.COMMUNITY_VERSION;
|
||||
} else if (!this.namespace.inRootNamespace) {
|
||||
if (!this.namespace.inRootNamespace) {
|
||||
return this.viewState.NON_ROOT_NAMESPACE;
|
||||
} else if (!canLoadSnapshot) {
|
||||
return this.viewState.CANNOT_UPLOAD;
|
||||
|
||||
@ -14,13 +14,11 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<form {{on "submit" this.loadSnapshot}}>
|
||||
<Hds::Form::Legend>
|
||||
Choose how to provide the snapshot
|
||||
</Hds::Form::Legend>
|
||||
<div class="has-top-padding-s">
|
||||
<Hds::Form::Radio::Field
|
||||
name="data-center-radio"
|
||||
<form {{on "submit" this.loadSnapshot}} class="has-top-margin-xl">
|
||||
<Hds::Form::Radio::Group @name="snapshot-load-method" as |G|>
|
||||
<G.Legend>Choose how to provide the snapshot</G.Legend>
|
||||
<G.RadioField
|
||||
name={{this.loadMethods.AUTOMATED}}
|
||||
checked={{eq this.selectedLoadMethod this.loadMethods.AUTOMATED}}
|
||||
disabled={{eq @model.configError.status 404}}
|
||||
@value={{this.loadMethods.AUTOMATED}}
|
||||
@ -43,11 +41,9 @@
|
||||
<F.HelperText>
|
||||
Provide the snapshot URL from a configured cloud storage
|
||||
</F.HelperText>
|
||||
</Hds::Form::Radio::Field>
|
||||
</div>
|
||||
<div class="has-top-padding-s has-bottom-padding-m">
|
||||
<Hds::Form::Radio::Field
|
||||
name="data-center-radio"
|
||||
</G.RadioField>
|
||||
<G.RadioField
|
||||
name={{this.loadMethods.MANUAL}}
|
||||
checked={{eq this.selectedLoadMethod this.loadMethods.MANUAL}}
|
||||
@value={{this.loadMethods.MANUAL}}
|
||||
{{on "change" this.selectLoadMethod}}
|
||||
@ -58,9 +54,11 @@
|
||||
<F.HelperText>
|
||||
Upload a new snapshot to the disk
|
||||
</F.HelperText>
|
||||
</Hds::Form::Radio::Field>
|
||||
</div>
|
||||
<div class="has-left-padding-l">
|
||||
</G.RadioField>
|
||||
|
||||
</Hds::Form::Radio::Group>
|
||||
|
||||
<div class="has-top-margin-l has-left-padding-l">
|
||||
|
||||
{{#if (eq this.selectedLoadMethod this.loadMethods.AUTOMATED)}}
|
||||
<div class="has-bottom-padding-m">
|
||||
@ -76,7 +74,13 @@
|
||||
>
|
||||
<F.Label>Snapshot configuration name</F.Label>
|
||||
<F.HelperText>
|
||||
Name of the configuration that created the snapshot. Existing automated snapshots should be configured via /sys
|
||||
Name of the configuration that created the snapshot. Existing automated snapshots should be configured via the
|
||||
<Hds::Link::Inline
|
||||
@href={{doc-link
|
||||
"/vault/api-docs/system/storage/raftautosnapshots#create-update-an-automated-snapshots-config"
|
||||
}}
|
||||
@isHrefExternal={{true}}
|
||||
>automated snapshots config</Hds::Link::Inline>
|
||||
endpoint.
|
||||
</F.HelperText>
|
||||
<F.Options>{{F.options}}</F.Options>
|
||||
@ -94,7 +98,13 @@
|
||||
>
|
||||
<F.Label>Snapshot configuration name</F.Label>
|
||||
<F.HelperText>
|
||||
Name of the configuration that created the snapshot. Existing automated snapshots should be configured via /sys
|
||||
Name of the configuration that created the snapshot. Existing automated snapshots should be configured via the
|
||||
<Hds::Link::Inline
|
||||
@href={{doc-link
|
||||
"/vault/api-docs/system/storage/raftautosnapshots#create-update-an-automated-snapshots-config"
|
||||
}}
|
||||
@isHrefExternal={{true}}
|
||||
>automated snapshots config</Hds::Link::Inline>
|
||||
endpoint.
|
||||
</F.HelperText>
|
||||
{{#if this.configError}}
|
||||
@ -123,7 +133,7 @@
|
||||
</div>
|
||||
{{else}}
|
||||
<FileToArrayBuffer
|
||||
class="hsa-left-padding-l"
|
||||
class="has-left-padding-l"
|
||||
@error={{this.fileError}}
|
||||
@label="Please choose a snapshot file"
|
||||
@onChange={{fn (mut this.file)}}
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
<hr class="has-background-gray-300" />
|
||||
|
||||
<Hds::Text::Display @tag="h3" class="has-top-padding-m">Recover or read data</Hds::Text::Display>
|
||||
<Hds::Text::Display @tag="h3" class="has-top-padding-m has-bottom-margin-l">Recover or read data</Hds::Text::Display>
|
||||
{{#if this.recoveryData}}
|
||||
<Hds::Alert @type="inline" @color="success" class="has-top-margin-m has-bottom-margin-m" data-test-inline-alert as |A|>
|
||||
<A.Title>Success</A.Title>
|
||||
@ -82,6 +82,7 @@
|
||||
{{/if}}
|
||||
|
||||
{{! Allow for manual entry of mount paths if no mounts are returned (such as when the user does not have LIST permissions) }}
|
||||
{{!-- {{#if (or this.mountOptions this.fetchMounts.isRunning)}} --}}
|
||||
{{#if this.mountOptions}}
|
||||
<Hds::Form::SuperSelect::Single::Field
|
||||
@onChange={{this.handleSelectMount}}
|
||||
|
||||
@ -11,7 +11,7 @@ import type ApiService from 'vault/services/api';
|
||||
import type Capabilities from 'vault/services/capabilities';
|
||||
import type { ModelFrom } from 'vault/vault/route';
|
||||
import type RouterService from '@ember/routing/router-service';
|
||||
import type Transition from '@ember/routing/transition';
|
||||
import type VersionService from 'vault/services/version';
|
||||
|
||||
export type SnapshotsRouteModel = ModelFrom<RecoverySnapshotsRoute>;
|
||||
|
||||
@ -19,24 +19,26 @@ export default class RecoverySnapshotsRoute extends Route {
|
||||
@service declare readonly api: ApiService;
|
||||
@service declare readonly capabilities: Capabilities;
|
||||
@service declare readonly router: RouterService;
|
||||
@service declare readonly version: VersionService;
|
||||
|
||||
async model() {
|
||||
const { canUpdate } = await this.capabilities.fetchPathCapabilities(
|
||||
'sys/storage/raft/snapshot/snapshot-load'
|
||||
);
|
||||
if (this.version.isEnterprise) {
|
||||
const { canUpdate } = await this.capabilities.fetchPathCapabilities(
|
||||
'sys/storage/raft/snapshot/snapshot-load'
|
||||
);
|
||||
|
||||
const snapshots = await this.fetchSnapshots();
|
||||
const snapshots = await this.fetchSnapshots();
|
||||
|
||||
return {
|
||||
snapshots,
|
||||
canLoadSnapshot: canUpdate,
|
||||
};
|
||||
return {
|
||||
snapshots,
|
||||
canLoadSnapshot: canUpdate,
|
||||
};
|
||||
}
|
||||
return { snapshots: [], showCommunityMessage: true };
|
||||
}
|
||||
|
||||
afterModel(model: SnapshotsRouteModel, transition: Transition) {
|
||||
// Don't redirect if we're already on details route
|
||||
const toRoute = transition.to?.name;
|
||||
if (model.snapshots.length === 1 && toRoute !== 'vault.cluster.recovery.snapshots.snapshot.details') {
|
||||
redirect(model: SnapshotsRouteModel) {
|
||||
if (model.snapshots.length === 1) {
|
||||
const snapshot_id = model.snapshots[0];
|
||||
this.router.transitionTo('vault.cluster.recovery.snapshots.snapshot.manage', snapshot_id);
|
||||
}
|
||||
|
||||
@ -7,17 +7,13 @@ import Route from '@ember/routing/route';
|
||||
import { service } from '@ember/service';
|
||||
|
||||
import type RouterService from '@ember/routing/router-service';
|
||||
import type { SnapshotsRouteModel } from '../snapshots';
|
||||
|
||||
export default class RecoverySnapshotsIndexRoute extends Route {
|
||||
@service declare readonly router: RouterService;
|
||||
|
||||
beforeModel() {
|
||||
const parentModel = this.modelFor('vault.cluster.recovery.snapshots') as SnapshotsRouteModel;
|
||||
|
||||
if (parentModel.snapshots.length === 1) {
|
||||
const snapshot_id = parentModel.snapshots[0];
|
||||
this.router.transitionTo('vault.cluster.recovery.snapshots.snapshot.manage', snapshot_id);
|
||||
}
|
||||
// There is not a recovery.snapshots.index view because currently only one snapshot can be loaded at a time.
|
||||
// Redirect to the parent route so we can reuse its logic and send users to "recovery.snapshots.snapshot.manage"
|
||||
// if a snapshot is loaded.
|
||||
redirect() {
|
||||
this.router.transitionTo('vault.cluster.recovery.snapshots');
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,9 +12,9 @@
|
||||
|
||||
{{#if (eq this.model.message "raft storage is not in use")}}
|
||||
<Hds::ApplicationState as |A|>
|
||||
<A.Header @title="Raft storage required" @icon="info" />
|
||||
<A.Body @text="Raft storage must be used in order to recover data from a snapshot." />
|
||||
<A.Footer as |F|>
|
||||
<A.Header @title="Raft storage required" @icon="info" data-test-empty-state-title />
|
||||
<A.Body @text="Raft storage must be used in order to recover data from a snapshot." data-test-empty-state-message />
|
||||
<A.Footer data-test-empty-state-actions as |F|>
|
||||
<F.LinkStandalone
|
||||
@text="Snapshot management"
|
||||
@icon="docs-link"
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
}}
|
||||
|
||||
{{outlet}}
|
||||
@ -4,54 +4,99 @@
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, currentRouteName, currentURL } from '@ember/test-helpers';
|
||||
import { visit, currentRouteName, currentURL, click } from '@ember/test-helpers';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import { login } from 'vault/tests/helpers/auth/auth-helpers';
|
||||
import { GENERAL } from 'vault/tests/helpers/general-selectors';
|
||||
import { Response } from 'miragejs';
|
||||
import { overrideResponse } from 'vault/tests/helpers/stubs';
|
||||
import { addDays } from 'date-fns';
|
||||
|
||||
module('Acceptance | recovery | snapshots', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.server.get('/sys/storage/raft/configuration', () => this.server.create('configuration', 'withRaft'));
|
||||
|
||||
return login();
|
||||
});
|
||||
|
||||
test('it renders empty state when no snapshots are loaded', async function (assert) {
|
||||
test('enterprise: it renders empty state when raft storage is not in use', async function (assert) {
|
||||
this.server.get('/sys/storage/raft/snapshot-load', () => {
|
||||
return new Response(404, { 'Content-Type': 'application/json' }, JSON.stringify({ errors: [] }));
|
||||
return overrideResponse(400, JSON.stringify({ errors: ['raft storage is not in use'] }));
|
||||
});
|
||||
await visit('/vault/recovery/snapshots');
|
||||
assert.strictEqual(currentURL(), '/vault/recovery/snapshots');
|
||||
assert.dom('header').exists('it renders header despite route throwing an error');
|
||||
assert.dom(GENERAL.emptyStateTitle).hasText('Raft storage required');
|
||||
assert
|
||||
.dom(GENERAL.emptyStateMessage)
|
||||
.hasText('Raft storage must be used in order to recover data from a snapshot.');
|
||||
assert.dom(GENERAL.emptyStateActions).hasText('Snapshot management');
|
||||
});
|
||||
|
||||
test('it renders promo for community versions', async function (assert) {
|
||||
const version = this.owner.lookup('service:version');
|
||||
version.type = 'community';
|
||||
this.server.get('/sys/storage/raft/snapshot-load', () => {
|
||||
// This assertion is intentionally setup to fail if a request is made to this endpoint
|
||||
// because community versions should NOT request the snapshot-load endpoint
|
||||
assert.true(false, 'it does not make a request to snapshot-load on CE versions');
|
||||
});
|
||||
|
||||
await visit('/vault/recovery/snapshots');
|
||||
|
||||
assert
|
||||
.dom(`${GENERAL.navLink('Secrets Recovery')} .hds-badge`)
|
||||
.hasText('Enterprise', 'side nav link renders "Enterprise" badge');
|
||||
assert.strictEqual(currentURL(), '/vault/recovery/snapshots');
|
||||
|
||||
assert.dom(GENERAL.emptyStateTitle).hasText('Upload a snapshot to get started');
|
||||
assert.dom(GENERAL.emptyStateActions).hasText('Upload snapshot');
|
||||
assert.dom(GENERAL.emptyStateTitle).hasText('Secrets Recovery is an enterprise feature');
|
||||
assert
|
||||
.dom(GENERAL.emptyStateMessage)
|
||||
.hasText(
|
||||
'Secrets Recovery allows you to restore accidentally deleted or lost secrets from a snapshot. The snapshots can be provided via upload or loaded from external storage.'
|
||||
);
|
||||
assert.dom(GENERAL.emptyStateActions).hasText('Learn more about upgrading');
|
||||
assert.dom(GENERAL.badge('enterprise')).exists();
|
||||
});
|
||||
|
||||
test('it redirects to snapshot route when a snapshot is loaded', async function (assert) {
|
||||
this.server.get('/sys/storage/raft/snapshot-load', () => {
|
||||
return { data: { keys: ['1234'] } };
|
||||
module('enterprise: with raft configured', function (hooks) {
|
||||
hooks.beforeEach(function () {
|
||||
this.server.get('/sys/storage/raft/configuration', () =>
|
||||
this.server.create('configuration', 'withRaft')
|
||||
);
|
||||
});
|
||||
|
||||
this.server.get('/sys/storage/raft/snapshot-load/1234', () => {
|
||||
return {
|
||||
data: {
|
||||
status: 'ready',
|
||||
expires_at: new Date(),
|
||||
snapshot_id: '1234',
|
||||
},
|
||||
};
|
||||
test('it renders empty state when no snapshots are loaded', async function (assert) {
|
||||
this.server.get('/sys/storage/raft/snapshot-load', () => {
|
||||
return new Response(404, { 'Content-Type': 'application/json' }, JSON.stringify({ errors: [] }));
|
||||
});
|
||||
|
||||
await visit('/vault/recovery/snapshots');
|
||||
|
||||
assert.strictEqual(currentURL(), '/vault/recovery/snapshots');
|
||||
|
||||
assert.dom(GENERAL.emptyStateTitle).hasText('Upload a snapshot to get started');
|
||||
assert.dom(GENERAL.emptyStateActions).hasText('Upload snapshot');
|
||||
});
|
||||
|
||||
await visit('vault/recovery/snapshots');
|
||||
test('it redirects to snapshot route when a snapshot is loaded', async function (assert) {
|
||||
this.server.get('/sys/storage/raft/snapshot-load', () => {
|
||||
return { data: { keys: ['1234'] } };
|
||||
});
|
||||
|
||||
assert.strictEqual(currentURL(), '/vault/recovery/snapshots/1234/manage');
|
||||
assert.strictEqual(currentRouteName(), 'vault.cluster.recovery.snapshots.snapshot.manage');
|
||||
this.server.get('/sys/storage/raft/snapshot-load/1234', () => {
|
||||
return {
|
||||
data: {
|
||||
status: 'ready',
|
||||
expires_at: addDays(new Date(), 3).toISOString(),
|
||||
snapshot_id: '1234',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await click(GENERAL.navLink('Secrets Recovery'));
|
||||
assert.strictEqual(currentURL(), '/vault/recovery/snapshots/1234/manage');
|
||||
assert.strictEqual(currentRouteName(), 'vault.cluster.recovery.snapshots.snapshot.manage');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -170,4 +170,5 @@ export const GENERAL = {
|
||||
|
||||
/* ────── Misc ────── */
|
||||
icon: (name: string) => (name ? `[data-test-icon="${name}"]` : '[data-test-icon]'),
|
||||
badge: (name: string) => (name ? `[data-test-badge="${name}"]` : '[data-test-badge]'),
|
||||
};
|
||||
|
||||
@ -12,10 +12,6 @@ import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import recoveryHandler from 'vault/mirage/handlers/recovery';
|
||||
import { GENERAL } from 'vault/tests/helpers/general-selectors';
|
||||
|
||||
const SELECTORS = {
|
||||
badge: (name) => `[data-test-badge="${name}"]`,
|
||||
};
|
||||
|
||||
module('Integration | Component | recovery/snapshots/snapshot-manage', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
setupMirage(hooks);
|
||||
@ -45,7 +41,7 @@ module('Integration | Component | recovery/snapshots/snapshot-manage', function
|
||||
|
||||
test('it displays loaded snapshot card', async function (assert) {
|
||||
await render(hbs`<Recovery::Page::Snapshots::SnapshotManage @model={{this.model}}/>`);
|
||||
assert.dom(SELECTORS.badge('status')).hasText('Ready', 'status badge renders');
|
||||
assert.dom(GENERAL.badge('status')).hasText('Ready', 'status badge renders');
|
||||
});
|
||||
|
||||
test('it displays namespace selector for root namespace', async function (assert) {
|
||||
|
||||
@ -12,10 +12,6 @@ import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
|
||||
import { GENERAL } from 'vault/tests/helpers/general-selectors';
|
||||
|
||||
const SELECTORS = {
|
||||
badge: (name) => `[data-test-badge="${name}"]`,
|
||||
};
|
||||
|
||||
module('Integration | Component | recovery/snapshots', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
setupMirage(hooks);
|
||||
@ -25,12 +21,12 @@ module('Integration | Component | recovery/snapshots', function (hooks) {
|
||||
snapshots: [],
|
||||
canLoadSnapshot: false,
|
||||
};
|
||||
this.version = this.owner.lookup('service:version');
|
||||
this.version.type = 'enterprise';
|
||||
this.renderComponent = () => render(hbs`<Recovery::Page::Snapshots @model={{this.model}}/>`);
|
||||
});
|
||||
|
||||
test('it displays empty state in CE', async function (assert) {
|
||||
this.version.type = 'community';
|
||||
this.model = { snapshots: [], showCommunityMessage: true };
|
||||
|
||||
await render(hbs`<Recovery::Page::Snapshots @model={{this.model}}/>`);
|
||||
assert
|
||||
.dom(GENERAL.emptyStateTitle)
|
||||
@ -45,14 +41,14 @@ module('Integration | Component | recovery/snapshots', function (hooks) {
|
||||
.dom(GENERAL.emptyStateActions)
|
||||
.hasText('Learn more about upgrading', 'CE empty state action renders');
|
||||
|
||||
assert.dom(SELECTORS.badge('enterprise')).exists();
|
||||
assert.dom(GENERAL.badge('enterprise')).exists();
|
||||
});
|
||||
|
||||
test('it displays empty state in non root namespace', async function (assert) {
|
||||
const nsService = this.owner.lookup('service:namespace');
|
||||
nsService.setNamespace('test-ns');
|
||||
|
||||
await render(hbs`<Recovery::Page::Snapshots @model={{this.model}}/>`);
|
||||
await this.renderComponent();
|
||||
|
||||
assert
|
||||
.dom(GENERAL.emptyStateTitle)
|
||||
@ -69,7 +65,7 @@ module('Integration | Component | recovery/snapshots', function (hooks) {
|
||||
});
|
||||
|
||||
test('it displays empty state when user cannot load snapshot', async function (assert) {
|
||||
await render(hbs`<Recovery::Page::Snapshots @model={{this.model}}/>`);
|
||||
await this.renderComponent();
|
||||
assert.dom(GENERAL.emptyStateTitle).hasText('No snapshot available', 'empty state title renders');
|
||||
assert
|
||||
.dom(GENERAL.emptyStateMessage)
|
||||
@ -84,7 +80,7 @@ module('Integration | Component | recovery/snapshots', function (hooks) {
|
||||
|
||||
test('it displays empty state when user can load snapshot', async function (assert) {
|
||||
this.model.canLoadSnapshot = true;
|
||||
await render(hbs`<Recovery::Page::Snapshots @model={{this.model}}/>`);
|
||||
await this.renderComponent();
|
||||
assert
|
||||
.dom(GENERAL.emptyStateTitle)
|
||||
.hasText('Upload a snapshot to get started', 'empty state title renders');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user