gitlab-org--gitlab-foss/spec/frontend/releases/components/app_index_spec.js

231 lines
6.3 KiB
JavaScript

import { shallowMount } from '@vue/test-utils';
import { merge } from 'lodash';
import Vue from 'vue';
import Vuex from 'vuex';
import { getParameterByName } from '~/lib/utils/url_utility';
import AppIndex from '~/releases/components/app_index.vue';
import ReleaseSkeletonLoader from '~/releases/components/release_skeleton_loader.vue';
import ReleasesPagination from '~/releases/components/releases_pagination.vue';
import ReleasesSort from '~/releases/components/releases_sort.vue';
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
getParameterByName: jest.fn(),
}));
Vue.use(Vuex);
describe('app_index.vue', () => {
let wrapper;
let fetchReleasesSpy;
let urlParams;
const createComponent = (storeUpdates) => {
wrapper = shallowMount(AppIndex, {
store: new Vuex.Store({
modules: {
index: merge(
{
namespaced: true,
actions: {
fetchReleases: fetchReleasesSpy,
},
state: {
isLoading: true,
releases: [],
},
},
storeUpdates,
),
},
}),
});
};
beforeEach(() => {
fetchReleasesSpy = jest.fn();
getParameterByName.mockImplementation((paramName) => urlParams[paramName]);
});
afterEach(() => {
wrapper.destroy();
});
// Finders
const findLoadingIndicator = () => wrapper.find(ReleaseSkeletonLoader);
const findEmptyState = () => wrapper.find('[data-testid="empty-state"]');
const findSuccessState = () => wrapper.find('[data-testid="success-state"]');
const findPagination = () => wrapper.find(ReleasesPagination);
const findSortControls = () => wrapper.find(ReleasesSort);
const findNewReleaseButton = () => wrapper.find('[data-testid="new-release-button"]');
// Expectations
const expectLoadingIndicator = (shouldExist) => {
it(`${shouldExist ? 'renders' : 'does not render'} a loading indicator`, () => {
expect(findLoadingIndicator().exists()).toBe(shouldExist);
});
};
const expectEmptyState = (shouldExist) => {
it(`${shouldExist ? 'renders' : 'does not render'} an empty state`, () => {
expect(findEmptyState().exists()).toBe(shouldExist);
});
};
const expectSuccessState = (shouldExist) => {
it(`${shouldExist ? 'renders' : 'does not render'} the success state`, () => {
expect(findSuccessState().exists()).toBe(shouldExist);
});
};
const expectPagination = (shouldExist) => {
it(`${shouldExist ? 'renders' : 'does not render'} the pagination controls`, () => {
expect(findPagination().exists()).toBe(shouldExist);
});
};
const expectNewReleaseButton = (shouldExist) => {
it(`${shouldExist ? 'renders' : 'does not render'} the "New release" button`, () => {
expect(findNewReleaseButton().exists()).toBe(shouldExist);
});
};
// Tests
describe('on startup', () => {
it.each`
before | after
${null} | ${null}
${'before_param_value'} | ${null}
${null} | ${'after_param_value'}
`(
'calls fetchRelease with the correct parameters based on the curent query parameters: before: $before, after: $after',
({ before, after }) => {
urlParams = { before, after };
createComponent();
expect(fetchReleasesSpy).toHaveBeenCalledTimes(1);
expect(fetchReleasesSpy).toHaveBeenCalledWith(expect.anything(), urlParams);
},
);
});
describe('when the request to fetch releases has not yet completed', () => {
beforeEach(() => {
createComponent();
});
expectLoadingIndicator(true);
expectEmptyState(false);
expectSuccessState(false);
expectPagination(false);
});
describe('when the request fails', () => {
beforeEach(() => {
createComponent({
state: {
isLoading: false,
hasError: true,
},
});
});
expectLoadingIndicator(false);
expectEmptyState(false);
expectSuccessState(false);
expectPagination(true);
});
describe('when the request succeeds but returns no releases', () => {
beforeEach(() => {
createComponent({
state: {
isLoading: false,
},
});
});
expectLoadingIndicator(false);
expectEmptyState(true);
expectSuccessState(false);
expectPagination(true);
});
describe('when the request succeeds and includes at least one release', () => {
beforeEach(() => {
createComponent({
state: {
isLoading: false,
releases: [{}],
},
});
});
expectLoadingIndicator(false);
expectEmptyState(false);
expectSuccessState(true);
expectPagination(true);
});
describe('sorting', () => {
beforeEach(() => {
createComponent();
});
it('renders the sort controls', () => {
expect(findSortControls().exists()).toBe(true);
});
it('calls the fetchReleases store method when the sort is updated', () => {
fetchReleasesSpy.mockClear();
findSortControls().vm.$emit('sort:changed');
expect(fetchReleasesSpy).toHaveBeenCalledTimes(1);
});
});
describe('"New release" button', () => {
describe('when the user is allowed to create releases', () => {
const newReleasePath = 'path/to/new/release/page';
beforeEach(() => {
createComponent({ state: { newReleasePath } });
});
expectNewReleaseButton(true);
it('renders the button with the correct href', () => {
expect(findNewReleaseButton().attributes('href')).toBe(newReleasePath);
});
});
describe('when the user is not allowed to create releases', () => {
beforeEach(() => {
createComponent();
});
expectNewReleaseButton(false);
});
});
describe("when the browser's back button is pressed", () => {
beforeEach(() => {
urlParams = {
before: 'before_param_value',
};
createComponent();
fetchReleasesSpy.mockClear();
window.dispatchEvent(new PopStateEvent('popstate'));
});
it('calls the fetchRelease store method with the parameters from the URL query', () => {
expect(fetchReleasesSpy).toHaveBeenCalledTimes(1);
expect(fetchReleasesSpy).toHaveBeenCalledWith(expect.anything(), urlParams);
});
});
});