diff --git a/bin/run-tests.js b/bin/run-tests.js
index 7d46ca226ea..f3b937039d8 100755
--- a/bin/run-tests.js
+++ b/bin/run-tests.js
@@ -184,9 +184,15 @@ function generateEachPackageTests() {
testFunctions.push(function() {
return run('package=' + packageName);
});
+ if (packages[packageName].requiresJQuery === false) {
+ testFunctions.push(function() {
+ return run('package=' + packageName + '&jquery=none');
+ });
+ }
testFunctions.push(function() {
return run('package=' + packageName + '&enableoptionalfeatures=true');
});
+
});
}
diff --git a/lib/packages.js b/lib/packages.js
index 5d87c84e3ca..825a494f3dd 100644
--- a/lib/packages.js
+++ b/lib/packages.js
@@ -1,14 +1,14 @@
module.exports = function() {
var packages = {
- 'container': { trees: null, requirements: ['ember-utils'], isTypeScript: true, vendorRequirements: ['@glimmer/di'] },
- 'ember-environment': { trees: null, requirements: [], skipTests: true },
- 'ember-utils': { trees: null, requirements: [] },
- 'ember-console': { trees: null, requirements: [], skipTests: true },
- 'ember-metal': { trees: null, requirements: ['ember-environment', 'ember-utils'], vendorRequirements: ['backburner'] },
- 'ember-debug': { trees: null, requirements: [] },
- 'ember-runtime': { trees: null, vendorRequirements: ['rsvp'], requirements: ['container', 'ember-environment', 'ember-console', 'ember-metal'] },
+ 'container': { trees: null, requirements: ['ember-utils'], isTypeScript: true, vendorRequirements: ['@glimmer/di'], requiresJQuery: false },
+ 'ember-environment': { trees: null, requirements: [], skipTests: true, requiresJQuery: false },
+ 'ember-utils': { trees: null, requirements: [], requiresJQuery: false },
+ 'ember-console': { trees: null, requirements: [], skipTests: true, requiresJQuery: false },
+ 'ember-metal': { trees: null, requirements: ['ember-environment', 'ember-utils'], vendorRequirements: ['backburner'], requiresJQuery: false },
+ 'ember-debug': { trees: null, requirements: [], requiresJQuery: false },
+ 'ember-runtime': { trees: null, vendorRequirements: ['rsvp'], requirements: ['container', 'ember-environment', 'ember-console', 'ember-metal'], requiresJQuery: false },
'ember-views': { trees: null, requirements: ['ember-runtime'], skipTests: true },
- 'ember-extension-support': { trees: null, requirements: ['ember-application'] },
+ 'ember-extension-support': { trees: null, requirements: ['ember-application'], requiresJQuery: false },
'ember-testing': { trees: null, requirements: ['ember-application', 'ember-routing'], testing: true },
'ember-template-compiler': {
trees: null,
@@ -27,10 +27,10 @@ module.exports = function() {
]
},
'ember-routing': { trees: null, vendorRequirements: ['router', 'route-recognizer'],
- requirements: ['ember-runtime', 'ember-views'] },
- 'ember-application': { trees: null, vendorRequirements: ['dag-map'], requirements: ['ember-routing'] },
+ requirements: ['ember-runtime', 'ember-views'], requiresJQuery: false },
+ 'ember-application': { trees: null, vendorRequirements: ['dag-map'], requirements: ['ember-routing'], requiresJQuery: false },
'ember': { trees: null, requirements: ['ember-application'] },
- 'internal-test-helpers': { trees: null },
+ 'internal-test-helpers': { trees: null, requiresJQuery: false },
'ember-glimmer': {
trees: null,
@@ -43,7 +43,7 @@ module.exports = function() {
'@glimmer/wire-format',
'@glimmer/node'
],
- testingVendorRequirements: []
+ testingVendorRequirements: [],
}
};
diff --git a/packages/ember-application/tests/system/application_test.js b/packages/ember-application/tests/system/application_test.js
index eebac7d26bd..8338ef92214 100644
--- a/packages/ember-application/tests/system/application_test.js
+++ b/packages/ember-application/tests/system/application_test.js
@@ -35,14 +35,13 @@ import {
} from 'internal-test-helpers';
moduleFor('Ember.Application, autobooting multiple apps', class extends ApplicationTestCase {
- constructor() {
- jQuery('#qunit-fixture').html(`
+ get fixture() {
+ return `
HI
- `);
- super();
+ `;
}
get applicationOptions() {
@@ -212,7 +211,7 @@ moduleFor('Ember.Application, default resolver with autoboot', class extends Def
}
[`@test Minimal Application initialized with just an application template`]() {
- jQuery('#qunit-fixture').html('');
+ this.setupFixture('');
this.runTask(() => this.createApplication());
this.assertInnerHTML('Hello World');
}
@@ -235,14 +234,14 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes
super.teardown();
}
- [`@test initialized application goes to initial route`](assert) {
+ [`@test initialized application goes to initial route`]() {
this.runTask(() => {
this.createApplication();
this.addTemplate('application', '{{outlet}}');
this.addTemplate('index', 'Hi from index
');
});
- assert.equal(this.$('h1').text(), 'Hi from index');
+ this.assertText('Hi from index');
}
[`@test ready hook is called before routing begins`](assert) {
@@ -289,10 +288,10 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes
// need to make some assertions about the created router
let router = this.application.__deprecatedInstance__.lookup('router:main');
assert.equal(router instanceof Router, true, 'Router was set from initialize call');
- assert.equal(this.$('h1').text(), 'Hello!');
+ this.assertText('Hello!');
}
- [`@test Application Controller backs the appplication template`](assert) {
+ [`@test Application Controller backs the appplication template`]() {
this.runTask(() => {
this.createApplication();
this.addTemplate('application', '{{greeting}}
');
@@ -300,7 +299,7 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes
greeting: 'Hello!'
}));
});
- assert.equal(this.$('h1').text(), 'Hello!');
+ this.assertText('Hello!');
}
[`@test enable log of libraries with an ENV var`](assert) {
@@ -320,8 +319,12 @@ moduleFor('Ember.Application, autobooting', class extends AutobootApplicationTes
this.runTask(() => this.createApplication());
assert.equal(messages[1], 'Ember : ' + VERSION);
- assert.equal(messages[2], 'jQuery : ' + jQuery().jquery);
- assert.equal(messages[3], 'my-lib : ' + '2.0.0a');
+ if (jQuery) {
+ assert.equal(messages[2], 'jQuery : ' + jQuery().jquery);
+ assert.equal(messages[3], 'my-lib : ' + '2.0.0a');
+ } else {
+ assert.equal(messages[2], 'my-lib : ' + '2.0.0a');
+ }
libraries.deRegister('my-lib');
}
diff --git a/packages/ember-application/tests/system/bootstrap-test.js b/packages/ember-application/tests/system/bootstrap-test.js
index 3cd58e6418a..28a814d3353 100644
--- a/packages/ember-application/tests/system/bootstrap-test.js
+++ b/packages/ember-application/tests/system/bootstrap-test.js
@@ -1,19 +1,17 @@
import { assign } from 'ember-utils';
-import { jQuery } from 'ember-views';
import {
moduleFor,
DefaultResolverApplicationTestCase
} from 'internal-test-helpers';
moduleFor('Ember.Application with default resolver and autoboot', class extends DefaultResolverApplicationTestCase {
- constructor() {
- jQuery('#qunit-fixture').html(`
+ get fixture() {
+ return `
- `);
- super();
+ `;
}
get applicationOptions() {
@@ -25,6 +23,6 @@ moduleFor('Ember.Application with default resolver and autoboot', class extends
['@test templates in script tags are extracted at application creation'](assert) {
this.runTask(() => this.createApplication());
- assert.equal(this.$('#app').text(), 'Hello World!');
+ assert.equal(document.getElementById('app').textContent, 'Hello World!');
}
});
diff --git a/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js b/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js
index fa5a4733aad..0663de5f831 100644
--- a/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js
+++ b/packages/ember-application/tests/system/dependency_injection/custom_resolver_test.js
@@ -26,9 +26,8 @@ moduleFor('Ember.Application with extended default resolver and autoboot', class
});
}
- [`@test a resolver can be supplied to application`](assert) {
+ [`@test a resolver can be supplied to application`]() {
this.runTask(() => this.createApplication());
- assert.equal(this.$('h1').text(), 'Fallback');
+ this.assertText('Fallback');
}
-
});
diff --git a/packages/ember-application/tests/system/initializers_test.js b/packages/ember-application/tests/system/initializers_test.js
index ab0d0e1659b..3acd2d1069c 100644
--- a/packages/ember-application/tests/system/initializers_test.js
+++ b/packages/ember-application/tests/system/initializers_test.js
@@ -1,15 +1,12 @@
import { assign } from 'ember-utils';
import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers';
import { Application } from 'ember-application';
-import { jQuery } from 'ember-views';
moduleFor('Ember.Application initializers', class extends AutobootApplicationTestCase {
- constructor() {
- jQuery('#qunit-fixture').html(`
- ONE
+ get fixture() {
+ return `ONE
TWO
- `);
- super();
+ `;
}
get applicationOptions() {
diff --git a/packages/ember-application/tests/system/instance_initializers_test.js b/packages/ember-application/tests/system/instance_initializers_test.js
index 71521493e81..434ebd38e44 100644
--- a/packages/ember-application/tests/system/instance_initializers_test.js
+++ b/packages/ember-application/tests/system/instance_initializers_test.js
@@ -1,15 +1,12 @@
import { assign } from 'ember-utils';
import { moduleFor, AutobootApplicationTestCase } from 'internal-test-helpers';
import { Application, ApplicationInstance } from 'ember-application';
-import { jQuery } from 'ember-views';
moduleFor('Ember.Application instance initializers', class extends AutobootApplicationTestCase {
- constructor() {
- jQuery('#qunit-fixture').html(`
- ONE
+ get fixture() {
+ return `ONE
TWO
- `);
- super();
+ `;
}
get applicationOptions() {
diff --git a/packages/ember-application/tests/system/visit_test.js b/packages/ember-application/tests/system/visit_test.js
index a6dd203969f..ba99b9f2152 100644
--- a/packages/ember-application/tests/system/visit_test.js
+++ b/packages/ember-application/tests/system/visit_test.js
@@ -12,7 +12,6 @@ import Engine from '../../system/engine';
import { Route } from 'ember-routing';
import { Component, helper } from 'ember-glimmer';
import { compile } from 'ember-template-compiler';
-import { jQuery } from 'ember-views';
function expectAsyncError() {
RSVP.off('error');
@@ -29,6 +28,13 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
return super.createApplication(options, Application.extend());
}
+ assertEmptyFixture(message) {
+ this.assert.strictEqual(
+ document.getElementById('qunit-fixture').children.length, 0,
+ `there are no elements in the fixture element ${message ? message : ''}`
+ );
+ }
+
// This tests whether the application is "autobooted" by registering an
// instance initializer and asserting it never gets run. Since this is
// inherently testing that async behavior *doesn't* happen, we set a
@@ -274,10 +280,7 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
[`@test visit() returns a promise that resolves when the view has rendered`](assert) {
this.addTemplate('application', `Hello world
`);
- assert.strictEqual(
- this.$().children().length, 0,
- 'there are no elements in the fixture element'
- );
+ this.assertEmptyFixture();
return this.visit('/').then(instance => {
assert.ok(
@@ -285,7 +288,7 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
'promise is resolved with an ApplicationInstance'
);
assert.equal(
- this.$('h1').text(), 'Hello world',
+ this.element.textContent, 'Hello world',
'the application was rendered once the promise resolves'
);
});
@@ -296,20 +299,15 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
this.addTemplate('application', 'Hello world
');
- assert.strictEqual(
- this.$().children().length, 0,
- 'there are no elements in the fixture element'
- );
+ this.assertEmptyFixture();
return this.visit('/', { shouldRender: false }).then(instance => {
assert.ok(
instance instanceof ApplicationInstance,
'promise is resolved with an ApplicationInstance'
);
- assert.strictEqual(
- this.$().children().length, 0,
- 'there are still no elements in the fixture element after visit'
- );
+
+ this.assertEmptyFixture('after visit');
});
}
@@ -318,10 +316,7 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
this.addTemplate('application', 'Hello world
');
- assert.strictEqual(
- this.$('#qunit-fixture').children().length, 0,
- 'there are no elements in the fixture element'
- );
+ this.assertEmptyFixture();
return this.visit('/', { shouldRender: true }).then(instance => {
assert.ok(
@@ -329,7 +324,7 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
'promise is resolved with an ApplicationInstance'
);
assert.strictEqual(
- this.$().children().length, 1,
+ document.querySelector('#qunit-fixture').children.length, 1,
'there is 1 element in the fixture element after visit'
);
});
@@ -352,20 +347,15 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
let BlogMap = function() {};
this.add('route-map:blog', BlogMap);
- assert.strictEqual(
- this.$('#qunit-fixture').children().length, 0,
- 'there are no elements in the fixture element'
- );
+ this.assertEmptyFixture();
return this.visit('/blog', { shouldRender: false }).then(instance => {
assert.ok(
instance instanceof ApplicationInstance,
'promise is resolved with an ApplicationInstance'
);
- assert.strictEqual(
- this.$().children().length, 0,
- 'there are still no elements in the fixture element after visit'
- );
+
+ this.assertEmptyFixture('after visit');
});
}
@@ -398,10 +388,7 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
let BlogMap = function() {};
this.add('route-map:blog', BlogMap);
- assert.strictEqual(
- this.$('#qunit-fixture').children().length, 0,
- 'there are no elements in the fixture element'
- );
+ this.assertEmptyFixture();
return this.visit('/blog', { isInteractive: false }).then(instance => {
assert.ok(
@@ -409,7 +396,7 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
'promise is resolved with an ApplicationInstance'
);
assert.strictEqual(
- this.$().find('p').text(), 'Dis cache money',
+ this.element.querySelector('p').textContent, 'Dis cache money',
'Engine component is resolved'
);
});
@@ -439,14 +426,11 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
let BlogMap = function() {};
this.add('route-map:blog', BlogMap);
- assert.strictEqual(
- this.$().children().length, 0,
- 'there are no elements in the fixture element'
- );
+ this.assertEmptyFixture();
return this.visit('/blog', { shouldRender: true }).then(() => {
assert.strictEqual(
- this.$().find('p').text(), 'Dis cache money',
+ this.element.querySelector('p').textContent, 'Dis cache money',
'Engine component is resolved'
);
});
@@ -475,14 +459,11 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
let BlogMap = function() {};
this.add('route-map:blog', BlogMap);
- assert.strictEqual(
- this.$().children().length, 0,
- 'there are no elements in the fixture element'
- );
+ this.assertEmptyFixture();
return this.visit('/blog', { shouldRender: true }).then(() => {
assert.strictEqual(
- this.$().text(), 'turnt up',
+ this.element.textContent, 'turnt up',
'Engine component is resolved'
);
});
@@ -576,18 +557,21 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
}
}));
- let $foo = jQuery('').appendTo('#qunit-fixture');
- let $bar = jQuery('').appendTo('#qunit-fixture');
+ let fixtureElement = document.querySelector('#qunit-fixture');
+ let foo = document.createElement('div');
+ let bar = document.createElement('div');
+ fixtureElement.appendChild(foo);
+ fixtureElement.appendChild(bar);
let data = encodeURIComponent(JSON.stringify({ name: 'Godfrey' }));
let instances = [];
return RSVP.all([
this.runTask(() => {
- return this.application.visit(`/x-foo?data=${data}`, { rootElement: $foo[0] });
+ return this.application.visit(`/x-foo?data=${data}`, { rootElement: foo });
}),
this.runTask(() => {
- return this.application.visit('/x-bar', { rootElement: $bar[0] });
+ return this.application.visit('/x-bar', { rootElement: bar });
})
]).then(_instances => {
instances = _instances;
@@ -598,28 +582,28 @@ moduleFor('Ember.Application - visit()', class extends ApplicationTestCase {
assert.ok(xBarInitCalled);
assert.ok(xBarDidInsertElementCalled);
- assert.equal($foo.find('h1').text(), 'X-Foo');
- assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 0 times (0 times combined)!');
- assert.ok($foo.text().indexOf('X-Bar') === -1);
+ assert.equal(foo.querySelector('h1').textContent, 'X-Foo');
+ assert.equal(foo.querySelector('p').textContent, 'Hello Godfrey, I have been clicked 0 times (0 times combined)!');
+ assert.ok(foo.textContent.indexOf('X-Bar') === -1);
- assert.equal($bar.find('h1').text(), 'X-Bar');
- assert.equal($bar.find('button').text(), 'Join 0 others in clicking me!');
- assert.ok($bar.text().indexOf('X-Foo') === -1);
+ assert.equal(bar.querySelector('h1').textContent, 'X-Bar');
+ assert.equal(bar.querySelector('button').textContent, 'Join 0 others in clicking me!');
+ assert.ok(bar.textContent.indexOf('X-Foo') === -1);
this.runTask(() => {
- $foo.find('x-foo').click();
+ this.click(foo.querySelector('x-foo'));
});
- assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 1 times (1 times combined)!');
- assert.equal($bar.find('button').text(), 'Join 1 others in clicking me!');
+ assert.equal(foo.querySelector('p').textContent, 'Hello Godfrey, I have been clicked 1 times (1 times combined)!');
+ assert.equal(bar.querySelector('button').textContent, 'Join 1 others in clicking me!');
this.runTask(() => {
- $bar.find('button').click();
- $bar.find('button').click();
+ this.click(bar.querySelector('button'));
+ this.click(bar.querySelector('button'));
});
- assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 1 times (3 times combined)!');
- assert.equal($bar.find('button').text(), 'Join 3 others in clicking me!');
+ assert.equal(foo.querySelector('p').textContent, 'Hello Godfrey, I have been clicked 1 times (3 times combined)!');
+ assert.equal(bar.querySelector('button').textContent, 'Join 3 others in clicking me!');
}).finally(() => {
this.runTask(() => {
diff --git a/packages/ember-glimmer/tests/integration/application/engine-test.js b/packages/ember-glimmer/tests/integration/application/engine-test.js
index aef0ac2f0cb..138ed5403c3 100644
--- a/packages/ember-glimmer/tests/integration/application/engine-test.js
+++ b/packages/ember-glimmer/tests/integration/application/engine-test.js
@@ -311,7 +311,10 @@ moduleFor('Application test: engine rendering', class extends ApplicationTest {
this.setupAppAndRoutableEngine(hooks);
return this.visit('/blog', { shouldRender: false }).then(() => {
- this.assertText('');
+ assert.strictEqual(
+ document.getElementById('qunit-fixture').children.length, 0,
+ `there are no elements in the qunit-fixture element`
+ );
this.assert.deepEqual(hooks, [
'application - application',
diff --git a/packages/ember-template-compiler/tests/system/bootstrap-test.js b/packages/ember-template-compiler/tests/system/bootstrap-test.js
index cdd3b880fe6..4d85435abe5 100644
--- a/packages/ember-template-compiler/tests/system/bootstrap-test.js
+++ b/packages/ember-template-compiler/tests/system/bootstrap-test.js
@@ -16,8 +16,6 @@ import {
AbstractTestCase
} from 'internal-test-helpers';
-const { trim } = jQuery;
-
let component, fixture;
function checkTemplate(templateName, assert) {
@@ -84,7 +82,7 @@ moduleFor('ember-templates: bootstrap', class extends AbstractTestCase {
assert.ok(template, 'template with name funkyTemplate available');
// This won't even work with Ember templates
- assert.equal(trim(template({ name: 'Tobias' })), 'Tobias');
+ assert.equal(template({ name: 'Tobias' }).trim(), 'Tobias');
}
['@test duplicated default application templates should throw exception'](assert) {
diff --git a/packages/ember-views/lib/system/event_dispatcher.js b/packages/ember-views/lib/system/event_dispatcher.js
index 70d7eebf0fc..165e067ea2a 100644
--- a/packages/ember-views/lib/system/event_dispatcher.js
+++ b/packages/ember-views/lib/system/event_dispatcher.js
@@ -11,6 +11,7 @@ import jQuery from './jquery';
import ActionManager from './action_manager';
import fallbackViewRegistry from '../compat/fallback-view-registry';
+const HAS_JQUERY = jQuery !== undefined;
const ROOT_ELEMENT_CLASS = 'ember-application';
const ROOT_ELEMENT_SELECTOR = `.${ROOT_ELEMENT_CLASS}`;
@@ -150,6 +151,8 @@ export default EmberObject.extend({
until: '2.17.0'
}
);
+
+ this._eventHandlers = Object.create(null);
},
/**
@@ -164,26 +167,51 @@ export default EmberObject.extend({
@method setup
@param addedEvents {Object}
*/
- setup(addedEvents, rootElement) {
- let event;
+ setup(addedEvents, _rootElement) {
+ let event, rootElement;
let events = this._finalEvents = assign({}, get(this, 'events'), addedEvents);
- if (isNone(rootElement)) {
- rootElement = get(this, 'rootElement');
- } else {
- set(this, 'rootElement', rootElement);
+ if (!isNone(_rootElement)) {
+ set(this, 'rootElement', _rootElement);
}
- rootElement = jQuery(rootElement);
+ let rootElementSelector = get(this, 'rootElement');
+ if (HAS_JQUERY) {
+ rootElement = jQuery(rootElementSelector);
+ assert(`You cannot use the same root element (${rootElement.selector || rootElement[0].tagName}) multiple times in an Ember.Application`, !rootElement.is(ROOT_ELEMENT_SELECTOR));
+ assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest(ROOT_ELEMENT_SELECTOR).length);
+ assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find(ROOT_ELEMENT_SELECTOR).length);
+
+ rootElement.addClass(ROOT_ELEMENT_CLASS);
- assert(`You cannot use the same root element (${rootElement.selector || rootElement[0].tagName}) multiple times in an Ember.Application`, !rootElement.is(ROOT_ELEMENT_SELECTOR));
- assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest(ROOT_ELEMENT_SELECTOR).length);
- assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find(ROOT_ELEMENT_SELECTOR).length);
+ if (!rootElement.is(ROOT_ELEMENT_SELECTOR)) {
+ throw new TypeError(`Unable to add '${ROOT_ELEMENT_CLASS}' class to root element (${rootElement.selector || rootElement[0].tagName}). Make sure you set rootElement to the body or an element in the body.`);
+ }
+ } else {
+ if (typeof rootElementSelector !== 'string') {
+ rootElement = rootElementSelector;
+ } else {
+ rootElement = document.querySelector(rootElementSelector);
+ }
- rootElement.addClass(ROOT_ELEMENT_CLASS);
+ assert(`You cannot use the same root element (${get(this, 'rootElement') || rootElement.tagName}) multiple times in an Ember.Application`, !rootElement.classList.contains(ROOT_ELEMENT_CLASS));
+ assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', (() => {
+ let target = rootElement.parentNode;
+ do {
+ if (target.classList.contains(ROOT_ELEMENT_CLASS)) {
+ return false;
+ }
- if (!rootElement.is(ROOT_ELEMENT_SELECTOR)) {
- throw new TypeError(`Unable to add '${ROOT_ELEMENT_CLASS}' class to root element (${rootElement.selector || rootElement[0].tagName}). Make sure you set rootElement to the body or an element in the body.`);
+ target = target.parentNode;
+ } while(target && target.nodeType === 1);
+
+ return true;
+ })());
+ assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.querySelector(ROOT_ELEMENT_SELECTOR));
+
+ rootElement.classList.add(ROOT_ELEMENT_CLASS);
+
+ assert(`Unable to add '${ROOT_ELEMENT_CLASS}' class to root element (${get(this, 'rootElement') || rootElement.tagName}). Make sure you set rootElement to the body or an element in the body.`, rootElement.classList.contains(ROOT_ELEMENT_CLASS));
}
let viewRegistry = this._getViewRegistry();
@@ -217,45 +245,119 @@ export default EmberObject.extend({
return;
}
- rootElement.on(`${event}.ember`, '.ember-view', function(evt, triggeringManager) {
- let view = viewRegistry[this.id];
- let result = true;
+ if (HAS_JQUERY) {
+ rootElement.on(`${event}.ember`, '.ember-view', function(evt, triggeringManager) {
+ let view = viewRegistry[this.id];
+ let result = true;
- let manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null;
+ let manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null;
- if (manager && manager !== triggeringManager) {
- result = self._dispatchEvent(manager, evt, eventName, view);
- } else if (view) {
- result = self._bubbleEvent(view, evt, eventName);
- }
+ if (manager && manager !== triggeringManager) {
+ result = self._dispatchEvent(manager, evt, eventName, view);
+ } else if (view) {
+ result = self._bubbleEvent(view, evt, eventName);
+ }
- return result;
- });
+ return result;
+ });
+
+ rootElement.on(`${event}.ember`, '[data-ember-action]', evt => {
+ let attributes = evt.currentTarget.attributes;
+ let handledActions = [];
+
+ for (let i = 0; i < attributes.length; i++) {
+ let attr = attributes.item(i);
+ let attrName = attr.name;
+
+ if (attrName.lastIndexOf('data-ember-action-', 0) !== -1) {
+ let action = ActionManager.registeredActions[attr.value];
+
+ // We have to check for action here since in some cases, jQuery will trigger
+ // an event on `removeChild` (i.e. focusout) after we've already torn down the
+ // action handlers for the view.
+ if (action && action.eventName === eventName && handledActions.indexOf(action) === -1) {
+ action.handler(evt);
+ // Action handlers can mutate state which in turn creates new attributes on the element.
+ // This effect could cause the `data-ember-action` attribute to shift down and be invoked twice.
+ // To avoid this, we keep track of which actions have been handled.
+ handledActions.push(action);
+ }
+ }
+ }
+ });
+ } else {
+ let viewHandler = (target, event) => {
+ let view = viewRegistry[target.id];
+ let result = true;
+
+ if (view) {
+ result = this._bubbleEvent(view, event, eventName);
+ }
+
+ return result;
+ };
+
+ let actionHandler = (target, event) => {
+ let actionId = target.getAttribute('data-ember-action');
+ let actions = ActionManager.registeredActions[actionId];
+
+ // In Glimmer2 this attribute is set to an empty string and an additional
+ // attribute it set for each action on a given element. In this case, the
+ // attributes need to be read so that a proper set of action handlers can
+ // be coalesced.
+ if (actionId === '') {
+ let attributes = target.attributes;
+ let attributeCount = attributes.length;
+
+ actions = [];
+
+ for (let i = 0; i < attributeCount; i++) {
+ let attr = attributes.item(i);
+ let attrName = attr.name;
- rootElement.on(`${event}.ember`, '[data-ember-action]', evt => {
- let attributes = evt.currentTarget.attributes;
- let handledActions = [];
-
- for (let i = 0; i < attributes.length; i++) {
- let attr = attributes.item(i);
- let attrName = attr.name;
-
- if (attrName.lastIndexOf('data-ember-action-', 0) !== -1) {
- let action = ActionManager.registeredActions[attr.value];
-
- // We have to check for action here since in some cases, jQuery will trigger
- // an event on `removeChild` (i.e. focusout) after we've already torn down the
- // action handlers for the view.
- if (action && action.eventName === eventName && handledActions.indexOf(action) === -1) {
- action.handler(evt);
- // Action handlers can mutate state which in turn creates new attributes on the element.
- // This effect could cause the `data-ember-action` attribute to shift down and be invoked twice.
- // To avoid this, we keep track of which actions have been handled.
- handledActions.push(action);
+ if (attrName.indexOf('data-ember-action-') === 0) {
+ actions = actions.concat(ActionManager.registeredActions[attr.value]);
+ }
}
}
- }
- });
+
+ // We have to check for actions here since in some cases, jQuery will trigger
+ // an event on `removeChild` (i.e. focusout) after we've already torn down the
+ // action handlers for the view.
+ if (!actions) {
+ return;
+ }
+
+ for (let index = 0; index < actions.length; index++) {
+ let action = actions[index];
+
+ if (action && action.eventName === eventName) {
+ return action.handler(event);
+ }
+ }
+ };
+
+ let handleEvent = this._eventHandlers[event] = (event) => {
+ let target = event.target;
+
+ do {
+ if (viewRegistry[target.id]) {
+ if (viewHandler(target, event) === false) {
+ event.preventDefault();
+ event.stopPropagation();
+ break;
+ }
+ } else if (target.hasAttribute('data-ember-action')) {
+ actionHandler(target, event);
+ break;
+ }
+
+ target = target.parentNode;
+ } while(target && target.nodeType === 1);
+ };
+
+ rootElement.addEventListener(event, handleEvent);
+ }
},
_getViewRegistry() {
@@ -298,8 +400,26 @@ export default EmberObject.extend({
},
destroy() {
- let rootElement = get(this, 'rootElement');
- jQuery(rootElement).off('.ember', '**').removeClass(ROOT_ELEMENT_CLASS);
+ let rootElementSelector = get(this, 'rootElement');
+ let rootElement;
+ if (rootElementSelector.nodeType) {
+ rootElement = rootElementSelector;
+ } else {
+ rootElement = document.querySelector(rootElementSelector);
+ }
+
+ if (!rootElement) { return; }
+
+ if (HAS_JQUERY) {
+ jQuery(rootElementSelector).off('.ember', '**');
+ } else {
+ for (let event in this._eventHandlers) {
+ rootElement.removeEventListener(event, this._eventHandlers[event]);
+ }
+ }
+
+ rootElement.classList.remove(ROOT_ELEMENT_CLASS);
+
return this._super(...arguments);
},
diff --git a/packages/ember/tests/helpers/link_to_test.js b/packages/ember/tests/helpers/link_to_test.js
index f33f2cc122c..a29ffa57e6c 100644
--- a/packages/ember/tests/helpers/link_to_test.js
+++ b/packages/ember/tests/helpers/link_to_test.js
@@ -654,7 +654,7 @@ moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class
{{#each model as |person|}}
-
- {{#link-to 'item' person}}
+ {{#link-to 'item' person id=person.id}}
{{person.name}}
{{/link-to}}
@@ -689,7 +689,7 @@ moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class
assert.equal(this.$('h3:contains(List)').length, 1, 'The home template was rendered');
assert.equal(normalizeUrl(this.$('#home-link').attr('href')), '/', 'The home link points back at /');
- this.click('li a:contains(Yehuda)');
+ this.click('#yehuda');
assert.equal(this.$('h3:contains(Item)').length, 1, 'The item template was rendered');
assert.equal(this.$('p').text(), 'Yehuda Katz', 'The name is correct');
@@ -701,7 +701,7 @@ moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class
assert.equal(normalizeUrl(this.$('li a:contains(Tom)').attr('href')), '/item/tom');
assert.equal(normalizeUrl(this.$('li a:contains(Erik)').attr('href')), '/item/erik');
- this.click('li a:contains(Erik)');
+ this.click('#erik');
assert.equal(this.$('h3:contains(Item)').length, 1, 'The item template was rendered');
assert.equal(this.$('p').text(), 'Erik Brynroflsson', 'The name is correct');
@@ -1138,7 +1138,7 @@ moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class
{{#each model as |person|}}
-
- {{link-to person.name 'item' person}}
+ {{link-to person.name 'item' person id=person.id}}
{{/each}}
@@ -1151,7 +1151,7 @@ moduleFor('The {{link-to}} helper - nested routes and link-to arguments', class
this.visit('/');
- this.click('li a:contains(Yehuda)');
+ this.click('#yehuda');
assert.equal(this.$('h3:contains(Item)').length, 1, 'The item template was rendered');
assert.equal(this.$('p').text(), 'Yehuda Katz', 'The name is correct');
@@ -1470,7 +1470,7 @@ moduleFor('The {{link-to}} helper - loading states and warnings', class extends
assertLinkStatus(staticLink);
expectWarning(()=> {
- this.click(contextLink);
+ this.click(contextLink[0]);
}, warningMessage);
// Set the destinationRoute (context is still null).
@@ -1496,14 +1496,14 @@ moduleFor('The {{link-to}} helper - loading states and warnings', class extends
assertLinkStatus(contextLink);
expectWarning(()=> {
- this.click(staticLink);
+ this.click(staticLink[0]);
}, warningMessage);
this.runTask(() => controller.set('secondRoute', 'about'));
assertLinkStatus(staticLink, '/about');
// Click the now-active link
- this.click(staticLink);
+ this.click(staticLink[0]);
}
});
diff --git a/packages/ember/tests/routing/basic_test.js b/packages/ember/tests/routing/basic_test.js
index fc49007e080..4d1673838db 100644
--- a/packages/ember/tests/routing/basic_test.js
+++ b/packages/ember/tests/routing/basic_test.js
@@ -32,8 +32,6 @@ import { compile } from 'ember-template-compiler';
import { Application, Engine } from 'ember-application';
import { Transition } from 'router';
-let trim = jQuery.trim;
-
let Router, App, router, registry, container, originalLoggerError, originalRenderSupport;
function bootApplication() {
@@ -3020,13 +3018,13 @@ QUnit.test('Tolerates stacked renders', function() {
}
});
bootApplication();
- equal(trim(jQuery('#qunit-fixture').text()), 'hi');
+ equal(jQuery('#qunit-fixture').text().trim(), 'hi');
run(router, 'send', 'openLayer');
- equal(trim(jQuery('#qunit-fixture').text()), 'hilayer');
+ equal(jQuery('#qunit-fixture').text().trim(), 'hilayer');
run(router, 'send', 'openLayer');
- equal(trim(jQuery('#qunit-fixture').text()), 'hilayer');
+ equal(jQuery('#qunit-fixture').text().trim(), 'hilayer');
run(router, 'send', 'close');
- equal(trim(jQuery('#qunit-fixture').text()), 'hi');
+ equal(jQuery('#qunit-fixture').text().trim(), 'hi');
});
QUnit.test('Renders child into parent with non-default template name', function() {
@@ -3081,11 +3079,11 @@ QUnit.test('Allows any route to disconnectOutlet another route\'s templates', fu
}
});
bootApplication();
- equal(trim(jQuery('#qunit-fixture').text()), 'hi');
+ equal(jQuery('#qunit-fixture').text().trim(), 'hi');
run(router, 'send', 'openLayer');
- equal(trim(jQuery('#qunit-fixture').text()), 'hilayer');
+ equal(jQuery('#qunit-fixture').text().trim(), 'hilayer');
run(router, 'send', 'close');
- equal(trim(jQuery('#qunit-fixture').text()), 'hi');
+ equal(jQuery('#qunit-fixture').text().trim(), 'hi');
});
QUnit.test('Can this.render({into:...}) the render helper', function() {
diff --git a/packages/internal-test-helpers/lib/test-cases/abstract-application.js b/packages/internal-test-helpers/lib/test-cases/abstract-application.js
index bb5969443ac..bc8db07edd8 100644
--- a/packages/internal-test-helpers/lib/test-cases/abstract-application.js
+++ b/packages/internal-test-helpers/lib/test-cases/abstract-application.js
@@ -1,5 +1,4 @@
import { compile } from 'ember-template-compiler';
-import { jQuery } from 'ember-views';
import { EMBER_GLIMMER_REMOVE_APPLICATION_TEMPLATE_WRAPPER } from 'ember/features';
import AbstractTestCase from './abstract';
import { runDestroy } from '../run';
@@ -10,9 +9,9 @@ export default class AbstractApplicationTestCase extends AbstractTestCase {
if (this._element) {
return this._element;
} else if (EMBER_GLIMMER_REMOVE_APPLICATION_TEMPLATE_WRAPPER) {
- return this._element = jQuery('#qunit-fixture')[0];
+ return this._element = document.querySelector('#qunit-fixture');
} else {
- return this._element = jQuery('#qunit-fixture > div.ember-view')[0];
+ return this._element = document.querySelector('#qunit-fixture > div.ember-view');
}
}
diff --git a/packages/internal-test-helpers/lib/test-cases/abstract-rendering.js b/packages/internal-test-helpers/lib/test-cases/abstract-rendering.js
index 8dff854f386..c275fa5ce8e 100644
--- a/packages/internal-test-helpers/lib/test-cases/abstract-rendering.js
+++ b/packages/internal-test-helpers/lib/test-cases/abstract-rendering.js
@@ -1,6 +1,6 @@
import { assign } from 'ember-utils';
import { compile } from 'ember-template-compiler';
-import { jQuery, EventDispatcher } from 'ember-views';
+import { EventDispatcher } from 'ember-views';
import { helper, Helper, Component, _resetRenderers} from 'ember-glimmer';
import AbstractTestCase from './abstract';
@@ -21,7 +21,7 @@ export default class AbstractRenderingTestCase extends AbstractTestCase {
});
this.renderer = this.owner.lookup('renderer:-dom');
- this.element = jQuery('#qunit-fixture')[0];
+ this.element = document.querySelector('#qunit-fixture');
this.component = null;
owner.register('event_dispatcher:main', EventDispatcher);
diff --git a/packages/internal-test-helpers/lib/test-cases/abstract.js b/packages/internal-test-helpers/lib/test-cases/abstract.js
index 3b34b63f952..26233173182 100644
--- a/packages/internal-test-helpers/lib/test-cases/abstract.js
+++ b/packages/internal-test-helpers/lib/test-cases/abstract.js
@@ -31,6 +31,11 @@ export default class AbstractTestCase {
this.element = null;
this.snapshot = null;
this.assert = QUnit.config.current.assert;
+
+ let { fixture } = this;
+ if (fixture) {
+ this.setupFixture(fixture);
+ }
}
teardown() {}
@@ -43,6 +48,11 @@ export default class AbstractTestCase {
return run.next(callback);
}
+ setupFixture(innerHTML) {
+ let fixture = document.getElementById('qunit-fixture');
+ fixture.innerHTML = innerHTML;
+ }
+
// The following methods require `this.element` to work
get firstChild() {
@@ -88,11 +98,17 @@ export default class AbstractTestCase {
}
click(selector) {
- return this.$(selector).click();
+ let element;
+ if (typeof selector === 'string') {
+ element = this.element.querySelector(selector);
+ } else {
+ element = selector;
+ }
+ return element.click();
}
textValue() {
- return this.$().text();
+ return this.element.textContent;
}
takeSnapshot() {