22 files changed
+370
-319
No files matched your search
@@ -63,7 +63,7 @@ export default class PasswordAuthenticator extends BasePasswordAuthenticator {
|
||||
authenticate() {
|
||||
return super.authenticate(...arguments).then((data) => {
|
||||
const token = data?.token;
|
||||
if (token) this.addTokenToAuthorization(token);
|
||||
this.addTokenToAuthorization(token);
|
||||
return data;
|
||||
});
|
||||
}
|
||||
@@ -77,7 +77,7 @@ export default class PasswordAuthenticator extends BasePasswordAuthenticator {
|
||||
*/
|
||||
restore(data) {
|
||||
const token = data?.token;
|
||||
if (token) this.addTokenToAuthorization(token);
|
||||
this.addTokenToAuthorization(token);
|
||||
return super.restore(data);
|
||||
}
|
||||
|
||||
@@ -93,6 +93,6 @@ export default class PasswordAuthenticator extends BasePasswordAuthenticator {
|
||||
const headers = adapterPrototype?.headers;
|
||||
if (!headers) adapterPrototype.headers = {};
|
||||
adapterPrototype.headers.Authorization = null;
|
||||
if (token) adapterPrototype.headers.Authorization = `Bearer ${token}`;
|
||||
adapterPrototype.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@
|
||||
</form.input>
|
||||
|
||||
<form.actions
|
||||
@disabled={{this.cannotSave}}
|
||||
@submitDisabled={{this.cannotSave}}
|
||||
@submitText={{t "actions.save"}}
|
||||
@cancelText={{t "actions.cancel"}} />
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{fn this.submit @submit}}
|
||||
@cancel={{fn this.cancel @cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
as |form|
|
||||
@@ -26,8 +25,9 @@
|
||||
</form.input>
|
||||
|
||||
<form.actions
|
||||
@disabled={{this.cannotSave}}
|
||||
@submitDisabled={{this.cannotSave}}
|
||||
@showCancel={{false}}
|
||||
@submitText={{t "actions.save"}}
|
||||
@cancelText={{t "actions.cancel"}} />
|
||||
|
||||
</Rose::Form>
|
||||
</Rose::Form>
|
||||
@@ -43,14 +43,4 @@ export default class FormAccountPasswordSetPasswordIndexComponent extends Compon
|
||||
next(() => this.resetPassword());
|
||||
fn(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset password value before callback.
|
||||
* @param {function} fn
|
||||
*/
|
||||
@action
|
||||
cancel(fn) {
|
||||
this.resetPassword();
|
||||
fn();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
import Controller from '@ember/controller';
|
||||
import { sort } from '@ember/object/computed';
|
||||
|
||||
export default class ScopesScopeAuthenticateController extends Controller {
|
||||
// =attributes
|
||||
|
||||
/**
|
||||
* Moves the global scope to index 0.
|
||||
* @type {Array}
|
||||
*/
|
||||
@sort('model.scopes', (a, b) => {
|
||||
if (a.isGlobal) {
|
||||
return -1;
|
||||
} else if (b.isGlobal) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
sortedScopes;
|
||||
get sortedScopes() {
|
||||
return [
|
||||
...this.model.scopes.filter((scope) => scope.id === 'global'),
|
||||
...this.model.scopes.filter((scope) => scope.id !== 'global'),
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
-10
@@ -47,14 +47,4 @@ export default class ScopesScopeAuthMethodsAuthMethodAccountsAccountSettingsRout
|
||||
this.notify.error(error.message, { closeAfter: null });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to hosts as if nothing ever happened.
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
this.replaceWith(
|
||||
'scopes.scope.auth-methods.auth-method.accounts.account.set-password'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -38,9 +38,8 @@ export default class ScopesScopeOrgsRoute extends Route {
|
||||
*/
|
||||
@action
|
||||
cancel(org) {
|
||||
const { isNew } = org;
|
||||
org.rollbackAttributes();
|
||||
if (isNew) this.transitionTo('scopes.scope.orgs');
|
||||
this.transitionTo('scopes.scope.orgs');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,13 +50,12 @@ export default class ScopesScopeOrgsRoute extends Route {
|
||||
@action
|
||||
@loading
|
||||
async save(org) {
|
||||
const { isNew } = org;
|
||||
try {
|
||||
await org.save();
|
||||
await this.transitionTo('scopes.scope', org);
|
||||
await this.transitionTo('scopes.scope.projects', org);
|
||||
this.refresh();
|
||||
this.notify.success(
|
||||
this.intl.t(isNew ? 'notifications.create-success' : 'notifications.save-success')
|
||||
this.intl.t('notifications.create-success')
|
||||
);
|
||||
} catch (error) {
|
||||
// TODO: replace with translated strings
|
||||
|
||||
@@ -4,8 +4,9 @@ import { action } from '@ember/object';
|
||||
import { all, hash } from 'rsvp';
|
||||
import { task, timeout } from 'ember-concurrency';
|
||||
import { A } from '@ember/array';
|
||||
import config from '../../../../../config/environment';
|
||||
|
||||
const POLL_TIMEOUT_SECONDS = 2.5;
|
||||
const POLL_TIMEOUT_SECONDS = config.sessionPollingTimeoutSeconds;
|
||||
|
||||
export default class ScopesScopeProjectsProjectSessionsRoute extends Route {
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ module.exports = function (environment) {
|
||||
appName: APP_NAME,
|
||||
|
||||
notifyTimeout: 4000,
|
||||
sessionPollingTimeoutSeconds: 2.5,
|
||||
enableConfirmService: true,
|
||||
|
||||
contentSecurityPolicyHeader: 'Content-Security-Policy',
|
||||
@@ -99,6 +100,8 @@ module.exports = function (environment) {
|
||||
|
||||
// Notification timeout should be 0 for fast tests
|
||||
ENV.notifyTimeout = 0;
|
||||
// Session polling timeout should be short
|
||||
ENV.sessionPollingTimeoutSeconds = 0.25;
|
||||
ENV.enableConfirmService = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,13 +71,16 @@ module('Acceptance | accounts | set password', function (hooks) {
|
||||
await a11yAudit();
|
||||
});
|
||||
|
||||
test('can cancel setting new password', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.setPassword);
|
||||
await fillIn('[name="password"]', 'update password');
|
||||
await click('form button:not([type="submit"])');
|
||||
assert.notOk(find('[name="password"]').textContent.trim());
|
||||
});
|
||||
// NOTE: since set password is a tabbed route with easy navigation away
|
||||
// from the form, and the form does not directly operate on a model instance,
|
||||
// a "cancel" flow doesn't make much sense. Disabling for now.
|
||||
// test('can cancel setting new password', async function (assert) {
|
||||
// assert.expect(1);
|
||||
// await visit(urls.setPassword);
|
||||
// await fillIn('[name="password"]', 'update password');
|
||||
// await click('form button:not([type="submit"])');
|
||||
// assert.notOk(find('[name="password"]').textContent.trim());
|
||||
// });
|
||||
|
||||
test('errors are displayed when setting password fails', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
@@ -37,8 +37,13 @@ module('Acceptance | authentication', function (hooks) {
|
||||
let authenticateURL;
|
||||
let authMethodAuthenticateURL;
|
||||
let authMethodGlobalAuthenticateURL;
|
||||
let changePasswordURL;
|
||||
let orgsURL;
|
||||
let projectsURL;
|
||||
let usersURL;
|
||||
let groupsURL;
|
||||
let rolesURL;
|
||||
let authMethodsURL;
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
invalidateSession();
|
||||
@@ -66,8 +71,13 @@ module('Acceptance | authentication', function (hooks) {
|
||||
authenticateURL = `/scopes/${orgScopeID}/authenticate`;
|
||||
authMethodGlobalAuthenticateURL = `/scopes/global/authenticate/${globalAuthMethodID}`;
|
||||
authMethodAuthenticateURL = `/scopes/${orgScopeID}/authenticate/${authMethodID}`;
|
||||
changePasswordURL = `/account/change-password`;
|
||||
orgsURL = `/scopes/global/orgs`;
|
||||
projectsURL = `/scopes/${orgScopeID}/projects`;
|
||||
usersURL = `/scopes/${orgScopeID}/users`;
|
||||
groupsURL = `/scopes/${orgScopeID}/groups`;
|
||||
rolesURL = `/scopes/${orgScopeID}/roles`;
|
||||
authMethodsURL = `/scopes/${orgScopeID}/auth-methods`;
|
||||
});
|
||||
|
||||
test('visiting auth methods authenticate route redirects to first auth method', async function (assert) {
|
||||
@@ -105,6 +115,20 @@ module('Acceptance | authentication', function (hooks) {
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('visiting change password while unauthenticated redirects to first global authenticate method', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(changePasswordURL);
|
||||
assert.equal(currentURL(), authMethodGlobalAuthenticateURL);
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('visiting orgs while unauthenticated redirects to first global authenticate method', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(orgsURL);
|
||||
assert.equal(currentURL(), authMethodGlobalAuthenticateURL);
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('visiting projects while unauthenticated redirects to first global authenticate method', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(projectsURL);
|
||||
@@ -112,6 +136,34 @@ module('Acceptance | authentication', function (hooks) {
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('visiting users while unauthenticated redirects to first global authenticate method', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(usersURL);
|
||||
assert.equal(currentURL(), authMethodGlobalAuthenticateURL);
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('visiting roles while unauthenticated redirects to first global authenticate method', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(rolesURL);
|
||||
assert.equal(currentURL(), authMethodGlobalAuthenticateURL);
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('visiting groups while unauthenticated redirects to first global authenticate method', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(groupsURL);
|
||||
assert.equal(currentURL(), authMethodGlobalAuthenticateURL);
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('visiting auth methods while unauthenticated redirects to first global authenticate method', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(authMethodsURL);
|
||||
assert.equal(currentURL(), authMethodGlobalAuthenticateURL);
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('visiting auth method authenticate route', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(authMethodAuthenticateURL);
|
||||
@@ -159,7 +211,19 @@ module('Acceptance | authentication', function (hooks) {
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('successful authentication redirects to projects', async function (assert) {
|
||||
test('successful authentication with the global scope redirects to orgs', async function (assert) {
|
||||
assert.expect(4);
|
||||
await visit(authMethodGlobalAuthenticateURL);
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), authMethodGlobalAuthenticateURL);
|
||||
await fillIn('[name="identification"]', 'test');
|
||||
await fillIn('[name="password"]', 'test');
|
||||
await click('[type="submit"]');
|
||||
assert.equal(currentURL(), orgsURL);
|
||||
assert.ok(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('successful authentication with an org scope redirects to projects', async function (assert) {
|
||||
assert.expect(4);
|
||||
await visit(authMethodAuthenticateURL);
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
|
||||
@@ -41,7 +41,7 @@ module('Acceptance | groups | members', function (hooks) {
|
||||
instances.group = this.server.create('group', {
|
||||
scope: instances.scopes.org,
|
||||
}, 'withMembers');
|
||||
membersCount = instances.group.memberIds.length;
|
||||
membersCount = instances.group.memberIds.length;
|
||||
urls.groups = `/scopes/${instances.scopes.org.id}/groups`;
|
||||
urls.group = `${urls.groups}/${instances.group.id}`;
|
||||
urls.members = `${urls.group}/members`;
|
||||
@@ -98,6 +98,9 @@ module('Acceptance | groups | members', function (hooks) {
|
||||
assert.equal(findAll('tbody tr').length, 0);
|
||||
await click('.rose-layout-page-actions a')
|
||||
assert.equal(currentURL(), urls.addMembers);
|
||||
// Click three times to select, unselect, then reselect (for coverage)
|
||||
await click('tbody label');
|
||||
await click('tbody label');
|
||||
await click('tbody label');
|
||||
await click('form [type="submit"]');
|
||||
await visit(urls.members);
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, currentURL, fillIn, click, find, findAll } 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 {
|
||||
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);
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
project: null,
|
||||
},
|
||||
hostCatalog: null,
|
||||
hostSets: null,
|
||||
};
|
||||
const urls = {
|
||||
orgScope: null,
|
||||
projects: null,
|
||||
project: null,
|
||||
hostCatalogs: null,
|
||||
hostCatalog: null,
|
||||
hostSets: null,
|
||||
newHostSet: null
|
||||
};
|
||||
let hostSetsCount;
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
// Setup Mirage mock resources for this test
|
||||
authenticateSession();
|
||||
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.hostSets = this.server.createList('host-set', 3, {
|
||||
scope: instances.scopes.project,
|
||||
hostCatalog: instances.hostCatalog
|
||||
});
|
||||
hostSetsCount = instances.hostCatalog.hostSetIds.length;
|
||||
// Generate route URLs for resources
|
||||
urls.orgScope = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.projects = `${urls.orgScope}/projects`;
|
||||
urls.project = `${urls.projects}/${instances.hostCatalog.scope.id}`;
|
||||
urls.hostCatalogs = `${urls.project}/host-catalogs`;
|
||||
urls.hostCatalog = `${urls.hostCatalogs}/${instances.hostCatalog.id}`;
|
||||
urls.hostSets = `${urls.hostCatalog}/host-sets`;
|
||||
urls.newHostSet = `${urls.hostSets}/new`;
|
||||
});
|
||||
|
||||
test('visiting host sets', async function (assert) {
|
||||
assert.expect(3);
|
||||
await visit(urls.hostSets);
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.hostSets);
|
||||
assert.ok(hostSetsCount);
|
||||
assert.equal(findAll('tbody tr').length, hostSetsCount);
|
||||
});
|
||||
|
||||
test('can navigate to a host set form', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.hostSets);
|
||||
await click('main tbody .rose-table-header-cell:nth-child(1) a');
|
||||
await a11yAudit();
|
||||
assert.notEqual(currentURL(), urls.hostSets);
|
||||
});
|
||||
|
||||
test('can create host set and save changes', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.newHostSet);
|
||||
await fillIn('[name="name"]', 'Test Name');
|
||||
await fillIn('[name="description"]', 'description');
|
||||
await click('form [type="submit"]:not(:disabled)');
|
||||
await visit(urls.hostSets);
|
||||
assert.equal(findAll('tbody tr').length, hostSetsCount + 1);
|
||||
});
|
||||
|
||||
test('can create host set and cancel changes', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(urls.newHostSet);
|
||||
await fillIn('[name="name"]', 'Test Name');
|
||||
await click('form button:not([type="submit"])');
|
||||
assert.equal(currentURL(), urls.hostSets);
|
||||
assert.equal(findAll('tbody tr').length, hostSetsCount);
|
||||
});
|
||||
|
||||
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 fillIn('[name="name"]', 'new target');
|
||||
await click('form [type="submit"]');
|
||||
await a11yAudit();
|
||||
assert.ok(find('[role="alert"]'));
|
||||
assert.ok(find('.rose-form-error-message'));
|
||||
});
|
||||
});
|
||||
@@ -1,132 +0,0 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, currentURL, fillIn, click, find, findAll } 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 {
|
||||
authenticateSession,
|
||||
// These are left here intentionally for future reference.
|
||||
//currentSession,
|
||||
//invalidateSession,
|
||||
} from 'ember-simple-auth/test-support';
|
||||
|
||||
module('Acceptance | host catalogs | hosts', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
project: null,
|
||||
},
|
||||
hostCatalog: null,
|
||||
hosts: null,
|
||||
};
|
||||
const urls = {
|
||||
orgScope: null,
|
||||
projects: null,
|
||||
project: null,
|
||||
hostCatalogs: null,
|
||||
hostCatalog: null,
|
||||
hosts: null,
|
||||
newHost: null
|
||||
};
|
||||
let hostsCount;
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
// Setup Mirage mock resources for this test
|
||||
authenticateSession();
|
||||
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.hosts = this.server.createList('host', 3, {
|
||||
scope: instances.scopes.project,
|
||||
hostCatalog: instances.hostCatalog
|
||||
});
|
||||
hostsCount = instances.hosts.length;
|
||||
// Generate route URLs for resources
|
||||
urls.orgScope = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.projects = `${urls.orgScope}/projects`;
|
||||
urls.project = `${urls.projects}/${instances.hostCatalog.scope.id}`;
|
||||
urls.hostCatalogs = `${urls.project}/host-catalogs`;
|
||||
urls.hostCatalog = `${urls.hostCatalogs}/${instances.hostCatalog.id}`;
|
||||
urls.hosts = `${urls.hostCatalog}/hosts`;
|
||||
urls.newHost = `${urls.hosts}/new`;
|
||||
});
|
||||
|
||||
test('visiting hosts', async function (assert) {
|
||||
assert.expect(3);
|
||||
await visit(urls.hosts);
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.hosts);
|
||||
assert.ok(hostsCount);
|
||||
assert.equal(findAll('tbody tr').length, hostsCount);
|
||||
});
|
||||
|
||||
test('can navigate to a host form', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.hosts);
|
||||
await click('main tbody .rose-table-header-cell:nth-child(1) a');
|
||||
await a11yAudit();
|
||||
assert.notEqual(currentURL(), urls.hosts);
|
||||
});
|
||||
|
||||
test('can create host and save changes', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.newHost);
|
||||
await fillIn('[name="name"]', 'Test Name');
|
||||
await fillIn('[name="description"]', 'description');
|
||||
await click('form [type="submit"]:not(:disabled)');
|
||||
await visit(urls.hosts);
|
||||
assert.equal(findAll('tbody tr').length, hostsCount + 1);
|
||||
});
|
||||
|
||||
test('can create host and cancel changes', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(urls.newHost);
|
||||
await fillIn('[name="name"]', 'Test Name');
|
||||
await click('form button:not([type="submit"])');
|
||||
assert.equal(currentURL(), urls.hosts);
|
||||
assert.equal(findAll('tbody tr').length, hostsCount);
|
||||
});
|
||||
|
||||
test('saving a new host with invalid fields displays error messages', async function (assert) {
|
||||
assert.expect(2);
|
||||
this.server.post('/hosts', () => {
|
||||
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.newHost);
|
||||
await fillIn('[name="name"]', 'new target');
|
||||
await click('form [type="submit"]');
|
||||
await a11yAudit();
|
||||
assert.ok(find('[role="alert"]'));
|
||||
assert.ok(find('.rose-form-error-message'));
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, currentURL, fillIn, click, find } from '@ember/test-helpers';
|
||||
import { visit, currentURL, fillIn, click, find, findAll } 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';
|
||||
@@ -32,6 +32,7 @@ module('Acceptance | host sets', function (hooks) {
|
||||
hostCatalog: null,
|
||||
hostSets: null,
|
||||
hostSet: null,
|
||||
newHostSet: null
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
@@ -61,6 +62,7 @@ module('Acceptance | host sets', function (hooks) {
|
||||
urls.hostCatalog = `${urls.hostCatalogs}/${instances.hostCatalog.id}`;
|
||||
urls.hostSets = `${urls.hostCatalog}/host-sets`;
|
||||
urls.hostSet = `${urls.hostSets}/${instances.hostSet.id}`;
|
||||
urls.newHostSet = `${urls.hostSets}/new`;
|
||||
});
|
||||
|
||||
test('visiting a host set', async function (assert) {
|
||||
@@ -148,4 +150,54 @@ module('Acceptance | host sets', function (hooks) {
|
||||
await a11yAudit();
|
||||
assert.ok(find('[role="alert"]'));
|
||||
});
|
||||
|
||||
test('can create host set and save changes', async function (assert) {
|
||||
assert.expect(1);
|
||||
const hostSetsCount = this.server.db.hostSets.length;
|
||||
await visit(urls.newHostSet);
|
||||
await fillIn('[name="name"]', 'Test Name');
|
||||
await fillIn('[name="description"]', 'description');
|
||||
await click('form [type="submit"]:not(:disabled)');
|
||||
await visit(urls.hostSets);
|
||||
assert.equal(findAll('tbody tr').length, hostSetsCount + 1);
|
||||
});
|
||||
|
||||
test('can create host set and cancel changes', async function (assert) {
|
||||
assert.expect(2);
|
||||
const hostSetsCount = this.server.db.hostSets.length;
|
||||
await visit(urls.newHostSet);
|
||||
await fillIn('[name="name"]', 'Test Name');
|
||||
await click('form button:not([type="submit"])');
|
||||
assert.equal(currentURL(), urls.hostSets);
|
||||
assert.equal(findAll('tbody tr').length, hostSetsCount);
|
||||
});
|
||||
|
||||
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 fillIn('[name="name"]', 'new target');
|
||||
await click('form [type="submit"]');
|
||||
await a11yAudit();
|
||||
assert.ok(find('[role="alert"]'));
|
||||
assert.ok(find('.rose-form-error-message'));
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, currentURL, fillIn, click, find } from '@ember/test-helpers';
|
||||
import { visit, currentURL, fillIn, click, find, findAll } 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';
|
||||
@@ -32,6 +32,7 @@ module('Acceptance | hosts', function (hooks) {
|
||||
hostCatalog: null,
|
||||
hosts: null,
|
||||
host: null,
|
||||
newHost: null
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
@@ -61,6 +62,7 @@ module('Acceptance | hosts', function (hooks) {
|
||||
urls.hostCatalog = `${urls.hostCatalogs}/${instances.hostCatalog.id}`;
|
||||
urls.hosts = `${urls.hostCatalog}/hosts`;
|
||||
urls.host = `${urls.hosts}/${instances.host.id}`;
|
||||
urls.newHost = `${urls.hosts}/new`;
|
||||
});
|
||||
|
||||
test('visiting a host', async function (assert) {
|
||||
@@ -150,4 +152,54 @@ module('Acceptance | hosts', function (hooks) {
|
||||
await a11yAudit();
|
||||
assert.ok(find('[role="alert"]'));
|
||||
});
|
||||
|
||||
test('can create host and save changes', async function (assert) {
|
||||
assert.expect(1);
|
||||
const hostsCount = this.server.db.hosts.length;
|
||||
await visit(urls.newHost);
|
||||
await fillIn('[name="name"]', 'Test Name');
|
||||
await fillIn('[name="description"]', 'description');
|
||||
await click('form [type="submit"]:not(:disabled)');
|
||||
await visit(urls.hosts);
|
||||
assert.equal(findAll('tbody tr').length, hostsCount + 1);
|
||||
});
|
||||
|
||||
test('can create host and cancel changes', async function (assert) {
|
||||
assert.expect(2);
|
||||
const hostsCount = this.server.db.hosts.length;
|
||||
await visit(urls.newHost);
|
||||
await fillIn('[name="name"]', 'Test Name');
|
||||
await click('form button:not([type="submit"])');
|
||||
assert.equal(currentURL(), urls.hosts);
|
||||
assert.equal(findAll('tbody tr').length, hostsCount);
|
||||
});
|
||||
|
||||
test('saving a new host with invalid fields displays error messages', async function (assert) {
|
||||
assert.expect(2);
|
||||
this.server.post('/hosts', () => {
|
||||
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.newHost);
|
||||
await fillIn('[name="name"]', 'new target');
|
||||
await click('form [type="submit"]');
|
||||
await a11yAudit();
|
||||
assert.ok(find('[role="alert"]'));
|
||||
assert.ok(find('.rose-form-error-message'));
|
||||
});
|
||||
});
|
||||
@@ -56,6 +56,29 @@ module('Acceptance | org', function (hooks) {
|
||||
assert.equal(findAll('article').length, orgsCount);
|
||||
});
|
||||
|
||||
test('visiting orgs when endpoint 404s shows an error message', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.get('/scopes', () => new Response(404));
|
||||
await visit(urls.orgs);
|
||||
await a11yAudit();
|
||||
assert.ok(find('.rose-message'));
|
||||
});
|
||||
|
||||
test('visiting orgs is successful even when the global scope cannot be fetched', async function (assert) {
|
||||
assert.expect(3);
|
||||
this.server.get('/scopes/:id', ({ scopes }, { params: { id } }) => {
|
||||
const scope = scopes.find(id);
|
||||
return (id === 'global')
|
||||
? new Response(404)
|
||||
: scope;
|
||||
});
|
||||
await visit(urls.orgs);
|
||||
await a11yAudit();
|
||||
assert.ok(orgsCount);
|
||||
assert.equal(currentURL(), urls.orgs);
|
||||
assert.equal(findAll('article').length, orgsCount);
|
||||
});
|
||||
|
||||
test('visiting scopes redirects to index', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.scopes);
|
||||
|
||||
@@ -90,6 +90,9 @@ module('Acceptance | roles | principals', function (hooks) {
|
||||
assert.equal(findAll('tbody tr').length, 0);
|
||||
await click('.rose-layout-page-actions a')
|
||||
assert.equal(currentURL(), urls.addPrincipals);
|
||||
// Click three times to select, unselect, then reselect (for coverage)
|
||||
await click('tbody label');
|
||||
await click('tbody label');
|
||||
await click('tbody label');
|
||||
await click('form [type="submit"]');
|
||||
await visit(urls.rolePrincipals);
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, currentURL, findAll, find, click } 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 { run, later } from '@ember/runloop';
|
||||
import { Response } from 'miragejs';
|
||||
import {
|
||||
authenticateSession,
|
||||
// These are left here intentionally for future reference.
|
||||
//currentSession,
|
||||
//invalidateSession,
|
||||
} from 'ember-simple-auth/test-support';
|
||||
|
||||
module('Acceptance | sessions', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
sessions: null,
|
||||
};
|
||||
const urls = {
|
||||
orgScope: null,
|
||||
sessions: null,
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
authenticateSession({});
|
||||
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: instances.scopes.org.type },
|
||||
});
|
||||
this.server.createList('group', 1, { scope: instances.scopes.org }, 'withMembers');
|
||||
this.server.createList('host-catalog', 1, { scope: instances.scopes.project }, 'withChildren');
|
||||
this.server.createList('target', 1, { scope: instances.scopes.project }, 'withRandomHostSets');
|
||||
instances.sessions = this.server.createList('session', 10, {
|
||||
scope: instances.scopes.project,
|
||||
}, 'withAssociations');
|
||||
urls.sessions = `/scopes/${instances.scopes.org.id}/projects/${instances.scopes.project.id}/sessions`;
|
||||
});
|
||||
|
||||
test('visiting sessions', async function (assert) {
|
||||
assert.expect(2);
|
||||
authenticateSession({});
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.sessions);
|
||||
assert.equal(findAll('tbody tr').length, instances.sessions.length);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('visiting sessions without users or targets is OK', async function (assert) {
|
||||
assert.expect(2);
|
||||
instances.sessions[0].update({
|
||||
userId: null,
|
||||
targetId: null
|
||||
});
|
||||
authenticateSession({});
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.sessions);
|
||||
assert.equal(findAll('tbody tr').length, instances.sessions.length);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('cancelling a session', async function (assert) {
|
||||
assert.expect(2);
|
||||
authenticateSession({});
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click('tbody tr:first-child td:last-child button');
|
||||
assert.ok(find('[role="alert"].is-success'));
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
assert.equal(currentURL(), urls.sessions);
|
||||
});
|
||||
|
||||
test('cancelling a session with error shows notification', async function (assert) {
|
||||
assert.expect(2);
|
||||
this.server.post('/sessions/:id_method', () => new Response(400));
|
||||
authenticateSession({});
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click('tbody tr:first-child td:last-child button');
|
||||
assert.ok(find('[role="alert"].is-error'));
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
assert.equal(currentURL(), urls.sessions);
|
||||
});
|
||||
});
|
||||
@@ -265,6 +265,9 @@ module('Acceptance | targets', function (hooks) {
|
||||
assert.equal(findAll('tbody tr').length, 0);
|
||||
await click('.rose-layout-page-actions a')
|
||||
assert.equal(currentURL(), urls.targetAddHostSets);
|
||||
// Click three times to select, unselect, then reselect (for coverage)
|
||||
await click('tbody label');
|
||||
await click('tbody label');
|
||||
await click('tbody label');
|
||||
await click('form [type="submit"]');
|
||||
await visit(urls.targetHostSets);
|
||||
|
||||
@@ -97,8 +97,11 @@ module('Acceptance | users | accounts', function (hooks) {
|
||||
instances.user.update({ accountIds: [] });
|
||||
await visit(urls.accounts);
|
||||
assert.equal(findAll('tbody tr').length, 0);
|
||||
await click('.rose-layout-page-actions a')
|
||||
await click('.rose-layout-page-actions a');
|
||||
assert.equal(currentURL(), urls.addAccounts);
|
||||
// Click three times to select, unselect, then reselect (for coverage)
|
||||
await click('tbody label');
|
||||
await click('tbody label');
|
||||
await click('tbody label');
|
||||
await click('form [type="submit"]');
|
||||
await visit(urls.accounts);
|
||||
|
||||
@@ -20,6 +20,32 @@ module('Integration | Component | error/message', function (hooks) {
|
||||
find('.rose-message-description').textContent.trim(),
|
||||
'You are not authenticated. Please authenticate and try again later.'
|
||||
);
|
||||
await render(hbs`<Error::Message @status='403' />`);
|
||||
assert.equal(
|
||||
find('.rose-message-title').textContent.trim(),
|
||||
'You are not authorized'
|
||||
);
|
||||
assert.equal(
|
||||
find('.rose-message-subtitle').textContent.trim(),
|
||||
'Error 403'
|
||||
);
|
||||
assert.equal(
|
||||
find('.rose-message-description').textContent.trim(),
|
||||
'You must be granted permissions to view this data. Ask your administrator if you think you should have access.'
|
||||
);
|
||||
await render(hbs`<Error::Message @status='404' />`);
|
||||
assert.equal(
|
||||
find('.rose-message-title').textContent.trim(),
|
||||
'Resource not found'
|
||||
);
|
||||
assert.equal(
|
||||
find('.rose-message-subtitle').textContent.trim(),
|
||||
'Error 404'
|
||||
);
|
||||
assert.equal(
|
||||
find('.rose-message-description').textContent.trim(),
|
||||
'We could not find the requested resource. You can ask your administrator or try again later.'
|
||||
);
|
||||
});
|
||||
|
||||
test('it renders default error for unknown error status', async function (assert) {
|
||||
|
||||
Reference in new issue
Block a user