Merge pull request #22540 from tansongyang/ember-rfc-232

ember-qunit and ember-test-helpers: Implement RFC 232
This commit is contained in:
Paul van Brenk
2017-12-28 16:04:08 -08:00
committed by GitHub
9 changed files with 368 additions and 6 deletions
+33 -1
View File
@@ -1,6 +1,16 @@
import Ember from 'ember';
import hbs from 'htmlbars-inline-precompile';
import { test, skip, moduleFor, moduleForModel, moduleForComponent, setResolver } from 'ember-qunit';
import { module } from 'qunit';
import {
test,
skip,
moduleFor,
moduleForModel,
moduleForComponent,
setResolver,
setupRenderingTest,
setupTest,
} from 'ember-qunit';
moduleForComponent('x-foo', {
integration: true
@@ -105,3 +115,25 @@ test('It can calculate the result', function(assert) {
skip('disabled test');
skip('disabled test', function(assert) { });
// https://github.com/emberjs/rfcs/blob/master/text/0232-simplify-qunit-testing-api.md#qunit-nested-modules-api
QUnit.module('some description', function(hooks) {
hooks.before(() => {});
hooks.beforeEach(() => {});
hooks.afterEach(() => {});
hooks.after(() => {});
QUnit.test('it blends', function(assert) {
assert.ok(true, 'of course!');
});
});
// http://rwjblue.com/2017/10/23/ember-qunit-simplication/#setuprenderingtest
module('x-foo', function(hooks) {
setupRenderingTest(hooks);
});
// http://rwjblue.com/2017/10/23/ember-qunit-simplication/#setuptest
module('foo service', function(hooks) {
setupTest(hooks);
});
+37 -1
View File
@@ -1,4 +1,4 @@
// Type definitions for ember-qunit 2.2
// Type definitions for ember-qunit 3.0
// Project: https://github.com/emberjs/ember-qunit#readme
// Definitions by: Derek Wickern <https://github.com/dwickern>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
@@ -43,6 +43,42 @@ declare module 'ember-qunit' {
*/
export function setResolver(resolver: Ember.Resolver): void;
/**
* Sets up tests that need to render snippets of templates.
*
* The setupRenderingTest method is used for tests that need to render
* snippets of templates. It is also invoked in the callback scope of a
* QUnit module (aka "nested module").
*
* Once invoked, all subsequent hooks.beforeEach and test invocations will
* have access to the following:
* * All of the methods / properties listed for `setupTest`
* * this.render(...) - Renders the provided template snippet returning a
* promise that resolves once rendering has completed
* * An importable render function that de-sugars into this.render will be
* the default output of blueprints
* * this.element - Returns the native DOM element representing the element
* that was rendered via this.render
* * this.$(...) - When jQuery is present, executes a jQuery selector with
* the current this.element as its root
*/
export function setupRenderingTest(hooks: NestedHooks): void;
/**
* Sets up tests that do not need to render snippets of templates.
*
* The `setupTest` method is used for all types of tests except for those
* that need to render snippets of templates. It is invoked in the callback
* scope of a QUnit module (aka "nested module").
*
* Once invoked, all subsequent hooks.beforeEach and test invocations will
* have access to the following:
* * this.owner - This exposes the standard "owner API" for the test environment.
* * this.set / this.setProperties - Allows setting values on the test context.
* * this.get / this.getProperties - Retrieves values from the test context.
*/
export function setupTest(hooks: NestedHooks): void;
export class QUnitAdapter extends Ember.Test.Adapter {}
export { module, test, skip, only, todo } from 'qunit';
+2 -1
View File
@@ -2,7 +2,8 @@
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
+107
View File
@@ -0,0 +1,107 @@
import Ember from 'ember';
import hbs from 'htmlbars-inline-precompile';
import { test, skip, moduleFor, moduleForModel, moduleForComponent, setResolver } from 'ember-qunit';
moduleForComponent('x-foo', {
integration: true
});
moduleForComponent('x-foo', {
unit: true,
needs: ['helper:pluralize-string']
});
moduleForModel('user', {
needs: ['model:child']
});
moduleFor('controller:home');
moduleFor('component:x-foo', 'Some description');
moduleFor('component:x-foo', 'TestModule callbacks', {
beforeSetup() {
},
beforeEach(assert) {
this.registry.register('helper:i18n', {});
this.register('service:i18n', {});
this.inject.service('i18n');
this.inject.service('i18n', { as: 'i18n' });
this.factory('object:user').create();
assert.ok(true);
},
afterEach(assert) {
assert.ok(true);
},
afterTeardown(assert) {
assert.ok(true);
}
});
// if you don't have a custom resolver, do it like this:
setResolver(Ember.DefaultResolver.create());
test('it renders', function(assert) {
assert.expect(2);
// setup the outer context
this.set('value', 'cat');
this.on('action', function(result) {
assert.equal(result, 'bar', 'The correct result was returned');
assert.equal(this.get('value'), 'cat');
});
// render the component
this.render(hbs`
{{ x-foo value=value action="result" }}
`);
this.render('{{ x-foo value=value action="result" }}');
this.render([
'{{ x-foo value=value action="result" }}'
]);
assert.equal(this.$('div>.value').text(), 'cat', 'The component shows the correct value');
this.$('button').click();
});
test('it renders', function(assert) {
assert.expect(1);
// creates the component instance
const subject = this.subject();
const subject2 = this.subject({
item: 42
});
const { inputFormat } = this.setProperties({
inputFormat: 'M/D/YY',
outputFormat: 'MMMM D, YYYY',
date: '5/3/10'
});
const { inputFormat: if2, outputFormat } = this.getProperties('inputFormat', 'outputFormat');
const inputFormat2 = this.get('inputFormat');
// render the component on the page
this.render();
assert.equal(this.$('.foo').text(), 'bar');
});
test('It can calculate the result', function(assert) {
assert.expect(1);
const subject = this.subject();
subject.set('value', 'foo');
assert.equal(subject.get('result'), 'bar');
});
skip('disabled test');
skip('disabled test', function(assert) { });
+118
View File
@@ -0,0 +1,118 @@
// Type definitions for ember-qunit 2.2
// Project: https://github.com/emberjs/ember-qunit#readme
// Definitions by: Derek Wickern <https://github.com/dwickern>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
/// <reference types="qunit" />
declare module 'ember-qunit' {
import Ember from 'ember';
import { ModuleCallbacks } from "ember-test-helpers";
interface QUnitModuleCallbacks extends ModuleCallbacks, Hooks {
beforeSetup?(assert: Assert): void;
setup?(assert: Assert): void;
teardown?(assert: Assert): void;
afterTeardown?(assert: Assert): void;
}
/**
* @param fullName The full name of the unit, ie controller:application, route:index.
* @param description The description of the module
*/
export function moduleFor(fullName: string, description: string, callbacks?: QUnitModuleCallbacks): void;
export function moduleFor(fullName: string, callbacks?: QUnitModuleCallbacks): void;
/**
* @param fullName the short name of the component that you'd use in a template, ie x-foo, ic-tabs, etc.
* @param description The description of the module
*/
export function moduleForComponent(fullName: string, description: string, callbacks?: QUnitModuleCallbacks): void;
export function moduleForComponent(fullName: string, callbacks?: QUnitModuleCallbacks): void;
/**
* @param fullName the short name of the model you'd use in store operations ie user, assignmentGroup, etc.
* @param description The description of the module
*/
export function moduleForModel(fullName: string, description: string, callbacks?: QUnitModuleCallbacks): void;
export function moduleForModel(fullName: string, callbacks?: QUnitModuleCallbacks): void;
/**
* Sets a Resolver globally which will be used to look up objects from each test's container.
*/
export function setResolver(resolver: Ember.Resolver): void;
export class QUnitAdapter extends Ember.Test.Adapter {}
export { module, test, skip, only, todo } from 'qunit';
}
declare module 'qunit' {
import { TestContext } from "ember-test-helpers";
export const module: typeof QUnit.module;
/**
* Add a test to run.
*
* Add a test to run using `QUnit.test()`.
*
* The `assert` argument to the callback contains all of QUnit's assertion
* methods. Use this argument to call your test assertions.
*
* `QUnit.test()` can automatically handle the asynchronous resolution of a
* Promise on your behalf if you return a thenable Promise as the result of
* your callback function.
*
* @param name Title of unit being tested
* @param callback Function to close over assertions
*/
export function test(name: string, callback: (this: TestContext, assert: Assert) => void): void;
/**
* Adds a test to exclusively run, preventing all other tests from running.
*
* Use this method to focus your test suite on a specific test. QUnit.only
* will cause any other tests in your suite to be ignored.
*
* Note, that if more than one QUnit.only is present only the first instance
* will run.
*
* This is an alternative to filtering tests to run in the HTML reporter. It
* is especially useful when you use a console reporter or in a codebase
* with a large set of long running tests.
*
* @param name Title of unit being tested
* @param callback Function to close over assertions
*/
export function only(name: string, callback: (this: TestContext, assert: Assert) => void): void;
/**
* Use this method to test a unit of code which is still under development (in a “todo” state).
* The test will pass as long as one failing assertion is present.
*
* If all assertions pass, then the test will fail signaling that `QUnit.todo` should
* be replaced by `QUnit.test`.
*
* @param name Title of unit being tested
* @param callback Function to close over assertions
*/
export function todo(name: string, callback: (this: TestContext, assert: Assert) => void): void;
/**
* Adds a test like object to be skipped.
*
* Use this method to replace QUnit.test() instead of commenting out entire
* tests.
*
* This test's prototype will be listed on the suite as a skipped test,
* ignoring the callback argument and the respective global and module's
* hooks.
*
* @param Title of unit being tested
*/
export const skip: typeof QUnit.skip;
export default QUnit;
}
+25
View File
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": false,
"baseUrl": "../../",
"typeRoots": ["../../"],
"paths": {
"ember-qunit": ["ember-qunit/v2"]
},
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"ember-qunit-tests.ts"
]
}
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "dtslint/dt.json",
"rules": {
"only-arrow-functions": false,
"strict-export-declare-modifiers": false,
"no-duplicate-imports": false,
"no-declare-current-package": false
}
}
@@ -1,8 +1,10 @@
/// <reference types="qunit" />
import { ModuleCallbacks, TestModule } from "ember-test-helpers";
import { ModuleCallbacks, TestContext, TestModule } from "ember-test-helpers";
import wait from 'ember-test-helpers/wait';
import hasEmberVersion from 'ember-test-helpers/has-ember-version';
import hbs from 'htmlbars-inline-precompile';
function moduleFor(name: string, description: string, callbacks: ModuleCallbacks) {
const module = new TestModule(name, description, callbacks);
@@ -23,3 +25,29 @@ async function testWait() {
if (hasEmberVersion(2, 10)) {
// ...
}
// https://github.com/emberjs/ember-test-helpers/blob/f07e86914f2a3823c4cb6787307f9ba2bf447e68/tests/unit/setup-context-test.js
QUnit.test('it sets up this.owner', function(this: TestContext, assert: Assert) {
const { owner } = this;
assert.ok(owner, 'owner was setup');
assert.equal(typeof owner.lookup, 'function', 'has expected lookup interface');
if (hasEmberVersion(2, 12)) {
assert.equal(typeof owner.factoryFor, 'function', 'has expected factory interface');
}
});
QUnit.test('can pauseTest to be resumed "later"', async function(this: TestContext, assert: Assert) {
const promise = this.pauseTest();
this.resumeTest();
await promise;
});
// https://github.com/emberjs/ember-test-helpers/blob/fb4c8d4cd36b54728ce180227f865b1fa0162632/tests/unit/setup-rendering-context-test.js
QUnit.test('render exposes an `.element` property', async function(this: TestContext, assert: Assert) {
await this.render(hbs`<p>Hello!</p>`);
assert.equal(this.element.textContent, 'Hello!');
});
+8 -2
View File
@@ -1,4 +1,4 @@
// Type definitions for ember-test-helpers 0.6
// Type definitions for ember-test-helpers 0.7
// Project: https://github.com/emberjs/ember-test-helpers#readme
// Definitions by: Derek Wickern <https://github.com/dwickern>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
@@ -34,7 +34,7 @@ declare module 'ember-test-helpers' {
send(actionName: string): void;
$: JQueryStatic;
subject(options?: {}): any;
render(template?: string | string[] | TemplateFactory): void;
render(template?: string | string[] | TemplateFactory): Promise<void>;
clearRender(): void;
registry: Ember.Registry;
container: Ember.Container;
@@ -47,6 +47,12 @@ declare module 'ember-test-helpers' {
controller(name: string, options?: { as: string }): any;
service(name: string, options?: { as: string }): any;
};
owner: Ember.ApplicationInstance & {
factoryFor(fullName: string, options?: {}): any;
};
pauseTest(): Promise<void>;
resumeTest(): void;
element: Element;
}
class TestModule {