UNPKG

chrome-devtools-frontend

Version:
274 lines (244 loc) • 8.81 kB
// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import {html, render} from '../ui/lit/lit.js'; import {renderElementIntoDOM} from './DOMHelpers.js'; import {TEXT_NODE, withMutations, withNoMutations} from './MutationHelpers.js'; /** * Needed because assert.throws from chai does not work async. */ async function assertThrowsAsync(fn: () => Promise<void>, errorMessage: string) { let caught = false; try { await fn(); } catch (e) { caught = true; assert.strictEqual(e.message, errorMessage); } if (!caught) { assert.fail('Expected error but got none.'); } } async function assertNotThrowsAsync(fn: () => Promise<void>) { let errorMessage = ''; try { await fn(); } catch (e) { errorMessage = e.message; } if (errorMessage) { assert.fail(`Expected no error but got:\n${errorMessage}`); } } describe('MutationHelpers', () => { describe('withMutations', () => { it('fails if there are no mutations', async () => { const div = document.createElement('div'); await assertThrowsAsync(async () => { await withMutations( [{ target: 'div', }], div, () => {}); }, 'Expected at least one mutation for ADD/REMOVE div, but got 0'); }); it('allows up to 10 mutations unless specified', async () => { const div = document.createElement('div'); renderElementIntoDOM(div); await assertNotThrowsAsync(async () => { await withMutations( [{ target: 'div', }], div, () => { for (let i = 0; i < 10; i++) { div.appendChild(document.createElement('div')); } }); }); }); it('errors if there are >10 mutations', async () => { const div = document.createElement('div'); renderElementIntoDOM(div); await assertThrowsAsync(async () => { await withMutations( [{ target: 'div', }], div, () => { for (let i = 0; i < 11; i++) { div.appendChild(document.createElement('div')); } }); }, 'Expected no more than 10 mutations for ADD/REMOVE div, but got 11'); }); it('lets the user provide the max', async () => { const div = document.createElement('div'); renderElementIntoDOM(div); await assertThrowsAsync(async () => { await withMutations( [{ target: 'div', max: 5, }], div, () => { for (let i = 0; i < 6; i++) { div.appendChild(document.createElement('div')); } }); }, 'Expected no more than 5 mutations for ADD/REMOVE div, but got 6'); }); it('supports a max of 0', async () => { const div = document.createElement('div'); renderElementIntoDOM(div); await assertThrowsAsync(async () => { await withMutations( [{ target: 'div', max: 0, }], div, () => { div.appendChild(document.createElement('div')); }); }, 'Expected no more than 0 mutations for ADD/REMOVE div, but got 1'); }); it('supports checking multiple expected mutations', async () => { const div = document.createElement('div'); renderElementIntoDOM(div); await assertThrowsAsync(async () => { await withMutations( [ { target: 'div', max: 1, }, {target: 'span', max: 0}, ], div, () => { div.appendChild(document.createElement('div')); div.appendChild(document.createElement('span')); }); }, 'Expected no more than 0 mutations for ADD/REMOVE span, but got 1'); }); it('errors if other unexpected mutations occur', async () => { const div = document.createElement('div'); renderElementIntoDOM(div); await assertThrowsAsync(async () => { await withMutations( [{ target: 'div', max: 1, }], div, () => { // this is OK as we are expecting one div mutation div.appendChild(document.createElement('div')); // not OK - we have not declared any span mutations div.appendChild(document.createElement('span')); }); }, 'Additional unexpected mutations were detected:\nspan: 1 addition'); }); it('lets you declare any expected text updates', async () => { const div = document.createElement('div'); const renderList = (list: string[]) => { render(html`${list.map(l => html`<span>${l}</span>`)}`, div, {host: this}); }; renderElementIntoDOM(div); renderList(['a', 'b']); await assertNotThrowsAsync(async () => { await withMutations( [ { target: 'div', }, {target: TEXT_NODE}, ], div, div => { renderList(['b', 'a']); div.appendChild(document.createElement('div')); }); }); }); it('fails if there are undeclared text updates', async () => { const div = document.createElement('div'); const renderList = (list: string[]) => { render(html`${list.map(l => html`<span>${l}</span>`)}`, div, {host: this}); }; renderElementIntoDOM(div); renderList(['a', 'b']); await assertThrowsAsync(async () => { await withMutations( [{ target: 'div', }], div, div => { renderList(['b', 'a']); div.appendChild(document.createElement('div')); }); }, 'Additional unexpected mutations were detected:\nTEXT_NODE: 2 updates'); }); }); describe('withNoMutations', () => { it('fails if there are DOM additions', async () => { const div = document.createElement('div'); renderElementIntoDOM(div); await assertThrowsAsync(async () => { await withNoMutations(div, element => { const child = document.createElement('span'); element.appendChild(child); }); }, 'Expected no mutations, but got 1: \nspan: 1 addition'); }); it('fails if there are DOM removals', async () => { const div = document.createElement('div'); const child = document.createElement('span'); div.appendChild(child); renderElementIntoDOM(div); await assertThrowsAsync(async () => { await withNoMutations(div, element => { element.removeChild(child); }); }, 'Expected no mutations, but got 1: \nspan: 1 removal'); }); it('correctly displays multiple unexpected mutations', async () => { const div = document.createElement('div'); renderElementIntoDOM(div); await assertThrowsAsync(async () => { await withNoMutations(div, element => { const child = document.createElement('span'); element.appendChild(child); element.removeChild(child); element.appendChild(document.createElement('p')); element.appendChild(document.createElement('p')); element.appendChild(document.createElement('p')); }); }, 'Expected no mutations, but got 5: \nspan: 1 addition, 1 removal\np: 3 additions'); }); it('fails if there are text re-orderings', async () => { const div = document.createElement('div'); const renderList = (list: string[]) => { render(html`${list.map(l => html`<span>${l}</span>`)}`, div, {host: this}); }; renderElementIntoDOM(div); renderList(['a', 'b']); await assertThrowsAsync(async () => { await withNoMutations(div, () => { renderList(['b', 'a']); }); }, 'Expected no mutations, but got 2: \nTEXT_NODE: 2 updates'); }); it('fails if there are text re-orderings and DOM additions', async () => { const div = document.createElement('div'); const renderList = (list: string[]) => { render(html`${list.map(l => html`<span>${l}</span>`)}`, div, {host: this}); }; renderElementIntoDOM(div); renderList(['a', 'b']); await assertThrowsAsync(async () => { await withNoMutations(div, div => { renderList(['b', 'a']); div.appendChild(document.createElement('ul')); }); }, 'Expected no mutations, but got 3: \nTEXT_NODE: 2 updates\nul: 1 addition'); }); }); });