Commit b33510a2 authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch '220797-remove-snippets-edit-vue-feature-flag' into 'master'

Remove snippets_edit_vue feature flag

See merge request gitlab-org/gitlab!43868
parents c5e00ece e0532966
import { initEditorLite } from '~/blob/utils';
import setupCollapsibleInputs from './collapsible_input';
let editor;
const initMonaco = () => {
const editorEl = document.getElementById('editor');
const contentEl = document.querySelector('.snippet-file-content');
const fileNameEl = document.querySelector('.js-snippet-file-name');
const form = document.querySelector('.snippet-form-holder form');
editor = initEditorLite({
el: editorEl,
blobPath: fileNameEl.value,
blobContent: contentEl.value,
});
fileNameEl.addEventListener('change', () => {
editor.updateModelLanguage(fileNameEl.value);
});
form.addEventListener('submit', () => {
contentEl.value = editor.getValue();
});
};
export default () => {
initMonaco();
setupCollapsibleInputs();
};
import $ from 'jquery';
import initSnippet from '~/snippet/snippet_bundle';
import ZenMode from '~/zen_mode';
import GLForm from '~/gl_form';
import { SnippetEditInit } from '~/snippets';
document.addEventListener('DOMContentLoaded', () => {
const form = document.querySelector('.snippet-form');
const personalSnippetOptions = {
members: false,
issues: false,
mergeRequests: false,
epics: false,
milestones: false,
labels: false,
snippets: false,
vulnerabilities: false,
};
const projectSnippetOptions = {};
const options =
form.dataset.snippetType === 'project' || form.dataset.projectPath
? projectSnippetOptions
: personalSnippetOptions;
if (gon?.features?.snippetsEditVue) {
SnippetEditInit();
} else {
initSnippet();
new GLForm($(form), options); // eslint-disable-line no-new
}
SnippetEditInit();
new ZenMode(); // eslint-disable-line no-new
});
......@@ -112,12 +112,6 @@ export default {
}
return this.snippet.webUrl;
},
titleFieldId() {
return `${this.isProjectSnippet ? 'project' : 'personal'}_snippet_title`;
},
descriptionFieldId() {
return `${this.isProjectSnippet ? 'project' : 'personal'}_snippet_description`;
},
newSnippetSchema() {
return {
title: '',
......@@ -228,14 +222,13 @@ export default {
/>
<template v-else>
<title-field
:id="titleFieldId"
id="snippet-title"
v-model="snippet.title"
data-qa-selector="snippet_title_field"
required
:autofocus="true"
/>
<snippet-description-edit
:id="descriptionFieldId"
v-model="snippet.description"
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
......
......@@ -18,10 +18,6 @@
}
}
.snippet-form-holder .file-holder .file-title {
padding: 2px;
}
.markdown-snippet-copy {
position: fixed;
top: -10px;
......
- if Feature.enabled?(:snippets_edit_vue, default_enabled: true)
- available_visibility_levels = available_visibility_levels(@snippet)
#js-snippet-edit.snippet-form{ data: {'project_path': @snippet.project&.full_path, 'snippet-gid': @snippet.new_record? ? '' : @snippet.to_global_id, 'markdown-preview-path': preview_markdown_path(parent), 'markdown-docs-path': help_page_path('user/markdown'), 'visibility-help-link': help_page_path("public_access/public_access"), 'visibility_levels': available_visibility_levels, 'selected_level': snippets_selected_visibility_level(available_visibility_levels, @snippet.visibility_level), 'multiple_levels_restricted': multiple_visibility_levels_restricted? } }
- else
.snippet-form-holder
= form_for @snippet, url: url,
html: { class: "snippet-form js-requires-input js-quick-submit common-note-form" },
data: { "snippet-type": @snippet.project_id ? 'project' : 'personal'} do |f|
= form_errors(@snippet)
.form-group
= f.label :title, class: 'label-bold'
= f.text_field :title, class: 'form-control', required: true, autofocus: true
.form-group.js-description-input
- description_placeholder = s_('Snippets|Optionally add a description about what your snippet does or how to use it...')
- is_expanded = @snippet.description && !@snippet.description.empty?
= f.label :description, s_("Snippets|Description (optional)"), class: 'label-bold'
.js-collapsible-input
.js-collapsed{ class: ('d-none' if is_expanded) }
= text_field_tag nil, nil, class: 'form-control', placeholder: description_placeholder
.js-expanded{ class: ('d-none' if !is_expanded) }
= render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
= render 'shared/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: description_placeholder
= render 'shared/notes/hints'
.form-group.file-editor
= f.label :file_name, s_('Snippets|File')
.file-holder.snippet
.js-file-title.file-title-flex-parent
= f.text_field :file_name, placeholder: s_("Snippets|Give your file a name to add code highlighting, e.g. example.rb for Ruby"), class: 'form-control js-snippet-file-name'
.file-content.code
#editor{ data: { 'editor-loading': true } }<
%pre.editor-loading-content= @snippet.content
= f.hidden_field :content, class: 'snippet-file-content'
.form-group
.font-weight-bold
= _('Visibility level')
= link_to sprite_icon('question-o'), help_page_path('public_access/public_access'), target: '_blank'
= render 'shared/visibility_level', f: f, visibility_level: @snippet.visibility_level, can_change_visibility_level: true, form_model: @snippet, with_label: false
- if params[:files]
- params[:files].each_with_index do |file, index|
= hidden_field_tag "files[]", file, id: "files_#{index}"
.form-actions
- if @snippet.new_record?
= f.submit 'Create snippet', class: "btn-success btn gl-button"
- else
= f.submit 'Save changes', class: "btn-success btn gl-button"
- if @snippet.project_id
= link_to "Cancel", project_snippets_path(@project), class: "btn gl-button btn-default"
- else
= link_to "Cancel", snippets_path(@project), class: "btn gl-button btn-default"
- available_visibility_levels = available_visibility_levels(@snippet)
#js-snippet-edit.snippet-form{ data: {'project_path': @snippet.project&.full_path, 'snippet-gid': @snippet.new_record? ? '' : @snippet.to_global_id, 'markdown-preview-path': preview_markdown_path(parent), 'markdown-docs-path': help_page_path('user/markdown'), 'visibility-help-link': help_page_path("public_access/public_access"), 'visibility_levels': available_visibility_levels, 'selected_level': snippets_selected_visibility_level(available_visibility_levels, @snippet.visibility_level), 'multiple_levels_restricted': multiple_visibility_levels_restricted? } }
---
name: snippets_edit_vue
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25667
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/207239
group: group::editor
type: development
default_enabled: true
......@@ -46,7 +46,6 @@ module Gitlab
push_frontend_feature_flag(:snippets_vue, default_enabled: true)
push_frontend_feature_flag(:monaco_blobs, default_enabled: true)
push_frontend_feature_flag(:monaco_ci, default_enabled: true)
push_frontend_feature_flag(:snippets_edit_vue, default_enabled: true)
push_frontend_feature_flag(:webperf_experiment, default_enabled: false)
push_frontend_feature_flag(:snippets_binary_blob, default_enabled: false)
push_frontend_feature_flag(:usage_data_api, default_enabled: false)
......
......@@ -23976,18 +23976,12 @@ msgstr ""
msgid "Snippets|Description (optional)"
msgstr ""
msgid "Snippets|File"
msgstr ""
msgid "Snippets|Files"
msgstr ""
msgid "Snippets|Give your file a name to add code highlighting, e.g. example.rb for Ruby"
msgstr ""
msgid "Snippets|Optionally add a description about what your snippet does or how to use it..."
msgstr ""
msgid "Snippets|Optionally add a description about what your snippet does or how to use it…"
msgstr ""
......
......@@ -17,115 +17,81 @@ RSpec.describe 'Projects > Snippets > Create Snippet', :js do
let(:file_content) { 'Hello World!' }
let(:md_description) { 'My Snippet **Description**' }
let(:description) { 'My Snippet Description' }
let(:snippet_title_field) { 'project_snippet_title' }
shared_examples 'snippet creation' do
def fill_form
snippet_fill_in_form(title: title, content: file_content, description: md_description)
end
it 'shows collapsible description input' do
collapsed = description_field
def fill_form
snippet_fill_in_form(title: title, content: file_content, description: md_description)
end
expect(page).not_to have_field(snippet_description_field)
expect(collapsed).to be_visible
before do
sign_in(user)
collapsed.click
visit new_project_snippet_path(project)
end
expect(page).to have_field(snippet_description_field)
expect(collapsed).not_to be_visible
end
it 'shows collapsible description input' do
collapsed = snippet_description_field_collapsed
it 'creates a new snippet' do
fill_form
click_button('Create snippet')
wait_for_requests
expect(page).not_to have_field(snippet_description_locator)
expect(collapsed).to be_visible
expect(page).to have_content(title)
expect(page).to have_content(file_content)
page.within(snippet_description_view_selector) do
expect(page).to have_content(description)
expect(page).to have_selector('strong')
end
end
collapsed.click
it 'uploads a file when dragging into textarea' do
fill_form
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
expect(snippet_description_value).to have_content('banana_sample')
expect(page).to have_field(snippet_description_locator)
expect(collapsed).not_to be_visible
end
click_button('Create snippet')
wait_for_requests
it 'creates a new snippet' do
fill_form
click_button('Create snippet')
wait_for_requests
link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z})
expect(page).to have_content(title)
expect(page).to have_content(file_content)
page.within('.snippet-header .snippet-description') do
expect(page).to have_content(description)
expect(page).to have_selector('strong')
end
end
context 'when the git operation fails' do
let(:error) { 'Error creating the snippet' }
before do
allow_next_instance_of(Snippets::CreateService) do |instance|
allow(instance).to receive(:create_commit).and_raise(StandardError, error)
end
it 'uploads a file when dragging into textarea' do
fill_form
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
fill_form
expect(snippet_description_value).to have_content('banana_sample')
click_button('Create snippet')
wait_for_requests
end
click_button('Create snippet')
wait_for_requests
it 'renders the new page and displays the error' do
expect(page).to have_content(error)
expect(page).to have_content('New Snippet')
end
end
link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z})
end
context 'Vue application' do
let(:snippet_description_field) { 'snippet-description' }
let(:snippet_description_view_selector) { '.snippet-header .snippet-description' }
context 'when the git operation fails' do
let(:error) { 'Error creating the snippet' }
before do
sign_in(user)
visit new_project_snippet_path(project)
end
it_behaves_like 'snippet creation'
it 'does not allow submitting the form without title and content' do
fill_in snippet_title_field, with: title
allow_next_instance_of(Snippets::CreateService) do |instance|
allow(instance).to receive(:create_commit).and_raise(StandardError, error)
end
expect(page).not_to have_button('Create snippet')
fill_form
snippet_fill_in_form(title: title, content: file_content)
expect(page).to have_button('Create snippet')
click_button('Create snippet')
wait_for_requests
end
end
context 'non-Vue application' do
let(:snippet_description_field) { 'project_snippet_description' }
let(:snippet_description_view_selector) { '.snippet-header .description' }
before do
stub_feature_flags(snippets_vue: false)
stub_feature_flags(snippets_edit_vue: false)
sign_in(user)
visit new_project_snippet_path(project)
it 'renders the new page and displays the error' do
expect(page).to have_content(error)
expect(page).to have_content('New Snippet')
end
end
it_behaves_like 'snippet creation'
it 'does not allow submitting the form without title and content' do
snippet_fill_in_title(title)
it 'displays validation errors' do
fill_in snippet_title_field, with: title
click_button('Create snippet')
wait_for_requests
expect(page).not_to have_button('Create snippet')
expect(page).to have_selector('#error_explanation')
end
snippet_fill_in_form(title: title, content: file_content)
expect(page).to have_button('Create snippet')
end
end
......@@ -9,9 +9,7 @@ RSpec.describe 'Projects > Snippets > User updates a snippet', :js do
let_it_be(:project) { create(:project, namespace: user.namespace) }
let_it_be(:snippet, reload: true) { create(:project_snippet, :repository, project: project, author: user) }
let(:snippet_title_field) { 'project_snippet_title' }
def bootstrap_snippet
before do
project.add_maintainer(user)
sign_in(user)
......@@ -20,64 +18,36 @@ RSpec.describe 'Projects > Snippets > User updates a snippet', :js do
wait_for_all_requests
end
shared_examples 'snippet update' do
it 'displays the snippet blob path and content' do
blob = snippet.blobs.first
aggregate_failures do
expect(snippet_get_first_blob_path).to eq blob.path
expect(snippet_get_first_blob_value).to have_content(blob.data.strip)
end
end
it 'updates a snippet' do
fill_in('project_snippet_title', with: 'Snippet new title')
click_button('Save')
it 'displays the snippet blob path and content' do
blob = snippet.blobs.first
expect(page).to have_content('Snippet new title')
end
context 'when the git operation fails' do
before do
allow_next_instance_of(Snippets::UpdateService) do |instance|
allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
end
fill_in(snippet_title_field, with: 'Snippet new title')
fill_in(snippet_blob_path_field, match: :first, with: 'new_file_name')
click_button('Save')
end
it 'renders edit page and displays the error' do
expect(page.find('.flash-container')).to have_content('Error updating the snippet - Error Message')
expect(page).to have_content('Edit Snippet')
end
aggregate_failures do
expect(snippet_get_first_blob_path).to eq blob.path
expect(snippet_get_first_blob_value).to have_content(blob.data.strip)
end
end
context 'Vue application' do
before do
bootstrap_snippet
end
it 'updates a snippet' do
fill_in('snippet-title', with: 'Snippet new title')
click_button('Save')
it_behaves_like 'snippet update' do
let(:snippet_blob_path_field) { 'snippet_file_name' }
let(:snippet_blob_content_selector) { '.file-content' }
end
expect(page).to have_content('Snippet new title')
end
context 'non-Vue application' do
context 'when the git operation fails' do
before do
stub_feature_flags(snippets_vue: false)
stub_feature_flags(snippets_edit_vue: false)
allow_next_instance_of(Snippets::UpdateService) do |instance|
allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
end
bootstrap_snippet
snippet_fill_in_form(title: 'Snippet new title', file_name: 'new_file_name')
click_button('Save')
end
it_behaves_like 'snippet update' do
let(:snippet_blob_path_field) { 'project_snippet_file_name' }
let(:snippet_blob_content_selector) { '.file-content' }
it 'renders edit page and displays the error' do
expect(page.find('.flash-container')).to have_content('Error updating the snippet - Error Message')
expect(page).to have_content('Edit Snippet')
end
end
end
......@@ -2,9 +2,11 @@
require 'spec_helper'
RSpec.shared_examples_for 'snippet editor' do
RSpec.describe 'snippet editor with spam', skip: "Will be handled in https://gitlab.com/gitlab-org/gitlab/-/issues/217722" do
include_context 'includes Spam constants'
let_it_be(:user) { create(:user) }
def description_field
find('.js-description-input').find('input,textarea')
end
......@@ -119,24 +121,3 @@ RSpec.shared_examples_for 'snippet editor' do
end
end
end
RSpec.describe 'User creates snippet', :js do
let_it_be(:user) { create(:user) }
context 'Vue application' do
before do
stub_feature_flags(snippets_edit_vue: false)
end
it_behaves_like "snippet editor"
end
context 'non-Vue application' do
before do
stub_feature_flags(snippets_vue: false)
stub_feature_flags(snippets_edit_vue: false)
end
it_behaves_like "snippet editor"
end
end
......@@ -13,163 +13,127 @@ RSpec.describe 'User creates snippet', :js do
let(:md_description) { 'My Snippet **Description**' }
let(:description) { 'My Snippet Description' }
let(:created_snippet) { Snippet.last }
let(:snippet_title_field) { 'personal_snippet_title' }
let(:snippet_title_field) { 'snippet-title' }
def description_field
find('.js-description-input').find('input,textarea')
before do
sign_in(user)
visit new_snippet_path
end
shared_examples 'snippet creation' do
def fill_form
snippet_fill_in_form(title: title, content: file_content, description: md_description)
end
def fill_form
snippet_fill_in_form(title: title, content: file_content, description: md_description)
end
it 'Authenticated user creates a snippet' do
fill_form
it 'Authenticated user creates a snippet' do
fill_form
click_button('Create snippet')
wait_for_requests
click_button('Create snippet')
wait_for_requests
expect(page).to have_content(title)
page.within(snippet_description_view_selector) do
expect(page).to have_content(description)
expect(page).to have_selector('strong')
end
expect(page).to have_content(file_content)
expect(page).to have_content(title)
page.within(snippet_description_view_selector) do
expect(page).to have_content(description)
expect(page).to have_selector('strong')
end
expect(page).to have_content(file_content)
end
it 'uploads a file when dragging into textarea' do
fill_form
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
expect(snippet_description_value).to have_content('banana_sample')
click_button('Create snippet')
wait_for_requests
link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src']
expect(link).to match(%r{/uploads/-/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z})
it 'uploads a file when dragging into textarea' do
fill_form
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
reqs = inspect_requests { visit("#{link}?ran=#{SecureRandom.base64(20)}") }
expect(reqs.first.status_code).to eq(200)
end
expect(snippet_description_value).to have_content('banana_sample')
context 'when the git operation fails' do
let(:error) { 'Error creating the snippet' }
click_button('Create snippet')
wait_for_requests
before do
allow_next_instance_of(Snippets::CreateService) do |instance|
allow(instance).to receive(:create_commit).and_raise(StandardError, error)
end
link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src']
expect(link).to match(%r{/uploads/-/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z})
fill_form
click_button('Create snippet')
wait_for_requests
end
reqs = inspect_requests { visit("#{link}?ran=#{SecureRandom.base64(20)}") }
expect(reqs.first.status_code).to eq(200)
end
it 'renders the new page and displays the error' do
expect(page).to have_content(error)
expect(page).to have_content('New Snippet')
context 'when the git operation fails' do
let(:error) { 'Error creating the snippet' }
action = find('form.snippet-form')['action']
expect(action).to include("/snippets")
end
end
context 'when snippets default visibility level is restricted' do
before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PRIVATE],
default_snippet_visibility: Gitlab::VisibilityLevel::PRIVATE)
before do
allow_next_instance_of(Snippets::CreateService) do |instance|
allow(instance).to receive(:create_commit).and_raise(StandardError, error)
end
it 'creates a snippet using the lowest available visibility level as default' do
visit new_snippet_path
fill_form
click_button('Create snippet')
wait_for_requests
expect(find('.blob-content')).to have_content(file_content)
expect(Snippet.last.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
end
fill_form
click_button('Create snippet')
wait_for_requests
end
it_behaves_like 'personal snippet with references' do
let(:container) { snippet_description_view_selector }
let(:md_description) { references }
it 'renders the new page and displays the error' do
expect(page).to have_content(error)
expect(page).to have_content('New Snippet')
subject do
fill_form
click_button('Create snippet')
wait_for_requests
end
action = find('form.snippet-form')['action']
expect(action).to include("/snippets")
end
end
context 'Vue application' do
let(:snippet_description_field) { 'snippet-description' }
let(:snippet_description_view_selector) { '.snippet-header .snippet-description' }
context 'when snippets default visibility level is restricted' do
before do
sign_in(user)
visit new_snippet_path
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PRIVATE],
default_snippet_visibility: Gitlab::VisibilityLevel::PRIVATE)
end
it_behaves_like 'snippet creation'
it 'creates a snippet using the lowest available visibility level as default' do
visit new_snippet_path
it 'validation fails for the first time' do
fill_in snippet_title_field, with: title
fill_form
expect(page).not_to have_button('Create snippet')
click_button('Create snippet')
wait_for_requests
snippet_fill_in_form(title: title, content: file_content)
expect(page).to have_button('Create snippet')
expect(find('.blob-content')).to have_content(file_content)
expect(Snippet.last.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
end
end
context 'non-Vue application' do
let(:snippet_description_field) { 'personal_snippet_description' }
let(:snippet_description_view_selector) { '.snippet-header .description' }
it_behaves_like 'personal snippet with references' do
let(:container) { snippet_description_view_selector }
let(:md_description) { references }
before do
stub_feature_flags(snippets_vue: false)
stub_feature_flags(snippets_edit_vue: false)
sign_in(user)
subject do
fill_form
click_button('Create snippet')
visit new_snippet_path
wait_for_requests
end
end
it_behaves_like 'snippet creation'
it 'validation fails for the first time' do
fill_in snippet_title_field, with: title
it 'validation fails for the first time' do
fill_in snippet_title_field, with: title
click_button('Create snippet')
expect(page).not_to have_button('Create snippet')
expect(page).to have_selector('#error_explanation')
end
snippet_fill_in_form(title: title, content: file_content)
expect(page).to have_button('Create snippet')
end
it 'previews a snippet with file' do
# Click placeholder first to expand full description field
description_field.click
fill_in snippet_description_field, with: 'My Snippet'
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
find('.js-md-preview-button').click
it 'previews a snippet with file' do
# Click placeholder first to expand full description field
snippet_fill_in_description('My Snippet')
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
find('.js-md-preview-button').click
page.within('.md-preview-holder') do
expect(page).to have_content('My Snippet')
page.within('.md-preview-holder') do
expect(page).to have_content('My Snippet')
link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src']
expect(link).to match(%r{/uploads/-/system/user/#{user.id}/\h{32}/banana_sample\.gif\z})
link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src']
expect(link).to match(%r{/uploads/-/system/user/#{user.id}/\h{32}/banana_sample\.gif\z})
# Adds a cache buster for checking if the image exists as Selenium is now handling the cached requests
# not anymore as requests when they come straight from memory cache.
reqs = inspect_requests { visit("#{link}?ran=#{SecureRandom.base64(20)}") }
expect(reqs.first.status_code).to eq(200)
end
# Adds a cache buster for checking if the image exists as Selenium is now handling the cached requests
# not anymore as requests when they come straight from memory cache.
# accept_confirm is needed because of https://gitlab.com/gitlab-org/gitlab/-/issues/262102
reqs = inspect_requests { accept_confirm { visit("#{link}?ran=#{SecureRandom.base64(20)}") } }
expect(reqs.first.status_code).to eq(200)
end
end
end
......@@ -11,107 +11,77 @@ RSpec.describe 'User edits snippet', :js do
let_it_be(:user) { create(:user) }
let_it_be(:snippet, reload: true) { create(:personal_snippet, :repository, :public, file_name: file_name, content: content, author: user) }
let(:snippet_title_field) { 'personal_snippet_title' }
before do
sign_in(user)
shared_examples 'snippet editing' do
it 'displays the snippet blob path and content' do
blob = snippet.blobs.first
aggregate_failures do
expect(snippet_get_first_blob_path).to eq blob.path
expect(snippet_get_first_blob_value).to have_content(blob.data.strip)
end
end
it 'updates the snippet' do
fill_in snippet_title_field, with: 'New Snippet Title'
click_button('Save changes')
wait_for_requests
expect(page).to have_content('New Snippet Title')
end
it 'updates the snippet with files attached' do
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
expect(snippet_description_value).to have_content('banana_sample')
visit edit_snippet_path(snippet)
wait_for_all_requests
end
click_button('Save changes')
wait_for_requests
it 'displays the snippet blob path and content' do
blob = snippet.blobs.first
link = find('a.no-attachment-icon img:not(.lazy)[alt="banana_sample"]')['src']
expect(link).to match(%r{/uploads/-/system/personal_snippet/#{snippet.id}/\h{32}/banana_sample\.gif\z})
aggregate_failures do
expect(snippet_get_first_blob_path).to eq blob.path
expect(snippet_get_first_blob_value).to have_content(blob.data.strip)
end
end
it 'updates the snippet to make it internal' do
choose 'Internal'
click_button 'Save changes'
wait_for_requests
it 'updates the snippet' do
snippet_fill_in_title('New Snippet Title')
expect(page).not_to have_selector('.gl-spinner')
expect(page).to have_no_selector('[data-testid="lock-icon"]')
expect(page).to have_selector('[data-testid="shield-icon"]')
end
click_button('Save changes')
wait_for_requests
it 'updates the snippet to make it public' do
choose 'Public'
expect(page).to have_content('New Snippet Title')
end
click_button 'Save changes'
wait_for_requests
it 'updates the snippet with files attached' do
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
expect(snippet_description_value).to have_content('banana_sample')
expect(page).to have_no_selector('[data-testid="lock-icon"]')
expect(page).to have_selector('[data-testid="earth-icon"]')
end
click_button('Save changes')
wait_for_requests
context 'when the git operation fails' do
before do
allow_next_instance_of(Snippets::UpdateService) do |instance|
allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
end
link = find('a.no-attachment-icon img:not(.lazy)[alt="banana_sample"]')['src']
expect(link).to match(%r{/uploads/-/system/personal_snippet/#{snippet.id}/\h{32}/banana_sample\.gif\z})
end
fill_in snippet_title_field, with: 'New Snippet Title'
fill_in snippet_blob_path_field, with: 'new_file_name', match: :first
it 'updates the snippet to make it internal' do
snippet_fill_in_visibility('Internal')
click_button('Save changes')
end
click_button 'Save changes'
wait_for_requests
it 'renders edit page and displays the error' do
expect(page.find('.flash-container')).to have_content('Error updating the snippet - Error Message')
expect(page).to have_content('Edit Snippet')
end
end
expect(page).to have_no_selector('[data-testid="lock-icon"]')
expect(page).to have_selector('[data-testid="shield-icon"]')
end
context 'Vue application' do
it_behaves_like 'snippet editing' do
let(:snippet_blob_path_field) { 'snippet_file_name' }
let(:snippet_blob_content_selector) { '.file-content' }
let(:snippet_description_field) { 'snippet-description' }
it 'updates the snippet to make it public' do
snippet_fill_in_visibility('Public')
before do
sign_in(user)
click_button 'Save changes'
wait_for_requests
visit edit_snippet_path(snippet)
wait_for_all_requests
end
end
expect(page).to have_no_selector('[data-testid="lock-icon"]')
expect(page).to have_selector('[data-testid="earth-icon"]')
end
context 'non-Vue application' do
it_behaves_like 'snippet editing' do
let(:snippet_blob_path_field) { 'personal_snippet_file_name' }
let(:snippet_blob_content_selector) { '.file-content' }
let(:snippet_description_field) { 'personal_snippet_description' }
context 'when the git operation fails' do
before do
allow_next_instance_of(Snippets::UpdateService) do |instance|
allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
end
before do
stub_feature_flags(snippets_vue: false)
stub_feature_flags(snippets_edit_vue: false)
snippet_fill_in_form(title: 'New Snippet Title', file_name: 'new_file_name')
sign_in(user)
click_button('Save changes')
end
visit edit_snippet_path(snippet)
wait_for_all_requests
end
it 'renders edit page and displays the error' do
expect(page.find('.flash-container')).to have_content('Error updating the snippet - Error Message')
expect(page).to have_content('Edit Snippet')
end
end
end
import { setHTMLFixture } from 'helpers/fixtures';
import Editor from '~/editor/editor_lite';
import initEditor from '~/snippet/snippet_bundle';
jest.mock('~/editor/editor_lite', () => jest.fn());
describe('Snippet editor', () => {
let editorEl;
let contentEl;
let fileNameEl;
let form;
const mockName = 'foo.bar';
const mockContent = 'Foo Bar';
const updatedMockContent = 'New Foo Bar';
const mockEditor = {
updateModelLanguage: jest.fn(),
getValue: jest.fn().mockReturnValueOnce(updatedMockContent),
};
const createInstance = jest.fn().mockImplementation(() => ({ ...mockEditor }));
Editor.mockImplementation(() => ({
createInstance,
}));
function setUpFixture(name, content) {
setHTMLFixture(`
<div class="snippet-form-holder">
<form>
<input class="js-snippet-file-name" type="text" value="${name}">
<input class="snippet-file-content" type="hidden" value="${content}">
<pre id="editor"></pre>
</form>
</div>
`);
}
function bootstrap(name = '', content = '') {
setUpFixture(name, content);
editorEl = document.getElementById('editor');
contentEl = document.querySelector('.snippet-file-content');
fileNameEl = document.querySelector('.js-snippet-file-name');
form = document.querySelector('.snippet-form-holder form');
initEditor();
}
function createEvent(name) {
return new Event(name, {
view: window,
bubbles: true,
cancelable: true,
});
}
beforeEach(() => {
bootstrap(mockName, mockContent);
});
it('correctly initializes Editor', () => {
expect(createInstance).toHaveBeenCalledWith({
el: editorEl,
blobPath: mockName,
blobContent: mockContent,
});
});
it('listens to file name changes and updates syntax highlighting of code', () => {
expect(mockEditor.updateModelLanguage).not.toHaveBeenCalled();
const event = createEvent('change');
fileNameEl.value = updatedMockContent;
fileNameEl.dispatchEvent(event);
expect(mockEditor.updateModelLanguage).toHaveBeenCalledWith(updatedMockContent);
});
it('listens to form submit event and populates the hidden field with most recent version of the content', () => {
expect(contentEl.value).toBe(mockContent);
const event = createEvent('submit');
form.dispatchEvent(event);
expect(contentEl.value).toBe(updatedMockContent);
});
});
import '~/snippet/snippet_edit';
import { triggerDOMEvent } from 'jest/helpers/dom_events_helper';
import { SnippetEditInit } from '~/snippets';
import initSnippet from '~/snippet/snippet_bundle';
jest.mock('~/snippet/snippet_bundle');
jest.mock('~/snippets');
jest.mock('~/gl_form');
describe('Snippet edit form initialization', () => {
const setFF = flag => {
gon.features = { snippetsEditVue: flag };
};
let features;
beforeEach(() => {
features = gon.features;
setFixtures('<div class="snippet-form"></div>');
});
afterEach(() => {
gon.features = features;
});
it.each`
name | flag | isVue
${'Regular'} | ${false} | ${false}
${'Vue'} | ${true} | ${true}
`('correctly initializes $name Snippet Edit form', ({ flag, isVue }) => {
initSnippet.mockClear();
it('correctly initializes Vue Snippet Edit form', () => {
SnippetEditInit.mockClear();
setFF(flag);
triggerDOMEvent('DOMContentLoaded');
if (isVue) {
expect(initSnippet).not.toHaveBeenCalled();
expect(SnippetEditInit).toHaveBeenCalled();
} else {
expect(initSnippet).toHaveBeenCalled();
expect(SnippetEditInit).not.toHaveBeenCalled();
}
expect(SnippetEditInit).toHaveBeenCalled();
});
});
......@@ -10,39 +10,69 @@ module Spec
include ActionView::Helpers::JavaScriptHelper
include Spec::Support::Helpers::Features::EditorLiteSpecHelpers
def snippet_description_locator
'snippet-description'
end
def snippet_blob_path_locator
'snippet_file_name'
end
def snippet_description_view_selector
'.snippet-header .snippet-description'
end
def snippet_description_field_collapsed
find('.js-description-input').find('input,textarea')
end
def snippet_get_first_blob_path
page.find_field(snippet_blob_path_field, match: :first).value
page.find_field('snippet_file_name', match: :first).value
end
def snippet_get_first_blob_value
page.find(snippet_blob_content_selector, match: :first)
page.find('.file-content', match: :first)
end
def snippet_description_value
page.find_field(snippet_description_field).value
page.find_field(snippet_description_locator).value
end
def snippet_fill_in_visibility(text)
page.find('#visibility-level-setting').choose(text)
end
def snippet_fill_in_form(title:, content:, description: '')
# fill_in snippet_title_field, with: title
# editor_set_value(content)
fill_in snippet_title_field, with: title
def snippet_fill_in_title(value)
fill_in 'snippet-title', with: value
end
if description
# Click placeholder first to expand full description field
description_field.click
fill_in snippet_description_field, with: description
end
def snippet_fill_in_description(value)
# Click placeholder first to expand full description field
snippet_description_field_collapsed.click
fill_in snippet_description_locator, with: value
end
def snippet_fill_in_content(value)
page.within('.file-editor') do
el = find('.inputarea')
el.send_keys content
el.send_keys value
end
end
private
def snippet_fill_in_file_name(value)
fill_in(snippet_blob_path_locator, match: :first, with: value)
end
def snippet_fill_in_form(title: nil, content: nil, file_name: nil, description: nil, visibility: nil)
snippet_fill_in_title(title) if title
def description_field
find('.js-description-input').find('input,textarea')
snippet_fill_in_description(description) if description
snippet_fill_in_file_name(file_name) if file_name
snippet_fill_in_content(content) if content
snippet_fill_in_visibility(visibility) if visibility
end
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment