@@ -36,19 +36,20 @@ | |||
"@types/react-dom": "16.8.4", | |||
"@types/react-helmet": "5.0.15", | |||
"@types/rehype-react": "4.0.0", | |||
"@typescript-eslint/parser": "2.6.0", | |||
"@typescript-eslint/eslint-plugin": "4.13.0", | |||
"@typescript-eslint/parser": "4.13.0", | |||
"babel-jest": "25.1.0", | |||
"enzyme": "3.11.0", | |||
"enzyme-adapter-react-16": "1.15.2", | |||
"enzyme-to-json": "3.4.4", | |||
"eslint": "6.8.0", | |||
"eslint-config-sonarqube": "0.6.1", | |||
"eslint-plugin-import": "2.20.1", | |||
"eslint-plugin-jest": "23.8.2", | |||
"eslint-plugin-jsx-a11y": "6.2.3", | |||
"eslint": "7.17.0", | |||
"eslint-config-sonarqube": "1.0.0", | |||
"eslint-plugin-import": "2.22.0", | |||
"eslint-plugin-jest": "24.1.0", | |||
"eslint-plugin-jsx-a11y": "6.4.0", | |||
"eslint-plugin-promise": "4.2.1", | |||
"eslint-plugin-react": "7.19.0", | |||
"eslint-plugin-react-hooks": "2.5.0", | |||
"eslint-plugin-react": "7.22.0", | |||
"eslint-plugin-react-hooks": "4.2.0", | |||
"eslint-plugin-sonarjs": "0.5.0", | |||
"fs-extra": "7.0.1", | |||
"glob-promise": "3.4.0", | |||
@@ -59,7 +60,7 @@ | |||
"react-test-renderer": "16.8.5", | |||
"remark": "11.0.2", | |||
"ts-jest": "25.2.1", | |||
"typescript": "3.8.3", | |||
"typescript": "4.1.3", | |||
"unist-util-visit": "2.0.2" | |||
}, | |||
"scripts": { |
@@ -87,7 +87,7 @@ it('should have valid links in suggestions file', () => { | |||
expect(hasErrors).toBe(false); | |||
}); | |||
it('should have valid and uniq links in url metadata field', () => { | |||
function collectErrors() { | |||
let urlLists = []; | |||
let hasErrors = false; | |||
parsedFiles.forEach(file => { | |||
@@ -103,6 +103,11 @@ it('should have valid and uniq links in url metadata field', () => { | |||
urlLists = [...urlLists, file.frontmatter.url]; | |||
}); | |||
return hasErrors; | |||
} | |||
it('should have valid and uniq links in url metadata field', () => { | |||
const hasErrors = collectErrors(); | |||
expect(hasErrors).toBe(false); | |||
}); | |||
@@ -25,7 +25,7 @@ import Sidebar from '../Sidebar'; | |||
jest.mock('../navTreeUtils', () => { | |||
return { | |||
...require.requireActual('../navTreeUtils'), | |||
...jest.requireActual('../navTreeUtils'), | |||
getNavTree: jest.fn().mockReturnValue([ | |||
'/foo/', | |||
{ |
@@ -70,7 +70,8 @@ | |||
"@types/react-virtualized": "9.21.8", | |||
"@types/sanitize-html": "1.22.0", | |||
"@types/valid-url": "1.0.2", | |||
"@typescript-eslint/parser": "2.24.0", | |||
"@typescript-eslint/eslint-plugin": "4.13.0", | |||
"@typescript-eslint/parser": "4.13.0", | |||
"autoprefixer": "9.7.4", | |||
"babel-core": "7.0.0-bridge.0", | |||
"babel-jest": "25.1.0", | |||
@@ -86,15 +87,14 @@ | |||
"enzyme-adapter-react-16": "1.15.2", | |||
"enzyme-to-json": "3.4.4", | |||
"escape-string-regexp": "2.0.0", | |||
"eslint": "6.8.0", | |||
"eslint-config-sonarqube": "0.6.1", | |||
"eslint-plugin-import": "2.20.1", | |||
"eslint-plugin-jest": "23.8.2", | |||
"eslint-plugin-jsx-a11y": "6.2.3", | |||
"eslint": "7.17.0", | |||
"eslint-config-sonarqube": "1.0.0", | |||
"eslint-plugin-import": "2.22.0", | |||
"eslint-plugin-jest": "24.1.0", | |||
"eslint-plugin-jsx-a11y": "6.4.0", | |||
"eslint-plugin-promise": "4.2.1", | |||
"eslint-plugin-react": "7.19.0", | |||
"eslint-plugin-react-hooks": "2.5.0", | |||
"eslint-plugin-sonarjs": "0.5.0", | |||
"eslint-plugin-react": "7.22.0", | |||
"eslint-plugin-react-hooks": "4.2.0", | |||
"expose-loader": "0.7.5", | |||
"glob": "7.1.6", | |||
"glob-promise": "3.4.0", | |||
@@ -116,7 +116,7 @@ | |||
"style-loader": "1.1.3", | |||
"ts-jest": "25.2.1", | |||
"ts-loader": "6.2.1", | |||
"typescript": "3.8.3", | |||
"typescript": "4.1.3", | |||
"webpack": "4.42.0", | |||
"webpack-bundle-analyzer": "3.6.1", | |||
"webpack-dev-server": "3.10.3" |
@@ -61,7 +61,7 @@ class App extends React.PureComponent<Props> { | |||
const outer = document.createElement('div'); | |||
outer.style.visibility = 'hidden'; | |||
outer.style.width = '100px'; | |||
outer.style.msOverflowStyle = 'scrollbar'; | |||
outer.style.setProperty('msOverflowStyle', 'scrollbar'); | |||
document.body.appendChild(outer); | |||
@@ -33,7 +33,7 @@ import { ComponentContainer } from '../ComponentContainer'; | |||
import PageUnavailableDueToIndexation from '../indexation/PageUnavailableDueToIndexation'; | |||
jest.mock('../../../api/branches', () => { | |||
const { mockMainBranch, mockPullRequest } = require.requireActual( | |||
const { mockMainBranch, mockPullRequest } = jest.requireActual( | |||
'../../../helpers/mocks/branch-like' | |||
); | |||
return { |
@@ -20,13 +20,21 @@ | |||
import handleRequiredAuthentication from 'sonar-ui-common/helpers/handleRequiredAuthentication'; | |||
import request from '../request-legacy'; | |||
const { checkStatus, parseError, requestTryAndRepeatUntil } = request; | |||
const { checkStatus, delay, parseError, requestTryAndRepeatUntil } = request; | |||
jest.mock('sonar-ui-common/helpers/handleRequiredAuthentication', () => ({ default: jest.fn() })); | |||
jest.mock('sonar-ui-common/helpers/cookies', () => ({ | |||
getCookie: jest.fn().mockReturnValue('qwerasdf') | |||
})); | |||
beforeAll(() => { | |||
jest.useFakeTimers(); | |||
}); | |||
afterAll(() => { | |||
jest.useRealTimers(); | |||
}); | |||
beforeEach(() => { | |||
jest.clearAllMocks(); | |||
}); | |||
@@ -91,6 +99,7 @@ describe('requestTryAndRepeatUntil', () => { | |||
for (let i = 1; i < 5; i++) { | |||
jest.runAllTimers(); | |||
expect(apiCall).toBeCalledTimes(i); | |||
// eslint-disable-next-line no-await-in-loop | |||
await new Promise(setImmediate); | |||
expect(stopRepeat).toBeCalledTimes(i); | |||
} | |||
@@ -115,6 +124,7 @@ describe('requestTryAndRepeatUntil', () => { | |||
for (let i = 1; i < 5; i++) { | |||
jest.runAllTimers(); | |||
expect(apiCall).toBeCalledTimes(i); | |||
// eslint-disable-next-line no-await-in-loop | |||
await new Promise(setImmediate); | |||
} | |||
apiCall.mockResolvedValue('Success'); | |||
@@ -141,6 +151,7 @@ describe('requestTryAndRepeatUntil', () => { | |||
for (let i = 1; i < 3; i++) { | |||
jest.runAllTimers(); | |||
expect(apiCall).toBeCalledTimes(i); | |||
// eslint-disable-next-line no-await-in-loop | |||
await new Promise(setImmediate); | |||
} | |||
apiCall.mockResolvedValue('Success'); | |||
@@ -156,6 +167,7 @@ describe('requestTryAndRepeatUntil', () => { | |||
for (let i = 1; i < 3; i++) { | |||
jest.advanceTimersByTime(500); | |||
expect(apiCall).toBeCalledTimes(i); | |||
// eslint-disable-next-line no-await-in-loop | |||
await new Promise(setImmediate); | |||
} | |||
@@ -284,3 +296,14 @@ describe('request functions', () => { | |||
}); | |||
}); | |||
}); | |||
describe('delay', () => { | |||
it('should work as expected', async () => { | |||
const param = { some: 'response' }; | |||
const promise = delay(param); | |||
jest.runAllTimers(); | |||
expect(await promise).toBe(param); | |||
}); | |||
}); |
@@ -87,7 +87,10 @@ const DEFAULT_HEADERS = { | |||
class Request { | |||
private data?: RequestData; | |||
constructor(private readonly url: string, private readonly options: { method?: string } = {}) {} | |||
constructor(private readonly url: string, private readonly options: { method?: string } = {}) { | |||
this.url = url; | |||
this.options = options; | |||
} | |||
getSubmitData(customHeaders: any = {}): { url: string; options: RequestInit } { | |||
let { url } = this; | |||
@@ -257,7 +260,9 @@ function requestDelete(url: string, data?: RequestData): Promise<any> { | |||
* Delay promise for testing purposes | |||
*/ | |||
function delay(response: any): Promise<any> { | |||
return new Promise(resolve => setTimeout(() => resolve(response), 1200)); | |||
return new Promise(resolve => { | |||
setTimeout(() => resolve(response), 1200); | |||
}); | |||
} | |||
function tryRequestAgain<T>( |
@@ -29,8 +29,11 @@ it('should render correctly', () => { | |||
it('should not refresh the page once the indexation is complete if there were failures', () => { | |||
const reload = jest.fn(); | |||
delete window.location; | |||
(window as any).location = { reload }; | |||
Object.defineProperty(window, 'location', { | |||
writable: true, | |||
value: { reload } | |||
}); | |||
const wrapper = shallowRender(); | |||
@@ -46,8 +49,11 @@ it('should not refresh the page once the indexation is complete if there were fa | |||
it('should refresh the page once the indexation is complete if there were NO failures', () => { | |||
const reload = jest.fn(); | |||
delete window.location; | |||
(window as any).location = { reload }; | |||
Object.defineProperty(window, 'location', { | |||
writable: true, | |||
value: { reload } | |||
}); | |||
const wrapper = shallowRender(); | |||
@@ -266,7 +266,8 @@ export class Menu extends React.PureComponent<Props> { | |||
{({ onToggleClick, open }) => ( | |||
<a | |||
aria-expanded={open} | |||
aria-haspopup="true" | |||
aria-haspopup="menu" | |||
role="button" | |||
className={classNames('dropdown-toggle', { active: isSettingsActive || open })} | |||
href="#" | |||
id="component-navigation-admin" | |||
@@ -558,7 +559,8 @@ export class Menu extends React.PureComponent<Props> { | |||
{({ onToggleClick, open }) => ( | |||
<a | |||
aria-expanded={open} | |||
aria-haspopup="true" | |||
aria-haspopup="menu" | |||
role="button" | |||
className={classNames('dropdown-toggle', { active: open })} | |||
href="#" | |||
id="component-navigation-more" |
@@ -17,7 +17,6 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { |
@@ -21,7 +21,7 @@ import { Location } from 'sonar-ui-common/helpers/urls'; | |||
import { BadgeOptions, BadgeType, getBadgeSnippet, getBadgeUrl } from '../utils'; | |||
jest.mock('sonar-ui-common/helpers/urls', () => ({ | |||
...require.requireActual('sonar-ui-common/helpers/urls'), | |||
...jest.requireActual('sonar-ui-common/helpers/urls'), | |||
getHostUrl: () => 'host', | |||
getPathUrlAsString: (o: Location) => | |||
`host${o.pathname}?id=${o.query ? o.query.id : ''}&branch=${o.query ? o.query.branch : ''}` |
@@ -28,7 +28,7 @@ jest.mock('../../../../../../../api/components', () => ({ | |||
})); | |||
jest.mock('lodash', () => { | |||
const lodash = require.requireActual('lodash'); | |||
const lodash = jest.requireActual('lodash'); | |||
lodash.debounce = jest.fn(fn => fn); | |||
return lodash; | |||
}); |
@@ -28,7 +28,6 @@ import { | |||
} from '../../../../../../components/hoc/withNotifications'; | |||
interface Props { | |||
className?: string; | |||
component: T.Component; | |||
} | |||
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockComponent } from '../../../../../../../helpers/testMocks'; |
@@ -139,7 +139,8 @@ export default class GlobalNavMenu extends React.PureComponent<Props> { | |||
{({ onToggleClick, open }) => ( | |||
<a | |||
aria-expanded={open} | |||
aria-haspopup="true" | |||
aria-haspopup="menu" | |||
role="button" | |||
className={classNames('dropdown-toggle', { active: open })} | |||
href="#" | |||
id="global-navigation-more" |
@@ -120,7 +120,8 @@ export default class SettingsNav extends React.PureComponent<Props> { | |||
{({ onToggleClick, open }) => ( | |||
<a | |||
aria-expanded={open} | |||
aria-haspopup="true" | |||
aria-haspopup="menu" | |||
role="button" | |||
className={classNames('dropdown-toggle', { | |||
active: | |||
open || | |||
@@ -162,7 +163,8 @@ export default class SettingsNav extends React.PureComponent<Props> { | |||
{({ onToggleClick, open }) => ( | |||
<a | |||
aria-expanded={open} | |||
aria-haspopup="true" | |||
aria-haspopup="menu" | |||
role="button" | |||
className={classNames('dropdown-toggle', { active: open || this.isProjectsActive() })} | |||
href="#" | |||
onClick={onToggleClick}> | |||
@@ -205,7 +207,8 @@ export default class SettingsNav extends React.PureComponent<Props> { | |||
{({ onToggleClick, open }) => ( | |||
<a | |||
aria-expanded={open} | |||
aria-haspopup="true" | |||
aria-haspopup="menu" | |||
role="button" | |||
className={classNames('dropdown-toggle', { active: open || this.isSecurityActive() })} | |||
href="#" | |||
onClick={onToggleClick}> |
@@ -46,11 +46,15 @@ if (isMainApp()) { | |||
} else { | |||
// login, maintenance or setup pages | |||
const appStatePromise: Promise<T.AppState> = new Promise(resolve => | |||
const appStatePromise: Promise<T.AppState | undefined> = new Promise(resolve => { | |||
loadAppState() | |||
.then(data => resolve(data)) | |||
.catch(() => resolve(undefined)) | |||
); | |||
.then(data => { | |||
resolve(data); | |||
}) | |||
.catch(() => { | |||
resolve(undefined); | |||
}); | |||
}); | |||
Promise.all([loadL10nBundle(), appStatePromise, loadApp()]).then( | |||
([l10nBundle, appState, startReactApp]) => { |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import SimpleModal from 'sonar-ui-common/components/controls/SimpleModal'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; |
@@ -25,7 +25,7 @@ import { mockComponentMeasure, mockRouter } from '../../../../helpers/testMocks' | |||
import MeasureContent from '../MeasureContent'; | |||
jest.mock('../../../../api/components', () => { | |||
const { mockComponentMeasure } = require.requireActual('../../../../helpers/testMocks'); | |||
const { mockComponentMeasure } = jest.requireActual('../../../../helpers/testMocks'); | |||
return { | |||
getComponentTree: jest.fn().mockResolvedValue({ | |||
paging: { pageIndex: 1, pageSize: 500, total: 2 }, |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockAzureProject, mockAzureRepository } from '../../../../helpers/mocks/alm-integrations'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import SearchBox from 'sonar-ui-common/components/controls/SearchBox'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import Radio from 'sonar-ui-common/components/controls/Radio'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { click } from 'sonar-ui-common/helpers/testUtils'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { SubmitButton } from 'sonar-ui-common/components/controls/buttons'; |
@@ -123,5 +123,5 @@ it('should not break the whole doc when one page cannot be parsed', () => { | |||
function getPages(overrides: T.Dict<ParsedContent> = {}) { | |||
// This allows the use of out-of-scope data inside jest.mock | |||
// Usually, it is impossible as jest.mock'ed module is hoisted on the top of the file | |||
return require.requireActual('../pages').default(overrides); | |||
return jest.requireActual('../pages').default(overrides); | |||
} |
@@ -84,7 +84,7 @@ jest.mock('sonar-ui-common/helpers/pages', () => ({ | |||
})); | |||
jest.mock('sonar-ui-common/helpers/request', () => { | |||
const { mockDocumentationMarkdown } = require.requireActual('../../../../helpers/testMocks'); | |||
const { mockDocumentationMarkdown } = jest.requireActual('../../../../helpers/testMocks'); | |||
return { | |||
request: jest.fn(() => ({ | |||
submit: jest.fn().mockResolvedValue({ | |||
@@ -96,7 +96,7 @@ jest.mock('sonar-ui-common/helpers/request', () => { | |||
}); | |||
jest.mock('../../pages', () => { | |||
const { mockDocumentationEntry } = require.requireActual('../../../../helpers/testMocks'); | |||
const { mockDocumentationEntry } = jest.requireActual('../../../../helpers/testMocks'); | |||
return { | |||
default: jest | |||
.fn() |
@@ -110,7 +110,8 @@ export default class App extends React.PureComponent<{}, State> { | |||
// reload all pages in order | |||
if (paging && paging.pageIndex > 1) { | |||
for (let p = 1; p < paging.pageIndex; p++) { | |||
await this.fetchMoreGroups(); | |||
// eslint-disable-next-line no-await-in-loop | |||
await this.fetchMoreGroups(); // This is a intentional promise chain | |||
} | |||
} | |||
}; |
@@ -25,7 +25,6 @@ import { getSelectedLocation } from '../utils'; | |||
interface Props { | |||
component?: T.Component; | |||
issue: T.Issue; | |||
link?: boolean; | |||
selectedFlowIndex?: number; | |||
selectedLocationIndex?: number; | |||
} |
@@ -22,7 +22,6 @@ import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import PageCounter from '../../../components/common/PageCounter'; | |||
interface Props { | |||
className?: string; | |||
current: number | undefined; | |||
total: number; | |||
} |
@@ -61,9 +61,7 @@ export default class PageActions extends React.PureComponent<Props> { | |||
<div className="issues-page-actions"> | |||
<ReloadButton onClick={this.props.onReload} /> | |||
{paging != null && ( | |||
<IssuesCounter className="spacer-left" current={selectedIndex} total={paging.total} /> | |||
)} | |||
{paging != null && <IssuesCounter current={selectedIndex} total={paging.total} />} | |||
{effortTotal !== undefined && <TotalEffort effort={effortTotal} />} | |||
</div> | |||
@@ -43,7 +43,6 @@ exports[`should render 1`] = ` | |||
onClick={[MockFunction]} | |||
/> | |||
<IssuesCounter | |||
className="spacer-left" | |||
current={5} | |||
total={12345} | |||
/> |
@@ -32,7 +32,7 @@ import { | |||
import CrossComponentSourceViewerWrapper from '../CrossComponentSourceViewerWrapper'; | |||
jest.mock('../../../../api/issues', () => { | |||
const { mockSnippetsByComponent } = require.requireActual('../../../../helpers/testMocks'); | |||
const { mockSnippetsByComponent } = jest.requireActual('../../../../helpers/testMocks'); | |||
return { | |||
getIssueFlowSnippets: jest.fn().mockResolvedValue({ 'main.js': mockSnippetsByComponent() }) | |||
}; |
@@ -25,7 +25,7 @@ import { Query } from '../../utils'; | |||
import StandardFacet from '../StandardFacet'; | |||
jest.mock('../../../../helpers/security-standard', () => ({ | |||
...require.requireActual('../../../../helpers/security-standard'), | |||
...jest.requireActual('../../../../helpers/security-standard'), | |||
getStandards: jest.fn().mockResolvedValue({ | |||
owaspTop10: { | |||
a1: { |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { isDiffMetric } from 'sonar-ui-common/helpers/measures'; | |||
@@ -45,7 +45,7 @@ jest.mock('sonar-ui-common/helpers/dates', () => ({ | |||
})); | |||
jest.mock('../../../../api/measures', () => { | |||
const { mockMeasure, mockMetric } = require.requireActual('../../../../helpers/testMocks'); | |||
const { mockMeasure, mockMetric } = jest.requireActual('../../../../helpers/testMocks'); | |||
return { | |||
getMeasuresWithPeriodAndMetrics: jest.fn((_, metricKeys: string[]) => { | |||
const metrics: T.Metric[] = []; | |||
@@ -83,10 +83,10 @@ jest.mock('../../../../api/measures', () => { | |||
}); | |||
jest.mock('../../../../api/quality-gates', () => { | |||
const { mockQualityGateProjectStatus, mockQualityGateApplicationStatus } = require.requireActual( | |||
const { mockQualityGateProjectStatus, mockQualityGateApplicationStatus } = jest.requireActual( | |||
'../../../../helpers/mocks/quality-gates' | |||
); | |||
const { MetricKey } = require.requireActual('../../../../types/metrics'); | |||
const { MetricKey } = jest.requireActual('../../../../types/metrics'); | |||
return { | |||
getQualityGateProjectStatus: jest.fn().mockResolvedValue( | |||
mockQualityGateProjectStatus({ | |||
@@ -124,7 +124,7 @@ jest.mock('../../../../api/quality-gates', () => { | |||
}); | |||
jest.mock('../../../../api/time-machine', () => { | |||
const { MetricKey } = require.requireActual('../../../../types/metrics'); | |||
const { MetricKey } = jest.requireActual('../../../../types/metrics'); | |||
return { | |||
getAllTimeMachineData: jest.fn().mockResolvedValue({ | |||
measures: [ | |||
@@ -143,7 +143,7 @@ jest.mock('../../../../api/time-machine', () => { | |||
}); | |||
jest.mock('../../../../api/projectActivity', () => { | |||
const { mockAnalysis } = require.requireActual('../../../../helpers/testMocks'); | |||
const { mockAnalysis } = jest.requireActual('../../../../helpers/testMocks'); | |||
return { | |||
getProjectActivity: jest.fn().mockResolvedValue({ | |||
analyses: [mockAnalysis(), mockAnalysis(), mockAnalysis(), mockAnalysis(), mockAnalysis()] | |||
@@ -175,8 +175,8 @@ jest.mock('../../../../api/application', () => ({ | |||
})); | |||
jest.mock('../../../../components/activity-graph/utils', () => { | |||
const { MetricKey } = require.requireActual('../../../../types/metrics'); | |||
const { GraphType } = require.requireActual('../../../../types/project-activity'); | |||
const { MetricKey } = jest.requireActual('../../../../types/metrics'); | |||
const { GraphType } = jest.requireActual('../../../../types/project-activity'); | |||
return { | |||
getActivityGraph: jest.fn(() => ({ graph: GraphType.coverage })), | |||
saveActivityGraph: jest.fn(), |
@@ -28,7 +28,7 @@ import { PR_METRICS } from '../../utils'; | |||
import { PullRequestOverview } from '../PullRequestOverview'; | |||
jest.mock('../../../../api/measures', () => { | |||
const { mockMeasure, mockMetric } = require.requireActual('../../../../helpers/testMocks'); | |||
const { mockMeasure, mockMetric } = jest.requireActual('../../../../helpers/testMocks'); | |||
return { | |||
getMeasuresWithMetrics: jest.fn().mockResolvedValue({ | |||
component: { |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import MetricBox, { MetricBoxProps } from '../MetricBox'; |
@@ -19,7 +19,7 @@ | |||
*/ | |||
/* eslint-disable import/first */ | |||
jest.mock('../../../../api/report', () => { | |||
const report = require.requireActual('../../../../api/report'); | |||
const report = jest.requireActual('../../../../api/report'); | |||
report.getReportStatus = jest.fn(() => Promise.resolve({})); | |||
return report; | |||
}); |
@@ -19,7 +19,7 @@ | |||
*/ | |||
/* eslint-disable import/first */ | |||
jest.mock('../../../../api/report', () => { | |||
const report = require.requireActual('../../../../api/report'); | |||
const report = jest.requireActual('../../../../api/report'); | |||
report.subscribe = jest.fn(() => Promise.resolve()); | |||
report.unsubscribe = jest.fn(() => Promise.resolve()); | |||
return report; |
@@ -32,7 +32,7 @@ jest.mock('date-fns/start_of_day', () => (date: Date) => { | |||
}); | |||
jest.mock('sonar-ui-common/helpers/dates', () => { | |||
const actual = require.requireActual('sonar-ui-common/helpers/dates'); | |||
const actual = jest.requireActual('sonar-ui-common/helpers/dates'); | |||
return { ...actual, toShortNotSoISOString: (date: string) => 'ISO.' + date }; | |||
}); | |||
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { mount, shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { IntlProvider } from 'react-intl'; |
@@ -31,7 +31,7 @@ jest.mock('date-fns/start_of_day', () => (date: Date) => { | |||
}); | |||
jest.mock('sonar-ui-common/helpers/dates', () => { | |||
const actual = require.requireActual('sonar-ui-common/helpers/dates'); | |||
const actual = jest.requireActual('sonar-ui-common/helpers/dates'); | |||
return { ...actual, toShortNotSoISOString: (date: string) => `ISO.${date}` }; | |||
}); | |||
@@ -76,22 +76,21 @@ export default class ProjectQualityGateApp extends React.PureComponent<Props, St | |||
if (!qualityGate.isDefault) { | |||
return false; | |||
} else { | |||
// If this is the default Quality Gate, check if it was explicitly | |||
// selected, or if we're inheriting the system default. | |||
/* eslint-disable-next-line sonarjs/prefer-immediate-return */ | |||
const selected = await searchProjects({ | |||
gateName: qualityGate.name, | |||
query: component.key | |||
} | |||
// If this is the default Quality Gate, check if it was explicitly | |||
// selected, or if we're inheriting the system default. | |||
const selected = await searchProjects({ | |||
gateName: qualityGate.name, | |||
query: component.key | |||
}) | |||
.then(({ results }) => { | |||
return Boolean(results.find(r => r.key === component.key)?.selected); | |||
}) | |||
.then(({ results }) => { | |||
return Boolean(results.find(r => r.key === component.key)?.selected); | |||
}) | |||
.catch(() => false); | |||
.catch(() => false); | |||
// If it's NOT selected, it means we're following the system default. | |||
return !selected; | |||
} | |||
// If it's NOT selected, it means we're following the system default. | |||
return !selected; | |||
}; | |||
fetchQualityGates = async () => { |
@@ -52,13 +52,14 @@ it('should render correctly', () => { | |||
}); | |||
it('should render select options correctly', () => { | |||
return new Promise(resolve => { | |||
return new Promise<void>(resolve => { | |||
const wrapper = shallowRender(); | |||
const render = wrapper.find(Select).props().optionRenderer; | |||
if (render) { | |||
expect(render({ value: '1', label: 'Gate 1' })).toMatchSnapshot('default'); | |||
resolve(); | |||
} | |||
expect(render).toBeDefined(); | |||
expect(render!({ value: '1', label: 'Gate 1' })).toMatchSnapshot('default'); | |||
resolve(); | |||
}); | |||
}); | |||
@@ -29,39 +29,37 @@ it('should render correctly', () => { | |||
}); | |||
it('should correctly handle changes', () => { | |||
return new Promise(resolve => { | |||
const onSubmit = jest.fn(); | |||
const wrapper = shallowRender({ onSubmit }); | |||
const langSelect = getLanguageSelect(wrapper); | |||
let profileSelect = getProfileSelect(wrapper); | |||
// Language select should only have 2; JS is not available. Profile Select | |||
// should have none, as no language is selected yet. | |||
expect(langSelect.props().options).toHaveLength(2); | |||
expect(profileSelect.props().options).toHaveLength(0); | |||
// Choose CSS. | |||
const langChange = langSelect.props().onChange; | |||
if (langChange) { | |||
langChange({ value: 'css' }); | |||
// Should now show 2 available profiles. | |||
profileSelect = getProfileSelect(wrapper); | |||
expect(profileSelect.props().options).toHaveLength(2); | |||
// Choose 1 profile. | |||
const profileChange = profileSelect.props().onChange; | |||
if (profileChange) { | |||
profileChange({ value: 'css2' }); | |||
submitSimpleModal(wrapper); | |||
expect(onSubmit).toHaveBeenLastCalledWith('css2'); | |||
resolve(); | |||
} | |||
} | |||
}); | |||
const onSubmit = jest.fn(); | |||
const wrapper = shallowRender({ onSubmit }); | |||
const langSelect = getLanguageSelect(wrapper); | |||
let profileSelect = getProfileSelect(wrapper); | |||
// Language select should only have 2; JS is not available. Profile Select | |||
// should have none, as no language is selected yet. | |||
expect(langSelect.props().options).toHaveLength(2); | |||
expect(profileSelect.props().options).toHaveLength(0); | |||
// Choose CSS. | |||
const langChange = langSelect.props().onChange; | |||
expect(langChange).toBeDefined(); | |||
langChange!({ value: 'css' }); | |||
// Should now show 2 available profiles. | |||
profileSelect = getProfileSelect(wrapper); | |||
expect(profileSelect.props().options).toHaveLength(2); | |||
// Choose 1 profile. | |||
const profileChange = profileSelect.props().onChange; | |||
expect(profileChange).toBeDefined(); | |||
profileChange!({ value: 'css2' }); | |||
submitSimpleModal(wrapper); | |||
expect(onSubmit).toHaveBeenLastCalledWith('css2'); | |||
}); | |||
function diveIntoSimpleModal(wrapper: ShallowWrapper) { |
@@ -32,48 +32,43 @@ it('should render correctly', () => { | |||
}); | |||
it('should render select options correctly', () => { | |||
return new Promise(resolve => { | |||
const wrapper = shallowRender(); | |||
const render = wrapper.find(Select).props().optionRenderer; | |||
if (render) { | |||
expect(render({ value: 'bar', label: 'Profile 1' })).toMatchSnapshot('default'); | |||
resolve(); | |||
} | |||
}); | |||
const wrapper = shallowRender(); | |||
const render = wrapper.find(Select).props().optionRenderer; | |||
expect(render).toBeDefined(); | |||
expect(render!({ value: 'bar', label: 'Profile 1' })).toMatchSnapshot('default'); | |||
}); | |||
it('should correctly handle changes', () => { | |||
return new Promise(resolve => { | |||
const onSubmit = jest.fn(); | |||
const wrapper = shallowRender({ onSubmit }, false); | |||
const onSubmit = jest.fn(); | |||
const wrapper = shallowRender({ onSubmit }, false); | |||
diveIntoSimpleModal(wrapper) | |||
.find(Radio) | |||
.at(0) | |||
.props() | |||
.onCheck(''); | |||
submitSimpleModal(wrapper); | |||
expect(onSubmit).toHaveBeenLastCalledWith(undefined, 'foo'); | |||
diveIntoSimpleModal(wrapper) | |||
.find(Radio) | |||
.at(0) | |||
.props() | |||
.onCheck(''); | |||
submitSimpleModal(wrapper); | |||
expect(onSubmit).toHaveBeenLastCalledWith(undefined, 'foo'); | |||
diveIntoSimpleModal(wrapper) | |||
.find(Radio) | |||
.at(1) | |||
.props() | |||
.onCheck(''); | |||
submitSimpleModal(wrapper); | |||
expect(onSubmit).toHaveBeenLastCalledWith('foo', 'foo'); | |||
diveIntoSimpleModal(wrapper) | |||
.find(Radio) | |||
.at(1) | |||
.props() | |||
.onCheck(''); | |||
submitSimpleModal(wrapper); | |||
expect(onSubmit).toHaveBeenLastCalledWith('foo', 'foo'); | |||
const change = diveIntoSimpleModal(wrapper) | |||
.find(Select) | |||
.props().onChange; | |||
const change = diveIntoSimpleModal(wrapper) | |||
.find(Select) | |||
.props().onChange; | |||
if (change) { | |||
change({ value: 'bar' }); | |||
submitSimpleModal(wrapper); | |||
expect(onSubmit).toHaveBeenLastCalledWith('bar', 'foo'); | |||
expect(change).toBeDefined(); | |||
resolve(); | |||
} | |||
}); | |||
change!({ value: 'bar' }); | |||
submitSimpleModal(wrapper); | |||
expect(onSubmit).toHaveBeenLastCalledWith('bar', 'foo'); | |||
}); | |||
function diveIntoSimpleModal(wrapper: ShallowWrapper) { |
@@ -50,7 +50,7 @@ jest.mock('../PageSidebar', () => ({ | |||
})); | |||
jest.mock('../../utils', () => { | |||
const utils = require.requireActual('../../utils'); | |||
const utils = jest.requireActual('../../utils'); | |||
utils.fetchProjects = jest.fn(() => Promise.resolve({ projects: [] })); | |||
return utils; | |||
}); |
@@ -50,20 +50,18 @@ interface Props { | |||
type?: string; | |||
} | |||
function renderFirstLine(props: Props) { | |||
function renderFirstLine(project: Props['project'], handleFavorite: Props['handleFavorite']) { | |||
const { | |||
project: { | |||
analysisDate, | |||
tags, | |||
qualifier, | |||
isFavorite, | |||
key, | |||
name, | |||
measures, | |||
needIssueSync, | |||
visibility | |||
} | |||
} = props; | |||
analysisDate, | |||
tags, | |||
qualifier, | |||
isFavorite, | |||
key, | |||
name, | |||
measures, | |||
needIssueSync, | |||
visibility | |||
} = project; | |||
return ( | |||
<div className="display-flex-center"> | |||
@@ -73,7 +71,7 @@ function renderFirstLine(props: Props) { | |||
className="spacer-right" | |||
component={key} | |||
favorite={isFavorite} | |||
handleFavorite={props.handleFavorite} | |||
handleFavorite={handleFavorite} | |||
qualifier={qualifier} | |||
/> | |||
)} | |||
@@ -134,10 +132,12 @@ function renderFirstLine(props: Props) { | |||
); | |||
} | |||
function renderSecondLine(props: Props, isNewCode: boolean) { | |||
const { | |||
project: { measures } | |||
} = props; | |||
function renderSecondLine( | |||
currentUser: Props['currentUser'], | |||
project: Props['project'], | |||
isNewCode: boolean | |||
) { | |||
const { measures } = project; | |||
return ( | |||
<div | |||
@@ -145,7 +145,7 @@ function renderSecondLine(props: Props, isNewCode: boolean) { | |||
'project-card-leak': isNewCode | |||
})}> | |||
<div className="project-card-main big-padded-left big-padded-right big-padded-bottom"> | |||
{renderMeasures(props, isNewCode)} | |||
{renderMeasures(currentUser, project, isNewCode)} | |||
</div> | |||
<div className="project-card-meta display-flex-end big-padded-left big-padded-right big-padded-bottom"> | |||
{isNewCode | |||
@@ -187,11 +187,12 @@ function renderSecondLine(props: Props, isNewCode: boolean) { | |||
); | |||
} | |||
function renderMeasures(props: Props, isNewCode: boolean) { | |||
const { | |||
currentUser, | |||
project: { measures, needIssueSync, analysisDate, leakPeriodDate, qualifier, key } | |||
} = props; | |||
function renderMeasures( | |||
currentUser: Props['currentUser'], | |||
project: Props['project'], | |||
isNewCode: boolean | |||
) { | |||
const { measures, needIssueSync, analysisDate, leakPeriodDate, qualifier, key } = project; | |||
if (analysisDate && (!isNewCode || leakPeriodDate)) { | |||
return ( | |||
@@ -202,44 +203,40 @@ function renderMeasures(props: Props, isNewCode: boolean) { | |||
newCodeStartingDate={leakPeriodDate} | |||
/> | |||
); | |||
} else { | |||
return ( | |||
<div className="spacer-top spacer-bottom"> | |||
<span className="note"> | |||
{isNewCode && analysisDate | |||
? translate('projects.no_new_code_period', qualifier) | |||
: translate('projects.not_analyzed', qualifier)} | |||
</span> | |||
{qualifier !== ComponentQualifier.Application && | |||
!analysisDate && | |||
isLoggedIn(currentUser) && | |||
!needIssueSync && ( | |||
<Link className="button spacer-left" to={getProjectUrl(key)}> | |||
{translate('projects.configure_analysis')} | |||
</Link> | |||
)} | |||
</div> | |||
); | |||
} | |||
return ( | |||
<div className="spacer-top spacer-bottom"> | |||
<span className="note"> | |||
{isNewCode && analysisDate | |||
? translate('projects.no_new_code_period', qualifier) | |||
: translate('projects.not_analyzed', qualifier)} | |||
</span> | |||
{qualifier !== ComponentQualifier.Application && | |||
!analysisDate && | |||
isLoggedIn(currentUser) && | |||
!needIssueSync && ( | |||
<Link className="button spacer-left" to={getProjectUrl(key)}> | |||
{translate('projects.configure_analysis')} | |||
</Link> | |||
)} | |||
</div> | |||
); | |||
} | |||
export default function ProjectCard(props: Props) { | |||
const { | |||
height, | |||
type, | |||
project: { needIssueSync, key } | |||
} = props; | |||
const { currentUser, height, type, project } = props; | |||
const isNewCode = type === 'leak'; | |||
return ( | |||
<div | |||
className={classNames('display-flex-column boxed-group it_project_card', { | |||
'project-card-disabled': needIssueSync | |||
'project-card-disabled': project.needIssueSync | |||
})} | |||
data-key={key} | |||
data-key={project.key} | |||
style={{ height }}> | |||
{renderFirstLine(props)} | |||
{renderSecondLine(props, isNewCode)} | |||
{renderFirstLine(project, props.handleFavorite)} | |||
{renderSecondLine(currentUser, project, isNewCode)} | |||
</div> | |||
); | |||
} |
@@ -27,9 +27,7 @@ import { ChangelogContainer } from '../ChangelogContainer'; | |||
beforeEach(() => jest.clearAllMocks()); | |||
jest.mock('../../../../api/quality-profiles', () => { | |||
const { mockQualityProfileChangelogEvent } = require.requireActual( | |||
'../../../../helpers/testMocks' | |||
); | |||
const { mockQualityProfileChangelogEvent } = jest.requireActual('../../../../helpers/testMocks'); | |||
return { | |||
getProfileChangelog: jest.fn().mockResolvedValue({ | |||
events: [ |
@@ -22,7 +22,7 @@ import * as React from 'react'; | |||
import ProfilePermissionsFormSelect from '../ProfilePermissionsFormSelect'; | |||
jest.mock('lodash', () => { | |||
const lodash = require.requireActual('lodash'); | |||
const lodash = jest.requireActual('lodash'); | |||
lodash.debounce = (fn: Function) => (...args: any[]) => fn(...args); | |||
return lodash; | |||
}); |
@@ -6,7 +6,7 @@ exports[`HotspotOpenInIdeButton should handle several IDE 1`] = ` | |||
open={false} | |||
overlay={ | |||
<DropdownOverlay> | |||
<Unknown | |||
<HotspotOpenInIdeOverlay | |||
ides={Array []} | |||
onIdeSelected={[Function]} | |||
/> | |||
@@ -31,7 +31,7 @@ exports[`HotspotOpenInIdeButton should handle several IDE: dropdown open 1`] = ` | |||
open={true} | |||
overlay={ | |||
<DropdownOverlay> | |||
<Unknown | |||
<HotspotOpenInIdeOverlay | |||
ides={ | |||
Array [ | |||
Object { | |||
@@ -69,7 +69,7 @@ exports[`HotspotOpenInIdeButton should render correctly 1`] = ` | |||
open={false} | |||
overlay={ | |||
<DropdownOverlay> | |||
<Unknown | |||
<HotspotOpenInIdeOverlay | |||
ides={Array []} | |||
onIdeSelected={[Function]} | |||
/> | |||
@@ -86,4 +86,4 @@ exports[`HotspotOpenInIdeButton should render correctly 1`] = ` | |||
/> | |||
</Button> | |||
</Toggler> | |||
`; | |||
`; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { change, submit, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { mockClusterSysInfo, mockStandaloneSysInfo } from '../../../helpers/testMocks'; | |||
import { SystemUpgrade } from '../../../types/system'; | |||
import * as u from '../utils'; |
@@ -223,9 +223,9 @@ export default class SourceViewerBase extends React.PureComponent<Props, State> | |||
const firstLine = sources[0]; | |||
const lastList = sources[sources.length - 1]; | |||
return lineNumber < firstLine.line || lineNumber > lastList.line; | |||
} else { | |||
return true; | |||
} | |||
return true; | |||
} | |||
fetchComponent() { | |||
@@ -383,10 +383,9 @@ export default class SourceViewerBase extends React.PureComponent<Props, State> | |||
// request one additional line to define `hasSourcesAfter` | |||
to++; | |||
return this.propsLoadSources(this.props.component, from, to, this.props.branchLike).then( | |||
sources => resolve(sources), | |||
onFailLoadSources | |||
); | |||
this.propsLoadSources(this.props.component, from, to, this.props.branchLike).then(sources => { | |||
resolve(sources); | |||
}, onFailLoadSources); | |||
}); | |||
}; | |||
@@ -146,6 +146,13 @@ it('should load sources after', async () => { | |||
expect(wrapper.state().issues).toHaveLength(2); | |||
}); | |||
it('should handle no sources when checking ranges', () => { | |||
const wrapper = shallowRender(); | |||
wrapper.setState({ sources: undefined }); | |||
expect(wrapper.instance().isLineOutsideOfRange(12)).toBe(true); | |||
}); | |||
function shallowRender(overrides: Partial<SourceViewerBase['props']> = {}) { | |||
return shallow<SourceViewerBase>( | |||
<SourceViewerBase branchLike={mockMainBranch()} component="my-component" {...overrides} /> |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { LineSCM, LineSCMProps } from '../LineSCM'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { SCMPopup, SCMPopupProps } from '../SCMPopup'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { parseDate } from 'sonar-ui-common/helpers/dates'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { parseDate } from 'sonar-ui-common/helpers/dates'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { parseDate } from 'sonar-ui-common/helpers/dates'; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import * as dates from 'sonar-ui-common/helpers/dates'; | |||
import { MetricKey } from '../../../types/metrics'; | |||
import { GraphType, Serie } from '../../../types/project-activity'; |
@@ -23,13 +23,16 @@ import Level from 'sonar-ui-common/components/ui/Level'; | |||
import { getBranchStatusByBranchLike, Store } from '../../store/rootReducer'; | |||
import { BranchLike } from '../../types/branch-like'; | |||
interface Props { | |||
interface ExposedProps { | |||
branchLike: BranchLike; | |||
component: string; | |||
} | |||
interface BranchStatusProps { | |||
status?: string; | |||
} | |||
export function BranchStatus({ status }: Props) { | |||
export function BranchStatus({ status }: BranchStatusProps) { | |||
if (!status) { | |||
return null; | |||
} | |||
@@ -37,7 +40,8 @@ export function BranchStatus({ status }: Props) { | |||
return <Level level={status} small={true} />; | |||
} | |||
const mapStateToProps = (state: Store, { branchLike, component }: Props) => { | |||
const mapStateToProps = (state: Store, props: ExposedProps) => { | |||
const { branchLike, component } = props; | |||
const { status } = getBranchStatusByBranchLike(state, component, branchLike); | |||
return { status }; | |||
}; |
@@ -59,29 +59,24 @@ it('should fetch task warnings if it has to', async () => { | |||
expect(getTask).toBeCalledWith('abcd1234', ['warnings']); | |||
}); | |||
it('should correctly handle dismissing warnings', () => { | |||
return new Promise(resolve => { | |||
const onWarningDismiss = jest.fn(); | |||
const wrapper = shallowRender({ | |||
componentKey: 'foo', | |||
onWarningDismiss, | |||
warnings: [mockTaskWarning({ key: 'bar', dismissable: true })] | |||
}); | |||
const click = wrapper.find('ButtonLink.link-base-color').props().onClick; | |||
if (click) { | |||
click(mockEvent()); | |||
waitAndUpdate(wrapper).then( | |||
() => { | |||
expect(dismissAnalysisWarning).toBeCalledWith('foo', 'bar'); | |||
expect(onWarningDismiss).toBeCalled(); | |||
resolve(); | |||
}, | |||
() => {} | |||
); | |||
} | |||
it('should correctly handle dismissing warnings', async () => { | |||
const onWarningDismiss = jest.fn(); | |||
const wrapper = shallowRender({ | |||
componentKey: 'foo', | |||
onWarningDismiss, | |||
warnings: [mockTaskWarning({ key: 'bar', dismissable: true })] | |||
}); | |||
const click = wrapper.find('ButtonLink.link-base-color').props().onClick; | |||
expect(click).toBeDefined(); | |||
click!(mockEvent()); | |||
await waitAndUpdate(wrapper); | |||
expect(dismissAnalysisWarning).toBeCalledWith('foo', 'bar'); | |||
expect(onWarningDismiss).toBeCalled(); | |||
}); | |||
it('should correctly handle updates', async () => { |
@@ -19,7 +19,6 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockBranch } from '../../../helpers/mocks/branch-like'; | |||
import { BranchStatus } from '../BranchStatus'; | |||
it('should render correctly', () => { | |||
@@ -29,5 +28,5 @@ it('should render correctly', () => { | |||
}); | |||
function shallowRender(status?: string) { | |||
return shallow(<BranchStatus branchLike={mockBranch()} component="foo" status={status} />); | |||
return shallow(<BranchStatus status={status} />); | |||
} |
@@ -38,6 +38,7 @@ export default class DocCollapsibleBlock extends React.PureComponent<{}, State> | |||
<a | |||
aria-expanded={this.state.open} | |||
aria-haspopup={true} | |||
role="button" | |||
className="link-no-underline" | |||
href="#" | |||
onClick={this.handleClick}> |
@@ -45,17 +45,17 @@ Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, co | |||
`; | |||
jest.mock('remark', () => { | |||
const remark = require.requireActual('remark'); | |||
const remark = jest.requireActual('remark'); | |||
return { default: remark }; | |||
}); | |||
jest.mock('remark-react', () => { | |||
const remarkReact = require.requireActual('remark-react'); | |||
const remarkReact = jest.requireActual('remark-react'); | |||
return { default: remarkReact }; | |||
}); | |||
jest.mock('lodash', () => { | |||
const lodash = require.requireActual('lodash'); | |||
const lodash = jest.requireActual('lodash'); | |||
lodash.debounce = (fn: any) => fn; | |||
return lodash; | |||
}); |
@@ -12,6 +12,7 @@ exports[`should render a collapsible block 1`] = ` | |||
className="link-no-underline" | |||
href="#" | |||
onClick={[Function]} | |||
role="button" | |||
> | |||
<OpenCloseIcon | |||
className="text-middle little-spacer-right" | |||
@@ -32,6 +33,7 @@ exports[`should render a collapsible block 2`] = ` | |||
className="link-no-underline" | |||
href="#" | |||
onClick={[Function]} | |||
role="button" | |||
> | |||
<OpenCloseIcon | |||
className="text-middle little-spacer-right" |
@@ -22,7 +22,7 @@ import * as React from 'react'; | |||
import Measure from '../Measure'; | |||
jest.mock('../../../helpers/measures', () => { | |||
const measures = require.requireActual('../../../helpers/measures'); | |||
const measures = jest.requireActual('../../../helpers/measures'); | |||
measures.getRatingTooltip = jest.fn(() => 'tooltip'); | |||
return measures; | |||
}); |
@@ -32,6 +32,7 @@ export interface RenderOptionsProps { | |||
export default function RenderOptions({ | |||
checked, | |||
name, | |||
onCheck, | |||
optionLabelKey, | |||
options, |
@@ -6,7 +6,7 @@ exports[`should render correctly: default 1`] = ` | |||
> | |||
<RadioToggle | |||
disabled={false} | |||
name="" | |||
name="bar" | |||
onCheck={[MockFunction]} | |||
options={ | |||
Array [ | |||
@@ -31,7 +31,7 @@ exports[`should render correctly: option checked 1`] = ` | |||
> | |||
<RadioToggle | |||
disabled={false} | |||
name="" | |||
name="bar" | |||
onCheck={[MockFunction]} | |||
options={ | |||
Array [ | |||
@@ -61,7 +61,7 @@ exports[`should render correctly: with title 1`] = ` | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="" | |||
name="bar" | |||
onCheck={[MockFunction]} | |||
options={ | |||
Array [ |
@@ -38,10 +38,10 @@ export async function getExtensionStart(key: string) { | |||
} | |||
if (!librariesExposed) { | |||
librariesExposed = true; | |||
// Async import allows to reduce initial vendor bundle size | |||
const exposeLibraries = (await import('../app/components/extensions/exposeLibraries')).default; | |||
exposeLibraries(); | |||
librariesExposed = true; | |||
} | |||
await installScript(`/static/${key}.js`); |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { | |||
QualityGateApplicationStatus, | |||
QualityGateProjectStatus, |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { Location } from 'history'; | |||
import { InjectedRouter } from 'react-router'; | |||
import { createStore, Store } from 'redux'; |
@@ -23,14 +23,12 @@ import { registerBranchStatusAction } from '../branches'; | |||
import { fetchBranchStatus, registerBranchStatus } from '../rootActions'; | |||
jest.mock('../branches', () => ({ | |||
...require.requireActual('../branches'), | |||
...jest.requireActual('../branches'), | |||
registerBranchStatusAction: jest.fn() | |||
})); | |||
jest.mock('../../api/quality-gates', () => { | |||
const { mockQualityGateProjectStatus } = require.requireActual( | |||
'../../helpers/mocks/quality-gates' | |||
); | |||
const { mockQualityGateProjectStatus } = jest.requireActual('../../helpers/mocks/quality-gates'); | |||
return { | |||
getQualityGateProjectStatus: jest.fn().mockResolvedValue( | |||
mockQualityGateProjectStatus({ |
@@ -23,7 +23,7 @@ import { getBranchStatusByBranchLike, Store } from '../rootReducer'; | |||
jest.mock('../branches', () => { | |||
return { | |||
...require.requireActual('../branches'), | |||
...jest.requireActual('../branches'), | |||
getBranchStatusByBranchLike: jest.fn() | |||
}; | |||
}); |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
/* eslint-disable sonarjs/no-duplicate-string */ | |||
import { mockCurrentUser, mockLoggedInUser, mockUser } from '../../helpers/testMocks'; | |||
import reducer, { | |||
getCurrentUser, |