GUI -- Removed onos-fixed-header redundancies, wrote unit tests for fixed-header…
… and sortable-header directives. Change-Id: Iccf9348a4697f494a4234b024781fede0719491d
Showing
3 changed files
with
148 additions
and
31 deletions
... | @@ -34,7 +34,7 @@ | ... | @@ -34,7 +34,7 @@ |
34 | 34 | ||
35 | tHeaders = t.selectAll('th'); | 35 | tHeaders = t.selectAll('th'); |
36 | numCols = tHeaders[0].length; | 36 | numCols = tHeaders[0].length; |
37 | - colWidth = Math.floor(winWidth/numCols); | 37 | + colWidth = Math.floor(winWidth / numCols); |
38 | 38 | ||
39 | tHeaders.each(function(thElement, index) { | 39 | tHeaders.each(function(thElement, index) { |
40 | thElement = d3.select(this); | 40 | thElement = d3.select(this); |
... | @@ -121,7 +121,9 @@ | ... | @@ -121,7 +121,9 @@ |
121 | fs = _fs_; | 121 | fs = _fs_; |
122 | var w = angular.element($window), | 122 | var w = angular.element($window), |
123 | table = d3.select(element[0]), | 123 | table = d3.select(element[0]), |
124 | - shouldResize = false; | 124 | + thead = table.select('thead'), |
125 | + tbody = table.select('tbody'), | ||
126 | + canAdjust = false; | ||
125 | 127 | ||
126 | scope.$watch(function () { | 128 | scope.$watch(function () { |
127 | return { | 129 | return { |
... | @@ -129,31 +131,24 @@ | ... | @@ -129,31 +131,24 @@ |
129 | w: window.innerWidth | 131 | w: window.innerWidth |
130 | }; | 132 | }; |
131 | }, function (newVal) { | 133 | }, function (newVal) { |
132 | - var thead = table.select('thead'), | ||
133 | - tbody = table.select('tbody'); | ||
134 | - | ||
135 | scope.windowHeight = newVal.h; | 134 | scope.windowHeight = newVal.h; |
136 | scope.windowWidth = newVal.w; | 135 | scope.windowWidth = newVal.w; |
137 | 136 | ||
138 | - scope.setTableHW = function () { | 137 | + scope.$on('LastElement', function () { |
139 | - scope.$on('LastElement', function (event) { | 138 | + // only adjust the table once it's completely loaded |
140 | - // only adjust the table once it's completely loaded | 139 | + fixTable(table, thead, tbody); |
141 | - fixTable(table, thead, tbody); | 140 | + canAdjust = true; |
142 | - shouldResize = true; | 141 | + }); |
143 | - }); | ||
144 | - }; | ||
145 | 142 | ||
146 | - if (shouldResize) { | 143 | + if (canAdjust) { |
147 | fixTable(table, thead, tbody); | 144 | fixTable(table, thead, tbody); |
148 | } | 145 | } |
149 | - | ||
150 | }, true); | 146 | }, true); |
151 | 147 | ||
152 | w.bind('onos-fixed-header', function () { | 148 | w.bind('onos-fixed-header', function () { |
153 | scope.$apply(); | 149 | scope.$apply(); |
154 | }); | 150 | }); |
155 | }; | 151 | }; |
156 | - | ||
157 | }]) | 152 | }]) |
158 | 153 | ||
159 | .directive('onosSortableHeader', ['$log', 'IconService', | 154 | .directive('onosSortableHeader', ['$log', 'IconService', | ... | ... |
... | @@ -3,7 +3,6 @@ | ... | @@ -3,7 +3,6 @@ |
3 | <h2>Devices ({{ctrl.deviceData.length}} total)</h2> | 3 | <h2>Devices ({{ctrl.deviceData.length}} total)</h2> |
4 | <table class="summary-list" | 4 | <table class="summary-list" |
5 | onos-fixed-header | 5 | onos-fixed-header |
6 | - ng-style="setTableHW()" | ||
7 | onos-sortable-header | 6 | onos-sortable-header |
8 | sort-callback="sortCallback(urlSuffix)"> | 7 | sort-callback="sortCallback(urlSuffix)"> |
9 | <thead> | 8 | <thead> | ... | ... |
... | @@ -20,11 +20,14 @@ | ... | @@ -20,11 +20,14 @@ |
20 | describe('factory: fw/widget/table.js', function () { | 20 | describe('factory: fw/widget/table.js', function () { |
21 | var $log, $compile, $rootScope, | 21 | var $log, $compile, $rootScope, |
22 | fs, is, | 22 | fs, is, |
23 | - table; | 23 | + scope, compiled, |
24 | + table, thead, tbody, | ||
25 | + tableIconTdSize = 33, | ||
26 | + bottomMargin = 200, | ||
27 | + numTestElems = 4; | ||
24 | 28 | ||
25 | var onosFixedHeaderTags = '<table ' + | 29 | var onosFixedHeaderTags = '<table ' + |
26 | - 'onos-fixed-header ' + | 30 | + 'onos-fixed-header>' + |
27 | - 'ng-style="setTableHW()">' + | ||
28 | '<thead>' + | 31 | '<thead>' + |
29 | '<tr>' + | 32 | '<tr>' + |
30 | '<th></th>' + | 33 | '<th></th>' + |
... | @@ -35,7 +38,7 @@ describe('factory: fw/widget/table.js', function () { | ... | @@ -35,7 +38,7 @@ describe('factory: fw/widget/table.js', function () { |
35 | '</thead>' + | 38 | '</thead>' + |
36 | '<tbody>' + | 39 | '<tbody>' + |
37 | '<tr>' + | 40 | '<tr>' + |
38 | - '<td>' + | 41 | + '<td class="table-icon">' + |
39 | '<div icon icon-id="{{dev._iconid_available}}">' + | 42 | '<div icon icon-id="{{dev._iconid_available}}">' + |
40 | '</div>' + | 43 | '</div>' + |
41 | '</td>' + | 44 | '</td>' + |
... | @@ -46,7 +49,7 @@ describe('factory: fw/widget/table.js', function () { | ... | @@ -46,7 +49,7 @@ describe('factory: fw/widget/table.js', function () { |
46 | '</tbody>' + | 49 | '</tbody>' + |
47 | '</table>', | 50 | '</table>', |
48 | 51 | ||
49 | - onosSortableHeaderTags = '<table class="summary-list" ' + | 52 | + onosSortableHeaderTags = '<table ' + |
50 | 'onos-sortable-header ' + | 53 | 'onos-sortable-header ' + |
51 | 'sort-callback="sortCallback(urlSuffix)">' + | 54 | 'sort-callback="sortCallback(urlSuffix)">' + |
52 | '<thead>' + | 55 | '<thead>' + |
... | @@ -82,29 +85,149 @@ describe('factory: fw/widget/table.js', function () { | ... | @@ -82,29 +85,149 @@ describe('factory: fw/widget/table.js', function () { |
82 | })); | 85 | })); |
83 | 86 | ||
84 | beforeEach(function () { | 87 | beforeEach(function () { |
88 | + scope = $rootScope.$new(); | ||
85 | }); | 89 | }); |
86 | 90 | ||
87 | afterEach(function () { | 91 | afterEach(function () { |
88 | table = null; | 92 | table = null; |
93 | + thead = null; | ||
94 | + tbody = null; | ||
89 | }); | 95 | }); |
90 | 96 | ||
91 | - it('should affirm that onos-fixed-header is working', function () { | 97 | + function compileTable() { |
92 | - table = $compile(onosFixedHeaderTags)($rootScope); | 98 | + compiled = $compile(table); |
93 | - $rootScope.$digest(); | 99 | + compiled(scope); |
100 | + scope.$digest(); | ||
101 | + } | ||
94 | 102 | ||
95 | - table = d3.select(table); | 103 | + function verifyGivenTags(dirName) { |
96 | expect(table).toBeDefined(); | 104 | expect(table).toBeDefined(); |
105 | + expect(table.attr(dirName)).toBe(''); | ||
106 | + | ||
107 | + thead = table.find('thead'); | ||
108 | + expect(thead).toBeDefined(); | ||
109 | + tbody = table.find('tbody'); | ||
110 | + expect(tbody).toBeDefined(); | ||
111 | + } | ||
112 | + | ||
113 | + function verifyCssDisplay() { | ||
114 | + var winHeight = fs.windowSize().height; | ||
115 | + | ||
116 | + expect(thead.css('display')).toBe('block'); | ||
117 | + expect(tbody.css('display')).toBe('block'); | ||
118 | + expect(tbody.css('height')).toBe((winHeight - bottomMargin) + 'px'); | ||
119 | + expect(tbody.css('overflow')).toBe('auto'); | ||
120 | + } | ||
121 | + | ||
122 | + function verifyColWidth() { | ||
123 | + var winWidth = fs.windowSize().width, | ||
124 | + colWidth, thElems, tdElem; | ||
125 | + | ||
126 | + colWidth = Math.floor(winWidth / numTestElems); | ||
127 | + | ||
128 | + thElems = thead.find('th'); | ||
129 | + | ||
130 | + angular.forEach(thElems, function (thElem, i) { | ||
131 | + thElem = angular.element(thElems[i]); | ||
132 | + tdElem = angular.element(tbody.find('td').eq(i)); | ||
133 | + | ||
134 | + if (tdElem.attr('class') === 'table-icon') { | ||
135 | + expect(thElem.css('width')).toBe(tableIconTdSize + 'px'); | ||
136 | + expect(tdElem.css('width')).toBe(tableIconTdSize + 'px'); | ||
137 | + } else { | ||
138 | + expect(thElem.css('width')).toBe(colWidth + 'px'); | ||
139 | + expect(tdElem.css('width')).toBe(colWidth + 'px'); | ||
140 | + } | ||
141 | + }); | ||
142 | + } | ||
143 | + | ||
144 | + function verifyCallbacks(thElems) { | ||
145 | + expect(scope.sortCallback).not.toHaveBeenCalled(); | ||
97 | 146 | ||
98 | - //expect(table.select('thead').style('display')).toBe('block'); | 147 | + // first test header has no 'sortable' attr |
148 | + thElems[0].click(); | ||
149 | + expect(scope.sortCallback).not.toHaveBeenCalled(); | ||
150 | + | ||
151 | + // the other headers have 'sortable' | ||
152 | + for(var i = 1; i < numTestElems; i += 1) { | ||
153 | + thElems[i].click(); | ||
154 | + expect(scope.sortCallback).toHaveBeenCalled(); | ||
155 | + } | ||
156 | + } | ||
157 | + | ||
158 | + function verifyIcons(thElems) { | ||
159 | + var currentTh, div; | ||
160 | + // make sure it has the correct icon after clicking | ||
161 | + thElems[1].click(); | ||
162 | + currentTh = angular.element(thElems[1]); | ||
163 | + div = currentTh.find('div'); | ||
164 | + expect(div.html()).toBe('<svg class="embeddedIcon" ' + | ||
165 | + 'width="10" height="10" viewBox="0 0 50 50">' + | ||
166 | + '<g class="icon tableColSortAsc">' + | ||
167 | + '<rect width="50" height="50" rx="5"></rect>' + | ||
168 | + '<use width="50" height="50" class="glyph" ' + | ||
169 | + 'xmlns:xlink="http://www.w3.org/1999/xlink" ' + | ||
170 | + 'xlink:href="#triangleUp">' + | ||
171 | + '</use>' + | ||
172 | + '</g></svg>'); | ||
173 | + thElems[1].click(); | ||
174 | + div = currentTh.find('div'); | ||
175 | + expect(div.html()).toBe('<svg class="embeddedIcon" ' + | ||
176 | + 'width="10" height="10" viewBox="0 0 50 50">' + | ||
177 | + '<g class="icon tableColSortDesc">' + | ||
178 | + '<rect width="50" height="50" rx="5"></rect>' + | ||
179 | + '<use width="50" height="50" class="glyph" ' + | ||
180 | + 'xmlns:xlink="http://www.w3.org/1999/xlink" ' + | ||
181 | + 'xlink:href="#triangleDown">' + | ||
182 | + '</use>' + | ||
183 | + '</g></svg>'); | ||
184 | + | ||
185 | + thElems[2].click(); | ||
186 | + div = currentTh.children(); | ||
187 | + // clicked on a new element, so the previous icon should have been deleted | ||
188 | + expect(div.html()).toBeFalsy(); | ||
189 | + | ||
190 | + // the new element should have the ascending icon | ||
191 | + currentTh = angular.element(thElems[2]); | ||
192 | + div = currentTh.children(); | ||
193 | + expect(div.html()).toBe('<svg class="embeddedIcon" ' + | ||
194 | + 'width="10" height="10" viewBox="0 0 50 50">' + | ||
195 | + '<g class="icon tableColSortAsc">' + | ||
196 | + '<rect width="50" height="50" rx="5"></rect>' + | ||
197 | + '<use width="50" height="50" class="glyph" ' + | ||
198 | + 'xmlns:xlink="http://www.w3.org/1999/xlink" ' + | ||
199 | + 'xlink:href="#triangleUp">' + | ||
200 | + '</use>' + | ||
201 | + '</g></svg>'); | ||
202 | + } | ||
203 | + | ||
204 | + it('should affirm that onos-fixed-header is working', function () { | ||
205 | + table = angular.element(onosFixedHeaderTags); | ||
206 | + | ||
207 | + compileTable(); | ||
208 | + verifyGivenTags('onos-fixed-header'); | ||
209 | + | ||
210 | + // table will not be fixed unless it receives the 'LastElement' event | ||
211 | + scope.$emit('LastElement'); | ||
212 | + scope.$digest(); | ||
213 | + | ||
214 | + verifyCssDisplay(); | ||
215 | + verifyColWidth(); | ||
99 | }); | 216 | }); |
100 | 217 | ||
101 | it('should affirm that onos-sortable-header is working', function () { | 218 | it('should affirm that onos-sortable-header is working', function () { |
102 | - table = $compile(onosSortableHeaderTags)($rootScope); | 219 | + var thElems; |
103 | - $rootScope.$digest(); | 220 | + table = angular.element(onosSortableHeaderTags); |
104 | 221 | ||
105 | - table = d3.select(table); | 222 | + compileTable(); |
106 | - expect(table).toBeDefined(); | 223 | + verifyGivenTags('onos-sortable-header'); |
224 | + // ctrlCallback functionality is tested in device-spec | ||
225 | + // only checking that it has been called correctly in the directive | ||
226 | + scope.sortCallback = jasmine.createSpy('sortCallback'); | ||
227 | + | ||
228 | + thElems = thead.find('th'); | ||
229 | + verifyCallbacks(thElems); | ||
230 | + verifyIcons(thElems); | ||
107 | }); | 231 | }); |
108 | 232 | ||
109 | - // TODO: write directive unit tests for table.js | ||
110 | }); | 233 | }); | ... | ... |
-
Please register or login to post a comment