Skip to content

Commit 32a1bbd

Browse files
committed
Add tests for the interpreter completion candidate flag
1 parent f4826e5 commit 32a1bbd

1 file changed

Lines changed: 147 additions & 0 deletions

File tree

zeppelin-web/src/app/notebook/paragraph/paragraph.controller.test.js

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ describe('Controller: ParagraphCtrl', function() {
22
beforeEach(angular.mock.module('zeppelinWebApp'));
33

44
let scope;
5+
let rootScope;
56
let websocketMsgSrvMock = {};
67
let paragraphMock = {
78
config: {},
@@ -19,6 +20,7 @@ describe('Controller: ParagraphCtrl', function() {
1920

2021
beforeEach(inject(function($controller, $rootScope) {
2122
scope = $rootScope.$new();
23+
rootScope = $rootScope;
2224
$rootScope.notebookScope = $rootScope.$new(true, $rootScope);
2325

2426
$controller('ParagraphCtrl', {
@@ -50,4 +52,149 @@ describe('Controller: ParagraphCtrl', function() {
5052
it('should set default value of "paragraphFocused" as false', function() {
5153
expect(scope.paragraphFocused).toEqual(false);
5254
});
55+
56+
describe('completion candidate filtering', function() {
57+
let FilteredList;
58+
let originalSetFilter;
59+
60+
let completionParagraph = {
61+
id: 'paragraph_completion',
62+
config: {
63+
editorSetting: {
64+
completionSupport: true,
65+
},
66+
},
67+
settings: {
68+
forms: {},
69+
},
70+
};
71+
72+
let fromInterpreter = function(value, meta) {
73+
return {value: value, caption: value, meta: meta, score: 300, fromBackend: true};
74+
};
75+
76+
let fromAce = function(value, meta) {
77+
return {value: value, caption: value, meta: meta, score: 0};
78+
};
79+
80+
// the filter lives on ace's FilteredList prototype, installed on focus
81+
let applyFilter = function(candidates) {
82+
let list = new FilteredList(candidates);
83+
list.setFilter('');
84+
return list.filtered;
85+
};
86+
87+
beforeEach(function() {
88+
FilteredList = ace.require('ace/autocomplete').FilteredList;
89+
originalSetFilter = FilteredList.prototype.setFilter;
90+
scope.init(completionParagraph);
91+
rootScope.$broadcast('focusParagraph', completionParagraph.id, 0, 0, true);
92+
});
93+
94+
afterEach(function() {
95+
FilteredList.prototype.setFilter = originalSetFilter;
96+
});
97+
98+
it('should keep interpreter candidates that carry a meta label', function() {
99+
let table = fromInterpreter('my_table', 'table');
100+
expect(applyFilter([table])).toContain(table);
101+
});
102+
103+
it('should hide ace candidates while interpreter candidates are available', function() {
104+
let table = fromInterpreter('my_table', 'table');
105+
let local = fromAce('my_local_var', 'local');
106+
let keyword = fromAce('select', 'keyword');
107+
108+
let filtered = applyFilter([table, local, keyword]);
109+
110+
expect(filtered).toContain(table);
111+
expect(filtered).not.toContain(local);
112+
expect(filtered).not.toContain(keyword);
113+
});
114+
115+
describe('when the interpreter answers with no candidates', function() {
116+
let editorElement;
117+
118+
// completionListLength is only settable through a listener aceLoaded registers
119+
beforeEach(function() {
120+
websocketMsgSrvMock.getEditorSetting = function() {};
121+
websocketMsgSrvMock.completion = function() {};
122+
123+
editorElement = document.createElement('div');
124+
editorElement.id = 'completion_test_editor';
125+
document.body.appendChild(editorElement);
126+
127+
scope.aceLoaded(ace.edit(editorElement));
128+
rootScope.$broadcast('completionListLength', 0);
129+
});
130+
131+
afterEach(function() {
132+
document.body.removeChild(editorElement);
133+
});
134+
135+
it('should fall back to ace candidates', function() {
136+
let local = fromAce('my_local_var', 'local');
137+
let keyword = fromAce('select', 'keyword');
138+
139+
let filtered = applyFilter([local, keyword]);
140+
141+
expect(filtered).toContain(local);
142+
expect(filtered).toContain(keyword);
143+
});
144+
});
145+
146+
describe('candidates built from an interpreter answer', function() {
147+
let editorElement;
148+
let editor;
149+
150+
beforeEach(function() {
151+
websocketMsgSrvMock.getEditorSetting = function() {};
152+
websocketMsgSrvMock.completion = function() {};
153+
154+
editorElement = document.createElement('div');
155+
editorElement.id = 'completion_producer_editor';
156+
document.body.appendChild(editorElement);
157+
158+
editor = ace.edit(editorElement);
159+
scope.aceLoaded(editor);
160+
editor.focus();
161+
});
162+
163+
afterEach(function() {
164+
document.body.removeChild(editorElement);
165+
});
166+
167+
// aceLoaded installs remoteCompleter as the first of ace's completers.
168+
let collectCandidates = function(completions) {
169+
let remoteCompleter = editor.completers[0];
170+
let received = null;
171+
172+
remoteCompleter.getCompletions(editor, editor.getSession(), {row: 0, column: 0}, '', function(err, items) {
173+
received = items;
174+
});
175+
rootScope.$broadcast('completionList', {completions: completions});
176+
177+
return received;
178+
};
179+
180+
it('should mark every candidate as coming from the interpreter', function() {
181+
let candidates = collectCandidates([
182+
{name: 'my_table', value: 'my_table', meta: 'table'},
183+
{name: 'my_schema', value: 'my_schema', meta: 'schema'},
184+
]);
185+
186+
expect(candidates).not.toBeNull();
187+
expect(candidates.length).toEqual(2);
188+
candidates.forEach(function(candidate) {
189+
expect(candidate.fromBackend).toBe(true);
190+
});
191+
});
192+
193+
it('should produce candidates that survive the filter', function() {
194+
let candidates = collectCandidates([{name: 'my_table', value: 'my_table', meta: 'table'}]);
195+
196+
expect(applyFilter(candidates)).toEqual(candidates);
197+
});
198+
});
199+
});
53200
});

0 commit comments

Comments
 (0)