提交 8cf8b523 编写于 作者: J Joao Moreno

💄 refactor AsyncDataTree tests

上级 27f011cb
......@@ -27,30 +27,43 @@ function find(elements: Element[] | undefined, id: string): Element {
throw new Error('element not found');
}
class Renderer implements ITreeRenderer<Element, void, HTMLElement> {
readonly templateId = 'default';
renderTemplate(container: HTMLElement): HTMLElement {
return container;
}
renderElement(element: ITreeNode<Element, void>, index: number, templateData: HTMLElement): void {
templateData.textContent = element.element.id;
}
disposeTemplate(templateData: HTMLElement): void {
// noop
}
}
class IdentityProvider implements IIdentityProvider<Element> {
getId(element: Element) {
return element.id;
}
}
class VirtualDelegate implements IListVirtualDelegate<Element> {
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<Element> {
getHeight() { return 20; }
getTemplateId(element: Element): string { return 'default'; }
};
const renderer = new class implements ITreeRenderer<Element, void, HTMLElement> {
readonly templateId = 'default';
renderTemplate(container: HTMLElement): HTMLElement {
return container;
}
renderElement(element: ITreeNode<Element, void>, index: number, templateData: HTMLElement): void {
templateData.textContent = element.element.id;
}
disposeTemplate(templateData: HTMLElement): void {
// noop
}
};
const dataSource = new class implements IAsyncDataSource<Element, Element> {
hasChildren(element: Element): boolean {
......@@ -61,70 +74,42 @@ suite('AsyncDataTree', function () {
}
};
const identityProvider = new class implements IIdentityProvider<Element> {
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<Element, Element>('test', container, delegate, [renderer], dataSource, { identityProvider });
const tree = new AsyncDataTree<Element, Element>('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<Element> {
getHeight() { return 20; }
getTemplateId(element: Element): string { return 'default'; }
};
const renderer = new class implements ITreeRenderer<Element, void, HTMLElement> {
readonly templateId = 'default';
renderTemplate(container: HTMLElement): HTMLElement {
return container;
}
renderElement(element: ITreeNode<Element, void>, index: number, templateData: HTMLElement): void {
templateData.textContent = element.element.id;
}
disposeTemplate(templateData: HTMLElement): void {
// noop
}
};
const getChildrenCalls: string[] = [];
const dataSource = new class implements IAsyncDataSource<Element, Element> {
......@@ -137,25 +122,17 @@ suite('AsyncDataTree', function () {
}
};
const identityProvider = new class implements IIdentityProvider<Element> {
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<Element, Element>('test', container, delegate, [renderer], dataSource, { identityProvider });
const tree = new AsyncDataTree<Element, Element>('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<Element> {
getHeight() { return 20; }
getTemplateId(element: Element): string { return 'default'; }
};
const renderer = new class implements ITreeRenderer<Element, void, HTMLElement> {
readonly templateId = 'default';
renderTemplate(container: HTMLElement): HTMLElement {
return container;
}
renderElement(element: ITreeNode<Element, void>, index: number, templateData: HTMLElement): void {
templateData.textContent = element.element.id;
}
disposeTemplate(templateData: HTMLElement): void {
// noop
}
};
const getChildrenCalls: string[] = [];
const dataSource = new class implements IAsyncDataSource<Element, Element> {
......@@ -225,63 +182,35 @@ suite('AsyncDataTree', function () {
}
};
const identityProvider = new class implements IIdentityProvider<Element> {
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<Element, Element>('test', container, delegate, [renderer], dataSource, { identityProvider });
const tree = new AsyncDataTree<Element, Element>('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<Element> {
getHeight() { return 20; }
getTemplateId(element: Element): string { return 'default'; }
};
const renderer = new class implements ITreeRenderer<Element, void, HTMLElement> {
readonly templateId = 'default';
renderTemplate(container: HTMLElement): HTMLElement {
return container;
}
renderElement(element: ITreeNode<Element, void>, index: number, templateData: HTMLElement): void {
templateData.textContent = element.element.id;
}
disposeTemplate(templateData: HTMLElement): void {
// noop
}
};
const dataSource = new class implements IAsyncDataSource<Element, Element> {
hasChildren(element: Element): boolean {
......@@ -292,64 +221,36 @@ suite('AsyncDataTree', function () {
}
};
const identityProvider = new class implements IIdentityProvider<Element> {
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<Element, Element>('test', container, delegate, [renderer], dataSource, { identityProvider });
const tree = new AsyncDataTree<Element, Element>('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<Element> {
getHeight() { return 20; }
getTemplateId(element: Element): string { return 'default'; }
};
const renderer = new class implements ITreeRenderer<Element, void, HTMLElement> {
readonly templateId = 'default';
renderTemplate(container: HTMLElement): HTMLElement {
return container;
}
renderElement(element: ITreeNode<Element, void>, index: number, templateData: HTMLElement): void {
templateData.textContent = element.element.id;
}
disposeTemplate(templateData: HTMLElement): void {
// noop
}
};
const getChildrenCalls: string[] = [];
const dataSource = new class implements IAsyncDataSource<Element, Element> {
......@@ -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<Element, Element>('test', container, delegate, [renderer], dataSource, {
const tree = new AsyncDataTree<Element, Element>('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<Element> {
getHeight() { return 20; }
getTemplateId(element: Element): string { return 'default'; }
};
const renderer = new class implements ITreeRenderer<Element, void, HTMLElement> {
readonly templateId = 'default';
renderTemplate(container: HTMLElement): HTMLElement {
return container;
}
renderElement(element: ITreeNode<Element, void>, index: number, templateData: HTMLElement): void {
templateData.textContent = element.element.id;
}
disposeTemplate(templateData: HTMLElement): void {
// noop
}
};
const calls: Function[] = [];
const dataSource = new class implements IAsyncDataSource<Element, Element> {
......@@ -414,32 +293,24 @@ suite('AsyncDataTree', function () {
}
};
const identityProvider = new class implements IIdentityProvider<Element> {
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<Element, Element>('test', container, delegate, [renderer], dataSource, { identityProvider });
const tree = new AsyncDataTree<Element, Element>('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<Element> {
getHeight() { return 20; }
getTemplateId(element: Element): string { return 'default'; }
};
const renderer = new class implements ITreeRenderer<Element, void, HTMLElement> {
readonly templateId = 'default';
renderTemplate(container: HTMLElement): HTMLElement {
return container;
}
renderElement(element: ITreeNode<Element, void>, index: number, templateData: HTMLElement): void {
templateData.textContent = element.element.id;
}
disposeTemplate(templateData: HTMLElement): void {
// noop
}
};
const calls: Function[] = [];
const dataSource = new class implements IAsyncDataSource<Element, Element> {
......@@ -485,31 +336,23 @@ suite('AsyncDataTree', function () {
}
};
const identityProvider = new class implements IIdentityProvider<Element> {
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<Element, Element>('test', container, delegate, [renderer], dataSource, { identityProvider });
const tree = new AsyncDataTree<Element, Element>('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')]);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册