From d01e0912ad47559386b8bf23410628ab8a9e98e6 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Thu, 29 Oct 2020 11:09:04 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20reintroduce=20host=20set?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/components/form/host-set/index.hbs | 59 ++++ ui/core/app/router.js | 4 + .../host-catalogs/host-catalog/host-sets.js | 76 +++++ .../host-catalog/host-sets/host-set.js | 52 ++++ .../host-catalog/host-sets/host-set/index.js | 4 + .../host-catalog/host-sets/index.js | 4 + .../host-catalog/host-sets/new.js | 50 ++++ .../host-catalogs/host-catalog/-actions.hbs | 2 - .../host-catalog/-navigation.hbs | 2 - .../host-catalogs/host-catalog/host-sets.hbs | 3 + .../host-catalog/host-sets/host-set.hbs | 3 + .../host-sets/host-set/-actions.hbs | 18 ++ .../host-sets/host-set/-header.hbs | 12 + .../host-sets/host-set/-navigation.hbs | 10 + .../host-catalog/host-sets/host-set/index.hbs | 5 + .../host-catalog/host-sets/index.hbs | 56 ++++ .../host-catalog/host-sets/new.hbs | 7 + .../host-catalog/host-sets/new/-header.hbs | 4 + .../host-catalogs/host-sets-test.js | 283 ++++++++++++++++++ .../host-catalog/host-sets-test.js | 11 + .../host-catalog/host-sets/host-set-test.js | 11 + .../host-sets/host-set/index-test.js | 11 + .../host-catalog/host-sets/index-test.js | 11 + .../host-catalog/host-sets/new-test.js | 11 + 24 files changed, 705 insertions(+), 4 deletions(-) create mode 100644 ui/core/app/components/form/host-set/index.hbs create mode 100644 ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets.js create mode 100644 ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set.js create mode 100644 ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index.js create mode 100644 ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/index.js create mode 100644 ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/new.js create mode 100644 ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets.hbs create mode 100644 ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set.hbs create mode 100644 ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-actions.hbs create mode 100644 ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-header.hbs create mode 100644 ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-navigation.hbs create mode 100644 ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index.hbs create mode 100644 ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/index.hbs create mode 100644 ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/new.hbs create mode 100644 ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/new/-header.hbs create mode 100644 ui/core/tests/acceptance/host-catalogs/host-sets-test.js create mode 100644 ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets-test.js create mode 100644 ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set-test.js create mode 100644 ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index-test.js create mode 100644 ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/index-test.js create mode 100644 ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/new-test.js diff --git a/ui/core/app/components/form/host-set/index.hbs b/ui/core/app/components/form/host-set/index.hbs new file mode 100644 index 000000000..d457ad0e7 --- /dev/null +++ b/ui/core/app/components/form/host-set/index.hbs @@ -0,0 +1,59 @@ + + + + + + {{#if @model.errors.name}} + + {{#each @model.errors.name as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.description}} + + {{#each @model.errors.description as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + + diff --git a/ui/core/app/router.js b/ui/core/app/router.js index cf7accb4a..ebed78060 100644 --- a/ui/core/app/router.js +++ b/ui/core/app/router.js @@ -71,6 +71,10 @@ Router.map(function () { this.route('new'); this.route('host', { path: ':host_id' }, function() {}); }); + this.route('host-sets', function() { + this.route('new'); + this.route('host-set', { path: ':host_set_id' }, function() {}); + }); }); }); }); diff --git a/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets.js b/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets.js new file mode 100644 index 000000000..e3cbc969c --- /dev/null +++ b/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets.js @@ -0,0 +1,76 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; +import loading from 'ember-loading/decorator'; +import { confirm } from '../../../../../decorators/confirm'; +import { notifySuccess, notifyError } from '../../../../../decorators/notify'; + +export default class ScopesScopeHostCatalogsHostCatalogHostSetsRoute extends Route { + // =services + + @service intl; + @service notify; + + // =methods + + /** + * Loads all host-sets under the current host catalog and it's parent scope. + * @return {Promise{[HostSetModel]}} + */ + model() { + const { id: host_catalog_id } = this.modelFor( + 'scopes.scope.host-catalogs.host-catalog' + ); + return this.store.query('host-set', { host_catalog_id }); + } + + // =actions + + /** + * Rollback changes on a host set. + * @param {HostSetModel} hostSet + */ + @action + cancel(hostSet) { + const { isNew } = hostSet; + hostSet.rollbackAttributes(); + if (isNew) + this.transitionTo( + 'scopes.scope.host-catalogs.host-catalog.host-sets' + ); + } + + /** + * Handle save of a host set. + * @param {HostSetModel} hostSet + * @param {Event} e + */ + @action + @loading + @notifyError(({ message }) => message) + @notifySuccess(({ isNew }) => isNew ? 'notifications.create-success' : 'notifications.save-success') + async save(hostSet) { + await hostSet.save(); + await this.transitionTo( + 'scopes.scope.host-catalogs.host-catalog.host-sets.host-set', + hostSet + ); + this.refresh(); + } + + /** + * Delete host set in current scope and redirect to index. + * @param {HostSetModel} hostSet + */ + @action + @loading + @confirm('questions.delete-confirm') + @notifyError(({ message }) => message, { catch: true }) + @notifySuccess('notifications.delete-success') + async deleteHostSet(hostSet) { + await hostSet.destroyRecord(); + await this.replaceWith( + 'scopes.scope.host-catalogs.host-catalog.host-sets' + ); + } +} diff --git a/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set.js b/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set.js new file mode 100644 index 000000000..31339c0dc --- /dev/null +++ b/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set.js @@ -0,0 +1,52 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetRoute extends Route { + // =methods + + /** + * Load a host-set using current host-catalog and its parent scope. + * @param {object} params + * @param {string} params.host_set_id + * @return {HostSetModel} + */ + async model({ host_set_id }) { + return this.store.findRecord('host-set', host_set_id, { reload: true }); + } + + /** + * Renders the host-set specific templates for header, navigation, and action page sections. + * @override + * @param {object} controller + * @param {object} model + */ + renderTemplate(controller, model) { + super.renderTemplate(...arguments); + + this.render( + 'scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-header', + { + into: 'scopes/scope/host-catalogs/host-catalog', + outlet: 'header', + model: model, + } + ); + + this.render( + 'scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-navigation', + { + into: 'scopes/scope/host-catalogs/host-catalog', + outlet: 'navigation', + model: model, + } + ); + + this.render( + 'scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-actions', + { + into: 'scopes/scope/host-catalogs/host-catalog', + outlet: 'actions', + model: model, + } + ); + } +} diff --git a/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index.js b/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index.js new file mode 100644 index 000000000..48e4b444d --- /dev/null +++ b/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index.js @@ -0,0 +1,4 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetIndexRoute extends Route { +} diff --git a/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/index.js b/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/index.js new file mode 100644 index 000000000..3af22321c --- /dev/null +++ b/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/index.js @@ -0,0 +1,4 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeHostCatalogsHostCatalogHostSetsIndexRoute extends Route { +} diff --git a/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/new.js b/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/new.js new file mode 100644 index 000000000..3980cf51b --- /dev/null +++ b/ui/core/app/routes/scopes/scope/host-catalogs/host-catalog/host-sets/new.js @@ -0,0 +1,50 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeHostCatalogsHostCatalogHostSetsNewRoute extends Route { + // =methods + + /** + * Creates a new unsaved host set in current host catalog scope. + * @return {HostSetModel} + */ + model() { + const { id: host_catalog_id } = this.modelFor( + 'scopes.scope.host-catalogs.host-catalog' + ); + return this.store.createRecord('host-set', { + type: 'static', + host_catalog_id, + }); + } + + /** + * Renders new host-set specific templates for header, navigation, and action page sections. + * @override + * @param {object} controller + * @param {object} model + */ + renderTemplate(controller, model) { + super.renderTemplate(...arguments); + + this.render( + 'scopes/scope/host-catalogs/host-catalog/host-sets/new/-header', + { + into: 'scopes/scope/host-catalogs/host-catalog', + outlet: 'header', + model: model, + } + ); + + this.render('_empty', { + into: 'scopes/scope/host-catalogs/host-catalog', + outlet: 'navigation', + model: model, + }); + + this.render('_empty', { + into: 'scopes/scope/host-catalogs/host-catalog', + outlet: 'actions', + model: model, + }); + } +} diff --git a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/-actions.hbs b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/-actions.hbs index 2cfb73b07..1e65e6dc7 100644 --- a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/-actions.hbs +++ b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/-actions.hbs @@ -5,14 +5,12 @@ > {{t "resources.host.actions.create"}} - {{!-- {{t "resources.host-set.actions.create"}} - --}} {{t 'resources.host.title_plural'}} - {{!-- {{t 'resources.host-set.title_plural'}} - --}} diff --git a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets.hbs b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets.hbs new file mode 100644 index 000000000..031f2510b --- /dev/null +++ b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets.hbs @@ -0,0 +1,3 @@ +{{title (t "resources.host-set.title_plural")}} + +{{outlet}} diff --git a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set.hbs b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set.hbs new file mode 100644 index 000000000..d66e83390 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set.hbs @@ -0,0 +1,3 @@ +{{title @model.displayName}} + +{{outlet}} diff --git a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-actions.hbs b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-actions.hbs new file mode 100644 index 000000000..b49a0dd51 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-actions.hbs @@ -0,0 +1,18 @@ + + {{!-- + + {{t 'resources.host-set.actions.create-host'}} + + + {{t 'resources.host-set.actions.add-hosts'}} + + --}} + + + {{t 'resources.host-set.actions.delete'}} + + diff --git a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-header.hbs b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-header.hbs new file mode 100644 index 000000000..a101b0a8a --- /dev/null +++ b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-header.hbs @@ -0,0 +1,12 @@ +

+ {{t "resources.host-set.title"}} + +

+

{{t "resources.host-set.description"}}

+ + {{@model.id}} + diff --git a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-navigation.hbs b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-navigation.hbs new file mode 100644 index 000000000..656b39947 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/-navigation.hbs @@ -0,0 +1,10 @@ + + + {{t 'titles.details'}} + + {{!-- + + {{t 'resources.host.title_plural'}} + + --}} + diff --git a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index.hbs b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index.hbs new file mode 100644 index 000000000..ac0b64897 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index.hbs @@ -0,0 +1,5 @@ + diff --git a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/index.hbs b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/index.hbs new file mode 100644 index 000000000..d4cb8ca74 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/index.hbs @@ -0,0 +1,56 @@ +{{#if @model}} + + + + + {{t "form.name.label"}} + {{t "form.type.label"}} + {{t "form.id.label"}} + + + + {{#each @model as |hostSet|}} + + + + {{hostSet.displayName}} + +

{{hostSet.description}}

+
+ + + {{t (concat 'resources.host-set.types.' hostSet.type)}} + + + + + {{hostSet.id}} + + +
+ {{/each}} +
+
+ +{{else}} + + + + + {{t "resources.host-set.description"}} + + + + {{t "titles.new"}} + + + + +{{/if}} diff --git a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/new.hbs b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/new.hbs new file mode 100644 index 000000000..bd5a0338c --- /dev/null +++ b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/new.hbs @@ -0,0 +1,7 @@ +{{title (t 'titles.new')}} + + diff --git a/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/new/-header.hbs b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/new/-header.hbs new file mode 100644 index 000000000..38ae01334 --- /dev/null +++ b/ui/core/app/templates/scopes/scope/host-catalogs/host-catalog/host-sets/new/-header.hbs @@ -0,0 +1,4 @@ +

+ {{t "titles.new"}} + +

diff --git a/ui/core/tests/acceptance/host-catalogs/host-sets-test.js b/ui/core/tests/acceptance/host-catalogs/host-sets-test.js new file mode 100644 index 000000000..7f575a500 --- /dev/null +++ b/ui/core/tests/acceptance/host-catalogs/host-sets-test.js @@ -0,0 +1,283 @@ +import { module, test } from 'qunit'; +import { visit, currentURL, find, click, fillIn } from '@ember/test-helpers'; +import { setupApplicationTest } from 'ember-qunit'; +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; +import a11yAudit from 'ember-a11y-testing/test-support/audit'; +import { Response } from 'miragejs'; +import { resolve, reject } from 'rsvp'; +import sinon from 'sinon'; +import { + authenticateSession, + // These are left here intentionally for future reference. + //currentSession, + //invalidateSession, +} from 'ember-simple-auth/test-support'; + +module('Acceptance | host-catalogs | host sets', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + let getHostCount; + + const instances = { + scopes: { + global: null, + org: null, + project: null, + hostCatalog: null, + host: null + } + }; + const urls = { + globalScope: null, + orgScope: null, + projectScope: null, + hostCatalogs: null, + hostCatalog: null, + hostSets: null, + hostSet: null, + unknownHostSet: null, + newHostSet: null, + }; + + hooks.beforeEach(function () { + // Generate resources + instances.scopes.global = this.server.create('scope', { id: 'global' }); + instances.scopes.org = this.server.create('scope', { + type: 'org', + scope: { id: 'global', type: 'global' }, + }); + instances.scopes.project = this.server.create('scope', { + type: 'project', + scope: { id: instances.scopes.org.id, type: 'org' }, + }); + instances.hostCatalog = this.server.create('host-catalog', { + scope: instances.scopes.project, + }); + instances.hostSet = this.server.create('host-set', { + scope: instances.scopes.project, + hostCatalog: instances.hostCatalog + }); + // Generate route URLs for resources + urls.globalScope = `/scopes/global/scopes`; + urls.orgScope = `/scopes/${instances.scopes.org.id}/scopes`; + urls.projectScope = `/scopes/${instances.scopes.project.id}`; + urls.hostCatalogs = `${urls.projectScope}/host-catalogs`; + urls.hostCatalog = `${urls.hostCatalogs}/${instances.hostCatalog.id}`; + urls.hostSets = `${urls.hostCatalog}/host-sets`; + urls.hostSet = `${urls.hostSets}/${instances.hostSet.id}`; + urls.unknownHostSet = `${urls.hostSets}/foo`; + urls.newHostSet = `${urls.hostSets}/new`; + // Generate resource couner + getHostCount = () => this.server.schema.hostSets.all().models.length; + authenticateSession({}); + }); + + test('visiting host sets', async function (assert) { + assert.expect(2); + await visit(urls.hostSets); + await a11yAudit(); + assert.equal(currentURL(), urls.hostSets); + await visit(urls.hostSet); + await a11yAudit(); + assert.equal(currentURL(), urls.hostSet); + }); + + test('visiting an unknown host set displays 404 message', async function (assert) { + assert.expect(1); + await visit(urls.unknownHostSet); + await a11yAudit(); + assert.ok(find('.rose-message-subtitle').textContent.trim(), 'Error 404'); + }); + + test('can create new host', async function (assert) { + assert.expect(1); + const count = getHostCount(); + await visit(urls.newHostSet); + await fillIn('[name="name"]', 'random string'); + await click('[type="submit"]'); + assert.equal(getHostCount(), count + 1); + }); + + test('can cancel create new host', async function (assert) { + assert.expect(2); + const count = getHostCount(); + await visit(urls.newHostSet); + await fillIn('[name="name"]', 'random string'); + await click('.rose-form-actions [type="button"]'); + assert.equal(currentURL(), urls.hostSets); + assert.equal(getHostCount(), count); + }); + + test('saving a new host set with invalid fields displays error messages', async function (assert) { + assert.expect(2); + this.server.post('/host-sets', () => { + return new Response( + 400, + {}, + { + status: 400, + code: 'invalid_argument', + message: 'The request was invalid.', + details: { + request_fields: [ + { + name: 'name', + description: 'Name is required.', + }, + ], + }, + } + ); + }); + await visit(urls.newHostSet); + await click('[type="submit"]'); + assert.ok(find('[role="alert"]').textContent.trim(), 'The request was invalid.'); + assert.ok( + find('.rose-form-error-message').textContent.trim(), + 'Name is required.' + ); + }); + + test('can save changes to existing host', async function (assert) { + assert.expect(3); + assert.notEqual(instances.hostSet.name, 'random string'); + await visit(urls.hostSet); + await click('form [type="button"]', 'Activate edit mode'); + await fillIn('[name="name"]', 'random string'); + await click('.rose-form-actions [type="submit"]'); + assert.equal(currentURL(), urls.hostSet); + assert.equal(this.server.schema.hostSets.all().models[0].name, 'random string'); + }); + + test('can cancel changes to existing host', async function (assert) { + assert.expect(2); + await visit(urls.hostSet); + await click('form [type="button"]', 'Activate edit mode'); + await fillIn('[name="name"]', 'random string'); + await click('.rose-form-actions [type="button"]'); + assert.notEqual(instances.hostSet.name, 'random string'); + assert.equal(find('[name="name"]').value, instances.hostSet.name); + }); + + test('saving an existing host set with invalid fields displays error messages', async function (assert) { + assert.expect(2); + this.server.patch('/host-sets/:id', () => { + return new Response( + 400, + {}, + { + status: 400, + code: 'invalid_argument', + message: 'The request was invalid.', + details: { + request_fields: [ + { + name: 'name', + description: 'Name is required.', + }, + ], + }, + } + ); + }); + await visit(urls.hostSet); + await click('form [type="button"]', 'Activate edit mode'); + await fillIn('[name="name"]', 'random string'); + await click('[type="submit"]'); + assert.ok(find('[role="alert"]').textContent.trim(), 'The request was invalid.'); + assert.ok( + find('.rose-form-error-message').textContent.trim(), + 'Name is required.' + ); + }); + + test('can discard unsaved host set changes via dialog', async function (assert) { + assert.expect(5); + const confirmService = this.owner.lookup('service:confirm'); + confirmService.enabled = true; + assert.notEqual(instances.hostSet.name, 'random string'); + await visit(urls.hostSet); + await click('form [type="button"]', 'Activate edit mode'); + await fillIn('[name="name"]', 'random string'); + assert.equal(currentURL(), urls.hostSet); + try { + await visit(urls.hostSets); + } catch (e) { + assert.ok(find('.rose-dialog')); + await click('.rose-dialog-footer button:first-child'); + assert.equal(currentURL(), urls.hostSets); + assert.notEqual(this.server.schema.hostSets.all().models[0].name, 'random string'); + } + }); + + test('can cancel discard unsaved host set changes via dialog', async function (assert) { + assert.expect(5); + const confirmService = this.owner.lookup('service:confirm'); + confirmService.enabled = true; + assert.notEqual(instances.hostSet.name, 'random string'); + await visit(urls.hostSet); + await click('form [type="button"]', 'Activate edit mode'); + await fillIn('[name="name"]', 'random string'); + assert.equal(currentURL(), urls.hostSet); + try { + await visit(urls.hostSets); + } catch (e) { + assert.ok(find('.rose-dialog')); + await click('.rose-dialog-footer button:last-child'); + assert.equal(currentURL(), urls.hostSet); + assert.notEqual(this.server.schema.hostSets.all().models[0].name, 'random string'); + } + }); + + test('can delete host', async function (assert) { + assert.expect(1); + const count = getHostCount(); + await visit(urls.hostSet); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.equal(getHostCount(), count - 1); + }); + + test('can accept delete host set via dialog', async function (assert) { + assert.expect(2); + const confirmService = this.owner.lookup('service:confirm'); + confirmService.enabled = true; + confirmService.confirm = sinon.fake.returns(resolve()); + const count = getHostCount(); + await visit(urls.hostSet); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.equal(getHostCount(), count - 1); + assert.ok(confirmService.confirm.calledOnce); + }); + + test('cannot cancel delete host set via dialog', async function (assert) { + assert.expect(2); + const confirmService = this.owner.lookup('service:confirm'); + confirmService.enabled = true; + confirmService.confirm = sinon.fake.returns(reject()); + const count = getHostCount(); + await visit(urls.hostSet); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.equal(getHostCount(), count); + assert.ok(confirmService.confirm.calledOnce); + }); + + test('deleting a host set which errors displays error messages', async function (assert) { + assert.expect(1); + this.server.del('/host-sets/:id', () => { + return new Response( + 490, + {}, + { + status: 490, + code: 'error', + message: 'Oops.', + } + ); + }); + await visit(urls.hostSet); + await click('.rose-layout-page-actions .rose-dropdown-button-danger'); + assert.ok(find('[role="alert"]').textContent.trim(), 'Oops.'); + }); + +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets-test.js b/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets-test.js new file mode 100644 index 000000000..8178e1810 --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/host-catalogs/host-catalog/host-sets', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/host-catalogs/host-catalog/host-sets'); + assert.ok(route); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set-test.js b/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set-test.js new file mode 100644 index 000000000..56f46755c --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/host-catalogs/host-catalog/host-sets/host-set', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/host-catalogs/host-catalog/host-sets/host-set'); + assert.ok(route); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index-test.js b/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index-test.js new file mode 100644 index 000000000..f2c55644a --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/host-catalogs/host-catalog/host-sets/host-set/index'); + assert.ok(route); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/index-test.js b/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/index-test.js new file mode 100644 index 000000000..c158018f5 --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/index-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/host-catalogs/host-catalog/host-sets/index', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/host-catalogs/host-catalog/host-sets/index'); + assert.ok(route); + }); +}); diff --git a/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/new-test.js b/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/new-test.js new file mode 100644 index 000000000..3216994c2 --- /dev/null +++ b/ui/core/tests/unit/routes/scopes/scope/host-catalogs/host-catalog/host-sets/new-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/host-catalogs/host-catalog/host-sets/new', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope/host-catalogs/host-catalog/host-sets/new'); + assert.ok(route); + }); +});