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>2022-06-30 15:09:03 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-30 15:09:03 +0300
commitb0139a824fba85e5b71e69f2c99d423700ff76cc (patch)
tree0be37882f9bdaf64d6bc8bcd486d0e1066124513 /spec
parent312ac59328577a230a049eb71c56f648508d209f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/projects/import_export/export_relation.rb11
-rw-r--r--spec/fixtures/gitlab/import_export/labels.tar.gzbin0 -> 768 bytes
-rw-r--r--spec/frontend/clusters_list/components/agent_table_spec.js8
-rw-r--r--spec/frontend/google_cloud/components/cloudsql/create_instance_form_spec.js103
-rw-r--r--spec/frontend/google_cloud/components/cloudsql/instance_table_spec.js65
-rw-r--r--spec/frontend/google_cloud/components/databases/service_table_spec.js44
-rw-r--r--spec/frontend/security_configuration/components/app_spec.js77
-rw-r--r--spec/frontend/work_items/components/item_title_spec.js2
-rw-r--r--spec/frontend/work_items/components/work_item_weight_spec.js154
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb8
-rw-r--r--spec/models/project_export_job_spec.rb13
-rw-r--r--spec/models/projects/import_export/relation_export_spec.rb23
-rw-r--r--spec/models/projects/import_export/relation_export_upload_spec.rb25
-rw-r--r--spec/support/matchers/event_store.rb11
14 files changed, 463 insertions, 81 deletions
diff --git a/spec/factories/projects/import_export/export_relation.rb b/spec/factories/projects/import_export/export_relation.rb
new file mode 100644
index 00000000000..2b6419dcecb
--- /dev/null
+++ b/spec/factories/projects/import_export/export_relation.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :project_relation_export, class: 'Projects::ImportExport::RelationExport' do
+ project_export_job factory: :project_export_job
+
+ relation { 'labels' }
+ status { 0 }
+ sequence(:jid) { |n| "project_relation_export_#{n}" }
+ end
+end
diff --git a/spec/fixtures/gitlab/import_export/labels.tar.gz b/spec/fixtures/gitlab/import_export/labels.tar.gz
new file mode 100644
index 00000000000..8329dcf3b4a
--- /dev/null
+++ b/spec/fixtures/gitlab/import_export/labels.tar.gz
Binary files differ
diff --git a/spec/frontend/clusters_list/components/agent_table_spec.js b/spec/frontend/clusters_list/components/agent_table_spec.js
index 2a43b45a2f5..b78f0a3686c 100644
--- a/spec/frontend/clusters_list/components/agent_table_spec.js
+++ b/spec/frontend/clusters_list/components/agent_table_spec.js
@@ -70,10 +70,10 @@ describe('AgentTable', () => {
});
it.each`
- status | iconName | lineNumber
- ${'Never connected'} | ${'status-neutral'} | ${0}
- ${'Connected'} | ${'status-success'} | ${1}
- ${'Not connected'} | ${'severity-critical'} | ${2}
+ status | iconName | lineNumber
+ ${'Never connected'} | ${'status-neutral'} | ${0}
+ ${'Connected'} | ${'status-success'} | ${1}
+ ${'Not connected'} | ${'status-alert'} | ${2}
`(
'displays agent connection status as "$status" at line $lineNumber',
({ status, iconName, lineNumber }) => {
diff --git a/spec/frontend/google_cloud/components/cloudsql/create_instance_form_spec.js b/spec/frontend/google_cloud/components/cloudsql/create_instance_form_spec.js
new file mode 100644
index 00000000000..de644a33b50
--- /dev/null
+++ b/spec/frontend/google_cloud/components/cloudsql/create_instance_form_spec.js
@@ -0,0 +1,103 @@
+import { GlFormCheckbox } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import InstanceForm from '~/google_cloud/components/cloudsql/create_instance_form.vue';
+
+describe('google_cloud::cloudsql::create_instance_form component', () => {
+ let wrapper;
+
+ const findByTestId = (id) => wrapper.findByTestId(id);
+ const findCancelButton = () => findByTestId('cancel-button');
+ const findCheckbox = () => wrapper.findComponent(GlFormCheckbox);
+ const findHeader = () => wrapper.find('header');
+ const findSubmitButton = () => findByTestId('submit-button');
+
+ const propsData = {
+ gcpProjects: [],
+ refs: [],
+ cancelPath: '#cancel-url',
+ formTitle: 'mock form title',
+ formDescription: 'mock form description',
+ databaseVersions: [],
+ tiers: [],
+ };
+
+ beforeEach(() => {
+ wrapper = shallowMountExtended(InstanceForm, { propsData, stubs: { GlFormCheckbox } });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('contains header', () => {
+ expect(findHeader().exists()).toBe(true);
+ });
+
+ it('contains GCP project form group', () => {
+ const formGroup = findByTestId('form_group_gcp_project');
+ expect(formGroup.exists()).toBe(true);
+ expect(formGroup.attributes('label')).toBe(InstanceForm.i18n.gcpProjectLabel);
+ expect(formGroup.attributes('description')).toBe(InstanceForm.i18n.gcpProjectDescription);
+ });
+
+ it('contains GCP project dropdown', () => {
+ const select = findByTestId('select_gcp_project');
+ expect(select.exists()).toBe(true);
+ });
+
+ it('contains Environments form group', () => {
+ const formGroup = findByTestId('form_group_environments');
+ expect(formGroup.exists()).toBe(true);
+ expect(formGroup.attributes('label')).toBe(InstanceForm.i18n.refsLabel);
+ expect(formGroup.attributes('description')).toBe(InstanceForm.i18n.refsDescription);
+ });
+
+ it('contains Environments dropdown', () => {
+ const select = findByTestId('select_environments');
+ expect(select.exists()).toBe(true);
+ });
+
+ it('contains Tier form group', () => {
+ const formGroup = findByTestId('form_group_tier');
+ expect(formGroup.exists()).toBe(true);
+ expect(formGroup.attributes('label')).toBe(InstanceForm.i18n.tierLabel);
+ expect(formGroup.attributes('description')).toBe(InstanceForm.i18n.tierDescription);
+ });
+
+ it('contains Tier dropdown', () => {
+ const select = findByTestId('select_tier');
+ expect(select.exists()).toBe(true);
+ });
+
+ it('contains Database Version form group', () => {
+ const formGroup = findByTestId('form_group_database_version');
+ expect(formGroup.exists()).toBe(true);
+ expect(formGroup.attributes('label')).toBe(InstanceForm.i18n.databaseVersionLabel);
+ });
+
+ it('contains Database Version dropdown', () => {
+ const select = findByTestId('select_database_version');
+ expect(select.exists()).toBe(true);
+ });
+
+ it('contains Submit button', () => {
+ expect(findSubmitButton().exists()).toBe(true);
+ expect(findSubmitButton().text()).toBe(InstanceForm.i18n.submitLabel);
+ });
+
+ it('contains Cancel button', () => {
+ expect(findCancelButton().exists()).toBe(true);
+ expect(findCancelButton().text()).toBe(InstanceForm.i18n.cancelLabel);
+ expect(findCancelButton().attributes('href')).toBe('#cancel-url');
+ });
+
+ it('contains Confirmation checkbox', () => {
+ const checkbox = findCheckbox();
+ expect(checkbox.text()).toBe(InstanceForm.i18n.checkboxLabel);
+ });
+
+ it('checkbox must be required', () => {
+ const checkbox = findCheckbox();
+ expect(checkbox.attributes('required')).toBe('true');
+ });
+});
diff --git a/spec/frontend/google_cloud/components/cloudsql/instance_table_spec.js b/spec/frontend/google_cloud/components/cloudsql/instance_table_spec.js
new file mode 100644
index 00000000000..286f2b8e379
--- /dev/null
+++ b/spec/frontend/google_cloud/components/cloudsql/instance_table_spec.js
@@ -0,0 +1,65 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlEmptyState, GlTable } from '@gitlab/ui';
+import InstanceTable from '~/google_cloud/components/cloudsql/instance_table.vue';
+
+describe('google_cloud::databases::service_table component', () => {
+ let wrapper;
+
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const findTable = () => wrapper.findComponent(GlTable);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when there are no instances', () => {
+ beforeEach(() => {
+ const propsData = {
+ cloudsqlInstances: [],
+ emptyIllustrationUrl: '#empty-illustration-url',
+ };
+ wrapper = shallowMount(InstanceTable, { propsData });
+ });
+
+ it('should depict empty state', () => {
+ const emptyState = findEmptyState();
+ expect(emptyState.exists()).toBe(true);
+ expect(emptyState.attributes('title')).toBe(InstanceTable.i18n.noInstancesTitle);
+ expect(emptyState.attributes('description')).toBe(InstanceTable.i18n.noInstancesDescription);
+ });
+ });
+
+ describe('when there are three instances', () => {
+ beforeEach(() => {
+ const propsData = {
+ cloudsqlInstances: [
+ {
+ ref: '*',
+ gcp_project: 'test-gcp-project',
+ instance_name: 'postgres-14-instance',
+ version: 'POSTGRES_14',
+ },
+ {
+ ref: 'production',
+ gcp_project: 'prod-gcp-project',
+ instance_name: 'postgres-14-instance',
+ version: 'POSTGRES_14',
+ },
+ {
+ ref: 'staging',
+ gcp_project: 'test-gcp-project',
+ instance_name: 'postgres-14-instance',
+ version: 'POSTGRES_14',
+ },
+ ],
+ emptyIllustrationUrl: '#empty-illustration-url',
+ };
+ wrapper = shallowMount(InstanceTable, { propsData });
+ });
+
+ it('should contain a table', () => {
+ const table = findTable();
+ expect(table.exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/google_cloud/components/databases/service_table_spec.js b/spec/frontend/google_cloud/components/databases/service_table_spec.js
new file mode 100644
index 00000000000..142e32c1a4b
--- /dev/null
+++ b/spec/frontend/google_cloud/components/databases/service_table_spec.js
@@ -0,0 +1,44 @@
+import { GlTable } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import ServiceTable from '~/google_cloud/components/databases/service_table.vue';
+
+describe('google_cloud::databases::service_table component', () => {
+ let wrapper;
+
+ const findTable = () => wrapper.findComponent(GlTable);
+
+ beforeEach(() => {
+ const propsData = {
+ cloudsqlPostgresUrl: '#url-cloudsql-postgres',
+ cloudsqlMysqlUrl: '#url-cloudsql-mysql',
+ cloudsqlSqlserverUrl: '#url-cloudsql-sqlserver',
+ alloydbPostgresUrl: '#url-alloydb-postgres',
+ memorystoreRedisUrl: '#url-memorystore-redis',
+ firestoreUrl: '#url-firestore',
+ };
+ wrapper = mountExtended(ServiceTable, { propsData });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should contain a table', () => {
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it.each`
+ name | testId | url
+ ${'cloudsql-postgres'} | ${'button-cloudsql-postgres'} | ${'#url-cloudsql-postgres'}
+ ${'cloudsql-mysql'} | ${'button-cloudsql-mysql'} | ${'#url-cloudsql-mysql'}
+ ${'cloudsql-sqlserver'} | ${'button-cloudsql-sqlserver'} | ${'#url-cloudsql-sqlserver'}
+ ${'alloydb-postgres'} | ${'button-alloydb-postgres'} | ${'#url-alloydb-postgres'}
+ ${'memorystore-redis'} | ${'button-memorystore-redis'} | ${'#url-memorystore-redis'}
+ ${'firestore'} | ${'button-firestore'} | ${'#url-firestore'}
+ `('renders $name button with correct url', ({ testId, url }) => {
+ const button = wrapper.findByTestId(testId);
+
+ expect(button.exists()).toBe(true);
+ expect(button.attributes('href')).toBe(url);
+ });
+});
diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js
index 97b6a1e8b74..c3824ad9701 100644
--- a/spec/frontend/security_configuration/components/app_spec.js
+++ b/spec/frontend/security_configuration/components/app_spec.js
@@ -42,12 +42,36 @@ describe('App component', () => {
let wrapper;
let userCalloutDismissSpy;
- const createComponent = ({ shouldShowCallout = true, ...propsData }) => {
+ const securityFeaturesMock = [
+ {
+ name: SAST_NAME,
+ shortName: SAST_SHORT_NAME,
+ description: SAST_DESCRIPTION,
+ helpPath: SAST_HELP_PATH,
+ configurationHelpPath: SAST_CONFIG_HELP_PATH,
+ type: REPORT_TYPE_SAST,
+ available: true,
+ },
+ ];
+
+ const complianceFeaturesMock = [
+ {
+ name: LICENSE_COMPLIANCE_NAME,
+ description: LICENSE_COMPLIANCE_DESCRIPTION,
+ helpPath: LICENSE_COMPLIANCE_HELP_PATH,
+ type: REPORT_TYPE_LICENSE_COMPLIANCE,
+ configurationHelpPath: LICENSE_COMPLIANCE_HELP_PATH,
+ },
+ ];
+
+ const createComponent = ({ shouldShowCallout = true, ...propsData } = {}) => {
userCalloutDismissSpy = jest.fn();
wrapper = extendedWrapper(
mount(SecurityConfigurationApp, {
propsData: {
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
securityTrainingEnabled: true,
...propsData,
},
@@ -108,38 +132,13 @@ describe('App component', () => {
const findAutoDevopsEnabledAlert = () => wrapper.findComponent(AutoDevopsEnabledAlert);
const findVulnerabilityManagementTab = () => wrapper.findByTestId('vulnerability-management-tab');
- const securityFeaturesMock = [
- {
- name: SAST_NAME,
- shortName: SAST_SHORT_NAME,
- description: SAST_DESCRIPTION,
- helpPath: SAST_HELP_PATH,
- configurationHelpPath: SAST_CONFIG_HELP_PATH,
- type: REPORT_TYPE_SAST,
- available: true,
- },
- ];
-
- const complianceFeaturesMock = [
- {
- name: LICENSE_COMPLIANCE_NAME,
- description: LICENSE_COMPLIANCE_DESCRIPTION,
- helpPath: LICENSE_COMPLIANCE_HELP_PATH,
- type: REPORT_TYPE_LICENSE_COMPLIANCE,
- configurationHelpPath: LICENSE_COMPLIANCE_HELP_PATH,
- },
- ];
-
afterEach(() => {
wrapper.destroy();
});
describe('basic structure', () => {
- beforeEach(async () => {
- createComponent({
- augmentedSecurityFeatures: securityFeaturesMock,
- augmentedComplianceFeatures: complianceFeaturesMock,
- });
+ beforeEach(() => {
+ createComponent();
});
it('renders main-heading with correct text', () => {
@@ -199,10 +198,7 @@ describe('App component', () => {
describe('Manage via MR Error Alert', () => {
beforeEach(() => {
- createComponent({
- augmentedSecurityFeatures: securityFeaturesMock,
- augmentedComplianceFeatures: complianceFeaturesMock,
- });
+ createComponent();
});
describe('on initial load', () => {
@@ -238,8 +234,6 @@ describe('App component', () => {
describe('given the right props', () => {
beforeEach(() => {
createComponent({
- augmentedSecurityFeatures: securityFeaturesMock,
- augmentedComplianceFeatures: complianceFeaturesMock,
autoDevopsEnabled: false,
gitlabCiPresent: false,
canEnableAutoDevops: true,
@@ -261,10 +255,7 @@ describe('App component', () => {
describe('given the wrong props', () => {
beforeEach(() => {
- createComponent({
- augmentedSecurityFeatures: securityFeaturesMock,
- augmentedComplianceFeatures: complianceFeaturesMock,
- });
+ createComponent();
});
it('should not show AutoDevopsAlert', () => {
expect(findAutoDevopsAlert().exists()).toBe(false);
@@ -289,8 +280,6 @@ describe('App component', () => {
}
createComponent({
- augmentedSecurityFeatures: securityFeaturesMock,
- augmentedComplianceFeatures: complianceFeaturesMock,
autoDevopsEnabled,
});
});
@@ -348,7 +337,6 @@ describe('App component', () => {
describe('given at least one unavailable feature', () => {
beforeEach(() => {
createComponent({
- augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(false)),
});
});
@@ -369,7 +357,6 @@ describe('App component', () => {
describe('given at least one unavailable feature, but banner is already dismissed', () => {
beforeEach(() => {
createComponent({
- augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(false)),
shouldShowCallout: false,
});
@@ -397,8 +384,6 @@ describe('App component', () => {
describe('when given latestPipelinePath props', () => {
beforeEach(() => {
createComponent({
- augmentedSecurityFeatures: securityFeaturesMock,
- augmentedComplianceFeatures: complianceFeaturesMock,
latestPipelinePath: 'test/path',
});
});
@@ -425,8 +410,6 @@ describe('App component', () => {
describe('given gitlabCiPresent & gitlabCiHistoryPath props', () => {
beforeEach(() => {
createComponent({
- augmentedSecurityFeatures: securityFeaturesMock,
- augmentedComplianceFeatures: complianceFeaturesMock,
gitlabCiPresent: true,
gitlabCiHistoryPath,
});
@@ -446,8 +429,6 @@ describe('App component', () => {
beforeEach(async () => {
createComponent({
- augmentedSecurityFeatures: securityFeaturesMock,
- augmentedComplianceFeatures: complianceFeaturesMock,
...props,
});
});
diff --git a/spec/frontend/work_items/components/item_title_spec.js b/spec/frontend/work_items/components/item_title_spec.js
index 2c3f6ef8634..a55f448c9a2 100644
--- a/spec/frontend/work_items/components/item_title_spec.js
+++ b/spec/frontend/work_items/components/item_title_spec.js
@@ -1,5 +1,4 @@
import { shallowMount } from '@vue/test-utils';
-import { escape } from 'lodash';
import ItemTitle from '~/work_items/components/item_title.vue';
jest.mock('lodash/escape', () => jest.fn((fn) => fn));
@@ -51,6 +50,5 @@ describe('ItemTitle', () => {
await findInputEl().trigger(sourceEvent);
expect(wrapper.emitted(eventName)).toBeTruthy();
- expect(escape).toHaveBeenCalledWith(mockUpdatedTitle);
});
});
diff --git a/spec/frontend/work_items/components/work_item_weight_spec.js b/spec/frontend/work_items/components/work_item_weight_spec.js
index 80a1d032ad7..c3bbea26cda 100644
--- a/spec/frontend/work_items/components/work_item_weight_spec.js
+++ b/spec/frontend/work_items/components/work_item_weight_spec.js
@@ -1,21 +1,51 @@
-import { shallowMount } from '@vue/test-utils';
+import { GlForm, GlFormInput } from '@gitlab/ui';
+import { nextTick } from 'vue';
+import { mockTracking } from 'helpers/tracking_helper';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { __ } from '~/locale';
import WorkItemWeight from '~/work_items/components/work_item_weight.vue';
+import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
+import localUpdateWorkItemMutation from '~/work_items/graphql/local_update_work_item.mutation.graphql';
-describe('WorkItemAssignees component', () => {
+describe('WorkItemWeight component', () => {
let wrapper;
- const createComponent = ({ weight, hasIssueWeightsFeature = true } = {}) => {
- wrapper = shallowMount(WorkItemWeight, {
+ const mutateSpy = jest.fn();
+ const workItemId = 'gid://gitlab/WorkItem/1';
+ const workItemType = 'Task';
+
+ const findForm = () => wrapper.findComponent(GlForm);
+ const findInput = () => wrapper.findComponent(GlFormInput);
+
+ const createComponent = ({
+ canUpdate = false,
+ hasIssueWeightsFeature = true,
+ isEditing = false,
+ weight,
+ } = {}) => {
+ wrapper = mountExtended(WorkItemWeight, {
propsData: {
+ canUpdate,
weight,
+ workItemId,
+ workItemType,
},
provide: {
hasIssueWeightsFeature,
},
+ mocks: {
+ $apollo: {
+ mutate: mutateSpy,
+ },
+ },
});
+
+ if (isEditing) {
+ findInput().vm.$emit('focus');
+ }
};
- describe('weight licensed feature', () => {
+ describe('`issue_weights` licensed feature', () => {
describe.each`
description | hasIssueWeightsFeature | exists
${'when available'} | ${true} | ${true}
@@ -24,23 +54,111 @@ describe('WorkItemAssignees component', () => {
it(hasIssueWeightsFeature ? 'renders component' : 'does not render component', () => {
createComponent({ hasIssueWeightsFeature });
- expect(wrapper.find('div').exists()).toBe(exists);
+ expect(findForm().exists()).toBe(exists);
});
});
});
- describe('weight text', () => {
- describe.each`
- description | weight | text
- ${'renders 1'} | ${1} | ${'1'}
- ${'renders 0'} | ${0} | ${'0'}
- ${'renders None'} | ${null} | ${'None'}
- ${'renders None'} | ${undefined} | ${'None'}
- `('when weight is $weight', ({ description, weight, text }) => {
- it(description, () => {
- createComponent({ weight });
-
- expect(wrapper.text()).toContain(text);
+ describe('weight input', () => {
+ it('has "Weight" label', () => {
+ createComponent();
+
+ expect(wrapper.findByLabelText(__('Weight')).exists()).toBe(true);
+ });
+
+ describe('placeholder attribute', () => {
+ describe.each`
+ description | isEditing | canUpdate | value
+ ${'when not editing and cannot update'} | ${false} | ${false} | ${__('None')}
+ ${'when editing and cannot update'} | ${true} | ${false} | ${__('None')}
+ ${'when not editing and can update'} | ${false} | ${true} | ${__('None')}
+ ${'when editing and can update'} | ${true} | ${true} | ${__('Enter a number')}
+ `('$description', ({ isEditing, canUpdate, value }) => {
+ it(`has a value of "${value}"`, async () => {
+ createComponent({ canUpdate, isEditing });
+ await nextTick();
+
+ expect(findInput().attributes('placeholder')).toBe(value);
+ });
+ });
+ });
+
+ describe('readonly attribute', () => {
+ describe.each`
+ description | canUpdate | value
+ ${'when cannot update'} | ${false} | ${'readonly'}
+ ${'when can update'} | ${true} | ${undefined}
+ `('$description', ({ canUpdate, value }) => {
+ it(`renders readonly=${value}`, () => {
+ createComponent({ canUpdate });
+
+ expect(findInput().attributes('readonly')).toBe(value);
+ });
+ });
+ });
+
+ describe('type attribute', () => {
+ describe.each`
+ description | isEditing | canUpdate | type
+ ${'when not editing and cannot update'} | ${false} | ${false} | ${'text'}
+ ${'when editing and cannot update'} | ${true} | ${false} | ${'text'}
+ ${'when not editing and can update'} | ${false} | ${true} | ${'text'}
+ ${'when editing and can update'} | ${true} | ${true} | ${'number'}
+ `('$description', ({ isEditing, canUpdate, type }) => {
+ it(`has a value of "${type}"`, async () => {
+ createComponent({ canUpdate, isEditing });
+ await nextTick();
+
+ expect(findInput().attributes('type')).toBe(type);
+ });
+ });
+ });
+
+ describe('value attribute', () => {
+ describe.each`
+ weight | value
+ ${1} | ${'1'}
+ ${0} | ${'0'}
+ ${null} | ${''}
+ ${undefined} | ${''}
+ `('when `weight` prop is "$weight"', ({ weight, value }) => {
+ it(`value is "${value}"`, () => {
+ createComponent({ weight });
+
+ expect(findInput().element.value).toBe(value);
+ });
+ });
+ });
+
+ describe('when blurred', () => {
+ it('calls a mutation to update the weight', () => {
+ const weight = 0;
+ createComponent({ isEditing: true, weight });
+
+ findInput().trigger('blur');
+
+ expect(mutateSpy).toHaveBeenCalledWith({
+ mutation: localUpdateWorkItemMutation,
+ variables: {
+ input: {
+ id: workItemId,
+ weight,
+ },
+ },
+ });
+ });
+
+ it('tracks updating the weight', () => {
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ createComponent();
+
+ findInput().trigger('blur');
+
+ expect(trackingSpy).toHaveBeenCalledWith(TRACKING_CATEGORY_SHOW, 'updated_weight', {
+ category: TRACKING_CATEGORY_SHOW,
+ label: 'item_weight',
+ property: 'type_Task',
+ });
});
});
});
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 34f4bdde3b5..28557aab830 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -129,6 +129,14 @@ RSpec.describe Gitlab::Diff::File do
expect(diff_file.rendered).to be_kind_of(Gitlab::Diff::Rendered::Notebook::DiffFile)
end
+ context 'when collapsed' do
+ it 'is nil' do
+ expect(diff).to receive(:collapsed?).and_return(true)
+
+ expect(diff_file.rendered).to be_nil
+ end
+ end
+
context 'when too large' do
it 'is nil' do
expect(diff).to receive(:too_large?).and_return(true)
diff --git a/spec/models/project_export_job_spec.rb b/spec/models/project_export_job_spec.rb
index 5a2b1443f8b..653d4d2df27 100644
--- a/spec/models/project_export_job_spec.rb
+++ b/spec/models/project_export_job_spec.rb
@@ -3,17 +3,14 @@
require 'spec_helper'
RSpec.describe ProjectExportJob, type: :model do
- let(:project) { create(:project) }
- let!(:job1) { create(:project_export_job, project: project, status: 0) }
- let!(:job2) { create(:project_export_job, project: project, status: 2) }
-
describe 'associations' do
- it { expect(job1).to belong_to(:project) }
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to have_many(:relation_exports) }
end
describe 'validations' do
- it { expect(job1).to validate_presence_of(:project) }
- it { expect(job1).to validate_presence_of(:jid) }
- it { expect(job1).to validate_presence_of(:status) }
+ it { is_expected.to validate_presence_of(:project) }
+ it { is_expected.to validate_presence_of(:jid) }
+ it { is_expected.to validate_presence_of(:status) }
end
end
diff --git a/spec/models/projects/import_export/relation_export_spec.rb b/spec/models/projects/import_export/relation_export_spec.rb
new file mode 100644
index 00000000000..c74ca82e161
--- /dev/null
+++ b/spec/models/projects/import_export/relation_export_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::ImportExport::RelationExport, type: :model do
+ subject { create(:project_relation_export) }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:project_export_job) }
+ it { is_expected.to have_one(:upload) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:project_export_job) }
+ it { is_expected.to validate_presence_of(:relation) }
+ it { is_expected.to validate_uniqueness_of(:relation).scoped_to(:project_export_job_id) }
+ it { is_expected.to validate_presence_of(:status) }
+ it { is_expected.to validate_numericality_of(:status).only_integer }
+ it { is_expected.to validate_length_of(:relation).is_at_most(255) }
+ it { is_expected.to validate_length_of(:jid).is_at_most(255) }
+ it { is_expected.to validate_length_of(:export_error).is_at_most(300) }
+ end
+end
diff --git a/spec/models/projects/import_export/relation_export_upload_spec.rb b/spec/models/projects/import_export/relation_export_upload_spec.rb
new file mode 100644
index 00000000000..c0014c5a14c
--- /dev/null
+++ b/spec/models/projects/import_export/relation_export_upload_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::ImportExport::RelationExportUpload, type: :model do
+ subject { described_class.new(relation_export: project_relation_export) }
+
+ let_it_be(:project_relation_export) { create(:project_relation_export) }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:relation_export) }
+ end
+
+ it 'stores export file' do
+ stub_uploads_object_storage(ImportExportUploader, enabled: false)
+
+ filename = 'labels.tar.gz'
+ subject.export_file = fixture_file_upload("spec/fixtures/gitlab/import_export/#{filename}")
+
+ subject.save!
+
+ url = "/uploads/-/system/projects/import_export/relation_export_upload/export_file/#{subject.id}/#{filename}"
+ expect(subject.export_file.url).to eq(url)
+ end
+end
diff --git a/spec/support/matchers/event_store.rb b/spec/support/matchers/event_store.rb
index eb5b37f39e5..14f6a42d7f4 100644
--- a/spec/support/matchers/event_store.rb
+++ b/spec/support/matchers/event_store.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
RSpec::Matchers.define :publish_event do |expected_event_class|
+ include RSpec::Matchers::Composable
+
supports_block_expectations
match do |proc|
@@ -15,10 +17,17 @@ RSpec::Matchers.define :publish_event do |expected_event_class|
proc.call
@events.any? do |event|
- event.instance_of?(expected_event_class) && event.data == @expected_data
+ event.instance_of?(expected_event_class) && match_data?(event.data, @expected_data)
end
end
+ def match_data?(actual, expected)
+ values_match?(actual.keys, expected.keys) &&
+ actual.keys.each do |key|
+ values_match?(actual[key], expected[key])
+ end
+ end
+
chain :with do |expected_data|
@expected_data = expected_data
end