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-05-23 18:08:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-05-23 18:08:42 +0300
commit3e53902ee13fc4e0bf3162c0c392dcfe1a0ede4b (patch)
tree5b42426053dabe6727c69ca568d547ede95275cb /spec
parent097eb364752b8dbb08758e6b7b98a6e4030792c8 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/content_editor/remark_markdown_processing_spec.js452
-rw-r--r--spec/lib/gitlab/project_template_spec.rb13
-rw-r--r--spec/models/bulk_imports/file_transfer/project_config_spec.rb2
-rw-r--r--spec/models/project_statistics_spec.rb12
-rw-r--r--spec/services/bulk_imports/file_export_service_spec.rb58
-rw-r--r--spec/services/bulk_imports/repository_bundle_export_service_spec.rb38
-rw-r--r--spec/support/helpers/project_template_test_helper.rb16
-rw-r--r--spec/support/shared_examples/views/pagination_shared_examples.rb35
-rw-r--r--spec/views/projects/tags/index.html.haml_spec.rb43
9 files changed, 540 insertions, 129 deletions
diff --git a/spec/frontend/content_editor/remark_markdown_processing_spec.js b/spec/frontend/content_editor/remark_markdown_processing_spec.js
index 6348b97d918..eeabcf0fe4c 100644
--- a/spec/frontend/content_editor/remark_markdown_processing_spec.js
+++ b/spec/frontend/content_editor/remark_markdown_processing_spec.js
@@ -11,11 +11,12 @@ import Italic from '~/content_editor/extensions/italic';
import Link from '~/content_editor/extensions/link';
import ListItem from '~/content_editor/extensions/list_item';
import OrderedList from '~/content_editor/extensions/ordered_list';
+import Paragraph from '~/content_editor/extensions/paragraph';
import Sourcemap from '~/content_editor/extensions/sourcemap';
import remarkMarkdownDeserializer from '~/content_editor/services/remark_markdown_deserializer';
import markdownSerializer from '~/content_editor/services/markdown_serializer';
-import { createTestEditor } from './test_utils';
+import { createTestEditor, createDocBuilder } from './test_utils';
const tiptapEditor = createTestEditor({
extensions: [
@@ -36,6 +37,44 @@ const tiptapEditor = createTestEditor({
],
});
+const {
+ builders: {
+ doc,
+ paragraph,
+ bold,
+ blockquote,
+ bulletList,
+ code,
+ codeBlock,
+ hardBreak,
+ heading,
+ horizontalRule,
+ image,
+ italic,
+ link,
+ listItem,
+ orderedList,
+ },
+} = createDocBuilder({
+ tiptapEditor,
+ names: {
+ blockquote: { nodeType: Blockquote.name },
+ bold: { markType: Bold.name },
+ bulletList: { nodeType: BulletList.name },
+ code: { markType: Code.name },
+ codeBlock: { nodeType: CodeBlockHighlight.name },
+ hardBreak: { nodeType: HardBreak.name },
+ heading: { nodeType: Heading.name },
+ horizontalRule: { nodeType: HorizontalRule.name },
+ image: { nodeType: Image.name },
+ italic: { nodeType: Italic.name },
+ link: { markType: Link.name },
+ listItem: { nodeType: ListItem.name },
+ orderedList: { nodeType: OrderedList.name },
+ paragraph: { nodeType: Paragraph.name },
+ },
+});
+
describe('Client side Markdown processing', () => {
const deserialize = async (content) => {
const { document } = await remarkMarkdownDeserializer().deserialize({
@@ -52,197 +91,486 @@ describe('Client side Markdown processing', () => {
pristineDoc: document,
});
+ const sourceAttrs = (sourceMapKey, sourceMarkdown) => ({
+ sourceMapKey,
+ sourceMarkdown,
+ });
+
it.each([
{
markdown: '__bold text__',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:13', '__bold text__'),
+ bold(sourceAttrs('0:13', '__bold text__'), 'bold text'),
+ ),
+ ),
},
{
markdown: '**bold text**',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:13', '**bold text**'),
+ bold(sourceAttrs('0:13', '**bold text**'), 'bold text'),
+ ),
+ ),
},
{
markdown: '<strong>bold text</strong>',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:26', '<strong>bold text</strong>'),
+ bold(sourceAttrs('0:26', '<strong>bold text</strong>'), 'bold text'),
+ ),
+ ),
},
{
markdown: '<b>bold text</b>',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:16', '<b>bold text</b>'),
+ bold(sourceAttrs('0:16', '<b>bold text</b>'), 'bold text'),
+ ),
+ ),
},
{
markdown: '_italic text_',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:13', '_italic text_'),
+ italic(sourceAttrs('0:13', '_italic text_'), 'italic text'),
+ ),
+ ),
},
{
markdown: '*italic text*',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:13', '*italic text*'),
+ italic(sourceAttrs('0:13', '*italic text*'), 'italic text'),
+ ),
+ ),
},
{
markdown: '<em>italic text</em>',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:20', '<em>italic text</em>'),
+ italic(sourceAttrs('0:20', '<em>italic text</em>'), 'italic text'),
+ ),
+ ),
},
{
markdown: '<i>italic text</i>',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:18', '<i>italic text</i>'),
+ italic(sourceAttrs('0:18', '<i>italic text</i>'), 'italic text'),
+ ),
+ ),
},
{
markdown: '`inline code`',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:13', '`inline code`'),
+ code(sourceAttrs('0:13', '`inline code`'), 'inline code'),
+ ),
+ ),
},
{
markdown: '**`inline code bold`**',
- },
- {
- markdown: '__`inline code italics`__',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:22', '**`inline code bold`**'),
+ bold(
+ sourceAttrs('0:22', '**`inline code bold`**'),
+ code(sourceAttrs('2:20', '`inline code bold`'), 'inline code bold'),
+ ),
+ ),
+ ),
+ },
+ {
+ markdown: '_`inline code italics`_',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:23', '_`inline code italics`_'),
+ italic(
+ sourceAttrs('0:23', '_`inline code italics`_'),
+ code(sourceAttrs('1:22', '`inline code italics`'), 'inline code italics'),
+ ),
+ ),
+ ),
},
{
markdown: '[GitLab](https://gitlab.com "Go to GitLab")',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:43', '[GitLab](https://gitlab.com "Go to GitLab")'),
+ link(
+ {
+ ...sourceAttrs('0:43', '[GitLab](https://gitlab.com "Go to GitLab")'),
+ href: 'https://gitlab.com',
+ title: 'Go to GitLab',
+ },
+ 'GitLab',
+ ),
+ ),
+ ),
},
{
markdown: '**[GitLab](https://gitlab.com "Go to GitLab")**',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:47', '**[GitLab](https://gitlab.com "Go to GitLab")**'),
+ bold(
+ sourceAttrs('0:47', '**[GitLab](https://gitlab.com "Go to GitLab")**'),
+ link(
+ {
+ ...sourceAttrs('2:45', '[GitLab](https://gitlab.com "Go to GitLab")'),
+ href: 'https://gitlab.com',
+ title: 'Go to GitLab',
+ },
+ 'GitLab',
+ ),
+ ),
+ ),
+ ),
},
{
markdown: `
This is a paragraph with a\\
hard line break`,
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:43', 'This is a paragraph with a\\\nhard line break'),
+ 'This is a paragraph with a',
+ hardBreak(sourceAttrs('26:28', '\\\n')),
+ '\nhard line break',
+ ),
+ ),
},
{
markdown: '![GitLab Logo](https://gitlab.com/logo.png "GitLab Logo")',
+ expectedDoc: doc(
+ paragraph(
+ sourceAttrs('0:57', '![GitLab Logo](https://gitlab.com/logo.png "GitLab Logo")'),
+ image({
+ ...sourceAttrs('0:57', '![GitLab Logo](https://gitlab.com/logo.png "GitLab Logo")'),
+ alt: 'GitLab Logo',
+ src: 'https://gitlab.com/logo.png',
+ title: 'GitLab Logo',
+ }),
+ ),
+ ),
},
{
markdown: '---',
+ expectedDoc: doc(horizontalRule(sourceAttrs('0:3', '---'))),
},
{
markdown: '***',
+ expectedDoc: doc(horizontalRule(sourceAttrs('0:3', '***'))),
},
{
markdown: '___',
+ expectedDoc: doc(horizontalRule(sourceAttrs('0:3', '___'))),
},
{
markdown: '<hr>',
+ expectedDoc: doc(horizontalRule(sourceAttrs('0:4', '<hr>'))),
},
{
markdown: '# Heading 1',
+ expectedDoc: doc(heading({ ...sourceAttrs('0:11', '# Heading 1'), level: 1 }, 'Heading 1')),
},
{
markdown: '## Heading 2',
+ expectedDoc: doc(heading({ ...sourceAttrs('0:12', '## Heading 2'), level: 2 }, 'Heading 2')),
},
{
markdown: '### Heading 3',
+ expectedDoc: doc(heading({ ...sourceAttrs('0:13', '### Heading 3'), level: 3 }, 'Heading 3')),
},
{
markdown: '#### Heading 4',
+ expectedDoc: doc(
+ heading({ ...sourceAttrs('0:14', '#### Heading 4'), level: 4 }, 'Heading 4'),
+ ),
},
{
markdown: '##### Heading 5',
+ expectedDoc: doc(
+ heading({ ...sourceAttrs('0:15', '##### Heading 5'), level: 5 }, 'Heading 5'),
+ ),
},
{
markdown: '###### Heading 6',
+ expectedDoc: doc(
+ heading({ ...sourceAttrs('0:16', '###### Heading 6'), level: 6 }, 'Heading 6'),
+ ),
},
-
{
markdown: `
- Heading
- one
- ======
- `,
+Heading
+one
+======
+ `,
+ expectedDoc: doc(
+ heading({ ...sourceAttrs('0:18', 'Heading\none\n======'), level: 1 }, 'Heading\none'),
+ ),
},
{
markdown: `
- Heading
- two
- -------
- `,
+Heading
+two
+-------
+ `,
+ expectedDoc: doc(
+ heading({ ...sourceAttrs('0:19', 'Heading\ntwo\n-------'), level: 2 }, 'Heading\ntwo'),
+ ),
},
{
markdown: `
- - List item 1
- - List item 2
- `,
+- List item 1
+- List item 2
+ `,
+ expectedDoc: doc(
+ bulletList(
+ sourceAttrs('0:27', '- List item 1\n- List item 2'),
+ listItem(sourceAttrs('0:13', '- List item 1'), paragraph('List item 1')),
+ listItem(sourceAttrs('14:27', '- List item 2'), paragraph('List item 2')),
+ ),
+ ),
},
{
markdown: `
- * List item 1
- * List item 2
- `,
+* List item 1
+* List item 2
+ `,
+ expectedDoc: doc(
+ bulletList(
+ sourceAttrs('0:27', '* List item 1\n* List item 2'),
+ listItem(sourceAttrs('0:13', '* List item 1'), paragraph('List item 1')),
+ listItem(sourceAttrs('14:27', '* List item 2'), paragraph('List item 2')),
+ ),
+ ),
},
{
markdown: `
- + List item 1
- + List item 2
- `,
++ List item 1
++ List item 2
+ `,
+ expectedDoc: doc(
+ bulletList(
+ sourceAttrs('0:27', '+ List item 1\n+ List item 2'),
+ listItem(sourceAttrs('0:13', '+ List item 1'), paragraph('List item 1')),
+ listItem(sourceAttrs('14:27', '+ List item 2'), paragraph('List item 2')),
+ ),
+ ),
},
{
markdown: `
- 1. List item 1
- 1. List item 2
- `,
+1. List item 1
+1. List item 2
+ `,
+ expectedDoc: doc(
+ orderedList(
+ sourceAttrs('0:29', '1. List item 1\n1. List item 2'),
+ listItem(sourceAttrs('0:14', '1. List item 1'), paragraph('List item 1')),
+ listItem(sourceAttrs('15:29', '1. List item 2'), paragraph('List item 2')),
+ ),
+ ),
},
{
markdown: `
- 1. List item 1
- 2. List item 2
- `,
+1. List item 1
+2. List item 2
+ `,
+ expectedDoc: doc(
+ orderedList(
+ sourceAttrs('0:29', '1. List item 1\n2. List item 2'),
+ listItem(sourceAttrs('0:14', '1. List item 1'), paragraph('List item 1')),
+ listItem(sourceAttrs('15:29', '2. List item 2'), paragraph('List item 2')),
+ ),
+ ),
},
{
markdown: `
- 1) List item 1
- 2) List item 2
- `,
+1) List item 1
+2) List item 2
+ `,
+ expectedDoc: doc(
+ orderedList(
+ sourceAttrs('0:29', '1) List item 1\n2) List item 2'),
+ listItem(sourceAttrs('0:14', '1) List item 1'), paragraph('List item 1')),
+ listItem(sourceAttrs('15:29', '2) List item 2'), paragraph('List item 2')),
+ ),
+ ),
},
{
markdown: `
- - List item 1
- - Sub list item 1
- `,
+- List item 1
+ - Sub list item 1
+ `,
+ expectedDoc: doc(
+ bulletList(
+ sourceAttrs('0:33', '- List item 1\n - Sub list item 1'),
+ listItem(
+ sourceAttrs('0:33', '- List item 1\n - Sub list item 1'),
+ paragraph('List item 1\n'),
+ bulletList(
+ sourceAttrs('16:33', '- Sub list item 1'),
+ listItem(sourceAttrs('16:33', '- Sub list item 1'), paragraph('Sub list item 1')),
+ ),
+ ),
+ ),
+ ),
},
{
markdown: `
- - List item 1 paragraph 1
+- List item 1 paragraph 1
- List item 1 paragraph 2
- - List item 2
- `,
+ List item 1 paragraph 2
+- List item 2
+ `,
+ expectedDoc: doc(
+ bulletList(
+ sourceAttrs(
+ '0:66',
+ '- List item 1 paragraph 1\n\n List item 1 paragraph 2\n- List item 2',
+ ),
+ listItem(
+ sourceAttrs('0:52', '- List item 1 paragraph 1\n\n List item 1 paragraph 2'),
+ paragraph(sourceAttrs('2:25', 'List item 1 paragraph 1'), 'List item 1 paragraph 1'),
+ paragraph(sourceAttrs('29:52', 'List item 1 paragraph 2'), 'List item 1 paragraph 2'),
+ ),
+ listItem(
+ sourceAttrs('53:66', '- List item 2'),
+ paragraph(sourceAttrs('55:66', 'List item 2'), 'List item 2'),
+ ),
+ ),
+ ),
},
{
markdown: `
- > This is a blockquote
- `,
+> This is a blockquote
+ `,
+ expectedDoc: doc(
+ blockquote(
+ sourceAttrs('0:22', '> This is a blockquote'),
+ paragraph(sourceAttrs('2:22', 'This is a blockquote'), 'This is a blockquote'),
+ ),
+ ),
},
{
markdown: `
- > - List item 1
- > - List item 2
- `,
+> - List item 1
+> - List item 2
+ `,
+ expectedDoc: doc(
+ blockquote(
+ sourceAttrs('0:31', '> - List item 1\n> - List item 2'),
+ bulletList(
+ sourceAttrs('2:31', '- List item 1\n> - List item 2'),
+ listItem(sourceAttrs('2:15', '- List item 1'), paragraph('List item 1')),
+ listItem(sourceAttrs('18:31', '- List item 2'), paragraph('List item 2')),
+ ),
+ ),
+ ),
},
{
markdown: `
- const fn = () => 'GitLab';
- `,
+code block
+
+ const fn = () => 'GitLab';
+
+ `,
+ expectedDoc: doc(
+ paragraph(sourceAttrs('0:10', 'code block'), 'code block'),
+ codeBlock(
+ {
+ ...sourceAttrs('12:42', " const fn = () => 'GitLab';"),
+ class: 'code highlight',
+ language: null,
+ },
+ "const fn = () => 'GitLab';",
+ ),
+ ),
},
{
markdown: `
- \`\`\`javascript
- const fn = () => 'GitLab';
- \`\`\`\
- `,
+\`\`\`javascript
+const fn = () => 'GitLab';
+\`\`\`\
+ `,
+ expectedDoc: doc(
+ codeBlock(
+ {
+ ...sourceAttrs('0:44', "```javascript\nconst fn = () => 'GitLab';\n```"),
+ class: 'code highlight',
+ language: 'javascript',
+ },
+ "const fn = () => 'GitLab';",
+ ),
+ ),
},
{
markdown: `
- ~~~javascript
- const fn = () => 'GitLab';
- ~~~
- `,
+~~~javascript
+const fn = () => 'GitLab';
+~~~
+ `,
+ expectedDoc: doc(
+ codeBlock(
+ {
+ ...sourceAttrs('0:44', "~~~javascript\nconst fn = () => 'GitLab';\n~~~"),
+ class: 'code highlight',
+ language: 'javascript',
+ },
+ "const fn = () => 'GitLab';",
+ ),
+ ),
},
{
markdown: `
- \`\`\`
- \`\`\`\
- `,
+\`\`\`
+\`\`\`\
+ `,
+ expectedDoc: doc(
+ codeBlock(
+ {
+ ...sourceAttrs('0:7', '```\n```'),
+ class: 'code highlight',
+ language: null,
+ },
+ '',
+ ),
+ ),
},
{
markdown: `
- \`\`\`javascript
- const fn = () => 'GitLab';
+\`\`\`javascript
+const fn = () => 'GitLab';
- \`\`\`\
- `,
- },
- ])('processes %s correctly', async ({ markdown }) => {
+\`\`\`\
+ `,
+ expectedDoc: doc(
+ codeBlock(
+ {
+ ...sourceAttrs('0:45', "```javascript\nconst fn = () => 'GitLab';\n\n```"),
+ class: 'code highlight',
+ language: 'javascript',
+ },
+ "const fn = () => 'GitLab';\n",
+ ),
+ ),
+ },
+ ])('processes %s correctly', async ({ markdown, expectedDoc }) => {
const trimmed = markdown.trim();
const document = await deserialize(trimmed);
+ expect(document.toJSON()).toEqual(expectedDoc.toJSON());
expect(serialize(document)).toEqual(trimmed);
});
});
diff --git a/spec/lib/gitlab/project_template_spec.rb b/spec/lib/gitlab/project_template_spec.rb
index 0ef52b63bc6..630369977ff 100644
--- a/spec/lib/gitlab/project_template_spec.rb
+++ b/spec/lib/gitlab/project_template_spec.rb
@@ -3,19 +3,12 @@
require 'spec_helper'
RSpec.describe Gitlab::ProjectTemplate do
+ include ProjectTemplateTestHelper
+
describe '.all' do
it 'returns all templates' do
- expected = %w[
- rails spring express iosswift dotnetcore android
- gomicro gatsby hugo jekyll plainhtml gitbook
- hexo middleman gitpod_spring_petclinic nfhugo
- nfjekyll nfplainhtml nfgitbook nfhexo salesforcedx
- serverless_framework tencent_serverless_framework
- jsonnet cluster_management kotlin_native_linux
- ]
-
expect(described_class.all).to be_an(Array)
- expect(described_class.all.map(&:name)).to match_array(expected)
+ expect(described_class.all.map(&:name)).to match_array(all_templates)
end
end
diff --git a/spec/models/bulk_imports/file_transfer/project_config_spec.rb b/spec/models/bulk_imports/file_transfer/project_config_spec.rb
index c64707663bf..0f02c5c546f 100644
--- a/spec/models/bulk_imports/file_transfer/project_config_spec.rb
+++ b/spec/models/bulk_imports/file_transfer/project_config_spec.rb
@@ -94,7 +94,7 @@ RSpec.describe BulkImports::FileTransfer::ProjectConfig do
describe '#file_relations' do
it 'returns project file relations' do
- expect(subject.file_relations).to contain_exactly('uploads', 'lfs_objects', 'repository_bundle')
+ expect(subject.file_relations).to contain_exactly('uploads', 'lfs_objects', 'repository', 'design')
end
end
end
diff --git a/spec/models/project_statistics_spec.rb b/spec/models/project_statistics_spec.rb
index 2c29d4c42f4..83f8b7dd532 100644
--- a/spec/models/project_statistics_spec.rb
+++ b/spec/models/project_statistics_spec.rb
@@ -54,6 +54,18 @@ RSpec.describe ProjectStatistics do
end
end
+ describe 'namespace relatable columns' do
+ it 'treats the correct columns as namespace relatable' do
+ expect(described_class::NAMESPACE_RELATABLE_COLUMNS).to match_array %i[
+ repository_size
+ wiki_size
+ lfs_objects_size
+ uploads_size
+ container_registry_size
+ ]
+ end
+ end
+
describe '#total_repository_size' do
it "sums repository and LFS object size" do
statistics.repository_size = 2
diff --git a/spec/services/bulk_imports/file_export_service_spec.rb b/spec/services/bulk_imports/file_export_service_spec.rb
index 12eb6f1fc66..453fc1d0c0d 100644
--- a/spec/services/bulk_imports/file_export_service_spec.rb
+++ b/spec/services/bulk_imports/file_export_service_spec.rb
@@ -4,56 +4,34 @@ require 'spec_helper'
RSpec.describe BulkImports::FileExportService do
let_it_be(:project) { create(:project) }
- let_it_be(:export_path) { Dir.mktmpdir }
-
- let(:relation) { BulkImports::FileTransfer::BaseConfig::UPLOADS_RELATION }
-
- subject(:service) { described_class.new(project, export_path, relation) }
describe '#execute' do
- it 'executes export service and archives exported data' do
- expect_next_instance_of(BulkImports::UploadsExportService) do |service|
- expect(service).to receive(:execute)
- end
-
- expect(subject).to receive(:tar_cf).with(archive: File.join(export_path, 'uploads.tar'), dir: export_path)
-
- subject.execute
- end
-
- context 'when relation is lfs objects' do
- let(:relation) { BulkImports::FileTransfer::ProjectConfig::LFS_OBJECTS_RELATION }
+ it 'executes export service and archives exported data for each file relation' do
+ relations = {
+ 'uploads' => BulkImports::UploadsExportService,
+ 'lfs_objects' => BulkImports::LfsObjectsExportService,
+ 'repository' => BulkImports::RepositoryBundleExportService,
+ 'design' => BulkImports::RepositoryBundleExportService
+ }
- it 'executes lfs objects export service' do
- expect_next_instance_of(BulkImports::LfsObjectsExportService) do |service|
- expect(service).to receive(:execute)
- end
-
- expect(subject).to receive(:tar_cf).with(archive: File.join(export_path, 'lfs_objects.tar'), dir: export_path)
+ relations.each do |relation, klass|
+ Dir.mktmpdir do |export_path|
+ service = described_class.new(project, export_path, relation)
- subject.execute
- end
- end
+ expect_next_instance_of(klass) do |service|
+ expect(service).to receive(:execute)
+ end
- context 'when relation is repository bundle' do
- let(:relation) { BulkImports::FileTransfer::ProjectConfig::REPOSITORY_BUNDLE_RELATION }
+ expect(service).to receive(:tar_cf).with(archive: File.join(export_path, "#{relation}.tar"), dir: export_path)
- it 'executes repository bundle export service' do
- expect_next_instance_of(BulkImports::RepositoryBundleExportService) do |service|
- expect(service).to receive(:execute)
+ service.execute
end
-
- expect(subject)
- .to receive(:tar_cf)
- .with(archive: File.join(export_path, 'repository_bundle.tar'), dir: export_path)
-
- subject.execute
end
end
context 'when unsupported relation is passed' do
it 'raises an error' do
- service = described_class.new(project, export_path, 'unsupported')
+ service = described_class.new(project, nil, 'unsupported')
expect { service.execute }.to raise_error(BulkImports::Error, 'Unsupported relation export type')
end
@@ -62,7 +40,9 @@ RSpec.describe BulkImports::FileExportService do
describe '#exported_filename' do
it 'returns filename of the exported file' do
- expect(subject.exported_filename).to eq('uploads.tar')
+ service = described_class.new(project, nil, 'uploads')
+
+ expect(service.exported_filename).to eq('uploads.tar')
end
end
end
diff --git a/spec/services/bulk_imports/repository_bundle_export_service_spec.rb b/spec/services/bulk_imports/repository_bundle_export_service_spec.rb
index 66e6145ae98..a7d98a7474a 100644
--- a/spec/services/bulk_imports/repository_bundle_export_service_spec.rb
+++ b/spec/services/bulk_imports/repository_bundle_export_service_spec.rb
@@ -3,32 +3,44 @@
require 'spec_helper'
RSpec.describe BulkImports::RepositoryBundleExportService do
- let(:project) { build(:project) }
+ let(:project) { create(:project) }
let(:export_path) { Dir.mktmpdir }
- subject(:service) { described_class.new(project, export_path) }
+ subject(:service) { described_class.new(repository, export_path, export_filename) }
after do
FileUtils.remove_entry(export_path) if Dir.exist?(export_path)
end
describe '#execute' do
- context 'when repository exists' do
- it 'bundles repository to disk' do
- allow(project.repository).to receive(:exists?).and_return(true)
- expect(project.repository).to receive(:bundle_to_disk).with(File.join(export_path, 'project.bundle'))
+ shared_examples 'repository export' do
+ context 'when repository exists' do
+ it 'bundles repository to disk' do
+ allow(repository).to receive(:exists?).and_return(true)
+ expect(repository).to receive(:bundle_to_disk).with(File.join(export_path, "#{export_filename}.bundle"))
+
+ service.execute
+ end
+ end
+
+ context 'when repository does not exist' do
+ it 'does not bundle repository to disk' do
+ allow(repository).to receive(:exists?).and_return(false)
+ expect(repository).not_to receive(:bundle_to_disk)
- service.execute
+ service.execute
+ end
end
end
- context 'when repository does not exist' do
- it 'does not bundle repository to disk' do
- allow(project.repository).to receive(:exists?).and_return(false)
- expect(project.repository).not_to receive(:bundle_to_disk)
+ include_examples 'repository export' do
+ let(:repository) { project.repository }
+ let(:export_filename) { 'repository' }
+ end
- service.execute
- end
+ include_examples 'repository export' do
+ let(:repository) { project.design_repository }
+ let(:export_filename) { 'design' }
end
end
end
diff --git a/spec/support/helpers/project_template_test_helper.rb b/spec/support/helpers/project_template_test_helper.rb
new file mode 100644
index 00000000000..fc699fe9943
--- /dev/null
+++ b/spec/support/helpers/project_template_test_helper.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module ProjectTemplateTestHelper
+ def all_templates
+ %w[
+ rails spring express iosswift dotnetcore android
+ gomicro gatsby hugo jekyll plainhtml gitbook
+ hexo middleman gitpod_spring_petclinic nfhugo
+ nfjekyll nfplainhtml nfgitbook nfhexo salesforcedx
+ serverless_framework tencent_serverless_framework
+ jsonnet cluster_management kotlin_native_linux
+ ]
+ end
+end
+
+ProjectTemplateTestHelper.prepend_mod
diff --git a/spec/support/shared_examples/views/pagination_shared_examples.rb b/spec/support/shared_examples/views/pagination_shared_examples.rb
new file mode 100644
index 00000000000..3932f320859
--- /dev/null
+++ b/spec/support/shared_examples/views/pagination_shared_examples.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'correct pagination' do
+ it 'paginates correctly to page 3 and back' do
+ expect(page).to have_selector(item_selector, count: per_page)
+ page1_item_text = page.find(item_selector).text
+ click_next_page(next_button_selector)
+
+ expect(page).to have_selector(item_selector, count: per_page)
+ page2_item_text = page.find(item_selector).text
+ click_next_page(next_button_selector)
+
+ expect(page).to have_selector(item_selector, count: per_page)
+ page3_item_text = page.find(item_selector).text
+ click_prev_page(prev_button_selector)
+
+ expect(page3_item_text).not_to eql(page2_item_text)
+ expect(page.find(item_selector).text).to eql(page2_item_text)
+
+ click_prev_page(prev_button_selector)
+
+ expect(page.find(item_selector).text).to eql(page1_item_text)
+ expect(page).to have_selector(item_selector, count: per_page)
+ end
+
+ def click_next_page(next_button_selector)
+ page.find(next_button_selector).click
+ wait_for_requests
+ end
+
+ def click_prev_page(prev_button_selector)
+ page.find(prev_button_selector).click
+ wait_for_requests
+ end
+end
diff --git a/spec/views/projects/tags/index.html.haml_spec.rb b/spec/views/projects/tags/index.html.haml_spec.rb
index ae59c1aa4b2..3169199b56a 100644
--- a/spec/views/projects/tags/index.html.haml_spec.rb
+++ b/spec/views/projects/tags/index.html.haml_spec.rb
@@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe 'projects/tags/index.html.haml' do
let_it_be(:project) { create(:project, :repository) }
- let_it_be(:tags) { project.repository.tags }
let_it_be(:git_tag) { project.repository.tags.last }
let_it_be(:release) do
create(:release, project: project,
@@ -25,9 +24,41 @@ RSpec.describe 'projects/tags/index.html.haml' do
allow(view).to receive(:current_user).and_return(project.namespace.owner)
end
- it 'renders links to the Releases page for tags associated with a release' do
- render
- expect(rendered).to have_link(release.name, href: project_releases_path(project, anchor: release.tag))
+ context 'when tag is associated with a release' do
+ context 'with feature flag disabled' do
+ before do
+ stub_feature_flags(fix_release_path_in_tag_index_page: false)
+ end
+
+ it 'renders a link to the release page with anchor' do
+ render
+ expect(rendered).to have_link(release.name, href: project_releases_path(project, anchor: release))
+ end
+ end
+
+ context 'with feature flag enabled' do
+ before do
+ stub_feature_flags(fix_release_path_in_tag_index_page: true)
+ end
+
+ context 'when name contains backslash' do
+ let_it_be(:release) { create(:release, project: project, tag: 'test/v1') }
+
+ before_all do
+ project.repository.add_tag(project.owner, 'test/v1', project.default_branch_or_main)
+ project.repository.expire_tags_cache
+
+ project.releases.reload
+
+ assign(:tags, Kaminari.paginate_array(tags).page(0))
+ end
+
+ it 'renders a link to the release page with backslash escaped' do
+ render
+ expect(rendered).to have_link(release.name, href: project_release_path(project, release))
+ end
+ end
+ end
end
context 'when the most recent build for a tag has artifacts' do
@@ -104,4 +135,8 @@ RSpec.describe 'projects/tags/index.html.haml' do
)
end
end
+
+ def tags
+ project.repository.tags
+ end
end