diff options
Diffstat (limited to 'spec/frontend/ml/model_registry/components/model_version_list_spec.js')
-rw-r--r-- | spec/frontend/ml/model_registry/components/model_version_list_spec.js | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/spec/frontend/ml/model_registry/components/model_version_list_spec.js b/spec/frontend/ml/model_registry/components/model_version_list_spec.js new file mode 100644 index 00000000000..41f7e71c543 --- /dev/null +++ b/spec/frontend/ml/model_registry/components/model_version_list_spec.js @@ -0,0 +1,184 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import { GlAlert } from '@gitlab/ui'; +import * as Sentry from '~/sentry/sentry_browser_wrapper'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import ModelVersionList from '~/ml/model_registry/components/model_version_list.vue'; +import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue'; +import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue'; +import ModelVersionRow from '~/ml/model_registry/components/model_version_row.vue'; +import getModelVersionsQuery from '~/ml/model_registry/graphql/queries/get_model_versions.query.graphql'; +import EmptyState from '~/ml/model_registry/components/empty_state.vue'; +import { GRAPHQL_PAGE_SIZE, MODEL_ENTITIES } from '~/ml/model_registry/constants'; +import { + emptyModelVersionsQuery, + modelVersionsQuery, + graphqlModelVersions, + graphqlPageInfo, +} from '../graphql_mock_data'; + +Vue.use(VueApollo); + +describe('ModelVersionList', () => { + let wrapper; + let apolloProvider; + + const findAlert = () => wrapper.findComponent(GlAlert); + const findLoader = () => wrapper.findComponent(PackagesListLoader); + const findRegistryList = () => wrapper.findComponent(RegistryList); + const findEmptyState = () => wrapper.findComponent(EmptyState); + const findListRow = () => wrapper.findComponent(ModelVersionRow); + const findAllRows = () => wrapper.findAllComponents(ModelVersionRow); + + const mountComponent = ({ + props = {}, + resolver = jest.fn().mockResolvedValue(modelVersionsQuery()), + } = {}) => { + const requestHandlers = [[getModelVersionsQuery, resolver]]; + apolloProvider = createMockApollo(requestHandlers); + + wrapper = shallowMountExtended(ModelVersionList, { + apolloProvider, + propsData: { + modelId: 2, + ...props, + }, + stubs: { + RegistryList, + }, + }); + }; + + beforeEach(() => { + jest.spyOn(Sentry, 'captureException').mockImplementation(); + }); + + describe('when list is loaded and has no data', () => { + const resolver = jest.fn().mockResolvedValue(emptyModelVersionsQuery); + beforeEach(async () => { + mountComponent({ resolver }); + await waitForPromises(); + }); + + it('shows empty state', () => { + expect(findEmptyState().props('entityType')).toBe(MODEL_ENTITIES.modelVersion); + }); + + it('does not display loader', () => { + expect(findLoader().exists()).toBe(false); + }); + + it('does not display rows', () => { + expect(findListRow().exists()).toBe(false); + }); + + it('does not display registry list', () => { + expect(findRegistryList().exists()).toBe(false); + }); + + it('does not display alert', () => { + expect(findAlert().exists()).toBe(false); + }); + }); + + describe('if load fails, alert', () => { + beforeEach(async () => { + const error = new Error('Failure!'); + mountComponent({ resolver: jest.fn().mockRejectedValue(error) }); + + await waitForPromises(); + }); + + it('is displayed', () => { + expect(findAlert().exists()).toBe(true); + }); + + it('shows error message', () => { + expect(findAlert().text()).toContain('Failed to load model versions with error: Failure!'); + }); + + it('is not dismissible', () => { + expect(findAlert().props('dismissible')).toBe(false); + }); + + it('is of variant danger', () => { + expect(findAlert().attributes('variant')).toBe('danger'); + }); + + it('error is logged in sentry', () => { + expect(Sentry.captureException).toHaveBeenCalled(); + }); + }); + + describe('when list is loaded with data', () => { + beforeEach(async () => { + mountComponent(); + await waitForPromises(); + }); + + it('displays package registry list', () => { + expect(findRegistryList().exists()).toEqual(true); + }); + + it('binds the right props', () => { + expect(findRegistryList().props()).toMatchObject({ + items: graphqlModelVersions, + pagination: {}, + isLoading: false, + hiddenDelete: true, + }); + }); + + it('displays package version rows', () => { + expect(findAllRows().exists()).toEqual(true); + expect(findAllRows()).toHaveLength(graphqlModelVersions.length); + }); + + it('binds the correct props', () => { + expect(findAllRows().at(0).props()).toMatchObject({ + modelVersion: expect.objectContaining(graphqlModelVersions[0]), + }); + + expect(findAllRows().at(1).props()).toMatchObject({ + modelVersion: expect.objectContaining(graphqlModelVersions[1]), + }); + }); + + it('does not display loader', () => { + expect(findLoader().exists()).toBe(false); + }); + + it('does not display empty state', () => { + expect(findEmptyState().exists()).toBe(false); + }); + }); + + describe('when user interacts with pagination', () => { + const resolver = jest.fn().mockResolvedValue(modelVersionsQuery()); + + beforeEach(async () => { + mountComponent({ resolver }); + await waitForPromises(); + }); + + it('when list emits next-page fetches the next set of records', async () => { + findRegistryList().vm.$emit('next-page'); + await waitForPromises(); + + expect(resolver).toHaveBeenLastCalledWith( + expect.objectContaining({ after: graphqlPageInfo.endCursor, first: GRAPHQL_PAGE_SIZE }), + ); + }); + + it('when list emits prev-page fetches the prev set of records', async () => { + findRegistryList().vm.$emit('prev-page'); + await waitForPromises(); + + expect(resolver).toHaveBeenLastCalledWith( + expect.objectContaining({ before: graphqlPageInfo.startCursor, last: GRAPHQL_PAGE_SIZE }), + ); + }); + }); +}); |