diff --git a/packages/diffhtml/lib/inner-html.js b/packages/diffhtml/lib/inner-html.js index dae0838f..e40359ee 100644 --- a/packages/diffhtml/lib/inner-html.js +++ b/packages/diffhtml/lib/inner-html.js @@ -3,16 +3,16 @@ import { EMPTY, ValidInput, TransactionConfig, Mount } from './util/types'; /** * - * @param {Mount} domNode + * @param {Mount} mount * @param {ValidInput} input * @param {TransactionConfig} config * * @return {Promise | unknown} */ -export default function innerHTML(domNode, input = EMPTY.STR, config = {}) { +export default function innerHTML(mount, input = EMPTY.STR, config = {}) { config.inner = true; config.executeScripts = 'executeScripts' in config ? config.executeScripts : true; config.tasks = config.tasks || defaultTasks; - return Transaction.create(domNode, input, config).start(); + return Transaction.create(mount, input, config).start(); } diff --git a/packages/diffhtml/lib/release.js b/packages/diffhtml/lib/release.js index b911689d..a85e855e 100644 --- a/packages/diffhtml/lib/release.js +++ b/packages/diffhtml/lib/release.js @@ -4,16 +4,16 @@ import { StateCache, NodeCache, ReleaseHookCache, Mount } from './util/types'; /** * Releases state and memory associated to a DOM Node. * - * @param {Mount} domNode - Valid input node + * @param {Mount} mount - Valid input node */ -export default function release(domNode) { +export default function release(mount) { // Try and find a state object for this DOM Node. - const state = StateCache.get(domNode); + const state = StateCache.get(mount); // If this was a top-level rendered element, deallocate the VTree // and remove the StateCache reference. if (state) { - StateCache.delete(domNode); + StateCache.delete(mount); // If there is a known root association that is not in the NodeCache, // remove this VTree. @@ -25,11 +25,11 @@ export default function release(domNode) { // The rest of this function only pertains to real HTML element nodes. If // this is undefined, then it isn't one. - if (!domNode) { + if (!mount) { return; } - const asHTMLElement = /** @type {HTMLElement} */(domNode); + const asHTMLElement = /** @type {HTMLElement} */(mount); // Crawl the childNodes if this is an HTMLElement for state trees. if (asHTMLElement.childNodes && asHTMLElement.childNodes.length) { diff --git a/packages/diffhtml/lib/tasks/parse-new-tree.js b/packages/diffhtml/lib/tasks/parse-new-tree.js index ddb73dae..975b5b18 100644 --- a/packages/diffhtml/lib/tasks/parse-new-tree.js +++ b/packages/diffhtml/lib/tasks/parse-new-tree.js @@ -6,7 +6,7 @@ import Transaction from '../transaction'; * @param {Transaction} transaction */ export default function parseNewTree(transaction) { - const { state, input, options } = transaction; + const { state, input, config: options } = transaction; const { measure } = state; const { inner } = options; diff --git a/packages/diffhtml/lib/tasks/patch-node.js b/packages/diffhtml/lib/tasks/patch-node.js index a2b63fb5..461ee6e7 100644 --- a/packages/diffhtml/lib/tasks/patch-node.js +++ b/packages/diffhtml/lib/tasks/patch-node.js @@ -10,11 +10,11 @@ import globalThis from '../util/global'; * @return {void} */ export default function patch(transaction) { - const { domNode, state, state: { measure, scriptsToExecute }, patches } = transaction; + const { mount, state, state: { measure, scriptsToExecute }, patches } = transaction; measure('patch node'); - const { ownerDocument } = /** @type {HTMLElement} */ (domNode); + const { ownerDocument } = /** @type {HTMLElement} */ (mount); const promises = transaction.promises || []; state.ownerDocument = ownerDocument || globalThis.document; diff --git a/packages/diffhtml/lib/tasks/reconcile-trees.js b/packages/diffhtml/lib/tasks/reconcile-trees.js index d0d0ad67..3f0e168c 100644 --- a/packages/diffhtml/lib/tasks/reconcile-trees.js +++ b/packages/diffhtml/lib/tasks/reconcile-trees.js @@ -12,21 +12,21 @@ import release from '../release'; * @param {Transaction} transaction */ export default function reconcileTrees(transaction) { - const { state, domNode, input, options } = transaction; + const { state, mount, input, config: options } = transaction; const { previousMarkup } = state; const { inner } = options; - const domNodeAsHTMLEl = /** @type {HTMLElement} */ (domNode); - const { outerHTML } = domNodeAsHTMLEl; + const mountAsHTMLEl = /** @type {HTMLElement} */ (mount); + const { outerHTML } = mountAsHTMLEl; // We rebuild the tree whenever the DOM Node changes, including the first // time we patch a DOM Node. if (previousMarkup !== outerHTML || !state.oldTree || !outerHTML) { - release(domNode); - state.oldTree = createTree(domNodeAsHTMLEl); + release(mount); + state.oldTree = createTree(mountAsHTMLEl); protectVTree(state.oldTree); // Reset the state cache after releasing. - StateCache.set(domNode, state); + StateCache.set(mount, state); } const { nodeName, attributes } = state.oldTree; diff --git a/packages/diffhtml/lib/tasks/schedule.js b/packages/diffhtml/lib/tasks/schedule.js index ff8561bf..425526e7 100644 --- a/packages/diffhtml/lib/tasks/schedule.js +++ b/packages/diffhtml/lib/tasks/schedule.js @@ -18,23 +18,31 @@ export default function schedule(transaction) { // Loop through all existing mounts to ensure we properly wait. StateCache.forEach(val => { - // Is parent. - const domNode = /** @type {HTMLElement} */ ( - val.activeTransaction && val.activeTransaction.domNode + const oldMount = /** @type {HTMLElement} */ ( + val.activeTransaction && val.activeTransaction.mount ); - const newNode = /** @type {HTMLElement} */ (transaction.domNode); + const newMount = /** @type {HTMLElement} */ (transaction.mount); - if (!domNode || !domNode.contains || !newNode || !newNode.contains) { + // Only consider transactions that have mounts and are rendering. + if (!oldMount || !newMount || !val.isRendering) { return; } + // If the new mount point exists within an existing point that is rendering, + // then wait for that transaction to finish. else if ( - (domNode.contains(newNode) || newNode.contains(domNode)) && - val.isRendering + oldMount.contains && oldMount.contains(newMount) || + newMount.contains && newMount.contains(oldMount) ) { state = val; isRendering = true; } + // Test if the active transaction is the same as the incoming by looking at + // the mount. Then look and see if the state is rendering. + else if (oldMount === newMount) { + state = val; + isRendering = true; + } }); const { activeTransaction, nextTransaction } = state; diff --git a/packages/diffhtml/lib/tasks/should-update.js b/packages/diffhtml/lib/tasks/should-update.js index c57a30c2..dd2516da 100644 --- a/packages/diffhtml/lib/tasks/should-update.js +++ b/packages/diffhtml/lib/tasks/should-update.js @@ -6,17 +6,17 @@ import Transaction from "../transaction"; * @param {Transaction} transaction */ export default function shouldUpdate(transaction) { - const { domNode, input, state, state: { measure }, options } = transaction; + const { mount, input, state, state: { measure }, config: options } = transaction; const prop = options.inner ? 'innerHTML' : 'outerHTML'; measure('should update'); - const domNodeAsEl = /** @type {HTMLElement} */ (domNode); + const mountAsHTMLEl = /** @type {HTMLElement} */ (mount); // If the contents haven't changed, abort the flow. Only support this if // the new markup is a string, otherwise it's possible for our object // recycling to match twice. - if (typeof input === 'string' && domNodeAsEl[prop]=== input) { + if (typeof input === 'string' && mountAsHTMLEl[prop]=== input) { return transaction.abort(true); } else if (typeof input === 'string') { diff --git a/packages/diffhtml/lib/tasks/sync-trees.js b/packages/diffhtml/lib/tasks/sync-trees.js index d93e153a..564df715 100644 --- a/packages/diffhtml/lib/tasks/sync-trees.js +++ b/packages/diffhtml/lib/tasks/sync-trees.js @@ -5,7 +5,7 @@ import process from '../util/process'; import Transaction from '../transaction'; export default function syncTrees(/** @type {Transaction} */ transaction) { - const { state, state: { measure }, oldTree, newTree, domNode } = transaction; + const { state, state: { measure }, oldTree, newTree, mount } = transaction; measure('sync trees'); @@ -31,7 +31,7 @@ export default function syncTrees(/** @type {Transaction} */ transaction) { // If there is no `parentNode` for the replace operation, we will need to // throw an error and prevent the `StateCache` from being updated. if (process.env.NODE_ENV !== 'production') { - if (!/** @type {HTMLElement} */ (domNode).parentNode) { + if (!/** @type {HTMLElement} */ (mount).parentNode) { throw new Error('Unable to replace top level node without a parent'); } } @@ -49,10 +49,10 @@ export default function syncTrees(/** @type {Transaction} */ transaction) { const newNode = createNode(newTree); // Update the StateCache since we are changing the top level element. - StateCache.delete(domNode); + StateCache.delete(mount); StateCache.set(/** @type {Mount} */ (newNode), state); - transaction.domNode = /** @type {HTMLElement} */ (newNode); + transaction.mount = /** @type {HTMLElement} */ (newNode); if (newTree.nodeName === 'script') { state.scriptsToExecute.set(newTree, newTree.attributes.type || EMPTY.STR); diff --git a/packages/diffhtml/lib/transaction.js b/packages/diffhtml/lib/transaction.js index 0433b978..12bb182f 100644 --- a/packages/diffhtml/lib/transaction.js +++ b/packages/diffhtml/lib/transaction.js @@ -33,12 +33,12 @@ export const tasks = { export default class Transaction { /** * - * @param {Mount} domNode + * @param {Mount} mount * @param {ValidInput} input * @param {TransactionConfig} options */ - static create(domNode, input, options) { - return new Transaction(domNode, input, options); + static create(mount, input, options) { + return new Transaction(mount, input, options); } /** @@ -80,7 +80,7 @@ export default class Transaction { */ static assert(transaction) { if (process.env.NODE_ENV !== 'production') { - if (typeof transaction.domNode !== 'object' || !transaction.domNode) { + if (typeof transaction.mount !== 'object' || !transaction.mount) { throw new Error('Transaction requires a DOM Node mount point'); } @@ -125,16 +125,15 @@ export default class Transaction { * @param {TransactionConfig} config */ constructor(mount, input, config) { - // TODO: Rename this to mount. - this.domNode = mount; + this.mount = mount; this.input = input; - // TODO: Rename this to config. - this.options = config; + this.config = config; this.state = StateCache.get(mount) || /** @type {TransactionState} */ ({ - measure: makeMeasure(mount, input), + measure: makeMeasure(this), svgElements: new Set(), scriptsToExecute: new Map(), + activeTransaction: this, }); this.tasks = /** @type {Function[]} */ ( @@ -195,9 +194,9 @@ export default class Transaction { * @return {Transaction} */ end() { - const { state, domNode, options } = this; + const { state, mount, config: options } = this; const { measure, svgElements, scriptsToExecute } = state; - const domNodeAsHTMLEl = /** @type {HTMLElement} */ (domNode); + const mountAsHTMLEl = /** @type {HTMLElement} */ (mount); measure('finalize'); @@ -218,7 +217,7 @@ export default class Transaction { }); // Save the markup immediately after patching. - state.previousMarkup = 'outerHTML' in domNodeAsHTMLEl ? domNodeAsHTMLEl.outerHTML : EMPTY.STR; + state.previousMarkup = 'outerHTML' in mountAsHTMLEl ? mountAsHTMLEl.outerHTML : EMPTY.STR; // Only execute scripts if the configuration is set. By default this is set // to true. You can toggle this behavior for your app to disable script @@ -280,10 +279,10 @@ export default class Transaction { state = EMPTY.OBJ; /** @type {Mount} */ - domNode = EMPTY.STR; + mount = EMPTY.OBJ; /** @type {ValidInput} */ - input = EMPTY.STR; + input = EMPTY.OBJ; /** @type {VTree=} */ oldTree = undefined; diff --git a/packages/diffhtml/lib/util/make-measure.js b/packages/diffhtml/lib/util/make-measure.js index 6f3f4ece..30dea5d6 100644 --- a/packages/diffhtml/lib/util/make-measure.js +++ b/packages/diffhtml/lib/util/make-measure.js @@ -1,50 +1,55 @@ -import { Mount, ValidInput, VTree } from "./types"; -import getConfig from './config'; - -export const marks = new Map(); -export const prefix = 'diffHTML'; +import getConfig from "./config"; +import { VTree } from "./types"; +const prefix = 'diffHTML'; +const marks = new Map(); const nop = () => {}; +let count = 0; /** + * Creates a measure function that will collect data about the currently running + * transaction. * - * @param {Mount} mount - * @param {ValidInput=} input + * @param {import('../transaction').default} transaction * @return {(name: string) => void} */ -export default function makeMeasure(mount, input) { - const wantsPerfChecks = getConfig('collectMetrics', false); - - // If the user has not requested they want perf checks, return a nop - // function. - if (!wantsPerfChecks) { return nop; } - +export default function makeMeasure(transaction) { + const { mount, input } = transaction; const inputAsVTree = /** @type {VTree} */ (input); + const id = count++; + + // Marks will only be available if the user has requested they want to collect + // metrics. + if (!getConfig('collectMetrics', false)) { return nop; } return name => { - const host = /** @type any */ (mount).host; + name = `[${id}] ${name}`; + + const { host } = /** @type {any} */ (mount); // Use the Web Component name if it's available. if (mount && host) { name = `${host.constructor.name} ${name}`; } + // Otherwise try an find the function name used. else if (inputAsVTree && typeof inputAsVTree.rawNodeName === 'function') { name = `${inputAsVTree.rawNodeName.name} ${name}`; } const endName = `${name}-end`; - if (!marks.has(name)) { - marks.set(name, performance.now()); - performance.mark(name); - } - else { - const totalMs = (performance.now() - marks.get(name)).toFixed(3); + if (marks.has(name)) { + const prevMark = marks.get(name) || 0; + const totalMs = (performance.now() - prevMark).toFixed(3); marks.delete(name); performance.mark(endName); performance.measure(`${prefix} ${name} (${totalMs}ms)`, name, endName); } + else { + marks.set(name, performance.now()); + performance.mark(name); + } }; } \ No newline at end of file diff --git a/packages/diffhtml/lib/util/types.js b/packages/diffhtml/lib/util/types.js index f970aa14..97592a1c 100644 --- a/packages/diffhtml/lib/util/types.js +++ b/packages/diffhtml/lib/util/types.js @@ -227,8 +227,8 @@ export const Supplemental = EMPTY.OBJ; * @property {VTree=} oldTree * @property {Boolean=} isRendering * @property {String=} previousMarkup - * @property {any=} activeTransaction - * @property {any=} nextTransaction + * @property {import('../transaction').default} activeTransaction + * @property {import('../transaction').default=} nextTransaction * @property {Document=} ownerDocument */ export const TransactionState = EMPTY.OBJ; diff --git a/packages/diffhtml/test/tasks.js b/packages/diffhtml/test/tasks.js index b1512bc4..57a0f4a0 100644 --- a/packages/diffhtml/test/tasks.js +++ b/packages/diffhtml/test/tasks.js @@ -1,4 +1,4 @@ -import { equal, deepEqual, notStrictEqual, throws } from 'assert'; +import { strictEqual, deepStrictEqual, notStrictEqual, throws } from 'assert'; import html from '../lib/html'; import release from '../lib/release'; import Transaction from '../lib/transaction'; @@ -23,7 +23,7 @@ describe('Tasks', function() { reconcileTrees(transaction); - deepEqual(transaction.oldTree, { + deepStrictEqual(transaction.oldTree, { rawNodeName: 'DIV', nodeName: 'div', nodeValue: '', @@ -40,7 +40,7 @@ describe('Tasks', function() { reconcileTrees(transaction); - deepEqual(transaction.oldTree, { + deepStrictEqual(transaction.oldTree, { rawNodeName: '#document-fragment', nodeName: '#document-fragment', nodeValue: '', @@ -63,7 +63,7 @@ describe('Tasks', function() { const { oldTree } = transaction; - deepEqual(oldTree, { + deepStrictEqual(oldTree, { rawNodeName: 'DIV', nodeName: 'div', nodeValue: '', @@ -77,7 +77,7 @@ describe('Tasks', function() { reconcileTrees(secondTransaction); - deepEqual(oldTree, secondTransaction.oldTree); + deepStrictEqual(oldTree, secondTransaction.oldTree); }); it('will upgrade the domNode if it is not the exact same as before', () => { @@ -88,7 +88,7 @@ describe('Tasks', function() { transaction.state.previousMarkup = this.fixture.outerHTML; transaction.state.oldTree = transaction.oldTree; - deepEqual(transaction.oldTree, { + deepStrictEqual(transaction.oldTree, { rawNodeName: 'DIV', nodeName: 'div', nodeValue: '', @@ -104,7 +104,7 @@ describe('Tasks', function() { const secondTransaction = Transaction.create(this.fixture, html`
`, {}); reconcileTrees(secondTransaction); - deepEqual(secondTransaction.oldTree, { + deepStrictEqual(secondTransaction.oldTree, { rawNodeName: 'DIV', nodeName: 'div', nodeValue: '', @@ -131,7 +131,7 @@ describe('Tasks', function() { reconcileTrees(transaction); - deepEqual(transaction.newTree, { + deepStrictEqual(transaction.newTree, { rawNodeName: Component, nodeName: '#document-fragment', nodeValue: '', @@ -155,7 +155,7 @@ describe('Tasks', function() { reconcileTrees(transaction); - deepEqual(transaction.newTree, { + deepStrictEqual(transaction.newTree, { rawNodeName: 'div', nodeName: 'div', nodeValue: '', @@ -177,7 +177,7 @@ describe('Tasks', function() { reconcileTrees(transaction); - deepEqual(transaction.newTree, { + deepStrictEqual(transaction.newTree, { rawNodeName: '#document-fragment', nodeName: '#document-fragment', nodeValue: '', @@ -198,8 +198,8 @@ describe('Tasks', function() { const { state } = transaction; - equal(state.isRendering, true); - equal(state.activeTransaction, transaction); + strictEqual(state.isRendering, true); + strictEqual(state.activeTransaction, transaction); }); it('will make a subsequent transaction wait for an existing element', async () => { @@ -216,15 +216,15 @@ describe('Tasks', function() { const promise = schedule(transaction2); const { state } = transaction1; - equal(typeof transaction2.promise.then, 'function'); - equal(state.nextTransaction, transaction2); - equal(transaction2.aborted, true); + strictEqual(typeof transaction2.promise.then, 'function'); + strictEqual(state.nextTransaction, transaction2); + strictEqual(transaction2.aborted, true); // Wait for the promise to complete. await promise; - equal(transaction2.aborted, false); - equal(state.activeTransaction, transaction2); + strictEqual(transaction2.aborted, false); + strictEqual(state.activeTransaction, transaction2); }); it('will make a new transaction wait for an existing parent element transaction', async () => { @@ -252,15 +252,15 @@ describe('Tasks', function() { // States are different per element notStrictEqual(state1, state2); - equal(typeof transaction2.promise.then, 'function'); - equal(state1.nextTransaction, transaction2); - equal(transaction2.aborted, true); + strictEqual(typeof transaction2.promise.then, 'function'); + strictEqual(state1.nextTransaction, transaction2); + strictEqual(transaction2.aborted, true); // Wait for the promise to complete. await promise; - equal(transaction2.aborted, false); - equal(state2.activeTransaction, transaction2); + strictEqual(transaction2.aborted, false); + strictEqual(state2.activeTransaction, transaction2); }); it('will make a new transaction wait for an existing child element render', async () => { @@ -288,15 +288,15 @@ describe('Tasks', function() { // States are different per element notStrictEqual(state1, state2); - equal(typeof transaction2.promise.then, 'function'); - equal(state1.nextTransaction, transaction2); - equal(transaction2.aborted, true); + strictEqual(typeof transaction2.promise.then, 'function'); + strictEqual(state1.nextTransaction, transaction2); + strictEqual(transaction2.aborted, true); // Wait for the promise to complete. await promise; - equal(transaction2.aborted, false); - equal(state2.activeTransaction, transaction2); + strictEqual(transaction2.aborted, false); + strictEqual(state2.activeTransaction, transaction2); }); }); diff --git a/packages/diffhtml/test/transaction.js b/packages/diffhtml/test/transaction.js index 0202e290..c4fb4abb 100644 --- a/packages/diffhtml/test/transaction.js +++ b/packages/diffhtml/test/transaction.js @@ -1,45 +1,46 @@ -import { ok, deepEqual, equal, doesNotThrow, throws } from 'assert'; +import { ok, deepStrictEqual, strictEqual, doesNotThrow, throws } from 'assert'; import { spy, stub, SinonSpy } from 'sinon'; import Transaction from '../lib/transaction'; import use from '../lib/use'; import release from '../lib/release'; import validateMemory from './util/validate-memory'; +import { EMPTY } from '../lib/util/types'; describe('Transaction', function() { const suite = /** @type {any} */(this); beforeEach(() => { process.env.NODE_ENV = 'development'; - suite.domNode = document.createElement('div'); + suite.mount = document.createElement('div'); suite.input = `
Hello world
`; - suite.options = { inner: false, tasks: [spy()] }; + suite.config = { inner: false, tasks: [spy()] }; }); afterEach(() => { - release(suite.domNode); + release(suite.mount); validateMemory(); }); describe('create', () => { it('will return a transaction instance', () => { - const { domNode, input, options } = suite; - const transaction = new Transaction(domNode, input, options); + const { mount, input, config } = suite; + const transaction = new Transaction(mount, input, config); ok(transaction instanceof Transaction); }); it('will attach relevant properties to the transaction instance', () => { - const { domNode, input, options } = suite; - const transaction = new Transaction(domNode, input, options); + const { mount, input, config } = suite; + const transaction = new Transaction(mount, input, config); const { tasks, state, endedCallbacks } = transaction; - deepEqual(transaction, { + deepStrictEqual({ ...transaction }, { // Public. - domNode, + mount, input, - options, + config, tasks, state, endedCallbacks, @@ -60,8 +61,8 @@ describe('Transaction', function() { Transaction.flow(suite, [testFn]); - equal(testFn.calledOnce, true); - equal(testFn.calledWith(this), true); + strictEqual(testFn.calledOnce, true); + strictEqual(testFn.calledWith(this), true); }); it('will set up multiple functions to run', () => { @@ -70,8 +71,8 @@ describe('Transaction', function() { Transaction.flow(suite, [testFn, testFnTwo]); - equal(testFn.calledOnce, true); - equal(testFnTwo.calledOnce, true); + strictEqual(testFn.calledOnce, true); + strictEqual(testFnTwo.calledOnce, true); }); it('will abort a flow when a function returns a value', () => { @@ -81,9 +82,9 @@ describe('Transaction', function() { Transaction.flow(suite, [testFn, testFnTwo, testFnThree]); - equal(testFn.calledOnce, true); - equal(testFnTwo.calledOnce, true); - equal(testFnThree.calledOnce, false); + strictEqual(testFn.calledOnce, true); + strictEqual(testFnTwo.calledOnce, true); + strictEqual(testFnThree.calledOnce, false); }); it('will throw an exception if any values are not functions', () => { @@ -100,11 +101,11 @@ describe('Transaction', function() { Transaction.flow(suite, [testFnOne, testFnTwo]); - equal(testFnOne.calledOnce, true); - equal(testFnOne.calledWith(this), true); + strictEqual(testFnOne.calledOnce, true); + strictEqual(testFnOne.calledWith(this), true); - equal(testFnTwo.calledOnce, true); - equal(testFnTwo.calledWith(this), true); + strictEqual(testFnTwo.calledOnce, true); + strictEqual(testFnTwo.calledWith(this), true); }); it('will force abort the flow, the last task will still execute', () => { @@ -112,15 +113,15 @@ describe('Transaction', function() { const testFnTwo = spy(); const testFnThree = spy(); - const transaction = Transaction.create(suite.domNode, null, { + const transaction = Transaction.create(suite.mount, null, { tasks: [testFnOne, testFnTwo, testFnThree], }); transaction.start(); - equal(testFnTwo.called, false); - equal(testFnThree.calledOnce, true); - equal(testFnThree.calledWith(transaction), true); + strictEqual(testFnTwo.called, false); + strictEqual(testFnThree.calledOnce, true); + strictEqual(testFnThree.calledWith(transaction), true); }); it('will silently abort the flow', () => { @@ -128,27 +129,27 @@ describe('Transaction', function() { const testFnTwo = spy(); const testFnThree = spy(); - const transaction = Transaction.create(suite.domNode, null, { + const transaction = Transaction.create(suite.mount, null, { tasks: [testFnOne, testFnTwo, testFnThree], }); transaction.start(); - equal(testFnTwo.called, false); - equal(testFnThree.calledOnce, false); - equal(testFnThree.calledWith(transaction), false); + strictEqual(testFnTwo.called, false); + strictEqual(testFnThree.calledOnce, false); + strictEqual(testFnThree.calledWith(transaction), false); }); }); describe('assert', () => { it('will not error if not aborted or completd', () => { - const { domNode, input } = suite; + const { mount, input } = suite; const tasks = [ transaction => transaction.abort(), spy(), ]; - const transaction = Transaction.create(domNode, input, { tasks }); + const transaction = Transaction.create(mount, input, { tasks }); transaction.aborted = false; transaction.completed = false; doesNotThrow(() => transaction.start()); @@ -156,26 +157,26 @@ describe('Transaction', function() { }); it('will error if a transaction has been aborted', () => { - const { domNode, input } = suite; + const { mount, input } = suite; const tasks = [ transaction => transaction.abort(), spy(), ]; - const transaction = Transaction.create(domNode, input, { tasks }); + const transaction = Transaction.create(mount, input, { tasks }); transaction.aborted = true; transaction.completed = true; throws(() => transaction.start()); }); it('will error if a transaction has been completed', () => { - const { domNode, input } = suite; + const { mount, input } = suite; const tasks = [ transaction => transaction.abort(), spy(), ]; - const transaction = Transaction.create(domNode, input, { tasks }); + const transaction = Transaction.create(mount, input, { tasks }); transaction.aborted = false; transaction.completed = true; throws(() => transaction.start()); @@ -184,8 +185,8 @@ describe('Transaction', function() { describe('invokeMiddleware', () => { it('will not modify the task flow if not provided a function', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); /** @type {unknown} */ const middleware = spy(); @@ -193,13 +194,13 @@ describe('Transaction', function() { Transaction.invokeMiddleware(transaction); - equal(transaction.tasks.length, 1); + strictEqual(transaction.tasks.length, 1); unsubscribe(); }); it('will modify the task flow if provided a function', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); const task = spy(); @@ -209,7 +210,7 @@ describe('Transaction', function() { Transaction.invokeMiddleware(transaction); - equal(transaction.tasks.length, 2); + strictEqual(transaction.tasks.length, 2); unsubscribe(); }); }); @@ -217,10 +218,10 @@ describe('Transaction', function() { describe('start', () => { it('will not error in production if trying to start a transaction without a dom node', () => { process.env.NODE_ENV = 'production'; - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); - transaction.domNode = null; + transaction.mount = null; doesNotThrow(() => { transaction.start(); @@ -228,20 +229,20 @@ describe('Transaction', function() { }); it('will error in development if trying to start a transaction without a dom node', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); - transaction.domNode = null; + transaction.mount = null; throws(() => { transaction.start(); }, / /); }); it('will error in development if trying to start a transaction without a dom node', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); - transaction.domNode = null; + transaction.mount = null; throws(() => { transaction.start(); @@ -249,19 +250,19 @@ describe('Transaction', function() { }); it('will start a transaction', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); transaction.start(); const firstTask = /** @type {SinonSpy} */ (transaction.tasks[0]); - equal(firstTask.calledOnce, true); + strictEqual(firstTask.calledOnce, true); }); it('will start a transaction with middleware', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); const task = spy(); @@ -271,97 +272,97 @@ describe('Transaction', function() { transaction.start(); - equal(transaction.tasks.length, 2); + strictEqual(transaction.tasks.length, 2); unsubscribe(); }); it('will get the return value from the flow', async () => { - const { domNode, input } = suite; + const { mount, input } = suite; const token = {}; const tasks = [() => token]; - const transaction = Transaction.create(domNode, input, { tasks }); + const transaction = Transaction.create(mount, input, { tasks }); const returnValue = await transaction.start(); - equal(returnValue, token); + strictEqual(returnValue, token); }); }); describe('abort', () => { it('will abort a transaction flow', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); transaction.start(); const returnValue = transaction.abort(); - equal(returnValue, undefined); - equal(transaction.aborted, true); + strictEqual(returnValue, undefined); + strictEqual(transaction.aborted, true); }); it('will return the last tasks return value', () => { - const { domNode, input } = suite; + const { mount, input } = suite; const token = {}; const tasks = [() => token]; - const transaction = Transaction.create(domNode, input, { tasks }); + const transaction = Transaction.create(mount, input, { tasks }); transaction.start(); const returnValue = transaction.abort(true); - equal(returnValue, token); - equal(transaction.aborted, true); + strictEqual(returnValue, token); + strictEqual(transaction.aborted, true); }); }); describe('end', () => { it('will mark the transaction as completed', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); transaction.end(); - equal(transaction.completed, true); + strictEqual(transaction.completed, true); }); it('will set the state', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); transaction.end(); - equal(transaction.state.previousMarkup, '
'); + strictEqual(transaction.state.previousMarkup, '
'); }); it('will change isRendering', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); transaction.start(); - equal(transaction.state.isRendering, undefined); + strictEqual(transaction.state.isRendering, undefined); transaction.end(); - equal(transaction.state.isRendering, false); + strictEqual(transaction.state.isRendering, false); }); }); describe('onceEnded', () => { it('will register callbacks to run after ended', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); const fn = () => {}; transaction.onceEnded(fn); - equal(transaction.endedCallbacks.size, 1); + strictEqual(transaction.endedCallbacks.size, 1); }); it('will trigger onceEnded callbacks', () => { - const { domNode, input, options } = suite; - const transaction = Transaction.create(domNode, input, options); + const { mount, input, config } = suite; + const transaction = Transaction.create(mount, input, config); const fn = spy(); transaction.onceEnded(fn); transaction.end(); - equal(fn.calledOnce, true); + strictEqual(fn.calledOnce, true); }); }); }); diff --git a/packages/diffhtml/test/util.js b/packages/diffhtml/test/util.js index 52c6c20e..16ee7f24 100644 --- a/packages/diffhtml/test/util.js +++ b/packages/diffhtml/test/util.js @@ -1368,117 +1368,101 @@ describe('Util', function() { describe('Performance', () => { it(`will return a NOP when the user doesn't have search`, () => { - const div = document.createElement('div'); - const vTree = createTree(div); - const measure = makeMeasure(div, vTree); + const mount = document.createElement('div'); + const input = createTree(mount); + const measure = makeMeasure({ mount, input }); strictEqual(measure.name, 'nop'); }); it(`will return a NOP when the user has search, but no diff`, () => { - const div = document.createElement('div'); - const vTree = createTree(div); + const mount = document.createElement('div'); + const input = createTree(mount); location.href = 'about:blank?'; - const measure = makeMeasure(div, vTree); + const measure = makeMeasure({ mount, input }); strictEqual(measure.name, 'nop'); }); it('will return a real measure function if requested', () => { - const div = document.createElement('div'); - const vTree = createTree(div); + const mount = document.createElement('div'); + const input = createTree(mount); location.href = 'about:blank?diff_collectmetrics'; - const measure = makeMeasure(div, vTree); + const measure = makeMeasure({ mount, input }); strictEqual(measure.name, ''); strictEqual(measure.length, 1); }); it('will use performance.mark on the first call', () => { - const div = document.createElement('div'); - const vTree = createTree(div); + const mount = document.createElement('div'); + const input = createTree(mount); location.href = 'about:blank?diff_collectmetrics'; - const measure = makeMeasure(div, vTree); + const measure = makeMeasure({ mount, input }); measure('test-1'); strictEqual(performance.mark.calledOnce, true); - deepStrictEqual(performance.mark.firstCall.args, ['test-1']); + ok(performance.mark.firstCall.args[0].match(/\[\d+\] test-1/)); }); it('will use performance.measure on the second call', () => { - const div = document.createElement('div'); - const vTree = createTree(div); + const mount = document.createElement('div'); + const input = createTree(mount); location.href = 'about:blank?diff_collectmetrics'; - const measure = makeMeasure(div, vTree); + const measure = makeMeasure({ mount, input }); measure('test-2'); measure('test-2'); strictEqual(performance.measure.callCount, 1); - deepStrictEqual(performance.mark.firstCall.args, ['test-2']); - deepStrictEqual(performance.mark.lastCall.args, ['test-2-end']); - deepStrictEqual(performance.measure.firstCall.args.slice(1), [ - 'test-2', - 'test-2-end', - ]); - - const regex = /diffHTML test-2 \((.*)ms\)/; + ok(performance.mark.firstCall.args[0].match(/\[\d+\] test-2/)); + ok(performance.mark.lastCall.args[0].match(/\[\d+\] test-2-end/)); + + const regex = /diffHTML \[\d+\] test-2 \((.*)ms\)/; ok(regex.exec(performance.measure.firstCall.args[0])); }); it('will log out web component names', () => { - const div = document.createElement('div'); - /** @type {any} */ (div).host = { constructor: { name: 'Component' } }; - const vTree = createTree(div); + const mount = document.createElement('div'); + /** @type {any} */ (mount).host = { constructor: { name: 'Component' } }; + const input = createTree(mount); location.href = 'about:blank?diff_collectmetrics'; - const measure = makeMeasure(div, vTree); + const measure = makeMeasure({ mount, input }); measure('test-3'); measure('test-3'); strictEqual(performance.measure.callCount, 1); - deepStrictEqual(performance.mark.firstCall.args, ['Component test-3']); - deepStrictEqual(performance.mark.lastCall.args, ['Component test-3-end']); - deepStrictEqual(performance.measure.firstCall.args.slice(1), [ - 'Component test-3', - 'Component test-3-end', - ]); - - const regex = /diffHTML Component test-3 \((.*)ms\)/; + + const regex = /diffHTML Component \[\d+\] test-3 \((.*)ms\)/; ok(regex.exec(performance.measure.firstCall.args[0])); }); it('will log out tagName component names', () => { class Component {} - const div = document.createElement('div'); - const vTree = createTree(Component); + const mount = document.createElement('div'); + const input = createTree(Component); location.href = 'about:blank?diff_collectmetrics'; - const measure = makeMeasure(div, vTree); + const measure = makeMeasure({ mount, input }); measure('test-4'); measure('test-4'); strictEqual(performance.measure.callCount, 1); - deepStrictEqual(performance.mark.firstCall.args, ['Component test-4']); - deepStrictEqual(performance.mark.lastCall.args, ['Component test-4-end']); - deepStrictEqual(performance.measure.firstCall.args.slice(1), [ - 'Component test-4', - 'Component test-4-end', - ]); - - const regex = /diffHTML Component test-4 \((.*)ms\)/; + + const regex = /diffHTML Component \[\d+\] test-4 \((.*)ms\)/; ok(regex.exec(performance.measure.firstCall.args[0])); }); });