Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-12 12:10:19 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-12 12:10:19 +0300
commit133ec9237af290062aae70e6f115db69b51c88de (patch)
tree866ddeec2098e6557e4fe93941438ada45713940 /spec
parentf9ad7e0c9fa576bf4d651ffe3e278750bf548400 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/finders/deployments_finder_spec.rb22
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/packages/package.json4
-rw-r--r--spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap2
-rw-r--r--spec/frontend/packages/shared/components/package_list_row_spec.js38
-rw-r--r--spec/frontend/packages/shared/components/package_path_spec.js86
-rw-r--r--spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js79
-rw-r--r--spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js47
-rw-r--r--spec/frontend/vue_shared/components/registry/list_item_spec.js8
-rw-r--r--spec/frontend/vue_shared/directives/validation_spec.js135
-rw-r--r--spec/graphql/types/project_type_spec.rb2
-rw-r--r--spec/helpers/nav/top_nav_helper_spec.rb170
-rw-r--r--spec/lib/gitlab/highlight_spec.rb23
-rw-r--r--spec/models/bulk_imports/export_spec.rb10
-rw-r--r--spec/models/bulk_imports/file_transfer/group_config_spec.rb (renamed from spec/models/bulk_imports/exports/group_config_spec.rb)6
-rw-r--r--spec/models/bulk_imports/file_transfer/project_config_spec.rb (renamed from spec/models/bulk_imports/exports/project_config_spec.rb)6
-rw-r--r--spec/models/bulk_imports/file_transfer_spec.rb25
-rw-r--r--spec/presenters/packages/detail/package_presenter_spec.rb1
-rw-r--r--spec/requests/api/graphql/project_query_spec.rb16
-rw-r--r--spec/services/bulk_imports/export_service_spec.rb6
-rw-r--r--spec/services/bulk_imports/relation_export_service_spec.rb2
-rw-r--r--spec/services/packages/rubygems/process_gem_service_spec.rb5
-rw-r--r--spec/workers/packages/nuget/extraction_worker_spec.rb9
-rw-r--r--spec/workers/packages/rubygems/extraction_worker_spec.rb22
23 files changed, 592 insertions, 132 deletions
diff --git a/spec/finders/deployments_finder_spec.rb b/spec/finders/deployments_finder_spec.rb
index 0c8a06d7e28..b294f1117f5 100644
--- a/spec/finders/deployments_finder_spec.rb
+++ b/spec/finders/deployments_finder_spec.rb
@@ -201,17 +201,31 @@ RSpec.describe DeploymentsFinder do
it 'adds `id` sorting as the second order column' do
order_value = subject.order_values[1]
- expect(order_value.to_sql).to eq(Deployment.arel_table[:id].desc.to_sql)
+ expect(order_value.to_sql).to eq(Deployment.arel_table[:id].asc.to_sql)
end
- it 'uses the `id DESC` as tie-breaker when ordering' do
+ it 'uses the `id ASC` as tie-breaker when ordering' do
updated_at = Time.now
deployment_1 = create(:deployment, :success, project: project, updated_at: updated_at)
deployment_2 = create(:deployment, :success, project: project, updated_at: updated_at)
deployment_3 = create(:deployment, :success, project: project, updated_at: updated_at)
- expect(subject).to eq([deployment_3, deployment_2, deployment_1])
+ expect(subject).to eq([deployment_1, deployment_2, deployment_3])
+ end
+
+ context 'when sort direction is desc' do
+ let(:params) { { **base_params, updated_after: 1.day.ago, order_by: 'updated_at', sort: 'desc' } }
+
+ it 'uses the `id DESC` as tie-breaker when ordering' do
+ updated_at = Time.now
+
+ deployment_1 = create(:deployment, :success, project: project, updated_at: updated_at)
+ deployment_2 = create(:deployment, :success, project: project, updated_at: updated_at)
+ deployment_3 = create(:deployment, :success, project: project, updated_at: updated_at)
+
+ expect(subject).to eq([deployment_3, deployment_2, deployment_1])
+ end
end
end
@@ -228,7 +242,7 @@ RSpec.describe DeploymentsFinder do
it 'sorts by `updated_at`' do
expect(subject.order_values.first.to_sql).to eq(Deployment.arel_table[:updated_at].asc.to_sql)
- expect(subject.order_values.second.to_sql).to eq(Deployment.arel_table[:id].desc.to_sql)
+ expect(subject.order_values.second.to_sql).to eq(Deployment.arel_table[:id].asc.to_sql)
end
context 'when deployments_finder_implicitly_enforce_ordering_for_updated_at_filter feature flag is disabled' do
diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/package.json b/spec/fixtures/api/schemas/public_api/v4/packages/package.json
index 08909efd10c..607e0df1886 100644
--- a/spec/fixtures/api/schemas/public_api/v4/packages/package.json
+++ b/spec/fixtures/api/schemas/public_api/v4/packages/package.json
@@ -4,6 +4,7 @@
"name",
"version",
"package_type",
+ "status",
"_links",
"versions"
],
@@ -20,6 +21,9 @@
"package_type": {
"type": "string"
},
+ "status": {
+ "type": "string"
+ },
"_links": {
"type": "object",
"required": [
diff --git a/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap b/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap
index 03b98478f3e..f4e617ecafe 100644
--- a/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap
+++ b/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap
@@ -34,6 +34,8 @@ exports[`packages_list_row renders 1`] = `
</gl-link-stub>
<!---->
+
+ <!---->
</div>
<!---->
diff --git a/spec/frontend/packages/shared/components/package_list_row_spec.js b/spec/frontend/packages/shared/components/package_list_row_spec.js
index fd54cd0f25d..bd15d48c4eb 100644
--- a/spec/frontend/packages/shared/components/package_list_row_spec.js
+++ b/spec/frontend/packages/shared/components/package_list_row_spec.js
@@ -1,8 +1,11 @@
+import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import PackagesListRow from '~/packages/shared/components/package_list_row.vue';
import PackagePath from '~/packages/shared/components/package_path.vue';
import PackageTags from '~/packages/shared/components/package_tags.vue';
+import { PACKAGE_ERROR_STATUS } from '~/packages/shared/constants';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { packageList } from '../../mock_data';
@@ -20,7 +23,10 @@ describe('packages_list_row', () => {
const findPackagePath = () => wrapper.find(PackagePath);
const findDeleteButton = () => wrapper.find('[data-testid="action-delete"]');
const findPackageIconAndName = () => wrapper.find(PackageIconAndName);
- const findInfrastructureIconAndName = () => wrapper.find(InfrastructureIconAndName);
+ const findInfrastructureIconAndName = () => wrapper.findComponent(InfrastructureIconAndName);
+ const findListItem = () => wrapper.findComponent(ListItem);
+ const findPackageLink = () => wrapper.findComponent(GlLink);
+ const findWarningIcon = () => wrapper.find('[data-testid="warning-icon"]');
const mountComponent = ({
isGroup = false,
@@ -44,6 +50,9 @@ describe('packages_list_row', () => {
showPackageType,
disableDelete,
},
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
});
};
@@ -146,4 +155,31 @@ describe('packages_list_row', () => {
expect(findInfrastructureIconAndName().exists()).toBe(true);
});
});
+
+ describe(`when the package is in ${PACKAGE_ERROR_STATUS} status`, () => {
+ beforeEach(() => {
+ mountComponent({ packageEntity: { ...packageWithoutTags, status: PACKAGE_ERROR_STATUS } });
+ });
+
+ it('list item has a disabled prop', () => {
+ expect(findListItem().props('disabled')).toBe(true);
+ });
+
+ it('details link is disabled', () => {
+ expect(findPackageLink().attributes('disabled')).toBe('true');
+ });
+
+ it('has a warning icon', () => {
+ const icon = findWarningIcon();
+ const tooltip = getBinding(icon.element, 'gl-tooltip');
+ expect(icon.props('icon')).toBe('warning');
+ expect(tooltip.value).toMatchObject({
+ title: 'Invalid Package: failed metadata extraction',
+ });
+ });
+
+ it('delete button is disabled', () => {
+ expect(findDeleteButton().props('disabled')).toBe(true);
+ });
+ });
});
diff --git a/spec/frontend/packages/shared/components/package_path_spec.js b/spec/frontend/packages/shared/components/package_path_spec.js
index 3c9cd3387ba..edbdd55c1d7 100644
--- a/spec/frontend/packages/shared/components/package_path_spec.js
+++ b/spec/frontend/packages/shared/components/package_path_spec.js
@@ -39,48 +39,66 @@ describe('PackagePath', () => {
const pathPieces = path.split('/').slice(1);
const hasTooltip = shouldExist.includes(ELLIPSIS_ICON);
- beforeEach(() => {
- mountComponent({ path });
- });
+ describe('not disabled component', () => {
+ beforeEach(() => {
+ mountComponent({ path });
+ });
- it('should have a base icon', () => {
- expect(findItem(BASE_ICON).exists()).toBe(true);
- });
+ it('should have a base icon', () => {
+ expect(findItem(BASE_ICON).exists()).toBe(true);
+ });
- it('should have a root link', () => {
- const root = findItem(ROOT_LINK);
- expect(root.exists()).toBe(true);
- expect(root.attributes('href')).toBe(rootUrl);
- });
+ it('should have a root link', () => {
+ const root = findItem(ROOT_LINK);
+ expect(root.exists()).toBe(true);
+ expect(root.attributes('href')).toBe(rootUrl);
+ });
- if (hasTooltip) {
- it('should have a tooltip', () => {
- const tooltip = findTooltip(findItem(ELLIPSIS_ICON));
- expect(tooltip).toBeDefined();
- expect(tooltip.value).toMatchObject({
- title: path,
+ if (hasTooltip) {
+ it('should have a tooltip', () => {
+ const tooltip = findTooltip(findItem(ELLIPSIS_ICON));
+ expect(tooltip).toBeDefined();
+ expect(tooltip.value).toMatchObject({
+ title: path,
+ });
});
- });
- }
+ }
- if (shouldExist.length) {
- it.each(shouldExist)(`should have %s`, (element) => {
- expect(findItem(element).exists()).toBe(true);
- });
- }
+ if (shouldExist.length) {
+ it.each(shouldExist)(`should have %s`, (element) => {
+ expect(findItem(element).exists()).toBe(true);
+ });
+ }
- if (shouldNotExist.length) {
- it.each(shouldNotExist)(`should not have %s`, (element) => {
- expect(findItem(element).exists()).toBe(false);
+ if (shouldNotExist.length) {
+ it.each(shouldNotExist)(`should not have %s`, (element) => {
+ expect(findItem(element).exists()).toBe(false);
+ });
+ }
+
+ if (shouldExist.includes(LEAF_LINK)) {
+ it('the last link should be the last piece of the path', () => {
+ const leaf = findItem(LEAF_LINK);
+ expect(leaf.attributes('href')).toBe(`/${path}`);
+ expect(leaf.text()).toBe(pathPieces[pathPieces.length - 1]);
+ });
+ }
+ });
+
+ describe('disabled component', () => {
+ beforeEach(() => {
+ mountComponent({ path, disabled: true });
});
- }
- if (shouldExist.includes(LEAF_LINK)) {
- it('the last link should be the last piece of the path', () => {
- const leaf = findItem(LEAF_LINK);
- expect(leaf.attributes('href')).toBe(`/${path}`);
- expect(leaf.text()).toBe(pathPieces[pathPieces.length - 1]);
+ it('root link is disabled', () => {
+ expect(findItem(ROOT_LINK).attributes('disabled')).toBe('true');
});
- }
+
+ if (shouldExist.includes(LEAF_LINK)) {
+ it('the last link is disabled', () => {
+ expect(findItem(LEAF_LINK).attributes('disabled')).toBe('true');
+ });
+ }
+ });
});
});
diff --git a/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js b/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
index 8b70f84c1bd..dc9063bde2c 100644
--- a/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
+++ b/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
@@ -1,5 +1,6 @@
import { GlFormCheckbox, GlSprintf, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import DeleteButton from '~/registry/explorer/components/delete_button.vue';
@@ -72,8 +73,15 @@ describe('tags list row', () => {
expect(findCheckbox().exists()).toBe(false);
});
- it('is disabled when the digest is missing', () => {
- mountComponent({ tag: { ...tag, digest: null } });
+ it.each`
+ digest | disabled
+ ${'foo'} | ${true}
+ ${null} | ${false}
+ ${null} | ${true}
+ ${'foo'} | ${true}
+ `('is disabled when the digest $digest and disabled is $disabled', ({ digest, disabled }) => {
+ mountComponent({ tag: { ...tag, digest }, disabled });
+
expect(findCheckbox().attributes('disabled')).toBe('true');
});
@@ -141,6 +149,12 @@ describe('tags list row', () => {
title: tag.location,
});
});
+
+ it('is disabled when the component is disabled', () => {
+ mountComponent({ ...defaultProps, disabled: true });
+
+ expect(findClipboardButton().attributes('disabled')).toBe('true');
+ });
});
describe('warning icon', () => {
@@ -266,15 +280,19 @@ describe('tags list row', () => {
});
it.each`
- canDelete | digest
- ${true} | ${null}
- ${false} | ${'foo'}
- ${false} | ${null}
- `('is disabled when canDelete is $canDelete and digest is $digest', ({ canDelete, digest }) => {
- mountComponent({ ...defaultProps, tag: { ...tag, canDelete, digest } });
-
- expect(findDeleteButton().attributes('disabled')).toBe('true');
- });
+ canDelete | digest | disabled
+ ${true} | ${null} | ${true}
+ ${false} | ${'foo'} | ${true}
+ ${false} | ${null} | ${true}
+ ${true} | ${'foo'} | ${true}
+ `(
+ 'is disabled when canDelete is $canDelete and digest is $digest and disabled is $disabled',
+ ({ canDelete, digest, disabled }) => {
+ mountComponent({ ...defaultProps, tag: { ...tag, canDelete, digest }, disabled });
+
+ expect(findDeleteButton().attributes('disabled')).toBe('true');
+ },
+ );
it('delete event emits delete', () => {
mountComponent();
@@ -287,13 +305,10 @@ describe('tags list row', () => {
describe('details rows', () => {
describe('when the tag has a digest', () => {
- beforeEach(() => {
+ it('has 3 details rows', async () => {
mountComponent();
+ await nextTick();
- return wrapper.vm.$nextTick();
- });
-
- it('has 3 details rows', () => {
expect(findDetailsRows().length).toBe(3);
});
@@ -303,17 +318,37 @@ describe('tags list row', () => {
${'manifest detail'} | ${findManifestDetail} | ${'Manifest digest: sha256:2cf3d2fdac1b04a14301d47d51cb88dcd26714c74f91440eeee99ce399089062'} | ${'log'} | ${true}
${'configuration detail'} | ${findConfigurationDetail} | ${'Configuration digest: sha256:c2613843ab33aabf847965442b13a8b55a56ae28837ce182627c0716eb08c02b'} | ${'cloud-gear'} | ${true}
`('$name details row', ({ finderFunction, text, icon, clipboard }) => {
- it(`has ${text} as text`, () => {
+ it(`has ${text} as text`, async () => {
+ mountComponent();
+ await nextTick();
+
expect(finderFunction().text()).toMatchInterpolatedText(text);
});
- it(`has the ${icon} icon`, () => {
+ it(`has the ${icon} icon`, async () => {
+ mountComponent();
+ await nextTick();
+
expect(finderFunction().props('icon')).toBe(icon);
});
- it(`is ${clipboard} that clipboard button exist`, () => {
- expect(finderFunction().find(ClipboardButton).exists()).toBe(clipboard);
- });
+ if (clipboard) {
+ it(`clipboard button exist`, async () => {
+ mountComponent();
+ await nextTick();
+
+ expect(finderFunction().find(ClipboardButton).exists()).toBe(clipboard);
+ });
+
+ it('is disabled when the component is disabled', async () => {
+ mountComponent({ ...defaultProps, disabled: true });
+ await nextTick();
+
+ expect(finderFunction().findComponent(ClipboardButton).attributes('disabled')).toBe(
+ 'true',
+ );
+ });
+ }
});
});
@@ -321,7 +356,7 @@ describe('tags list row', () => {
it('hides the details rows', async () => {
mountComponent({ tag: { ...tag, digest: null } });
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(findDetailsRows().length).toBe(0);
});
});
diff --git a/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js b/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js
index 6c897b983f7..323d7b177e7 100644
--- a/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js
+++ b/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js
@@ -25,10 +25,11 @@ describe('Image List Row', () => {
const findDetailsLink = () => wrapper.find('[data-testid="details-link"]');
const findTagsCount = () => wrapper.find('[data-testid="tags-count"]');
- const findDeleteBtn = () => wrapper.find(DeleteButton);
- const findClipboardButton = () => wrapper.find(ClipboardButton);
+ const findDeleteBtn = () => wrapper.findComponent(DeleteButton);
+ const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
const findWarningIcon = () => wrapper.find('[data-testid="warning-icon"]');
- const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader);
+ const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
+ const findListItemComponent = () => wrapper.findComponent(ListItem);
const mountComponent = (props) => {
wrapper = shallowMount(Component, {
@@ -52,20 +53,28 @@ describe('Image List Row', () => {
wrapper = null;
});
- describe('main tooltip', () => {
- it(`the title is ${ROW_SCHEDULED_FOR_DELETION}`, () => {
- mountComponent();
+ describe('list item component', () => {
+ describe('tooltip', () => {
+ it(`the title is ${ROW_SCHEDULED_FOR_DELETION}`, () => {
+ mountComponent();
+
+ const tooltip = getBinding(wrapper.element, 'gl-tooltip');
+ expect(tooltip).toBeDefined();
+ expect(tooltip.value.title).toBe(ROW_SCHEDULED_FOR_DELETION);
+ });
- const tooltip = getBinding(wrapper.element, 'gl-tooltip');
- expect(tooltip).toBeDefined();
- expect(tooltip.value.title).toBe(ROW_SCHEDULED_FOR_DELETION);
+ it('is disabled when item is being deleted', () => {
+ mountComponent({ item: { ...item, status: IMAGE_DELETE_SCHEDULED_STATUS } });
+
+ const tooltip = getBinding(wrapper.element, 'gl-tooltip');
+ expect(tooltip.value.disabled).toBe(false);
+ });
});
- it('is disabled when item is being deleted', () => {
+ it('is disabled when the item is in deleting status', () => {
mountComponent({ item: { ...item, status: IMAGE_DELETE_SCHEDULED_STATUS } });
- const tooltip = getBinding(wrapper.element, 'gl-tooltip');
- expect(tooltip.value.disabled).toBe(false);
+ expect(findListItemComponent().props('disabled')).toBe(true);
});
});
@@ -118,6 +127,20 @@ describe('Image List Row', () => {
},
);
});
+
+ describe('when the item is deleting', () => {
+ beforeEach(() => {
+ mountComponent({ item: { ...item, status: IMAGE_DELETE_SCHEDULED_STATUS } });
+ });
+
+ it('the router link is disabled', () => {
+ // we check the event prop as is the only workaround to disable a router link
+ expect(findDetailsLink().props('event')).toBe('');
+ });
+ it('the clipboard button is disabled', () => {
+ expect(findClipboardButton().attributes('disabled')).toBe('true');
+ });
+ });
});
describe('delete button', () => {
diff --git a/spec/frontend/vue_shared/components/registry/list_item_spec.js b/spec/frontend/vue_shared/components/registry/list_item_spec.js
index 33c9c808dc3..ca4bf0b0652 100644
--- a/spec/frontend/vue_shared/components/registry/list_item_spec.js
+++ b/spec/frontend/vue_shared/components/registry/list_item_spec.js
@@ -101,16 +101,16 @@ describe('list item', () => {
});
describe('disabled prop', () => {
- it('when true applies disabled-content class', () => {
+ it('when true applies gl-opacity-5 class', () => {
mountComponent({ disabled: true });
- expect(wrapper.classes('disabled-content')).toBe(true);
+ expect(wrapper.classes('gl-opacity-5')).toBe(true);
});
- it('when false does not apply disabled-content class', () => {
+ it('when false does not apply gl-opacity-5 class', () => {
mountComponent({ disabled: false });
- expect(wrapper.classes('disabled-content')).toBe(false);
+ expect(wrapper.classes('gl-opacity-5')).toBe(false);
});
});
diff --git a/spec/frontend/vue_shared/directives/validation_spec.js b/spec/frontend/vue_shared/directives/validation_spec.js
index 0c84be9354f..80c283c1a91 100644
--- a/spec/frontend/vue_shared/directives/validation_spec.js
+++ b/spec/frontend/vue_shared/directives/validation_spec.js
@@ -1,10 +1,10 @@
import { shallowMount } from '@vue/test-utils';
-import validation from '~/vue_shared/directives/validation';
+import validation, { initForm } from '~/vue_shared/directives/validation';
describe('validation directive', () => {
let wrapper;
- const createComponent = ({ inputAttributes, showValidation, template } = {}) => {
+ const createComponentFactory = ({ inputAttributes, template, data }) => {
const defaultInputAttributes = {
type: 'text',
required: true,
@@ -23,16 +23,7 @@ describe('validation directive', () => {
data() {
return {
attributes: inputAttributes || defaultInputAttributes,
- showValidation,
- form: {
- state: null,
- fields: {
- exampleField: {
- state: null,
- feedback: '',
- },
- },
- },
+ ...data,
};
},
template: template || defaultTemplate,
@@ -41,6 +32,44 @@ describe('validation directive', () => {
wrapper = shallowMount(component, { attachTo: document.body });
};
+ const createComponent = ({ inputAttributes, showValidation, template } = {}) =>
+ createComponentFactory({
+ inputAttributes,
+ data: {
+ showValidation,
+ form: {
+ state: null,
+ fields: {
+ exampleField: {
+ state: null,
+ feedback: '',
+ },
+ },
+ },
+ },
+ template,
+ });
+
+ const createComponentWithInitForm = ({ inputAttributes } = {}) =>
+ createComponentFactory({
+ inputAttributes,
+ data: {
+ form: initForm({
+ fields: {
+ exampleField: {
+ state: null,
+ value: 'lorem',
+ },
+ },
+ }),
+ },
+ template: `
+ <form>
+ <input v-validation:[form.showValidation] name="exampleField" v-bind="attributes" />
+ </form>
+ `,
+ });
+
afterEach(() => {
wrapper.destroy();
wrapper = null;
@@ -179,4 +208,86 @@ describe('validation directive', () => {
});
});
});
+
+ describe('component using initForm', () => {
+ it('sets the form fields correctly', () => {
+ createComponentWithInitForm();
+
+ expect(getFormData().state).toBe(false);
+ expect(getFormData().showValidation).toBe(false);
+
+ expect(getFormData().fields.exampleField).toMatchObject({
+ value: 'lorem',
+ state: null,
+ required: true,
+ feedback: expect.any(String),
+ });
+ });
+ });
+});
+
+describe('initForm', () => {
+ const MOCK_FORM = {
+ fields: {
+ name: {
+ value: 'lorem',
+ },
+ description: {
+ value: 'ipsum',
+ required: false,
+ skipValidation: true,
+ },
+ },
+ };
+
+ it('returns form object', () => {
+ expect(initForm(MOCK_FORM)).toMatchObject({
+ state: false,
+ showValidation: false,
+ fields: {
+ name: { value: 'lorem', required: true, state: null, feedback: null },
+ description: { value: 'ipsum', required: false, state: true, feedback: null },
+ },
+ });
+ });
+
+ it('returns form object with additional parameters', () => {
+ const customFormObject = {
+ foo: {
+ bar: 'lorem',
+ },
+ };
+
+ const form = {
+ ...MOCK_FORM,
+ ...customFormObject,
+ };
+
+ expect(initForm(form)).toMatchObject({
+ state: false,
+ showValidation: false,
+ fields: {
+ name: { value: 'lorem', required: true, state: null, feedback: null },
+ description: { value: 'ipsum', required: false, state: true, feedback: null },
+ },
+ ...customFormObject,
+ });
+ });
+
+ it('can override existing state and showValidation values', () => {
+ const form = {
+ ...MOCK_FORM,
+ state: true,
+ showValidation: true,
+ };
+
+ expect(initForm(form)).toMatchObject({
+ state: true,
+ showValidation: true,
+ fields: {
+ name: { value: 'lorem', required: true, state: null, feedback: null },
+ description: { value: 'ipsum', required: false, state: true, feedback: null },
+ },
+ });
+ });
});
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 3ef2fbba002..0f7cadbd4a7 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe GitlabSchema.types['Project'] do
it 'has the expected fields' do
expected_fields = %w[
user_permissions id full_path path name_with_namespace
- name description description_html tag_list ssh_url_to_repo
+ name description description_html tag_list topics ssh_url_to_repo
http_url_to_repo web_url star_count forks_count
created_at last_activity_at archived visibility
container_registry_enabled shared_runners_enabled
diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb
index 42626ff7c23..5c9e1e82b01 100644
--- a/spec/helpers/nav/top_nav_helper_spec.rb
+++ b/spec/helpers/nav/top_nav_helper_spec.rb
@@ -11,12 +11,17 @@ RSpec.describe Nav::TopNavHelper do
let(:current_user) { nil }
let(:current_project) { nil }
+ let(:current_group) { nil }
let(:with_current_settings_admin_mode) { false }
let(:with_header_link_admin_mode) { false }
+ let(:with_sherlock_enabled) { false }
let(:with_projects) { false }
+ let(:with_groups) { false }
let(:with_milestones) { false }
+ let(:with_snippets) { false }
+ let(:with_activity) { false }
- let(:subject) { helper.top_nav_view_model(project: current_project) }
+ let(:subject) { helper.top_nav_view_model(project: current_project, group: current_group) }
let(:active_title) { 'Menu' }
@@ -24,13 +29,17 @@ RSpec.describe Nav::TopNavHelper do
allow(helper).to receive(:current_user) { current_user }
allow(Gitlab::CurrentSettings).to receive(:admin_mode) { with_current_settings_admin_mode }
allow(helper).to receive(:header_link?).with(:admin_mode) { with_header_link_admin_mode }
+ allow(Gitlab::Sherlock).to receive(:enabled?) { with_sherlock_enabled }
# Defaulting all `dashboard_nav_link?` calls to false ensures the EE-specific behavior
# is not enabled in this CE spec
allow(helper).to receive(:dashboard_nav_link?).with(anything) { false }
allow(helper).to receive(:dashboard_nav_link?).with(:projects) { with_projects }
+ allow(helper).to receive(:dashboard_nav_link?).with(:groups) { with_groups }
allow(helper).to receive(:dashboard_nav_link?).with(:milestones) { with_milestones }
+ allow(helper).to receive(:dashboard_nav_link?).with(:snippets) { with_snippets }
+ allow(helper).to receive(:dashboard_nav_link?).with(:activity) { with_activity }
end
it 'has :activeTitle' do
@@ -39,13 +48,30 @@ RSpec.describe Nav::TopNavHelper do
context 'when current_user is nil (anonymous)' do
it 'has expected :primary' do
- expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
+ expected_projects_item = ::Gitlab::Nav::TopNavMenuItem.build(
href: '/explore',
icon: 'project',
id: 'project',
title: 'Projects'
)
- expect(subject[:primary]).to eq([expected_primary])
+ expected_groups_item = ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/explore/groups',
+ icon: 'group',
+ id: 'groups',
+ title: 'Groups'
+ )
+ expected_snippets_item = ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/explore/snippets',
+ icon: 'snippet',
+ id: 'snippets',
+ title: 'Snippets'
+ )
+ expect(subject[:primary])
+ .to eq([
+ expected_projects_item,
+ expected_groups_item,
+ expected_snippets_item
+ ])
end
end
@@ -124,7 +150,7 @@ RSpec.describe Nav::TopNavHelper do
let_it_be(:project) { build_stubbed(:project) }
let(:current_project) { project }
- let(:avatar_url) { 'avatar_url' }
+ let(:avatar_url) { 'project_avatar_url' }
before do
allow(project).to receive(:persisted?) { true }
@@ -146,6 +172,87 @@ RSpec.describe Nav::TopNavHelper do
end
end
+ context 'with groups' do
+ let(:with_groups) { true }
+ let(:groups_view) { subject[:views][:groups] }
+
+ it 'has expected :primary' do
+ expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
+ css_class: 'qa-groups-dropdown',
+ data: {
+ track_event: 'click_dropdown',
+ track_label: 'groups_dropdown'
+ },
+ icon: 'group',
+ id: 'groups',
+ title: 'Groups',
+ view: 'groups'
+ )
+ expect(subject[:primary]).to eq([expected_primary])
+ end
+
+ context 'groups' do
+ it 'has expected :currentUserName' do
+ expect(groups_view[:currentUserName]).to eq(current_user.username)
+ end
+
+ it 'has expected :namespace' do
+ expect(groups_view[:namespace]).to eq('groups')
+ end
+
+ it 'has expected :linksPrimary' do
+ expected_links_primary = [
+ ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/dashboard/groups',
+ id: 'your',
+ title: 'Your groups'
+ ),
+ ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/explore/groups',
+ id: 'explore',
+ title: 'Explore groups'
+ )
+ ]
+ expect(groups_view[:linksPrimary]).to eq(expected_links_primary)
+ end
+
+ it 'has expected :linksSecondary' do
+ expected_links_secondary = [
+ ::Gitlab::Nav::TopNavMenuItem.build(
+ href: '/groups/new#create-group-pane',
+ id: 'create',
+ title: 'Create group'
+ )
+ ]
+ expect(groups_view[:linksSecondary]).to eq(expected_links_secondary)
+ end
+
+ context 'with persisted group' do
+ let_it_be(:group) { build_stubbed(:group) }
+
+ let(:current_group) { group }
+ let(:avatar_url) { 'group_avatar_url' }
+
+ before do
+ allow(group).to receive(:persisted?) { true }
+ allow(group).to receive(:avatar_url) { avatar_url }
+ end
+
+ it 'has expected :container' do
+ expected_container = {
+ avatarUrl: avatar_url,
+ id: group.id,
+ name: group.name,
+ namespace: group.full_name,
+ webUrl: group_path(group)
+ }
+
+ expect(groups_view[:currentItem]).to eq(expected_container)
+ end
+ end
+ end
+ end
+
context 'with milestones' do
let(:with_milestones) { true }
@@ -162,6 +269,61 @@ RSpec.describe Nav::TopNavHelper do
expect(subject[:primary]).to eq([expected_primary])
end
end
+
+ context 'with snippets' do
+ let(:with_snippets) { true }
+
+ it 'has expected :primary' do
+ expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
+ data: {
+ qa_selector: 'snippets_link'
+ },
+ href: '/dashboard/snippets',
+ icon: 'snippet',
+ id: 'snippets',
+ title: 'Snippets'
+ )
+ expect(subject[:primary]).to eq([expected_primary])
+ end
+ end
+
+ context 'with activity' do
+ let(:with_activity) { true }
+
+ it 'has expected :primary' do
+ expected_primary = ::Gitlab::Nav::TopNavMenuItem.build(
+ data: {
+ qa_selector: 'activity_link'
+ },
+ href: '/dashboard/activity',
+ icon: 'history',
+ id: 'activity',
+ title: 'Activity'
+ )
+ expect(subject[:primary]).to eq([expected_primary])
+ end
+ end
+
+ context 'when sherlock is enabled' do
+ let(:with_sherlock_enabled) { true }
+
+ before do
+ # Note: We have to mock the sherlock route because the route is conditional on
+ # sherlock being enabled, but it parsed at Rails load time and can't be overridden
+ # in a spec.
+ allow(helper).to receive(:sherlock_transactions_path) { '/fake_sherlock_path' }
+ end
+
+ it 'has sherlock as last :secondary item' do
+ expected_sherlock_item = ::Gitlab::Nav::TopNavMenuItem.build(
+ id: 'sherlock',
+ title: 'Sherlock Transactions',
+ icon: 'admin',
+ href: '/fake_sherlock_path'
+ )
+ expect(subject[:secondary].last).to eq(expected_sherlock_item)
+ end
+ end
end
context 'when current_user is admin' do
diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb
index 5ec66e7f6a8..a5e4d37d306 100644
--- a/spec/lib/gitlab/highlight_spec.rb
+++ b/spec/lib/gitlab/highlight_spec.rb
@@ -46,12 +46,20 @@ RSpec.describe Gitlab::Highlight do
expect(result).to eq(%[<span id="LC1" class="line" lang="plaintext">plain text contents</span>])
end
- it 'returns plain version for long content' do
- stub_config(extra: { 'maximum_text_highlight_size_kilobytes' => 0.0001 } ) # 1.024 bytes
+ context 'when content is too long to be highlighted' do
+ let(:result) { described_class.highlight(file_name, content) } # content is 44 bytes
- result = described_class.highlight(file_name, content) # content is 44 bytes
+ before do
+ stub_config(extra: { 'maximum_text_highlight_size_kilobytes' => 0.0001 } ) # 1.024 bytes
+ end
+
+ it 'increments the metric for oversized files' do
+ expect { result }.to change { over_highlight_size_limit('text highlighter') }.by(1)
+ end
- expect(result).to eq(%[<span id="LC1" class="line" lang="">(make-pathname :defaults name</span>\n<span id="LC2" class="line" lang="">:type "assem")</span>])
+ it 'returns plain version for long content' do
+ expect(result).to eq(%[<span id="LC1" class="line" lang="">(make-pathname :defaults name</span>\n<span id="LC2" class="line" lang="">:type "assem")</span>])
+ end
end
it 'highlights multi-line comments' do
@@ -168,4 +176,11 @@ RSpec.describe Gitlab::Highlight do
.counter(:highlight_timeout, 'Counts the times highlights have timed out')
.get(source: source)
end
+
+ def over_highlight_size_limit(source)
+ Gitlab::Metrics
+ .counter(:over_highlight_size_limit,
+ 'Count the times text has been over the highlight size limit')
+ .get(source: source)
+ end
end
diff --git a/spec/models/bulk_imports/export_spec.rb b/spec/models/bulk_imports/export_spec.rb
index 26d25e6901e..d85b77d599b 100644
--- a/spec/models/bulk_imports/export_spec.rb
+++ b/spec/models/bulk_imports/export_spec.rb
@@ -47,12 +47,12 @@ RSpec.describe BulkImports::Export, type: :model do
end
end
- describe '#exportable' do
+ describe '#portable' do
context 'when associated with project' do
it 'returns project' do
export = create(:bulk_import_export, project: create(:project), group: nil)
- expect(export.exportable).to be_instance_of(Project)
+ expect(export.portable).to be_instance_of(Project)
end
end
@@ -60,7 +60,7 @@ RSpec.describe BulkImports::Export, type: :model do
it 'returns group' do
export = create(:bulk_import_export)
- expect(export.exportable).to be_instance_of(Group)
+ expect(export.portable).to be_instance_of(Group)
end
end
end
@@ -70,7 +70,7 @@ RSpec.describe BulkImports::Export, type: :model do
it 'returns project config' do
export = create(:bulk_import_export, project: create(:project), group: nil)
- expect(export.config).to be_instance_of(BulkImports::Exports::ProjectConfig)
+ expect(export.config).to be_instance_of(BulkImports::FileTransfer::ProjectConfig)
end
end
@@ -78,7 +78,7 @@ RSpec.describe BulkImports::Export, type: :model do
it 'returns group config' do
export = create(:bulk_import_export)
- expect(export.config).to be_instance_of(BulkImports::Exports::GroupConfig)
+ expect(export.config).to be_instance_of(BulkImports::FileTransfer::GroupConfig)
end
end
end
diff --git a/spec/models/bulk_imports/exports/group_config_spec.rb b/spec/models/bulk_imports/file_transfer/group_config_spec.rb
index 856977c9310..21da71de3c7 100644
--- a/spec/models/bulk_imports/exports/group_config_spec.rb
+++ b/spec/models/bulk_imports/file_transfer/group_config_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::Exports::GroupConfig do
+RSpec.describe BulkImports::FileTransfer::GroupConfig do
let_it_be(:exportable) { create(:group) }
let_it_be(:hex) { '123' }
@@ -18,7 +18,7 @@ RSpec.describe BulkImports::Exports::GroupConfig do
expect(finder).to receive(:find_root).with(:group).and_call_original
end
- expect(subject.exportable_tree).not_to be_empty
+ expect(subject.portable_tree).not_to be_empty
end
end
@@ -32,7 +32,7 @@ RSpec.describe BulkImports::Exports::GroupConfig do
describe '#exportable_relations' do
it 'returns a list of top level exportable relations' do
- expect(subject.exportable_relations).to include('milestones', 'badges', 'boards', 'labels')
+ expect(subject.portable_relations).to include('milestones', 'badges', 'boards', 'labels')
end
end
end
diff --git a/spec/models/bulk_imports/exports/project_config_spec.rb b/spec/models/bulk_imports/file_transfer/project_config_spec.rb
index c0b685a091d..021f96ac2a3 100644
--- a/spec/models/bulk_imports/exports/project_config_spec.rb
+++ b/spec/models/bulk_imports/file_transfer/project_config_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::Exports::ProjectConfig do
+RSpec.describe BulkImports::FileTransfer::ProjectConfig do
let_it_be(:exportable) { create(:project) }
let_it_be(:hex) { '123' }
@@ -18,7 +18,7 @@ RSpec.describe BulkImports::Exports::ProjectConfig do
expect(finder).to receive(:find_root).with(:project).and_call_original
end
- expect(subject.exportable_tree).not_to be_empty
+ expect(subject.portable_tree).not_to be_empty
end
end
@@ -32,7 +32,7 @@ RSpec.describe BulkImports::Exports::ProjectConfig do
describe '#exportable_relations' do
it 'returns a list of top level exportable relations' do
- expect(subject.exportable_relations).to include('issues', 'labels', 'milestones', 'merge_requests')
+ expect(subject.portable_relations).to include('issues', 'labels', 'milestones', 'merge_requests')
end
end
end
diff --git a/spec/models/bulk_imports/file_transfer_spec.rb b/spec/models/bulk_imports/file_transfer_spec.rb
new file mode 100644
index 00000000000..5a2b303626c
--- /dev/null
+++ b/spec/models/bulk_imports/file_transfer_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::FileTransfer do
+ describe '.config_for' do
+ context 'when portable is group' do
+ it 'returns group config' do
+ expect(described_class.config_for(build(:group))).to be_instance_of(BulkImports::FileTransfer::GroupConfig)
+ end
+ end
+
+ context 'when portable is project' do
+ it 'returns project config' do
+ expect(described_class.config_for(build(:project))).to be_instance_of(BulkImports::FileTransfer::ProjectConfig)
+ end
+ end
+
+ context 'when portable is unsupported' do
+ it 'raises an error' do
+ expect { described_class.config_for(nil) }.to raise_error(BulkImports::FileTransfer::UnsupportedObjectType)
+ end
+ end
+ end
+end
diff --git a/spec/presenters/packages/detail/package_presenter_spec.rb b/spec/presenters/packages/detail/package_presenter_spec.rb
index 6f4ae5a5a96..d8f1c98e762 100644
--- a/spec/presenters/packages/detail/package_presenter_spec.rb
+++ b/spec/presenters/packages/detail/package_presenter_spec.rb
@@ -50,6 +50,7 @@ RSpec.describe ::Packages::Detail::PackagePresenter do
name: package.name,
package_files: expected_package_files,
package_type: package.package_type,
+ status: package.status,
project_id: package.project_id,
tags: package.tags.as_json,
updated_at: package.updated_at,
diff --git a/spec/requests/api/graphql/project_query_spec.rb b/spec/requests/api/graphql/project_query_spec.rb
index 2cdd7273b18..b367bbaaf43 100644
--- a/spec/requests/api/graphql/project_query_spec.rb
+++ b/spec/requests/api/graphql/project_query_spec.rb
@@ -57,6 +57,22 @@ RSpec.describe 'getting project information' do
end
end
+ context 'topics' do
+ it 'includes empty topics array if no topics set' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data_at(:project, :topics)).to match([])
+ end
+
+ it 'includes topics array' do
+ project.update!(tag_list: 'topic1, topic2, topic3')
+
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data_at(:project, :topics)).to match(%w[topic1 topic2 topic3])
+ end
+ end
+
it 'includes inherited members in project_members' do
group_member = create(:group_member, group: group)
project_member = create(:project_member, project: project)
diff --git a/spec/services/bulk_imports/export_service_spec.rb b/spec/services/bulk_imports/export_service_spec.rb
index 4a31094a22a..2414f7c5ca7 100644
--- a/spec/services/bulk_imports/export_service_spec.rb
+++ b/spec/services/bulk_imports/export_service_spec.rb
@@ -10,12 +10,12 @@ RSpec.describe BulkImports::ExportService do
group.add_owner(user)
end
- subject { described_class.new(exportable: group, user: user) }
+ subject { described_class.new(portable: group, user: user) }
describe '#execute' do
it 'schedules RelationExportWorker for each top level relation' do
expect(subject).to receive(:execute).and_return(ServiceResponse.success).and_call_original
- top_level_relations = BulkImports::Export.config(group).exportable_relations
+ top_level_relations = BulkImports::FileTransfer.config_for(group).portable_relations
top_level_relations.each do |relation|
expect(BulkImports::RelationExportWorker)
@@ -28,7 +28,7 @@ RSpec.describe BulkImports::ExportService do
context 'when exception occurs' do
it 'does not schedule RelationExportWorker' do
- service = described_class.new(exportable: nil, user: user)
+ service = described_class.new(portable: nil, user: user)
expect(service)
.to receive(:execute)
diff --git a/spec/services/bulk_imports/relation_export_service_spec.rb b/spec/services/bulk_imports/relation_export_service_spec.rb
index 1116fb1f988..bf286998df2 100644
--- a/spec/services/bulk_imports/relation_export_service_spec.rb
+++ b/spec/services/bulk_imports/relation_export_service_spec.rb
@@ -77,7 +77,7 @@ RSpec.describe BulkImports::RelationExportService do
it 'tracks exception' do
expect(Gitlab::ErrorTracking)
.to receive(:track_exception)
- .with(exception_class, exportable_id: group.id, exportable_type: group.class.name)
+ .with(exception_class, portable_id: group.id, portable_type: group.class.name)
.and_call_original
subject.execute
diff --git a/spec/services/packages/rubygems/process_gem_service_spec.rb b/spec/services/packages/rubygems/process_gem_service_spec.rb
index 83e868d9579..64deb39c6d8 100644
--- a/spec/services/packages/rubygems/process_gem_service_spec.rb
+++ b/spec/services/packages/rubygems/process_gem_service_spec.rb
@@ -16,12 +16,11 @@ RSpec.describe Packages::Rubygems::ProcessGemService do
describe '#execute' do
subject { service.execute }
- context 'no gem file', :aggregate_failures do
+ context 'no gem file' do
let(:package_file) { nil }
it 'returns an error' do
- expect(subject.error?).to be(true)
- expect(subject.message).to eq('Gem was not processed')
+ expect { subject }.to raise_error(::Packages::Rubygems::ProcessGemService::ExtractionError, 'Gem was not processed - package_file is not set')
end
end
diff --git a/spec/workers/packages/nuget/extraction_worker_spec.rb b/spec/workers/packages/nuget/extraction_worker_spec.rb
index 4703afc9413..3cc2c79176b 100644
--- a/spec/workers/packages/nuget/extraction_worker_spec.rb
+++ b/spec/workers/packages/nuget/extraction_worker_spec.rb
@@ -14,14 +14,15 @@ RSpec.describe Packages::Nuget::ExtractionWorker, type: :worker do
subject { described_class.new.perform(package_file_id) }
shared_examples 'handling the metadata error' do |exception_class: ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError|
- it 'removes the package and the package file' do
+ it 'updates package status to error', :aggregate_failures do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
instance_of(exception_class),
project_id: package.project_id
)
- expect { subject }
- .to change { Packages::Package.count }.by(-1)
- .and change { Packages::PackageFile.count }.by(-1)
+
+ subject
+
+ expect(package.reload).to be_error
end
end
diff --git a/spec/workers/packages/rubygems/extraction_worker_spec.rb b/spec/workers/packages/rubygems/extraction_worker_spec.rb
index 15c0a3be90c..6f65dceacf7 100644
--- a/spec/workers/packages/rubygems/extraction_worker_spec.rb
+++ b/spec/workers/packages/rubygems/extraction_worker_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Packages::Rubygems::ExtractionWorker, type: :worker do
describe '#perform' do
- let_it_be(:package) { create(:rubygems_package) }
+ let_it_be(:package) { create(:rubygems_package, :processing) }
let(:package_file) { package.package_files.first }
let(:package_file_id) { package_file.id }
@@ -14,15 +14,13 @@ RSpec.describe Packages::Rubygems::ExtractionWorker, type: :worker do
subject { described_class.new.perform(*job_args) }
- include_examples 'an idempotent worker' do
- it 'processes the gem', :aggregate_failures do
- expect { subject }
- .to change { Packages::Package.count }.by(0)
- .and change { Packages::PackageFile.count }.by(2)
+ it 'processes the gem', :aggregate_failures do
+ expect { subject }
+ .to change { Packages::Package.count }.by(0)
+ .and change { Packages::PackageFile.count }.by(1)
- expect(Packages::Package.last.id).to be(package.id)
- expect(package.name).not_to be(package_name)
- end
+ expect(Packages::Package.last.id).to be(package.id)
+ expect(package.name).not_to be(package_name)
end
it 'handles a processing failure', :aggregate_failures do
@@ -34,9 +32,9 @@ RSpec.describe Packages::Rubygems::ExtractionWorker, type: :worker do
project_id: package.project_id
)
- expect { subject }
- .to change { Packages::Package.count }.by(-1)
- .and change { Packages::PackageFile.count }.by(-2)
+ subject
+
+ expect(package.reload).to be_error
end
context 'returns when there is no package file' do