Merge pull request #503 from hashicorp/tests-coverage-desktop
Build all desktop tests in Github action
This commit is contained in:
13 files changed
+1912
-91
No files matched your search
@@ -413,9 +413,12 @@ export default function () {
|
||||
);
|
||||
this.get('/sessions/:id', function ({ sessions }, { params: { id } }) {
|
||||
const session = sessions.find(id);
|
||||
return session.update({
|
||||
status: pickRandomStatusString(),
|
||||
});
|
||||
if (!Ember.testing) {
|
||||
session.update({
|
||||
status: pickRandomStatusString(),
|
||||
});
|
||||
}
|
||||
return session;
|
||||
});
|
||||
this.post(
|
||||
'/sessions/:idMethod',
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
"clipboard": "^2.0.6",
|
||||
"core": "*",
|
||||
"doctoc": "^1.4.0",
|
||||
"ember-a11y-testing": "^4.0.2",
|
||||
"ember-auto-import": "^1.10.1",
|
||||
"ember-autofocus-modifier": "^1.1.0",
|
||||
"ember-cli": "~3.24.0",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { module, test } from 'qunit';
|
||||
import {
|
||||
visit,
|
||||
currentURL,
|
||||
//fillIn,
|
||||
fillIn,
|
||||
click,
|
||||
find,
|
||||
//findAll,
|
||||
@@ -12,8 +12,8 @@ import {
|
||||
import { run, later } from '@ember/runloop';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
//import { Response } from 'miragejs';
|
||||
//import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import { Response } from 'miragejs';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import {
|
||||
currentSession,
|
||||
authenticateSession,
|
||||
@@ -37,8 +37,6 @@ module('Acceptance | authentication', function (hooks) {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
hostCatalog: null,
|
||||
target: null,
|
||||
};
|
||||
|
||||
const stubs = {
|
||||
@@ -60,6 +58,7 @@ module('Acceptance | authentication', function (hooks) {
|
||||
},
|
||||
},
|
||||
targets: null,
|
||||
sessions: null,
|
||||
};
|
||||
|
||||
const setDefaultOrigin = (test) => {
|
||||
@@ -93,21 +92,13 @@ module('Acceptance | authentication', function (hooks) {
|
||||
scope: instances.scopes.org,
|
||||
});
|
||||
|
||||
instances.hostCatalog = this.server.create(
|
||||
'host-catalog',
|
||||
{ scope: instances.scopes.project },
|
||||
'withChildren'
|
||||
);
|
||||
instances.target = this.server.create(
|
||||
'target',
|
||||
{ scope: instances.scopes.project },
|
||||
'withRandomHostSets'
|
||||
);
|
||||
|
||||
urls.scopes.global = `/scopes/${instances.scopes.global.id}`;
|
||||
urls.scopes.org = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.authenticate.global = `${urls.scopes.global}/authenticate`;
|
||||
urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`;
|
||||
urls.projects = `${urls.scopes.global}/projects`;
|
||||
urls.targets = `${urls.projects}/targets`;
|
||||
urls.sessions = `${urls.projects}/sessions`;
|
||||
|
||||
class MockIPC {
|
||||
origin = null;
|
||||
@@ -147,7 +138,7 @@ module('Acceptance | authentication', function (hooks) {
|
||||
test('visiting index while unauthenticated redirects to global authenticate method', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(urls.index);
|
||||
//await a11yAudit();
|
||||
await a11yAudit();
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
});
|
||||
@@ -156,11 +147,89 @@ module('Acceptance | authentication', function (hooks) {
|
||||
assert.expect(2);
|
||||
instances.authMethods.global.destroy();
|
||||
await visit(urls.authenticate.global);
|
||||
//await a11yAudit();
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.authenticate.global);
|
||||
assert.ok(find('.rose-message'));
|
||||
});
|
||||
|
||||
test('visiting authenticate route without origin redirects to origin index', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.owner.lookup('service:origin').rendererOrigin = null;
|
||||
await visit(urls.authenticate.global);
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.origin);
|
||||
});
|
||||
|
||||
test('visiting authenticate route when the scope cannot be loaded is allowed', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.get('/scopes', () => {
|
||||
return new Response(404);
|
||||
});
|
||||
await visit(urls.authenticate.global);
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
});
|
||||
|
||||
test('failed authentication shows a notification message', async function (assert) {
|
||||
assert.expect(3);
|
||||
await visit(urls.authenticate.methods.global);
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
await fillIn('[name="identification"]', 'error');
|
||||
await click('[type="submit"]');
|
||||
assert.ok(find('.rose-notification.is-error'));
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
});
|
||||
|
||||
test('can reset origin before authentication', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.authenticate.methods.global);
|
||||
await click('.change-origin a');
|
||||
assert.equal(currentURL(), urls.origin);
|
||||
});
|
||||
|
||||
test('deauthentication redirects to first global authenticate method', async function (assert) {
|
||||
assert.expect(3);
|
||||
await visit(urls.authenticate.methods.global);
|
||||
await fillIn('[name="identification"]', 'test');
|
||||
await fillIn('[name="password"]', 'test');
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.ok(currentSession().isAuthenticated);
|
||||
await click('.rose-header-utilities .rose-dropdown summary');
|
||||
assert.equal(
|
||||
find(
|
||||
'.rose-header-utilities .rose-dropdown-content button'
|
||||
).textContent.trim(),
|
||||
'Deauthenticate'
|
||||
);
|
||||
await click('.rose-header-utilities .rose-dropdown-content button');
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
}, 750);
|
||||
await click('[type="submit"]');
|
||||
});
|
||||
|
||||
test('401 responses result in deauthentication', async function (assert) {
|
||||
assert.expect(3);
|
||||
await visit(urls.authenticate.methods.global);
|
||||
await fillIn('[name="identification"]', 'test');
|
||||
await fillIn('[name="password"]', 'test');
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.ok(
|
||||
currentSession().isAuthenticated,
|
||||
'Session begins authenticated, before encountering 401'
|
||||
);
|
||||
assert.ok(currentURL(), urls.targets);
|
||||
this.server.get('/sessions', () => new Response(401));
|
||||
await visit(urls.sessions);
|
||||
assert.notOk(
|
||||
currentSession().isAuthenticated,
|
||||
'Session is unauthenticated, after encountering 401'
|
||||
);
|
||||
}, 750);
|
||||
await click('[type="submit"]');
|
||||
});
|
||||
|
||||
test('color theme is applied from session data', async function (assert) {
|
||||
assert.expect(12);
|
||||
authenticateSession({
|
||||
|
||||
@@ -2,24 +2,27 @@ import { module, test } from 'qunit';
|
||||
import {
|
||||
visit,
|
||||
currentURL,
|
||||
//fillIn,
|
||||
//click,
|
||||
//find,
|
||||
fillIn,
|
||||
click,
|
||||
find,
|
||||
//findAll,
|
||||
//getRootElement
|
||||
//setupOnerror,
|
||||
} from '@ember/test-helpers';
|
||||
import { run, later } from '@ember/runloop';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
//import { Response } from 'miragejs';
|
||||
//import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import sinon from 'sinon';
|
||||
import {
|
||||
//currentSession,
|
||||
//authenticateSession,
|
||||
currentSession,
|
||||
// authenticateSession,
|
||||
invalidateSession,
|
||||
} from 'ember-simple-auth/test-support';
|
||||
import config from '../../config/environment';
|
||||
|
||||
module('Acceptance | authentication', function (hooks) {
|
||||
module('Acceptance | origin', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
@@ -43,6 +46,7 @@ module('Acceptance | authentication', function (hooks) {
|
||||
const stubs = {
|
||||
global: null,
|
||||
org: null,
|
||||
ipcService: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
@@ -54,8 +58,11 @@ module('Acceptance | authentication', function (hooks) {
|
||||
},
|
||||
authenticate: {
|
||||
global: null,
|
||||
org: null,
|
||||
methods: {
|
||||
global: null,
|
||||
},
|
||||
},
|
||||
projects: null,
|
||||
targets: null,
|
||||
};
|
||||
|
||||
@@ -76,13 +83,9 @@ module('Acceptance | authentication', function (hooks) {
|
||||
});
|
||||
stubs.project = { id: instances.scopes.project.id, type: 'project' };
|
||||
|
||||
// create other resources
|
||||
instances.authMethods.global = this.server.create('auth-method', {
|
||||
scope: instances.scopes.global,
|
||||
});
|
||||
instances.authMethods.org = this.server.create('auth-method', {
|
||||
scope: instances.scopes.org,
|
||||
});
|
||||
|
||||
instances.hostCatalog = this.server.create(
|
||||
'host-catalog',
|
||||
@@ -96,9 +99,10 @@ module('Acceptance | authentication', function (hooks) {
|
||||
);
|
||||
|
||||
urls.scopes.global = `/scopes/${instances.scopes.global.id}`;
|
||||
urls.scopes.org = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.authenticate.global = `${urls.scopes.global}/authenticate/${instances.authMethods.global.id}`;
|
||||
urls.authenticate.org = `${urls.scopes.global}/authenticate/${instances.authMethods.org.id}`;
|
||||
urls.authenticate.global = `${urls.scopes.global}/authenticate`;
|
||||
urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`;
|
||||
urls.projects = `${urls.scopes.global}/projects`;
|
||||
urls.targets = `${urls.projects}/targets`;
|
||||
|
||||
class MockIPC {
|
||||
origin = null;
|
||||
@@ -115,6 +119,8 @@ module('Acceptance | authentication', function (hooks) {
|
||||
this.origin = origin;
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
resetOrigin() {}
|
||||
}
|
||||
|
||||
mockIPC = new MockIPC();
|
||||
@@ -132,13 +138,92 @@ module('Acceptance | authentication', function (hooks) {
|
||||
|
||||
hooks.afterEach(function () {
|
||||
window.removeEventListener('message', messageHandler);
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
test('visiting index', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.origin);
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.origin);
|
||||
});
|
||||
|
||||
test('visiting index without an origin specified redirects to origin route', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(urls.index);
|
||||
//await a11yAudit();
|
||||
await a11yAudit();
|
||||
assert.notOk(mockIPC.origin);
|
||||
assert.equal(currentURL(), urls.origin);
|
||||
});
|
||||
|
||||
test('can set origin', async function (assert) {
|
||||
assert.expect(2);
|
||||
assert.notOk(mockIPC.origin);
|
||||
await visit(urls.origin);
|
||||
await a11yAudit();
|
||||
await fillIn('[name="host"]', window.location.origin);
|
||||
await click('[type="submit"]');
|
||||
assert.equal(mockIPC.origin, window.location.origin);
|
||||
});
|
||||
|
||||
test('captures error on origin update', async function (assert) {
|
||||
assert.expect(2);
|
||||
assert.notOk(mockIPC.origin);
|
||||
sinon.stub(this.owner.lookup('service:origin'), 'setOrigin').throws();
|
||||
await visit(urls.origin);
|
||||
await a11yAudit();
|
||||
await fillIn('[name="host"]', window.location.origin);
|
||||
await click('[type="submit"]');
|
||||
assert.ok(find('.rose-notification.is-error'));
|
||||
});
|
||||
|
||||
test('can reset origin before authentication', async function (assert) {
|
||||
assert.expect(4);
|
||||
assert.notOk(mockIPC.origin);
|
||||
await visit(urls.origin);
|
||||
await fillIn('[name="host"]', window.location.origin);
|
||||
await click('[type="submit"]');
|
||||
assert.equal(mockIPC.origin, window.location.origin);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
await click('.change-origin a');
|
||||
assert.equal(currentURL(), urls.origin);
|
||||
});
|
||||
|
||||
test('origin set automatically in dev mode', async function (assert) {
|
||||
assert.expect(1);
|
||||
config.autoOrigin = true;
|
||||
await visit(urls.origin);
|
||||
await fillIn('[name="host"]', window.location.origin);
|
||||
await click('[type="submit"]');
|
||||
assert.equal(
|
||||
this.owner.lookup('controller:origin').origin,
|
||||
window.location.origin
|
||||
);
|
||||
config.autoOrigin = false;
|
||||
});
|
||||
|
||||
test('can reset origin on error', async function (assert) {
|
||||
assert.expect(4);
|
||||
await visit(urls.origin);
|
||||
await a11yAudit();
|
||||
await fillIn('[name="host"]', window.location.origin);
|
||||
await click('[type="submit"]');
|
||||
await fillIn('[name="identification"]', 'test');
|
||||
await fillIn('[name="password"]', 'test');
|
||||
this.server.get('/targets', () => new Response(500));
|
||||
await later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.ok(currentSession().isAuthenticated);
|
||||
assert.equal(
|
||||
find('main section button').textContent.trim(),
|
||||
'Disconnect'
|
||||
);
|
||||
}, 750);
|
||||
await click('[type="submit"]');
|
||||
later(async () => {
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
}, 750);
|
||||
await click('main section button');
|
||||
});
|
||||
});
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
//import { Response } from 'miragejs';
|
||||
//import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import {
|
||||
currentSession,
|
||||
authenticateSession,
|
||||
@@ -142,7 +142,7 @@ module('Acceptance | projects', function (hooks) {
|
||||
invalidateSession();
|
||||
assert.expect(2);
|
||||
await visit(urls.projects);
|
||||
//await a11yAudit();
|
||||
await a11yAudit();
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
});
|
||||
@@ -150,7 +150,7 @@ module('Acceptance | projects', function (hooks) {
|
||||
test('visiting index', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.projects);
|
||||
//await a11yAudit();
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.projects);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,261 @@
|
||||
import { module, test } from 'qunit';
|
||||
import {
|
||||
visit,
|
||||
currentURL,
|
||||
//fillIn,
|
||||
click,
|
||||
find,
|
||||
findAll,
|
||||
//getRootElement
|
||||
//setupOnerror,
|
||||
} from '@ember/test-helpers';
|
||||
import { run, later } from '@ember/runloop';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { Response } from 'miragejs';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import {
|
||||
currentSession,
|
||||
authenticateSession,
|
||||
invalidateSession,
|
||||
} from 'ember-simple-auth/test-support';
|
||||
|
||||
module('Acceptance | projects | sessions', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let mockIPC;
|
||||
let messageHandler;
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
project: null,
|
||||
},
|
||||
authMethods: {
|
||||
global: null,
|
||||
},
|
||||
user: null,
|
||||
session: null,
|
||||
};
|
||||
|
||||
const stubs = {
|
||||
global: null,
|
||||
org: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
index: '/',
|
||||
origin: '/origin',
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
authenticate: {
|
||||
global: null,
|
||||
methods: {
|
||||
global: null,
|
||||
},
|
||||
},
|
||||
projects: null,
|
||||
sessions: null,
|
||||
};
|
||||
|
||||
const setDefaultOrigin = (test) => {
|
||||
const windowOrigin = window.location.origin;
|
||||
const origin = test.owner.lookup('service:origin');
|
||||
origin.rendererOrigin = windowOrigin;
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
instances.user = this.server.create('user', {
|
||||
scope: instances.scopes.global,
|
||||
});
|
||||
|
||||
authenticateSession({ user_id: instances.user.id });
|
||||
|
||||
// create scopes
|
||||
instances.scopes.global = this.server.create('scope', { id: 'global' });
|
||||
stubs.global = { id: 'global', type: 'global' };
|
||||
instances.scopes.org = this.server.create('scope', {
|
||||
type: 'org',
|
||||
scope: stubs.global,
|
||||
});
|
||||
stubs.org = { id: instances.scopes.org.id, type: 'org' };
|
||||
instances.scopes.project = this.server.create('scope', {
|
||||
type: 'project',
|
||||
scope: stubs.org,
|
||||
});
|
||||
stubs.project = { id: instances.scopes.project.id, type: 'project' };
|
||||
|
||||
instances.authMethods.global = this.server.create('auth-method', {
|
||||
scope: instances.scopes.global,
|
||||
});
|
||||
instances.target = this.server.create(
|
||||
'target',
|
||||
{ scope: instances.scopes.project },
|
||||
'withRandomHostSets'
|
||||
);
|
||||
instances.session = this.server.create(
|
||||
'session',
|
||||
{
|
||||
scope: instances.scopes.project,
|
||||
target: instances.target,
|
||||
status: 'active',
|
||||
user: instances.user,
|
||||
},
|
||||
'withAssociations'
|
||||
);
|
||||
|
||||
urls.scopes.global = `/scopes/${instances.scopes.global.id}`;
|
||||
urls.scopes.org = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.authenticate.global = `${urls.scopes.global}/authenticate`;
|
||||
urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`;
|
||||
urls.projects = `${urls.scopes.org}/projects`;
|
||||
urls.sessions = `${urls.projects}/sessions`;
|
||||
|
||||
class MockIPC {
|
||||
origin = null;
|
||||
|
||||
invoke(method, payload) {
|
||||
return this[method](payload);
|
||||
}
|
||||
|
||||
getOrigin() {
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
setOrigin(origin) {
|
||||
this.origin = origin;
|
||||
return this.origin;
|
||||
}
|
||||
}
|
||||
|
||||
mockIPC = new MockIPC();
|
||||
messageHandler = async function (event) {
|
||||
if (event.origin !== window.location.origin) return;
|
||||
const { method, payload } = event.data;
|
||||
if (method) {
|
||||
const response = await mockIPC.invoke(method, payload);
|
||||
event.ports[0].postMessage(response);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', messageHandler);
|
||||
setDefaultOrigin(this);
|
||||
});
|
||||
|
||||
hooks.afterEach(function () {
|
||||
window.removeEventListener('message', messageHandler);
|
||||
});
|
||||
|
||||
test('visiting index while unauthenticated redirects to global authenticate method', async function (assert) {
|
||||
invalidateSession();
|
||||
assert.expect(2);
|
||||
await visit(urls.sessions);
|
||||
await a11yAudit();
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
});
|
||||
|
||||
test('visiting index', async function (assert) {
|
||||
assert.expect(2);
|
||||
const sessionsCount = this.server.schema.sessions.all().models.length;
|
||||
// This later/cancelTimers technique allows us to test a page with
|
||||
// active polling. Normally an acceptance test waits for all runloop timers
|
||||
// to stop before returning from an awaited test, but polling means that
|
||||
// runloop timers exist indefinitely. We thus schedule a cancelation before
|
||||
// proceeding with our tests.
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
// await a11yAudit();
|
||||
assert.equal(currentURL(), urls.sessions);
|
||||
assert.equal(findAll('tbody tr').length, sessionsCount);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('visiting empty sessions', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.get('/sessions', () => new Response(200));
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await a11yAudit();
|
||||
assert.ok(
|
||||
find('.rose-message-title').textContent.trim(),
|
||||
'No Sessions Available'
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('visiting sessions without targets is OK', async function (assert) {
|
||||
assert.expect(2);
|
||||
instances.session.update({ targetId: undefined });
|
||||
const sessionsCount = this.server.schema.sessions.all().models.length;
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.sessions);
|
||||
assert.equal(findAll('tbody tr').length, sessionsCount);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('can identify active sessions', async function (assert) {
|
||||
assert.expect(1);
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.ok(
|
||||
find('tbody tr:first-child th:first-child .session-status-active')
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('cannot identify pending sessions', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.session.update({ status: 'pending' });
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.notOk(
|
||||
find('tbody tr:first-child th:first-child .session-status-active')
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('cannot identify terminated sessions', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.session.update({ status: 'terminated' });
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.notOk(
|
||||
find('tbody tr:first-child th:first-child .session-status-active')
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('cancelling a session', async function (assert) {
|
||||
assert.expect(1);
|
||||
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);
|
||||
});
|
||||
|
||||
test('cancelling a session with error shows notification', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.post('/sessions/:id_method', () => new Response(400));
|
||||
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);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,307 @@
|
||||
import { module, test } from 'qunit';
|
||||
import {
|
||||
visit,
|
||||
currentURL,
|
||||
//fillIn,
|
||||
click,
|
||||
find,
|
||||
findAll,
|
||||
//getRootElement
|
||||
//setupOnerror,
|
||||
} from '@ember/test-helpers';
|
||||
import { run, later } from '@ember/runloop';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { Response } from 'miragejs';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import sinon from 'sinon';
|
||||
import {
|
||||
currentSession,
|
||||
authenticateSession,
|
||||
invalidateSession,
|
||||
} from 'ember-simple-auth/test-support';
|
||||
|
||||
module('Acceptance | projects | targets', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let mockIPC;
|
||||
let messageHandler;
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
project: null,
|
||||
},
|
||||
authMethods: {
|
||||
global: null,
|
||||
},
|
||||
target: null,
|
||||
session: null,
|
||||
};
|
||||
|
||||
const stubs = {
|
||||
global: null,
|
||||
org: null,
|
||||
ipsService: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
index: '/',
|
||||
origin: '/origin',
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
authenticate: {
|
||||
global: null,
|
||||
methods: {
|
||||
global: null,
|
||||
},
|
||||
},
|
||||
projects: null,
|
||||
targets: null,
|
||||
target: null,
|
||||
sessions: null,
|
||||
};
|
||||
|
||||
const setDefaultOrigin = (test) => {
|
||||
const windowOrigin = window.location.origin;
|
||||
const origin = test.owner.lookup('service:origin');
|
||||
origin.rendererOrigin = windowOrigin;
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
authenticateSession();
|
||||
|
||||
// create scopes
|
||||
instances.scopes.global = this.server.create('scope', { id: 'global' });
|
||||
stubs.global = { id: 'global', type: 'global' };
|
||||
instances.scopes.org = this.server.create('scope', {
|
||||
type: 'org',
|
||||
scope: stubs.global,
|
||||
});
|
||||
stubs.org = { id: instances.scopes.org.id, type: 'org' };
|
||||
instances.scopes.project = this.server.create('scope', {
|
||||
type: 'project',
|
||||
scope: stubs.org,
|
||||
});
|
||||
stubs.project = { id: instances.scopes.project.id, type: 'project' };
|
||||
|
||||
instances.authMethods.global = this.server.create('auth-method', {
|
||||
scope: instances.scopes.global,
|
||||
});
|
||||
|
||||
instances.hostCatalog = this.server.create(
|
||||
'host-catalog',
|
||||
{ scope: instances.scopes.project },
|
||||
'withChildren'
|
||||
);
|
||||
instances.target = this.server.create(
|
||||
'target',
|
||||
{ scope: instances.scopes.project },
|
||||
'withRandomHostSets'
|
||||
);
|
||||
|
||||
instances.session = this.server.create(
|
||||
'session',
|
||||
{
|
||||
scope: instances.scopes.project,
|
||||
status: 'active',
|
||||
},
|
||||
'withAssociations'
|
||||
);
|
||||
|
||||
urls.scopes.global = `/scopes/${instances.scopes.global.id}`;
|
||||
urls.scopes.org = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.authenticate.global = `${urls.scopes.global}/authenticate`;
|
||||
urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`;
|
||||
urls.projects = `${urls.scopes.org}/projects`;
|
||||
urls.targets = `${urls.projects}/targets`;
|
||||
urls.target = `${urls.targets}/${instances.target.id}`;
|
||||
urls.sessions = `${urls.target}/sessions`;
|
||||
|
||||
class MockIPC {
|
||||
origin = null;
|
||||
|
||||
invoke(method, payload) {
|
||||
return this[method](payload);
|
||||
}
|
||||
|
||||
getOrigin() {
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
setOrigin(origin) {
|
||||
this.origin = origin;
|
||||
return this.origin;
|
||||
}
|
||||
}
|
||||
|
||||
mockIPC = new MockIPC();
|
||||
messageHandler = async function (event) {
|
||||
if (event.origin !== window.location.origin) return;
|
||||
const { method, payload } = event.data;
|
||||
if (method) {
|
||||
const response = await mockIPC.invoke(method, payload);
|
||||
event.ports[0].postMessage(response);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', messageHandler);
|
||||
setDefaultOrigin(this);
|
||||
|
||||
const ipcService = this.owner.lookup('service:ipc');
|
||||
stubs.ipcService = sinon.stub(ipcService, 'invoke');
|
||||
});
|
||||
|
||||
hooks.afterEach(function () {
|
||||
window.removeEventListener('message', messageHandler);
|
||||
});
|
||||
|
||||
test('visiting index while unauthenticated redirects to global authenticate method', async function (assert) {
|
||||
invalidateSession();
|
||||
assert.expect(2);
|
||||
await visit(urls.targets);
|
||||
await a11yAudit();
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
});
|
||||
|
||||
test('visiting index', async function (assert) {
|
||||
assert.expect(2);
|
||||
const targetsCount = this.server.schema.targets.all().models.length;
|
||||
// This later/cancelTimers technique allows us to test a page with
|
||||
// active polling. Normally an acceptance test waits for all runloop timers
|
||||
// to stop before returning from an awaited test, but polling means that
|
||||
// runloop timers exist indefinitely. We thus schedule a cancelation before
|
||||
// proceeding with our tests.
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.targets);
|
||||
assert.equal(findAll('tbody tr').length, targetsCount);
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
|
||||
test('visiting a target', async function (assert) {
|
||||
assert.expect(1);
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click('tbody tr th a');
|
||||
assert.equal(currentURL(), urls.sessions);
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
|
||||
test('visiting empty targets', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.get('/targets', () => new Response(200));
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.equal(
|
||||
find('.rose-message-title').textContent.trim(),
|
||||
'No Targets Available'
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
|
||||
test('connecting to a target', async function (assert) {
|
||||
assert.expect(4);
|
||||
stubs.ipcService.withArgs('cliExists').returns(true);
|
||||
stubs.ipcService.withArgs('connect').returns({
|
||||
session_id: instances.session.id,
|
||||
address: 'a_123',
|
||||
port: 'p_123',
|
||||
protocol: 'tcp',
|
||||
});
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
assert.ok(find('.rose-dialog-success'), 'Success dialog');
|
||||
assert.equal(findAll('.rose-dialog-footer button').length, 1);
|
||||
assert.equal(
|
||||
find('.rose-dialog-footer button').textContent.trim(),
|
||||
'OK',
|
||||
'Cannot retry'
|
||||
);
|
||||
assert.equal(
|
||||
find('.rose-dialog-body .copyable-content').textContent.trim(),
|
||||
'Local proxy address (tcp): a_123:p_123'
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
|
||||
test('handles cli error on connect', async function (assert) {
|
||||
assert.expect(4);
|
||||
stubs.ipcService.withArgs('cliExists').returns(true);
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
assert.ok(find('.rose-dialog-error'), 'Error dialog');
|
||||
const dialogButtons = findAll('.rose-dialog-footer button');
|
||||
assert.equal(dialogButtons.length, 2);
|
||||
assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry');
|
||||
assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel');
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
|
||||
test('handles connect error', async function (assert) {
|
||||
assert.expect(4);
|
||||
stubs.ipcService.withArgs('cliExists').returns(true);
|
||||
stubs.ipcService.withArgs('connect').rejects();
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
assert.ok(find('.rose-dialog-error'), 'Error dialog');
|
||||
const dialogButtons = findAll('.rose-dialog-footer button');
|
||||
assert.equal(dialogButtons.length, 2);
|
||||
assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry');
|
||||
assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel');
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
|
||||
test('can retry on error', async function (assert) {
|
||||
assert.expect(1);
|
||||
stubs.ipcService.withArgs('cliExists').rejects();
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
const firstErrorDialog = find('.rose-dialog');
|
||||
await click('.rose-dialog footer .rose-button-primary', 'Retry');
|
||||
const secondErrorDialog = find('.rose-dialog');
|
||||
assert.notEqual(secondErrorDialog.id, firstErrorDialog.id);
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,298 @@
|
||||
import { module, test } from 'qunit';
|
||||
import {
|
||||
visit,
|
||||
currentURL,
|
||||
//fillIn,
|
||||
click,
|
||||
find,
|
||||
findAll,
|
||||
//getRootElement
|
||||
//setupOnerror,
|
||||
} from '@ember/test-helpers';
|
||||
import { run, later } from '@ember/runloop';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
// import { Response } from 'miragejs';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import sinon from 'sinon';
|
||||
import {
|
||||
currentSession,
|
||||
authenticateSession,
|
||||
invalidateSession,
|
||||
} from 'ember-simple-auth/test-support';
|
||||
|
||||
module('Acceptance | projects | targets | hosts', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let mockIPC;
|
||||
let messageHandler;
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
project: null,
|
||||
},
|
||||
authMethods: {
|
||||
global: null,
|
||||
},
|
||||
user: null,
|
||||
target: null,
|
||||
session: null,
|
||||
};
|
||||
|
||||
const stubs = {
|
||||
global: null,
|
||||
org: null,
|
||||
ipcService: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
index: '/',
|
||||
origin: '/origin',
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
authenticate: {
|
||||
global: null,
|
||||
methods: {
|
||||
global: null,
|
||||
},
|
||||
},
|
||||
projects: null,
|
||||
targets: null,
|
||||
target: null,
|
||||
hosts: null,
|
||||
};
|
||||
|
||||
const setDefaultOrigin = (test) => {
|
||||
const windowOrigin = window.location.origin;
|
||||
const origin = test.owner.lookup('service:origin');
|
||||
origin.rendererOrigin = windowOrigin;
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
instances.user = this.server.create('user', {
|
||||
scope: instances.scopes.global,
|
||||
});
|
||||
|
||||
authenticateSession({ user_id: instances.user.id });
|
||||
|
||||
// create scopes
|
||||
instances.scopes.global = this.server.create('scope', { id: 'global' });
|
||||
stubs.global = { id: 'global', type: 'global' };
|
||||
instances.scopes.org = this.server.create('scope', {
|
||||
type: 'org',
|
||||
scope: stubs.global,
|
||||
});
|
||||
stubs.org = { id: instances.scopes.org.id, type: 'org' };
|
||||
instances.scopes.project = this.server.create('scope', {
|
||||
type: 'project',
|
||||
scope: stubs.org,
|
||||
});
|
||||
stubs.project = { id: instances.scopes.project.id, type: 'project' };
|
||||
|
||||
instances.authMethods.global = this.server.create('auth-method', {
|
||||
scope: instances.scopes.global,
|
||||
});
|
||||
instances.hostCatalog = this.server.create(
|
||||
'host-catalog',
|
||||
{ scope: instances.scopes.project },
|
||||
'withChildren'
|
||||
);
|
||||
instances.target = this.server.create('target', {
|
||||
scope: instances.scopes.project,
|
||||
hostSets: instances.hostCatalog.hostSets,
|
||||
});
|
||||
instances.session = this.server.create(
|
||||
'session',
|
||||
{
|
||||
scope: instances.scopes.project,
|
||||
status: 'active',
|
||||
},
|
||||
'withAssociations'
|
||||
);
|
||||
|
||||
urls.scopes.global = `/scopes/${instances.scopes.global.id}`;
|
||||
urls.scopes.org = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.authenticate.global = `${urls.scopes.global}/authenticate`;
|
||||
urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`;
|
||||
urls.projects = `${urls.scopes.org}/projects`;
|
||||
urls.targets = `${urls.projects}/targets`;
|
||||
urls.target = `${urls.targets}/${instances.target.id}`;
|
||||
urls.hosts = `${urls.target}/hosts`;
|
||||
|
||||
class MockIPC {
|
||||
origin = null;
|
||||
|
||||
invoke(method, payload) {
|
||||
return this[method](payload);
|
||||
}
|
||||
|
||||
getOrigin() {
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
setOrigin(origin) {
|
||||
this.origin = origin;
|
||||
return this.origin;
|
||||
}
|
||||
}
|
||||
|
||||
mockIPC = new MockIPC();
|
||||
messageHandler = async function (event) {
|
||||
if (event.origin !== window.location.origin) return;
|
||||
const { method, payload } = event.data;
|
||||
if (method) {
|
||||
const response = await mockIPC.invoke(method, payload);
|
||||
event.ports[0].postMessage(response);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', messageHandler);
|
||||
setDefaultOrigin(this);
|
||||
|
||||
const ipcService = this.owner.lookup('service:ipc');
|
||||
stubs.ipcService = sinon.stub(ipcService, 'invoke');
|
||||
});
|
||||
|
||||
hooks.afterEach(function () {
|
||||
window.removeEventListener('message', messageHandler);
|
||||
});
|
||||
|
||||
test('visiting index while unauthenticated redirects to global authenticate method', async function (assert) {
|
||||
invalidateSession();
|
||||
assert.expect(2);
|
||||
await visit(urls.hosts);
|
||||
await a11yAudit();
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
});
|
||||
|
||||
test('visiting index', async function (assert) {
|
||||
assert.expect(2);
|
||||
const hostsCount = this.server.schema.hosts.all().models.length;
|
||||
// This later/cancelTimers technique allows us to test a page with
|
||||
// active polling. Normally an acceptance test waits for all runloop timers
|
||||
// to stop before returning from an awaited test, but polling means that
|
||||
// runloop timers exist indefinitely. We thus schedule a cancelation before
|
||||
// proceeding with our tests.
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
// await a11yAudit();
|
||||
assert.equal(currentURL(), urls.hosts);
|
||||
assert.equal(findAll('tbody tr').length, hostsCount);
|
||||
}, 750);
|
||||
await visit(urls.hosts);
|
||||
});
|
||||
|
||||
test('visiting empty hosts', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.target.update({ hostSets: [] });
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.ok(
|
||||
find('.rose-message-title').textContent.trim(),
|
||||
'No Hosts Available'
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.hosts);
|
||||
});
|
||||
|
||||
test('connecting to a host', async function (assert) {
|
||||
assert.expect(3);
|
||||
stubs.ipcService.withArgs('cliExists').returns(true);
|
||||
stubs.ipcService.withArgs('connect').returns({
|
||||
session_id: instances.session.id,
|
||||
address: 'a_123',
|
||||
port: 'p_123',
|
||||
protocol: 'tcp',
|
||||
});
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
assert.ok(find('.rose-dialog-success'), 'Success dialog');
|
||||
assert.equal(
|
||||
find('.rose-dialog-footer .rose-button-primary').textContent.trim(),
|
||||
'OK',
|
||||
'Cannot retry'
|
||||
);
|
||||
assert.equal(
|
||||
find('.rose-dialog-body .copyable-content').textContent.trim(),
|
||||
'Local proxy address (tcp): a_123:p_123'
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.hosts);
|
||||
});
|
||||
|
||||
test('handles cli error on connect', async function (assert) {
|
||||
assert.expect(4);
|
||||
stubs.ipcService.withArgs('cliExists').returns(false);
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
assert.ok(find('.rose-dialog-error'), 'Error dialog');
|
||||
const dialogButtons = findAll('.rose-dialog-footer button');
|
||||
assert.equal(dialogButtons.length, 2);
|
||||
assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry');
|
||||
assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel');
|
||||
}, 750);
|
||||
await visit(urls.hosts);
|
||||
});
|
||||
|
||||
test('handles connect error', async function (assert) {
|
||||
assert.expect(4);
|
||||
stubs.ipcService.withArgs('cliExists').returns(true);
|
||||
stubs.ipcService.withArgs('connect').rejects();
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
assert.ok(find('.rose-dialog-error'), 'Error dialog');
|
||||
const dialogButtons = findAll('.rose-dialog-footer button');
|
||||
assert.equal(dialogButtons.length, 2);
|
||||
assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry');
|
||||
assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel');
|
||||
}, 750);
|
||||
await visit(urls.hosts);
|
||||
});
|
||||
|
||||
test('can retry on error', async function (assert) {
|
||||
assert.expect(1);
|
||||
stubs.ipcService.withArgs('cliExists').rejects();
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
const firstErrorDialog = find('.rose-dialog');
|
||||
await click('.rose-dialog footer .rose-button-primary', 'Retry');
|
||||
const secondErrorDialog = find('.rose-dialog');
|
||||
assert.notEqual(secondErrorDialog.id, firstErrorDialog.id);
|
||||
}, 750);
|
||||
await visit(urls.hosts);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,381 @@
|
||||
import { module, test } from 'qunit';
|
||||
import {
|
||||
visit,
|
||||
currentURL,
|
||||
//fillIn,
|
||||
click,
|
||||
find,
|
||||
findAll,
|
||||
//getRootElement
|
||||
//setupOnerror,
|
||||
} from '@ember/test-helpers';
|
||||
import { run, later } from '@ember/runloop';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { Response } from 'miragejs';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import sinon from 'sinon';
|
||||
import {
|
||||
currentSession,
|
||||
authenticateSession,
|
||||
invalidateSession,
|
||||
} from 'ember-simple-auth/test-support';
|
||||
|
||||
module('Acceptance | projects | targets | sessions', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let mockIPC;
|
||||
let messageHandler;
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
project: null,
|
||||
},
|
||||
authMethods: {
|
||||
global: null,
|
||||
},
|
||||
user: null,
|
||||
target: null,
|
||||
session: null,
|
||||
};
|
||||
|
||||
const stubs = {
|
||||
global: null,
|
||||
org: null,
|
||||
ipcService: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
index: '/',
|
||||
origin: '/origin',
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
authenticate: {
|
||||
global: null,
|
||||
methods: {
|
||||
global: null,
|
||||
},
|
||||
},
|
||||
projects: null,
|
||||
targets: null,
|
||||
target: null,
|
||||
sessions: null,
|
||||
};
|
||||
|
||||
const setDefaultOrigin = (test) => {
|
||||
const windowOrigin = window.location.origin;
|
||||
const origin = test.owner.lookup('service:origin');
|
||||
origin.rendererOrigin = windowOrigin;
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
instances.user = this.server.create('user', {
|
||||
scope: instances.scopes.global,
|
||||
});
|
||||
|
||||
authenticateSession({ user_id: instances.user.id });
|
||||
|
||||
// create scopes
|
||||
instances.scopes.global = this.server.create('scope', { id: 'global' });
|
||||
stubs.global = { id: 'global', type: 'global' };
|
||||
instances.scopes.org = this.server.create('scope', {
|
||||
type: 'org',
|
||||
scope: stubs.global,
|
||||
});
|
||||
stubs.org = { id: instances.scopes.org.id, type: 'org' };
|
||||
instances.scopes.project = this.server.create('scope', {
|
||||
type: 'project',
|
||||
scope: stubs.org,
|
||||
});
|
||||
stubs.project = { id: instances.scopes.project.id, type: 'project' };
|
||||
|
||||
instances.authMethods.global = this.server.create('auth-method', {
|
||||
scope: instances.scopes.global,
|
||||
});
|
||||
|
||||
instances.hostCatalog = this.server.create(
|
||||
'host-catalog',
|
||||
{ scope: instances.scopes.project },
|
||||
'withChildren'
|
||||
);
|
||||
instances.target = this.server.create(
|
||||
'target',
|
||||
{ scope: instances.scopes.project },
|
||||
'withRandomHostSets'
|
||||
);
|
||||
|
||||
instances.session = this.server.create(
|
||||
'session',
|
||||
{
|
||||
scope: instances.scopes.project,
|
||||
target: instances.target,
|
||||
status: 'active',
|
||||
user: instances.user,
|
||||
},
|
||||
'withAssociations'
|
||||
);
|
||||
|
||||
urls.scopes.global = `/scopes/${instances.scopes.global.id}`;
|
||||
urls.scopes.org = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.authenticate.global = `${urls.scopes.global}/authenticate`;
|
||||
urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`;
|
||||
urls.projects = `${urls.scopes.org}/projects`;
|
||||
urls.targets = `${urls.projects}/targets`;
|
||||
urls.target = `${urls.targets}/${instances.target.id}`;
|
||||
urls.sessions = `${urls.target}/sessions`;
|
||||
|
||||
class MockIPC {
|
||||
origin = null;
|
||||
|
||||
invoke(method, payload) {
|
||||
return this[method](payload);
|
||||
}
|
||||
|
||||
getOrigin() {
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
setOrigin(origin) {
|
||||
this.origin = origin;
|
||||
return this.origin;
|
||||
}
|
||||
}
|
||||
|
||||
mockIPC = new MockIPC();
|
||||
messageHandler = async function (event) {
|
||||
if (event.origin !== window.location.origin) return;
|
||||
const { method, payload } = event.data;
|
||||
if (method) {
|
||||
const response = await mockIPC.invoke(method, payload);
|
||||
event.ports[0].postMessage(response);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', messageHandler);
|
||||
setDefaultOrigin(this);
|
||||
|
||||
const ipcService = this.owner.lookup('service:ipc');
|
||||
stubs.ipcService = sinon.stub(ipcService, 'invoke');
|
||||
});
|
||||
|
||||
hooks.afterEach(function () {
|
||||
window.removeEventListener('message', messageHandler);
|
||||
});
|
||||
|
||||
test('visiting index while unauthenticated redirects to global authenticate method', async function (assert) {
|
||||
invalidateSession();
|
||||
assert.expect(2);
|
||||
await visit(urls.sessions);
|
||||
await a11yAudit();
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
});
|
||||
|
||||
test('visiting index', async function (assert) {
|
||||
assert.expect(2);
|
||||
const sessionsCount = this.server.schema.sessions.all().models.length;
|
||||
// This later/cancelTimers technique allows us to test a page with
|
||||
// active polling. Normally an acceptance test waits for all runloop timers
|
||||
// to stop before returning from an awaited test, but polling means that
|
||||
// runloop timers exist indefinitely. We thus schedule a cancelation before
|
||||
// proceeding with our tests.
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
// await a11yAudit();
|
||||
assert.equal(currentURL(), urls.sessions);
|
||||
assert.equal(findAll('tbody tr').length, sessionsCount);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('visiting index redirects to sessions', async function (assert) {
|
||||
assert.expect(1);
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
// await a11yAudit();
|
||||
assert.equal(currentURL(), urls.sessions);
|
||||
}, 750);
|
||||
await visit(urls.target);
|
||||
});
|
||||
|
||||
test('visiting empty sessions', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.get('/sessions', () => new Response(200));
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.ok(
|
||||
find('.rose-message-title').textContent.trim(),
|
||||
'No Sessions Available'
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('can identify target with active sessions', async function (assert) {
|
||||
assert.expect(1);
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.ok(find('.rose-layout-page-header .rose-badge-success'));
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('can identify target with pending sessions', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.session.update({ status: 'pending' });
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.ok(find('.rose-layout-page-header .rose-badge-success'));
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('cannot identify target with terminated sessions', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.session.update({ status: 'terminated' });
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.notOk(find('.rose-layout-page-header .rose-badge-success'));
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('cancelling a session', async function (assert) {
|
||||
assert.expect(2);
|
||||
const sessionsCount = this.server.schema.sessions.all().models.length;
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click('tbody tr:first-child td:last-child button');
|
||||
assert.ok(find('[role="alert"].is-success'));
|
||||
assert.equal(findAll('tbody tr').length, sessionsCount - 1);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('cancelling a session with error shows notification', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.post('/sessions/:id_method', () => new Response(400));
|
||||
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);
|
||||
});
|
||||
|
||||
test('connecting to a target', async function (assert) {
|
||||
assert.expect(3);
|
||||
stubs.ipcService.withArgs('cliExists').returns(true);
|
||||
stubs.ipcService.withArgs('connect').returns({
|
||||
session_id: instances.session.id,
|
||||
address: 'a_123',
|
||||
port: 'p_123',
|
||||
protocol: 'tcp',
|
||||
});
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click('.rose-layout-page-actions button', 'Activate connect mode');
|
||||
assert.ok(find('.rose-dialog-success'), 'Success dialog');
|
||||
assert.equal(
|
||||
find('.rose-dialog-footer .rose-button-primary').textContent.trim(),
|
||||
'OK',
|
||||
'Cannot retry'
|
||||
);
|
||||
assert.equal(
|
||||
find('.rose-dialog-body .copyable-content').textContent.trim(),
|
||||
'Local proxy address (tcp): a_123:p_123'
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('connect details in session', async function (assert) {
|
||||
assert.expect(2);
|
||||
stubs.ipcService.withArgs('cliExists').returns(true);
|
||||
stubs.ipcService.withArgs('connect').returns({
|
||||
session_id: instances.session.id,
|
||||
address: 'a_123',
|
||||
port: 'p_123',
|
||||
protocol: 'tcp',
|
||||
});
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
instances.session.update('status', 'active');
|
||||
await click('.rose-layout-page-actions button', 'Activate connect mode');
|
||||
assert.ok(find('.rose-dialog-success'), 'Success dialog');
|
||||
await click('.rose-dialog-dismiss');
|
||||
assert.equal(
|
||||
find(
|
||||
'tbody tr:first-child td:nth-child(2) .copyable-content'
|
||||
).textContent.trim(),
|
||||
'a_123:p_123'
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('handles cli error on connect', async function (assert) {
|
||||
assert.expect(4);
|
||||
stubs.ipcService.withArgs('cliExists').returns(false);
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click('.rose-layout-page-actions button', 'Activate connect mode');
|
||||
assert.ok(find('.rose-dialog-error'), 'Error dialog');
|
||||
const dialogButtons = findAll('.rose-dialog-footer button');
|
||||
assert.equal(dialogButtons.length, 2);
|
||||
assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry');
|
||||
assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel');
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('handles connect error', async function (assert) {
|
||||
assert.expect(4);
|
||||
stubs.ipcService.withArgs('cliExists').returns(true);
|
||||
stubs.ipcService.withArgs('connect').rejects();
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click('.rose-layout-page-actions button', 'Activate connect mode');
|
||||
assert.ok(find('.rose-dialog-error'), 'Error dialog');
|
||||
const dialogButtons = findAll('.rose-dialog-footer button');
|
||||
assert.equal(dialogButtons.length, 2);
|
||||
assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry');
|
||||
assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel');
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
|
||||
test('can retry on error', async function (assert) {
|
||||
assert.expect(1);
|
||||
stubs.ipcService.withArgs('cliExists').rejects();
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click('.rose-layout-page-actions button', 'Activate connect mode');
|
||||
const firstErrorDialog = find('.rose-dialog');
|
||||
await click('.rose-dialog footer .rose-button-primary', 'Retry');
|
||||
const secondErrorDialog = find('.rose-dialog');
|
||||
assert.notEqual(secondErrorDialog.id, firstErrorDialog.id);
|
||||
}, 750);
|
||||
await visit(urls.sessions);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,348 @@
|
||||
import { module, test } from 'qunit';
|
||||
import {
|
||||
visit,
|
||||
currentURL,
|
||||
//fillIn,
|
||||
click,
|
||||
find,
|
||||
findAll,
|
||||
//getRootElement
|
||||
//setupOnerror,
|
||||
} from '@ember/test-helpers';
|
||||
import { run, later } from '@ember/runloop';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { Response } from 'miragejs';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import sinon from 'sinon';
|
||||
import {
|
||||
currentSession,
|
||||
authenticateSession,
|
||||
invalidateSession,
|
||||
} from 'ember-simple-auth/test-support';
|
||||
|
||||
module('Acceptance | scopes', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let mockIPC;
|
||||
let messageHandler;
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
project: null,
|
||||
},
|
||||
authMethods: {
|
||||
global: null,
|
||||
},
|
||||
target: null,
|
||||
session: null,
|
||||
};
|
||||
|
||||
const stubs = {
|
||||
global: null,
|
||||
org: null,
|
||||
ipcService: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
index: '/',
|
||||
origin: '/origin',
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
org2: null,
|
||||
},
|
||||
authenticate: {
|
||||
global: null,
|
||||
methods: {
|
||||
global: null,
|
||||
},
|
||||
},
|
||||
projects: null,
|
||||
org2Projects: null,
|
||||
globalProjects: null,
|
||||
targets: null,
|
||||
org2Targets: null,
|
||||
globalTargets: null,
|
||||
target: null,
|
||||
targetSessions: null,
|
||||
};
|
||||
|
||||
const setDefaultOrigin = (test) => {
|
||||
const windowOrigin = window.location.origin;
|
||||
const origin = test.owner.lookup('service:origin');
|
||||
origin.rendererOrigin = windowOrigin;
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
authenticateSession();
|
||||
|
||||
// create scopes
|
||||
instances.scopes.global = this.server.create('scope', { id: 'global' });
|
||||
stubs.global = { id: 'global', type: 'global' };
|
||||
instances.scopes.org = this.server.create('scope', {
|
||||
type: 'org',
|
||||
scope: stubs.global,
|
||||
});
|
||||
instances.scopes.org2 = this.server.create('scope', {
|
||||
type: 'org',
|
||||
scope: stubs.global,
|
||||
});
|
||||
stubs.org = { id: instances.scopes.org.id, type: 'org' };
|
||||
instances.scopes.project = this.server.create('scope', {
|
||||
type: 'project',
|
||||
scope: stubs.org,
|
||||
});
|
||||
stubs.project = { id: instances.scopes.project.id, type: 'project' };
|
||||
|
||||
instances.authMethods.global = this.server.create('auth-method', {
|
||||
scope: instances.scopes.global,
|
||||
});
|
||||
|
||||
instances.hostCatalog = this.server.create(
|
||||
'host-catalog',
|
||||
{ scope: instances.scopes.project },
|
||||
'withChildren'
|
||||
);
|
||||
instances.target = this.server.create(
|
||||
'target',
|
||||
{ scope: instances.scopes.project },
|
||||
'withRandomHostSets'
|
||||
);
|
||||
|
||||
instances.session = this.server.create(
|
||||
'session',
|
||||
{
|
||||
scope: instances.scopes.project,
|
||||
status: 'active',
|
||||
},
|
||||
'withAssociations'
|
||||
);
|
||||
|
||||
urls.scopes.global = `/scopes/${instances.scopes.global.id}`;
|
||||
urls.scopes.org = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.scopes.org2 = `/scopes/${instances.scopes.org2.id}`;
|
||||
urls.authenticate.global = `${urls.scopes.global}/authenticate`;
|
||||
urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`;
|
||||
urls.projects = `${urls.scopes.org}/projects`;
|
||||
urls.org2Projects = `${urls.scopes.org2}/projects`;
|
||||
urls.globalProjects = `${urls.scopes.global}/projects`;
|
||||
urls.targets = `${urls.projects}/targets`;
|
||||
urls.org2Targets = `${urls.org2Projects}/targets`;
|
||||
urls.globalTargets = `${urls.globalProjects}/targets`;
|
||||
urls.target = `${urls.targets}/${instances.target.id}`;
|
||||
urls.targetSessions = `${urls.target}/sessions`;
|
||||
|
||||
class MockIPC {
|
||||
origin = null;
|
||||
|
||||
invoke(method, payload) {
|
||||
return this[method](payload);
|
||||
}
|
||||
|
||||
getOrigin() {
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
setOrigin(origin) {
|
||||
this.origin = origin;
|
||||
return this.origin;
|
||||
}
|
||||
}
|
||||
|
||||
mockIPC = new MockIPC();
|
||||
messageHandler = async function (event) {
|
||||
if (event.origin !== window.location.origin) return;
|
||||
const { method, payload } = event.data;
|
||||
if (method) {
|
||||
const response = await mockIPC.invoke(method, payload);
|
||||
event.ports[0].postMessage(response);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', messageHandler);
|
||||
setDefaultOrigin(this);
|
||||
|
||||
const ipcService = this.owner.lookup('service:ipc');
|
||||
stubs.ipcService = sinon.stub(ipcService, 'invoke');
|
||||
});
|
||||
|
||||
hooks.afterEach(function () {
|
||||
window.removeEventListener('message', messageHandler);
|
||||
});
|
||||
|
||||
test('visiting index', async function (assert) {
|
||||
assert.expect(2);
|
||||
const targetsCount = this.server.schema.targets.all().models.length;
|
||||
// This later/cancelTimers technique allows us to test a page with
|
||||
// active polling. Normally an acceptance test waits for all runloop timers
|
||||
// to stop before returning from an awaited test, but polling means that
|
||||
// runloop timers exist indefinitely. We thus schedule a cancelation before
|
||||
// proceeding with our tests.
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.targets);
|
||||
assert.equal(findAll('tbody tr').length, targetsCount);
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
|
||||
test('visiting global scope', async function (assert) {
|
||||
assert.expect(1);
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.globalTargets);
|
||||
}, 750);
|
||||
await visit(urls.scopes.global);
|
||||
});
|
||||
|
||||
// TODO: this probably shouldn't be the case, but was setup to enable
|
||||
// authentication when the global scope couldn't be loaded.
|
||||
// In order to resolve this, we might hoist authentication routes up from
|
||||
// under scopes.
|
||||
test('visiting global scope is not successful when the global scope cannot be fetched', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.get('/scopes/:id', ({ scopes }, { params: { id } }) => {
|
||||
const scope = scopes.find(id);
|
||||
const response = id === 'global' ? new Response(404) : scope;
|
||||
return response;
|
||||
});
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.globalTargets);
|
||||
}, 750);
|
||||
await visit(urls.scopes.global);
|
||||
});
|
||||
|
||||
test('visiting org scope', async function (assert) {
|
||||
assert.expect(1);
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await a11yAudit();
|
||||
assert.equal(currentURL(), urls.targets);
|
||||
}, 750);
|
||||
await visit(urls.scopes.org);
|
||||
});
|
||||
|
||||
test('can navigate among org scopes via header navigation', async function (assert) {
|
||||
assert.expect(3);
|
||||
await later(async () => run.cancelTimers(), 750);
|
||||
await visit(urls.targets);
|
||||
await later(async () => assert.equal(currentURL(), urls.targets), 750);
|
||||
await click('.rose-header-nav .rose-dropdown a:nth-of-type(2)');
|
||||
await later(async () => assert.equal(currentURL(), urls.org2Targets), 750);
|
||||
await click('.rose-header-nav .rose-dropdown a:nth-of-type(3)');
|
||||
later(async () => assert.equal(currentURL(), urls.globalTargets), 750);
|
||||
await click('.rose-header-nav .rose-dropdown a:nth-of-type(1)');
|
||||
});
|
||||
|
||||
test('visiting index while unauthenticated redirects to global authenticate method', async function (assert) {
|
||||
invalidateSession();
|
||||
assert.expect(2);
|
||||
await visit(urls.targets);
|
||||
await a11yAudit();
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
});
|
||||
|
||||
test('visiting a target', async function (assert) {
|
||||
assert.expect(1);
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click('tbody tr th a');
|
||||
assert.equal(currentURL(), urls.targetSessions);
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
|
||||
test('visiting empty targets', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.get('/targets', () => new Response(200));
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
assert.ok(
|
||||
find('.rose-message-title').textContent.trim(),
|
||||
'No Targets Available'
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
|
||||
test('connecting to a target', async function (assert) {
|
||||
assert.expect(3);
|
||||
stubs.ipcService.withArgs('cliExists').returns(true);
|
||||
stubs.ipcService.withArgs('connect').returns({
|
||||
session_id: instances.session.id,
|
||||
address: 'a_123',
|
||||
port: 'p_123',
|
||||
protocol: 'tcp',
|
||||
});
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
assert.ok(find('.rose-dialog-success'), 'Success dialog');
|
||||
assert.equal(findAll('.rose-dialog-footer button').length, 1);
|
||||
assert.equal(
|
||||
find('.rose-dialog-footer button').textContent.trim(),
|
||||
'OK',
|
||||
'Cannot retry'
|
||||
);
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
|
||||
test('handles cli error on connect', async function (assert) {
|
||||
assert.expect(4);
|
||||
stubs.ipcService.withArgs('cliExists').returns(false);
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
assert.ok(find('.rose-dialog-error'), 'Error dialog');
|
||||
const dialogButtons = findAll('.rose-dialog-footer button');
|
||||
assert.equal(dialogButtons.length, 2);
|
||||
assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry');
|
||||
assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel');
|
||||
}, 750);
|
||||
await visit(urls.scopes.global);
|
||||
});
|
||||
|
||||
test('handles connect error', async function (assert) {
|
||||
assert.expect(4);
|
||||
stubs.ipcService.withArgs('cliExists').returns(true);
|
||||
stubs.ipcService.withArgs('connect').rejects();
|
||||
const confirmService = this.owner.lookup('service:confirm');
|
||||
confirmService.enabled = true;
|
||||
|
||||
later(async () => {
|
||||
run.cancelTimers();
|
||||
await click(
|
||||
'tbody tr:first-child td:last-child button',
|
||||
'Activate connect mode'
|
||||
);
|
||||
assert.ok(find('.rose-dialog-error'), 'Error dialog');
|
||||
const dialogButtons = findAll('.rose-dialog-footer button');
|
||||
assert.equal(dialogButtons.length, 2);
|
||||
assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry');
|
||||
assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel');
|
||||
}, 750);
|
||||
await visit(urls.targets);
|
||||
});
|
||||
});
|
||||
@@ -1,26 +1,27 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { render, find } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | branded-card', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<BrandedCard />`);
|
||||
assert.ok(find('.branded-card'));
|
||||
assert.ok(find('.branded-card-title'));
|
||||
assert.ok(find('.branded-card-description'));
|
||||
});
|
||||
|
||||
assert.equal(this.element.textContent.trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
await render(hbs`
|
||||
<BrandedCard>
|
||||
template block text
|
||||
</BrandedCard>
|
||||
`);
|
||||
|
||||
assert.equal(this.element.textContent.trim(), 'template block text');
|
||||
test('it renders with content', async function (assert) {
|
||||
await render(hbs`<BrandedCard
|
||||
@title="title"
|
||||
@description="description"
|
||||
/>`);
|
||||
assert.equal(find('.branded-card-title').textContent.trim(), 'title');
|
||||
assert.equal(
|
||||
find('.branded-card-description').textContent.trim(),
|
||||
'description'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,12 +1,27 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
import sinon from 'sinon';
|
||||
|
||||
module('Unit | Service | origin', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
// TODO: Replace this with your real tests.
|
||||
test('it exists', function (assert) {
|
||||
let service = this.owner.lookup('service:origin');
|
||||
assert.ok(service);
|
||||
let service, ipcService;
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
service = this.owner.lookup('service:origin');
|
||||
ipcService = this.owner.lookup('service:ipc');
|
||||
});
|
||||
|
||||
test('resets origin on error', async function (assert) {
|
||||
assert.expect(4);
|
||||
const ipcServiceStubbed = sinon.stub(ipcService, 'invoke');
|
||||
await service.setOrigin(window.location.origin);
|
||||
assert.equal(service.rendererOrigin, window.location.origin);
|
||||
assert.equal(service.adapter.host, window.location.origin);
|
||||
ipcServiceStubbed.withArgs('setOrigin').rejects();
|
||||
service.setOrigin('invalid-origin').catch(() => {
|
||||
assert.notOk(service.rendererOrigin);
|
||||
assert.equal(service.adapter.host, window.location.origin);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -4174,6 +4174,11 @@ axe-core@3.5.5:
|
||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.5.5.tgz#84315073b53fa3c0c51676c588d59da09a192227"
|
||||
integrity sha512-5P0QZ6J5xGikH780pghEdbEKijCTrruK9KxtPZCFWUpef0f6GipO+xEZ5GKCb020mmqgbiNO6TcA55CriL784Q==
|
||||
|
||||
axe-core@^4.1.2:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.3.tgz#64a4c85509e0991f5168340edc4bedd1ceea6966"
|
||||
integrity sha512-vwPpH4Aj4122EW38mxO/fxhGKtwWTMLDIJfZ1He0Edbtjcfna/R3YB67yVhezUMzqc3Jr3+Ii50KRntlENL4xQ==
|
||||
|
||||
babel-code-frame@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
|
||||
@@ -6495,9 +6500,9 @@ caniuse-api@^3.0.0:
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001157, caniuse-lite@^1.0.30001181:
|
||||
version "1.0.30001187"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001187.tgz#5706942631f83baa5a0218b7dfa6ced29f845438"
|
||||
integrity sha512-w7/EP1JRZ9552CyrThUnay2RkZ1DXxKe/Q2swTC4+LElLh9RRYrL1Z+27LlakB8kzY0fSmHw9mc7XYDUKAKWMA==
|
||||
version "1.0.30001204"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001204.tgz#256c85709a348ec4d175e847a3b515c66e79f2aa"
|
||||
integrity sha512-JUdjWpcxfJ9IPamy2f5JaRDCaqJOxDzOSKtbdx4rH9VivMd1vIzoPumsJa9LoMIi4Fx2BV2KZOxWhNkBjaYivQ==
|
||||
|
||||
capture-exit@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -7736,6 +7741,11 @@ data-urls@^2.0.0:
|
||||
whatwg-mimetype "^2.3.0"
|
||||
whatwg-url "^8.0.0"
|
||||
|
||||
date-and-time@^0.14.1:
|
||||
version "0.14.2"
|
||||
resolved "https://registry.yarnpkg.com/date-and-time/-/date-and-time-0.14.2.tgz#a4266c3dead460f6c231fe9674e585908dac354e"
|
||||
integrity sha512-EFTCh9zRSEpGPmJaexg7HTuzZHh6cnJj1ui7IGCFNXzd2QdpsNh05Db5TF3xzJm30YN+A8/6xHSuRcQqoc3kFA==
|
||||
|
||||
date-time@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2"
|
||||
@@ -7785,7 +7795,7 @@ debug@~4.1.0:
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debuglog@^1.0.1:
|
||||
debuglog@*, debuglog@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
|
||||
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
|
||||
@@ -8350,9 +8360,9 @@ electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.649:
|
||||
integrity sha512-ojGDupQ3UMkvPWcTICe4JYe17+o9OLiFMPoduoR72Zp2ILt1mRVeqnxBEd6s/ptekrnsFU+0A4lStfBe/wyG/A==
|
||||
|
||||
electron-to-chromium@^1.3.564:
|
||||
version "1.3.687"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.687.tgz#c336184b7ab70427ffe2ee79eaeaedbc1ad8c374"
|
||||
integrity sha512-IpzksdQNl3wdgkzf7dnA7/v10w0Utf1dF2L+B4+gKrloBrxCut+au+kky3PYvle3RMdSxZP+UiCZtLbcYRxSNQ==
|
||||
version "1.3.693"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.693.tgz#5089c506a925c31f93fcb173a003a22e341115dd"
|
||||
integrity sha512-vUdsE8yyeu30RecppQtI+XTz2++LWLVEIYmzeCaCRLSdtKZ2eXqdJcrs85KwLiPOPVc6PELgWyXBsfqIvzGZag==
|
||||
|
||||
element-resize-detector@^1.2.1:
|
||||
version "1.2.1"
|
||||
@@ -8385,6 +8395,24 @@ ember-a11y-testing@^3.0.0:
|
||||
ember-cli-version-checker "5.1.1"
|
||||
ember-get-config "0.2.4"
|
||||
|
||||
ember-a11y-testing@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/ember-a11y-testing/-/ember-a11y-testing-4.0.2.tgz#960ee9582bd315bd16d9dedbf450fd508d021d99"
|
||||
integrity sha512-3pa+6bibbY4Vsl3uKFpD0OH4Mzd8NQUwenaWWWngiJo+R/U6AgJllxo/apORzRgvLxKtBCEpXVocUp/gkZ3rOQ==
|
||||
dependencies:
|
||||
axe-core "^4.1.2"
|
||||
body-parser "^1.19.0"
|
||||
broccoli-funnel "^3.0.3"
|
||||
broccoli-merge-trees "^4.2.0"
|
||||
date-and-time "^0.14.1"
|
||||
ember-auto-import "^1.10.1"
|
||||
ember-cli-babel "^7.21.0"
|
||||
ember-cli-typescript "^3.0.0"
|
||||
ember-cli-version-checker "^5.1.2"
|
||||
ember-destroyable-polyfill "^2.0.1"
|
||||
fs-extra "^9.0.1"
|
||||
validate-peer-dependencies "^1.1.0"
|
||||
|
||||
ember-assign-polyfill@^2.6.0:
|
||||
version "2.7.2"
|
||||
resolved "https://registry.yarnpkg.com/ember-assign-polyfill/-/ember-assign-polyfill-2.7.2.tgz#58f6f60235126cb23df248c846008fa9a3245fc1"
|
||||
@@ -8833,7 +8861,7 @@ ember-cli-typescript@^2.0.0-rc.2, ember-cli-typescript@^2.0.2:
|
||||
stagehand "^1.0.0"
|
||||
walk-sync "^1.0.0"
|
||||
|
||||
ember-cli-typescript@^3.1.3, ember-cli-typescript@^3.1.4:
|
||||
ember-cli-typescript@^3.0.0, ember-cli-typescript@^3.1.3, ember-cli-typescript@^3.1.4:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-typescript/-/ember-cli-typescript-3.1.4.tgz#21d6ccd670d1f2e34c9cce68c6e32c442f46806b"
|
||||
integrity sha512-HJ73kL45OGRmIkPhBNFt31I1SGUvdZND+LCH21+qpq3pPlFpJG8GORyXpP+2ze8PbnITNLzwe5AwUrpyuRswdQ==
|
||||
@@ -9120,7 +9148,7 @@ ember-decorators-polyfill@^1.1.5:
|
||||
ember-cli-version-checker "^3.1.3"
|
||||
ember-compatibility-helpers "^1.2.0"
|
||||
|
||||
ember-destroyable-polyfill@^2.0.2, ember-destroyable-polyfill@^2.0.3:
|
||||
ember-destroyable-polyfill@^2.0.1, ember-destroyable-polyfill@^2.0.2, ember-destroyable-polyfill@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/ember-destroyable-polyfill/-/ember-destroyable-polyfill-2.0.3.tgz#1673ed66609a82268ef270a7d917ebd3647f11e1"
|
||||
integrity sha512-TovtNqCumzyAiW0/OisSkkVK93xnVF4NRU6+FN0ubpfwEOpRrmM2RqDwXI6YAChCgSHON1cz0DfQStpA1Gjuuw==
|
||||
@@ -12264,9 +12292,9 @@ heimdalljs@^0.3.0:
|
||||
rsvp "~3.2.1"
|
||||
|
||||
highlight.js@^10.1.1, highlight.js@^10.4.1, highlight.js@~10.5.0:
|
||||
version "10.6.0"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.6.0.tgz#0073aa71d566906965ba6e1b7be7b2682f5e18b6"
|
||||
integrity sha512-8mlRcn5vk/r4+QcqerapwBYTe+iPL5ih6xrNylxrnBdHQiijDETfXX7VIxC3UiCRiINBJfANBAsPzAvRQj8RpQ==
|
||||
version "10.7.1"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.1.tgz#a8ec4152db24ea630c90927d6cae2a45f8ecb955"
|
||||
integrity sha512-S6G97tHGqJ/U8DsXcEdnACbirtbx58Bx9CzIVeYli8OuswCfYI/LsXH2EiGcoGio1KAC3x4mmUwulOllJ2ZyRA==
|
||||
|
||||
hmac-drbg@^1.0.1:
|
||||
version "1.0.1"
|
||||
@@ -12316,6 +12344,13 @@ hosted-git-info@^3.0.2, hosted-git-info@^3.0.6:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
hosted-git-info@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.1.tgz#710ef5452ea429a844abc33c981056e7371edab7"
|
||||
integrity sha512-eT7NrxAsppPRQEBSwKSosReE+v8OzABwEScQYk5d4uxaEPlzxTIku7LINXtBGalthkLhJnq5lBI89PfK43zAKg==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
html-encoding-sniffer@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
|
||||
@@ -12600,9 +12635,9 @@ ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8:
|
||||
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
|
||||
|
||||
immer@8.0.1, immer@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656"
|
||||
integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==
|
||||
version "8.0.4"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.4.tgz#3a21605a4e2dded852fb2afd208ad50969737b7a"
|
||||
integrity sha512-jMfL18P+/6P6epANRvRk6q8t+3gGhqsJ9EuJ25AXE+9bNTYtssvzeYbEd0mXRYWCmmXSIbnlpz6vd6iJlmGGGQ==
|
||||
|
||||
import-cwd@^2.0.0:
|
||||
version "2.1.0"
|
||||
@@ -12644,7 +12679,7 @@ import-lazy@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153"
|
||||
integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==
|
||||
|
||||
imurmurhash@^0.1.4:
|
||||
imurmurhash@*, imurmurhash@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
||||
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
|
||||
@@ -14327,6 +14362,11 @@ lodash._baseflatten@^3.0.0:
|
||||
lodash.isarguments "^3.0.0"
|
||||
lodash.isarray "^3.0.0"
|
||||
|
||||
lodash._baseindexof@*:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
|
||||
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=
|
||||
|
||||
lodash._baseuniq@~4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
|
||||
@@ -14335,11 +14375,16 @@ lodash._baseuniq@~4.6.0:
|
||||
lodash._createset "~4.0.0"
|
||||
lodash._root "~3.0.0"
|
||||
|
||||
lodash._bindcallback@^3.0.0:
|
||||
lodash._bindcallback@*, lodash._bindcallback@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
|
||||
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
|
||||
|
||||
lodash._cacheindexof@*:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
|
||||
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=
|
||||
|
||||
lodash._createassigner@^3.0.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11"
|
||||
@@ -14349,12 +14394,19 @@ lodash._createassigner@^3.0.0:
|
||||
lodash._isiterateecall "^3.0.0"
|
||||
lodash.restparam "^3.0.0"
|
||||
|
||||
lodash._createcache@*:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
|
||||
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
|
||||
dependencies:
|
||||
lodash._getnative "^3.0.0"
|
||||
|
||||
lodash._createset@~4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
|
||||
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
|
||||
|
||||
lodash._getnative@^3.0.0:
|
||||
lodash._getnative@*, lodash._getnative@^3.0.0:
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
|
||||
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
|
||||
@@ -14567,7 +14619,7 @@ lodash.pick@^4.4.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
|
||||
integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
|
||||
|
||||
lodash.restparam@^3.0.0:
|
||||
lodash.restparam@*, lodash.restparam@^3.0.0:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
|
||||
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
|
||||
@@ -15785,9 +15837,9 @@ node-modules-regexp@^1.0.0:
|
||||
integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=
|
||||
|
||||
node-notifier@^5.0.1, node-notifier@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.1.tgz#f86e89bbc925f2b068784b31f382afdc6ca56be1"
|
||||
integrity sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5"
|
||||
integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==
|
||||
dependencies:
|
||||
growly "^1.3.0"
|
||||
is-wsl "^2.2.0"
|
||||
@@ -15995,12 +16047,12 @@ npm-package-arg@^7.0.0:
|
||||
validate-npm-package-name "^3.0.0"
|
||||
|
||||
npm-package-arg@^8.0.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.0.tgz#b5f6319418c3246a1c38e1a8fbaa06231bc5308f"
|
||||
integrity sha512-/ep6QDxBkm9HvOhOg0heitSd7JHA1U7y1qhhlRlteYYAi9Pdb/ZV7FW5aHpkrpM8+P+4p/jjR8zCyKPBMBjSig==
|
||||
version "8.1.2"
|
||||
resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.2.tgz#b868016ae7de5619e729993fbd8d11dc3c52ab62"
|
||||
integrity sha512-6Eem455JsSMJY6Kpd3EyWE+n5hC+g9bSyHr9K9U2zqZb7+02+hObQ2c0+8iDk/mNF+8r1MhY44WypKJAkySIYA==
|
||||
dependencies:
|
||||
hosted-git-info "^3.0.6"
|
||||
semver "^7.0.0"
|
||||
hosted-git-info "^4.0.1"
|
||||
semver "^7.3.4"
|
||||
validate-npm-package-name "^3.0.0"
|
||||
|
||||
npm-package-arg@^8.1.0:
|
||||
@@ -17671,9 +17723,9 @@ query-string@^5.0.1:
|
||||
strict-uri-encode "^1.0.0"
|
||||
|
||||
query-string@^6.8.2:
|
||||
version "6.14.0"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.14.0.tgz#0b7b7ca326f5facf10dd2d45d26645cd287f8c92"
|
||||
integrity sha512-In3o+lUxlgejoVJgwEdYtdxrmlL0cQWJXj0+kkI7RWVo7hg5AhFtybeKlC9Dpgbr8eOC4ydpEh8017WwyfzqVQ==
|
||||
version "6.14.1"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a"
|
||||
integrity sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==
|
||||
dependencies:
|
||||
decode-uri-component "^0.2.0"
|
||||
filter-obj "^1.1.0"
|
||||
@@ -19519,9 +19571,9 @@ socks-proxy-agent@^5.0.0:
|
||||
socks "^2.3.3"
|
||||
|
||||
socks@^2.3.3:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/socks/-/socks-2.5.1.tgz#7720640b6b5ec9a07d556419203baa3f0596df5f"
|
||||
integrity sha512-oZCsJJxapULAYJaEYBSzMcz8m3jqgGrHaGhkmU/o/PQfFWYWxkAaA0UMGImb6s6tEXfKi959X6VJjMMQ3P6TTQ==
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.0.tgz#6b984928461d39871b3666754b9000ecf39dfac2"
|
||||
integrity sha512-mNmr9owlinMplev0Wd7UHFlqI4ofnBnNzFuzrm63PPaHgbkqCFe4T5LzwKmtQ/f2tX0NTpcdVLyD/FHxFBstYw==
|
||||
dependencies:
|
||||
ip "^1.1.5"
|
||||
smart-buffer "^4.1.0"
|
||||
|
||||
Reference in new issue
Block a user