2020-04-22 19:07:51 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
RSpec.describe Issues::ExportCsvService, :with_license, feature_category: :team_planning do
|
2020-04-22 19:07:51 +05:30
|
|
|
let_it_be(:user) { create(:user) }
|
2021-03-11 19:13:27 +05:30
|
|
|
let_it_be(:group) { create(:group) }
|
|
|
|
let_it_be(:project) { create(:project, :public, group: group) }
|
|
|
|
let_it_be(:issue) { create(:issue, project: project, author: user) }
|
|
|
|
let_it_be(:bad_issue) { create(:issue, project: project, author: user) }
|
2021-04-29 21:17:54 +05:30
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
subject { described_class.new(Issue.all, project) }
|
2020-04-22 19:07:51 +05:30
|
|
|
|
|
|
|
it 'renders csv to string' do
|
|
|
|
expect(subject.csv_data).to be_a String
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#email' do
|
|
|
|
it 'emails csv' do
|
|
|
|
expect { subject.email(user) }.to change(ActionMailer::Base.deliveries, :count)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'renders with a target filesize' do
|
2021-03-08 18:12:59 +05:30
|
|
|
expect_next_instance_of(CsvBuilder) do |csv_builder|
|
|
|
|
expect(csv_builder).to receive(:render).with(described_class::TARGET_FILESIZE).once
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
|
|
|
subject.email(user)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def csv
|
|
|
|
CSV.parse(subject.csv_data, headers: true)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'includes' do
|
2021-03-11 19:13:27 +05:30
|
|
|
let_it_be(:milestone) { create(:milestone, title: 'v1.0', project: project) }
|
|
|
|
let_it_be(:idea_label) { create(:label, project: project, title: 'Idea') }
|
|
|
|
let_it_be(:feature_label) { create(:label, project: project, title: 'Feature') }
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2021-03-11 19:13:27 +05:30
|
|
|
before_all do
|
2020-04-22 19:07:51 +05:30
|
|
|
# Creating a timelog touches the updated_at timestamp of issue,
|
|
|
|
# so create these first.
|
2020-11-24 15:15:51 +05:30
|
|
|
issue.timelogs.create!(time_spent: 360, user: user)
|
|
|
|
issue.timelogs.create!(time_spent: 200, user: user)
|
2020-04-22 19:07:51 +05:30
|
|
|
issue.update!(milestone: milestone,
|
|
|
|
assignees: [user],
|
|
|
|
description: 'Issue with details',
|
|
|
|
state: :opened,
|
|
|
|
due_date: DateTime.new(2014, 3, 2),
|
|
|
|
created_at: DateTime.new(2015, 4, 3, 2, 1, 0),
|
|
|
|
updated_at: DateTime.new(2016, 5, 4, 3, 2, 1),
|
|
|
|
closed_at: DateTime.new(2017, 6, 5, 4, 3, 2),
|
|
|
|
weight: 4,
|
|
|
|
discussion_locked: true,
|
|
|
|
labels: [feature_label, idea_label],
|
|
|
|
time_estimate: 72000)
|
|
|
|
end
|
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
shared_examples 'exports CSVs for issues' do
|
|
|
|
it 'includes the columns required for import' do
|
|
|
|
expect(csv.headers).to include('Title', 'Description')
|
|
|
|
end
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
it 'returns two issues' do
|
|
|
|
expect(csv.count).to eq(2)
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'iid' do
|
|
|
|
expect(csv[0]['Issue ID']).to eq issue.iid.to_s
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'url' do
|
|
|
|
expect(csv[0]['URL']).to match(/http.*#{project.full_path}.*#{issue.iid}/)
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'title' do
|
|
|
|
expect(csv[0]['Title']).to eq issue.title
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'state' do
|
|
|
|
expect(csv[0]['State']).to eq 'Open'
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'description' do
|
|
|
|
expect(csv[0]['Description']).to eq issue.description
|
|
|
|
expect(csv[1]['Description']).to eq nil
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'author name' do
|
|
|
|
expect(csv[0]['Author']).to eq issue.author_name
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'author username' do
|
|
|
|
expect(csv[0]['Author Username']).to eq issue.author.username
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'assignee name' do
|
|
|
|
expect(csv[0]['Assignee']).to eq user.name
|
|
|
|
expect(csv[1]['Assignee']).to eq ''
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'assignee username' do
|
|
|
|
expect(csv[0]['Assignee Username']).to eq user.username
|
|
|
|
expect(csv[1]['Assignee Username']).to eq ''
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'confidential' do
|
|
|
|
expect(csv[0]['Confidential']).to eq 'No'
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'milestone' do
|
|
|
|
expect(csv[0]['Milestone']).to eq issue.milestone.title
|
|
|
|
expect(csv[1]['Milestone']).to eq nil
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'labels' do
|
|
|
|
expect(csv[0]['Labels']).to eq 'Feature,Idea'
|
|
|
|
expect(csv[1]['Labels']).to eq nil
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'due_date' do
|
|
|
|
expect(csv[0]['Due Date']).to eq '2014-03-02'
|
|
|
|
expect(csv[1]['Due Date']).to eq nil
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'created_at' do
|
|
|
|
expect(csv[0]['Created At (UTC)']).to eq '2015-04-03 02:01:00'
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'updated_at' do
|
|
|
|
expect(csv[0]['Updated At (UTC)']).to eq '2016-05-04 03:02:01'
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'closed_at' do
|
|
|
|
expect(csv[0]['Closed At (UTC)']).to eq '2017-06-05 04:03:02'
|
|
|
|
expect(csv[1]['Closed At (UTC)']).to eq nil
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'discussion_locked' do
|
|
|
|
expect(csv[0]['Locked']).to eq 'Yes'
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'weight' do
|
|
|
|
expect(csv[0]['Weight']).to eq '4'
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'time estimate' do
|
|
|
|
expect(csv[0]['Time Estimate']).to eq '72000'
|
|
|
|
expect(csv[1]['Time Estimate']).to eq '0'
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
specify 'time spent' do
|
|
|
|
expect(csv[0]['Time Spent']).to eq '560'
|
|
|
|
expect(csv[1]['Time Spent']).to eq '0'
|
2020-04-22 19:07:51 +05:30
|
|
|
end
|
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
context 'with issues filtered by labels and project' do
|
|
|
|
subject do
|
|
|
|
described_class.new(
|
|
|
|
IssuesFinder.new(user,
|
|
|
|
project_id: project.id,
|
|
|
|
label_name: %w(Idea Feature)).execute, project)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns only filtered objects' do
|
|
|
|
expect(csv.count).to eq(1)
|
|
|
|
expect(csv[0]['Issue ID']).to eq issue.iid.to_s
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
end
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
context 'with label links' do
|
|
|
|
let(:labeled_issues) { create_list(:labeled_issue, 2, project: project, author: user, labels: [feature_label, idea_label]) }
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
it 'does not run a query for each label link' do
|
|
|
|
control_count = ActiveRecord::QueryRecorder.new { csv }.count
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
labeled_issues
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
expect { csv }.not_to exceed_query_limit(control_count)
|
|
|
|
expect(csv.count).to eq(4)
|
|
|
|
end
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
it 'returns the labels in sorted order' do
|
|
|
|
labeled_issues
|
2021-03-11 19:13:27 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
labeled_rows = csv.select { |entry| labeled_issues.map(&:iid).include?(entry['Issue ID'].to_i) }
|
|
|
|
expect(labeled_rows.count).to eq(2)
|
|
|
|
expect(labeled_rows.map { |entry| entry['Labels'] }).to all(eq("Feature,Idea"))
|
|
|
|
end
|
2021-03-11 19:13:27 +05:30
|
|
|
end
|
|
|
|
end
|
2023-04-23 21:23:45 +05:30
|
|
|
|
|
|
|
context 'with export_csv_preload_in_batches feature flag disabled' do
|
|
|
|
before do
|
|
|
|
stub_feature_flags(export_csv_preload_in_batches: false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it_behaves_like 'exports CSVs for issues'
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with export_csv_preload_in_batches feature flag enabled' do
|
|
|
|
it_behaves_like 'exports CSVs for issues'
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'with minimal details' do
|
|
|
|
it 'renders labels as nil' do
|
|
|
|
expect(csv[0]['Labels']).to eq nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|