Merge branch 'main' into fix-empty-ipc-payload
This commit is contained in:
25 files changed
+439
-90
No files matched your search
@@ -4,7 +4,7 @@ import { get } from '@ember/object';
|
||||
|
||||
/**
|
||||
* A dead simple memory storage class used by `StorageService` when it
|
||||
* is configued for memory-only.
|
||||
* is configured for memory-only.
|
||||
*/
|
||||
class MemoryStorage {
|
||||
/**
|
||||
@@ -42,7 +42,7 @@ class MemoryStorage {
|
||||
|
||||
/**
|
||||
* The storage service provides a simple way to persist data in the browser.
|
||||
* Most of the time localStorage is used. Appplications may specify in-memory
|
||||
* Most of the time localStorage is used. Applications may specify in-memory
|
||||
* storage via the config, for example:
|
||||
*
|
||||
* ENV.storage = {
|
||||
|
||||
+18
-1
@@ -69,7 +69,7 @@ export default class ExampleRoute extends Route {
|
||||
}
|
||||
```
|
||||
|
||||
In the application template, interate over confirmations, yielding the
|
||||
In the application template, iterate over confirmations, yielding the
|
||||
confirmation instance as well as accept and deny functions which, when called,
|
||||
update the confirmation status.
|
||||
|
||||
@@ -108,6 +108,23 @@ async myAction() {
|
||||
}
|
||||
```
|
||||
|
||||
## Scope Service
|
||||
|
||||
This addon exposes a service to hold all active scopes (org and project where available).
|
||||
|
||||
To make use of the service, import it and initialize it using service injection.
|
||||
|
||||
```js
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ExampleRoute extends Route {
|
||||
@service scope;
|
||||
async myAction() {
|
||||
// do something
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Yarn Commands
|
||||
|
||||
List of available project commands. `yarn run <command-name>`
|
||||
|
||||
@@ -3,7 +3,7 @@ import { tracked } from '@glimmer/tracking';
|
||||
|
||||
/**
|
||||
* This simple non-functional service is used to retain references to
|
||||
* the currently active scope or scopes.
|
||||
* the current active scope(s).
|
||||
*/
|
||||
export default class ScopeService extends Service {
|
||||
// =attributes
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'core/services/scope';
|
||||
Whitespace-only changes.
@@ -0,0 +1,18 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
|
||||
module('Unit | Service | scope', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it can contain org scope', function (assert) {
|
||||
let service = this.owner.lookup('service:scope');
|
||||
service.org = {};
|
||||
assert.ok(service.org, 'Service contains org scope');
|
||||
});
|
||||
|
||||
test('it can contain project scope', function (assert) {
|
||||
let service = this.owner.lookup('service:scope');
|
||||
service.project = {};
|
||||
assert.ok(service.project, 'Service contains project scope');
|
||||
});
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
|
||||
module('Unit | Service | scope', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
// TODO: Replace this with your real tests.
|
||||
test('it exists', function (assert) {
|
||||
let service = this.owner.lookup('service:scope');
|
||||
assert.ok(service);
|
||||
});
|
||||
});
|
||||
@@ -9,10 +9,12 @@ export default class Router extends EmberRouter {
|
||||
Router.map(function () {
|
||||
this.route('scopes', function () {
|
||||
this.route('scope', { path: ':scope_id' }, function () {
|
||||
this.route('targets', function () {});
|
||||
this.route('authenticate', function () {
|
||||
this.route('method', { path: ':auth_method_id' });
|
||||
});
|
||||
this.route('projects', function () {
|
||||
this.route('targets', function () {});
|
||||
});
|
||||
});
|
||||
});
|
||||
this.route('origin');
|
||||
|
||||
@@ -5,6 +5,7 @@ import { A } from '@ember/array';
|
||||
export default class ScopesScopeRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service intl;
|
||||
@service session;
|
||||
@service scope;
|
||||
|
||||
@@ -25,10 +26,12 @@ export default class ScopesScopeRoute extends Route {
|
||||
// from ID because global has a fixed ID.
|
||||
const type = id === 'global' ? 'global' : 'org';
|
||||
return this.store.findRecord('scope', id).catch(() => {
|
||||
console.error('caught error');
|
||||
const maybeExistingScope = this.store.peekRecord('scope', id);
|
||||
|
||||
const scopeOptions = { id, type };
|
||||
/* istanbul ignore else */
|
||||
if (type === 'global') {
|
||||
scopeOptions.name = this.intl.t('titles.global');
|
||||
}
|
||||
return (
|
||||
maybeExistingScope || this.store.createRecord('scope', scopeOptions)
|
||||
);
|
||||
@@ -41,36 +44,25 @@ export default class ScopesScopeRoute extends Route {
|
||||
* a project. These are used for scope navigation.
|
||||
*/
|
||||
async afterModel(model) {
|
||||
// Load all orgs
|
||||
let orgs;
|
||||
// First, load orgs and, if necessary, projects
|
||||
let orgs, projects;
|
||||
orgs = await this.store
|
||||
.query('scope', { scope_id: 'global' })
|
||||
.catch(() => A([]));
|
||||
|
||||
// Then pull out the "selected" org, if relevant
|
||||
let selectedOrg;
|
||||
if (model.isGlobal || model.isOrg) selectedOrg = model;
|
||||
|
||||
let projects;
|
||||
if (model.isOrg) {
|
||||
projects = await this.store.query('scope', { scope_id: model.id });
|
||||
if (model.isProject) {
|
||||
projects = await this.store.query('scope', { scope_id: model.scopeID });
|
||||
}
|
||||
// Then pull out the "selected" scopes, if relevant
|
||||
let selectedOrg, selectedProject;
|
||||
if (model.isGlobal || model.isOrg) selectedOrg = model;
|
||||
if (model.isProject) {
|
||||
selectedProject = model;
|
||||
selectedOrg = this.store.peekRecord('scope', model.scopeID);
|
||||
}
|
||||
|
||||
// Update the scope service with the current scope(s);
|
||||
this.scope.org = selectedOrg;
|
||||
this.scope.projects = projects;
|
||||
this.scopes = { orgs, selectedOrg };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
redirect(model) {
|
||||
const { isAuthenticated } = this.session;
|
||||
const { isGlobal } = model;
|
||||
if (isAuthenticated && isGlobal && this.scopes.orgs?.length) {
|
||||
this.replaceWith('scopes.scope', this.scopes.orgs.firstObject.id);
|
||||
}
|
||||
this.scope.project = selectedProject;
|
||||
this.scopes = { orgs, projects, selectedOrg, selectedProject };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,4 +88,15 @@ export default class ScopesScopeRoute extends Route {
|
||||
outlet: 'header-nav',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* In global scope, redirect to first org on authentication.
|
||||
*/
|
||||
redirect(model) {
|
||||
const { isAuthenticated } = this.session;
|
||||
const { isGlobal } = model;
|
||||
if (isAuthenticated && isGlobal && this.scopes.orgs?.length) {
|
||||
this.replaceWith('scopes.scope', this.scopes.orgs.firstObject.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export default class ScopesScopeIndexRoute extends Route {
|
||||
if (!this.session.isAuthenticated) {
|
||||
this.replaceWith('scopes.scope.authenticate');
|
||||
} else {
|
||||
this.replaceWith('scopes.scope.targets');
|
||||
this.replaceWith('scopes.scope.projects.targets');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ScopesScopeProjectsRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads project scopes for the current scope.
|
||||
* @return {Promise
|
||||
*/
|
||||
model() {
|
||||
const currentScope = this.modelFor('scopes.scope');
|
||||
return this.store.query('scope', {
|
||||
scope_id: currentScope.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -2,11 +2,10 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { all } from 'rsvp';
|
||||
|
||||
export default class ScopesScopeTargetsRoute extends Route {
|
||||
export default class ScopesScopeProjectsTargetsRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service scope;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -22,8 +21,9 @@ export default class ScopesScopeTargetsRoute extends Route {
|
||||
* @return {Promise{[TargetModel]}}
|
||||
*/
|
||||
async model() {
|
||||
const projects = this.modelFor('scopes.scope.projects');
|
||||
let projectTargets = await all(
|
||||
this.scope.projects.map(({ id: scope_id }) =>
|
||||
projects.map(({ id: scope_id }) =>
|
||||
this.store.query('target', { scope_id })
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,3 @@
|
||||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class ScopesScopeProjectsTargetsIndexRoute extends Route {}
|
||||
@@ -1,3 +0,0 @@
|
||||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class ScopesScopeTargetsIndexRoute extends Route {}
|
||||
@@ -1,20 +0,0 @@
|
||||
import Service from '@ember/service';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
/**
|
||||
* This simple non-functional service is used to retain references to
|
||||
* the currently active scope or scopes.
|
||||
*/
|
||||
export default class ScopeService extends Service {
|
||||
// =attributes
|
||||
|
||||
/**
|
||||
* @type {ScopeModel}
|
||||
*/
|
||||
@tracked org;
|
||||
|
||||
/**
|
||||
* @type {[ScopeModel]}
|
||||
*/
|
||||
@tracked projects;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{{outlet}}
|
||||
File renamed without changes.
File renamed without changes.
@@ -19,10 +19,8 @@ module.exports = function (defaults) {
|
||||
importCss: false,
|
||||
},
|
||||
svg: {
|
||||
paths: [
|
||||
'../../addons/core/public'
|
||||
]
|
||||
}
|
||||
paths: ['../../addons/core/public'],
|
||||
},
|
||||
});
|
||||
|
||||
// Use `app.import` to add additional libraries to the generated
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
import { module, test } from 'qunit';
|
||||
import {
|
||||
visit,
|
||||
currentURL,
|
||||
//fillIn,
|
||||
//click,
|
||||
//find,
|
||||
//findAll,
|
||||
//getRootElement
|
||||
//setupOnerror,
|
||||
} from '@ember/test-helpers';
|
||||
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', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let mockIPC;
|
||||
let messageHandler;
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
project: null,
|
||||
},
|
||||
authMethods: {
|
||||
global: null,
|
||||
},
|
||||
target: 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,
|
||||
};
|
||||
|
||||
const setDefaultOrigin = (test) => {
|
||||
const origin = window.location.origin;
|
||||
const session = test.owner.lookup('service:session');
|
||||
session.set('data.origin', origin);
|
||||
};
|
||||
|
||||
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'
|
||||
);
|
||||
|
||||
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`;
|
||||
|
||||
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.projects);
|
||||
//await a11yAudit();
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
});
|
||||
|
||||
test('visiting index', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.projects);
|
||||
//await a11yAudit();
|
||||
assert.equal(currentURL(), urls.projects);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,158 @@
|
||||
import { module, test } from 'qunit';
|
||||
import {
|
||||
visit,
|
||||
currentURL,
|
||||
//fillIn,
|
||||
//click,
|
||||
//find,
|
||||
//findAll,
|
||||
//getRootElement
|
||||
//setupOnerror,
|
||||
} from '@ember/test-helpers';
|
||||
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 | 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,
|
||||
};
|
||||
|
||||
const stubs = {
|
||||
global: null,
|
||||
org: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
index: '/',
|
||||
origin: '/origin',
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
authenticate: {
|
||||
global: null,
|
||||
methods: {
|
||||
global: null,
|
||||
},
|
||||
},
|
||||
projects: null,
|
||||
targets: null,
|
||||
};
|
||||
|
||||
const setDefaultOrigin = (test) => {
|
||||
const origin = window.location.origin;
|
||||
const session = test.owner.lookup('service:session');
|
||||
session.set('data.origin', origin);
|
||||
};
|
||||
|
||||
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'
|
||||
);
|
||||
|
||||
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`;
|
||||
|
||||
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.targets);
|
||||
//await a11yAudit();
|
||||
assert.notOk(currentSession().isAuthenticated);
|
||||
assert.equal(currentURL(), urls.authenticate.methods.global);
|
||||
});
|
||||
|
||||
test('visiting index', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.targets);
|
||||
//await a11yAudit();
|
||||
assert.equal(currentURL(), urls.targets);
|
||||
});
|
||||
});
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
|
||||
module('Unit | Route | scopes/scope/targets', function (hooks) {
|
||||
module('Unit | Route | scopes/scope/projects', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let route = this.owner.lookup('route:scopes/scope/targets');
|
||||
let route = this.owner.lookup('route:scopes/scope/projects');
|
||||
assert.ok(route);
|
||||
});
|
||||
});
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
|
||||
module('Unit | Route | scopes/scope/targets/index', function (hooks) {
|
||||
module('Unit | Route | scopes/scope/projects/targets', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let route = this.owner.lookup('route:scopes/scope/targets/index');
|
||||
let route = this.owner.lookup('route:scopes/scope/projects/targets');
|
||||
assert.ok(route);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
|
||||
module('Unit | Route | scopes/scope/projects/targets/index', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let route = this.owner.lookup('route:scopes/scope/projects/targets/index');
|
||||
assert.ok(route);
|
||||
});
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
|
||||
module('Unit | Service | scope', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
// TODO: Replace this with your real tests.
|
||||
test('it exists', function (assert) {
|
||||
let service = this.owner.lookup('service:scope');
|
||||
assert.ok(service);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user