page.shouldHaveTotal(2).shouldDisplayAllProjects();
}
+ @Test
+ public void should_add_language() {
+ ProjectsPage page = nav.openProjects();
+ page.getFacetByProperty("languages")
+ .selectOptionItem("xoo2")
+ .shouldHaveValue("xoo2", "0");
+ }
+
+ @Test
+ public void should_sort_by_facet() {
+ ProjectsPage page = nav.openProjects();
+ page.getFacetByProperty("duplications")
+ .sortListDesc();
+ page.getProjectByIdx(0).shouldHaveMeasure("duplicated_lines_density", "63.7%");
+ page.getFacetByProperty("duplications")
+ .sortListAsc();
+ page.getProjectByIdx(0).shouldHaveMeasure("duplicated_lines_density", "0.0%");
+ }
+
+ @Test
+ public void should_search_for_project() {
+ ProjectsPage page = nav.openProjects();
+ page.searchProject("s").shouldHaveTotal(2);
+ page.searchProject("sam").shouldHaveTotal(1);
+ }
}
package pageobjects.projects;
import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
import com.codeborne.selenide.SelenideElement;
+import org.openqa.selenium.WebElement;
public class FacetItem {
public void selectValue(String key) {
this.elt.$(".facet[data-key=\"" + key + "\"]").click();
}
+
+ public FacetItem selectOptionItem(String value) {
+ this.elt.$(".Select-input input").val(value).pressEnter();
+ return this;
+ }
+
+ public FacetItem sortListDesc() {
+ this.getSortingButton("-").click();
+ return this;
+ }
+
+ public FacetItem sortListAsc() {
+ this.getSortingButton("[a-zA-Z ]").click();
+ return this;
+ }
+
+ public SelenideElement getSortingButton(String selector) {
+ ElementsCollection buttons = this.elt.$$(".projects-facet-sort a");
+ return buttons.find(new Condition("AttributeMatch") {
+ @Override
+ public boolean apply(WebElement webElement) {
+ return webElement.getAttribute("href").matches(".*sort=" + selector + ".*");
+ }
+ });
+ }
}
return new ProjectItem(element);
}
+ public ProjectItem getProjectByIdx(Integer idx) {
+ return new ProjectItem(getProjects().get(idx));
+ }
+
public FacetItem getFacetByProperty(String facetProperty) {
SelenideElement element = getFacets().find(Condition.attribute("data-key", facetProperty));
return new FacetItem(element);
$("#favorite-projects").click();
return shouldDisplayFavoriteProjects();
}
+
+ public ProjectsPage searchProject(String search) {
+ SelenideElement searchInput = $(".projects-facet-search input");
+ searchInput.setValue("").sendKeys(search);
+ return this;
+ }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 React from 'react';
+import { shallow } from 'enzyme';
+import LanguageFilterFooter from '../LanguageFilterFooter';
+
+const languages = {
+ java: {
+ key: 'java',
+ name: 'Java'
+ },
+ cs: {
+ key: 'cs',
+ name: 'C#'
+ },
+ js: {
+ key: 'js',
+ name: 'JavaScript'
+ },
+ flex: {
+ key: 'flex',
+ name: 'Flex'
+ },
+ php: {
+ key: 'php',
+ name: 'PHP'
+ },
+ py: {
+ key: 'py',
+ name: 'Python'
+ }
+};
+const facet = { java: 39, cs: 4, js: 1 };
+
+it('should render the languages without the ones in the facet', () => {
+ const wrapper = shallow(
+ <LanguageFilterFooter
+ property="foo"
+ query={{ languages: null }}
+ facet={facet}
+ languages={languages}/>
+ );
+ expect(wrapper).toMatchSnapshot();
+ expect(wrapper.find('Select').props().options.length).toBe(3);
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 React from 'react';
+import { shallow } from 'enzyme';
+import SearchFilter from '../SearchFilter';
+
+it('should render correctly without any search query', () => {
+ const wrapper = shallow(
+ <SearchFilter
+ handleSearch={() => {}}
+ query={{ search: null }}/>
+ );
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render with a search query', () => {
+ const wrapper = shallow(
+ <SearchFilter
+ handleSearch={() => {}}
+ query={{ search: 'foo' }}/>
+ );
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should display a help message when there is less than 2 characters', () => {
+ const wrapper = shallow(
+ <SearchFilter
+ handleSearch={() => {}}
+ query={{ search: 'a' }}/>
+ );
+ expect(wrapper).toMatchSnapshot();
+ wrapper.setState({ userQuery: 'foo' });
+ expect(wrapper).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 React from 'react';
+import { shallow } from 'enzyme';
+import SortingFilter from '../SortingFilter';
+
+it('should render with default parameters and empty query', () => {
+ const wrapper = shallow(
+ <SortingFilter
+ property="foo"
+ query={{}}/>
+ );
+ expect(wrapper).toMatchSnapshot();
+ const sortingFilter = wrapper.instance();
+ expect(sortingFilter.isSortActive('left')).toBeFalsy();
+ expect(sortingFilter.isSortActive('right')).toBeFalsy();
+});
+
+it('should render with custom parameters', () => {
+ const wrapper = shallow(
+ <SortingFilter
+ property="foo"
+ query={{}}
+ sortDesc="right"
+ leftText="worst"
+ rightText="best"/>
+ );
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render correctly with matching query', () => {
+ const wrapper = shallow(
+ <SortingFilter
+ property="foo"
+ query={{ sort: '-foo', languages: 'php,cpp' }}
+ sortDesc="right"/>
+ );
+ expect(wrapper).toMatchSnapshot();
+ const sortingFilter = wrapper.instance();
+ expect(sortingFilter.isSortActive('left')).toBeFalsy();
+ expect(sortingFilter.isSortActive('right')).toBeTruthy();
+});
+
+it('should render correctly with no matching query', () => {
+ const wrapper = shallow(
+ <SortingFilter
+ property="foo"
+ query={{ sort: 'bar' }}/>
+ );
+ expect(wrapper).toMatchSnapshot();
+ const sortingFilter = wrapper.instance();
+ expect(sortingFilter.isSortActive('left')).toBeFalsy();
+ expect(sortingFilter.isSortActive('right')).toBeFalsy();
+});
--- /dev/null
+exports[`test should render the languages without the ones in the facet 1`] = `
+<Select
+ addLabelText="Add \"{label}\"?"
+ arrowRenderer={[Function]}
+ autosize={true}
+ backspaceRemoves={true}
+ backspaceToRemoveMessage="Press backspace to remove {label}"
+ className="input-super-large"
+ clearAllText="Clear all"
+ clearValueText="Clear value"
+ clearable={false}
+ delimiter=","
+ disabled={false}
+ escapeClearsValue={true}
+ filterOptions={[Function]}
+ ignoreAccents={true}
+ ignoreCase={true}
+ inputProps={Object {}}
+ isLoading={false}
+ joinValues={false}
+ labelKey="label"
+ matchPos="any"
+ matchProp="any"
+ menuBuffer={0}
+ menuRenderer={[Function]}
+ multi={false}
+ noResultsText="No results found"
+ onBlurResetsInput={true}
+ onChange={[Function]}
+ onCloseResetsInput={true}
+ openAfterFocus={false}
+ optionComponent={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "Flex",
+ "value": "flex",
+ },
+ Object {
+ "label": "PHP",
+ "value": "php",
+ },
+ Object {
+ "label": "Python",
+ "value": "py",
+ },
+ ]
+ }
+ pageSize={5}
+ placeholder="search_verb"
+ required={false}
+ scrollMenuIntoView={true}
+ searchable={true}
+ simpleValue={false}
+ tabSelectsValue={true}
+ valueComponent={[Function]}
+ valueKey="value" />
+`;
--- /dev/null
+exports[`test should display a help message when there is less than 2 characters 1`] = `
+<div
+ className="projects-facet-search"
+ data-key="search">
+ <input
+ autoComplete="off"
+ className="input-super-large touched"
+ onChange={[Function]}
+ placeholder="projects.search"
+ type="search"
+ value="a" />
+ <span
+ className="note spacer-left">
+ select2.tooShort.2
+ </span>
+</div>
+`;
+
+exports[`test should display a help message when there is less than 2 characters 2`] = `
+<div
+ className="projects-facet-search"
+ data-key="search">
+ <input
+ autoComplete="off"
+ className="input-super-large"
+ onChange={[Function]}
+ placeholder="projects.search"
+ type="search"
+ value="foo" />
+ <span
+ className="note spacer-left">
+ select2.tooShort.2
+ </span>
+</div>
+`;
+
+exports[`test should render correctly without any search query 1`] = `
+<div
+ className="projects-facet-search"
+ data-key="search">
+ <input
+ autoComplete="off"
+ className="input-super-large"
+ onChange={[Function]}
+ placeholder="projects.search"
+ type="search"
+ value="" />
+ <span
+ className="note spacer-left">
+ select2.tooShort.2
+ </span>
+</div>
+`;
+
+exports[`test should render with a search query 1`] = `
+<div
+ className="projects-facet-search"
+ data-key="search">
+ <input
+ autoComplete="off"
+ className="input-super-large"
+ onChange={[Function]}
+ placeholder="projects.search"
+ type="search"
+ value="foo" />
+ <span
+ className="note spacer-left">
+ select2.tooShort.2
+ </span>
+</div>
+`;
--- /dev/null
+exports[`test should render correctly with matching query 1`] = `
+<div
+ className="projects-facet-sort">
+ <span>
+ projects.sort_list
+ </span>
+ <div
+ className="spacer-left button-group">
+ <Link
+ className="button button-small button-grey"
+ onClick={[Function]}
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/projects",
+ "query": Object {
+ "languages": "php,cpp",
+ "sort": "foo",
+ },
+ }
+ }>
+ worst
+ </Link>
+ <Link
+ className="button button-small button-grey button-active"
+ onClick={[Function]}
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/projects",
+ "query": Object {
+ "languages": "php,cpp",
+ },
+ }
+ }>
+ best
+ </Link>
+ </div>
+</div>
+`;
+
+exports[`test should render correctly with no matching query 1`] = `
+<div
+ className="projects-facet-sort">
+ <span>
+ projects.sort_list
+ </span>
+ <div
+ className="spacer-left button-group">
+ <Link
+ className="button button-small button-grey"
+ onClick={[Function]}
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/projects",
+ "query": Object {
+ "sort": "-foo",
+ },
+ }
+ }>
+ worst
+ </Link>
+ <Link
+ className="button button-small button-grey"
+ onClick={[Function]}
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/projects",
+ "query": Object {
+ "sort": "foo",
+ },
+ }
+ }>
+ best
+ </Link>
+ </div>
+</div>
+`;
+
+exports[`test should render with custom parameters 1`] = `
+<div
+ className="projects-facet-sort">
+ <span>
+ projects.sort_list
+ </span>
+ <div
+ className="spacer-left button-group">
+ <Link
+ className="button button-small button-grey"
+ onClick={[Function]}
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/projects",
+ "query": Object {
+ "sort": "foo",
+ },
+ }
+ }>
+ worst
+ </Link>
+ <Link
+ className="button button-small button-grey"
+ onClick={[Function]}
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/projects",
+ "query": Object {
+ "sort": "-foo",
+ },
+ }
+ }>
+ best
+ </Link>
+ </div>
+</div>
+`;
+
+exports[`test should render with default parameters and empty query 1`] = `
+<div
+ className="projects-facet-sort">
+ <span>
+ projects.sort_list
+ </span>
+ <div
+ className="spacer-left button-group">
+ <Link
+ className="button button-small button-grey"
+ onClick={[Function]}
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/projects",
+ "query": Object {
+ "sort": "-foo",
+ },
+ }
+ }>
+ worst
+ </Link>
+ <Link
+ className="button button-small button-grey"
+ onClick={[Function]}
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/projects",
+ "query": Object {
+ "sort": "foo",
+ },
+ }
+ }>
+ best
+ </Link>
+ </div>
+</div>
+`;