Skip to content

Commit

Permalink
test(quay): add unit tests for quay plugin (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
invincibleJai authored Jun 9, 2023
1 parent ebb7e13 commit e9d7ed5
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 4 deletions.
1 change: 1 addition & 0 deletions plugins/quay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@backstage/test-utils": "1.3.1",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "12.1.5",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/user-event": "14.4.3",
"@types/node": "18.16.16",
"cross-fetch": "3.1.6",
Expand Down
71 changes: 71 additions & 0 deletions plugins/quay/src/components/QuayRepository/QuayRepository.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import { BrowserRouter } from 'react-router-dom';

import { render } from '@testing-library/react';

import { useTags } from '../../hooks';
import { QuayRepository } from './QuayRepository';

jest.mock('@backstage/core-plugin-api', () => ({
...jest.requireActual('@backstage/core-plugin-api'),
useApi: jest
.fn()
.mockReturnValue({ getOptionalString: (param: any) => param }),
}));

jest.mock('../../hooks/', () => ({
useRepository: () => ({
repository: 'redhat-backstage-build',
organization: 'janus-idp',
}),
useTags: jest.fn().mockReturnValue({}),
}));

describe('QuayRepository', () => {
afterAll(() => {
jest.resetAllMocks();
});

it('should show loading if loading is true', () => {
(useTags as jest.Mock).mockReturnValue({ loading: true, data: [] });
const { getByTestId } = render(<QuayRepository />);
expect(getByTestId('quay-repo-progress')).not.toBeNull();
});

it('should show empty table if loaded and data is not present', () => {
(useTags as jest.Mock).mockReturnValue({ loading: false, data: [] });
const { getByTestId, queryByText } = render(
<BrowserRouter>
<QuayRepository />
</BrowserRouter>,
);
expect(getByTestId('quay-repo-table')).not.toBeNull();
expect(getByTestId('quay-repo-table-empty')).not.toBeNull();
expect(queryByText(/Quay repository/i)).toBeInTheDocument();
expect(queryByText(/No data was added yet/i)).toBeInTheDocument();
});

it('should show table if loaded and data is present', () => {
(useTags as jest.Mock).mockReturnValue({
loading: false,
data: [
{
name: 'latest',
manifest_digest:
'sha256:e766248d812bcdadc1ee293b564af1f2517dd6c0327eefab2411e4f11e980d54',
size: null,
last_modified: 'Wed, 15 Mar 2023 18:22:18 -0000',
},
],
});
const { queryByTestId, queryByText } = render(
<BrowserRouter>
<QuayRepository />
</BrowserRouter>,
);
expect(queryByTestId('quay-repo-table')).not.toBeNull();
expect(queryByTestId('quay-repo-table-empty')).toBeNull();
expect(queryByText(/Quay repository/i)).toBeInTheDocument();
expect(queryByText(/No data was added yet/i)).not.toBeInTheDocument();
});
});
10 changes: 7 additions & 3 deletions plugins/quay/src/components/QuayRepository/QuayRepository.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,22 @@ export function QuayRepository(_props: QuayRepositoryProps) {
const { loading, data } = useTags(organization, repository);

if (loading) {
return <Progress />;
return (
<div data-testid="quay-repo-progress">
<Progress />
</div>
);
}

return (
<div style={{ border: '1px solid #ddd' }}>
<div data-testid="quay-repo-table" style={{ border: '1px solid #ddd' }}>
<Table
title={title}
options={{ paging: true, padding: 'dense' }}
data={data}
columns={columns}
emptyContent={
<div className={classes.empty}>
<div data-testid="quay-repo-table-empty" className={classes.empty}>
No data was added yet,&nbsp;
<Link to="https://backstage.io/">learn how to add data</Link>.
</div>
Expand Down
25 changes: 25 additions & 0 deletions plugins/quay/src/components/QuayTagDetails/QuayTagDetails.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { BrowserRouter } from 'react-router-dom';

import { render } from '@testing-library/react';

import data from '../../api/fixtures/securityDetail/foo.json';
import { Layer } from '../../types';
import QuayTagDetails from './component';

describe('QuayTagDetails', () => {
it('should render tag details if vulnerabilities exists', () => {
const { queryByText } = render(
<BrowserRouter>
<QuayTagDetails
layer={data.data.Layer as Layer}
rootLink={jest.fn()}
digest="data-digest"
/>
,
</BrowserRouter>,
);
expect(queryByText(/Back to repository/i)).toBeInTheDocument();
expect(queryByText(/Vulnerabilities for data-digest/i)).toBeInTheDocument();
});
});
68 changes: 68 additions & 0 deletions plugins/quay/src/components/QuayTagPage/QuayTagPage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react';
import { useParams } from 'react-router-dom';

import { render } from '@testing-library/react';

import { useTagDetails } from '../../hooks';
import QuayTagPage from './component';

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn().mockReturnValue({}),
}));

jest.mock('@backstage/core-plugin-api', () => ({
...jest.requireActual('@backstage/core-plugin-api'),
useApi: jest
.fn()
.mockReturnValue({ getOptionalString: (param: any) => param }),
useRouteRef: jest.fn(),
}));

jest.mock('../../hooks/', () => ({
useRepository: () => ({
repository: 'redhat-backstage-build',
organization: 'janus-idp',
}),
useTags: jest.fn().mockReturnValue({}),
useTagDetails: jest.fn().mockReturnValue({}),
}));

jest.mock('../QuayTagDetails', () => ({
QuayTagDetails: () => <div>QuayTagDetails</div>,
}));

describe('QuayTagPage', () => {
afterAll(() => {
jest.resetAllMocks();
});

it('should throw error if digest is not defined', () => {
expect(() => render(<QuayTagPage />)).toThrow('digest is not defined');
});

it('should show loading if loading is in progress', () => {
(useParams as jest.Mock).mockReturnValue({ digest: 'digest_data' });
(useTagDetails as jest.Mock).mockReturnValue({ loading: true });
const { queryByTestId } = render(<QuayTagPage />);
expect(queryByTestId('quay-tag-page-progress')).not.toBeNull();
});

it('should show error: no digest if value is not there', () => {
(useParams as jest.Mock).mockReturnValue({ digest: 'digest_data' });
(useTagDetails as jest.Mock).mockReturnValue({ loading: false });
const { queryByTestId, queryAllByText } = render(<QuayTagPage />);
expect(queryAllByText(/no digest/i)[0]).toBeInTheDocument();
expect(queryByTestId('quay-tag-page-progress')).toBeNull();
});

it('should show QuayTagDetails if value is there', () => {
(useParams as jest.Mock).mockReturnValue({ digest: 'digest_data' });
(useTagDetails as jest.Mock).mockReturnValue({
loading: false,
value: { data: [{ Features: [] }] },
});
const { queryByText } = render(<QuayTagPage />);
expect(queryByText(/QuayTagDetails/i)).toBeInTheDocument();
});
});
6 changes: 5 additions & 1 deletion plugins/quay/src/components/QuayTagPage/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ export const QuayTagPage = () => {
}
const { loading, value } = useTagDetails(organization, repository, digest);
if (loading) {
return <Progress variant="query" />;
return (
<div data-testid="quay-tag-page-progress">
<Progress variant="query" />
</div>
);
}
if (!value || !value.data) {
return <ErrorPanel error={new Error('no digest')} />;
Expand Down
37 changes: 37 additions & 0 deletions plugins/quay/src/components/Router.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';

import { renderInTestApp } from '@backstage/test-utils';

import { QuayRepository } from './QuayRepository';
import { QuayTagPage } from './QuayTagPage';
import { Router } from './Router';

jest.mock('./QuayRepository', () => ({
QuayRepository: jest.fn(() => null),
}));

jest.mock('./QuayTagPage', () => ({
QuayTagPage: jest.fn(() => null),
}));

describe('Router', () => {
beforeEach(() => {
(QuayRepository as jest.Mock).mockClear();
(QuayTagPage as jest.Mock).mockClear();
});
describe('/', () => {
it('should render the QuayRepository', async () => {
await renderInTestApp(<Router />);
expect(QuayRepository).toHaveBeenCalled();
});
});

describe('/tag/:digestId', () => {
it('should render the QuayTagPage page', async () => {
await renderInTestApp(<Router />, {
routeEntries: ['/tag/my-digest'],
});
expect(QuayTagPage).toHaveBeenCalled();
});
});
});
26 changes: 26 additions & 0 deletions plugins/quay/src/hooks/useRepository.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { renderHook } from '@testing-library/react-hooks';

import { useRepository } from './quay';

jest.mock('@backstage/plugin-catalog-react', () => ({
useEntity: () => ({
entity: {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'foo',
annotations: { 'quay.io/repository-slug': 'foo/bar' },
},
},
}),
}));

describe('useRepository', () => {
it('should return organization and repository', () => {
const { result } = renderHook(() => useRepository());
expect(result.current).toEqual({
organization: 'foo',
repository: 'bar',
});
});
});
22 changes: 22 additions & 0 deletions plugins/quay/src/hooks/useTagDetails.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { waitFor } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';

import { useTagDetails } from './quay';

jest.mock('@backstage/core-plugin-api', () => ({
...jest.requireActual('@backstage/core-plugin-api'),
useApi: jest
.fn()
.mockReturnValue({ getSecurityDetails: (param: any) => param }),
}));

describe('useTagDetails', () => {
it('should return tag details for provided org, repo and digest', async () => {
const { result } = renderHook(() =>
useTagDetails('foo', 'bar', 'mock-digest'),
);
await waitFor(() => {
expect(result.current).toEqual({ loading: false, value: 'foo' });
});
});
});
24 changes: 24 additions & 0 deletions plugins/quay/src/hooks/useTags.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { waitFor } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';

import { useTags } from './quay';

jest.mock('@backstage/core-plugin-api', () => ({
...jest.requireActual('@backstage/core-plugin-api'),
useApi: jest.fn().mockReturnValue({
getSecurityDetails: (param: any) => param,
getTags: jest.fn().mockReturnValue({
tags: [{ name: 'tag1', manifest_digest: 'manifestDigest' }],
}),
}),
}));

describe('useTags', () => {
it('should return tags for provided org and repo', async () => {
const { result } = renderHook(() => useTags('foo', 'bar'));
await waitFor(() => {
expect(result.current.loading).toBeFalsy();
expect(result.current.data).toHaveLength(1);
});
});
});

0 comments on commit e9d7ed5

Please sign in to comment.