Skip to content
This repository has been archived by the owner on Mar 5, 2018. It is now read-only.

Commit

Permalink
Test and refactor rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
pittst3r committed Apr 2, 2017
1 parent ab53a6d commit 9d83e86
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 15 deletions.
39 changes: 26 additions & 13 deletions src/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,18 @@ export default class Application implements Owner {
private _registry: Registry;
private _container: Container;
private _renderResult: RenderResult;
/** Whether the initial render has completed. */
private _rendered: boolean;
private _afterRender: Option<() => void>;
/** Whether a re-render has been scheduled. */
private _scheduled: boolean;
private _scheduled: Option<Promise<void>> = null;
private _initializers: Initializer[] = [];
private _initialized = false;

constructor(options: ApplicationOptions) {
this.rootName = options.rootName;
this.resolver = options.resolver;
this._scheduled = new Promise<void>(resolve => {
this._afterRender = resolve;
});
}

/** @hidden */
Expand Down Expand Up @@ -136,13 +138,22 @@ export default class Application implements Owner {

this.env.commit();

this._rendered = true;
let { _afterRender: afterRender } = this;

this._afterRender = null;
this._scheduled = null;
this._renderResult = result.value;

afterRender();
}

renderComponent(component: string | ComponentDefinition<Component>, parent: Simple.Node, nextSibling: Option<Simple.Node>): void {
renderComponent(
component: string | ComponentDefinition<Component>,
parent: Simple.Node,
nextSibling: Option<Simple.Node> = null
): Promise<void> {
this._roots.push({ id: this._rootsIndex++, component, parent, nextSibling });
this.scheduleRerender();
return this.scheduleRerender();
}

/** @hidden */
Expand All @@ -153,13 +164,15 @@ export default class Application implements Owner {
}

/** @hidden */
scheduleRerender(): void {
if (this._scheduled || !this._rendered) { return; }

this._scheduled = true;
requestAnimationFrame(() => {
this._scheduled = false;
this.rerender();
scheduleRerender(): Promise<void> {
if (this._scheduled) return this._scheduled;

return this._scheduled = new Promise<void>(resolve => {
requestAnimationFrame(() => {
this._scheduled = null;
this.rerender();
resolve();
});
});
}

Expand Down
122 changes: 122 additions & 0 deletions test/render-component-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import buildApp from './test-helpers/test-app';

const { module, test } = QUnit;

module('renderComponent');

test('renders a component', function(assert) {
assert.expect(1);

let containerElement = document.createElement('div');

let app = buildApp()
.template('hello-world', `<h1>Hello Glimmer!</h1>`)
.boot();

return app.renderComponent('hello-world', containerElement).then(() => {
assert.equal(containerElement.innerHTML, '<h1>Hello Glimmer!</h1>');
});
});

test('renders a component without affecting existing content', function(assert) {
assert.expect(2);

let containerElement = document.createElement('div');
let previousSibling = document.createElement('p');

previousSibling.appendChild(document.createTextNode('foo'));
containerElement.appendChild(previousSibling);
containerElement.appendChild(document.createTextNode('bar'));

let app = buildApp()
.template('hello-world', `<h1>Hello Glimmer!</h1>`)
.boot();

assert.equal(containerElement.innerHTML, '<p>foo</p>bar');

return app.renderComponent('hello-world', containerElement).then(() => {
assert.equal(containerElement.innerHTML, '<p>foo</p>bar<h1>Hello Glimmer!</h1>');
});
});

test('renders a component before a given sibling', function(assert) {
assert.expect(2);

let containerElement = document.createElement('div');
let previousSibling = document.createElement('p');
let nextSibling = document.createElement('aside');

containerElement.appendChild(previousSibling);
containerElement.appendChild(nextSibling);

let app = buildApp()
.template('hello-world', `<h1>Hello Glimmer!</h1>`)
.boot();

assert.equal(containerElement.innerHTML, '<p></p><aside></aside>');

return app.renderComponent('hello-world', containerElement, nextSibling).then(() => {
assert.equal(containerElement.innerHTML, '<p></p><h1>Hello Glimmer!</h1><aside></aside>');
});
});

test('renders multiple components in different places', function(assert) {
assert.expect(2);

let firstContainerElement = document.createElement('div');
let secondContainerElement = document.createElement('div');

let app = buildApp()
.template('hello-world', `<h1>Hello Glimmer!</h1>`)
.template('hello-robbie', `<h1>Hello Robbie!</h1>`)
.boot();

return Promise.all([
app.renderComponent('hello-world', firstContainerElement),
app.renderComponent('hello-robbie', secondContainerElement)
]).then(() => {
assert.equal(firstContainerElement.innerHTML, '<h1>Hello Glimmer!</h1>');
assert.equal(secondContainerElement.innerHTML, '<h1>Hello Robbie!</h1>');
});
});

test('renders multiple components in the same container', function(assert) {
assert.expect(1);

let containerElement = document.createElement('div');

let app = buildApp()
.template('hello-world', `<h1>Hello Glimmer!</h1>`)
.template('hello-robbie', `<h1>Hello Robbie!</h1>`)
.boot();

return Promise.all([
app.renderComponent('hello-world', containerElement),
app.renderComponent('hello-robbie', containerElement)
]).then(() => {
assert.equal(containerElement.innerHTML, '<h1>Hello Glimmer!</h1><h1>Hello Robbie!</h1>');
});
});

test('renders multiple components in the same container in particular places', function(assert) {
assert.expect(2);

let containerElement = document.createElement('div');
let nextSibling = document.createElement('aside');

containerElement.appendChild(nextSibling);

let app = buildApp()
.template('hello-world', `<h1>Hello Glimmer!</h1>`)
.template('hello-robbie', `<h1>Hello Robbie!</h1>`)
.boot();

assert.equal(containerElement.innerHTML, '<aside></aside>');

return Promise.all([
app.renderComponent('hello-world', containerElement),
app.renderComponent('hello-robbie', containerElement, nextSibling)
]).then(() => {
assert.equal(containerElement.innerHTML, '<h1>Hello Robbie!</h1><aside></aside><h1>Hello Glimmer!</h1>');
});
});
4 changes: 2 additions & 2 deletions test/test-helpers/test-app.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import Application from '../../src/application';
import Resolver, { BasicModuleRegistry } from '@glimmer/resolver';
import { Factory } from '@glimmer/di';

import { TestComponent, TestComponentManager } from './components';
import { precompile } from './compiler';

interface ComponentFactory {
export interface ComponentFactory {
create(injections: object): TestComponent;
}

Expand Down Expand Up @@ -52,6 +51,7 @@ export class AppBuilder {
constructor(name: string) {
this.rootName = name;
this.modules[`component-manager:/${this.rootName}/component-managers/main`] = TestComponentManager;
this.template('main', '<div />');
}

template(name: string, template: string) {
Expand Down

0 comments on commit 9d83e86

Please sign in to comment.