Skip to content

Commit

Permalink
feat(testing): new tracing capabolities
Browse files Browse the repository at this point in the history
  • Loading branch information
Sayan751 committed Oct 9, 2019
1 parent 11b2f35 commit ffb65ba
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 107 deletions.
3 changes: 3 additions & 0 deletions packages/__tests__/integration/app/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { CallCollection } from '@aurelia/testing';

export const callCollection = new CallCollection();
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { computed, customElement, bindable } from '@aurelia/runtime';
import template from './user-preference.html';
import { trace } from '@aurelia/testing';
import { callCollection } from '../../debug';

@customElement({ name: 'user-preference', template })
export class UserPreference {
@bindable public user: User;
}

@trace(callCollection)
export class User {

public changes = new Set<string>();
constructor(
public firstName: string,
public lastName: string,
Expand All @@ -21,13 +23,11 @@ export class User {

@computed({ static: true })
public get fullNameStatic() {
this.log('static');
return `${this.firstName}${this.lastName ? ` ${this.lastName}` : ''}`;
}

// default setting that is no decorator === `@computed({ static: false })`
// default setting, that is no decorator === `@computed({ static: false })`
public get fullNameNonStatic() {
this.log('nonStatic');
if (this.age < 1) {
return 'infant';
}
Expand All @@ -36,15 +36,13 @@ export class User {

@computed({ static: true })
public get fullNameWrongStatic() {
this.log('wrongStatic');
if (this.age < 1) {
return `infant`;
}
return `${this.firstName}${this.lastName ? ` ${this.lastName}` : ''}`;
}

public get roleNonVolatile() {
this.log('nonVolatile');
return `${this.role}, ${this.organization}`;
}
public set roleNonVolatile(value: string) {
Expand All @@ -54,17 +52,9 @@ export class User {

@computed({ volatile: true })
public get locationVolatile() {
this.log('volatile');
return `${this.city}, ${this.country}`;
}
public set locationVolatile(value: string) {
this.country = value;
}

private log(name: 'default' | 'static' | 'nonStatic' | 'wrongStatic' | 'nonVolatile' | 'volatile') {
this.changes.add(name);
}
private getFullName() {
return `${this.firstName}${this.lastName ? ` ${this.lastName}` : ''}`;
}
}
9 changes: 6 additions & 3 deletions packages/__tests__/integration/app/startup.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { IRegistration } from '@aurelia/kernel';
import { Aurelia, FrequentMutations } from '@aurelia/runtime';
import { HTMLTestContext, TestContext } from '@aurelia/testing';
import { HTMLTestContext, TestContext, CallCollection } from '@aurelia/testing';
import { App as component } from './app';
import { atoms } from './atoms';
import { molecules } from './molecules';
import { callCollection } from './debug';

export class TestExecutionContext {
constructor(
public au: Aurelia,
public host: HTMLElement,
public ctx: HTMLTestContext,
public tearDown: () => Promise<void>
public tearDown: () => Promise<void>,
public callCollection: CallCollection
) { }
}

Expand All @@ -33,7 +35,8 @@ export async function startup() {
async function tearDown() {
await au.stop().wait();
ctx.doc.body.removeChild(host);
callCollection.calls.splice(0);
}

return new TestExecutionContext(au, host, ctx, tearDown);
return new TestExecutionContext(au, host, ctx, tearDown, callCollection);
}
196 changes: 108 additions & 88 deletions packages/__tests__/integration/integration.spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import { CustomElement } from '@aurelia/runtime';
import { assert, fail } from '@aurelia/testing';
import { assert, fail, Call } from '@aurelia/testing';
import { App } from './app/app';
import { startup, TestExecutionContext } from './app/startup';

describe.only('app', function () {
describe('app', function () {

function getViewModel<T>(element: Element) {
const { viewModel } = CustomElement.behaviorFor(element) as unknown as { viewModel: T };
return viewModel;
}

function $it(title: string, testFunction: (ctx: TestExecutionContext) => Promise<void> | void) {
return it(title, async function () {
function createTestFunction(testFunction: (ctx: TestExecutionContext) => Promise<void> | void) {
return async function () {
const ctx = await startup();
try {
await testFunction(ctx);
Expand All @@ -20,10 +15,36 @@ describe.only('app', function () {
} finally {
await ctx.tearDown();
}
});
}
}
function $it(title: string, testFunction: (ctx: TestExecutionContext) => Promise<void> | void) {
return it(title, createTestFunction(testFunction));
}
$it.skip = function (title: string, testFunction: (ctx: TestExecutionContext) => Promise<void> | void) {
return it.skip(title, createTestFunction(testFunction));
}
$it.skip = function (title: string, _testFunction: (ctx: TestExecutionContext) => Promise<void> | void) {
return it.skip(title);
$it.only = function (title: string, testFunction: (ctx: TestExecutionContext) => Promise<void> | void) {
return it.only(title, createTestFunction(testFunction));
}

function getViewModel<T>(element: Element) {
const { viewModel } = CustomElement.behaviorFor(element) as unknown as { viewModel: T };
return viewModel;
}
function assertCalls(
calls: Call[],
fromIndex: number,
instance: any,
expectedCalls: string[],
unexpectedCalls?: string[],
message?: string) {
const recentCalls = new Set(calls.slice(fromIndex).map((c) => Object.is(c.instance, instance) && c.method));
for (const expectedCall of expectedCalls) {
assert.equal(recentCalls.has(expectedCall), true, `${message||''} expected ${expectedCall}`);
}
for (const expectedCall of unexpectedCalls) {
assert.equal(recentCalls.has(expectedCall), false, `${message||''} not expected ${expectedCall}`);
}
}

$it('has some readonly texts with different binding modes', async function ({ host }) {
Expand Down Expand Up @@ -149,80 +170,79 @@ describe.only('app', function () {
assert.html.textContent('h2', `${camera.modelNumber} by ${camera.make}`, 'incorrect text', specsViewer);
});

$it('uses a user preference control that \'computes\' the full name of the user correctly - static', async function ({ host, ctx }) {
const { user } = getViewModel<App>(host);

const userPref = host.querySelector('user-preference');

const statc = userPref.querySelector('#static');
const nonStatic = userPref.querySelector('#nonStatic');
const wrongStatic = userPref.querySelector('#wrongStatic');

assert.html.textContent(statc, 'John Doe', 'incorrect text statc');
assert.html.textContent(nonStatic, 'infant', 'incorrect text nonStatic');
assert.html.textContent(wrongStatic, 'infant', 'incorrect text wrongStatic');

const { changes: uc } = user;
uc.clear();
user.firstName = 'Jane';
ctx.lifecycle.processRAFQueue(undefined);
assert.html.textContent(statc, 'Jane Doe', 'incorrect text statc - fname');
assert.html.textContent(nonStatic, 'infant', 'incorrect text nonStatic - fname');
assert.html.textContent(wrongStatic, 'infant', 'incorrect text wrongStatic - fname');
assert.equal(uc.has('static'), true, 'static change should have triggered - fname');
assert.equal(uc.has('nonStatic'), false, 'nonStatic change should not have triggered - fname');
assert.equal(uc.has('wrongStatic'), false, 'wrongStatic change should not have triggered - fname');

uc.clear();
user.age = 10;
ctx.lifecycle.processRAFQueue(undefined);
assert.html.textContent(statc, 'Jane Doe', 'incorrect text statc - age');
assert.html.textContent(nonStatic, 'Jane Doe', 'incorrect text nonStatic - age');
assert.html.textContent(wrongStatic, 'Jane Doe', 'incorrect text wrongStatic - age');
assert.equal(uc.has('static'), false, 'static change should not have triggered - age');
assert.equal(uc.has('nonStatic'), true, 'nonStatic change should have triggered - age');
assert.equal(uc.has('wrongStatic'), true, 'wrongStatic change should have triggered - age');

uc.clear();
user.lastName = 'Smith';
ctx.lifecycle.processRAFQueue(undefined);
assert.html.textContent(statc, 'Jane Smith', 'incorrect text statc - lname');
assert.html.textContent(nonStatic, 'Jane Smith', 'incorrect text nonStatic - lname');
assert.html.textContent(wrongStatic, 'Jane Doe', 'incorrect text wrongStatic - lname');
assert.equal(uc.has('static'), true, 'static change should have triggered - lname');
assert.equal(uc.has('nonStatic'), true, 'nonStatic change should have triggered - lname');
assert.equal(uc.has('wrongStatic'), false, 'wrongStatic change should have triggered - lname');
});

$it('uses a user preference control that \'computes\' the organization of the user correctly - volatile', async function ({ host, ctx }) {

const { user } = getViewModel<App>(host);

const userPref = host.querySelector('user-preference');

const nonVolatile = userPref.querySelector('#nonVolatile');
const volatile = userPref.querySelector('#volatile');

assert.html.textContent(nonVolatile, 'Role1, Org1', 'incorrect text nonVolatile');
assert.html.textContent(volatile, 'City1, Country1', 'incorrect text volatile');

const { changes: uc } = user;
uc.clear();
user.roleNonVolatile = 'Role2';
user.locationVolatile = 'Country2';
ctx.lifecycle.processRAFQueue(undefined);
assert.html.textContent(nonVolatile, 'Role2, Org1', 'incorrect text nonVolatile - role');
assert.html.textContent(volatile, 'City1, Country2', 'incorrect text volatile - country');
assert.equal(uc.has('nonVolatile'), true, 'nonVolatile change should have triggered - role');
assert.equal(uc.has('volatile'), true, 'volatile change should have triggered - country');

uc.clear();
user.organization = 'Org2'
user.city = 'City2';
ctx.lifecycle.processRAFQueue(undefined);
assert.html.textContent(nonVolatile, 'Role2, Org1', 'incorrect text nonVolatile - role');
assert.html.textContent(volatile, 'City2, Country2', 'incorrect text volatile - country');
assert.equal(uc.has('nonVolatile'), false, 'nonVolatile change should not have triggered - role');
assert.equal(uc.has('volatile'), true, 'volatile change should have triggered - country');
});
$it('uses a user preference control that \'computes\' the full name of the user correctly - static',
async function ({ host, ctx, callCollection: { calls } }) {
const { user } = getViewModel<App>(host);

const userPref = host.querySelector('user-preference');

const statc = userPref.querySelector('#static');
const nonStatic = userPref.querySelector('#nonStatic');
const wrongStatic = userPref.querySelector('#wrongStatic');

assert.html.textContent(statc, 'John Doe', 'incorrect text statc');
assert.html.textContent(nonStatic, 'infant', 'incorrect text nonStatic');
assert.html.textContent(wrongStatic, 'infant', 'incorrect text wrongStatic');

let index = calls.length;
user.firstName = 'Jane';
ctx.lifecycle.processRAFQueue(undefined);
assert.html.textContent(statc, 'Jane Doe', 'incorrect text statc - fname');
assert.html.textContent(nonStatic, 'infant', 'incorrect text nonStatic - fname');
assert.html.textContent(wrongStatic, 'infant', 'incorrect text wrongStatic - fname');
assert.greaterThan(calls.length, index);
assertCalls(calls, index, user, ['get fullNameStatic'], ['get fullNameNonStatic', 'get fullNameWrongStatic']);

index = calls.length;
user.age = 10;
ctx.lifecycle.processRAFQueue(undefined);
assert.html.textContent(statc, 'Jane Doe', 'incorrect text statc - age');
assert.html.textContent(nonStatic, 'Jane Doe', 'incorrect text nonStatic - age');
assert.html.textContent(wrongStatic, 'Jane Doe', 'incorrect text wrongStatic - age');
assert.greaterThan(calls.length, index);
assertCalls(calls, index, user, ['get fullNameNonStatic', 'get fullNameWrongStatic'], ['get fullNameStatic']);

index = calls.length;
user.lastName = 'Smith';
ctx.lifecycle.processRAFQueue(undefined);
assert.html.textContent(statc, 'Jane Smith', 'incorrect text statc - lname');
assert.html.textContent(nonStatic, 'Jane Smith', 'incorrect text nonStatic - lname');
assert.html.textContent(wrongStatic, 'Jane Doe', 'incorrect text wrongStatic - lname');
assert.greaterThan(calls.length, index);
assertCalls(calls, index, user, ['get fullNameStatic', 'get fullNameNonStatic'], ['get fullNameWrongStatic']);
}
);

$it('uses a user preference control that \'computes\' the organization of the user correctly - volatile',
async function ({ host, ctx, callCollection: { calls } }) {

const { user } = getViewModel<App>(host);

const userPref = host.querySelector('user-preference');

const nonVolatile = userPref.querySelector('#nonVolatile');
const volatile = userPref.querySelector('#volatile');

assert.html.textContent(nonVolatile, 'Role1, Org1', 'incorrect text nonVolatile');
assert.html.textContent(volatile, 'City1, Country1', 'incorrect text volatile');

let index = calls.length;
user.roleNonVolatile = 'Role2';
user.locationVolatile = 'Country2';
ctx.lifecycle.processRAFQueue(undefined);
assert.html.textContent(nonVolatile, 'Role2, Org1', 'incorrect text nonVolatile - role');
assert.html.textContent(volatile, 'City1, Country2', 'incorrect text volatile - country');
assert.greaterThan(calls.length, index);
assertCalls(calls, index, user, ['get roleNonVolatile', 'get locationVolatile'], []);

index = calls.length;
user.organization = 'Org2'
user.city = 'City2';
ctx.lifecycle.processRAFQueue(undefined);
assert.html.textContent(nonVolatile, 'Role2, Org1', 'incorrect text nonVolatile - role');
assert.html.textContent(volatile, 'City2, Country2', 'incorrect text volatile - country');
assert.greaterThan(calls.length, index);
assertCalls(calls, index, user, ['get locationVolatile'], ['get roleNonVolatile']);
}
);
});
1 change: 1 addition & 0 deletions packages/testing/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export {
CallCollection,
recordCalls,
stopRecordingCalls,
trace
} from './tracing';
export {
trimFull,
Expand Down
Loading

0 comments on commit ffb65ba

Please sign in to comment.