GUI -- Removed onos-fixed-header redundancies, wrote unit tests for fixed-header and sortable-header directives.

Change-Id: Iccf9348a4697f494a4234b024781fede0719491d
diff --git a/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js b/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js
index 0a3fcb6..c0a317e 100644
--- a/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js
+++ b/web/gui/src/main/webapp/tests/app/fw/widget/table-spec.js
@@ -20,11 +20,14 @@
 describe('factory: fw/widget/table.js', function () {
     var $log, $compile, $rootScope,
         fs, is,
-        table;
+        scope, compiled,
+        table, thead, tbody,
+        tableIconTdSize = 33,
+        bottomMargin = 200,
+        numTestElems = 4;
 
     var onosFixedHeaderTags = '<table ' +
-                                'onos-fixed-header ' +
-                                'ng-style="setTableHW()">' +
+                                'onos-fixed-header>' +
                                 '<thead>' +
                                 '<tr>' +
                                 '<th></th>' +
@@ -35,7 +38,7 @@
                                 '</thead>' +
                                 '<tbody>' +
                                 '<tr>' +
-                                '<td>' +
+                                '<td class="table-icon">' +
                                     '<div icon icon-id="{{dev._iconid_available}}">' +
                                     '</div>' +
                                 '</td>' +
@@ -46,7 +49,7 @@
                                 '</tbody>' +
                                 '</table>',
 
-        onosSortableHeaderTags = '<table class="summary-list" ' +
+        onosSortableHeaderTags = '<table ' +
                                 'onos-sortable-header ' +
                                 'sort-callback="sortCallback(urlSuffix)">' +
                                 '<thead>' +
@@ -82,29 +85,149 @@
     }));
 
     beforeEach(function () {
+        scope = $rootScope.$new();
     });
 
     afterEach(function () {
         table = null;
+        thead = null;
+        tbody = null;
     });
 
-    it('should affirm that onos-fixed-header is working', function () {
-        table = $compile(onosFixedHeaderTags)($rootScope);
-        $rootScope.$digest();
+    function compileTable() {
+        compiled = $compile(table);
+        compiled(scope);
+        scope.$digest();
+    }
 
-        table = d3.select(table);
+    function verifyGivenTags(dirName) {
         expect(table).toBeDefined();
+        expect(table.attr(dirName)).toBe('');
 
-        //expect(table.select('thead').style('display')).toBe('block');
+        thead = table.find('thead');
+        expect(thead).toBeDefined();
+        tbody = table.find('tbody');
+        expect(tbody).toBeDefined();
+    }
+
+    function verifyCssDisplay() {
+        var winHeight = fs.windowSize().height;
+
+        expect(thead.css('display')).toBe('block');
+        expect(tbody.css('display')).toBe('block');
+        expect(tbody.css('height')).toBe((winHeight - bottomMargin) + 'px');
+        expect(tbody.css('overflow')).toBe('auto');
+    }
+
+    function verifyColWidth() {
+        var winWidth = fs.windowSize().width,
+            colWidth, thElems, tdElem;
+
+        colWidth = Math.floor(winWidth / numTestElems);
+
+        thElems = thead.find('th');
+
+        angular.forEach(thElems, function (thElem, i) {
+            thElem = angular.element(thElems[i]);
+            tdElem = angular.element(tbody.find('td').eq(i));
+
+            if (tdElem.attr('class') === 'table-icon') {
+                expect(thElem.css('width')).toBe(tableIconTdSize + 'px');
+                expect(tdElem.css('width')).toBe(tableIconTdSize + 'px');
+            } else {
+                expect(thElem.css('width')).toBe(colWidth + 'px');
+                expect(tdElem.css('width')).toBe(colWidth + 'px');
+            }
+        });
+    }
+
+    function verifyCallbacks(thElems) {
+        expect(scope.sortCallback).not.toHaveBeenCalled();
+
+        // first test header has no 'sortable' attr
+        thElems[0].click();
+        expect(scope.sortCallback).not.toHaveBeenCalled();
+
+        // the other headers have 'sortable'
+        for(var i = 1; i < numTestElems; i += 1) {
+            thElems[i].click();
+            expect(scope.sortCallback).toHaveBeenCalled();
+        }
+    }
+
+    function verifyIcons(thElems) {
+        var currentTh, div;
+        // make sure it has the correct icon after clicking
+        thElems[1].click();
+        currentTh = angular.element(thElems[1]);
+        div = currentTh.find('div');
+        expect(div.html()).toBe('<svg class="embeddedIcon" ' +
+                                'width="10" height="10" viewBox="0 0 50 50">' +
+                                '<g class="icon tableColSortAsc">' +
+                                '<rect width="50" height="50" rx="5"></rect>' +
+                                '<use width="50" height="50" class="glyph" ' +
+                                'xmlns:xlink="http://www.w3.org/1999/xlink" ' +
+                                'xlink:href="#triangleUp">' +
+                                '</use>' +
+                                '</g></svg>');
+        thElems[1].click();
+        div = currentTh.find('div');
+        expect(div.html()).toBe('<svg class="embeddedIcon" ' +
+                                'width="10" height="10" viewBox="0 0 50 50">' +
+                                '<g class="icon tableColSortDesc">' +
+                                '<rect width="50" height="50" rx="5"></rect>' +
+                                '<use width="50" height="50" class="glyph" ' +
+                                'xmlns:xlink="http://www.w3.org/1999/xlink" ' +
+                                'xlink:href="#triangleDown">' +
+                                '</use>' +
+                                '</g></svg>');
+
+        thElems[2].click();
+        div = currentTh.children();
+        // clicked on a new element, so the previous icon should have been deleted
+        expect(div.html()).toBeFalsy();
+
+        // the new element should have the ascending icon
+        currentTh = angular.element(thElems[2]);
+        div = currentTh.children();
+        expect(div.html()).toBe('<svg class="embeddedIcon" ' +
+                                'width="10" height="10" viewBox="0 0 50 50">' +
+                                '<g class="icon tableColSortAsc">' +
+                                '<rect width="50" height="50" rx="5"></rect>' +
+                                '<use width="50" height="50" class="glyph" ' +
+                                'xmlns:xlink="http://www.w3.org/1999/xlink" ' +
+                                'xlink:href="#triangleUp">' +
+                                '</use>' +
+                                '</g></svg>');
+    }
+
+    it('should affirm that onos-fixed-header is working', function () {
+        table = angular.element(onosFixedHeaderTags);
+
+        compileTable();
+        verifyGivenTags('onos-fixed-header');
+
+        // table will not be fixed unless it receives the 'LastElement' event
+        scope.$emit('LastElement');
+        scope.$digest();
+
+        verifyCssDisplay();
+        verifyColWidth();
     });
 
     it('should affirm that onos-sortable-header is working', function () {
-        table = $compile(onosSortableHeaderTags)($rootScope);
-        $rootScope.$digest();
+        var thElems;
+        table = angular.element(onosSortableHeaderTags);
 
-        table = d3.select(table);
-        expect(table).toBeDefined();
+        compileTable();
+        verifyGivenTags('onos-sortable-header');
+        // ctrlCallback functionality is tested in device-spec
+        // only checking that it has been called correctly in the directive
+        scope.sortCallback = jasmine.createSpy('sortCallback');
+
+        thElems = thead.find('th');
+        verifyCallbacks(thElems);
+        verifyIcons(thElems);
     });
 
-    // TODO: write directive unit tests for table.js
 });