diff options
Diffstat (limited to 'spec/frontend/projects/storage_counter')
4 files changed, 338 insertions, 0 deletions
diff --git a/spec/frontend/projects/storage_counter/components/app_spec.js b/spec/frontend/projects/storage_counter/components/app_spec.js new file mode 100644 index 00000000000..f3da01e0602 --- /dev/null +++ b/spec/frontend/projects/storage_counter/components/app_spec.js @@ -0,0 +1,150 @@ +import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import StorageCounterApp from '~/projects/storage_counter/components/app.vue'; +import { TOTAL_USAGE_DEFAULT_TEXT } from '~/projects/storage_counter/constants'; +import getProjectStorageCount from '~/projects/storage_counter/queries/project_storage.query.graphql'; +import UsageGraph from '~/vue_shared/components/storage_counter/usage_graph.vue'; +import { + mockGetProjectStorageCountGraphQLResponse, + mockEmptyResponse, + projectData, + defaultProvideValues, +} from '../mock_data'; + +const localVue = createLocalVue(); +localVue.use(VueApollo); + +describe('Storage counter app', () => { + let wrapper; + + const createMockApolloProvider = ({ reject = false, mockedValue } = {}) => { + let response; + + if (reject) { + response = jest.fn().mockRejectedValue(mockedValue || new Error('GraphQL error')); + } else { + response = jest.fn().mockResolvedValue(mockedValue); + } + + const requestHandlers = [[getProjectStorageCount, response]]; + + return createMockApollo(requestHandlers); + }; + + const createComponent = ({ provide = {}, mockApollo } = {}) => { + wrapper = extendedWrapper( + shallowMount(StorageCounterApp, { + localVue, + apolloProvider: mockApollo, + provide: { + ...defaultProvideValues, + ...provide, + }, + }), + ); + }; + + const findAlert = () => wrapper.findComponent(GlAlert); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + const findUsagePercentage = () => wrapper.findByTestId('total-usage'); + const findUsageQuotasHelpLink = () => wrapper.findByTestId('usage-quotas-help-link'); + const findUsageGraph = () => wrapper.findComponent(UsageGraph); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('with apollo fetching successful', () => { + let mockApollo; + + beforeEach(async () => { + mockApollo = createMockApolloProvider({ + mockedValue: mockGetProjectStorageCountGraphQLResponse, + }); + createComponent({ mockApollo }); + await waitForPromises(); + }); + + it('renders correct total usage', () => { + expect(findUsagePercentage().text()).toBe(projectData.storage.totalUsage); + }); + + it('renders correct usage quotas help link', () => { + expect(findUsageQuotasHelpLink().attributes('href')).toBe( + defaultProvideValues.helpLinks.usageQuotasHelpPagePath, + ); + }); + }); + + describe('with apollo loading', () => { + let mockApollo; + + beforeEach(() => { + mockApollo = createMockApolloProvider({ + mockedValue: new Promise(() => {}), + }); + createComponent({ mockApollo }); + }); + + it('should show loading icon', () => { + expect(findLoadingIcon().exists()).toBe(true); + }); + }); + + describe('with apollo returning empty data', () => { + let mockApollo; + + beforeEach(async () => { + mockApollo = createMockApolloProvider({ + mockedValue: mockEmptyResponse, + }); + createComponent({ mockApollo }); + await waitForPromises(); + }); + + it('shows default text for total usage', () => { + expect(findUsagePercentage().text()).toBe(TOTAL_USAGE_DEFAULT_TEXT); + }); + }); + + describe('with apollo fetching error', () => { + let mockApollo; + + beforeEach(() => { + mockApollo = createMockApolloProvider(); + createComponent({ mockApollo, reject: true }); + }); + + it('renders gl-alert', () => { + expect(findAlert().exists()).toBe(true); + }); + }); + + describe('rendering <usage-graph />', () => { + let mockApollo; + + beforeEach(async () => { + mockApollo = createMockApolloProvider({ + mockedValue: mockGetProjectStorageCountGraphQLResponse, + }); + createComponent({ mockApollo }); + await waitForPromises(); + }); + + it('renders usage-graph component if project.statistics exists', () => { + expect(findUsageGraph().exists()).toBe(true); + }); + + it('passes project.statistics to usage-graph component', () => { + const { + __typename, + ...statistics + } = mockGetProjectStorageCountGraphQLResponse.data.project.statistics; + expect(findUsageGraph().props('rootStorageStatistics')).toMatchObject(statistics); + }); + }); +}); diff --git a/spec/frontend/projects/storage_counter/components/storage_table_spec.js b/spec/frontend/projects/storage_counter/components/storage_table_spec.js new file mode 100644 index 00000000000..14298318fff --- /dev/null +++ b/spec/frontend/projects/storage_counter/components/storage_table_spec.js @@ -0,0 +1,62 @@ +import { GlTable } from '@gitlab/ui'; +import { mount } from '@vue/test-utils'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import StorageTable from '~/projects/storage_counter/components/storage_table.vue'; +import { projectData, defaultProvideValues } from '../mock_data'; + +describe('StorageTable', () => { + let wrapper; + + const defaultProps = { + storageTypes: projectData.storage.storageTypes, + }; + + const createComponent = (props = {}) => { + wrapper = extendedWrapper( + mount(StorageTable, { + propsData: { + ...defaultProps, + ...props, + }, + }), + ); + }; + + const findTable = () => wrapper.findComponent(GlTable); + + beforeEach(() => { + createComponent(); + }); + afterEach(() => { + wrapper.destroy(); + }); + + describe('with storage types', () => { + it.each(projectData.storage.storageTypes)( + 'renders table row correctly %o', + ({ storageType: { id, name, description } }) => { + expect(wrapper.findByTestId(`${id}-name`).text()).toBe(name); + expect(wrapper.findByTestId(`${id}-description`).text()).toBe(description); + expect(wrapper.findByTestId(`${id}-help-link`).attributes('href')).toBe( + defaultProvideValues.helpLinks[id.replace(`Size`, `HelpPagePath`)] + .replace(`Size`, ``) + .replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`), + ); + }, + ); + }); + + describe('without storage types', () => { + beforeEach(() => { + createComponent({ storageTypes: [] }); + }); + + it('should render the table header <th>', () => { + expect(findTable().find('th').exists()).toBe(true); + }); + + it('should not render any table data <td>', () => { + expect(findTable().find('td').exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/projects/storage_counter/mock_data.js b/spec/frontend/projects/storage_counter/mock_data.js new file mode 100644 index 00000000000..b9fa68b3ec7 --- /dev/null +++ b/spec/frontend/projects/storage_counter/mock_data.js @@ -0,0 +1,109 @@ +export const mockGetProjectStorageCountGraphQLResponse = { + data: { + project: { + id: 'gid://gitlab/Project/20', + statistics: { + buildArtifactsSize: 400000.0, + pipelineArtifactsSize: 25000.0, + lfsObjectsSize: 4800000.0, + packagesSize: 3800000.0, + repositorySize: 3900000.0, + snippetsSize: 1200000.0, + storageSize: 15300000.0, + uploadsSize: 900000.0, + wikiSize: 300000.0, + __typename: 'ProjectStatistics', + }, + __typename: 'Project', + }, + }, +}; + +export const mockEmptyResponse = { data: { project: null } }; + +export const defaultProvideValues = { + projectPath: '/project-path', + helpLinks: { + usageQuotasHelpPagePath: '/usage-quotas', + buildArtifactsHelpPagePath: '/build-artifacts', + lfsObjectsHelpPagePath: '/lsf-objects', + packagesHelpPagePath: '/packages', + repositoryHelpPagePath: '/repository', + snippetsHelpPagePath: '/snippets', + uploadsHelpPagePath: '/uploads', + wikiHelpPagePath: '/wiki', + }, +}; + +export const projectData = { + storage: { + totalUsage: '14.6 MiB', + storageTypes: [ + { + storageType: { + id: 'buildArtifactsSize', + name: 'Artifacts', + description: 'Pipeline artifacts and job artifacts, created with CI/CD.', + warningMessage: + 'There is a known issue with Artifact storage where the total could be incorrect for some projects. More details and progress are available in %{warningLinkStart}the epic%{warningLinkEnd}.', + helpPath: '/build-artifacts', + }, + value: 400000, + }, + { + storageType: { + id: 'lfsObjectsSize', + name: 'LFS Storage', + description: 'Audio samples, videos, datasets, and graphics.', + helpPath: '/lsf-objects', + }, + value: 4800000, + }, + { + storageType: { + id: 'packagesSize', + name: 'Packages', + description: 'Code packages and container images.', + helpPath: '/packages', + }, + value: 3800000, + }, + { + storageType: { + id: 'repositorySize', + name: 'Repository', + description: 'Git repository, managed by the Gitaly service.', + helpPath: '/repository', + }, + value: 3900000, + }, + { + storageType: { + id: 'snippetsSize', + name: 'Snippets', + description: 'Shared bits of code and text.', + helpPath: '/snippets', + }, + value: 1200000, + }, + { + storageType: { + id: 'uploadsSize', + name: 'Uploads', + description: 'File attachments and smaller design graphics.', + helpPath: '/uploads', + }, + value: 900000, + }, + { + storageType: { + id: 'wikiSize', + name: 'Wiki', + description: 'Wiki content.', + helpPath: '/wiki', + }, + value: 300000, + }, + ], + }, +}; diff --git a/spec/frontend/projects/storage_counter/utils_spec.js b/spec/frontend/projects/storage_counter/utils_spec.js new file mode 100644 index 00000000000..57c755266a0 --- /dev/null +++ b/spec/frontend/projects/storage_counter/utils_spec.js @@ -0,0 +1,17 @@ +import { parseGetProjectStorageResults } from '~/projects/storage_counter/utils'; +import { + mockGetProjectStorageCountGraphQLResponse, + projectData, + defaultProvideValues, +} from './mock_data'; + +describe('parseGetProjectStorageResults', () => { + it('parses project statistics correctly', () => { + expect( + parseGetProjectStorageResults( + mockGetProjectStorageCountGraphQLResponse.data, + defaultProvideValues.helpLinks, + ), + ).toMatchObject(projectData); + }); +}); |