import { getRulesApp } from '../../api/rules';
import { get, save } from '../../helpers/storage';
import { Dict } from '../../types/types';
-import { ComponentDescriptor, RuleDescriptor, WorkspaceContext } from './context';
-import './styles.css';
import WorkspaceComponentViewer from './WorkspaceComponentViewer';
import WorkspaceNav from './WorkspaceNav';
import WorkspacePortal from './WorkspacePortal';
+import { ComponentDescriptor, WorkspaceContext } from './context';
+import './styles.css';
const WORKSPACE = 'sonarqube-workspace';
interface State {
height: number;
maximized?: boolean;
open: { component?: string };
- rules: RuleDescriptor[];
}
export const MIN_HEIGHT = 0.05;
export const TYPE_KEY = '__type__';
export enum WorkspaceTypes {
- Rule = 'rule',
Component = 'component',
}
}
componentDidUpdate(_: {}, prevState: State) {
- if (prevState.components !== this.state.components || prevState.rules !== this.state.rules) {
+ if (prevState.components !== this.state.components) {
this.saveWorkspace();
}
}
const components: ComponentDescriptor[] = data.filter(
(x) => x[TYPE_KEY] === WorkspaceTypes.Component
);
- const rules: RuleDescriptor[] = data.filter((x) => x[TYPE_KEY] === WorkspaceTypes.Rule);
- return { components, rules };
+ return { components };
} catch {
// Fail silently.
- return { components: [], rules: [] };
+ return { components: [] };
}
};
...this.state.components.map((x) =>
omit({ ...x, [TYPE_KEY]: WorkspaceTypes.Component }, 'line')
),
- ...this.state.rules.map((x) => ({ ...x, [TYPE_KEY]: WorkspaceTypes.Rule })),
];
save(WORKSPACE, JSON.stringify(data));
};
};
render() {
- const { components, externalRulesRepoNames, height, maximized, open, rules } = this.state;
+ const { components, externalRulesRepoNames, height, maximized, open } = this.state;
const openComponent = open.component && components.find((x) => x.key === open.component);
>
{this.props.children}
<WorkspacePortal>
- {(components.length > 0 || rules.length > 0) && (
+ {components.length > 0 && (
<WorkspaceNav
components={components}
onComponentClose={this.handleComponentClose}
<div
className="workspace-viewer-container"
+ role="complementary"
ref={(node) => (this.container = node)}
style={{ height: this.props.height }}
>
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 * as React from 'react';
-import { RuleDescriptor } from './context';
-import WorkspaceNavItem from './WorkspaceNavItem';
-import WorkspaceRuleTitle from './WorkspaceRuleTitle';
-
-export interface Props {
- rule: RuleDescriptor;
- onClose: (ruleKey: string) => void;
- onOpen: (ruleKey: string) => void;
-}
-
-export default class WorkspaceNavRule extends React.PureComponent<Props> {
- handleClose = () => {
- this.props.onClose(this.props.rule.key);
- };
-
- handleOpen = () => {
- this.props.onOpen(this.props.rule.key);
- };
-
- render() {
- return (
- <WorkspaceNavItem onClose={this.handleClose} onOpen={this.handleOpen}>
- <WorkspaceRuleTitle limited rule={this.props.rule} />
- </WorkspaceNavItem>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 { keyBy } from 'lodash';
-import * as React from 'react';
-import { getRuleDetails, getRulesApp } from '../../api/rules';
-import RuleDetailsDescription from '../../apps/coding-rules/components/RuleDetailsDescription';
-import RuleDetailsMeta from '../../apps/coding-rules/components/RuleDetailsMeta';
-import '../../apps/coding-rules/styles.css';
-import { Dict, RuleDetails } from '../../types/types';
-import Spinner from '../ui/Spinner';
-
-interface Props {
- onLoad: (details: { name: string }) => void;
- ruleKey: string;
-}
-
-interface State {
- loading: boolean;
- referencedRepositories: Dict<{ key: string; language: string; name: string }>;
- ruleDetails?: RuleDetails;
-}
-
-export default class WorkspaceRuleDetails extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { loading: true, referencedRepositories: {} };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchRuleDetails();
- }
-
- componentDidUpdate(prevProps: Props) {
- if (prevProps.ruleKey !== this.props.ruleKey) {
- this.fetchRuleDetails();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchRuleDetails = () => {
- this.setState({ loading: true });
- Promise.all([getRulesApp(), getRuleDetails({ key: this.props.ruleKey })]).then(
- ([{ repositories }, { rule }]) => {
- if (this.mounted) {
- this.setState({
- loading: false,
- referencedRepositories: keyBy(repositories, 'key'),
- ruleDetails: rule,
- });
- this.props.onLoad({ name: rule.name });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- noOp = () => {};
-
- render() {
- return (
- <Spinner loading={this.state.loading}>
- {this.state.ruleDetails && (
- <>
- <RuleDetailsMeta
- canWrite={false}
- onTagsChange={this.noOp}
- referencedRepositories={this.state.referencedRepositories}
- ruleDetails={this.state.ruleDetails}
- />
- <RuleDetailsDescription
- canWrite={false}
- onChange={this.noOp}
- ruleDetails={this.state.ruleDetails}
- />
- </>
- )}
- </Spinner>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 * as React from 'react';
-import { colors } from '../../app/theme';
-import LightBulbIcon from '../../components/icons/LightBulbIcon';
-import { RuleDescriptor } from './context';
-
-interface Props {
- limited?: boolean;
- rule: RuleDescriptor;
-}
-
-export default function WorkspaceRuleTitle({ limited, rule }: Props) {
- const { name = '—' } = rule;
- return (
- <>
- <LightBulbIcon className="little-spacer-right" fill={colors.blue} />
- {limited ? <span className="text-limited">{name}</span> : name}
- </>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 * as React from 'react';
-import { RuleDescriptor } from './context';
-import WorkspaceHeader, { Props as WorkspaceHeaderProps } from './WorkspaceHeader';
-import WorkspaceRuleDetails from './WorkspaceRuleDetails';
-import WorkspaceRuleTitle from './WorkspaceRuleTitle';
-
-export interface Props extends Omit<WorkspaceHeaderProps, 'children' | 'onClose'> {
- rule: RuleDescriptor;
- height: number;
- onClose: (componentKey: string) => void;
- onLoad: (details: { key: string; name: string }) => void;
-}
-
-interface State {
- loading: boolean;
-}
-
-export default class WorkspaceRuleViewer extends React.PureComponent<Props> {
- state: State = { loading: true };
-
- componentDidUpdate(prevProps: Props) {
- if (prevProps.rule.key !== this.props.rule.key) {
- this.setState({ loading: true });
- }
- }
-
- handleClose = () => {
- this.props.onClose(this.props.rule.key);
- };
-
- handleLoaded = (rule: { name: string }) => {
- this.props.onLoad({ key: this.props.rule.key, name: rule.name });
- // Allow time for the actual rendering, and the browser to pick it up.
- setTimeout(() => {
- this.setState({ loading: false });
- }, 1000);
- };
-
- render() {
- const { rule } = this.props;
- const { loading } = this.state;
-
- return (
- <div className="workspace-viewer">
- <WorkspaceHeader
- maximized={this.props.maximized}
- onClose={this.handleClose}
- onCollapse={this.props.onCollapse}
- onMaximize={this.props.onMaximize}
- onMinimize={this.props.onMinimize}
- onResize={this.props.onResize}
- >
- <WorkspaceRuleTitle rule={rule} />
- </WorkspaceHeader>
-
- <div
- aria-busy={loading}
- aria-live="polite"
- className="workspace-viewer-container"
- style={{ height: this.props.height }}
- >
- <WorkspaceRuleDetails onLoad={this.handleLoaded} ruleKey={rule.key} />
- </div>
- </div>
- );
- }
-}
* 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 userEvent from '@testing-library/user-event';
import * as React from 'react';
import { mockBranch } from '../../../helpers/mocks/branch-like';
import { get, save } from '../../../helpers/storage';
-import { waitAndUpdate } from '../../../helpers/testUtils';
+import { renderComponent } from '../../../helpers/testReactTestingUtils';
+import { byRole, byText } from '../../../helpers/testSelector';
+import { BranchLike } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
-import Workspace, { INITIAL_HEIGHT, MIN_HEIGHT, TYPE_KEY, WorkspaceTypes } from '../Workspace';
+import Workspace, { TYPE_KEY, WorkspaceTypes } from '../Workspace';
+import { WorkspaceContext } from '../context';
jest.mock('../../../helpers/storage', () => {
return {
- get: jest.fn(),
+ get: jest.fn(() => {
+ throw Error('no local storage');
+ }),
save: jest.fn(),
};
});
jest.mock('../../../api/rules', () => ({
getRulesApp: jest.fn().mockResolvedValue({
- repositories: [
- { key: 'foo', name: 'Foo' },
- { key: 'external_bar', name: 'Bar' },
- ],
+ repositories: [{ key: 'repo', language: 'xoo', name: 'Xoo Repository' }],
}),
}));
+// Simplify the SourceViewer
+jest.mock('../../SourceViewer/SourceViewer', () => {
+ function SourceViewer({
+ component,
+ onLoaded,
+ }: {
+ component: string;
+ onLoaded: (component: { path: string; q: string }) => void;
+ }) {
+ // Trigger the "loadComponent" to update the name of the component
+ React.useEffect(() => {
+ onLoaded({ path: `path/to/component/${component}`, q: ComponentQualifier.File });
+ }, [component, onLoaded]);
+
+ return <div />;
+ }
+
+ return {
+ __esModule: true,
+ default: SourceViewer,
+ };
+});
+
const WINDOW_HEIGHT = 1000;
const originalHeight = window.innerHeight;
beforeEach(jest.clearAllMocks);
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot('default');
- expect(
- shallowRender({
- components: [{ branchLike: mockBranch(), key: 'foo' }],
- open: { component: 'foo' },
- })
- ).toMatchSnapshot('open component');
-});
-
-it('should correctly load data from local storage', () => {
- const rule1 = { [TYPE_KEY]: WorkspaceTypes.Rule, key: 'foo' };
- const rule2 = {
- [TYPE_KEY]: WorkspaceTypes.Rule,
- key: 'baz',
- name: 'Baz',
- };
+it('should load data from local storage and allow to open another component', async () => {
+ const user = userEvent.setup();
const component = {
[TYPE_KEY]: WorkspaceTypes.Component,
branchLike: mockBranch(),
key: 'foo',
+ name: 'previously opened file',
};
- (get as jest.Mock).mockReturnValue(JSON.stringify([rule1, rule2, component]));
+ jest.mocked(get).mockReturnValueOnce(JSON.stringify([component]));
- let wrapper = shallowRender();
- expect(wrapper.state().rules).toEqual([rule1, rule2]);
- expect(wrapper.state().components).toEqual([component]);
+ renderWorkspace();
- (get as jest.Mock).mockImplementationOnce(() => {
- throw Error('No local storage');
- });
- wrapper = shallowRender();
- expect(wrapper.state().rules).toEqual([]);
- expect(wrapper.state().components).toEqual([]);
-});
+ expect(byText('previously opened file').get()).toBeInTheDocument();
+ expect(
+ byRole('heading', { name: 'qualifier.FIL path/to/component/k1' }).query()
+ ).not.toBeInTheDocument();
-it('should correctly store data locally', () => {
- const wrapper = shallowRender({
- components: [{ branchLike: mockBranch(), key: 'foo' }],
- rules: [{ key: 'foo' }],
- });
- wrapper.instance().saveWorkspace();
- expect((save as jest.Mock).mock.calls[0][1]).toMatchSnapshot();
-});
+ await user.click(ui.componentOpenButton.get());
-it('should load rule engine names', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- expect(wrapper.state().externalRulesRepoNames).toEqual({ bar: 'Bar' });
+ expect(
+ byRole('heading', { name: 'qualifier.FIL path/to/component/k1' }).get()
+ ).toBeInTheDocument();
+ expect(save).toHaveBeenCalled();
});
-it('should allow elements to be loaded and updated', () => {
- const component = { key: 'foo', branchLike: mockBranch() };
- const rule = { key: 'bar' };
- const wrapper = shallowRender({
- components: [component],
- rules: [rule],
- });
- const instance = wrapper.instance();
+it('should be resizable', async () => {
+ const user = userEvent.setup();
- instance.handleComponentLoad({ key: 'baz', name: 'Baz', qualifier: ComponentQualifier.TestFile });
- expect(wrapper.state().components).toEqual([component]);
+ renderWorkspace();
- instance.handleComponentLoad({ key: 'foo', name: 'Foo', qualifier: ComponentQualifier.File });
- expect(wrapper.state().components).toEqual([
- { ...component, name: 'Foo', qualifier: ComponentQualifier.File },
- ]);
-});
+ await user.click(ui.componentOpenButton.get());
-it('should be resizable', () => {
- (get as jest.Mock).mockReturnValue(
- JSON.stringify([{ [TYPE_KEY]: WorkspaceTypes.Rule, key: 'foo' }])
- );
- const wrapper = shallowRender();
- const instance = wrapper.instance();
+ expect(ui.workspaceViewerContainer.get()).toHaveStyle({ height: '300px' });
- instance.handleMaximize();
- expect(wrapper.state().maximized).toBe(true);
+ await user.click(ui.fullWindowButton.get());
- instance.handleMinimize();
- expect(wrapper.state().maximized).toBe(false);
+ // 85% of window height, forced at 1000 in the test (WINDOW_HEIGHT)
+ expect(ui.workspaceViewerContainer.get()).toHaveStyle({ height: '850px' });
- instance.handleResize(-200);
- expect(wrapper.state().height).toBe(INITIAL_HEIGHT + 200);
+ expect(ui.normalWindowButton.get()).toBeInTheDocument();
+ expect(ui.fullWindowButton.query()).not.toBeInTheDocument();
+ await user.click(ui.normalWindowButton.get());
- instance.handleResize(1000);
- expect(wrapper.state().height).toBe(WINDOW_HEIGHT * MIN_HEIGHT);
-});
-
-it('should be openable/collapsible', () => {
- const component = {
- branchLike: mockBranch(),
- key: 'foo',
- };
- const wrapper = shallowRender();
- const instance = wrapper.instance();
+ expect(ui.workspaceViewerContainer.get()).toHaveStyle({ height: '300px' });
- instance.handleOpenComponent(component);
- expect(wrapper.state().open).toEqual({ component: 'foo' });
+ await user.click(ui.collapseButton.get());
- instance.handleCollapse();
- expect(wrapper.state().open).toEqual({});
+ expect(ui.workspaceViewerContainer.query()).not.toBeInTheDocument();
- instance.handleComponentReopen(component.key);
- expect(wrapper.state().open).toEqual({ component: 'foo' });
+ const fileLink = byRole('link', { name: 'qualifier.FIL path/to/component/k1' });
+ expect(fileLink.get()).toBeInTheDocument();
+ await user.click(fileLink.get());
- instance.handleComponentClose('bar');
- expect(wrapper.state().open).toEqual({ component: 'foo' });
- instance.handleComponentClose('foo');
- expect(wrapper.state().open).toEqual({});
+ await user.click(ui.closeButton.get());
+ expect(fileLink.query()).not.toBeInTheDocument();
});
-function shallowRender(state?: Partial<Workspace['state']>) {
- const wrapper = shallow<Workspace>(
+function renderWorkspace(componentKey = 'k1', branchLike?: BranchLike) {
+ return renderComponent(
<Workspace>
- <div className="child" />
+ <TestComponent componentKey={componentKey} branchLike={branchLike} />
</Workspace>
);
- return state ? wrapper.setState(state as Workspace['state']) : wrapper;
}
+
+function TestComponent({
+ componentKey,
+ branchLike,
+}: {
+ componentKey: string;
+ branchLike?: BranchLike;
+}) {
+ const { openComponent } = React.useContext(WorkspaceContext);
+
+ const clickHandler = React.useCallback(() => {
+ openComponent({
+ key: componentKey,
+ branchLike,
+ name: componentKey,
+ qualifier: ComponentQualifier.File,
+ });
+ }, [openComponent, componentKey, branchLike]);
+
+ return (
+ <button type="button" onClick={clickHandler}>
+ open component
+ </button>
+ );
+}
+
+const ui = {
+ componentOpenButton: byRole('button', { name: 'open component' }),
+ collapseButton: byRole('button', { name: 'workspace.minimize' }),
+ normalWindowButton: byRole('button', { name: 'workspace.normal_size' }),
+ fullWindowButton: byRole('button', { name: 'workspace.full_window' }),
+ closeButton: byRole('button', { name: 'workspace.close' }),
+ workspaceViewerContainer: byRole('complementary'),
+};
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 WorkspaceComponentTitle from '../WorkspaceComponentTitle';
-
-it('should render component', () => {
- const component = { branchLike: undefined, key: 'foo' };
- expect(shallow(<WorkspaceComponentTitle component={component} />)).toMatchSnapshot();
-});
-
-it('should render loaded component', () => {
- const component = { branchLike: undefined, key: 'foo', name: 'src/foo.js', qualifier: 'FIL' };
- expect(shallow(<WorkspaceComponentTitle component={component} />)).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 WorkspaceHeader, { Props } from '../WorkspaceHeader';
-
-it('should render', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should resize', () => {
- const onResize = jest.fn();
- const wrapper = shallowRender({ onResize });
- wrapper.find('DraggableCore').prop<Function>('onDrag')({}, { deltaY: 15 });
- expect(onResize).toHaveBeenCalledWith(15);
-});
-
-function shallowRender(props?: Partial<Props>) {
- return shallow(
- <WorkspaceHeader
- onClose={jest.fn()}
- onCollapse={jest.fn()}
- onMaximize={jest.fn()}
- onMinimize={jest.fn()}
- onResize={jest.fn()}
- {...props}
- >
- <div id="workspace-header-children" />
- </WorkspaceHeader>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 WorkspaceNav, { Props } from '../WorkspaceNav';
-
-it('should render', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should not render open component', () => {
- expect(shallowRender({ open: { component: 'bar' } })).toMatchSnapshot();
-});
-
-function shallowRender(props?: Partial<Props>) {
- const components = [
- { branchLike: undefined, key: 'foo' },
- { branchLike: undefined, key: 'bar' },
- ];
- return shallow(
- <WorkspaceNav
- components={components}
- onComponentClose={jest.fn()}
- onComponentOpen={jest.fn()}
- open={{}}
- {...props}
- />
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 WorkspaceNavComponent, { Props } from '../WorkspaceNavComponent';
-
-it('should render', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should close', () => {
- const onClose = jest.fn();
- const wrapper = shallowRender({ onClose });
- wrapper.find('WorkspaceNavItem').prop<Function>('onClose')();
- expect(onClose).toHaveBeenCalledWith('foo');
-});
-
-it('should open', () => {
- const onOpen = jest.fn();
- const wrapper = shallowRender({ onOpen });
- wrapper.find('WorkspaceNavItem').prop<Function>('onOpen')();
- expect(onOpen).toHaveBeenCalledWith('foo');
-});
-
-function shallowRender(props?: Partial<Props>) {
- const component = { branchLike: undefined, key: 'foo' };
- return shallow(
- <WorkspaceNavComponent
- component={component}
- onClose={jest.fn()}
- onOpen={jest.fn()}
- {...props}
- />
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 WorkspaceNavItem, { Props } from '../WorkspaceNavItem';
-
-it('should render', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should close', () => {
- const onClose = jest.fn();
- const wrapper = shallowRender({ onClose });
- click(wrapper.find('ClearButton'));
- expect(onClose).toHaveBeenCalled();
-});
-
-it('should open', () => {
- const onOpen = jest.fn();
- const wrapper = shallowRender({ onOpen });
- click(wrapper.find('.workspace-nav-item-link'));
- expect(onOpen).toHaveBeenCalled();
-});
-
-function shallowRender(props?: Partial<Props>) {
- return shallow(
- <WorkspaceNavItem onClose={jest.fn()} onOpen={jest.fn()} {...props}>
- <div id="workspace-nav-item" />
- </WorkspaceNavItem>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 WorkspaceNavRule, { Props } from '../WorkspaceNavRule';
-
-it('should render', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should close', () => {
- const onClose = jest.fn();
- const wrapper = shallowRender({ onClose });
- wrapper.find('WorkspaceNavItem').prop<Function>('onClose')();
- expect(onClose).toHaveBeenCalledWith('foo');
-});
-
-it('should open', () => {
- const onOpen = jest.fn();
- const wrapper = shallowRender({ onOpen });
- wrapper.find('WorkspaceNavItem').prop<Function>('onOpen')();
- expect(onOpen).toHaveBeenCalledWith('foo');
-});
-
-function shallowRender(props?: Partial<Props>) {
- const rule = { key: 'foo' };
- return shallow(
- <WorkspaceNavRule onClose={jest.fn()} onOpen={jest.fn()} rule={rule} {...props} />
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 WorkspacePortal from '../WorkspacePortal';
-
-it('should create portal element', () => {
- const wrapper = shallow(<WorkspacePortal />);
- const { el } = wrapper.instance() as WorkspacePortal;
- expect(el.tagName.toLowerCase()).toBe('div');
- expect(el.className).toBe('workspace');
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 { waitAndUpdate } from '../../../helpers/testUtils';
-import WorkspaceRuleDetails from '../WorkspaceRuleDetails';
-
-jest.mock('../../../api/rules', () => ({
- getRulesApp: jest.fn(() =>
- Promise.resolve({ repositories: [{ key: 'repo', language: 'xoo', name: 'Xoo Repository' }] })
- ),
- getRuleDetails: jest.fn(() => Promise.resolve({ rule: { key: 'foo', name: 'Foo' } })),
-}));
-
-it('should render', async () => {
- const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
-
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should call back on load', async () => {
- const onLoad = jest.fn();
- const wrapper = shallowRender({ onLoad });
- await waitAndUpdate(wrapper);
- expect(onLoad).toHaveBeenCalledWith({ name: 'Foo' });
-});
-
-function shallowRender(props?: Partial<WorkspaceRuleDetails['props']>) {
- return shallow<WorkspaceRuleDetails>(
- <WorkspaceRuleDetails onLoad={jest.fn()} ruleKey="foo" {...props} />
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 WorkspaceRuleTitle from '../WorkspaceRuleTitle';
-
-it('should render rule', () => {
- const rule = { key: 'foo' };
- expect(shallow(<WorkspaceRuleTitle rule={rule} />)).toMatchSnapshot();
-});
-
-it('should render loaded rule', () => {
- const rule = { key: 'foo', name: 'Foo' };
- expect(shallow(<WorkspaceRuleTitle rule={rule} />)).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 WorkspaceRuleViewer, { Props } from '../WorkspaceRuleViewer';
-
-beforeEach(() => {
- jest.useFakeTimers();
-});
-
-afterEach(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-it('should render', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should correctly mark the content as busy loading (aria)', () => {
- const rule = { key: 'foo', name: 'Foo' };
- const wrapper = shallowRender({ rule });
- const instance = wrapper.instance();
- const container = () => wrapper.find('.workspace-viewer-container');
-
- expect(container().prop('aria-busy')).toBe(true);
-
- instance.handleLoaded(rule);
- jest.runAllTimers();
- wrapper.update();
- expect(container().prop('aria-busy')).toBe(false);
-
- const newRule = { key: 'bar', name: 'Bar' };
- wrapper.setProps({ rule: newRule }).update();
- expect(container().prop('aria-busy')).toBe(true);
-
- instance.handleLoaded(newRule);
- jest.runAllTimers();
- wrapper.update();
- expect(container().prop('aria-busy')).toBe(false);
-});
-
-it('should close', () => {
- const onClose = jest.fn();
- const wrapper = shallowRender({ onClose });
- wrapper.find('WorkspaceHeader').prop<Function>('onClose')();
- expect(onClose).toHaveBeenCalledWith('foo');
-});
-
-it('should call back after load', () => {
- const onLoad = jest.fn();
- const wrapper = shallowRender({ onLoad });
- const details = wrapper.findWhere((w) => w.name().includes('WorkspaceRuleDetails'));
- details.prop<Function>('onLoad')({ name: 'Foo' });
- expect(onLoad).toHaveBeenCalledWith({ key: 'foo', name: 'Foo' });
-});
-
-function shallowRender(props?: Partial<Props>) {
- const rule = { key: 'foo', name: 'Foo' };
- return shallow<WorkspaceRuleViewer>(
- <WorkspaceRuleViewer
- height={300}
- onClose={jest.fn()}
- onCollapse={jest.fn()}
- onLoad={jest.fn()}
- onMaximize={jest.fn()}
- onMinimize={jest.fn()}
- onResize={jest.fn()}
- rule={rule}
- {...props}
- />
- );
-}
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should correctly store data locally 1`] = `"[{"branchLike":{"analysisDate":"2018-01-01","excludedFromPurge":true,"isMain":false,"name":"branch-6.7"},"key":"foo","__type__":"component"},{"key":"foo","__type__":"rule"}]"`;
-
-exports[`should render correctly: default 1`] = `
-<ContextProvider
- value={
- {
- "externalRulesRepoNames": {},
- "openComponent": [Function],
- }
- }
->
- <div
- className="child"
- />
- <WorkspacePortal />
-</ContextProvider>
-`;
-
-exports[`should render correctly: open component 1`] = `
-<ContextProvider
- value={
- {
- "externalRulesRepoNames": {},
- "openComponent": [Function],
- }
- }
->
- <div
- className="child"
- />
- <WorkspacePortal>
- <WorkspaceNav
- components={
- [
- {
- "branchLike": {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": false,
- "name": "branch-6.7",
- },
- "key": "foo",
- },
- ]
- }
- onComponentClose={[Function]}
- onComponentOpen={[Function]}
- open={
- {
- "component": "foo",
- }
- }
- />
- <WorkspaceComponentViewer
- component={
- {
- "branchLike": {
- "analysisDate": "2018-01-01",
- "excludedFromPurge": true,
- "isMain": false,
- "name": "branch-6.7",
- },
- "key": "foo",
- }
- }
- height={300}
- onClose={[Function]}
- onCollapse={[Function]}
- onLoad={[Function]}
- onMaximize={[Function]}
- onMinimize={[Function]}
- onResize={[Function]}
- />
- </WorkspacePortal>
-</ContextProvider>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render component 1`] = `
-<Fragment>
- —
-</Fragment>
-`;
-
-exports[`should render loaded component 1`] = `
-<Fragment>
- <QualifierIcon
- className="little-spacer-right"
- qualifier="FIL"
- />
- src/foo.js
-</Fragment>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<header
- className="workspace-viewer-header"
->
- <h6
- className="workspace-viewer-name"
- >
- <div
- id="workspace-header-children"
- />
- </h6>
- <DraggableCore
- allowAnyClick={false}
- disabled={false}
- enableUserSelectHack={true}
- offsetParent={<body />}
- onDrag={[Function]}
- onMouseDown={[Function]}
- onStart={[Function]}
- onStop={[Function]}
- scale={1}
- >
- <div
- className="workspace-viewer-resize js-resize"
- />
- </DraggableCore>
- <div
- className="workspace-viewer-actions"
- >
- <WorkspaceHeaderButton
- icon={[Function]}
- onClick={[MockFunction]}
- tooltip="workspace.minimize"
- />
- <WorkspaceHeaderButton
- icon={[Function]}
- onClick={[MockFunction]}
- tooltip="workspace.full_window"
- />
- <WorkspaceHeaderButton
- icon={[Function]}
- onClick={[MockFunction]}
- tooltip="workspace.close"
- />
- </div>
-</header>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should not render open component 1`] = `
-<nav
- className="workspace-nav"
->
- <ul
- className="workspace-nav-list"
- >
- <WorkspaceNavComponent
- component={
- {
- "branchLike": undefined,
- "key": "foo",
- }
- }
- key="component-foo"
- onClose={[MockFunction]}
- onOpen={[MockFunction]}
- />
- </ul>
-</nav>
-`;
-
-exports[`should render 1`] = `
-<nav
- className="workspace-nav"
->
- <ul
- className="workspace-nav-list"
- >
- <WorkspaceNavComponent
- component={
- {
- "branchLike": undefined,
- "key": "foo",
- }
- }
- key="component-foo"
- onClose={[MockFunction]}
- onOpen={[MockFunction]}
- />
- <WorkspaceNavComponent
- component={
- {
- "branchLike": undefined,
- "key": "bar",
- }
- }
- key="component-bar"
- onClose={[MockFunction]}
- onOpen={[MockFunction]}
- />
- </ul>
-</nav>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<WorkspaceNavItem
- onClose={[Function]}
- onOpen={[Function]}
->
- <WorkspaceComponentTitle
- component={
- {
- "branchLike": undefined,
- "key": "foo",
- }
- }
- limited={true}
- />
-</WorkspaceNavItem>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<li
- className="workspace-nav-item"
->
- <a
- className="workspace-nav-item-link"
- href="#"
- onClick={[Function]}
- >
- <div
- id="workspace-nav-item"
- />
- </a>
- <ClearButton
- className="js-close workspace-nav-item-close workspace-header-icon button-small little-spacer-left"
- color="#fff"
- iconProps={
- {
- "size": 12,
- }
- }
- onClick={[MockFunction]}
- />
-</li>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<WorkspaceNavItem
- onClose={[Function]}
- onOpen={[Function]}
->
- <WorkspaceRuleTitle
- limited={true}
- rule={
- {
- "key": "foo",
- }
- }
- />
-</WorkspaceNavItem>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<Spinner
- loading={true}
-/>
-`;
-
-exports[`should render 2`] = `
-<Spinner
- loading={false}
->
- <RuleDetailsMeta
- canWrite={false}
- onTagsChange={[Function]}
- referencedRepositories={
- {
- "repo": {
- "key": "repo",
- "language": "xoo",
- "name": "Xoo Repository",
- },
- }
- }
- ruleDetails={
- {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <RuleDetailsDescription
- canWrite={false}
- onChange={[Function]}
- ruleDetails={
- {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
-</Spinner>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render loaded rule 1`] = `
-<Fragment>
- <LightBulbIcon
- className="little-spacer-right"
- fill="#4b9fd5"
- />
- Foo
-</Fragment>
-`;
-
-exports[`should render rule 1`] = `
-<Fragment>
- <LightBulbIcon
- className="little-spacer-right"
- fill="#4b9fd5"
- />
- —
-</Fragment>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<div
- className="workspace-viewer"
->
- <WorkspaceHeader
- onClose={[Function]}
- onCollapse={[MockFunction]}
- onMaximize={[MockFunction]}
- onMinimize={[MockFunction]}
- onResize={[MockFunction]}
- >
- <WorkspaceRuleTitle
- rule={
- {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- </WorkspaceHeader>
- <div
- aria-busy={true}
- aria-live="polite"
- className="workspace-viewer-container"
- style={
- {
- "height": 300,
- }
- }
- >
- <WorkspaceRuleDetails
- onLoad={[Function]}
- ruleKey="foo"
- />
- </div>
-</div>
-`;