Commit 5d8e0d80 authored by Stan Hu's avatar Stan Hu

Merge branch 'ce-to-ee-2018-09-25' into 'master'

CE upstream - 2018-09-25 21:21 UTC

See merge request gitlab-org/gitlab-ee!7486
parents a4ed1e16 13e056f7
<script>
import { mapState, mapGetters } from 'vuex';
import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import SkeletonLoading from '@gitlab-org/gitlab-ui/dist/components/base/skeleton_loading';
import IdeTree from './ide_tree.vue';
import ResizablePanel from './resizable_panel.vue';
import ActivityBar from './activity_bar.vue';
......@@ -13,7 +13,7 @@ import { activityBarViews } from '../constants';
export default {
components: {
SkeletonLoadingContainer,
SkeletonLoading,
ResizablePanel,
ActivityBar,
CommitSection,
......@@ -56,7 +56,7 @@ export default {
:key="n"
class="multi-file-loading-container"
>
<skeleton-loading-container />
<skeleton-loading />
</div>
</div>
</template>
......
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import SkeletonLoading from '@gitlab-org/gitlab-ui/dist/components/base/skeleton_loading';
import FileRow from '~/vue_shared/components/file_row.vue';
import NavDropdown from './nav_dropdown.vue';
import FileRowExtra from './file_row_extra.vue';
......@@ -9,7 +9,7 @@ import FileRowExtra from './file_row_extra.vue';
export default {
components: {
Icon,
SkeletonLoadingContainer,
SkeletonLoading,
NavDropdown,
FileRow,
},
......@@ -51,7 +51,7 @@ export default {
:key="n"
class="multi-file-loading-container"
>
<skeleton-loading-container />
<skeleton-loading />
</div>
</template>
<template v-else>
......
<script>
import { mapState } from 'vuex';
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
export default {
components: {
skeletonLoadingContainer,
},
computed: {
...mapState([
'leftPanelCollapsed',
]),
},
};
</script>
<template>
<tr
class="loading-file"
aria-label="Loading files"
>
<td class="multi-file-table-col-name">
<skeleton-loading-container
:small="true"
/>
</td>
<template v-if="!leftPanelCollapsed">
<td class="d-none d-sm-none d-md-block">
<skeleton-loading-container
:small="true"
/>
</td>
<td class="d-none d-sm-block">
<skeleton-loading-container
:small="true"
class="animation-container-right"
/>
</td>
</template>
</tr>
</template>
......@@ -16,7 +16,7 @@ import 'vendor/jquery.atwho';
import AjaxCache from '~/lib/utils/ajax_cache';
import Vue from 'vue';
import syntaxHighlight from '~/syntax_highlight';
import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import SkeletonLoading from '@gitlab-org/gitlab-ui/dist/components/base/skeleton_loading';
import axios from './lib/utils/axios_utils';
import { getLocationHash } from './lib/utils/url_utility';
import Flash from './flash';
......@@ -1293,10 +1293,10 @@ export default class Notes {
new Vue({
el,
components: {
SkeletonLoadingContainer,
SkeletonLoading,
},
render(createElement) {
return createElement('skeleton-loading-container');
return createElement('skeleton-loading');
},
});
}
......
......@@ -3,13 +3,13 @@ import { mapState, mapActions } from 'vuex';
import imageDiffHelper from '~/image_diff/helpers/index';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import SkeletonLoading from '@gitlab-org/gitlab-ui/dist/components/base/skeleton_loading';
import { trimFirstCharOfLineContent } from '~/diffs/store/utils';
export default {
components: {
DiffFileHeader,
SkeletonLoadingContainer,
SkeletonLoading,
},
props: {
discussion: {
......@@ -142,7 +142,7 @@ export default {
class="line_content js-success-lazy-load"
>
<span></span>
<skeleton-loading-container />
<skeleton-loading />
<span></span>
</td>
</tr>
......
......@@ -28,11 +28,17 @@ export default {
return this.mr.divergedCommitsCount > 0;
},
commitsBehindText() {
return sprintf(s__('mrWidget|The source branch is %{commitsBehindLinkStart}%{commitsBehind}%{commitsBehindLinkEnd} the target branch'), {
return sprintf(
s__(
'mrWidget|The source branch is %{commitsBehindLinkStart}%{commitsBehind}%{commitsBehindLinkEnd} the target branch',
),
{
commitsBehindLinkStart: `<a href="${_.escape(this.mr.targetBranchPath)}">`,
commitsBehind: n__('%d commit behind', '%d commits behind', this.mr.divergedCommitsCount),
commitsBehindLinkEnd: '</a>',
}, false);
},
false,
);
},
branchNameClipboardData() {
// This supports code in app/assets/javascripts/copy_to_clipboard.js that
......@@ -45,17 +51,24 @@ export default {
},
webIdePath() {
if (this.mr.canPushToSourceBranch) {
return mergeUrlParams({
target_project: this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath ?
this.mr.targetProjectFullPath : '',
}, webIDEUrl(`/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}`));
return mergeUrlParams(
{
target_project:
this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath
? this.mr.targetProjectFullPath
: '',
},
webIDEUrl(`/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}`),
);
}
return null;
},
ideButtonTitle() {
return !this.mr.canPushToSourceBranch
? s__('mrWidget|You are not allowed to edit this project directly. Please fork to make changes.')
? s__(
'mrWidget|You are not allowed to edit this project directly. Please fork to make changes.',
)
: '';
},
},
......@@ -104,37 +117,34 @@ export default {
<div
v-if="mr.isOpen"
class="branch-actions"
>
<span
v-tooltip
:title="ideButtonTitle"
data-placement="bottom"
tabindex="0"
class="branch-actions d-flex"
>
<a
v-if="!mr.sourceBranchRemoved"
v-tooltip
:href="webIdePath"
:title="ideButtonTitle"
:class="{ disabled: !mr.canPushToSourceBranch }"
class="btn btn-default inline js-web-ide d-none d-md-inline-block"
class="btn btn-default js-web-ide d-none d-md-inline-block append-right-8"
data-placement="bottom"
tabindex="0"
role="button"
>
{{ s__("mrWidget|Open in Web IDE") }}
</a>
</span>
<button
:disabled="mr.sourceBranchRemoved"
data-target="#modal_merge_info"
data-toggle="modal"
class="btn btn-default inline js-check-out-branch"
class="btn btn-default js-check-out-branch append-right-default"
type="button"
>
{{ s__("mrWidget|Check out branch") }}
</button>
<span class="dropdown prepend-left-10">
<span class="dropdown">
<button
type="button"
class="btn inline dropdown-toggle"
class="btn dropdown-toggle"
data-toggle="dropdown"
aria-label="Download as"
aria-haspopup="true"
......
......@@ -2,14 +2,14 @@
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import $ from 'jquery';
import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import SkeletonLoading from '@gitlab-org/gitlab-ui/dist/components/base/skeleton_loading';
const { CancelToken } = axios;
let axiosSource;
export default {
components: {
SkeletonLoadingContainer,
SkeletonLoading,
},
props: {
content: {
......@@ -81,7 +81,7 @@ export default {
<div
ref="markdown-preview"
class="md md-previewer">
<skeleton-loading-container v-if="isLoading" />
<skeleton-loading v-if="isLoading" />
<div
v-else
v-html="previewContent">
......
<script>
import SkeletonLoading from '@gitlab-org/gitlab-ui/dist/components/base/skeleton_loading';
export default {
name: 'SkeletonNote',
components: {
SkeletonLoading,
},
};
</script>
<template>
<li class="timeline-entry note">
<div class="timeline-entry-inner">
......@@ -6,20 +17,9 @@
<div class="timeline-content">
<div class="note-header"></div>
<div class="note-body">
<skeleton-loading-container />
<skeleton-loading />
</div>
</div>
</div>
</li>
</template>
<script>
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
export default {
name: 'SkeletonNote',
components: {
skeletonLoadingContainer,
},
};
</script>
<script>
export default {
props: {
small: {
type: Boolean,
required: false,
default: false,
},
lines: {
type: Number,
required: false,
default: 3,
},
},
computed: {
lineClasses() {
return new Array(this.lines).fill().map((_, i) => `skeleton-line-${i + 1}`);
},
},
};
</script>
<template>
<div
:class="{
'animation-container-small': small,
}"
class="animation-container"
>
<div
v-for="(css, index) in lineClasses"
:key="index"
:class="css"
>
</div>
</div>
</template>
......@@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base
include WorkhorseHelper
include EnforcesTwoFactorAuthentication
include WithPerformanceBar
include InvalidUTF8ErrorHandler
before_action :authenticate_sessionless_user!
before_action :authenticate_user!
......
module InvalidUTF8ErrorHandler
extend ActiveSupport::Concern
included do
rescue_from ArgumentError, with: :handle_invalid_utf8
end
private
def handle_invalid_utf8(error)
if error.message == "invalid byte sequence in UTF-8"
render_412
else
raise(error)
end
end
def render_412
respond_to do |format|
format.html { render "errors/precondition_failed", layout: "errors", status: 412 }
format.js { render json: { error: 'Invalid UTF-8' }, status: :precondition_failed, content_type: 'application/json' }
format.any { head :precondition_failed }
end
end
end
# frozen_string_literal: true
class Dashboard::ApplicationController < ApplicationController
include ControllerWithCrossProjectAccessCheck
......
# frozen_string_literal: true
class Dashboard::GroupsController < Dashboard::ApplicationController
include GroupTree
......
# frozen_string_literal: true
class Dashboard::LabelsController < Dashboard::ApplicationController
def index
respond_to do |format|
......
# frozen_string_literal: true
class Dashboard::MilestonesController < Dashboard::ApplicationController
include MilestoneActions
......
# frozen_string_literal: true
class Dashboard::ProjectsController < Dashboard::ApplicationController
include ParamsBackwardCompatibility
include RendersMemberAccess
......
# frozen_string_literal: true
class Dashboard::SnippetsController < Dashboard::ApplicationController
skip_cross_project_access_check :index
......
# frozen_string_literal: true
class Dashboard::TodosController < Dashboard::ApplicationController
include ActionView::Helpers::NumberHelper
......
# frozen_string_literal: true
class Explore::ApplicationController < ApplicationController
skip_before_action :authenticate_user!
......
# frozen_string_literal: true
class Explore::GroupsController < Explore::ApplicationController
include GroupTree
......
# frozen_string_literal: true
class Explore::ProjectsController < Explore::ApplicationController
include ParamsBackwardCompatibility
include RendersMemberAccess
......
# frozen_string_literal: true
class Explore::SnippetsController < Explore::ApplicationController
def index
@snippets = SnippetsFinder.new(current_user).execute
......
# frozen_string_literal: true
module GoogleApi
class AuthorizationsController < ApplicationController
def callback
......
# frozen_string_literal: true
class Groups::ApplicationController < ApplicationController
prepend EE::Groups::ApplicationController
include RoutableActions
......
# frozen_string_literal: true
class Groups::AvatarsController < Groups::ApplicationController
before_action :authorize_admin_group!
......
# frozen_string_literal: true
class Groups::BoardsController < Groups::ApplicationController
prepend EE::Boards::BoardsController
include BoardsResponses
......
# frozen_string_literal: true
module Groups
class ChildrenController < Groups::ApplicationController
before_action :group
......
# frozen_string_literal: true
class Groups::GroupMembersController < Groups::ApplicationController
prepend EE::Groups::GroupMembersController
......
# frozen_string_literal: true
class Groups::LabelsController < Groups::ApplicationController
include ToggleSubscriptionAction
......
# frozen_string_literal: true
class Groups::MilestonesController < Groups::ApplicationController
prepend EE::Groups::MilestonesController
......
# frozen_string_literal: true
class Groups::RunnersController < Groups::ApplicationController
# Proper policies should be implemented per
# https://gitlab.com/gitlab-org/gitlab-ce/issues/45894
......
# frozen_string_literal: true
module Groups
module Settings
class CiCdController < Groups::ApplicationController
......
# frozen_string_literal: true
module Groups
class SharedProjectsController < Groups::ApplicationController
respond_to :json
......
# frozen_string_literal: true
class Groups::UploadsController < Groups::ApplicationController
include UploadsActions
include WorkhorseRequest
......
# frozen_string_literal: true
module Groups
class VariablesController < Groups::ApplicationController
before_action :authorize_admin_build!
......
# frozen_string_literal: true
class Import::BaseController < ApplicationController
private
......
# frozen_string_literal: true
class Import::BitbucketController < Import::BaseController
before_action :verify_bitbucket_import_enabled
before_action :bitbucket_auth, except: :callback
......
# frozen_string_literal: true
class Import::FogbugzController < Import::BaseController
before_action :verify_fogbugz_import_enabled
before_action :user_map, only: [:new_user_map, :create_user_map]
......
# frozen_string_literal: true
class Import::GiteaController < Import::GithubController
def new
if session[access_token_key].present? && session[host_key].present?
......
# frozen_string_literal: true
class Import::GithubController < Import::BaseController
prepend ::EE::Import::GithubController
......
# frozen_string_literal: true
class Import::GitlabController < Import::BaseController
MAX_PROJECT_PAGES = 15
PER_PAGE_PROJECTS = 100
......
# frozen_string_literal: true
class Import::GitlabProjectsController < Import::BaseController
before_action :whitelist_query_limiting, only: [:create]
before_action :verify_gitlab_project_import_enabled
......
# frozen_string_literal: true
class Import::GoogleCodeController < Import::BaseController
before_action :verify_google_code_import_enabled
before_action :user_map, only: [:new_user_map, :create_user_map]
......
# frozen_string_literal: true
class Import::ManifestController < Import::BaseController
before_action :whitelist_query_limiting, only: [:create]
before_action :verify_import_enabled
......
# frozen_string_literal: true
class Ldap::OmniauthCallbacksController < OmniauthCallbacksController
extend ::Gitlab::Utils::Override
prepend EE::OmniauthCallbacksController
......
# frozen_string_literal: true
class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
include Gitlab::GonHelper
include Gitlab::Allowable
......
# frozen_string_literal: true
class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
layout 'profile'
......
# frozen_string_literal: true
class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicationsController
include PageLayoutHelper
......
# frozen_string_literal: true
class Profiles::AccountsController < Profiles::ApplicationController
include AuthHelper
......
# frozen_string_literal: true
class Profiles::ActiveSessionsController < Profiles::ApplicationController
def index
@sessions = ActiveSession.list(current_user)
......
# frozen_string_literal: true
class Profiles::ApplicationController < ApplicationController
layout 'profile'
end
# frozen_string_literal: true
class Profiles::AvatarsController < Profiles::ApplicationController
def destroy
@user = current_user
......
# frozen_string_literal: true
class Profiles::ChatNamesController < Profiles::ApplicationController
before_action :chat_name_token, only: [:new]
before_action :chat_name_params, only: [:new, :create, :deny]
......
# frozen_string_literal: true
class Profiles::EmailsController < Profiles::ApplicationController
before_action :find_email, only: [:destroy, :resend_confirmation_instructions]
......
# frozen_string_literal: true
class Profiles::GpgKeysController < Profiles::ApplicationController
before_action :set_gpg_key, only: [:destroy, :revoke]
......
# frozen_string_literal: true
class Profiles::KeysController < Profiles::ApplicationController
skip_before_action :authenticate_user!, only: [:get_keys]
......
# frozen_string_literal: true
class Profiles::NotificationsController < Profiles::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def show
......
# frozen_string_literal: true
class Profiles::PasswordsController < Profiles::ApplicationController
skip_before_action :check_password_expiration, only: [:new, :create]
skip_before_action :check_two_factor_requirement, only: [:new, :create]
......
# frozen_string_literal: true
class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
def index
set_index_vars
......
# frozen_string_literal: true
class Profiles::PreferencesController < Profiles::ApplicationController
before_action :user
......
# frozen_string_literal: true
class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
skip_before_action :check_two_factor_requirement
......@@ -30,7 +32,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
unless two_factor_grace_period_expired?
grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours
flash.now[:alert] << " You need to do this before #{l(grace_period_deadline)}."
flash.now[:alert] = flash.now[:alert] + " You need to do this before #{l(grace_period_deadline)}."
end
end
......
# frozen_string_literal: true
class Profiles::U2fRegistrationsController < Profiles::ApplicationController
def destroy
u2f_registration = current_user.u2f_registrations.find(params[:id])
......
......@@ -13,4 +13,4 @@
= link_to 'Standard', '#login-pane', class: 'nav-link qa-standard-tab', 'data-toggle' => 'tab'
- if allow_signup?
%li.nav-item
= link_to 'Register', '#register-pane', class: 'nav-link', 'data-toggle' => 'tab'
= link_to 'Register', '#register-pane', class: 'nav-link qa-register-tab', 'data-toggle' => 'tab'
- content_for(:title, 'Encoding Error')
%img{ :alt => "GitLab Logo", :src => image_path('logo.svg') }
%h1
412
.container
%h3 Precondition failed
%hr
%p Page can't be loaded because of invalid parameters.
---
title: Render 412 when invalid UTF-8 parameters are passed to controller
merge_request:
author:
type: other
---
title: Enable more frozen string in app/controllers/
merge_request:
author: gfyoung
type: performance
---
title: Fix merge request header margins
merge_request: 21878
author:
type: other
---
title: Add clean-up phase for ScheduleDiffFilesDeletion migration
merge_request: 21734
author:
type: other
# frozen_string_literal: true
class ConsumeRemainingDiffFilesDeletionJobs < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
MIGRATION = 'ScheduleDiffFilesDeletion'.freeze
TMP_INDEX = 'tmp_partial_diff_id_with_files_index'.freeze
def up
# Perform any ongoing background migration that might still be scheduled.
Gitlab::BackgroundMigration.steal(MIGRATION)
remove_concurrent_index_by_name(:merge_request_diffs, TMP_INDEX)
end
def down
add_concurrent_index(:merge_request_diffs, :id, where: "(state NOT IN ('without_files', 'empty'))", name: TMP_INDEX)
end
end
......@@ -158,7 +158,9 @@ Find it under your project's **Repository > Graph**.
## Repository Languages
For the default branch of each repository, GitLab will determine what programming languages
were used and display this on the projects pages.
were used and display this on the projects pages. If this information is missing, it will
be added after updating the default branch on the project. This process can take up to 5
minutes.
![Repository Languages bar](img/repository_languages.png)
......
......@@ -13,8 +13,43 @@ module QA
product(:user) { |factory| factory.user }
def fabricate!
def visit_project_with_retry
# The user intermittently fails to stay signed in after visiting the
# project page. The new user is registered and then signs in and a
# screenshot shows that signing in was successful. Then the project
# page is visited but a screenshot shows the user is no longer signed
# in. It's difficult to reproduce locally but GDK logs don't seem to
# show anything unexpected. This method attempts to work around the
# problem and capture data to help troubleshoot.
Capybara::Screenshot.screenshot_and_save_page
start = Time.now
while Time.now - start < 20
push.project.visit!
puts "Visited project page"
Capybara::Screenshot.screenshot_and_save_page
return if Page::Menu::Main.act { has_personal_area?(wait: 0) }
puts "Not signed in. Attempting to sign in again."
Capybara::Screenshot.screenshot_and_save_page
Page::Menu::Main.act { sign_out }
Page::Main::Login.perform do |login|
login.sign_in_using_credentials(user)
end
end
raise "Failed to load project page and stay logged in"
end
def fabricate!
visit_project_with_retry
Page::Project::Show.act { fork_project }
Page::Project::Fork::New.perform do |fork_new|
......
......@@ -37,7 +37,10 @@ module QA
product(:password) { |factory| factory.password }
def fabricate!
# Don't try to log-out if we're not logged-in
if Page::Menu::Main.act { has_personal_area?(wait: 0) }
Page::Menu::Main.perform { |main| main.sign_out }
end
if credentials_given?
Page::Main::Login.perform do |login|
......
......@@ -76,6 +76,10 @@ module QA
find_element(name).set(content)
end
def has_element?(name)
has_css?(element_selector_css(name))
end
def within_element(name)
page.within(element_selector_css(name)) do
yield
......
......@@ -23,6 +23,7 @@ module QA
view 'app/views/devise/shared/_tabs_ldap.html.haml' do
element :ldap_tab
element :standard_tab
element :register_tab
end
view 'app/views/devise/shared/_tabs_normal.html.haml' do
......@@ -35,7 +36,7 @@ module QA
# we need to wait for the instance to start. That said, in some cases
# we are already logged-in so we check both cases here.
wait(max: 500) do
page.has_css?('.login-page') ||
has_css?('.login-page') ||
Page::Menu::Main.act { has_personal_area?(wait: 0) }
end
end
......@@ -78,12 +79,28 @@ module QA
'/users/sign_in'
end
def has_sign_in_tab?
has_element?(:sign_in_tab)
end
def has_ldap_tab?
has_element?(:ldap_tab)
end
def has_standard_tab?
has_element?(:standard_tab)
end
def sign_in_tab?
page.has_button?('Sign in')
has_css?(".active", text: 'Sign in')
end
def ldap_tab?
page.has_link?('LDAP')
has_css?(".active", text: 'LDAP')
end
def standard_tab?
has_css?(".active", text: 'Standard')
end
def switch_to_sign_in_tab
......@@ -113,8 +130,8 @@ module QA
end
def sign_in_using_gitlab_credentials(user)
switch_to_sign_in_tab unless sign_in_tab?
switch_to_standard_tab if ldap_tab?
switch_to_sign_in_tab if has_sign_in_tab?
switch_to_standard_tab if has_standard_tab?
fill_element :login_field, user.username
fill_element :password_field, user.password
......@@ -122,7 +139,7 @@ module QA
end
def set_initial_password_if_present
return unless page.has_content?('Change your password')
return unless has_content?('Change your password')
fill_element :password_field, Runtime::User.password
fill_element :password_confirmation, Runtime::User.password
......
......@@ -19,7 +19,7 @@ module QA
fill_in :new_user_password, with: user.password
click_button 'Register'
Page::Menu::Main.act { has_personal_area? }
Page::Menu::Main.act { assert_has_personal_area }
end
end
end
......
......@@ -61,8 +61,13 @@ module QA
end
def has_personal_area?(wait: Capybara.default_max_wait_time)
# No need to wait, either we're logged-in, or not.
using_wait_time(wait) { page.has_selector?('.qa-user-avatar') }
using_wait_time(wait) do
page.has_selector?(element_selector_css(:user_avatar))
end
end
def assert_has_personal_area
raise "Failed to sign in" unless has_personal_area?
end
private
......
# frozen_string_literal: true
module QA
shared_examples 'registration and login' do
it 'user registers and logs in' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Factory::Resource::User.fabricate!
# TODO, since `Signed in successfully` message was removed
# this is the only way to tell if user is signed in correctly.
#
Page::Menu::Main.perform do |menu|
expect(menu).to have_personal_area
end
end
end
context :manage do
describe 'standard' do
it_behaves_like 'registration and login'
end
end
context :manage, :orchestrated, :ldap do
describe 'while LDAP is enabled' do
it_behaves_like 'registration and login'
end
end
end
......@@ -694,4 +694,38 @@ describe ApplicationController do
expect(response).to have_gitlab_http_status(403)
end
end
context 'when invalid UTF-8 parameters are received' do
controller(described_class) do
def index
params[:text].split(' ')
render json: :ok
end
end
before do
sign_in user
end
context 'html' do
it 'renders 412' do
get :index, text: "hi \255"
expect(response).to have_gitlab_http_status(412)
expect(response).to render_template :precondition_failed
end
end
context 'js' do
it 'renders 412' do
get :index, text: "hi \255", format: :js
json_response = JSON.parse(response.body)
expect(response).to have_gitlab_http_status(412)
expect(json_response['error']).to eq('Invalid UTF-8')
end
end
end
end
import Vue from 'vue';
import store from '~/ide/stores';
import repoLoadingFile from '~/ide/components/repo_loading_file.vue';
import { resetStore } from '../helpers';
describe('RepoLoadingFile', () => {
let vm;
function createComponent() {
const RepoLoadingFile = Vue.extend(repoLoadingFile);
return new RepoLoadingFile({
store,
}).$mount();
}
function assertLines(lines) {
lines.forEach((line, n) => {
const index = n + 1;
expect(line.classList.contains(`skeleton-line-${index}`)).toBeTruthy();
});
}
function assertColumns(columns) {
columns.forEach(column => {
const container = column.querySelector('.animation-container');
const lines = [...container.querySelectorAll(':scope > div')];
expect(container).toBeTruthy();
expect(lines.length).toEqual(3);
assertLines(lines);
});
}
afterEach(() => {
vm.$destroy();
resetStore(vm.$store);
});
it('renders 3 columns of animated LoC', () => {
vm = createComponent();
const columns = [...vm.$el.querySelectorAll('td')];
expect(columns.length).toEqual(3);
assertColumns(columns);
});
it('renders 1 column of animated LoC if isMini', done => {
vm = createComponent();
vm.$store.state.leftPanelCollapsed = true;
vm.$store.state.openFiles.push('test');
vm.$nextTick(() => {
const columns = [...vm.$el.querySelectorAll('td')];
expect(columns.length).toEqual(1);
assertColumns(columns);
done();
});
});
});
import Vue from 'vue';
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Skeleton loading container', () => {
let vm;
beforeEach(() => {
const component = Vue.extend(skeletonLoadingContainer);
vm = mountComponent(component);
});
afterEach(() => {
vm.$destroy();
});
it('renders 3 skeleton lines by default', () => {
expect(vm.$el.querySelector('.skeleton-line-3')).not.toBeNull();
});
it('renders in full mode by default', () => {
expect(vm.$el.classList.contains('animation-container-small')).toBeFalsy();
});
describe('small', () => {
beforeEach((done) => {
vm.small = true;
Vue.nextTick(done);
});
it('renders in small mode', () => {
expect(vm.$el.classList.contains('animation-container-small')).toBeTruthy();
});
});
describe('lines', () => {
beforeEach((done) => {
vm.lines = 5;
Vue.nextTick(done);
});
it('renders 5 lines', () => {
expect(vm.$el.querySelector('.skeleton-line-5')).not.toBeNull();
expect(vm.$el.querySelector('.skeleton-line-6')).toBeNull();
});
});
});
This diff is collapsed.
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