]> source.dussan.org Git - sonarqube.git/commitdiff
move tests
authorStas Vilchik <vilchiks@gmail.com>
Thu, 19 May 2016 16:26:36 +0000 (18:26 +0200)
committerStas Vilchik <vilchiks@gmail.com>
Fri, 3 Jun 2016 14:09:08 +0000 (16:09 +0200)
40 files changed:
server/sonar-web/package.json
server/sonar-web/pom.xml
server/sonar-web/src/main/js/apps/background-tasks/__tests__/background-tasks-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/QualityGateCondition-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/permission-templates/__tests__/permission-templates-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/projects/__tests__/projects-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/apps/system/__tests__/system-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/__tests__/issue-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/__tests__/source-viewer-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/charts/__tests__/bar-chart-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/charts/__tests__/bubble-chart-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/charts/__tests__/line-chart-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/charts/__tests__/treemap-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/components/charts/__tests__/work-cloud-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/__tests__/l10n-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/__tests__/measures-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/__tests__/path-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/__tests__/urls-test.js [new file with mode: 0644]
server/sonar-web/src/main/js/main/nav/__tests__/nav-test.js [new file with mode: 0644]
server/sonar-web/tests/apps/background-tasks-test.js [deleted file]
server/sonar-web/tests/apps/overview/components/App-test.js [deleted file]
server/sonar-web/tests/apps/overview/components/EmptyOverview-test.js [deleted file]
server/sonar-web/tests/apps/overview/qualityGate/QualityGateCondition-test.js [deleted file]
server/sonar-web/tests/apps/permission-templates-test.js [deleted file]
server/sonar-web/tests/apps/projects-test.js [deleted file]
server/sonar-web/tests/apps/system-test.js [deleted file]
server/sonar-web/tests/components/charts/bar-chart-test.js [deleted file]
server/sonar-web/tests/components/charts/bubble-chart-test.js [deleted file]
server/sonar-web/tests/components/charts/line-chart-test.js [deleted file]
server/sonar-web/tests/components/charts/treemap-test.js [deleted file]
server/sonar-web/tests/components/charts/work-cloud-test.js [deleted file]
server/sonar-web/tests/components/issue-test.js [deleted file]
server/sonar-web/tests/components/source-viewer-test.js [deleted file]
server/sonar-web/tests/helpers/l10n-test.js [deleted file]
server/sonar-web/tests/helpers/measures-test.js [deleted file]
server/sonar-web/tests/helpers/path-test.js [deleted file]
server/sonar-web/tests/helpers/urls-test.js [deleted file]
server/sonar-web/tests/nav-test.js [deleted file]

index 5e4da37d17b157d86a883bf4c38c421ae3617d26..58ea1221ec99092781d46bfb17713bdc6e43b9fc 100644 (file)
@@ -85,7 +85,7 @@
   "scripts": {
     "build-fast": "gulp build:dev",
     "build": "gulp build",
-    "test": "mocha --opts tests/mocha.opts tests",
+    "test": "mocha --opts tests/mocha.opts src/main/js/**/__tests__/**/*",
     "coverage": "babel-node node_modules/.bin/isparta cover --root 'src/main/js' --include-all-sources --excludes '**/libs/**' --dir 'target/coverage' node_modules/.bin/_mocha -- --opts tests/mocha.opts tests",
     "lint": "eslint src/main/js && jscs src/main/js",
     "dev": "NODE_ENV=hot node devServer"
index 96617d15b4068fe9d3523edb233365db17378fe2..6b465ece10bff5441606c3763119385d7c1951f3 100644 (file)
@@ -14,7 +14,9 @@
   <properties>
     <!-- self-analysis -->
     <sonar.sources>src/main/js,src/main/less</sonar.sources>
-    <sonar.exclusions>src/main/js/libs/third-party/**/*,src/main/js/libs/require.js</sonar.exclusions>
+    <sonar.tests>src/main/js</sonar.tests>
+    <sonar.test.inclusions>src/main/js/**/__tests__/**</sonar.test.inclusions>
+    <sonar.exclusions>src/main/js/libs/third-party/**/*,src/main/js/libs/require.js,src/main/js/**/__tests__/**</sonar.exclusions>
     <npm.script>build</npm.script>
   </properties>
   
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/__tests__/background-tasks-test.js b/server/sonar-web/src/main/js/apps/background-tasks/__tests__/background-tasks-test.js
new file mode 100644 (file)
index 0000000..ab0583a
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import ReactDOM from 'react-dom';
+import TestUtils from 'react-addons-test-utils';
+import chai, { expect } from 'chai';
+import sinon from 'sinon';
+import sinonChai from 'sinon-chai';
+
+import Stats from '../components/Stats';
+import Search from '../components/Search';
+import { STATUSES, CURRENTS, DEBOUNCE_DELAY, DEFAULT_FILTERS } from '../constants';
+import { formatDuration } from '../utils';
+
+chai.use(sinonChai);
+
+describe('Background Tasks', function () {
+  describe('Constants', () => {
+    it('should have STATUSES', () => {
+      expect(STATUSES).to.be.a('object');
+      expect(Object.keys(STATUSES).length).to.equal(7);
+    });
+
+    it('should have CURRENTS', () => {
+      expect(CURRENTS).to.be.a('object');
+      expect(Object.keys(CURRENTS).length).to.equal(2);
+    });
+  });
+
+  describe('Search', () => {
+    const defaultProps = {
+      ...DEFAULT_FILTERS,
+      loading: false,
+      types: [],
+      onFilterUpdate: () => true,
+      onReload: () => true
+    };
+
+    it('should render search form', () => {
+      const component = TestUtils.renderIntoDocument(
+          <Search {...defaultProps}/>
+      );
+      const searchBox = TestUtils.scryRenderedDOMComponentsWithClass(component, 'js-search');
+      expect(searchBox).to.have.length(1);
+    });
+
+    it('should not render search form', () => {
+      const component = TestUtils.renderIntoDocument(
+          <Search {...defaultProps} component={{ id: 'ABCD' }}/>
+      );
+      const searchBox = TestUtils.scryRenderedDOMComponentsWithClass(component, 'js-search');
+      expect(searchBox).to.be.empty;
+    });
+
+    it('should search', (done) => {
+      const searchSpy = sinon.spy();
+      const component = TestUtils.renderIntoDocument(
+          <Search {...defaultProps} onFilterUpdate={searchSpy}/>);
+      const searchInput = ReactDOM.findDOMNode(
+          TestUtils.findRenderedDOMComponentWithClass(component, 'js-search'));
+      searchInput.value = 'some search query';
+      TestUtils.Simulate.change(searchInput);
+      setTimeout(() => {
+        expect(searchSpy).to.have.been.calledWith({ query: 'some search query' });
+        done();
+      }, DEBOUNCE_DELAY);
+    });
+
+    it('should reload', () => {
+      const reloadSpy = sinon.spy();
+      const component = TestUtils.renderIntoDocument(
+          <Search {...defaultProps} onReload={reloadSpy}/>
+      );
+      const reloadButton = component.refs.reloadButton;
+      expect(reloadSpy).to.not.have.been.called;
+      TestUtils.Simulate.click(reloadButton);
+      expect(reloadSpy).to.have.been.called;
+    });
+  });
+
+  describe('Stats', () => {
+    describe('Pending', () => {
+      it('should show zero pending', () => {
+        const result = TestUtils.renderIntoDocument(<Stats pendingCount={0}/>);
+        const pendingCounter = result.refs.pendingCount;
+        expect(pendingCounter.textContent).to.contain('0');
+      });
+
+      it('should show 5 pending', () => {
+        const result = TestUtils.renderIntoDocument(<Stats pendingCount={5}/>);
+        const pendingCounter = result.refs.pendingCount;
+        expect(pendingCounter.textContent).to.contain('5');
+      });
+
+      it('should not show cancel pending button', () => {
+        const result = TestUtils.renderIntoDocument(<Stats pendingCount={0}/>);
+        const cancelPending = result.refs.cancelPending;
+        expect(cancelPending).to.not.be.ok;
+      });
+
+      it('should show cancel pending button', () => {
+        const result = TestUtils.renderIntoDocument(<Stats pendingCount={5}/>);
+        const cancelPending = result.refs.cancelPending;
+        expect(cancelPending).to.be.ok;
+      });
+
+      it('should trigger cancelling pending', () => {
+        const spy = sinon.spy();
+        const result = TestUtils.renderIntoDocument(<Stats pendingCount={5} onCancelAllPending={spy}/>);
+        const cancelPending = result.refs.cancelPending;
+        expect(spy).to.not.have.been.called;
+        TestUtils.Simulate.click(cancelPending);
+        expect(spy).to.have.been.called;
+      });
+    });
+
+    describe('Failures', () => {
+      it('should show zero failures', () => {
+        const result = TestUtils.renderIntoDocument(<Stats failingCount={0}/>);
+        const failureCounter = result.refs.failureCount;
+        expect(failureCounter.textContent).to.contain('0');
+      });
+
+      it('should show 5 failures', () => {
+        const result = TestUtils.renderIntoDocument(<Stats failingCount={5}/>);
+        const failureCounter = result.refs.failureCount;
+        expect(failureCounter.textContent).to.contain('5');
+      });
+
+      it('should not show link to failures', () => {
+        const result = TestUtils.renderIntoDocument(<Stats failingCount={0}/>);
+        const failureCounter = result.refs.failureCount;
+        expect(failureCounter.tagName.toLowerCase()).to.not.equal('a');
+      });
+
+      it('should show link to failures', () => {
+        const result = TestUtils.renderIntoDocument(<Stats failingCount={5}/>);
+        const failureCounter = result.refs.failureCount;
+        expect(failureCounter.tagName.toLowerCase()).to.equal('a');
+      });
+
+      it('should trigger filtering failures', () => {
+        const spy = sinon.spy();
+        const result = TestUtils.renderIntoDocument(<Stats failingCount={5} onShowFailing={spy}/>);
+        const failureCounter = result.refs.failureCount;
+        expect(spy).to.not.have.been.called;
+        TestUtils.Simulate.click(failureCounter);
+        expect(spy).to.have.been.called;
+      });
+    });
+  });
+
+  describe('Helpers', () => {
+    describe('#formatDuration()', () => {
+      it('should format 173ms', () => {
+        expect(formatDuration(173)).to.equal('173ms');
+      });
+
+      it('should format 999ms', () => {
+        expect(formatDuration(999)).to.equal('999ms');
+      });
+
+      it('should format 1s', () => {
+        expect(formatDuration(1000)).to.equal('1s');
+      });
+
+      it('should format 1s', () => {
+        expect(formatDuration(1001)).to.equal('1s');
+      });
+
+      it('should format 2s', () => {
+        expect(formatDuration(1501)).to.equal('2s');
+      });
+
+      it('should format 59s', () => {
+        expect(formatDuration(59000)).to.equal('59s');
+      });
+
+      it('should format 1min', () => {
+        expect(formatDuration(60000)).to.equal('1min');
+      });
+
+      it('should format 1min', () => {
+        expect(formatDuration(62757)).to.equal('1min');
+      });
+
+      it('should format 4min', () => {
+        expect(formatDuration(224567)).to.equal('4min');
+      });
+
+      it('should format 80min', () => {
+        expect(formatDuration(80 * 60 * 1000)).to.equal('80min');
+      });
+    });
+  });
+});
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.js b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.js
new file mode 100644 (file)
index 0000000..ad699ec
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { expect } from 'chai';
+import { shallow } from 'enzyme';
+
+import App from '../App';
+import OverviewApp from '../OverviewApp';
+import EmptyOverview from '../EmptyOverview';
+
+describe('Overview :: App', () => {
+  it('should render OverviewApp', () => {
+    const component = {
+      id: 'id',
+      snapshotDate: '2016-01-01'
+    };
+
+    const output = shallow(
+        <App component={component}/>
+    );
+
+    expect(output.type())
+        .to.equal(OverviewApp);
+  });
+
+  it('should render EmptyOverview', () => {
+    const component = { id: 'id' };
+
+    const output = shallow(
+        <App component={component}/>
+    );
+
+    expect(output.type())
+        .to.equal(EmptyOverview);
+  });
+
+  it('should pass leakPeriodIndex', () => {
+    const component = {
+      id: 'id',
+      snapshotDate: '2016-01-01'
+    };
+
+    const output = shallow(
+        <App component={component}/>
+    );
+
+    expect(output.prop('leakPeriodIndex'))
+        .to.equal('1');
+  });
+});
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.js b/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.js
new file mode 100644 (file)
index 0000000..d9c499a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { expect } from 'chai';
+import { shallow } from 'enzyme';
+
+import EmptyOverview from '../EmptyOverview';
+
+describe('Overview :: EmptyOverview', () => {
+  it('should render component key', () => {
+    const component = {
+      id: 'id',
+      key: 'abcd',
+      snapshotDate: '2016-01-01'
+    };
+
+    const output = shallow(
+        <EmptyOverview component={component}/>
+    );
+
+    expect(output.find('code').text())
+        .to.equal('abcd');
+  });
+});
diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/QualityGateCondition-test.js b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/QualityGateCondition-test.js
new file mode 100644 (file)
index 0000000..dcd2911
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import { expect } from 'chai';
+import { shallow } from 'enzyme';
+
+import QualityGateCondition from '../QualityGateCondition';
+import { DrilldownLink } from '../../../../components/shared/drilldown-link';
+
+describe('Overview :: QualityGateCondition', () => {
+  it('should render DrilldownLink', () => {
+    const component = {
+      id: 'abcd',
+      key: 'abcd-key'
+    };
+    const periods = [];
+    const condition = {
+      actual: '10',
+      error: '0',
+      level: 'ERROR',
+      measure: {
+        metric: {
+          key: 'open_issues',
+          type: 'INT',
+          name: 'Open Issues'
+        },
+        value: '10'
+      },
+      metric: 'open_issues',
+      op: 'GT'
+    };
+
+    const output = shallow(
+        <QualityGateCondition
+            component={component}
+            periods={periods}
+            condition={condition}/>
+    );
+
+    const link = output.find(DrilldownLink);
+    expect(link.prop('component')).to.equal('abcd-key');
+    expect(link.prop('metric')).to.equal('open_issues');
+  });
+});
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/__tests__/permission-templates-test.js b/server/sonar-web/src/main/js/apps/permission-templates/__tests__/permission-templates-test.js
new file mode 100644 (file)
index 0000000..ade4d7b
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+/* eslint no-unused-expressions: 0 */
+import React from 'react';
+import TestUtils from 'react-addons-test-utils';
+import { expect } from 'chai';
+import sinon from 'sinon';
+
+import Defaults from '../permission-template-defaults';
+import SetDefaults from '../permission-template-set-defaults';
+
+describe('Permission Templates', function () {
+  describe('Defaults', () => {
+    it('should display one qualifier', () => {
+      const permissionTemplate = { defaultFor: ['VW'] };
+      const topQualifiers = ['TRK', 'VW'];
+      const result = TestUtils.renderIntoDocument(
+          <Defaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers}/>
+      );
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-trk')).to.be.empty;
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-vw')).to.have.length(1);
+    });
+
+    it('should display two qualifiers', () => {
+      const permissionTemplate = { defaultFor: ['TRK', 'VW'] };
+      const topQualifiers = ['TRK', 'VW'];
+      const result = TestUtils.renderIntoDocument(
+          <Defaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers}/>
+      );
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-trk')).to.have.length(1);
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-vw')).to.have.length(1);
+    });
+
+    it('should not display qualifiers', () => {
+      const permissionTemplate = { defaultFor: [] };
+      const topQualifiers = ['TRK', 'VW'];
+      const result = TestUtils.renderIntoDocument(
+          <Defaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers}/>
+      );
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-trk')).to.be.empty;
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-vw')).to.be.empty;
+    });
+
+    it('should omit "project" if there is only one qualifier', () => {
+      const permissionTemplate = { defaultFor: ['TRK'] };
+      const topQualifiers = ['TRK'];
+      const result = TestUtils.renderIntoDocument(
+          <Defaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers}/>
+      );
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-trk')).to.be.empty;
+    });
+  });
+
+  describe('SetDefaults', () => {
+    const refresh = sinon.spy();
+
+    it('should display a dropdown with one option', () => {
+      const permissionTemplate = { defaultFor: ['VW'] };
+      const topQualifiers = ['TRK', 'VW'];
+      const result = TestUtils.renderIntoDocument(
+          <SetDefaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers} refresh={refresh}/>
+      );
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'dropdown')).to.have.length(1);
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'a')).to.have.length(1);
+    });
+
+    it('should display a dropdown with two options', () => {
+      const permissionTemplate = { defaultFor: [] };
+      const topQualifiers = ['TRK', 'VW'];
+      const result = TestUtils.renderIntoDocument(
+          <SetDefaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers} refresh={refresh}/>
+      );
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'dropdown')).to.have.length(1);
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'a')).to.have.length(2);
+    });
+
+    it('should not display a dropdown', () => {
+      const permissionTemplate = { defaultFor: ['TRK', 'VW'] };
+      const topQualifiers = ['TRK', 'VW'];
+      const result = TestUtils.renderIntoDocument(
+          <SetDefaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers} refresh={refresh}/>
+      );
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'dropdown')).to.be.empty;
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'a')).to.be.empty;
+    });
+
+    it('should omit dropdown if there is only one qualifier', () => {
+      const permissionTemplate = { defaultFor: [] };
+      const topQualifiers = ['TRK'];
+      const result = TestUtils.renderIntoDocument(
+          <SetDefaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers} refresh={refresh}/>
+      );
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'dropdown')).to.be.empty;
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'a')).to.have.length(1);
+    });
+  });
+});
diff --git a/server/sonar-web/src/main/js/apps/projects/__tests__/projects-test.js b/server/sonar-web/src/main/js/apps/projects/__tests__/projects-test.js
new file mode 100644 (file)
index 0000000..51f0ba2
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import TestUtils from 'react-addons-test-utils';
+import { expect } from 'chai';
+import sinon from 'sinon';
+
+import Projects from '../projects';
+
+describe('Projects', function () {
+  describe('Projects', () => {
+    it('should render list of projects with no selection', () => {
+      const projects = [
+        { id: '1', key: 'a', name: 'A', qualifier: 'TRK' },
+        { id: '2', key: 'b', name: 'B', qualifier: 'TRK' }
+      ];
+
+      const result = TestUtils.renderIntoDocument(
+          <Projects projects={projects} selection={[]} refresh={sinon.spy()}/>);
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'tr')).to.have.length(2);
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-checkbox-checked')).to.be.empty;
+    });
+
+    it('should render list of projects with one selected', () => {
+      const projects = [
+        { id: '1', key: 'a', name: 'A', qualifier: 'TRK' },
+        { id: '2', key: 'b', name: 'B', qualifier: 'TRK' }
+      ];
+      const selection = ['1'];
+
+      const result = TestUtils.renderIntoDocument(
+          <Projects projects={projects} selection={selection} refresh={sinon.spy()}/>);
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'tr')).to.have.length(2);
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-checkbox-checked')).to.have.length(1);
+    });
+  });
+});
diff --git a/server/sonar-web/src/main/js/apps/system/__tests__/system-test.js b/server/sonar-web/src/main/js/apps/system/__tests__/system-test.js
new file mode 100644 (file)
index 0000000..2de40ad
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import ReactDOM from 'react-dom';
+import TestUtils from 'react-addons-test-utils';
+import { expect } from 'chai';
+
+import ItemValue from '../item-value';
+
+describe('System', function () {
+
+  describe('Item Value', function () {
+    it('should render string', () => {
+      const result = TestUtils.renderIntoDocument(<ItemValue value="/some/path/as/an/example"/>);
+      const content = ReactDOM.findDOMNode(TestUtils.findRenderedDOMComponentWithTag(result, 'code'));
+      expect(content.textContent).to.equal('/some/path/as/an/example');
+    });
+
+    it('should render `true`', () => {
+      const result = TestUtils.renderIntoDocument(<ItemValue value={true}/>);
+      TestUtils.findRenderedDOMComponentWithClass(result, 'icon-check');
+    });
+
+    it('should render `false`', () => {
+      const result = TestUtils.renderIntoDocument(<ItemValue value={false}/>);
+      TestUtils.findRenderedDOMComponentWithClass(result, 'icon-delete');
+    });
+
+    it('should render object', () => {
+      const result = TestUtils.renderIntoDocument(<ItemValue value={{ name: 'Java', version: '3.2' }}/>);
+      TestUtils.findRenderedDOMComponentWithTag(result, 'table');
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'tr')).to.have.length(2);
+    });
+
+    it('should render `true` inside object', () => {
+      const result = TestUtils.renderIntoDocument(<ItemValue value={{ name: 'Java', isCool: true }}/>);
+      TestUtils.findRenderedDOMComponentWithTag(result, 'table');
+      TestUtils.findRenderedDOMComponentWithClass(result, 'icon-check');
+    });
+
+    it('should render object inside object', () => {
+      const result = TestUtils.renderIntoDocument(
+          <ItemValue value={{ users: { docs: 1, shards: 5 }, tests: { docs: 68, shards: 5 } }}/>);
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'table')).to.have.length(3);
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'tr')).to.have.length(6);
+    });
+  });
+
+  describe('Log Level', function () {
+    let previousFetch;
+    let fetchUrl;
+    let fetchOptions;
+
+    before(function () {
+      previousFetch = window.fetch;
+      window.fetch = function (url, options) {
+        fetchUrl = url;
+        fetchOptions = options;
+        return Promise.resolve();
+      };
+    });
+
+    after(function () {
+      window.fetch = previousFetch;
+    });
+
+    it('should render select box', () => {
+      const result = TestUtils.renderIntoDocument(<ItemValue value="INFO" name="Logs Level"/>);
+      TestUtils.findRenderedDOMComponentWithTag(result, 'select');
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'option')).to.have.length(3);
+    });
+
+    it('should set initial value', () => {
+      const result = TestUtils.renderIntoDocument(<ItemValue value="DEBUG" name="Logs Level"/>);
+      const select = ReactDOM.findDOMNode(TestUtils.findRenderedDOMComponentWithTag(result, 'select'));
+      expect(select.value).to.equal('DEBUG');
+    });
+
+    it('should render warning', () => {
+      const result = TestUtils.renderIntoDocument(<ItemValue value="DEBUG" name="Logs Level"/>);
+      TestUtils.findRenderedDOMComponentWithClass(result, 'alert');
+    });
+
+    it('should not render warning', () => {
+      const result = TestUtils.renderIntoDocument(<ItemValue value="INFO" name="Logs Level"/>);
+      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'alert')).to.be.empty;
+    });
+
+    it('should change value', () => {
+      const result = TestUtils.renderIntoDocument(<ItemValue value="INFO" name="Logs Level"/>);
+      const select = ReactDOM.findDOMNode(TestUtils.findRenderedDOMComponentWithTag(result, 'select'));
+      select.value = 'TRACE';
+      TestUtils.Simulate.change(select);
+      expect(fetchUrl).to.equal('/api/system/change_log_level');
+      expect(fetchOptions.method).to.equal('POST');
+      expect(fetchOptions.body).to.equal('level=TRACE');
+    });
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/__tests__/issue-test.js b/server/sonar-web/src/main/js/components/__tests__/issue-test.js
new file mode 100644 (file)
index 0000000..75d4e89
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import chai, { expect } from 'chai';
+import sinon from 'sinon';
+import sinonChai from 'sinon-chai';
+
+import Issue from '../issue/models/issue';
+
+chai.use(sinonChai);
+
+describe('Issue', function () {
+  describe('Model', function () {
+    it('should have correct urlRoot', function () {
+      const issue = new Issue();
+      expect(issue.urlRoot()).to.equal('/api/issues');
+    });
+
+    it('should parse response without root issue object', function () {
+      const issue = new Issue();
+      const example = { a: 1 };
+      expect(issue.parse(example)).to.deep.equal(example);
+    });
+
+    it('should parse response with the root issue object', function () {
+      const issue = new Issue();
+      const example = { a: 1 };
+      expect(issue.parse({ issue: example })).to.deep.equal(example);
+    });
+
+    it('should reset attributes (no attributes initially)', function () {
+      const issue = new Issue();
+      const example = { a: 1 };
+      issue.reset(example);
+      expect(issue.toJSON()).to.deep.equal(example);
+    });
+
+    it('should reset attributes (override attribute)', function () {
+      const issue = new Issue({ a: 2 });
+      const example = { a: 1 };
+      issue.reset(example);
+      expect(issue.toJSON()).to.deep.equal(example);
+    });
+
+    it('should reset attributes (different attributes)', function () {
+      const issue = new Issue({ a: 2 });
+      const example = { b: 1 };
+      issue.reset(example);
+      expect(issue.toJSON()).to.deep.equal(example);
+    });
+
+    it('should unset `textRange` of a closed issue', function () {
+      const issue = new Issue();
+      const result = issue.parse({ issue: { status: 'CLOSED', textRange: { startLine: 5 } } });
+      expect(result.textRange).to.not.be.ok;
+    });
+
+    it('should unset `flows` of a closed issue', function () {
+      const issue = new Issue();
+      const result = issue.parse({ issue: { status: 'CLOSED', flows: [1, 2, 3] } });
+      expect(result.flows).to.deep.equal([]);
+    });
+
+    describe('Actions', function () {
+      it('should assign', function () {
+        const issue = new Issue({ key: 'issue-key' });
+        const spy = sinon.spy();
+        issue._action = spy;
+        issue.assign('admin');
+        expect(spy).to.have.been.calledWith({
+          data: { assignee: 'admin', issue: 'issue-key' },
+          url: '/api/issues/assign'
+        });
+      });
+
+      it('should unassign', function () {
+        const issue = new Issue({ key: 'issue-key' });
+        const spy = sinon.spy();
+        issue._action = spy;
+        issue.assign();
+        expect(spy).to.have.been.calledWith({
+          data: { assignee: undefined, issue: 'issue-key' },
+          url: '/api/issues/assign'
+        });
+      });
+
+      it('should plan', function () {
+        const issue = new Issue({ key: 'issue-key' });
+        const spy = sinon.spy();
+        issue._action = spy;
+        issue.plan('plan');
+        expect(spy).to.have.been.calledWith({ data: { plan: 'plan', issue: 'issue-key' }, url: '/api/issues/plan' });
+      });
+
+      it('should unplan', function () {
+        const issue = new Issue({ key: 'issue-key' });
+        const spy = sinon.spy();
+        issue._action = spy;
+        issue.plan();
+        expect(spy).to.have.been.calledWith({ data: { plan: undefined, issue: 'issue-key' }, url: '/api/issues/plan' });
+      });
+
+      it('should set severity', function () {
+        const issue = new Issue({ key: 'issue-key' });
+        const spy = sinon.spy();
+        issue._action = spy;
+        issue.setSeverity('BLOCKER');
+        expect(spy).to.have.been.calledWith({
+          data: { severity: 'BLOCKER', issue: 'issue-key' },
+          url: '/api/issues/set_severity'
+        });
+      });
+    });
+
+    describe('#getLinearLocations', function () {
+      it('should return single line location', function () {
+        const issue = new Issue({ textRange: { startLine: 1, endLine: 1, startOffset: 0, endOffset: 10 } });
+        const locations = issue.getLinearLocations();
+        expect(locations.length).to.equal(1);
+
+        expect(locations[0].line).to.equal(1);
+        expect(locations[0].from).to.equal(0);
+        expect(locations[0].to).to.equal(10);
+      });
+
+      it('should return location not from 0', function () {
+        const issue = new Issue({ textRange: { startLine: 1, endLine: 1, startOffset: 5, endOffset: 10 } });
+        const locations = issue.getLinearLocations();
+        expect(locations.length).to.equal(1);
+
+        expect(locations[0].line).to.equal(1);
+        expect(locations[0].from).to.equal(5);
+        expect(locations[0].to).to.equal(10);
+      });
+
+      it('should return 2-lines location', function () {
+        const issue = new Issue({ textRange: { startLine: 2, endLine: 3, startOffset: 5, endOffset: 10 } });
+        const locations = issue.getLinearLocations();
+        expect(locations.length).to.equal(2);
+
+        expect(locations[0].line).to.equal(2);
+        expect(locations[0].from).to.equal(5);
+        expect(locations[0].to).to.equal(999999);
+
+        expect(locations[1].line).to.equal(3);
+        expect(locations[1].from).to.equal(0);
+        expect(locations[1].to).to.equal(10);
+      });
+
+      it('should return 3-lines location', function () {
+        const issue = new Issue({ textRange: { startLine: 4, endLine: 6, startOffset: 5, endOffset: 10 } });
+        const locations = issue.getLinearLocations();
+        expect(locations.length).to.equal(3);
+
+        expect(locations[0].line).to.equal(4);
+        expect(locations[0].from).to.equal(5);
+        expect(locations[0].to).to.equal(999999);
+
+        expect(locations[1].line).to.equal(5);
+        expect(locations[1].from).to.equal(0);
+        expect(locations[1].to).to.equal(999999);
+
+        expect(locations[2].line).to.equal(6);
+        expect(locations[2].from).to.equal(0);
+        expect(locations[2].to).to.equal(10);
+      });
+
+      it('should return [] when no location', function () {
+        const issue = new Issue();
+        const locations = issue.getLinearLocations();
+        expect(locations.length).to.equal(0);
+      });
+    });
+  });
+});
diff --git a/server/sonar-web/src/main/js/components/__tests__/source-viewer-test.js b/server/sonar-web/src/main/js/components/__tests__/source-viewer-test.js
new file mode 100644 (file)
index 0000000..99ce9b0
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { expect } from 'chai';
+
+import helper from '../source-viewer/helpers/code-with-issue-locations-helper';
+
+describe('Source Viewer', function () {
+  describe('Code With Issue Locations Helper', function () {
+    it('should be a function', function () {
+      expect(helper).to.be.a('function');
+    });
+
+    it('should mark one location', function () {
+      const code = '<span class="k">if</span> (<span class="sym-2 sym">a</span> + <span class="c">1</span>) {';
+      const locations = [{ from: 1, to: 5 }];
+      const result = helper(code, locations, 'x');
+      expect(result).to.equal([
+        '<span class="k">i</span>',
+        '<span class="k x">f</span>',
+        '<span class=" x"> (</span>',
+        '<span class="sym-2 sym x">a</span>',
+        '<span class=""> + </span>',
+        '<span class="c">1</span>',
+        '<span class="">) {</span>'
+      ].join(''));
+    });
+
+    it('should mark two locations', function () {
+      const code = 'abcdefghijklmnopqrst';
+      const locations = [
+        { from: 1, to: 6 },
+        { from: 11, to: 16 }
+      ];
+      const result = helper(code, locations, 'x');
+      expect(result).to.equal([
+        '<span class="">a</span>',
+        '<span class=" x">bcdef</span>',
+        '<span class="">ghijk</span>',
+        '<span class=" x">lmnop</span>',
+        '<span class="">qrst</span>'
+      ].join(''));
+    });
+
+    it('should mark one locations', function () {
+      const code = '<span class="cppd"> * Copyright (C) 2008-2014 SonarSource</span>';
+      const locations = [{ from: 15, to: 20 }];
+      const result = helper(code, locations, 'x');
+      expect(result).to.equal([
+        '<span class="cppd"> * Copyright (C</span>',
+        '<span class="cppd x">) 200</span>',
+        '<span class="cppd">8-2014 SonarSource</span>'
+      ].join(''));
+    });
+
+    it('should mark two locations', function () {
+      const code = '<span class="cppd"> * Copyright (C) 2008-2014 SonarSource</span>';
+      const locations = [
+        { from: 24, to: 29 },
+        { from: 15, to: 20 }
+      ];
+      const result = helper(code, locations, 'x');
+      expect(result).to.equal([
+        '<span class="cppd"> * Copyright (C</span>',
+        '<span class="cppd x">) 200</span>',
+        '<span class="cppd">8-20</span>',
+        '<span class="cppd x">14 So</span>',
+        '<span class="cppd">narSource</span>'
+      ].join(''));
+    });
+
+    it('should parse line with < and >', function () {
+      const code = '<span class="j">#include &lt;stdio.h&gt;</span>';
+      const result = helper(code, []);
+      expect(result).to.equal('<span class="j">#include &lt;stdio.h&gt;</span>');
+    });
+
+    it('should parse syntax and usage highlighting', function () {
+      const code = '<span class="k"><span class="sym-3 sym">this</span></span>';
+      const expected = '<span class="k sym-3 sym">this</span>';
+      const result = helper(code, []);
+      expect(result).to.equal(expected);
+    });
+
+    it('should parse nested tags', function () {
+      const code = '<span class="k"><span class="sym-3 sym">this</span> is</span>';
+      const expected = '<span class="k sym-3 sym">this</span><span class="k"> is</span>';
+      const result = helper(code, []);
+      expect(result).to.equal(expected);
+    });
+  });
+});
+
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/bar-chart-test.js b/server/sonar-web/src/main/js/components/charts/__tests__/bar-chart-test.js
new file mode 100644 (file)
index 0000000..d3c50a4
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import TestUtils from 'react-addons-test-utils';
+import { expect } from 'chai';
+
+import { BarChart } from '../bar-chart';
+
+describe('Bar Chart', function () {
+
+  it('should display bars', function () {
+    const data = [
+      { x: 1, y: 10 },
+      { x: 2, y: 30 },
+      { x: 3, y: 20 }
+    ];
+    const chart = TestUtils.renderIntoDocument(
+        <BarChart
+            data={data}
+            width={100}
+            height={100}
+            barsWidth={20}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bar-chart-bar')).to.have.length(3);
+  });
+
+  it('should display ticks', function () {
+    const data = [
+      { x: 1, y: 10 },
+      { x: 2, y: 30 },
+      { x: 3, y: 20 }
+    ];
+    const ticks = ['A', 'B', 'C'];
+    const chart = TestUtils.renderIntoDocument(
+        <BarChart
+            data={data}
+            xTicks={ticks}
+            width={100}
+            height={100}
+            barsWidth={20}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bar-chart-tick')).to.have.length(3);
+  });
+
+  it('should display values', function () {
+    const data = [
+      { x: 1, y: 10 },
+      { x: 2, y: 30 },
+      { x: 3, y: 20 }
+    ];
+    const values = ['A', 'B', 'C'];
+    const chart = TestUtils.renderIntoDocument(
+        <BarChart
+            data={data}
+            xValues={values}
+            width={100}
+            height={100}
+            barsWidth={20}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bar-chart-tick')).to.have.length(3);
+  });
+
+  it('should display bars, ticks and values', function () {
+    const data = [
+      { x: 1, y: 10 },
+      { x: 2, y: 30 },
+      { x: 3, y: 20 }
+    ];
+    const ticks = ['A', 'B', 'C'];
+    const values = ['A', 'B', 'C'];
+    const chart = TestUtils.renderIntoDocument(
+        <BarChart
+            data={data}
+            xTicks={ticks}
+            xValues={values}
+            width={100}
+            height={100}
+            barsWidth={20}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bar-chart-bar')).to.have.length(3);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bar-chart-tick')).to.have.length(6);
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/bubble-chart-test.js b/server/sonar-web/src/main/js/components/charts/__tests__/bubble-chart-test.js
new file mode 100644 (file)
index 0000000..bb03185
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import TestUtils from 'react-addons-test-utils';
+import { expect } from 'chai';
+
+import { BubbleChart } from '../bubble-chart';
+
+describe('Bubble Chart', function () {
+
+  it('should display bubbles', function () {
+    const items = [
+      { x: 1, y: 10, size: 7 },
+      { x: 2, y: 30, size: 5 },
+      { x: 3, y: 20, size: 2 }
+    ];
+    const chart = TestUtils.renderIntoDocument(<BubbleChart items={items} width={100} height={100}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bubble-chart-bubble')).to.have.length(3);
+  });
+
+  it('should display grid', function () {
+    const items = [
+      { x: 1, y: 10, size: 7 },
+      { x: 2, y: 30, size: 5 },
+      { x: 3, y: 20, size: 2 }
+    ];
+    const chart = TestUtils.renderIntoDocument(<BubbleChart items={items} width={100} height={100}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithTag(chart, 'line')).to.not.be.empty;
+  });
+
+  it('should display ticks', function () {
+    const items = [
+      { x: 1, y: 10, size: 7 },
+      { x: 2, y: 30, size: 5 },
+      { x: 3, y: 20, size: 2 }
+    ];
+    const chart = TestUtils.renderIntoDocument(<BubbleChart items={items} width={100} height={100}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bubble-chart-tick')).to.not.be.empty;
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/line-chart-test.js b/server/sonar-web/src/main/js/components/charts/__tests__/line-chart-test.js
new file mode 100644 (file)
index 0000000..e4144bb
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import TestUtils from 'react-addons-test-utils';
+import { expect } from 'chai';
+
+import { LineChart } from '../line-chart';
+
+describe('Line Chart', function () {
+
+  it('should display line', function () {
+    const data = [
+      { x: 1, y: 10 },
+      { x: 2, y: 30 },
+      { x: 3, y: 20 }
+    ];
+    const chart = TestUtils.renderIntoDocument(
+        <LineChart
+            data={data}
+            width={100}
+            height={100}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'line-chart-path')).to.have.length(1);
+  });
+
+  it('should display ticks', function () {
+    const data = [
+      { x: 1, y: 10 },
+      { x: 2, y: 30 },
+      { x: 3, y: 20 }
+    ];
+    const ticks = ['A', 'B', 'C'];
+    const chart = TestUtils.renderIntoDocument(
+        <LineChart
+            data={data}
+            xTicks={ticks}
+            width={100}
+            height={100}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'line-chart-tick')).to.have.length(3);
+  });
+
+  it('should display values', function () {
+    const data = [
+      { x: 1, y: 10 },
+      { x: 2, y: 30 },
+      { x: 3, y: 20 }
+    ];
+    const values = ['A', 'B', 'C'];
+    const chart = TestUtils.renderIntoDocument(
+        <LineChart
+            data={data}
+            xValues={values}
+            width={100}
+            height={100}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'line-chart-tick')).to.have.length(3);
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/treemap-test.js b/server/sonar-web/src/main/js/components/charts/__tests__/treemap-test.js
new file mode 100644 (file)
index 0000000..1ce0054
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import TestUtils from 'react-addons-test-utils';
+import { expect } from 'chai';
+
+import { Treemap } from '../treemap';
+
+describe('Treemap', function () {
+
+  it('should display', function () {
+    const items = [
+      { size: 10, color: '#777', label: 'SonarQube :: Server' },
+      { size: 30, color: '#777', label: 'SonarQube :: Web' },
+      { size: 20, color: '#777', label: 'SonarQube :: Search' }
+    ];
+    const chart = TestUtils.renderIntoDocument(
+        <Treemap
+            items={items}
+            width={100}
+            height={100}
+            breadcrumbs={[]}
+            canBeClicked={() => true}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'treemap-cell')).to.have.length(3);
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/work-cloud-test.js b/server/sonar-web/src/main/js/components/charts/__tests__/work-cloud-test.js
new file mode 100644 (file)
index 0000000..177151a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import TestUtils from 'react-addons-test-utils';
+import { expect } from 'chai';
+
+import { WordCloud } from '../word-cloud';
+
+describe('Word Cloud', function () {
+
+  it('should display', function () {
+    const items = [
+      { size: 10, link: '#', text: 'SonarQube :: Server' },
+      { size: 30, link: '#', text: 'SonarQube :: Web' },
+      { size: 20, link: '#', text: 'SonarQube :: Search' }
+    ];
+    const chart = TestUtils.renderIntoDocument(<WordCloud items={items} width={100} height={100}/>);
+    expect(TestUtils.scryRenderedDOMComponentsWithTag(chart, 'a')).to.have.length(3);
+  });
+
+});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/l10n-test.js b/server/sonar-web/src/main/js/helpers/__tests__/l10n-test.js
new file mode 100644 (file)
index 0000000..2bfb213
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { expect } from 'chai';
+import { resetBundle, translate, translateWithParameters } from '../l10n';
+
+describe('l10n', () => {
+  afterEach(() => {
+    resetBundle({});
+  });
+
+  describe('#translate', () => {
+    it('should translate simple message', () => {
+      resetBundle({ 'my_key': 'my message' });
+      expect(translate('my_key')).to.equal('my message');
+    });
+
+    it('should translate message with composite key', () => {
+      resetBundle({ 'my.composite.message': 'my message' });
+      expect(translate('my', 'composite', 'message')).to.equal('my message');
+      expect(translate('my.composite', 'message')).to.equal('my message');
+      expect(translate('my', 'composite.message')).to.equal('my message');
+      expect(translate('my.composite.message')).to.equal('my message');
+    });
+
+    it('should not translate message but return its key', () => {
+      expect(translate('random')).to.equal('random');
+      expect(translate('random', 'key')).to.equal('random.key');
+      expect(translate('composite.random', 'key')).to.equal('composite.random.key');
+    });
+  });
+
+  describe('#translateWithParameters', () => {
+    it('should translate message with one parameter in the beginning', () => {
+      resetBundle({ 'x_apples': '{0} apples' });
+      expect(translateWithParameters('x_apples', 5)).to.equal('5 apples');
+    });
+
+    it('should translate message with one parameter in the middle', () => {
+      resetBundle({ 'x_apples': 'I have {0} apples' });
+      expect(translateWithParameters('x_apples', 5)).to.equal('I have 5 apples');
+    });
+
+    it('should translate message with one parameter in the end', () => {
+      resetBundle({ 'x_apples': 'Apples: {0}' });
+      expect(translateWithParameters('x_apples', 5)).to.equal('Apples: 5');
+    });
+
+    it('should translate message with several parameters', () => {
+      resetBundle({ 'x_apples': '{0}: I have {2} apples in my {1} baskets - {3}' });
+      expect(translateWithParameters('x_apples', 1, 2, 3, 4)).to.equal('1: I have 3 apples in my 2 baskets - 4');
+    });
+
+    it('should not translate message but return its key', () => {
+      expect(translateWithParameters('random', 5)).to.equal('random.5');
+      expect(translateWithParameters('random', 1, 2, 3)).to.equal('random.1.2.3');
+      expect(translateWithParameters('composite.random', 1, 2)).to.equal('composite.random.1.2');
+    });
+  });
+});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/measures-test.js b/server/sonar-web/src/main/js/helpers/__tests__/measures-test.js
new file mode 100644 (file)
index 0000000..e6c377b
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { expect } from 'chai';
+
+import { resetBundle } from '../l10n';
+import { formatMeasure, formatMeasureVariation } from '../measures';
+
+describe('Measures', function () {
+  const HOURS_IN_DAY = 8;
+  const ONE_MINUTE = 1;
+  const ONE_HOUR = ONE_MINUTE * 60;
+  const ONE_DAY = HOURS_IN_DAY * ONE_HOUR;
+
+  before(function () {
+    resetBundle({
+      'work_duration.x_days': '{0}d',
+      'work_duration.x_hours': '{0}h',
+      'work_duration.x_minutes': '{0}min',
+      'work_duration.about': '~ {0}',
+      'metric.level.ERROR': 'Error',
+      'metric.level.WARN': 'Warning',
+      'metric.level.OK': 'Ok'
+    });
+    window.SS = { hoursInDay: HOURS_IN_DAY };
+  });
+
+  describe('#formatMeasure()', function () {
+    it('should format INT', function () {
+      expect(formatMeasure(0, 'INT')).to.equal('0');
+      expect(formatMeasure(1, 'INT')).to.equal('1');
+      expect(formatMeasure(-5, 'INT')).to.equal('-5');
+      expect(formatMeasure(999, 'INT')).to.equal('999');
+      expect(formatMeasure(1000, 'INT')).to.equal('1,000');
+      expect(formatMeasure(1529, 'INT')).to.equal('1,529');
+      expect(formatMeasure(10000, 'INT')).to.equal('10,000');
+      expect(formatMeasure(1234567890, 'INT')).to.equal('1,234,567,890');
+    });
+
+    it('should format SHORT_INT', function () {
+      expect(formatMeasure(0, 'SHORT_INT')).to.equal('0');
+      expect(formatMeasure(1, 'SHORT_INT')).to.equal('1');
+      expect(formatMeasure(999, 'SHORT_INT')).to.equal('999');
+      expect(formatMeasure(1000, 'SHORT_INT')).to.equal('1k');
+      expect(formatMeasure(1529, 'SHORT_INT')).to.equal('1.5k');
+      expect(formatMeasure(10000, 'SHORT_INT')).to.equal('10k');
+      expect(formatMeasure(10678, 'SHORT_INT')).to.equal('11k');
+      expect(formatMeasure(1234567890, 'SHORT_INT')).to.equal('1b');
+    });
+
+    it('should format FLOAT', function () {
+      expect(formatMeasure(0.0, 'FLOAT')).to.equal('0.0');
+      expect(formatMeasure(1.0, 'FLOAT')).to.equal('1.0');
+      expect(formatMeasure(1.3, 'FLOAT')).to.equal('1.3');
+      expect(formatMeasure(1.34, 'FLOAT')).to.equal('1.34');
+      expect(formatMeasure(50.89, 'FLOAT')).to.equal('50.89');
+      expect(formatMeasure(100.0, 'FLOAT')).to.equal('100.0');
+      expect(formatMeasure(123.456, 'FLOAT')).to.equal('123.456');
+      expect(formatMeasure(123456.7, 'FLOAT')).to.equal('123,456.7');
+      expect(formatMeasure(1234567890.0, 'FLOAT')).to.equal('1,234,567,890.0');
+    });
+
+    it('should respect FLOAT precision', function () {
+      expect(formatMeasure(0.1, 'FLOAT')).to.equal('0.1');
+      expect(formatMeasure(0.12, 'FLOAT')).to.equal('0.12');
+      expect(formatMeasure(0.12345, 'FLOAT')).to.equal('0.12345');
+      expect(formatMeasure(0.123456, 'FLOAT')).to.equal('0.12346');
+    });
+
+    it('should format PERCENT', function () {
+      expect(formatMeasure(0.0, 'PERCENT')).to.equal('0.0%');
+      expect(formatMeasure(1.0, 'PERCENT')).to.equal('1.0%');
+      expect(formatMeasure(1.3, 'PERCENT')).to.equal('1.3%');
+      expect(formatMeasure(1.34, 'PERCENT')).to.equal('1.3%');
+      expect(formatMeasure(50.89, 'PERCENT')).to.equal('50.9%');
+      expect(formatMeasure(100.0, 'PERCENT')).to.equal('100.0%');
+    });
+
+    it('should format WORK_DUR', function () {
+      expect(formatMeasure(0, 'WORK_DUR')).to.equal('0');
+      expect(formatMeasure(5 * ONE_DAY, 'WORK_DUR')).to.equal('5d');
+      expect(formatMeasure(2 * ONE_HOUR, 'WORK_DUR')).to.equal('2h');
+      expect(formatMeasure(40 * ONE_MINUTE, 'WORK_DUR')).to.equal('40min');
+      expect(formatMeasure(ONE_MINUTE, 'WORK_DUR')).to.equal('1min');
+      expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR, 'WORK_DUR')).to.equal('5d 2h');
+      expect(formatMeasure(2 * ONE_HOUR + ONE_MINUTE, 'WORK_DUR')).to.equal('2h 1min');
+      expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'WORK_DUR')).to.equal('5d 2h');
+      expect(formatMeasure(15 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'WORK_DUR')).to.equal('15d');
+      expect(formatMeasure(-5 * ONE_DAY, 'WORK_DUR')).to.equal('-5d');
+      expect(formatMeasure(-2 * ONE_HOUR, 'WORK_DUR')).to.equal('-2h');
+      expect(formatMeasure(-1 * ONE_MINUTE, 'WORK_DUR')).to.equal('-1min');
+    });
+
+    it('should format SHORT_WORK_DUR', function () {
+      expect(formatMeasure(0, 'SHORT_WORK_DUR')).to.equal('0');
+      expect(formatMeasure(5 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('5d');
+      expect(formatMeasure(2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('2h');
+      expect(formatMeasure(40 * ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('40min');
+      expect(formatMeasure(ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('1min');
+      expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('5d');
+      expect(formatMeasure(2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('2h');
+      expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('5d');
+      expect(formatMeasure(15 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('15d');
+      expect(formatMeasure(7 * ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('7min');
+      expect(formatMeasure(-5 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('-5d');
+      expect(formatMeasure(-2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('-2h');
+      expect(formatMeasure(-1 * ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('-1min');
+
+      expect(formatMeasure(1529 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('1.5kd');
+      expect(formatMeasure(1234567 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('1md');
+      expect(formatMeasure(1234567 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('1md');
+    });
+
+    it('should format RATING', function () {
+      expect(formatMeasure(1, 'RATING')).to.equal('A');
+      expect(formatMeasure(2, 'RATING')).to.equal('B');
+      expect(formatMeasure(3, 'RATING')).to.equal('C');
+      expect(formatMeasure(4, 'RATING')).to.equal('D');
+      expect(formatMeasure(5, 'RATING')).to.equal('E');
+    });
+
+    it('should format LEVEL', function () {
+      expect(formatMeasure('ERROR', 'LEVEL')).to.equal('Error');
+      expect(formatMeasure('WARN', 'LEVEL')).to.equal('Warning');
+      expect(formatMeasure('OK', 'LEVEL')).to.equal('Ok');
+      expect(formatMeasure('UNKNOWN', 'LEVEL')).to.equal('UNKNOWN');
+    });
+
+    it('should format MILLISEC', function () {
+      expect(formatMeasure(0, 'MILLISEC')).to.equal('0ms');
+      expect(formatMeasure(1, 'MILLISEC')).to.equal('1ms');
+      expect(formatMeasure(173, 'MILLISEC')).to.equal('173ms');
+      expect(formatMeasure(3649, 'MILLISEC')).to.equal('4s');
+      expect(formatMeasure(893481, 'MILLISEC')).to.equal('15min');
+      expect(formatMeasure(17862325, 'MILLISEC')).to.equal('298min');
+    });
+
+    it('should not format unknown type', function () {
+      expect(formatMeasure('random value', 'RANDOM_TYPE')).to.equal('random value');
+    });
+
+    it('should return null if value is empty string', function () {
+      expect(formatMeasure('', 'PERCENT')).to.be.null;
+    });
+
+    it('should not fail without parameters', function () {
+      expect(formatMeasure()).to.be.null;
+    });
+  });
+
+  describe('#formatMeasureVariation()', function () {
+    it('should format INT', function () {
+      expect(formatMeasureVariation(0, 'INT')).to.equal('+0');
+      expect(formatMeasureVariation(1, 'INT')).to.equal('+1');
+      expect(formatMeasureVariation(-1, 'INT')).to.equal('-1');
+      expect(formatMeasureVariation(1529, 'INT')).to.equal('+1,529');
+      expect(formatMeasureVariation(-1529, 'INT')).to.equal('-1,529');
+    });
+
+    it('should format SHORT_INT', function () {
+      expect(formatMeasureVariation(0, 'SHORT_INT')).to.equal('+0');
+      expect(formatMeasureVariation(1, 'SHORT_INT')).to.equal('+1');
+      expect(formatMeasureVariation(-1, 'SHORT_INT')).to.equal('-1');
+      expect(formatMeasureVariation(1529, 'SHORT_INT')).to.equal('+1.5k');
+      expect(formatMeasureVariation(-1529, 'SHORT_INT')).to.equal('-1.5k');
+      expect(formatMeasureVariation(10678, 'SHORT_INT')).to.equal('+11k');
+      expect(formatMeasureVariation(-10678, 'SHORT_INT')).to.equal('-11k');
+    });
+
+    it('should format FLOAT', function () {
+      expect(formatMeasureVariation(0.0, 'FLOAT')).to.equal('+0.0');
+      expect(formatMeasureVariation(1.0, 'FLOAT')).to.equal('+1.0');
+      expect(formatMeasureVariation(-1.0, 'FLOAT')).to.equal('-1.0');
+      expect(formatMeasureVariation(50.89, 'FLOAT')).to.equal('+50.89');
+      expect(formatMeasureVariation(-50.89, 'FLOAT')).to.equal('-50.89');
+    });
+
+    it('should respect FLOAT precision', function () {
+      expect(formatMeasureVariation(0.1, 'FLOAT')).to.equal('+0.1');
+      expect(formatMeasureVariation(0.12, 'FLOAT')).to.equal('+0.12');
+      expect(formatMeasureVariation(0.12345, 'FLOAT')).to.equal('+0.12345');
+      expect(formatMeasureVariation(0.123456, 'FLOAT')).to.equal('+0.12346');
+    });
+
+    it('should format PERCENT', function () {
+      expect(formatMeasureVariation(0.0, 'PERCENT')).to.equal('+0.0%');
+      expect(formatMeasureVariation(1.0, 'PERCENT')).to.equal('+1.0%');
+      expect(formatMeasureVariation(-1.0, 'PERCENT')).to.equal('-1.0%');
+      expect(formatMeasureVariation(50.89, 'PERCENT')).to.equal('+50.9%');
+      expect(formatMeasureVariation(-50.89, 'PERCENT')).to.equal('-50.9%');
+    });
+
+    it('should format WORK_DUR', function () {
+      expect(formatMeasureVariation(0, 'WORK_DUR')).to.equal('+0');
+      expect(formatMeasureVariation(5 * ONE_DAY, 'WORK_DUR')).to.equal('+5d');
+      expect(formatMeasureVariation(2 * ONE_HOUR, 'WORK_DUR')).to.equal('+2h');
+      expect(formatMeasureVariation(ONE_MINUTE, 'WORK_DUR')).to.equal('+1min');
+      expect(formatMeasureVariation(-5 * ONE_DAY, 'WORK_DUR')).to.equal('-5d');
+      expect(formatMeasureVariation(-2 * ONE_HOUR, 'WORK_DUR')).to.equal('-2h');
+      expect(formatMeasureVariation(-1 * ONE_MINUTE, 'WORK_DUR')).to.equal('-1min');
+    });
+
+    it('should format SHORT_WORK_DUR', function () {
+      expect(formatMeasureVariation(0, 'SHORT_WORK_DUR')).to.equal('+0');
+      expect(formatMeasureVariation(5 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('+5d');
+      expect(formatMeasureVariation(2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('+2h');
+      expect(formatMeasureVariation(ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('+1min');
+      expect(formatMeasureVariation(5 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('+5d');
+      expect(formatMeasureVariation(2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('+2h');
+      expect(formatMeasureVariation(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('+5d');
+      expect(formatMeasureVariation(15 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('+15d');
+      expect(formatMeasureVariation(7 * ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('+7min');
+      expect(formatMeasureVariation(-5 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('-5d');
+      expect(formatMeasureVariation(-2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('-2h');
+      expect(formatMeasureVariation(-1 * ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('-1min');
+
+      expect(formatMeasureVariation(1529 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('+1.5kd');
+      expect(formatMeasureVariation(1234567 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('+1md');
+      expect(formatMeasureVariation(1234567 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('+1md');
+    });
+
+    it('should not format unknown type', function () {
+      expect(formatMeasureVariation('random value', 'RANDOM_TYPE')).to.equal('random value');
+    });
+
+    it('should not fail without parameters', function () {
+      expect(formatMeasureVariation()).to.be.null;
+    });
+  });
+});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/path-test.js b/server/sonar-web/src/main/js/helpers/__tests__/path-test.js
new file mode 100644 (file)
index 0000000..cdd4fb8
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { expect } from 'chai';
+import { collapsedDirFromPath, fileFromPath } from '../path';
+
+describe('Path', function () {
+  describe('#collapsedDirFromPath()', function () {
+    it('should return null when pass null', function () {
+      expect(collapsedDirFromPath(null)).to.be.null;
+    });
+
+    it('should return "/" when pass "/"', function () {
+      expect(collapsedDirFromPath('/')).to.equal('/');
+    });
+
+    it('should not cut short path', function () {
+      expect(collapsedDirFromPath('src/main/js/components/state.js')).to.equal('src/main/js/components/');
+    });
+
+    it('should cut long path', function () {
+      expect(collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js'))
+          .to.equal('src/.../js/components/navigator/app/models/');
+    });
+
+    it('should cut very long path', function () {
+      expect(collapsedDirFromPath('src/main/another/js/components/navigator/app/models/state.js'))
+          .to.equal('src/.../js/components/navigator/app/models/');
+    });
+  });
+
+  describe('#fileFromPath()', function () {
+    it('should return null when pass null', function () {
+      expect(fileFromPath(null)).to.be.null;
+    });
+
+    it('should return empty string when pass "/"', function () {
+      expect(fileFromPath('/')).to.equal('');
+    });
+
+    it('should return file name when pass only file name', function () {
+      expect(fileFromPath('file.js')).to.equal('file.js');
+    });
+
+    it('should return file name when pass file path', function () {
+      expect(fileFromPath('src/main/js/file.js')).to.equal('file.js');
+    });
+
+    it('should return file name when pass file name without extension', function () {
+      expect(fileFromPath('src/main/file')).to.equal('file');
+    });
+  });
+});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/urls-test.js b/server/sonar-web/src/main/js/helpers/__tests__/urls-test.js
new file mode 100644 (file)
index 0000000..293b863
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { expect } from 'chai';
+
+import { getComponentUrl, getComponentIssuesUrl, getComponentDrilldownUrl } from '../urls';
+
+const SIMPLE_COMPONENT_KEY = 'sonarqube';
+const COMPLEX_COMPONENT_KEY = 'org.sonarsource.sonarqube:sonarqube';
+const COMPLEX_COMPONENT_KEY_ENCODED = encodeURIComponent(COMPLEX_COMPONENT_KEY);
+const METRIC = 'coverage';
+
+describe('URLs', function () {
+  let oldBaseUrl;
+
+  beforeEach(function () {
+    oldBaseUrl = window.baseUrl;
+  });
+
+  afterEach(function () {
+    window.baseUrl = oldBaseUrl;
+  });
+
+  describe('#getComponentUrl', function () {
+    it('should return component url', function () {
+      expect(getComponentUrl(SIMPLE_COMPONENT_KEY)).to.equal('/dashboard?id=' + SIMPLE_COMPONENT_KEY);
+    });
+
+    it('should encode component key', function () {
+      expect(getComponentUrl(COMPLEX_COMPONENT_KEY)).to.equal('/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED);
+    });
+
+    it('should take baseUrl into account', function () {
+      window.baseUrl = '/context';
+      expect(getComponentUrl(COMPLEX_COMPONENT_KEY)).to.equal('/context/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED);
+    });
+  });
+
+  describe('#getComponentIssuesUrl', function () {
+    it('should work without parameters', function () {
+      expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, {})).to.equal(
+          '/component_issues?id=' + SIMPLE_COMPONENT_KEY + '#');
+    });
+
+    it('should encode component key', function () {
+      expect(getComponentIssuesUrl(COMPLEX_COMPONENT_KEY, {})).to.equal(
+          '/component_issues?id=' + COMPLEX_COMPONENT_KEY_ENCODED + '#');
+    });
+
+    it('should work with parameters', function () {
+      expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, { resolved: 'false' })).to.equal(
+          '/component_issues?id=' + SIMPLE_COMPONENT_KEY + '#resolved=false');
+    });
+
+    it('should encode parameters', function () {
+      expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, { componentUuids: COMPLEX_COMPONENT_KEY })).to.equal(
+          '/component_issues?id=' + SIMPLE_COMPONENT_KEY + '#componentUuids=' + COMPLEX_COMPONENT_KEY_ENCODED);
+    });
+
+    it('should take baseUrl into account', function () {
+      window.baseUrl = '/context';
+      expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, {})).to.equal(
+          '/context/component_issues?id=' + SIMPLE_COMPONENT_KEY + '#');
+    });
+  });
+
+  describe('#getComponentDrilldownUrl', function () {
+    it('should return component drilldown url', function () {
+      expect(getComponentDrilldownUrl(SIMPLE_COMPONENT_KEY, METRIC)).to.equal(
+          '/component_measures/metric/' + METRIC + '?id=' + SIMPLE_COMPONENT_KEY);
+    });
+
+    it('should encode component key', function () {
+      expect(getComponentDrilldownUrl(COMPLEX_COMPONENT_KEY, METRIC)).to.equal(
+          '/component_measures/metric/' + METRIC + '?id=' + COMPLEX_COMPONENT_KEY_ENCODED);
+    });
+
+    it('should take baseUrl into account', function () {
+      window.baseUrl = '/context';
+      expect(getComponentDrilldownUrl(SIMPLE_COMPONENT_KEY, METRIC)).to.equal(
+          '/context/component_measures/metric/' + METRIC + '?id=' + SIMPLE_COMPONENT_KEY);
+    });
+  });
+});
diff --git a/server/sonar-web/src/main/js/main/nav/__tests__/nav-test.js b/server/sonar-web/src/main/js/main/nav/__tests__/nav-test.js
new file mode 100644 (file)
index 0000000..f9b88a7
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import React from 'react';
+import TestUtils from 'react-addons-test-utils';
+import { expect } from 'chai';
+
+import ComponentNavBreadcrumbs from '../component/component-nav-breadcrumbs';
+
+describe('Nav', function () {
+  describe('ComponentNavBreadcrumbs', () => {
+    it('should not render breadcrumbs with one element', function () {
+      const breadcrumbs = [
+        { key: 'my-project', name: 'My Project', qualifier: 'TRK' }
+      ];
+      const result = TestUtils.renderIntoDocument(
+          React.createElement(ComponentNavBreadcrumbs, { breadcrumbs })
+      );
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'li')).to.have.length(1);
+      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'a')).to.have.length(1);
+    });
+  });
+});
diff --git a/server/sonar-web/tests/apps/background-tasks-test.js b/server/sonar-web/tests/apps/background-tasks-test.js
deleted file mode 100644 (file)
index acb38eb..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/* eslint no-unused-expressions: 0 */
-import React from 'react';
-import ReactDOM from 'react-dom';
-import TestUtils from 'react-addons-test-utils';
-
-import Header from '../../src/main/js/apps/background-tasks/components/Header';
-import Stats from '../../src/main/js/apps/background-tasks/components/Stats';
-import Search from '../../src/main/js/apps/background-tasks/components/Search';
-import Tasks from '../../src/main/js/apps/background-tasks/components/Tasks';
-import { STATUSES, CURRENTS, DEBOUNCE_DELAY, DEFAULT_FILTERS } from '../../src/main/js/apps/background-tasks/constants';
-import { formatDuration } from '../../src/main/js/apps/background-tasks/utils';
-
-let chai = require('chai');
-let expect = chai.expect;
-let sinon = require('sinon');
-chai.use(require('sinon-chai'));
-
-describe('Background Tasks', function () {
-  describe('Constants', () => {
-    it('should have STATUSES', () => {
-      expect(STATUSES).to.be.a('object');
-      expect(Object.keys(STATUSES).length).to.equal(7);
-    });
-
-    it('should have CURRENTS', () => {
-      expect(CURRENTS).to.be.a('object');
-      expect(Object.keys(CURRENTS).length).to.equal(2);
-    });
-  });
-
-  describe('Search', () => {
-    const defaultProps = {
-      ...DEFAULT_FILTERS,
-      loading: false,
-      types: [],
-      onFilterUpdate: () => true,
-      onReload: () => true
-    };
-
-    it('should render search form', () => {
-      let component = TestUtils.renderIntoDocument(
-          <Search {...defaultProps}/>
-      );
-      let searchBox = TestUtils.scryRenderedDOMComponentsWithClass(component, 'js-search');
-      expect(searchBox).to.have.length(1);
-    });
-
-    it('should not render search form', () => {
-      let component = TestUtils.renderIntoDocument(
-          <Search {...defaultProps} component={{ id: 'ABCD' }}/>
-      );
-      let searchBox = TestUtils.scryRenderedDOMComponentsWithClass(component, 'js-search');
-      expect(searchBox).to.be.empty;
-    });
-
-    it('should search', (done) => {
-      let searchSpy = sinon.spy();
-      let component = TestUtils.renderIntoDocument(
-          <Search {...defaultProps} onFilterUpdate={searchSpy}/>);
-      let searchInput = ReactDOM.findDOMNode(
-          TestUtils.findRenderedDOMComponentWithClass(component, 'js-search'));
-      searchInput.value = 'some search query';
-      TestUtils.Simulate.change(searchInput);
-      setTimeout(() => {
-        expect(searchSpy).to.have.been.calledWith({ query: "some search query" });
-        done();
-      }, DEBOUNCE_DELAY);
-    });
-
-    it('should reload', () => {
-      let reloadSpy = sinon.spy();
-      let component = TestUtils.renderIntoDocument(
-          <Search {...defaultProps} onReload={reloadSpy}/>
-      );
-      let reloadButton = component.refs.reloadButton;
-      expect(reloadSpy).to.not.have.been.called;
-      TestUtils.Simulate.click(reloadButton);
-      expect(reloadSpy).to.have.been.called;
-    });
-  });
-
-  describe('Stats', () => {
-    describe('Pending', () => {
-      it('should show zero pending', () => {
-        let result = TestUtils.renderIntoDocument(<Stats pendingCount={0}/>);
-        let pendingCounter = result.refs.pendingCount;
-        expect(pendingCounter.textContent).to.contain('0');
-      });
-
-      it('should show 5 pending', () => {
-        let result = TestUtils.renderIntoDocument(<Stats pendingCount={5}/>);
-        let pendingCounter = result.refs.pendingCount;
-        expect(pendingCounter.textContent).to.contain('5');
-      });
-
-      it('should not show cancel pending button', () => {
-        let result = TestUtils.renderIntoDocument(<Stats pendingCount={0}/>);
-        let cancelPending = result.refs.cancelPending;
-        expect(cancelPending).to.not.be.ok;
-      });
-
-      it('should show cancel pending button', () => {
-        let result = TestUtils.renderIntoDocument(<Stats pendingCount={5}/>);
-        let cancelPending = result.refs.cancelPending;
-        expect(cancelPending).to.be.ok;
-      });
-
-      it('should trigger cancelling pending', () => {
-        let spy = sinon.spy();
-        let result = TestUtils.renderIntoDocument(<Stats pendingCount={5} onCancelAllPending={spy}/>);
-        let cancelPending = result.refs.cancelPending;
-        expect(spy).to.not.have.been.called;
-        TestUtils.Simulate.click(cancelPending);
-        expect(spy).to.have.been.called;
-      });
-    });
-
-    describe('Failures', () => {
-      it('should show zero failures', () => {
-        let result = TestUtils.renderIntoDocument(<Stats failingCount={0}/>);
-        let failureCounter = result.refs.failureCount;
-        expect(failureCounter.textContent).to.contain('0');
-      });
-
-      it('should show 5 failures', () => {
-        let result = TestUtils.renderIntoDocument(<Stats failingCount={5}/>);
-        let failureCounter = result.refs.failureCount;
-        expect(failureCounter.textContent).to.contain('5');
-      });
-
-      it('should not show link to failures', () => {
-        let result = TestUtils.renderIntoDocument(<Stats failingCount={0}/>);
-        let failureCounter = result.refs.failureCount;
-        expect(failureCounter.tagName.toLowerCase()).to.not.equal('a');
-      });
-
-      it('should show link to failures', () => {
-        let result = TestUtils.renderIntoDocument(<Stats failingCount={5}/>);
-        let failureCounter = result.refs.failureCount;
-        expect(failureCounter.tagName.toLowerCase()).to.equal('a');
-      });
-
-      it('should trigger filtering failures', () => {
-        let spy = sinon.spy();
-        let result = TestUtils.renderIntoDocument(<Stats failingCount={5} onShowFailing={spy}/>);
-        let failureCounter = result.refs.failureCount;
-        expect(spy).to.not.have.been.called;
-        TestUtils.Simulate.click(failureCounter);
-        expect(spy).to.have.been.called;
-      });
-    });
-  });
-
-  describe('Helpers', () => {
-    describe('#formatDuration()', () => {
-      it('should format 173ms', () => {
-        expect(formatDuration(173)).to.equal('173ms');
-      });
-
-      it('should format 999ms', () => {
-        expect(formatDuration(999)).to.equal('999ms');
-      });
-
-      it('should format 1s', () => {
-        expect(formatDuration(1000)).to.equal('1s');
-      });
-
-      it('should format 1s', () => {
-        expect(formatDuration(1001)).to.equal('1s');
-      });
-
-      it('should format 2s', () => {
-        expect(formatDuration(1501)).to.equal('2s');
-      });
-
-      it('should format 59s', () => {
-        expect(formatDuration(59000)).to.equal('59s');
-      });
-
-      it('should format 1min', () => {
-        expect(formatDuration(60000)).to.equal('1min');
-      });
-
-      it('should format 1min', () => {
-        expect(formatDuration(62757)).to.equal('1min');
-      });
-
-      it('should format 4min', () => {
-        expect(formatDuration(224567)).to.equal('4min');
-      });
-
-      it('should format 80min', () => {
-        expect(formatDuration(80 * 60 * 1000)).to.equal('80min');
-      });
-    });
-  });
-});
diff --git a/server/sonar-web/tests/apps/overview/components/App-test.js b/server/sonar-web/tests/apps/overview/components/App-test.js
deleted file mode 100644 (file)
index 0848891..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { expect } from 'chai';
-import { shallow } from 'enzyme';
-
-import App from '../../../../src/main/js/apps/overview/components/App';
-import OverviewApp from '../../../../src/main/js/apps/overview/components/OverviewApp';
-import EmptyOverview from '../../../../src/main/js/apps/overview/components/EmptyOverview';
-
-describe('Overview :: App', () => {
-  it('should render OverviewApp', () => {
-    const component = {
-      id: 'id',
-      snapshotDate: '2016-01-01'
-    };
-
-    const output = shallow(
-        <App component={component}/>
-    );
-
-    expect(output.type())
-        .to.equal(OverviewApp);
-  });
-
-  it('should render EmptyOverview', () => {
-    const component = { id: 'id' };
-
-    const output = shallow(
-        <App component={component}/>
-    );
-
-    expect(output.type())
-        .to.equal(EmptyOverview);
-  });
-
-  it('should pass leakPeriodIndex', () => {
-    const component = {
-      id: 'id',
-      snapshotDate: '2016-01-01'
-    };
-
-    const output = shallow(
-        <App component={component}/>
-    );
-
-    expect(output.prop('leakPeriodIndex'))
-        .to.equal('1');
-  });
-});
diff --git a/server/sonar-web/tests/apps/overview/components/EmptyOverview-test.js b/server/sonar-web/tests/apps/overview/components/EmptyOverview-test.js
deleted file mode 100644 (file)
index 65a1c0d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { expect } from 'chai';
-import { shallow } from 'enzyme';
-
-import EmptyOverview from '../../../../src/main/js/apps/overview/components/EmptyOverview';
-
-describe('Overview :: EmptyOverview', () => {
-  it('should render component key', () => {
-    const component = {
-      id: 'id',
-      key: 'abcd',
-      snapshotDate: '2016-01-01'
-    };
-
-    const output = shallow(
-        <EmptyOverview component={component}/>
-    );
-
-    expect(output.find('code').text())
-        .to.equal('abcd');
-  });
-});
diff --git a/server/sonar-web/tests/apps/overview/qualityGate/QualityGateCondition-test.js b/server/sonar-web/tests/apps/overview/qualityGate/QualityGateCondition-test.js
deleted file mode 100644 (file)
index 3f0e924..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { expect } from 'chai';
-import { shallow } from 'enzyme';
-
-import QualityGateCondition from '../../../../src/main/js/apps/overview/qualityGate/QualityGateCondition';
-import { DrilldownLink } from '../../../../src/main/js/components/shared/drilldown-link';
-
-describe('Overview :: QualityGateCondition', () => {
-  it('should render DrilldownLink', () => {
-    const component = {
-      id: 'abcd',
-      key: 'abcd-key'
-    };
-    const periods = [];
-    const condition = {
-      actual: '10',
-      error: '0',
-      level: 'ERROR',
-      measure: {
-        metric: {
-          key: 'open_issues',
-          type: 'INT',
-          name: 'Open Issues'
-        },
-        value: '10'
-      },
-      metric: 'open_issues',
-      op: 'GT'
-    };
-
-    const output = shallow(
-        <QualityGateCondition
-            component={component}
-            periods={periods}
-            condition={condition}/>
-    );
-
-    const link = output.find(DrilldownLink);
-    expect(link.prop('component')).to.equal('abcd-key');
-    expect(link.prop('metric')).to.equal('open_issues');
-  });
-});
diff --git a/server/sonar-web/tests/apps/permission-templates-test.js b/server/sonar-web/tests/apps/permission-templates-test.js
deleted file mode 100644 (file)
index be99e6f..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/* eslint no-unused-expressions: 0 */
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-
-import Defaults from '../../src/main/js/apps/permission-templates/permission-template-defaults';
-import SetDefaults from '../../src/main/js/apps/permission-templates/permission-template-set-defaults';
-
-let expect = require('chai').expect;
-let sinon = require('sinon');
-
-describe('Permission Templates', function () {
-  describe('Defaults', () => {
-    it('should display one qualifier', () => {
-      let permissionTemplate = { defaultFor: ['VW'] },
-          topQualifiers = ['TRK', 'VW'];
-      let result = TestUtils.renderIntoDocument(
-          <Defaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers}/>
-      );
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-trk')).to.be.empty;
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-vw')).to.have.length(1);
-    });
-
-    it('should display two qualifiers', () => {
-      let permissionTemplate = { defaultFor: ['TRK', 'VW'] },
-          topQualifiers = ['TRK', 'VW'];
-      let result = TestUtils.renderIntoDocument(
-          <Defaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers}/>
-      );
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-trk')).to.have.length(1);
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-vw')).to.have.length(1);
-    });
-
-    it('should not display qualifiers', () => {
-      let permissionTemplate = { defaultFor: [] },
-          topQualifiers = ['TRK', 'VW'];
-      let result = TestUtils.renderIntoDocument(
-          <Defaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers}/>
-      );
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-trk')).to.be.empty;
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-vw')).to.be.empty;
-    });
-
-    it('should omit "project" if there is only one qualifier', () => {
-      let permissionTemplate = { defaultFor: ['TRK'] },
-          topQualifiers = ['TRK'];
-      let result = TestUtils.renderIntoDocument(
-          <Defaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers}/>
-      );
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-qualifier-trk')).to.be.empty;
-    });
-  });
-
-  describe('SetDefaults', () => {
-    var refresh = sinon.spy();
-
-    it('should display a dropdown with one option', () => {
-      let permissionTemplate = { defaultFor: ['VW'] },
-          topQualifiers = ['TRK', 'VW'];
-      let result = TestUtils.renderIntoDocument(
-          <SetDefaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers} refresh={refresh}/>
-      );
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'dropdown')).to.have.length(1);
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'a')).to.have.length(1);
-    });
-
-    it('should display a dropdown with two options', () => {
-      let permissionTemplate = { defaultFor: [] },
-          topQualifiers = ['TRK', 'VW'];
-      let result = TestUtils.renderIntoDocument(
-          <SetDefaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers} refresh={refresh}/>
-      );
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'dropdown')).to.have.length(1);
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'a')).to.have.length(2);
-    });
-
-    it('should not display a dropdown', () => {
-      let permissionTemplate = { defaultFor: ['TRK', 'VW'] },
-          topQualifiers = ['TRK', 'VW'];
-      let result = TestUtils.renderIntoDocument(
-          <SetDefaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers} refresh={refresh}/>
-      );
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'dropdown')).to.be.empty;
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'a')).to.be.empty;
-    });
-
-    it('should omit dropdown if there is only one qualifier', () => {
-      let permissionTemplate = { defaultFor: [] },
-          topQualifiers = ['TRK'];
-      let result = TestUtils.renderIntoDocument(
-          <SetDefaults permissionTemplate={permissionTemplate} topQualifiers={topQualifiers} refresh={refresh}/>
-      );
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'dropdown')).to.be.empty;
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'a')).to.have.length(1);
-    });
-  });
-});
diff --git a/server/sonar-web/tests/apps/projects-test.js b/server/sonar-web/tests/apps/projects-test.js
deleted file mode 100644 (file)
index 3fb1768..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-
-import Projects from '../../src/main/js/apps/projects/projects';
-
-let expect = require('chai').expect;
-let sinon = require('sinon');
-
-describe('Projects', function () {
-  describe('Projects', () => {
-    it('should render list of projects with no selection', () => {
-      let projects = [
-        { id: '1', key: 'a', name: 'A', qualifier: 'TRK' },
-        { id: '2', key: 'b', name: 'B', qualifier: 'TRK' }
-      ];
-
-      let result = TestUtils.renderIntoDocument(
-          <Projects projects={projects} selection={[]} refresh={sinon.spy()}/>);
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'tr')).to.have.length(2);
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-checkbox-checked')).to.be.empty;
-    });
-
-    it('should render list of projects with one selected', () => {
-      let projects = [
-            { id: '1', key: 'a', name: 'A', qualifier: 'TRK' },
-            { id: '2', key: 'b', name: 'B', qualifier: 'TRK' }
-          ],
-          selection = ['1'];
-
-      let result = TestUtils.renderIntoDocument(
-          <Projects projects={projects} selection={selection} refresh={sinon.spy()}/>);
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'tr')).to.have.length(2);
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'icon-checkbox-checked')).to.have.length(1);
-    });
-  });
-});
diff --git a/server/sonar-web/tests/apps/system-test.js b/server/sonar-web/tests/apps/system-test.js
deleted file mode 100644 (file)
index a7a9c52..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import TestUtils from 'react-addons-test-utils';
-
-import ItemValue from '../../src/main/js/apps/system/item-value';
-
-let expect = require('chai').expect;
-let sinon = require('sinon');
-
-describe('System', function () {
-
-  describe('Item Value', function () {
-    it('should render string', () => {
-      let result = TestUtils.renderIntoDocument(<ItemValue value="/some/path/as/an/example"/>);
-      let content = ReactDOM.findDOMNode(TestUtils.findRenderedDOMComponentWithTag(result, 'code'));
-      expect(content.textContent).to.equal('/some/path/as/an/example');
-    });
-
-    it('should render `true`', () => {
-      let result = TestUtils.renderIntoDocument(<ItemValue value={true}/>);
-      TestUtils.findRenderedDOMComponentWithClass(result, 'icon-check');
-    });
-
-    it('should render `false`', () => {
-      let result = TestUtils.renderIntoDocument(<ItemValue value={false}/>);
-      TestUtils.findRenderedDOMComponentWithClass(result, 'icon-delete');
-    });
-
-    it('should render object', () => {
-      let result = TestUtils.renderIntoDocument(<ItemValue value={{ name: 'Java', version: '3.2' }}/>);
-      TestUtils.findRenderedDOMComponentWithTag(result, 'table');
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'tr')).to.have.length(2);
-    });
-
-    it('should render `true` inside object', () => {
-      let result = TestUtils.renderIntoDocument(<ItemValue value={{ name: 'Java', isCool: true }}/>);
-      TestUtils.findRenderedDOMComponentWithTag(result, 'table');
-      TestUtils.findRenderedDOMComponentWithClass(result, 'icon-check');
-    });
-
-    it('should render object inside object', () => {
-      let result = TestUtils.renderIntoDocument(
-          <ItemValue value={{ users: { docs: 1, shards: 5 }, tests: { docs: 68, shards: 5 }  }}/>);
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'table')).to.have.length(3);
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'tr')).to.have.length(6);
-    });
-  });
-
-  describe('Log Level', function () {
-    var previousFetch, fetchUrl, fetchOptions;
-
-    before(function () {
-      previousFetch = window.fetch;
-      window.fetch = function (url, options) {
-        fetchUrl = url;
-        fetchOptions = options;
-        return Promise.resolve();
-      };
-    });
-
-    after(function () {
-      window.fetch = previousFetch;
-    });
-
-    it('should render select box', () => {
-      let result = TestUtils.renderIntoDocument(<ItemValue value="INFO" name="Logs Level"/>);
-      TestUtils.findRenderedDOMComponentWithTag(result, 'select');
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'option')).to.have.length(3);
-    });
-
-    it('should set initial value', () => {
-      let result = TestUtils.renderIntoDocument(<ItemValue value="DEBUG" name="Logs Level"/>);
-      let select = ReactDOM.findDOMNode(TestUtils.findRenderedDOMComponentWithTag(result, 'select'));
-      expect(select.value).to.equal('DEBUG');
-    });
-
-    it('should render warning', () => {
-      let result = TestUtils.renderIntoDocument(<ItemValue value="DEBUG" name="Logs Level"/>);
-      TestUtils.findRenderedDOMComponentWithClass(result, 'alert');
-    });
-
-    it('should not render warning', () => {
-      let result = TestUtils.renderIntoDocument(<ItemValue value="INFO" name="Logs Level"/>);
-      expect(TestUtils.scryRenderedDOMComponentsWithClass(result, 'alert')).to.be.empty;
-    });
-
-    it('should change value', () => {
-      let result = TestUtils.renderIntoDocument(<ItemValue value="INFO" name="Logs Level"/>);
-      let select = ReactDOM.findDOMNode(TestUtils.findRenderedDOMComponentWithTag(result, 'select'));
-      select.value = 'TRACE';
-      TestUtils.Simulate.change(select);
-      expect(fetchUrl).to.equal('/api/system/change_log_level');
-      expect(fetchOptions.method).to.equal('POST');
-      expect(fetchOptions.body).to.equal('level=TRACE');
-    });
-  });
-
-});
diff --git a/server/sonar-web/tests/components/charts/bar-chart-test.js b/server/sonar-web/tests/components/charts/bar-chart-test.js
deleted file mode 100644 (file)
index e56497e..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-import { expect } from 'chai';
-
-import { BarChart } from '../../../src/main/js/components/charts/bar-chart';
-
-
-describe('Bar Chart', function () {
-
-  it('should display bars', function () {
-    const data = [
-      { x: 1, y: 10 },
-      { x: 2, y: 30 },
-      { x: 3, y: 20 }
-    ];
-    let chart = TestUtils.renderIntoDocument(<BarChart data={data} width={100} height={100} barsWidth={20}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bar-chart-bar')).to.have.length(3);
-  });
-
-  it('should display ticks', function () {
-    const data = [
-      { x: 1, y: 10 },
-      { x: 2, y: 30 },
-      { x: 3, y: 20 }
-    ];
-    const ticks = ['A', 'B', 'C'];
-    let chart = TestUtils.renderIntoDocument(<BarChart data={data} xTicks={ticks} width={100} height={100} barsWidth={20}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bar-chart-tick')).to.have.length(3);
-  });
-
-  it('should display values', function () {
-    const data = [
-      { x: 1, y: 10 },
-      { x: 2, y: 30 },
-      { x: 3, y: 20 }
-    ];
-    const values = ['A', 'B', 'C'];
-    let chart = TestUtils.renderIntoDocument(<BarChart data={data} xValues={values} width={100} height={100} barsWidth={20}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bar-chart-tick')).to.have.length(3);
-  });
-
-  it('should display bars, ticks and values', function () {
-    const data = [
-      { x: 1, y: 10 },
-      { x: 2, y: 30 },
-      { x: 3, y: 20 }
-    ];
-    const ticks = ['A', 'B', 'C'];
-    const values = ['A', 'B', 'C'];
-    let chart = TestUtils.renderIntoDocument(
-        <BarChart data={data} xTicks={ticks} xValues={values} width={100} height={100} barsWidth={20}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bar-chart-bar')).to.have.length(3);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bar-chart-tick')).to.have.length(6);
-  });
-
-});
diff --git a/server/sonar-web/tests/components/charts/bubble-chart-test.js b/server/sonar-web/tests/components/charts/bubble-chart-test.js
deleted file mode 100644 (file)
index f9994ea..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-import { expect } from 'chai';
-
-import { BubbleChart } from '../../../src/main/js/components/charts/bubble-chart';
-
-
-describe('Bubble Chart', function () {
-
-  it('should display bubbles', function () {
-    const items = [
-      { x: 1, y: 10, size: 7 },
-      { x: 2, y: 30, size: 5 },
-      { x: 3, y: 20, size: 2 }
-    ];
-    let chart = TestUtils.renderIntoDocument(<BubbleChart items={items} width={100} height={100}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bubble-chart-bubble')).to.have.length(3);
-  });
-
-  it('should display grid', function () {
-    const items = [
-      { x: 1, y: 10, size: 7 },
-      { x: 2, y: 30, size: 5 },
-      { x: 3, y: 20, size: 2 }
-    ];
-    let chart = TestUtils.renderIntoDocument(<BubbleChart items={items} width={100} height={100}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithTag(chart, 'line')).to.not.be.empty;
-  });
-
-  it('should display ticks', function () {
-    const items = [
-      { x: 1, y: 10, size: 7 },
-      { x: 2, y: 30, size: 5 },
-      { x: 3, y: 20, size: 2 }
-    ];
-    let chart = TestUtils.renderIntoDocument(<BubbleChart items={items} width={100} height={100}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'bubble-chart-tick')).to.not.be.empty;
-  });
-
-});
diff --git a/server/sonar-web/tests/components/charts/line-chart-test.js b/server/sonar-web/tests/components/charts/line-chart-test.js
deleted file mode 100644 (file)
index 5e6ee41..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-import { expect } from 'chai';
-
-import { LineChart } from '../../../src/main/js/components/charts/line-chart';
-
-
-describe('Line Chart', function () {
-
-  it('should display line', function () {
-    const data = [
-      { x: 1, y: 10 },
-      { x: 2, y: 30 },
-      { x: 3, y: 20 }
-    ];
-    let chart = TestUtils.renderIntoDocument(<LineChart data={data} width={100} height={100}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'line-chart-path')).to.have.length(1);
-  });
-
-  it('should display ticks', function () {
-    const data = [
-      { x: 1, y: 10 },
-      { x: 2, y: 30 },
-      { x: 3, y: 20 }
-    ];
-    const ticks = ['A', 'B', 'C'];
-    let chart = TestUtils.renderIntoDocument(<LineChart data={data} xTicks={ticks} width={100} height={100}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'line-chart-tick')).to.have.length(3);
-  });
-
-  it('should display values', function () {
-    const data = [
-      { x: 1, y: 10 },
-      { x: 2, y: 30 },
-      { x: 3, y: 20 }
-    ];
-    const values = ['A', 'B', 'C'];
-    let chart = TestUtils.renderIntoDocument(<LineChart data={data} xValues={values} width={100} height={100}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'line-chart-tick')).to.have.length(3);
-  });
-
-});
diff --git a/server/sonar-web/tests/components/charts/treemap-test.js b/server/sonar-web/tests/components/charts/treemap-test.js
deleted file mode 100644 (file)
index 3200db3..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-import { expect } from 'chai';
-
-import { Treemap } from '../../../src/main/js/components/charts/treemap';
-
-
-describe('Treemap', function () {
-
-  it('should display', function () {
-    const items = [
-      { size: 10, color: '#777', label: 'SonarQube :: Server' },
-      { size: 30, color: '#777', label: 'SonarQube :: Web' },
-      { size: 20, color: '#777', label: 'SonarQube :: Search' }
-    ];
-    let chart = TestUtils.renderIntoDocument(
-        <Treemap items={items} width={100} height={100} breadcrumbs={[]} canBeClicked={() => true}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithClass(chart, 'treemap-cell')).to.have.length(3);
-  });
-
-});
diff --git a/server/sonar-web/tests/components/charts/work-cloud-test.js b/server/sonar-web/tests/components/charts/work-cloud-test.js
deleted file mode 100644 (file)
index 4bdafe1..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-import { expect } from 'chai';
-
-import { WordCloud } from '../../../src/main/js/components/charts/word-cloud';
-
-
-describe('Word Cloud', function () {
-
-  it('should display', function () {
-    const items = [
-      { size: 10, link: '#', text: 'SonarQube :: Server' },
-      { size: 30, link: '#', text: 'SonarQube :: Web' },
-      { size: 20, link: '#', text: 'SonarQube :: Search' }
-    ];
-    let chart = TestUtils.renderIntoDocument(<WordCloud items={items} width={100} height={100}/>);
-    expect(TestUtils.scryRenderedDOMComponentsWithTag(chart, 'a')).to.have.length(3);
-  });
-
-});
diff --git a/server/sonar-web/tests/components/issue-test.js b/server/sonar-web/tests/components/issue-test.js
deleted file mode 100644 (file)
index 34b0312..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-import Issue from '../../src/main/js/components/issue/models/issue';
-
-let sinon = require('sinon'),
-    sinonChai = require('sinon-chai'),
-    chai = require('chai'),
-    expect = chai.expect;
-
-chai.use(sinonChai);
-
-describe('Issue', function () {
-  describe('Model', function () {
-    it('should have correct urlRoot', function () {
-      var issue = new Issue();
-      expect(issue.urlRoot()).to.equal('/api/issues');
-    });
-
-    it('should parse response without root issue object', function () {
-      var issue = new Issue();
-      var example = { a: 1 };
-      expect(issue.parse(example)).to.deep.equal(example);
-    });
-
-    it('should parse response with the root issue object', function () {
-      var issue = new Issue();
-      var example = { a: 1 };
-      expect(issue.parse({ issue: example })).to.deep.equal(example);
-    });
-
-    it('should reset attributes (no attributes initially)', function () {
-      var issue = new Issue();
-      var example = { a: 1 };
-      issue.reset(example);
-      expect(issue.toJSON()).to.deep.equal(example);
-    });
-
-    it('should reset attributes (override attribute)', function () {
-      var issue = new Issue({ a: 2 });
-      var example = { a: 1 };
-      issue.reset(example);
-      expect(issue.toJSON()).to.deep.equal(example);
-    });
-
-    it('should reset attributes (different attributes)', function () {
-      var issue = new Issue({ a: 2 });
-      var example = { b: 1 };
-      issue.reset(example);
-      expect(issue.toJSON()).to.deep.equal(example);
-    });
-
-    it('should unset `textRange` of a closed issue', function () {
-      var issue = new Issue();
-      var result = issue.parse({ issue: { status: 'CLOSED', textRange: { startLine: 5 } } });
-      expect(result.textRange).to.not.be.ok;
-    });
-
-    it('should unset `flows` of a closed issue', function () {
-      var issue = new Issue();
-      var result = issue.parse({ issue: { status: 'CLOSED', flows: [1, 2, 3] } });
-      expect(result.flows).to.deep.equal([]);
-    });
-
-    describe('Actions', function () {
-      it('should assign', function () {
-        var issue = new Issue({ key: 'issue-key' });
-        var spy = sinon.spy();
-        issue._action = spy;
-        issue.assign('admin');
-        expect(spy).to.have.been.calledWith({
-          data: { assignee: 'admin', issue: 'issue-key' },
-          url: '/api/issues/assign'
-        });
-      });
-
-      it('should unassign', function () {
-        var issue = new Issue({ key: 'issue-key' });
-        var spy = sinon.spy();
-        issue._action = spy;
-        issue.assign();
-        expect(spy).to.have.been.calledWith({
-          data: { assignee: undefined, issue: 'issue-key' },
-          url: '/api/issues/assign'
-        });
-      });
-
-      it('should plan', function () {
-        var issue = new Issue({ key: 'issue-key' });
-        var spy = sinon.spy();
-        issue._action = spy;
-        issue.plan('plan');
-        expect(spy).to.have.been.calledWith({ data: { plan: 'plan', issue: 'issue-key' }, url: '/api/issues/plan' });
-      });
-
-      it('should unplan', function () {
-        var issue = new Issue({ key: 'issue-key' });
-        var spy = sinon.spy();
-        issue._action = spy;
-        issue.plan();
-        expect(spy).to.have.been.calledWith({ data: { plan: undefined, issue: 'issue-key' }, url: '/api/issues/plan' });
-      });
-
-      it('should set severity', function () {
-        var issue = new Issue({ key: 'issue-key' });
-        var spy = sinon.spy();
-        issue._action = spy;
-        issue.setSeverity('BLOCKER');
-        expect(spy).to.have.been.calledWith({
-          data: { severity: 'BLOCKER', issue: 'issue-key' },
-          url: '/api/issues/set_severity'
-        });
-      });
-    });
-
-    describe('#getLinearLocations', function () {
-      it('should return single line location', function () {
-        var issue = new Issue({ textRange: { startLine: 1, endLine: 1, startOffset: 0, endOffset: 10 } }),
-            locations = issue.getLinearLocations();
-        expect(locations.length).to.equal(1);
-
-        expect(locations[0].line).to.equal(1);
-        expect(locations[0].from).to.equal(0);
-        expect(locations[0].to).to.equal(10);
-      });
-
-      it('should return location not from 0', function () {
-        var issue = new Issue({ textRange: { startLine: 1, endLine: 1, startOffset: 5, endOffset: 10 } }),
-            locations = issue.getLinearLocations();
-        expect(locations.length).to.equal(1);
-
-        expect(locations[0].line).to.equal(1);
-        expect(locations[0].from).to.equal(5);
-        expect(locations[0].to).to.equal(10);
-      });
-
-      it('should return 2-lines location', function () {
-        var issue = new Issue({ textRange: { startLine: 2, endLine: 3, startOffset: 5, endOffset: 10 } }),
-            locations = issue.getLinearLocations();
-        expect(locations.length).to.equal(2);
-
-        expect(locations[0].line).to.equal(2);
-        expect(locations[0].from).to.equal(5);
-        expect(locations[0].to).to.equal(999999);
-
-        expect(locations[1].line).to.equal(3);
-        expect(locations[1].from).to.equal(0);
-        expect(locations[1].to).to.equal(10);
-      });
-
-      it('should return 3-lines location', function () {
-        var issue = new Issue({ textRange: { startLine: 4, endLine: 6, startOffset: 5, endOffset: 10 } }),
-            locations = issue.getLinearLocations();
-        expect(locations.length).to.equal(3);
-
-        expect(locations[0].line).to.equal(4);
-        expect(locations[0].from).to.equal(5);
-        expect(locations[0].to).to.equal(999999);
-
-        expect(locations[1].line).to.equal(5);
-        expect(locations[1].from).to.equal(0);
-        expect(locations[1].to).to.equal(999999);
-
-        expect(locations[2].line).to.equal(6);
-        expect(locations[2].from).to.equal(0);
-        expect(locations[2].to).to.equal(10);
-      });
-
-      it('should return [] when no location', function () {
-        var issue = new Issue(),
-            locations = issue.getLinearLocations();
-        expect(locations.length).to.equal(0);
-      });
-    });
-  });
-});
diff --git a/server/sonar-web/tests/components/source-viewer-test.js b/server/sonar-web/tests/components/source-viewer-test.js
deleted file mode 100644 (file)
index 1ee6fee..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-import helper from '../../src/main/js/components/source-viewer/helpers/code-with-issue-locations-helper';
-
-let expect = require('chai').expect;
-
-describe('Source Viewer', function () {
-  describe('Code With Issue Locations Helper', function () {
-    it('should be a function', function () {
-      expect(helper).to.be.a('function');
-    });
-
-    it('should mark one location', function () {
-      var code = '<span class="k">if</span> (<span class="sym-2 sym">a</span> + <span class="c">1</span>) {',
-          locations = [{ from: 1, to: 5 }],
-          result = helper(code, locations, 'x');
-      expect(result).to.equal([
-        '<span class="k">i</span>',
-        '<span class="k x">f</span>',
-        '<span class=" x"> (</span>',
-        '<span class="sym-2 sym x">a</span>',
-        '<span class=""> + </span>',
-        '<span class="c">1</span>',
-        '<span class="">) {</span>'
-      ].join(''));
-    });
-
-    it('should mark two locations', function () {
-      var code = 'abcdefghijklmnopqrst',
-          locations = [
-            { from: 1, to: 6 },
-            { from: 11, to: 16 }
-          ],
-          result = helper(code, locations, 'x');
-      expect(result).to.equal([
-        '<span class="">a</span>',
-        '<span class=" x">bcdef</span>',
-        '<span class="">ghijk</span>',
-        '<span class=" x">lmnop</span>',
-        '<span class="">qrst</span>'
-      ].join(''));
-    });
-
-    it('should mark one locations', function () {
-      var code = '<span class="cppd"> * Copyright (C) 2008-2014 SonarSource</span>',
-          locations = [{ from: 15, to: 20 }],
-          result = helper(code, locations, 'x');
-      expect(result).to.equal([
-        '<span class="cppd"> * Copyright (C</span>',
-        '<span class="cppd x">) 200</span>',
-        '<span class="cppd">8-2014 SonarSource</span>'
-      ].join(''));
-    });
-
-    it('should mark two locations', function () {
-      var code = '<span class="cppd"> * Copyright (C) 2008-2014 SonarSource</span>',
-          locations = [
-            { from: 24, to: 29 },
-            { from: 15, to: 20 }
-          ],
-          result = helper(code, locations, 'x');
-      expect(result).to.equal([
-        '<span class="cppd"> * Copyright (C</span>',
-        '<span class="cppd x">) 200</span>',
-        '<span class="cppd">8-20</span>',
-        '<span class="cppd x">14 So</span>',
-        '<span class="cppd">narSource</span>'
-      ].join(''));
-    });
-
-    it('should parse line with < and >', function () {
-      var code = '<span class="j">#include &lt;stdio.h&gt;</span>',
-          result = helper(code, []);
-      expect(result).to.equal('<span class="j">#include &lt;stdio.h&gt;</span>');
-    });
-
-    it('should parse syntax and usage highlighting', function () {
-      var code = '<span class="k"><span class="sym-3 sym">this</span></span>',
-          expected = '<span class="k sym-3 sym">this</span>',
-          result = helper(code, []);
-      expect(result).to.equal(expected);
-    });
-
-    it('should parse nested tags', function () {
-      var code = '<span class="k"><span class="sym-3 sym">this</span> is</span>',
-          expected = '<span class="k sym-3 sym">this</span><span class="k"> is</span>',
-          result = helper(code, []);
-      expect(result).to.equal(expected);
-    });
-  });
-});
-
diff --git a/server/sonar-web/tests/helpers/l10n-test.js b/server/sonar-web/tests/helpers/l10n-test.js
deleted file mode 100644 (file)
index 068cb5b..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-import { expect } from 'chai';
-import { resetBundle, translate, translateWithParameters } from '../../src/main/js/helpers/l10n';
-
-describe('l10n', () => {
-  afterEach(() => {
-    resetBundle({});
-  });
-
-  describe('#translate', () => {
-    it('should translate simple message', () => {
-      resetBundle({ 'my_key': 'my message' });
-      expect(translate('my_key')).to.equal('my message');
-    });
-
-    it('should translate message with composite key', () => {
-      resetBundle({ 'my.composite.message': 'my message' });
-      expect(translate('my', 'composite', 'message')).to.equal('my message');
-      expect(translate('my.composite', 'message')).to.equal('my message');
-      expect(translate('my', 'composite.message')).to.equal('my message');
-      expect(translate('my.composite.message')).to.equal('my message');
-    });
-
-    it('should not translate message but return its key', () => {
-      expect(translate('random')).to.equal('random');
-      expect(translate('random', 'key')).to.equal('random.key');
-      expect(translate('composite.random', 'key')).to.equal('composite.random.key');
-    });
-  });
-
-  describe('#translateWithParameters', () => {
-    it('should translate message with one parameter in the beginning', () => {
-      resetBundle({ 'x_apples': '{0} apples' });
-      expect(translateWithParameters('x_apples', 5)).to.equal('5 apples');
-    });
-
-    it('should translate message with one parameter in the middle', () => {
-      resetBundle({ 'x_apples': 'I have {0} apples' });
-      expect(translateWithParameters('x_apples', 5)).to.equal('I have 5 apples');
-    });
-
-    it('should translate message with one parameter in the end', () => {
-      resetBundle({ 'x_apples': 'Apples: {0}' });
-      expect(translateWithParameters('x_apples', 5)).to.equal('Apples: 5');
-    });
-
-    it('should translate message with several parameters', () => {
-      resetBundle({ 'x_apples': '{0}: I have {2} apples in my {1} baskets - {3}' });
-      expect(translateWithParameters('x_apples', 1, 2, 3, 4)).to.equal('1: I have 3 apples in my 2 baskets - 4');
-    });
-
-    it('should not translate message but return its key', () => {
-      expect(translateWithParameters('random', 5)).to.equal('random.5');
-      expect(translateWithParameters('random', 1, 2, 3)).to.equal('random.1.2.3');
-      expect(translateWithParameters('composite.random', 1, 2)).to.equal('composite.random.1.2');
-    });
-  });
-});
diff --git a/server/sonar-web/tests/helpers/measures-test.js b/server/sonar-web/tests/helpers/measures-test.js
deleted file mode 100644 (file)
index 0b27578..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-import { expect } from 'chai';
-
-import { resetBundle } from '../../src/main/js/helpers/l10n';
-import { formatMeasure, formatMeasureVariation } from '../../src/main/js/helpers/measures';
-
-
-describe('Measures', function () {
-  var HOURS_IN_DAY = 8,
-      ONE_MINUTE = 1,
-      ONE_HOUR = ONE_MINUTE * 60,
-      ONE_DAY = HOURS_IN_DAY * ONE_HOUR;
-
-  before(function () {
-    resetBundle({
-      'work_duration.x_days': '{0}d',
-      'work_duration.x_hours': '{0}h',
-      'work_duration.x_minutes': '{0}min',
-      'work_duration.about': '~ {0}',
-      'metric.level.ERROR': 'Error',
-      'metric.level.WARN': 'Warning',
-      'metric.level.OK': 'Ok'
-    });
-    window.SS = { hoursInDay: HOURS_IN_DAY };
-  });
-
-  describe('#formatMeasure()', function () {
-    it('should format INT', function () {
-      expect(formatMeasure(0, 'INT')).to.equal('0');
-      expect(formatMeasure(1, 'INT')).to.equal('1');
-      expect(formatMeasure(-5, 'INT')).to.equal('-5');
-      expect(formatMeasure(999, 'INT')).to.equal('999');
-      expect(formatMeasure(1000, 'INT')).to.equal('1,000');
-      expect(formatMeasure(1529, 'INT')).to.equal('1,529');
-      expect(formatMeasure(10000, 'INT')).to.equal('10,000');
-      expect(formatMeasure(1234567890, 'INT')).to.equal('1,234,567,890');
-    });
-
-    it('should format SHORT_INT', function () {
-      expect(formatMeasure(0, 'SHORT_INT')).to.equal('0');
-      expect(formatMeasure(1, 'SHORT_INT')).to.equal('1');
-      expect(formatMeasure(999, 'SHORT_INT')).to.equal('999');
-      expect(formatMeasure(1000, 'SHORT_INT')).to.equal('1k');
-      expect(formatMeasure(1529, 'SHORT_INT')).to.equal('1.5k');
-      expect(formatMeasure(10000, 'SHORT_INT')).to.equal('10k');
-      expect(formatMeasure(10678, 'SHORT_INT')).to.equal('11k');
-      expect(formatMeasure(1234567890, 'SHORT_INT')).to.equal('1b');
-    });
-
-    it('should format FLOAT', function () {
-      expect(formatMeasure(0.0, 'FLOAT')).to.equal('0.0');
-      expect(formatMeasure(1.0, 'FLOAT')).to.equal('1.0');
-      expect(formatMeasure(1.3, 'FLOAT')).to.equal('1.3');
-      expect(formatMeasure(1.34, 'FLOAT')).to.equal('1.34');
-      expect(formatMeasure(50.89, 'FLOAT')).to.equal('50.89');
-      expect(formatMeasure(100.0, 'FLOAT')).to.equal('100.0');
-      expect(formatMeasure(123.456, 'FLOAT')).to.equal('123.456');
-      expect(formatMeasure(123456.7, 'FLOAT')).to.equal('123,456.7');
-      expect(formatMeasure(1234567890.0, 'FLOAT')).to.equal('1,234,567,890.0');
-    });
-
-    it('should respect FLOAT precision', function () {
-      expect(formatMeasure(0.1, 'FLOAT')).to.equal('0.1');
-      expect(formatMeasure(0.12, 'FLOAT')).to.equal('0.12');
-      expect(formatMeasure(0.12345, 'FLOAT')).to.equal('0.12345');
-      expect(formatMeasure(0.123456, 'FLOAT')).to.equal('0.12346');
-    });
-
-    it('should format PERCENT', function () {
-      expect(formatMeasure(0.0, 'PERCENT')).to.equal('0.0%');
-      expect(formatMeasure(1.0, 'PERCENT')).to.equal('1.0%');
-      expect(formatMeasure(1.3, 'PERCENT')).to.equal('1.3%');
-      expect(formatMeasure(1.34, 'PERCENT')).to.equal('1.3%');
-      expect(formatMeasure(50.89, 'PERCENT')).to.equal('50.9%');
-      expect(formatMeasure(100.0, 'PERCENT')).to.equal('100.0%');
-    });
-
-    it('should format WORK_DUR', function () {
-      expect(formatMeasure(0, 'WORK_DUR')).to.equal('0');
-      expect(formatMeasure(5 * ONE_DAY, 'WORK_DUR')).to.equal('5d');
-      expect(formatMeasure(2 * ONE_HOUR, 'WORK_DUR')).to.equal('2h');
-      expect(formatMeasure(40 * ONE_MINUTE, 'WORK_DUR')).to.equal('40min');
-      expect(formatMeasure(ONE_MINUTE, 'WORK_DUR')).to.equal('1min');
-      expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR, 'WORK_DUR')).to.equal('5d 2h');
-      expect(formatMeasure(2 * ONE_HOUR + ONE_MINUTE, 'WORK_DUR')).to.equal('2h 1min');
-      expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'WORK_DUR')).to.equal('5d 2h');
-      expect(formatMeasure(15 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'WORK_DUR')).to.equal('15d');
-      expect(formatMeasure(-5 * ONE_DAY, 'WORK_DUR')).to.equal('-5d');
-      expect(formatMeasure(-2 * ONE_HOUR, 'WORK_DUR')).to.equal('-2h');
-      expect(formatMeasure(-1 * ONE_MINUTE, 'WORK_DUR')).to.equal('-1min');
-    });
-
-    it('should format SHORT_WORK_DUR', function () {
-      expect(formatMeasure(0, 'SHORT_WORK_DUR')).to.equal('0');
-      expect(formatMeasure(5 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('5d');
-      expect(formatMeasure(2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('2h');
-      expect(formatMeasure(40 * ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('40min');
-      expect(formatMeasure(ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('1min');
-      expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('5d');
-      expect(formatMeasure(2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('2h');
-      expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('5d');
-      expect(formatMeasure(15 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('15d');
-      expect(formatMeasure(7 * ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('7min');
-      expect(formatMeasure(-5 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('-5d');
-      expect(formatMeasure(-2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('-2h');
-      expect(formatMeasure(-1 * ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('-1min');
-
-      expect(formatMeasure(1529 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('1.5kd');
-      expect(formatMeasure(1234567 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('1md');
-      expect(formatMeasure(1234567 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('1md');
-    });
-
-    it('should format RATING', function () {
-      expect(formatMeasure(1, 'RATING')).to.equal('A');
-      expect(formatMeasure(2, 'RATING')).to.equal('B');
-      expect(formatMeasure(3, 'RATING')).to.equal('C');
-      expect(formatMeasure(4, 'RATING')).to.equal('D');
-      expect(formatMeasure(5, 'RATING')).to.equal('E');
-    });
-
-    it('should format LEVEL', function () {
-      expect(formatMeasure('ERROR', 'LEVEL')).to.equal('Error');
-      expect(formatMeasure('WARN', 'LEVEL')).to.equal('Warning');
-      expect(formatMeasure('OK', 'LEVEL')).to.equal('Ok');
-      expect(formatMeasure('UNKNOWN', 'LEVEL')).to.equal('UNKNOWN');
-    });
-
-    it('should format MILLISEC', function () {
-      expect(formatMeasure(0, 'MILLISEC')).to.equal('0ms');
-      expect(formatMeasure(1, 'MILLISEC')).to.equal('1ms');
-      expect(formatMeasure(173, 'MILLISEC')).to.equal('173ms');
-      expect(formatMeasure(3649, 'MILLISEC')).to.equal('4s');
-      expect(formatMeasure(893481, 'MILLISEC')).to.equal('15min');
-      expect(formatMeasure(17862325, 'MILLISEC')).to.equal('298min');
-    });
-
-    it('should not format unknown type', function () {
-      expect(formatMeasure('random value', 'RANDOM_TYPE')).to.equal('random value');
-    });
-
-    it('should return null if value is empty string', function () {
-      expect(formatMeasure('', 'PERCENT')).to.be.null;
-    });
-
-    it('should not fail without parameters', function () {
-      expect(formatMeasure()).to.be.null;
-    });
-  });
-
-  describe('#formatMeasureVariation()', function () {
-    it('should format INT', function () {
-      expect(formatMeasureVariation(0, 'INT')).to.equal('+0');
-      expect(formatMeasureVariation(1, 'INT')).to.equal('+1');
-      expect(formatMeasureVariation(-1, 'INT')).to.equal('-1');
-      expect(formatMeasureVariation(1529, 'INT')).to.equal('+1,529');
-      expect(formatMeasureVariation(-1529, 'INT')).to.equal('-1,529');
-    });
-
-    it('should format SHORT_INT', function () {
-      expect(formatMeasureVariation(0, 'SHORT_INT')).to.equal('+0');
-      expect(formatMeasureVariation(1, 'SHORT_INT')).to.equal('+1');
-      expect(formatMeasureVariation(-1, 'SHORT_INT')).to.equal('-1');
-      expect(formatMeasureVariation(1529, 'SHORT_INT')).to.equal('+1.5k');
-      expect(formatMeasureVariation(-1529, 'SHORT_INT')).to.equal('-1.5k');
-      expect(formatMeasureVariation(10678, 'SHORT_INT')).to.equal('+11k');
-      expect(formatMeasureVariation(-10678, 'SHORT_INT')).to.equal('-11k');
-    });
-
-    it('should format FLOAT', function () {
-      expect(formatMeasureVariation(0.0, 'FLOAT')).to.equal('+0.0');
-      expect(formatMeasureVariation(1.0, 'FLOAT')).to.equal('+1.0');
-      expect(formatMeasureVariation(-1.0, 'FLOAT')).to.equal('-1.0');
-      expect(formatMeasureVariation(50.89, 'FLOAT')).to.equal('+50.89');
-      expect(formatMeasureVariation(-50.89, 'FLOAT')).to.equal('-50.89');
-    });
-
-    it('should respect FLOAT precision', function () {
-      expect(formatMeasureVariation(0.1, 'FLOAT')).to.equal('+0.1');
-      expect(formatMeasureVariation(0.12, 'FLOAT')).to.equal('+0.12');
-      expect(formatMeasureVariation(0.12345, 'FLOAT')).to.equal('+0.12345');
-      expect(formatMeasureVariation(0.123456, 'FLOAT')).to.equal('+0.12346');
-    });
-
-    it('should format PERCENT', function () {
-      expect(formatMeasureVariation(0.0, 'PERCENT')).to.equal('+0.0%');
-      expect(formatMeasureVariation(1.0, 'PERCENT')).to.equal('+1.0%');
-      expect(formatMeasureVariation(-1.0, 'PERCENT')).to.equal('-1.0%');
-      expect(formatMeasureVariation(50.89, 'PERCENT')).to.equal('+50.9%');
-      expect(formatMeasureVariation(-50.89, 'PERCENT')).to.equal('-50.9%');
-    });
-
-    it('should format WORK_DUR', function () {
-      expect(formatMeasureVariation(0, 'WORK_DUR')).to.equal('+0');
-      expect(formatMeasureVariation(5 * ONE_DAY, 'WORK_DUR')).to.equal('+5d');
-      expect(formatMeasureVariation(2 * ONE_HOUR, 'WORK_DUR')).to.equal('+2h');
-      expect(formatMeasureVariation(ONE_MINUTE, 'WORK_DUR')).to.equal('+1min');
-      expect(formatMeasureVariation(-5 * ONE_DAY, 'WORK_DUR')).to.equal('-5d');
-      expect(formatMeasureVariation(-2 * ONE_HOUR, 'WORK_DUR')).to.equal('-2h');
-      expect(formatMeasureVariation(-1 * ONE_MINUTE, 'WORK_DUR')).to.equal('-1min');
-    });
-
-    it('should format SHORT_WORK_DUR', function () {
-      expect(formatMeasureVariation(0, 'SHORT_WORK_DUR')).to.equal('+0');
-      expect(formatMeasureVariation(5 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('+5d');
-      expect(formatMeasureVariation(2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('+2h');
-      expect(formatMeasureVariation(ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('+1min');
-      expect(formatMeasureVariation(5 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('+5d');
-      expect(formatMeasureVariation(2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('+2h');
-      expect(formatMeasureVariation(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('+5d');
-      expect(formatMeasureVariation(15 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('+15d');
-      expect(formatMeasureVariation(7 * ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('+7min');
-      expect(formatMeasureVariation(-5 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('-5d');
-      expect(formatMeasureVariation(-2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('-2h');
-      expect(formatMeasureVariation(-1 * ONE_MINUTE, 'SHORT_WORK_DUR')).to.equal('-1min');
-
-      expect(formatMeasureVariation(1529 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('+1.5kd');
-      expect(formatMeasureVariation(1234567 * ONE_DAY, 'SHORT_WORK_DUR')).to.equal('+1md');
-      expect(formatMeasureVariation(1234567 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).to.equal('+1md');
-    });
-
-    it('should not format unknown type', function () {
-      expect(formatMeasureVariation('random value', 'RANDOM_TYPE')).to.equal('random value');
-    });
-
-    it('should not fail without parameters', function () {
-      expect(formatMeasureVariation()).to.be.null;
-    });
-  });
-});
diff --git a/server/sonar-web/tests/helpers/path-test.js b/server/sonar-web/tests/helpers/path-test.js
deleted file mode 100644 (file)
index f663fb5..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-import { expect } from 'chai';
-import { collapsedDirFromPath, fileFromPath } from '../../src/main/js/helpers/path'
-
-describe('Path', function () {
-  describe('#collapsedDirFromPath()', function () {
-    it('should return null when pass null', function () {
-      expect(collapsedDirFromPath(null)).to.be.null;
-    });
-
-    it('should return "/" when pass "/"', function () {
-      expect(collapsedDirFromPath('/')).to.equal('/');
-    });
-
-    it('should not cut short path', function () {
-      expect(collapsedDirFromPath('src/main/js/components/state.js')).to.equal('src/main/js/components/');
-    });
-
-    it('should cut long path', function () {
-      expect(collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js'))
-          .to.equal('src/.../js/components/navigator/app/models/');
-    });
-
-    it('should cut very long path', function () {
-      expect(collapsedDirFromPath('src/main/another/js/components/navigator/app/models/state.js'))
-          .to.equal('src/.../js/components/navigator/app/models/');
-    });
-  });
-
-  describe('#fileFromPath()', function () {
-    it('should return null when pass null', function () {
-      expect(fileFromPath(null)).to.be.null;
-    });
-
-    it('should return empty string when pass "/"', function () {
-      expect(fileFromPath('/')).to.equal('');
-    });
-
-    it('should return file name when pass only file name', function () {
-      expect(fileFromPath('file.js')).to.equal('file.js');
-    });
-
-    it('should return file name when pass file path', function () {
-      expect(fileFromPath('src/main/js/file.js')).to.equal('file.js');
-    });
-
-    it('should return file name when pass file name without extension', function () {
-      expect(fileFromPath('src/main/file')).to.equal('file');
-    });
-  });
-});
diff --git a/server/sonar-web/tests/helpers/urls-test.js b/server/sonar-web/tests/helpers/urls-test.js
deleted file mode 100644 (file)
index 39b7c43..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-import { expect } from 'chai';
-
-import { getComponentUrl, getComponentIssuesUrl, getComponentDrilldownUrl } from '../../src/main/js/helpers/urls';
-
-
-const SIMPLE_COMPONENT_KEY = 'sonarqube';
-const COMPLEX_COMPONENT_KEY = 'org.sonarsource.sonarqube:sonarqube';
-const COMPLEX_COMPONENT_KEY_ENCODED = encodeURIComponent(COMPLEX_COMPONENT_KEY);
-const METRIC = 'coverage';
-const PERIOD = '3';
-
-
-describe('URLs', function () {
-  var oldBaseUrl;
-
-  beforeEach(function () {
-    oldBaseUrl = window.baseUrl;
-  });
-
-  afterEach(function () {
-    window.baseUrl = oldBaseUrl;
-  });
-
-  describe('#getComponentUrl', function () {
-    it('should return component url', function () {
-      expect(getComponentUrl(SIMPLE_COMPONENT_KEY)).to.equal('/dashboard?id=' + SIMPLE_COMPONENT_KEY);
-    });
-
-    it('should encode component key', function () {
-      expect(getComponentUrl(COMPLEX_COMPONENT_KEY)).to.equal('/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED);
-    });
-
-    it('should take baseUrl into account', function () {
-      window.baseUrl = '/context';
-      expect(getComponentUrl(COMPLEX_COMPONENT_KEY)).to.equal('/context/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED);
-    });
-  });
-
-  describe('#getComponentIssuesUrl', function () {
-    it('should work without parameters', function () {
-      expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, {})).to.equal(
-          '/component_issues?id=' + SIMPLE_COMPONENT_KEY + '#');
-    });
-
-    it('should encode component key', function () {
-      expect(getComponentIssuesUrl(COMPLEX_COMPONENT_KEY, {})).to.equal(
-          '/component_issues?id=' + COMPLEX_COMPONENT_KEY_ENCODED + '#');
-    });
-
-    it('should work with parameters', function () {
-      expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, { resolved: 'false' })).to.equal(
-          '/component_issues?id=' + SIMPLE_COMPONENT_KEY + '#resolved=false');
-    });
-
-    it('should encode parameters', function () {
-      expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, { componentUuids: COMPLEX_COMPONENT_KEY })).to.equal(
-          '/component_issues?id=' + SIMPLE_COMPONENT_KEY + '#componentUuids=' + COMPLEX_COMPONENT_KEY_ENCODED);
-    });
-
-    it('should take baseUrl into account', function () {
-      window.baseUrl = '/context';
-      expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, {})).to.equal(
-          '/context/component_issues?id=' + SIMPLE_COMPONENT_KEY + '#');
-    });
-  });
-
-  describe('#getComponentDrilldownUrl', function () {
-    it('should return component drilldown url', function () {
-      expect(getComponentDrilldownUrl(SIMPLE_COMPONENT_KEY, METRIC)).to.equal(
-          '/component_measures/metric/' + METRIC + '?id=' + SIMPLE_COMPONENT_KEY);
-    });
-
-    it('should encode component key', function () {
-      expect(getComponentDrilldownUrl(COMPLEX_COMPONENT_KEY, METRIC)).to.equal(
-          '/component_measures/metric/' + METRIC + '?id=' + COMPLEX_COMPONENT_KEY_ENCODED);
-    });
-
-    it('should take baseUrl into account', function () {
-      window.baseUrl = '/context';
-      expect(getComponentDrilldownUrl(SIMPLE_COMPONENT_KEY, METRIC)).to.equal(
-          '/context/component_measures/metric/' + METRIC + '?id=' + SIMPLE_COMPONENT_KEY);
-    });
-  });
-});
diff --git a/server/sonar-web/tests/nav-test.js b/server/sonar-web/tests/nav-test.js
deleted file mode 100644 (file)
index fc9f18e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-import ComponentNavBreadcrumbs from '../src/main/js/main/nav/component/component-nav-breadcrumbs';
-
-
-let expect = require('chai').expect;
-
-
-describe('Nav', function () {
-  describe('ComponentNavBreadcrumbs', () => {
-    it('should not render breadcrumbs with one element', function () {
-      var breadcrumbs = [
-        { key: 'my-project', name: 'My Project', qualifier: 'TRK' }
-      ];
-      var result = TestUtils.renderIntoDocument(
-          React.createElement(ComponentNavBreadcrumbs, { breadcrumbs: breadcrumbs })
-      );
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'li')).to.have.length(1);
-      expect(TestUtils.scryRenderedDOMComponentsWithTag(result, 'a')).to.have.length(1);
-    });
-  });
-});