aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-ui-common/components/ui/__tests__
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-ui-common/components/ui/__tests__')
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/Alert-test.tsx58
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/AutoEllipsis-test.tsx75
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/DeferredSpinner-test.tsx73
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/FilesCounter-test.tsx30
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/GenericAvatar-test.tsx27
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/Level-test.tsx36
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/MandatoryFieldMarker-test.tsx32
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/MandatoryFieldsExplanation-test.tsx34
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/NavBar-test.tsx40
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/NewsBox-test.tsx43
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/PageActions-test.tsx32
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/Rating-test.tsx41
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/SizeRating-test.tsx34
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/Alert-test.tsx.snap207
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/AutoEllipsis-test.tsx.snap9
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/DeferredSpinner-test.tsx.snap87
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/FilesCounter-test.tsx.snap25
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/GenericAvatar-test.tsx.snap47
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/Level-test.tsx.snap43
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/MandatoryFieldMarker-test.tsx.snap19
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/MandatoryFieldsExplanation-test.tsx.snap43
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/NavBar-test.tsx.snap64
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/NewsBox-test.tsx.snap42
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/PageActions-test.tsx.snap103
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/Rating-test.tsx.snap46
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/SizeRating-test.tsx.snap46
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/__snapshots__/popups-test.tsx.snap79
-rw-r--r--server/sonar-ui-common/components/ui/__tests__/popups-test.tsx127
28 files changed, 1542 insertions, 0 deletions
diff --git a/server/sonar-ui-common/components/ui/__tests__/Alert-test.tsx b/server/sonar-ui-common/components/ui/__tests__/Alert-test.tsx
new file mode 100644
index 00000000000..6355d5fae94
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/Alert-test.tsx
@@ -0,0 +1,58 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { Alert, AlertProps } from '../Alert';
+
+it('should render properly', () => {
+ expect(shallowRender({ variant: 'error' })).toMatchSnapshot();
+});
+
+it('verification of all variants of alert', () => {
+ const variants: AlertProps['variant'][] = ['error', 'warning', 'success', 'info', 'loading'];
+ variants.forEach((variant) => {
+ const wrapper = shallowRender({ variant });
+ expect(wrapper.prop('variantInfo')).toMatchSnapshot();
+ });
+});
+
+it('should render inline alert', () => {
+ expect(shallowRender({ display: 'inline' }).find('Styled(div)[isInline=true]').exists()).toBe(
+ true
+ );
+});
+
+it('should render banner alert', () => {
+ expect(shallowRender({ display: 'banner' }).find('Styled(div)[isBanner=true]').exists()).toBe(
+ true
+ );
+});
+
+it('should render banner alert with correct css', () => {
+ expect(shallowRender({ display: 'banner' }).render()).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<AlertProps>) {
+ return shallow(
+ <Alert className="alert-test" id="error-message" variant="error" {...props}>
+ This is an error!
+ </Alert>
+ );
+}
diff --git a/server/sonar-ui-common/components/ui/__tests__/AutoEllipsis-test.tsx b/server/sonar-ui-common/components/ui/__tests__/AutoEllipsis-test.tsx
new file mode 100644
index 00000000000..c01d263d456
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/AutoEllipsis-test.tsx
@@ -0,0 +1,75 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { mount, shallow } from 'enzyme';
+import * as React from 'react';
+import AutoEllipsis, { defaultShouldEllipsis } from '../AutoEllipsis';
+
+it('should render', () => {
+ const wrapper = shallow(
+ <AutoEllipsis maxWidth={5} useParent={false}>
+ <span className="medium">my test text</span>
+ </AutoEllipsis>
+ );
+
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render with text-ellipsis class', () => {
+ const wrapper = mount(
+ <AutoEllipsis customShouldEllipsis={() => true} maxWidth={5} useParent={false}>
+ <span className="medium">my test text</span>
+ </AutoEllipsis>
+ );
+
+ expect(wrapper.find('span').hasClass('medium')).toBe(true);
+ expect(wrapper.find('span').hasClass('text-ellipsis')).toBe(true);
+});
+
+const node5 = { clientWidth: 5, clientHeight: 5 } as any;
+const node10 = { clientWidth: 10, clientHeight: 10 } as any;
+const nodeParentSmaller = { ...node10, parentElement: node5 };
+const nodeParentBigger = { ...node5, parentElement: node10 };
+
+it('should correctly compute the auto-ellipsis', () => {
+ expect(defaultShouldEllipsis(node10, { maxWidth: 5, useParent: false })).toBe(true);
+ expect(defaultShouldEllipsis(node10, { maxHeight: 5, useParent: false })).toBe(true);
+ expect(defaultShouldEllipsis(node10, { maxWidth: 5, maxHeight: 5, useParent: false })).toBe(true);
+ expect(defaultShouldEllipsis(node10, { maxWidth: 5, maxHeight: 10, useParent: false })).toBe(
+ true
+ );
+ expect(defaultShouldEllipsis(node10, { maxWidth: 10, maxHeight: 5, useParent: false })).toBe(
+ true
+ );
+ expect(defaultShouldEllipsis(node10, { maxWidth: 10, useParent: false })).toBe(false);
+ expect(defaultShouldEllipsis(node10, { maxHeight: 10, useParent: false })).toBe(false);
+
+ expect(defaultShouldEllipsis(nodeParentSmaller, { maxWidth: 10, useParent: false })).toBe(false);
+ expect(defaultShouldEllipsis(nodeParentSmaller, { maxHeight: 10, useParent: false })).toBe(false);
+});
+
+it('should correctly compute the auto-ellipsis with a parent node', () => {
+ expect(defaultShouldEllipsis(nodeParentSmaller, {})).toBe(true);
+ expect(defaultShouldEllipsis(nodeParentSmaller, { maxWidth: 10 })).toBe(true);
+ expect(defaultShouldEllipsis(nodeParentSmaller, { maxHeight: 10 })).toBe(true);
+ expect(defaultShouldEllipsis(nodeParentSmaller, { maxWidth: 10, maxHeight: 10 })).toBe(false);
+ expect(defaultShouldEllipsis(nodeParentBigger, {})).toBe(false);
+ expect(defaultShouldEllipsis(nodeParentBigger, { maxWidth: 2 })).toBe(true);
+ expect(defaultShouldEllipsis(nodeParentBigger, { maxHeight: 2 })).toBe(true);
+});
diff --git a/server/sonar-ui-common/components/ui/__tests__/DeferredSpinner-test.tsx b/server/sonar-ui-common/components/ui/__tests__/DeferredSpinner-test.tsx
new file mode 100644
index 00000000000..6404ff6d0d9
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/DeferredSpinner-test.tsx
@@ -0,0 +1,73 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { mount } from 'enzyme';
+import * as React from 'react';
+import DeferredSpinner from '../DeferredSpinner';
+
+jest.useFakeTimers();
+
+it('renders spinner after timeout', () => {
+ const spinner = mount(<DeferredSpinner />);
+ expect(spinner).toMatchSnapshot();
+ jest.runAllTimers();
+ spinner.update();
+ expect(spinner).toMatchSnapshot();
+});
+
+it('add custom className', () => {
+ const spinner = mount(<DeferredSpinner className="foo" />);
+ jest.runAllTimers();
+ spinner.update();
+ expect(spinner).toMatchSnapshot();
+});
+
+it('renders children before timeout', () => {
+ const spinner = mount(
+ <DeferredSpinner>
+ <div>foo</div>
+ </DeferredSpinner>
+ );
+ expect(spinner).toMatchSnapshot();
+ jest.runAllTimers();
+ spinner.update();
+ expect(spinner).toMatchSnapshot();
+});
+
+it('is controlled by loading prop', () => {
+ const spinner = mount(
+ <DeferredSpinner loading={false}>
+ <div>foo</div>
+ </DeferredSpinner>
+ );
+ expect(spinner).toMatchSnapshot();
+ spinner.setProps({ loading: true });
+ expect(spinner).toMatchSnapshot();
+ jest.runAllTimers();
+ spinner.update();
+ expect(spinner).toMatchSnapshot();
+ spinner.setProps({ loading: false });
+ spinner.update();
+ expect(spinner).toMatchSnapshot();
+});
+
+it('renders a placeholder while waiting', () => {
+ const spinner = mount(<DeferredSpinner placeholder={true} />);
+ expect(spinner).toMatchSnapshot();
+});
diff --git a/server/sonar-ui-common/components/ui/__tests__/FilesCounter-test.tsx b/server/sonar-ui-common/components/ui/__tests__/FilesCounter-test.tsx
new file mode 100644
index 00000000000..90c65e2b3c6
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/FilesCounter-test.tsx
@@ -0,0 +1,30 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import FilesCounter from '../FilesCounter';
+
+it('should display x files on y total', () => {
+ expect(shallow(<FilesCounter current={12} total={123455} />)).toMatchSnapshot();
+});
+
+it('should display only total of files', () => {
+ expect(shallow(<FilesCounter current={undefined} total={123455} />)).toMatchSnapshot();
+});
diff --git a/server/sonar-ui-common/components/ui/__tests__/GenericAvatar-test.tsx b/server/sonar-ui-common/components/ui/__tests__/GenericAvatar-test.tsx
new file mode 100644
index 00000000000..468b063f2bc
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/GenericAvatar-test.tsx
@@ -0,0 +1,27 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import GenericAvatar from '../GenericAvatar';
+
+it('should render properly', () => {
+ expect(shallow(<GenericAvatar name="foo" size={40} />)).toMatchSnapshot();
+ expect(shallow(<GenericAvatar name="foo" size={40} round={true} />)).toMatchSnapshot();
+});
diff --git a/server/sonar-ui-common/components/ui/__tests__/Level-test.tsx b/server/sonar-ui-common/components/ui/__tests__/Level-test.tsx
new file mode 100644
index 00000000000..6cc7904f749
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/Level-test.tsx
@@ -0,0 +1,36 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import Level, { LevelProps } from '../Level';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default ok');
+ expect(shallowRender({ level: 'ERROR' })).toMatchSnapshot('default error');
+ expect(shallowRender({ muted: true, small: true })).toMatchSnapshot('muted and small');
+ expect(shallowRender({ 'aria-label': 'ARIA Label' })).toMatchSnapshot('with aria-label');
+ expect(shallowRender({ 'aria-labelledby': 'element-id' })).toMatchSnapshot(
+ 'with aria-labelledby'
+ );
+});
+
+function shallowRender(props: Partial<LevelProps> = {}) {
+ return shallow(<Level className="foo" level="OK" {...props} />);
+}
diff --git a/server/sonar-ui-common/components/ui/__tests__/MandatoryFieldMarker-test.tsx b/server/sonar-ui-common/components/ui/__tests__/MandatoryFieldMarker-test.tsx
new file mode 100644
index 00000000000..dc3453990f5
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/MandatoryFieldMarker-test.tsx
@@ -0,0 +1,32 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import MandatoryFieldMarker, { MandatoryFieldMarkerProps } from '../MandatoryFieldMarker';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(shallowRender({ className: 'foo-bar' })).toMatchSnapshot('with className');
+});
+
+function shallowRender(props: Partial<MandatoryFieldMarkerProps> = {}) {
+ return shallow<MandatoryFieldMarkerProps>(<MandatoryFieldMarker {...props} />);
+}
diff --git a/server/sonar-ui-common/components/ui/__tests__/MandatoryFieldsExplanation-test.tsx b/server/sonar-ui-common/components/ui/__tests__/MandatoryFieldsExplanation-test.tsx
new file mode 100644
index 00000000000..1fd156d93ea
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/MandatoryFieldsExplanation-test.tsx
@@ -0,0 +1,34 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import MandatoryFieldsExplanation, {
+ MandatoryFieldsExplanationProps,
+} from '../MandatoryFieldsExplanation';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(shallowRender({ className: 'foo-bar' })).toMatchSnapshot('with className');
+});
+
+function shallowRender(props: Partial<MandatoryFieldsExplanationProps> = {}) {
+ return shallow<MandatoryFieldsExplanationProps>(<MandatoryFieldsExplanation {...props} />);
+}
diff --git a/server/sonar-ui-common/components/ui/__tests__/NavBar-test.tsx b/server/sonar-ui-common/components/ui/__tests__/NavBar-test.tsx
new file mode 100644
index 00000000000..7f4e78e8164
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/NavBar-test.tsx
@@ -0,0 +1,40 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import NavBar from '../NavBar';
+
+it('should render correctly', () => {
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render correctly with notif and not limited', () => {
+ const wrapper = shallowRender({ limited: false, notif: <div className="my-notifs" /> });
+ expect(wrapper).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<NavBar['props']> = {}) {
+ return shallow(
+ <NavBar height={42} {...props}>
+ <div className="my-navbar-content" />
+ </NavBar>
+ );
+}
diff --git a/server/sonar-ui-common/components/ui/__tests__/NewsBox-test.tsx b/server/sonar-ui-common/components/ui/__tests__/NewsBox-test.tsx
new file mode 100644
index 00000000000..25693412f31
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/NewsBox-test.tsx
@@ -0,0 +1,43 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { click } from '../../../helpers/testUtils';
+import NewsBox, { Props } from '../NewsBox';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+});
+
+it('should call onClose', () => {
+ const onClose = jest.fn();
+ const wrapper = shallowRender({ onClose });
+
+ click(wrapper.find('ClearButton'));
+ expect(onClose).toBeCalled();
+});
+
+function shallowRender(props: Partial<Props> = {}) {
+ return shallow(
+ <NewsBox onClose={jest.fn()} title="title" {...props}>
+ <div>description</div>
+ </NewsBox>
+ );
+}
diff --git a/server/sonar-ui-common/components/ui/__tests__/PageActions-test.tsx b/server/sonar-ui-common/components/ui/__tests__/PageActions-test.tsx
new file mode 100644
index 00000000000..f144f882a53
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/PageActions-test.tsx
@@ -0,0 +1,32 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import PageActions, { Props } from '../PageActions';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ total: 10 })).toMatchSnapshot();
+ expect(shallowRender({ current: 12, showShortcuts: false, total: 120 })).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<Props> = {}) {
+ return shallow(<PageActions showShortcuts={true} {...props} />);
+}
diff --git a/server/sonar-ui-common/components/ui/__tests__/Rating-test.tsx b/server/sonar-ui-common/components/ui/__tests__/Rating-test.tsx
new file mode 100644
index 00000000000..55293f59b4c
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/Rating-test.tsx
@@ -0,0 +1,41 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import Rating from '../Rating';
+
+it('renders numeric value', () => {
+ expect(shallow(<Rating value={2} />)).toMatchSnapshot();
+});
+
+it('renders string value', () => {
+ expect(shallow(<Rating value="2.0" muted={true} small={true} />)).toMatchSnapshot();
+});
+
+it('renders undefined value', () => {
+ expect(shallow(<Rating value={undefined} muted={true} small={true} />)).toMatchSnapshot();
+});
+
+it('renders with a custom aria-label', () => {
+ expect(shallow(<Rating aria-label="custom" aria-hidden={false} value="2.0" />)).toMatchSnapshot();
+ expect(
+ shallow(<Rating aria-label="custom" aria-hidden={false} value={undefined} />)
+ ).toMatchSnapshot();
+});
diff --git a/server/sonar-ui-common/components/ui/__tests__/SizeRating-test.tsx b/server/sonar-ui-common/components/ui/__tests__/SizeRating-test.tsx
new file mode 100644
index 00000000000..43eb09c600b
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/SizeRating-test.tsx
@@ -0,0 +1,34 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import SizeRating, { Props } from '../SizeRating';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ muted: true, small: true, value: 1000 })).toMatchSnapshot();
+ expect(shallowRender({ value: 10000 })).toMatchSnapshot();
+ expect(shallowRender({ value: 100000 })).toMatchSnapshot();
+ expect(shallowRender({ value: 500000 })).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<Props> = {}) {
+ return shallow(<SizeRating value={100} {...props} />);
+}
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/Alert-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/Alert-test.tsx.snap
new file mode 100644
index 00000000000..893212cc564
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/Alert-test.tsx.snap
@@ -0,0 +1,207 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render banner alert with correct css 1`] = `
+.emotion-3 {
+ border: 1px solid;
+ border-radius: 2px;
+ margin-bottom: 8px;
+ border-color: #f4b1b0;
+ background-color: #f2dede;
+ color: #862422;
+ display: block;
+}
+
+.emotion-3:empty {
+ display: none;
+}
+
+.emotion-3 a,
+.emotion-3 .button-link {
+ border-color: #236a97;
+}
+
+.emotion-2 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: stretch;
+ -webkit-box-align: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+ min-width: 1080px;
+ max-width: 1320px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 20px;
+ padding-right: 20px;
+ box-sizing: border-box;
+}
+
+.emotion-0 {
+ -webkit-flex: 0 0 auto;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ width: calc(2 * 8px);
+ border-right: none;
+ border-color: #f4b1b0;
+}
+
+.emotion-1 {
+ -webkit-flex: 1 1 auto;
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ overflow: auto;
+ text-align: left;
+ padding: 8px calc(2 * 8px);
+}
+
+<div
+ class="alert alert-test emotion-3"
+ id="error-message"
+ role="alert"
+>
+ <div
+ class="emotion-2"
+ >
+ <div
+ aria-label="alert.tooltip.error"
+ class="emotion-0"
+ >
+ <svg
+ height="16"
+ space="preserve"
+ style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
+ version="1.1"
+ viewBox="0 0 16 16"
+ width="16"
+ xlink="http://www.w3.org/1999/xlink"
+ >
+ <path
+ d="M11.402 10.018q0-0.232-0.17-0.402l-1.616-1.616 1.616-1.616q0.17-0.17 0.17-0.402 0-0.241-0.17-0.411l-0.804-0.804q-0.17-0.17-0.411-0.17-0.232 0-0.402 0.17l-1.616 1.616-1.616-1.616q-0.17-0.17-0.402-0.17-0.241 0-0.411 0.17l-0.804 0.804q-0.17 0.17-0.17 0.411 0 0.232 0.17 0.402l1.616 1.616-1.616 1.616q-0.17 0.17-0.17 0.402 0 0.241 0.17 0.411l0.804 0.804q0.17 0.17 0.411 0.17 0.232 0 0.402-0.17l1.616-1.616 1.616 1.616q0.17 0.17 0.402 0.17 0.241 0 0.411-0.17l0.804-0.804q0.17-0.17 0.17-0.411zM14.857 8q0 1.866-0.92 3.442t-2.496 2.496-3.442 0.92-3.442-0.92-2.496-2.496-0.92-3.442 0.92-3.442 2.496-2.496 3.442-0.92 3.442 0.92 2.496 2.496 0.92 3.442z"
+ style="fill:#a4030f"
+ />
+ </svg>
+ </div>
+ <div
+ class="alert-content emotion-1"
+ >
+ This is an error!
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render properly 1`] = `
+<Styled(div)
+ className="alert alert-test"
+ id="error-message"
+ isInline={false}
+ role="alert"
+ variantInfo={
+ Object {
+ "backGroundColor": "#f2dede",
+ "borderColor": "#f4b1b0",
+ "color": "#862422",
+ "icon": <AlertErrorIcon
+ fill="#a4030f"
+ />,
+ }
+ }
+>
+ <Styled(div)
+ isBanner={false}
+ >
+ <Styled(div)
+ aria-label="alert.tooltip.error"
+ isBanner={false}
+ variantInfo={
+ Object {
+ "backGroundColor": "#f2dede",
+ "borderColor": "#f4b1b0",
+ "color": "#862422",
+ "icon": <AlertErrorIcon
+ fill="#a4030f"
+ />,
+ }
+ }
+ >
+ <AlertErrorIcon
+ fill="#a4030f"
+ />
+ </Styled(div)>
+ <Styled(div)
+ className="alert-content"
+ >
+ This is an error!
+ </Styled(div)>
+ </Styled(div)>
+</Styled(div)>
+`;
+
+exports[`verification of all variants of alert 1`] = `
+Object {
+ "backGroundColor": "#f2dede",
+ "borderColor": "#f4b1b0",
+ "color": "#862422",
+ "icon": <AlertErrorIcon
+ fill="#a4030f"
+ />,
+}
+`;
+
+exports[`verification of all variants of alert 2`] = `
+Object {
+ "backGroundColor": "#fcf8e3",
+ "borderColor": "#faebcc",
+ "color": "#6f4f17",
+ "icon": <AlertWarnIcon
+ fill="#db781a"
+ />,
+}
+`;
+
+exports[`verification of all variants of alert 3`] = `
+Object {
+ "backGroundColor": "#dff0d8",
+ "borderColor": "#d6e9c6",
+ "color": "#215821",
+ "icon": <AlertSuccessIcon
+ fill="#6d9867"
+ />,
+}
+`;
+
+exports[`verification of all variants of alert 4`] = `
+Object {
+ "backGroundColor": "#d9edf7",
+ "borderColor": "#b1dff3",
+ "color": "#0e516f",
+ "icon": <InfoIcon
+ fill="#0271b9"
+ />,
+}
+`;
+
+exports[`verification of all variants of alert 5`] = `
+Object {
+ "backGroundColor": "#d9edf7",
+ "borderColor": "#b1dff3",
+ "color": "#0e516f",
+ "icon": <DeferredSpinner
+ timeout={0}
+ />,
+}
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/AutoEllipsis-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/AutoEllipsis-test.tsx.snap
new file mode 100644
index 00000000000..84212d45e27
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/AutoEllipsis-test.tsx.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render 1`] = `
+<span
+ className="medium"
+>
+ my test text
+</span>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/DeferredSpinner-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/DeferredSpinner-test.tsx.snap
new file mode 100644
index 00000000000..6822674e7d2
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/DeferredSpinner-test.tsx.snap
@@ -0,0 +1,87 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`add custom className 1`] = `
+<DeferredSpinner
+ className="foo"
+>
+ <i
+ className="deferred-spinner foo"
+ />
+</DeferredSpinner>
+`;
+
+exports[`is controlled by loading prop 1`] = `
+<DeferredSpinner
+ loading={false}
+>
+ <div>
+ foo
+ </div>
+</DeferredSpinner>
+`;
+
+exports[`is controlled by loading prop 2`] = `
+<DeferredSpinner
+ loading={true}
+>
+ <div>
+ foo
+ </div>
+</DeferredSpinner>
+`;
+
+exports[`is controlled by loading prop 3`] = `
+<DeferredSpinner
+ loading={true}
+>
+ <i
+ className="deferred-spinner"
+ />
+</DeferredSpinner>
+`;
+
+exports[`is controlled by loading prop 4`] = `
+<DeferredSpinner
+ loading={false}
+>
+ <div>
+ foo
+ </div>
+</DeferredSpinner>
+`;
+
+exports[`renders a placeholder while waiting 1`] = `
+<DeferredSpinner
+ placeholder={true}
+>
+ <i
+ className="deferred-spinner-placeholder"
+ />
+</DeferredSpinner>
+`;
+
+exports[`renders children before timeout 1`] = `
+<DeferredSpinner>
+ <div>
+ foo
+ </div>
+</DeferredSpinner>
+`;
+
+exports[`renders children before timeout 2`] = `
+<DeferredSpinner>
+ <i
+ className="deferred-spinner"
+ />
+</DeferredSpinner>
+`;
+
+exports[`renders spinner after timeout 1`] = `<DeferredSpinner />`;
+
+exports[`renders spinner after timeout 2`] = `
+<DeferredSpinner>
+ <i
+ className="deferred-spinner"
+ />
+</DeferredSpinner>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/FilesCounter-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/FilesCounter-test.tsx.snap
new file mode 100644
index 00000000000..bb01a6121da
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/FilesCounter-test.tsx.snap
@@ -0,0 +1,25 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display only total of files 1`] = `
+<span>
+ <strong>
+ 123,455
+ </strong>
+
+ component_measures.files
+</span>
+`;
+
+exports[`should display x files on y total 1`] = `
+<span>
+ <strong>
+ <span>
+ 12
+ /
+ </span>
+ 123,455
+ </strong>
+
+ component_measures.files
+</span>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/GenericAvatar-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/GenericAvatar-test.tsx.snap
new file mode 100644
index 00000000000..9c2bb0fa7fd
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/GenericAvatar-test.tsx.snap
@@ -0,0 +1,47 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render properly 1`] = `
+<div
+ className="rounded"
+ style={
+ Object {
+ "backgroundColor": "#c68c01",
+ "borderRadius": undefined,
+ "color": "#fff",
+ "display": "inline-block",
+ "fontSize": 14,
+ "fontWeight": "normal",
+ "height": 40,
+ "lineHeight": "40px",
+ "textAlign": "center",
+ "verticalAlign": "top",
+ "width": 40,
+ }
+ }
+>
+ F
+</div>
+`;
+
+exports[`should render properly 2`] = `
+<div
+ className="rounded"
+ style={
+ Object {
+ "backgroundColor": "#c68c01",
+ "borderRadius": "50%",
+ "color": "#fff",
+ "display": "inline-block",
+ "fontSize": 14,
+ "fontWeight": "normal",
+ "height": 40,
+ "lineHeight": "40px",
+ "textAlign": "center",
+ "verticalAlign": "top",
+ "width": 40,
+ }
+ }
+>
+ F
+</div>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/Level-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/Level-test.tsx.snap
new file mode 100644
index 00000000000..089171fcc17
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/Level-test.tsx.snap
@@ -0,0 +1,43 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default error 1`] = `
+<span
+ className="foo level level-ERROR"
+>
+ ERROR
+</span>
+`;
+
+exports[`should render correctly: default ok 1`] = `
+<span
+ className="foo level level-OK"
+>
+ OK
+</span>
+`;
+
+exports[`should render correctly: muted and small 1`] = `
+<span
+ className="foo level level-OK level-small level-muted"
+>
+ OK
+</span>
+`;
+
+exports[`should render correctly: with aria-label 1`] = `
+<span
+ aria-label="ARIA Label"
+ className="foo level level-OK"
+>
+ OK
+</span>
+`;
+
+exports[`should render correctly: with aria-labelledby 1`] = `
+<span
+ aria-labelledby="element-id"
+ className="foo level level-OK"
+>
+ OK
+</span>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/MandatoryFieldMarker-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/MandatoryFieldMarker-test.tsx.snap
new file mode 100644
index 00000000000..1adb77718dd
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/MandatoryFieldMarker-test.tsx.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<em
+ aria-label="field_required"
+ className="mandatory little-spacer-left"
+>
+ *
+</em>
+`;
+
+exports[`should render correctly: with className 1`] = `
+<em
+ aria-label="field_required"
+ className="mandatory little-spacer-left foo-bar"
+>
+ *
+</em>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/MandatoryFieldsExplanation-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/MandatoryFieldsExplanation-test.tsx.snap
new file mode 100644
index 00000000000..ca469b7e71c
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/MandatoryFieldsExplanation-test.tsx.snap
@@ -0,0 +1,43 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<div
+ aria-hidden={true}
+ className="text-muted"
+>
+ <FormattedMessage
+ defaultMessage="fields_marked_with_x_required"
+ id="fields_marked_with_x_required"
+ values={
+ Object {
+ "star": <em
+ className="mandatory"
+ >
+ *
+ </em>,
+ }
+ }
+ />
+</div>
+`;
+
+exports[`should render correctly: with className 1`] = `
+<div
+ aria-hidden={true}
+ className="text-muted foo-bar"
+>
+ <FormattedMessage
+ defaultMessage="fields_marked_with_x_required"
+ id="fields_marked_with_x_required"
+ values={
+ Object {
+ "star": <em
+ className="mandatory"
+ >
+ *
+ </em>,
+ }
+ }
+ />
+</div>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/NavBar-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/NavBar-test.tsx.snap
new file mode 100644
index 00000000000..a039d0ebb24
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/NavBar-test.tsx.snap
@@ -0,0 +1,64 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<nav
+ className="navbar"
+ style={
+ Object {
+ "height": 42,
+ "top": undefined,
+ }
+ }
+>
+ <div
+ className="navbar-inner"
+ style={
+ Object {
+ "height": 42,
+ "left": 0,
+ }
+ }
+ >
+ <div
+ className="clearfix navbar-limited"
+ >
+ <div
+ className="my-navbar-content"
+ />
+ </div>
+ </div>
+</nav>
+`;
+
+exports[`should render correctly with notif and not limited 1`] = `
+<nav
+ className="navbar"
+ style={
+ Object {
+ "height": 42,
+ "top": undefined,
+ }
+ }
+>
+ <div
+ className="navbar-inner navbar-inner-with-notif"
+ style={
+ Object {
+ "height": 42,
+ "left": 0,
+ }
+ }
+ >
+ <div
+ className="clearfix"
+ >
+ <div
+ className="my-navbar-content"
+ />
+ </div>
+ <div
+ className="my-notifs"
+ />
+ </div>
+</nav>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/NewsBox-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/NewsBox-test.tsx.snap
new file mode 100644
index 00000000000..91e58894fbf
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/NewsBox-test.tsx.snap
@@ -0,0 +1,42 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="news-box"
+ role="alert"
+>
+ <div
+ className="news-box-header"
+ >
+ <div
+ className="display-flex-center"
+ >
+ <span
+ className="badge badge-info spacer-right"
+ >
+ new
+ </span>
+ <strong>
+ title
+ </strong>
+ </div>
+ <ClearButton
+ className="button-tiny"
+ iconProps={
+ Object {
+ "size": 12,
+ "thin": true,
+ }
+ }
+ onClick={[MockFunction]}
+ />
+ </div>
+ <div
+ className="big-spacer-top note"
+ >
+ <div>
+ description
+ </div>
+ </div>
+</div>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/PageActions-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/PageActions-test.tsx.snap
new file mode 100644
index 00000000000..bb220fbacaf
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/PageActions-test.tsx.snap
@@ -0,0 +1,103 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="page-actions display-flex-center"
+>
+ <span
+ className="note nowrap"
+ >
+ <span
+ className="big-spacer-right"
+ >
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ ↑
+ </span>
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ ↓
+ </span>
+ component_measures.to_select_files
+ </span>
+ <span>
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ ←
+ </span>
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ →
+ </span>
+ component_measures.to_navigate
+ </span>
+ </span>
+</div>
+`;
+
+exports[`should render correctly 2`] = `
+<div
+ className="page-actions display-flex-center"
+>
+ <span
+ className="note nowrap"
+ >
+ <span
+ className="big-spacer-right"
+ >
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ ↑
+ </span>
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ ↓
+ </span>
+ component_measures.to_select_files
+ </span>
+ <span>
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ ←
+ </span>
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ →
+ </span>
+ component_measures.to_navigate
+ </span>
+ </span>
+ <div
+ className="nowrap"
+ >
+ <FilesCounter
+ className="big-spacer-left"
+ total={10}
+ />
+ </div>
+</div>
+`;
+
+exports[`should render correctly 3`] = `
+<div
+ className="page-actions display-flex-center"
+>
+ <div
+ className="nowrap"
+ >
+ <FilesCounter
+ className="big-spacer-left"
+ current={12}
+ total={120}
+ />
+ </div>
+</div>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/Rating-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/Rating-test.tsx.snap
new file mode 100644
index 00000000000..9455ce98965
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/Rating-test.tsx.snap
@@ -0,0 +1,46 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders numeric value 1`] = `
+<span
+ aria-label="metric.has_rating_X.B"
+ className="rating rating-B"
+>
+ B
+</span>
+`;
+
+exports[`renders string value 1`] = `
+<span
+ aria-label="metric.has_rating_X.B"
+ className="rating rating-B rating-small rating-muted"
+>
+ B
+</span>
+`;
+
+exports[`renders undefined value 1`] = `
+<span
+ aria-label="metric.no_rating"
+>
+ –
+</span>
+`;
+
+exports[`renders with a custom aria-label 1`] = `
+<span
+ aria-hidden={false}
+ aria-label="custom"
+ className="rating rating-B"
+>
+ B
+</span>
+`;
+
+exports[`renders with a custom aria-label 2`] = `
+<span
+ aria-hidden={false}
+ aria-label="custom"
+>
+ –
+</span>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/SizeRating-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/SizeRating-test.tsx.snap
new file mode 100644
index 00000000000..a35517cc685
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/SizeRating-test.tsx.snap
@@ -0,0 +1,46 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ aria-hidden="true"
+ className="size-rating"
+>
+ XS
+</div>
+`;
+
+exports[`should render correctly 2`] = `
+<div
+ aria-hidden="true"
+ className="size-rating size-rating-small size-rating-muted"
+>
+ S
+</div>
+`;
+
+exports[`should render correctly 3`] = `
+<div
+ aria-hidden="true"
+ className="size-rating"
+>
+ M
+</div>
+`;
+
+exports[`should render correctly 4`] = `
+<div
+ aria-hidden="true"
+ className="size-rating"
+>
+ L
+</div>
+`;
+
+exports[`should render correctly 5`] = `
+<div
+ aria-hidden="true"
+ className="size-rating"
+>
+ XL
+</div>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/__snapshots__/popups-test.tsx.snap b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/popups-test.tsx.snap
new file mode 100644
index 00000000000..87b7811eb17
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/__snapshots__/popups-test.tsx.snap
@@ -0,0 +1,79 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Popup should render Popup 1`] = `
+<ClickEventBoundary>
+ <div
+ className="popup is-left-top foo"
+ style={
+ Object {
+ "left": -5,
+ }
+ }
+ >
+ <PopupArrow
+ style={
+ Object {
+ "top": -5,
+ }
+ }
+ />
+ </div>
+</ClickEventBoundary>
+`;
+
+exports[`Popup should render PopupArrow 1`] = `
+<div
+ className="popup-arrow"
+ style={
+ Object {
+ "left": -5,
+ }
+ }
+/>
+`;
+
+exports[`PortalPopup should render correctly with overlay 1`] = `
+<Fragment>
+ <div
+ id="popup-trigger"
+ />
+ <PortalWrapper>
+ <WithTheme(ScreenPositionFixer)
+ ready={true}
+ >
+ <Component />
+ </WithTheme(ScreenPositionFixer)>
+ </PortalWrapper>
+</Fragment>
+`;
+
+exports[`PortalPopup should render correctly with overlay 2`] = `
+<Popup
+ arrowStyle={
+ Object {
+ "marginLeft": 0,
+ }
+ }
+ placement="bottom"
+ style={
+ Object {
+ "height": 10,
+ "left": 0,
+ "top": 0,
+ "width": 10,
+ }
+ }
+>
+ <span
+ id="overlay"
+ />
+</Popup>
+`;
+
+exports[`PortalPopup should render correctly without overlay 1`] = `
+<Fragment>
+ <div
+ id="popup-trigger"
+ />
+</Fragment>
+`;
diff --git a/server/sonar-ui-common/components/ui/__tests__/popups-test.tsx b/server/sonar-ui-common/components/ui/__tests__/popups-test.tsx
new file mode 100644
index 00000000000..777c1004d77
--- /dev/null
+++ b/server/sonar-ui-common/components/ui/__tests__/popups-test.tsx
@@ -0,0 +1,127 @@
+/*
+ * Sonar UI Common
+ * Copyright (C) 2019-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { findDOMNode } from 'react-dom';
+import ScreenPositionFixer from '../../controls/ScreenPositionFixer';
+import { Popup, PopupArrow, PopupPlacement, PortalPopup } from '../popups';
+
+jest.mock('react-dom', () => ({
+ ...jest.requireActual('react-dom'),
+ findDOMNode: jest.fn().mockReturnValue(undefined),
+}));
+
+describe('Popup', () => {
+ it('should render Popup', () => {
+ expect(
+ shallow(
+ <Popup
+ arrowStyle={{ top: -5 }}
+ className="foo"
+ placement={PopupPlacement.LeftTop}
+ style={{ left: -5 }}
+ />
+ )
+ ).toMatchSnapshot();
+ });
+
+ it('should render PopupArrow', () => {
+ expect(shallow(<PopupArrow style={{ left: -5 }} />)).toMatchSnapshot();
+ });
+});
+
+describe('PortalPopup', () => {
+ it('should render correctly without overlay', () => {
+ expect(shallowRender({ overlay: undefined })).toMatchSnapshot();
+ });
+
+ it('should render correctly with overlay', () => {
+ const wrapper = shallowRender();
+ wrapper.setState({ left: 0, top: 0, width: 10, height: 10 });
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find(ScreenPositionFixer).dive().dive().dive()).toMatchSnapshot();
+ });
+
+ it('should correctly compute the popup positioning', () => {
+ const fakeDomNode = document.createElement('div');
+ fakeDomNode.getBoundingClientRect = jest
+ .fn()
+ .mockReturnValue({ left: 10, top: 10, width: 10, height: 10 });
+ (findDOMNode as jest.Mock).mockReturnValue(fakeDomNode);
+ const wrapper = shallowRender();
+ const getPlacementSpy = jest.spyOn(wrapper.instance(), 'getPlacement');
+
+ wrapper.instance().popupNode = {
+ current: {
+ getBoundingClientRect: jest.fn().mockReturnValue({ width: 8, height: 8 }),
+ } as any,
+ };
+
+ wrapper.instance().positionPopup();
+ expect(wrapper.state()).toEqual(expect.objectContaining({ left: 11, top: 20 }));
+
+ getPlacementSpy.mockReturnValue(PopupPlacement.BottomLeft);
+ wrapper.instance().positionPopup();
+ expect(wrapper.state()).toEqual(expect.objectContaining({ left: 10, top: 20 }));
+
+ getPlacementSpy.mockReturnValue(PopupPlacement.BottomRight);
+ wrapper.instance().positionPopup();
+ expect(wrapper.state()).toEqual(expect.objectContaining({ left: 12, top: 20 }));
+
+ getPlacementSpy.mockReturnValue(PopupPlacement.LeftTop);
+ wrapper.instance().positionPopup();
+ expect(wrapper.state()).toEqual(expect.objectContaining({ left: 2, top: 10 }));
+
+ getPlacementSpy.mockReturnValue(PopupPlacement.RightBottom);
+ wrapper.instance().positionPopup();
+ expect(wrapper.state()).toEqual(expect.objectContaining({ left: 20, top: 12 }));
+
+ getPlacementSpy.mockReturnValue(PopupPlacement.RightTop);
+ wrapper.instance().positionPopup();
+ expect(wrapper.state()).toEqual(expect.objectContaining({ left: 20, top: 10 }));
+
+ getPlacementSpy.mockReturnValue(PopupPlacement.TopLeft);
+ wrapper.instance().positionPopup();
+ expect(wrapper.state()).toEqual(expect.objectContaining({ left: 10, top: 2 }));
+ });
+
+ it('should correctly compute the popup arrow positioning', () => {
+ const wrapper = shallowRender({ arrowOffset: -2 });
+ const getPlacementSpy = jest.spyOn(wrapper.instance(), 'getPlacement');
+
+ expect(
+ wrapper.instance().adjustArrowPosition(PopupPlacement.BottomLeft, { leftFix: 10, topFix: 10 })
+ ).toEqual({ marginLeft: -12 });
+
+ expect(
+ wrapper
+ .instance()
+ .adjustArrowPosition(PopupPlacement.RightBottom, { leftFix: 10, topFix: 10 })
+ ).toEqual({ marginTop: -12 });
+ });
+
+ function shallowRender(props: Partial<PortalPopup['props']> = {}) {
+ return shallow<PortalPopup>(
+ <PortalPopup overlay={<span id="overlay" />} {...props}>
+ <div id="popup-trigger" />
+ </PortalPopup>
+ );
+ }
+});