From 8cf8b523b9bb2be41c045ad3711b6fb0db2ea118 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 5 Sep 2019 17:46:25 +0200 Subject: [PATCH] :lipstick: refactor AsyncDataTree tests --- .../browser/ui/tree/asyncDataTree.test.ts | 333 +++++------------- 1 file changed, 88 insertions(+), 245 deletions(-) diff --git a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts index 0c7d67a253a..f57c017c0af 100644 --- a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts +++ b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts @@ -27,30 +27,43 @@ function find(elements: Element[] | undefined, id: string): Element { throw new Error('element not found'); } +class Renderer implements ITreeRenderer { + readonly templateId = 'default'; + renderTemplate(container: HTMLElement): HTMLElement { + return container; + } + renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { + templateData.textContent = element.element.id; + } + disposeTemplate(templateData: HTMLElement): void { + // noop + } +} + +class IdentityProvider implements IIdentityProvider { + getId(element: Element) { + return element.id; + } +} + +class VirtualDelegate implements IListVirtualDelegate { + getHeight() { return 20; } + getTemplateId(element: Element): string { return 'default'; } +} + +class Model { + + constructor(readonly root: Element) { } + + get(id: string): Element { + return find(this.root.children, id); + } +} + suite('AsyncDataTree', function () { test('Collapse state should be preserved across refresh calls', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const dataSource = new class implements IAsyncDataSource { hasChildren(element: Element): boolean { @@ -61,70 +74,42 @@ suite('AsyncDataTree', function () { } }; - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a' }] - }; - - const _: (id: string) => Element = find.bind(null, root.children); + }); - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); assert.equal(container.querySelectorAll('.monaco-list-row').length, 0); - await tree.setInput(root); + await tree.setInput(model.root); assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; assert(!hasClass(twistie, 'collapsible')); assert(!hasClass(twistie, 'collapsed')); - _('a').children = [ + model.get('a').children = [ { id: 'aa' }, { id: 'ab' }, { id: 'ac' } ]; - await tree.updateChildren(root); + await tree.updateChildren(model.root); assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); - await tree.expand(_('a')); + await tree.expand(model.get('a')); assert.equal(container.querySelectorAll('.monaco-list-row').length, 4); - _('a').children = []; - await tree.updateChildren(root); + model.get('a').children = []; + await tree.updateChildren(model.root); assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); }); test('issue #68648', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const getChildrenCalls: string[] = []; const dataSource = new class implements IAsyncDataSource { @@ -137,25 +122,17 @@ suite('AsyncDataTree', function () { } }; - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a' }] - }; - - const _: (id: string) => Element = find.bind(null, root.children); + }); - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); - await tree.setInput(root); + await tree.setInput(model.root); assert.deepStrictEqual(getChildrenCalls, ['root']); let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -163,8 +140,8 @@ suite('AsyncDataTree', function () { assert(!hasClass(twistie, 'collapsed')); assert(tree.getNode().children[0].collapsed); - _('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; - await tree.updateChildren(root); + model.get('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; + await tree.updateChildren(model.root); assert.deepStrictEqual(getChildrenCalls, ['root', 'root']); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -172,8 +149,8 @@ suite('AsyncDataTree', function () { assert(hasClass(twistie, 'collapsed')); assert(tree.getNode().children[0].collapsed); - _('a').children = []; - await tree.updateChildren(root); + model.get('a').children = []; + await tree.updateChildren(model.root); assert.deepStrictEqual(getChildrenCalls, ['root', 'root', 'root']); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -181,8 +158,8 @@ suite('AsyncDataTree', function () { assert(!hasClass(twistie, 'collapsed')); assert(tree.getNode().children[0].collapsed); - _('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; - await tree.updateChildren(root); + model.get('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; + await tree.updateChildren(model.root); assert.deepStrictEqual(getChildrenCalls, ['root', 'root', 'root', 'root']); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; @@ -193,26 +170,6 @@ suite('AsyncDataTree', function () { test('issue #67722 - once resolved, refreshed collapsed nodes should only get children when expanded', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const getChildrenCalls: string[] = []; const dataSource = new class implements IAsyncDataSource { @@ -225,63 +182,35 @@ suite('AsyncDataTree', function () { } }; - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }] }] - }; - - const _: (id: string) => Element = find.bind(null, root.children); + }); - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); - await tree.setInput(root); - assert(tree.getNode(_('a')).collapsed); + await tree.setInput(model.root); + assert(tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root']); - await tree.expand(_('a')); - assert(!tree.getNode(_('a')).collapsed); + await tree.expand(model.get('a')); + assert(!tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a']); - tree.collapse(_('a')); - assert(tree.getNode(_('a')).collapsed); + tree.collapse(model.get('a')); + assert(tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a']); await tree.updateChildren(); - assert(tree.getNode(_('a')).collapsed); + assert(tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a', 'root'], 'a should not be refreshed, since it\' collapsed'); }); test('resolved collapsed nodes which lose children should lose twistie as well', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const dataSource = new class implements IAsyncDataSource { hasChildren(element: Element): boolean { @@ -292,64 +221,36 @@ suite('AsyncDataTree', function () { } }; - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }] }] - }; - - const _: (id: string) => Element = find.bind(null, root.children); + }); - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); - await tree.setInput(root); - await tree.expand(_('a')); + await tree.setInput(model.root); + await tree.expand(model.get('a')); let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; assert(hasClass(twistie, 'collapsible')); assert(!hasClass(twistie, 'collapsed')); - assert(!tree.getNode(_('a')).collapsed); + assert(!tree.getNode(model.get('a')).collapsed); - tree.collapse(_('a')); - _('a').children = []; - await tree.updateChildren(root); + tree.collapse(model.get('a')); + model.get('a').children = []; + await tree.updateChildren(model.root); twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; assert(!hasClass(twistie, 'collapsible')); assert(!hasClass(twistie, 'collapsed')); - assert(tree.getNode(_('a')).collapsed); + assert(tree.getNode(model.get('a')).collapsed); }); test('support default collapse state per element', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const getChildrenCalls: string[] = []; const dataSource = new class implements IAsyncDataSource { @@ -362,47 +263,25 @@ suite('AsyncDataTree', function () { } }; - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }] }] - }; - - const _: (id: string) => Element = find.bind(null, root.children); + }); - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { collapseByDefault: el => el.id !== 'a' }); tree.layout(200); - await tree.setInput(root); - assert(!tree.getNode(_('a')).collapsed); + await tree.setInput(model.root); + assert(!tree.getNode(model.get('a')).collapsed); assert.deepStrictEqual(getChildrenCalls, ['root', 'a']); }); test('issue #80098 - concurrent refresh and expand', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const calls: Function[] = []; const dataSource = new class implements IAsyncDataSource { @@ -414,32 +293,24 @@ suite('AsyncDataTree', function () { } }; - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }] }] - }; - - const _: (id: string) => Element = find.bind(null, root.children); + }); - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); - const pSetInput = tree.setInput(root); + const pSetInput = tree.setInput(model.root); calls.pop()!(); // resolve getChildren(root) await pSetInput; - const pUpdateChildrenA = tree.updateChildren(_('a')); - const pExpandA = tree.expand(_('a')); + const pUpdateChildrenA = tree.updateChildren(model.get('a')); + const pExpandA = tree.expand(model.get('a')); assert.equal(calls.length, 1, 'expand(a) still hasn\'t called getChildren(a)'); calls.pop()!(); @@ -454,26 +325,6 @@ suite('AsyncDataTree', function () { test('issue #80098 - first expand should call getChildren', async () => { const container = document.createElement('div'); - container.style.width = '200px'; - container.style.height = '200px'; - - const delegate = new class implements IListVirtualDelegate { - getHeight() { return 20; } - getTemplateId(element: Element): string { return 'default'; } - }; - - const renderer = new class implements ITreeRenderer { - readonly templateId = 'default'; - renderTemplate(container: HTMLElement): HTMLElement { - return container; - } - renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { - templateData.textContent = element.element.id; - } - disposeTemplate(templateData: HTMLElement): void { - // noop - } - }; const calls: Function[] = []; const dataSource = new class implements IAsyncDataSource { @@ -485,31 +336,23 @@ suite('AsyncDataTree', function () { } }; - const identityProvider = new class implements IIdentityProvider { - getId(element: Element) { - return element.id; - } - }; - - const root: Element = { + const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }] }] - }; - - const _: (id: string) => Element = find.bind(null, root.children); + }); - const tree = new AsyncDataTree('test', container, delegate, [renderer], dataSource, { identityProvider }); + const tree = new AsyncDataTree('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); - const pSetInput = tree.setInput(root); + const pSetInput = tree.setInput(model.root); calls.pop()!(); // resolve getChildren(root) await pSetInput; - const pExpandA = tree.expand(_('a')); + const pExpandA = tree.expand(model.get('a')); assert.equal(calls.length, 1, 'expand(a) should\'ve called getChildren(a)'); let race = await Promise.race([pExpandA.then(() => 'expand'), timeout(1).then(() => 'timeout')]); -- GitLab