@@ -117,7 +117,7 @@ exports[`MlExperiment with candidates renders correctly 1`] = `
scope="col"
>
- L1 Ratio
+ Name
- Rmse
+ Created at
|
- Auc
+ User
|
- Mae
+ L1 Ratio
|
+
+ Rmse
+
+ |
+
+
+ Auc
+
+ |
+
+
+ Mae
+
+ |
+ |
- 0.4
+
+ aCandidate
+
|
- 1
+
|
|
+ >
+
+ @root
+
+
|
+ >
+
+ 0.4
+
+
+
+ 1
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
Details
|
@@ -224,6 +312,7 @@ exports[`MlExperiment with candidates renders correctly 1`] = `
href="link_to_artifact"
rel="noopener"
target="_blank"
+ title="Artifacts"
>
Artifacts
@@ -238,42 +327,104 @@ exports[`MlExperiment with candidates renders correctly 1`] = `
class=""
role="cell"
>
- 0.5
+
+
+
|
|
+ >
+
+
- 0.3
+
+ -
+
|
|
+ >
+
+ 0.5
+
+
+
+
+
+ |
+
+
+ 0.3
+
+ |
+
+
+
+
+ |
+
Details
|
|
+ >
+
+
+ -
+
+
+
- 0.5
+
+
+
|
+ >
+
+
- 0.3
+
+ -
+
|
|
+ >
+
+ 0.5
+
+
+
+
+
+ |
+
+
+ 0.3
+
+ |
+
+
+
+
+ |
+
Details
|
|
+ >
+
+
+ -
+
+
+
- 0.5
+
+
+
|
+ >
+
+
- 0.3
+
+ -
+
|
|
+ >
+
+ 0.5
+
+
+
+
+
+ |
+
+
+ 0.3
+
+ |
+
+
+
+
+ |
+
Details
|
|
+ >
+
+
+ -
+
+
+
- 0.5
+
+
+
|
+ >
+
+
- 0.3
+
+ -
+
|
|
+ >
+
+ 0.5
+
+
+
+
+
+ |
+
+
+ 0.3
+
+ |
+
+
+
+
+ |
+
Details
|
|
+ >
+
+
+ -
+
+
+
diff --git a/spec/frontend/ml/experiment_tracking/components/ml_experiment_spec.js b/spec/frontend/ml/experiment_tracking/components/ml_experiment_spec.js
index c62e8a7beef..abcaf17303f 100644
--- a/spec/frontend/ml/experiment_tracking/components/ml_experiment_spec.js
+++ b/spec/frontend/ml/experiment_tracking/components/ml_experiment_spec.js
@@ -46,11 +46,47 @@ describe('MlExperiment', () => {
const createWrapperWithCandidates = (pagination = defaultPagination) => {
return createWrapper(
[
- { rmse: 1, l1_ratio: 0.4, details: 'link_to_candidate1', artifact: 'link_to_artifact' },
- { auc: 0.3, l1_ratio: 0.5, details: 'link_to_candidate2' },
- { auc: 0.3, l1_ratio: 0.5, details: 'link_to_candidate3' },
- { auc: 0.3, l1_ratio: 0.5, details: 'link_to_candidate4' },
- { auc: 0.3, l1_ratio: 0.5, details: 'link_to_candidate5' },
+ {
+ rmse: 1,
+ l1_ratio: 0.4,
+ details: 'link_to_candidate1',
+ artifact: 'link_to_artifact',
+ name: 'aCandidate',
+ created_at: '2023-01-05T14:07:02.975Z',
+ user: { username: 'root', path: '/root' },
+ },
+ {
+ auc: 0.3,
+ l1_ratio: 0.5,
+ details: 'link_to_candidate2',
+ created_at: '2023-01-05T14:07:02.975Z',
+ name: null,
+ user: null,
+ },
+ {
+ auc: 0.3,
+ l1_ratio: 0.5,
+ details: 'link_to_candidate3',
+ created_at: '2023-01-05T14:07:02.975Z',
+ name: null,
+ user: null,
+ },
+ {
+ auc: 0.3,
+ l1_ratio: 0.5,
+ details: 'link_to_candidate4',
+ created_at: '2023-01-05T14:07:02.975Z',
+ name: null,
+ user: null,
+ },
+ {
+ auc: 0.3,
+ l1_ratio: 0.5,
+ details: 'link_to_candidate5',
+ created_at: '2023-01-05T14:07:02.975Z',
+ name: null,
+ user: null,
+ },
],
['rmse', 'auc', 'mae'],
['l1_ratio'],
diff --git a/spec/frontend/monitoring/requests/index_spec.js b/spec/frontend/monitoring/requests/index_spec.js
index d105fe0def2..94f1f896e3c 100644
--- a/spec/frontend/monitoring/requests/index_spec.js
+++ b/spec/frontend/monitoring/requests/index_spec.js
@@ -5,6 +5,7 @@ import * as commonUtils from '~/lib/utils/common_utils';
import statusCodes, {
HTTP_STATUS_BAD_REQUEST,
HTTP_STATUS_NO_CONTENT,
+ HTTP_STATUS_SERVICE_UNAVAILABLE,
HTTP_STATUS_UNAUTHORIZED,
HTTP_STATUS_UNPROCESSABLE_ENTITY,
} from '~/lib/utils/http_status';
@@ -138,7 +139,7 @@ describe('monitoring metrics_requests', () => {
code | reason
${HTTP_STATUS_BAD_REQUEST} | ${'Parameters are missing or incorrect'}
${HTTP_STATUS_UNPROCESSABLE_ENTITY} | ${"Expression can't be executed"}
- ${statusCodes.SERVICE_UNAVAILABLE} | ${'Query timed out or aborted'}
+ ${HTTP_STATUS_SERVICE_UNAVAILABLE} | ${'Query timed out or aborted'}
`('rejects with details: "$reason" after getting an HTTP $code error', ({ code, reason }) => {
mock.onGet(prometheusEndpoint).reply(code, {
status: 'error',
diff --git a/spec/frontend/monitoring/store/mutations_spec.js b/spec/frontend/monitoring/store/mutations_spec.js
index 94f32777f4b..3baef743f42 100644
--- a/spec/frontend/monitoring/store/mutations_spec.js
+++ b/spec/frontend/monitoring/store/mutations_spec.js
@@ -1,4 +1,4 @@
-import httpStatusCodes, { HTTP_STATUS_BAD_REQUEST } from '~/lib/utils/http_status';
+import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_SERVICE_UNAVAILABLE } from '~/lib/utils/http_status';
import { dashboardEmptyStates, metricStates } from '~/monitoring/constants';
import * as types from '~/monitoring/stores/mutation_types';
import mutations from '~/monitoring/stores/mutations';
@@ -317,7 +317,7 @@ describe('Monitoring mutations', () => {
metricId,
error: {
response: {
- status: httpStatusCodes.SERVICE_UNAVAILABLE,
+ status: HTTP_STATUS_SERVICE_UNAVAILABLE,
},
},
});
diff --git a/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js b/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js
index e0e26434680..9c1ebf5a2eb 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js
@@ -63,6 +63,14 @@ describe('DeleteModal', () => {
expect(wrapper.emitted('confirm')).toHaveLength(1);
});
+ it('emits cancel when cancel event is emitted', () => {
+ expect(wrapper.emitted('cancel')).toBeUndefined();
+
+ findModal().vm.$emit('cancel');
+
+ expect(wrapper.emitted('cancel')).toHaveLength(1);
+ });
+
it('show calls gl-modal show', () => {
findModal().vm.show();
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
index 7cc5bea0f7a..5e9cb8fbb0b 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
@@ -1,14 +1,19 @@
import { GlAlert, GlSprintf } from '@gitlab/ui';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { stubComponent } from 'helpers/stub_component';
import PackagesListRow from '~/packages_and_registries/package_registry/components/list/package_list_row.vue';
import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
import DeletePackageModal from '~/packages_and_registries/shared/components/delete_package_modal.vue';
+import DeleteModal from '~/packages_and_registries/package_registry/components/delete_modal.vue';
import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue';
import {
DELETE_PACKAGE_TRACKING_ACTION,
+ DELETE_PACKAGES_TRACKING_ACTION,
REQUEST_DELETE_PACKAGE_TRACKING_ACTION,
+ REQUEST_DELETE_PACKAGES_TRACKING_ACTION,
CANCEL_DELETE_PACKAGE_TRACKING_ACTION,
+ CANCEL_DELETE_PACKAGES_TRACKING_ACTION,
} from '~/packages_and_registries/package_registry/constants';
import PackagesList from '~/packages_and_registries/package_registry/components/list/packages_list.vue';
import Tracking from '~/tracking';
@@ -44,6 +49,7 @@ describe('packages_list', () => {
const findRegistryList = () => wrapper.findComponent(RegistryList);
const findPackagesListRow = () => wrapper.findComponent(PackagesListRow);
const findErrorPackageAlert = () => wrapper.findComponent(GlAlert);
+ const findDeletePackagesModal = () => wrapper.findComponent(DeleteModal);
const mountComponent = (props) => {
wrapper = shallowMountExtended(PackagesList, {
@@ -53,6 +59,11 @@ describe('packages_list', () => {
},
stubs: {
DeletePackageModal,
+ DeleteModal: stubComponent(DeleteModal, {
+ methods: {
+ show: jest.fn(),
+ },
+ }),
GlSprintf,
RegistryList,
},
@@ -125,20 +136,48 @@ describe('packages_list', () => {
});
});
- describe('when the user can destroy the package', () => {
- beforeEach(async () => {
+ describe.each`
+ description | finderFunction | deletePayload
+ ${'when the user can destroy the package'} | ${findPackagesListRow} | ${firstPackage}
+ ${'when the user can bulk destroy packages and deletes only one package'} | ${findRegistryList} | ${[firstPackage]}
+ `('$description', ({ finderFunction, deletePayload }) => {
+ let eventSpy;
+ const category = 'UI::NpmPackages';
+
+ beforeEach(() => {
+ eventSpy = jest.spyOn(Tracking, 'event');
mountComponent();
- await findPackagesListRow().vm.$emit('delete', firstPackage);
+ finderFunction().vm.$emit('delete', deletePayload);
});
it('passes itemToBeDeleted to the modal', () => {
expect(findPackageListDeleteModal().props('itemToBeDeleted')).toStrictEqual(firstPackage);
});
- it('emits package:delete when modal confirms', async () => {
- await findPackageListDeleteModal().vm.$emit('ok');
+ it('requesting delete tracks the right action', () => {
+ expect(eventSpy).toHaveBeenCalledWith(
+ category,
+ REQUEST_DELETE_PACKAGE_TRACKING_ACTION,
+ expect.any(Object),
+ );
+ });
- expect(wrapper.emitted('package:delete')[0]).toEqual([firstPackage]);
+ describe('when modal confirms', () => {
+ beforeEach(() => {
+ findPackageListDeleteModal().vm.$emit('ok');
+ });
+
+ it('emits package:delete when modal confirms', () => {
+ expect(wrapper.emitted('package:delete')[0]).toEqual([firstPackage]);
+ });
+
+ it('tracks the right action', () => {
+ expect(eventSpy).toHaveBeenCalledWith(
+ category,
+ DELETE_PACKAGE_TRACKING_ACTION,
+ expect.any(Object),
+ );
+ });
});
it.each(['ok', 'cancel'])('resets itemToBeDeleted when modal emits %s', async (event) => {
@@ -146,26 +185,73 @@ describe('packages_list', () => {
expect(findPackageListDeleteModal().props('itemToBeDeleted')).toBeNull();
});
+
+ it('canceling delete tracks the right action', () => {
+ findPackageListDeleteModal().vm.$emit('cancel');
+
+ expect(eventSpy).toHaveBeenCalledWith(
+ category,
+ CANCEL_DELETE_PACKAGE_TRACKING_ACTION,
+ expect.any(Object),
+ );
+ });
});
describe('when the user can bulk destroy packages', () => {
+ let eventSpy;
+ const items = [firstPackage, secondPackage];
+
beforeEach(() => {
+ eventSpy = jest.spyOn(Tracking, 'event');
mountComponent();
+ findRegistryList().vm.$emit('delete', items);
});
- it('passes itemToBeDeleted to the modal when there is only one package', async () => {
- await findRegistryList().vm.$emit('delete', [firstPackage]);
-
- expect(findPackageListDeleteModal().props('itemToBeDeleted')).toStrictEqual(firstPackage);
+ it('passes itemsToBeDeleted to the modal', () => {
+ expect(findDeletePackagesModal().props('itemsToBeDeleted')).toStrictEqual(items);
expect(wrapper.emitted('delete')).toBeUndefined();
});
- it('emits delete when there is more than one package', () => {
- const items = [firstPackage, secondPackage];
- findRegistryList().vm.$emit('delete', items);
+ it('requesting delete tracks the right action', () => {
+ expect(eventSpy).toHaveBeenCalledWith(
+ undefined,
+ REQUEST_DELETE_PACKAGES_TRACKING_ACTION,
+ expect.any(Object),
+ );
+ });
- expect(wrapper.emitted('delete')).toHaveLength(1);
- expect(wrapper.emitted('delete')[0]).toEqual([items]);
+ describe('when modal confirms', () => {
+ beforeEach(() => {
+ findDeletePackagesModal().vm.$emit('confirm');
+ });
+
+ it('emits delete event', () => {
+ expect(wrapper.emitted('delete')[0]).toEqual([items]);
+ });
+
+ it('tracks the right action', () => {
+ expect(eventSpy).toHaveBeenCalledWith(
+ undefined,
+ DELETE_PACKAGES_TRACKING_ACTION,
+ expect.any(Object),
+ );
+ });
+ });
+
+ it.each(['confirm', 'cancel'])('resets itemsToBeDeleted when modal emits %s', async (event) => {
+ await findDeletePackagesModal().vm.$emit(event);
+
+ expect(findDeletePackagesModal().props('itemsToBeDeleted')).toHaveLength(0);
+ });
+
+ it('canceling delete tracks the right action', () => {
+ findDeletePackagesModal().vm.$emit('cancel');
+
+ expect(eventSpy).toHaveBeenCalledWith(
+ undefined,
+ CANCEL_DELETE_PACKAGES_TRACKING_ACTION,
+ expect.any(Object),
+ );
});
});
@@ -223,44 +309,4 @@ describe('packages_list', () => {
expect(wrapper.emitted('next-page')).toHaveLength(1);
});
});
-
- describe('tracking', () => {
- let eventSpy;
- const category = 'UI::NpmPackages';
-
- beforeEach(() => {
- eventSpy = jest.spyOn(Tracking, 'event');
- mountComponent();
- findPackagesListRow().vm.$emit('delete', firstPackage);
- return nextTick();
- });
-
- it('requesting the delete tracks the right action', () => {
- expect(eventSpy).toHaveBeenCalledWith(
- category,
- REQUEST_DELETE_PACKAGE_TRACKING_ACTION,
- expect.any(Object),
- );
- });
-
- it('confirming delete tracks the right action', () => {
- findPackageListDeleteModal().vm.$emit('ok');
-
- expect(eventSpy).toHaveBeenCalledWith(
- category,
- DELETE_PACKAGE_TRACKING_ACTION,
- expect.any(Object),
- );
- });
-
- it('canceling delete tracks the right action', () => {
- findPackageListDeleteModal().vm.$emit('cancel');
-
- expect(eventSpy).toHaveBeenCalledWith(
- category,
- CANCEL_DELETE_PACKAGE_TRACKING_ACTION,
- expect.any(Object),
- );
- });
- });
});
diff --git a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
index f26aefea221..b3cbd9f5dcf 100644
--- a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
@@ -1,17 +1,14 @@
import { GlAlert, GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
-
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { stubComponent } from 'helpers/stub_component';
import ListPage from '~/packages_and_registries/package_registry/pages/list.vue';
import PackageTitle from '~/packages_and_registries/package_registry/components/list/package_title.vue';
import PackageSearch from '~/packages_and_registries/package_registry/components/list/package_search.vue';
import OriginalPackageList from '~/packages_and_registries/package_registry/components/list/packages_list.vue';
import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
-import DeleteModal from '~/packages_and_registries/package_registry/components/delete_modal.vue';
import {
PROJECT_RESOURCE_TYPE,
GROUP_RESOURCE_TYPE,
@@ -62,7 +59,6 @@ describe('PackagesListApp', () => {
const findListComponent = () => wrapper.findComponent(PackageList);
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findDeletePackage = () => wrapper.findComponent(DeletePackage);
- const findDeletePackagesModal = () => wrapper.findComponent(DeleteModal);
const mountComponent = ({
resolver = jest.fn().mockResolvedValue(packagesListQuery()),
@@ -87,11 +83,6 @@ describe('PackagesListApp', () => {
GlLink,
PackageList,
DeletePackage,
- DeleteModal: stubComponent(DeleteModal, {
- methods: {
- show: jest.fn(),
- },
- }),
},
});
};
@@ -296,18 +287,6 @@ describe('PackagesListApp', () => {
describe('bulk delete package', () => {
const items = [{ id: '1' }, { id: '2' }];
- it('deletePackage is bound to package-list package:delete event', async () => {
- mountComponent();
-
- await waitForFirstRequest();
-
- findListComponent().vm.$emit('delete', [{ id: '1' }, { id: '2' }]);
-
- await waitForPromises();
-
- expect(findDeletePackagesModal().props('itemsToBeDeleted')).toEqual(items);
- });
-
it('calls mutation with the right values and shows success alert', async () => {
const mutationResolver = jest.fn().mockResolvedValue(packagesDestroyMutation());
mountComponent({
@@ -318,8 +297,6 @@ describe('PackagesListApp', () => {
findListComponent().vm.$emit('delete', items);
- findDeletePackagesModal().vm.$emit('confirm');
-
expect(mutationResolver).toHaveBeenCalledWith({
ids: items.map((item) => item.id),
});
@@ -341,8 +318,6 @@ describe('PackagesListApp', () => {
findListComponent().vm.$emit('delete', items);
- findDeletePackagesModal().vm.$emit('confirm');
-
await waitForPromises();
expect(findAlert().exists()).toBe(true);
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js
index 7c9aae13d25..1a696e00f85 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_content_spec.js
@@ -5,7 +5,7 @@ import MockAdapter from 'axios-mock-adapter';
import WikiContent from '~/pages/shared/wikis/components/wiki_content.vue';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
import axios from '~/lib/utils/axios_utils';
-import httpStatus from '~/lib/utils/http_status';
+import httpStatus, { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
import waitForPromises from 'helpers/wait_for_promises';
import { handleLocationHash } from '~/lib/utils/common_utils';
@@ -88,7 +88,7 @@ describe('pages/shared/wikis/components/wiki_content', () => {
describe('when loading content fails', () => {
beforeEach(() => {
- mock.onGet(PATH).replyOnce(httpStatus.INTERNAL_SERVER_ERROR, '');
+ mock.onGet(PATH).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR, '');
buildWrapper();
return waitForPromises();
});
diff --git a/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js b/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
index 2f7c17723cc..1c7cb07ccfe 100644
--- a/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
+++ b/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
@@ -8,7 +8,10 @@ import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_help
import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
-import httpStatusCodes, { HTTP_STATUS_BAD_REQUEST } from '~/lib/utils/http_status';
+import httpStatusCodes, {
+ HTTP_STATUS_BAD_REQUEST,
+ HTTP_STATUS_INTERNAL_SERVER_ERROR,
+} from '~/lib/utils/http_status';
import { redirectTo } from '~/lib/utils/url_utility';
import PipelineNewForm from '~/pipeline_new/components/pipeline_new_form.vue';
import ciConfigVariablesQuery from '~/pipeline_new/graphql/queries/ci_config_variables.graphql';
@@ -365,7 +368,7 @@ describe('Pipeline New Form', () => {
beforeEach(() => {
mock
.onGet(projectRefsEndpoint, { params: { search: '' } })
- .reply(httpStatusCodes.INTERNAL_SERVER_ERROR);
+ .reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
findRefsDropdown().vm.$emit('loadingError');
});
@@ -449,9 +452,7 @@ describe('Pipeline New Form', () => {
describe('when the error response cannot be handled', () => {
beforeEach(async () => {
- mock
- .onPost(pipelinesPath)
- .reply(httpStatusCodes.INTERNAL_SERVER_ERROR, 'something went wrong');
+ mock.onPost(pipelinesPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, 'something went wrong');
findForm().vm.$emit('submit', dummySubmitEvent);
diff --git a/spec/frontend/pipeline_new/components/refs_dropdown_spec.js b/spec/frontend/pipeline_new/components/refs_dropdown_spec.js
index 6fae970aaf0..a9921a228c4 100644
--- a/spec/frontend/pipeline_new/components/refs_dropdown_spec.js
+++ b/spec/frontend/pipeline_new/components/refs_dropdown_spec.js
@@ -3,7 +3,7 @@ import MockAdapter from 'axios-mock-adapter';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
-import httpStatusCodes from '~/lib/utils/http_status';
+import httpStatusCodes, { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
import RefsDropdown from '~/pipeline_new/components/refs_dropdown.vue';
@@ -166,7 +166,7 @@ describe('Pipeline New Form', () => {
beforeEach(async () => {
mock
.onGet(projectRefsEndpoint, { params: { search: '' } })
- .reply(httpStatusCodes.INTERNAL_SERVER_ERROR);
+ .reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
findDropdown().vm.$emit('shown');
await waitForPromises();
diff --git a/spec/frontend/repository/commits_service_spec.js b/spec/frontend/repository/commits_service_spec.js
index 2ff2f4f6eb5..3b7db6ffba3 100644
--- a/spec/frontend/repository/commits_service_spec.js
+++ b/spec/frontend/repository/commits_service_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { loadCommits, isRequested, resetRequestedCommits } from '~/repository/commits_service';
-import httpStatus from '~/lib/utils/http_status';
+import httpStatus, { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
import { createAlert } from '~/flash';
import { I18N_COMMIT_DATA_FETCH_ERROR } from '~/repository/constants';
import { refWithSpecialCharMock } from './mock_data';
@@ -71,7 +71,7 @@ describe('commits service', () => {
it('calls `createAlert` when the request fails', async () => {
const invalidPath = '/#@ some/path';
const invalidUrl = `${url}${invalidPath}`;
- mock.onGet(invalidUrl).replyOnce(httpStatus.INTERNAL_SERVER_ERROR, [], {});
+ mock.onGet(invalidUrl).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR, [], {});
await requestCommits(1, 'my-project', invalidPath);
diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js
index 6ece72c41bb..99e23348b92 100644
--- a/spec/frontend/repository/components/blob_content_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_content_viewer_spec.js
@@ -25,7 +25,7 @@ import CodeIntelligence from '~/code_navigation/components/app.vue';
import * as urlUtility from '~/lib/utils/url_utility';
import { isLoggedIn, handleLocationHash } from '~/lib/utils/common_utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import httpStatusCodes from '~/lib/utils/http_status';
+import httpStatusCodes, { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
import LineHighlighter from '~/blob/line_highlighter';
import { LEGACY_FILE_TYPES } from '~/repository/constants';
import { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constants';
@@ -368,7 +368,7 @@ describe('Blob content viewer component', () => {
it('does not load a CodeIntelligence component when no viewers are loaded', async () => {
const url = 'some_file.js?format=json&viewer=rich';
- mockAxios.onGet(url).replyOnce(httpStatusCodes.INTERNAL_SERVER_ERROR);
+ mockAxios.onGet(url).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
await createComponent({ blob: { ...richViewerMock, fileType: 'unknown' } });
expect(findCodeIntelligence().exists()).toBe(false);
diff --git a/spec/frontend/vue_merge_request_widget/extensions/test_report/index_spec.js b/spec/frontend/vue_merge_request_widget/extensions/test_report/index_spec.js
index baef247b649..334cddbbc06 100644
--- a/spec/frontend/vue_merge_request_widget/extensions/test_report/index_spec.js
+++ b/spec/frontend/vue_merge_request_widget/extensions/test_report/index_spec.js
@@ -8,7 +8,10 @@ import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
import extensionsContainer from '~/vue_merge_request_widget/components/extensions/container';
import { registerExtension } from '~/vue_merge_request_widget/components/extensions';
-import httpStatusCodes, { HTTP_STATUS_NO_CONTENT } from '~/lib/utils/http_status';
+import httpStatusCodes, {
+ HTTP_STATUS_INTERNAL_SERVER_ERROR,
+ HTTP_STATUS_NO_CONTENT,
+} from '~/lib/utils/http_status';
import TestCaseDetails from '~/pipelines/components/test_reports/test_case_details.vue';
import { failedReport } from 'jest/ci/reports/mock_data/mock_data';
@@ -91,7 +94,7 @@ describe('Test report extension', () => {
});
it('with an error response, displays failed to load text', async () => {
- mockApi(httpStatusCodes.INTERNAL_SERVER_ERROR);
+ mockApi(HTTP_STATUS_INTERNAL_SERVER_ERROR);
createComponent();
await waitForPromises();
diff --git a/spec/frontend/vue_merge_request_widget/extentions/accessibility/index_spec.js b/spec/frontend/vue_merge_request_widget/extentions/accessibility/index_spec.js
index a06ad930abe..d3ae81b9b10 100644
--- a/spec/frontend/vue_merge_request_widget/extentions/accessibility/index_spec.js
+++ b/spec/frontend/vue_merge_request_widget/extentions/accessibility/index_spec.js
@@ -6,7 +6,7 @@ import axios from '~/lib/utils/axios_utils';
import extensionsContainer from '~/vue_merge_request_widget/components/extensions/container';
import { registerExtension } from '~/vue_merge_request_widget/components/extensions';
import accessibilityExtension from '~/vue_merge_request_widget/extensions/accessibility';
-import httpStatusCodes from '~/lib/utils/http_status';
+import httpStatusCodes, { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
import { accessibilityReportResponseErrors, accessibilityReportResponseSuccess } from './mock_data';
describe('Accessibility extension', () => {
@@ -53,7 +53,7 @@ describe('Accessibility extension', () => {
});
it('displays failed loading text', async () => {
- mockApi(httpStatusCodes.INTERNAL_SERVER_ERROR);
+ mockApi(HTTP_STATUS_INTERNAL_SERVER_ERROR);
createComponent();
diff --git a/spec/frontend/vue_merge_request_widget/extentions/code_quality/index_spec.js b/spec/frontend/vue_merge_request_widget/extentions/code_quality/index_spec.js
index 4b26be40ae2..99c4c898d7a 100644
--- a/spec/frontend/vue_merge_request_widget/extentions/code_quality/index_spec.js
+++ b/spec/frontend/vue_merge_request_widget/extentions/code_quality/index_spec.js
@@ -7,7 +7,10 @@ import axios from '~/lib/utils/axios_utils';
import extensionsContainer from '~/vue_merge_request_widget/components/extensions/container';
import { registerExtension } from '~/vue_merge_request_widget/components/extensions';
import codeQualityExtension from '~/vue_merge_request_widget/extensions/code_quality';
-import httpStatusCodes, { HTTP_STATUS_NO_CONTENT } from '~/lib/utils/http_status';
+import httpStatusCodes, {
+ HTTP_STATUS_INTERNAL_SERVER_ERROR,
+ HTTP_STATUS_NO_CONTENT,
+} from '~/lib/utils/http_status';
import {
i18n,
codeQualityPrefixes,
@@ -76,7 +79,7 @@ describe('Code Quality extension', () => {
});
it('displays failed loading text', async () => {
- mockApi(httpStatusCodes.INTERNAL_SERVER_ERROR);
+ mockApi(HTTP_STATUS_INTERNAL_SERVER_ERROR);
createComponent();
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js
index 66ef473f368..658681bcd05 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js
@@ -4,7 +4,7 @@ import testAction from 'helpers/vuex_action_helper';
import { mockBranches } from 'jest/vue_shared/components/filtered_search_bar/mock_data';
import Api from '~/api';
import { createAlert } from '~/flash';
-import httpStatusCodes from '~/lib/utils/http_status';
+import httpStatusCodes, { HTTP_STATUS_SERVICE_UNAVAILABLE } from '~/lib/utils/http_status';
import * as actions from '~/vue_shared/components/filtered_search_bar/store/modules/filters/actions';
import * as types from '~/vue_shared/components/filtered_search_bar/store/modules/filters/mutation_types';
import initialState from '~/vue_shared/components/filtered_search_bar/store/modules/filters/state';
@@ -143,7 +143,7 @@ describe('Filters actions', () => {
describe('error', () => {
beforeEach(() => {
- mock.onAny().replyOnce(httpStatusCodes.SERVICE_UNAVAILABLE);
+ mock.onAny().replyOnce(HTTP_STATUS_SERVICE_UNAVAILABLE);
});
it('dispatches RECEIVE_BRANCHES_ERROR', () => {
@@ -155,7 +155,7 @@ describe('Filters actions', () => {
{ type: types.REQUEST_BRANCHES },
{
type: types.RECEIVE_BRANCHES_ERROR,
- payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ payload: HTTP_STATUS_SERVICE_UNAVAILABLE,
},
],
[],
@@ -215,7 +215,7 @@ describe('Filters actions', () => {
describe('error', () => {
beforeEach(() => {
- mock.onAny().replyOnce(httpStatusCodes.SERVICE_UNAVAILABLE);
+ mock.onAny().replyOnce(HTTP_STATUS_SERVICE_UNAVAILABLE);
});
it('dispatches RECEIVE_AUTHORS_ERROR and groupEndpoint set', () => {
@@ -227,7 +227,7 @@ describe('Filters actions', () => {
{ type: types.REQUEST_AUTHORS },
{
type: types.RECEIVE_AUTHORS_ERROR,
- payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ payload: HTTP_STATUS_SERVICE_UNAVAILABLE,
},
],
[],
@@ -246,7 +246,7 @@ describe('Filters actions', () => {
{ type: types.REQUEST_AUTHORS },
{
type: types.RECEIVE_AUTHORS_ERROR,
- payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ payload: HTTP_STATUS_SERVICE_UNAVAILABLE,
},
],
[],
@@ -282,7 +282,7 @@ describe('Filters actions', () => {
describe('error', () => {
beforeEach(() => {
- mock.onAny().replyOnce(httpStatusCodes.SERVICE_UNAVAILABLE);
+ mock.onAny().replyOnce(HTTP_STATUS_SERVICE_UNAVAILABLE);
});
it('dispatches RECEIVE_MILESTONES_ERROR', () => {
@@ -294,7 +294,7 @@ describe('Filters actions', () => {
{ type: types.REQUEST_MILESTONES },
{
type: types.RECEIVE_MILESTONES_ERROR,
- payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ payload: HTTP_STATUS_SERVICE_UNAVAILABLE,
},
],
[],
@@ -352,7 +352,7 @@ describe('Filters actions', () => {
describe('error', () => {
let restoreVersion;
beforeEach(() => {
- mock.onAny().replyOnce(httpStatusCodes.SERVICE_UNAVAILABLE);
+ mock.onAny().replyOnce(HTTP_STATUS_SERVICE_UNAVAILABLE);
restoreVersion = gon.api_version;
gon.api_version = 'v1';
});
@@ -370,7 +370,7 @@ describe('Filters actions', () => {
{ type: types.REQUEST_ASSIGNEES },
{
type: types.RECEIVE_ASSIGNEES_ERROR,
- payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ payload: HTTP_STATUS_SERVICE_UNAVAILABLE,
},
],
[],
@@ -389,7 +389,7 @@ describe('Filters actions', () => {
{ type: types.REQUEST_ASSIGNEES },
{
type: types.RECEIVE_ASSIGNEES_ERROR,
- payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ payload: HTTP_STATUS_SERVICE_UNAVAILABLE,
},
],
[],
@@ -425,7 +425,7 @@ describe('Filters actions', () => {
describe('error', () => {
beforeEach(() => {
- mock.onAny().replyOnce(httpStatusCodes.SERVICE_UNAVAILABLE);
+ mock.onAny().replyOnce(HTTP_STATUS_SERVICE_UNAVAILABLE);
});
it('dispatches RECEIVE_LABELS_ERROR', () => {
@@ -437,7 +437,7 @@ describe('Filters actions', () => {
{ type: types.REQUEST_LABELS },
{
type: types.RECEIVE_LABELS_ERROR,
- payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ payload: HTTP_STATUS_SERVICE_UNAVAILABLE,
},
],
[],
diff --git a/spec/helpers/projects/ml/experiments_helper_spec.rb b/spec/helpers/projects/ml/experiments_helper_spec.rb
index 9fafa43f99f..2b70201456a 100644
--- a/spec/helpers/projects/ml/experiments_helper_spec.rb
+++ b/spec/helpers/projects/ml/experiments_helper_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe Projects::Ml::ExperimentsHelper, feature_category: :mlops do
end
let_it_be(:candidate1) do
- create(:ml_candidates, experiment: experiment, user: project.creator).tap do |c|
+ create(:ml_candidates, experiment: experiment, user: project.creator, name: 'candidate1').tap do |c|
c.params.build([{ name: 'param2', value: 'p3' }, { name: 'param3', value: 'p4' }])
c.metrics.create!(name: 'metric3', value: 0.4)
end
@@ -27,18 +27,39 @@ RSpec.describe Projects::Ml::ExperimentsHelper, feature_category: :mlops do
let_it_be(:candidates) { [candidate0, candidate1] }
describe '#candidates_table_items' do
- subject { helper.candidates_table_items(candidates) }
+ subject { Gitlab::Json.parse(helper.candidates_table_items(candidates)) }
- it 'creates the correct model for the table' do
- expected_value = [
+ it 'creates the correct model for the table', :aggregate_failures do
+ expected_values = [
{ 'param1' => 'p1', 'param2' => 'p2', 'metric1' => '0.1000', 'metric2' => '0.2000', 'metric3' => '0.3000',
'artifact' => "/#{project.full_path}/-/packages/#{candidate0.artifact.id}",
- 'details' => "/#{project.full_path}/-/ml/candidates/#{candidate0.iid}" },
+ 'details' => "/#{project.full_path}/-/ml/candidates/#{candidate0.iid}",
+ 'name' => candidate0.name,
+ 'created_at' => candidate0.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
+ 'user' => { 'username' => candidate0.user.username, 'path' => "/#{candidate0.user.username}" } },
{ 'param2' => 'p3', 'param3' => 'p4', 'metric3' => '0.4000',
- 'artifact' => nil, 'details' => "/#{project.full_path}/-/ml/candidates/#{candidate1.iid}" }
+ 'artifact' => nil, 'details' => "/#{project.full_path}/-/ml/candidates/#{candidate1.iid}",
+ 'name' => candidate1.name,
+ 'created_at' => candidate1.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
+ 'user' => { 'username' => candidate1.user.username, 'path' => "/#{candidate1.user.username}" } }
]
- expect(Gitlab::Json.parse(subject)).to match_array(expected_value)
+ subject.sort_by! { |s| s[:name] }
+
+ expect(subject[0]).to eq(expected_values[0])
+ expect(subject[1]).to eq(expected_values[1])
+ end
+
+ context 'when candidate does not have user' do
+ let(:candidates) { [candidate0] }
+
+ before do
+ allow(candidate0).to receive(:user).and_return(nil)
+ end
+
+ it 'has the user property, but is nil' do
+ expect(subject[0]['user']).to be_nil
+ end
end
end
diff --git a/spec/models/ml/candidate_spec.rb b/spec/models/ml/candidate_spec.rb
index 85f2440f2d7..fa8952dc0f4 100644
--- a/spec/models/ml/candidate_spec.rb
+++ b/spec/models/ml/candidate_spec.rb
@@ -121,12 +121,13 @@ RSpec.describe Ml::Candidate, factory_default: :keep do
end
end
- describe "#including_metrics_and_params" do
- subject { described_class.including_metrics_and_params.find_by(id: candidate.id) }
+ describe "#including_relationships" do
+ subject { described_class.including_relationships.find_by(id: candidate.id) }
it 'loads latest metrics and params', :aggregate_failures do
expect(subject.association_cached?(:latest_metrics)).to be(true)
expect(subject.association_cached?(:params)).to be(true)
+ expect(subject.association_cached?(:user)).to be(true)
end
end
end
diff --git a/yarn.lock b/yarn.lock
index 3c28081dd14..48678e839fe 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5097,10 +5097,10 @@ dompurify@2.3.8:
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.8.tgz#224fe9ae57d7ebd9a1ae1ac18c1c1ca3f532226f"
integrity sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw==
-dompurify@^2.4.1, dompurify@^2.4.2:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.2.tgz#c3409b49357804c9b00e1fbebea81f26514c5bc3"
- integrity sha512-ckbbxcGpfTJ7SNHC2yT2pHSCYxo2oQgSfdoDHQANzMzQyGzVmalF9W/B+X97Cdik5xFwWtwJP232gIP2+1kNEA==
+dompurify@^2.4.1, dompurify@^2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.3.tgz#f4133af0e6a50297fc8874e2eaedc13a3c308c03"
+ integrity sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==
domutils@^2.5.2, domutils@^2.6.0:
version "2.6.0"