diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-11 00:09:11 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-11 00:09:11 +0300 |
commit | 696b36294520f8a311586f99e838b6a61b1b3f32 (patch) | |
tree | aa043fc07393643a80453a579c590fe437d02ead | |
parent | c57e10faab0abb213e7a18274fd5a98ba87a5c09 (diff) |
Add latest changes from gitlab-org/gitlab@master
8 files changed, 260 insertions, 243 deletions
diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue index 4da417a37ce..7ce33fd2278 100644 --- a/app/assets/javascripts/ide/components/ide_status_bar.vue +++ b/app/assets/javascripts/ide/components/ide_status_bar.vue @@ -81,7 +81,7 @@ export default { <span v-if="latestPipeline && latestPipeline.details" class="ide-status-pipeline"> <button type="button" - class="p-0 border-0 h-50" + class="p-0 border-0 bg-transparent" @click="openRightPane($options.rightSidebarViews.pipelines)" > <ci-icon diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb index bbf0bdd3662..f0e6cebe0e4 100644 --- a/app/controllers/oauth/applications_controller.rb +++ b/app/controllers/oauth/applications_controller.rb @@ -8,8 +8,8 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController include Gitlab::Experimentation::ControllerConcern include InitializesCurrentUserMode - before_action :verify_user_oauth_applications_enabled, except: :index - before_action :authenticate_user! + prepend_before_action :verify_user_oauth_applications_enabled, except: :index + prepend_before_action :authenticate_user! before_action :add_gon_variables before_action :load_scopes, only: [:index, :create, :edit, :update] diff --git a/changelogs/unreleased/204729-nomethoderror-undefined-method-oauth_applications-for-nil-nilclass.yml b/changelogs/unreleased/204729-nomethoderror-undefined-method-oauth_applications-for-nil-nilclass.yml new file mode 100644 index 00000000000..1a4fdf5d941 --- /dev/null +++ b/changelogs/unreleased/204729-nomethoderror-undefined-method-oauth_applications-for-nil-nilclass.yml @@ -0,0 +1,5 @@ +--- +title: Fix 500 error while accessing Oauth::ApplicationsController without a valid session +merge_request: 24775 +author: +type: fixed diff --git a/changelogs/unreleased/fix-ide-pipeline-background.yml b/changelogs/unreleased/fix-ide-pipeline-background.yml new file mode 100644 index 00000000000..50aa656a748 --- /dev/null +++ b/changelogs/unreleased/fix-ide-pipeline-background.yml @@ -0,0 +1,5 @@ +--- +title: Fix pipeline icon background in Web IDE +merge_request: 24707 +author: +type: fixed diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 0274679fd2c..b6ecd5e5926 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -19239,6 +19239,9 @@ msgstr "" msgid "There was an error gathering the chart data" msgstr "" +msgid "There was an error getting the epic participants." +msgstr "" + msgid "There was an error loading users activity calendar." msgstr "" diff --git a/spec/controllers/oauth/applications_controller_spec.rb b/spec/controllers/oauth/applications_controller_spec.rb index 5f1f6af3999..09f8ad4332d 100644 --- a/spec/controllers/oauth/applications_controller_spec.rb +++ b/spec/controllers/oauth/applications_controller_spec.rb @@ -4,31 +4,82 @@ require 'spec_helper' describe Oauth::ApplicationsController do let(:user) { create(:user) } + let(:application) { create(:oauth_application, owner: user) } context 'project members' do before do sign_in(user) end - describe 'GET #index' do - it 'shows list of applications' do - get :index - - expect(response).to have_gitlab_http_status(:ok) + shared_examples 'redirects to login page when the user is not signed in' do + before do + sign_out(user) end - it 'redirects back to profile page if OAuth applications are disabled' do - disable_user_oauth + it { is_expected.to redirect_to(new_user_session_path) } + end + + describe 'GET #new' do + subject { get :new } + + it { is_expected.to have_gitlab_http_status(:ok) } + + it_behaves_like 'redirects to login page when the user is not signed in' + end + + describe 'DELETE #destroy' do + subject { delete :destroy, params: { id: application.id } } + + it { is_expected.to redirect_to(oauth_applications_url) } + + it_behaves_like 'redirects to login page when the user is not signed in' + end + + describe 'GET #edit' do + subject { get :edit, params: { id: application.id } } + + it { is_expected.to have_gitlab_http_status(:ok) } + + it_behaves_like 'redirects to login page when the user is not signed in' + end + + describe 'PUT #update' do + subject { put :update, params: { id: application.id, doorkeeper_application: { name: 'application' } } } + + it { is_expected.to redirect_to(oauth_application_url(application)) } + + it_behaves_like 'redirects to login page when the user is not signed in' + end + + describe 'GET #show' do + subject { get :show, params: { id: application.id } } + + it { is_expected.to have_gitlab_http_status(:ok) } + + it_behaves_like 'redirects to login page when the user is not signed in' + end + + describe 'GET #index' do + subject { get :index } + + it { is_expected.to have_gitlab_http_status(:ok) } - get :index + context 'when OAuth applications are disabled' do + before do + disable_user_oauth + end - expect(response).to have_gitlab_http_status(:ok) + it { is_expected.to have_gitlab_http_status(:ok) } end + + it_behaves_like 'redirects to login page when the user is not signed in' end describe 'POST #create' do + subject { post :create, params: oauth_params } + it 'creates an application' do - post :create, params: oauth_params + subject expect(response).to have_gitlab_http_status(:found) expect(response).to redirect_to(oauth_application_path(Doorkeeper::Application.last)) @@ -37,7 +88,7 @@ describe Oauth::ApplicationsController do it 'redirects back to profile page if OAuth applications are disabled' do disable_user_oauth - post :create, params: oauth_params + subject expect(response).to have_gitlab_http_status(:found) expect(response).to redirect_to(profile_path) @@ -59,6 +110,8 @@ describe Oauth::ApplicationsController do expect(response.body).to include 'Redirect URI is forbidden by the server' end end + + it_behaves_like 'redirects to login page when the user is not signed in' end end diff --git a/spec/frontend/environments/folder/environments_folder_view_spec.js b/spec/frontend/environments/folder/environments_folder_view_spec.js new file mode 100644 index 00000000000..740225ddd9d --- /dev/null +++ b/spec/frontend/environments/folder/environments_folder_view_spec.js @@ -0,0 +1,180 @@ +import { mount } from '@vue/test-utils'; +import axios from '~/lib/utils/axios_utils'; +import MockAdapter from 'axios-mock-adapter'; +import EnvironmentsFolderViewComponent from '~/environments/folder/environments_folder_view.vue'; +import EnvironmentTable from '~/environments/components/environments_table.vue'; +import { environmentsList } from '../mock_data'; +import { removeBreakLine, removeWhitespace } from 'helpers/text_helper'; +import { GlPagination } from '@gitlab/ui'; + +describe('Environments Folder View', () => { + let mock; + let wrapper; + + const mockData = { + endpoint: 'environments.json', + folderName: 'review', + canReadEnvironment: true, + cssContainerClass: 'container', + canaryDeploymentFeatureId: 'canary_deployment', + showCanaryDeploymentCallout: true, + userCalloutsPath: '/callouts', + lockPromotionSvgPath: '/assets/illustrations/lock-promotion.svg', + helpCanaryDeploymentsPath: 'help/canary-deployments', + }; + + const mockEnvironments = environmentList => { + mock.onGet(mockData.endpoint).reply( + 200, + { + environments: environmentList, + stopped_count: 1, + available_count: 0, + }, + { + 'X-nExt-pAge': '2', + 'x-page': '1', + 'X-Per-Page': '2', + 'X-Prev-Page': '', + 'X-TOTAL': '20', + 'X-Total-Pages': '10', + }, + ); + }; + + const createWrapper = () => { + wrapper = mount(EnvironmentsFolderViewComponent, { propsData: mockData }); + }; + + const findEnvironmentsTabAvailable = () => wrapper.find('.js-environments-tab-available'); + + const findEnvironmentsTabStopped = () => wrapper.find('.js-environments-tab-stopped'); + + beforeEach(() => { + mock = new MockAdapter(axios); + }); + + afterEach(() => { + mock.restore(); + wrapper.destroy(); + }); + + describe('successful request', () => { + beforeEach(() => { + mockEnvironments(environmentsList); + createWrapper(); + return axios.waitForAll(); + }); + + it('should render a table with environments', () => { + const table = wrapper.find(EnvironmentTable); + + expect(table.exists()).toBe(true); + expect(table.find('.environment-name').text()).toEqual(environmentsList[0].name); + }); + + it('should render available tab with count', () => { + const tabTable = findEnvironmentsTabAvailable(); + + expect(tabTable.text()).toContain('Available'); + expect(tabTable.find('.badge').text()).toContain('0'); + }); + + it('should render stopped tab with count', () => { + const tabTable = findEnvironmentsTabStopped(); + + expect(tabTable.text()).toContain('Stopped'); + expect(tabTable.find('.badge').text()).toContain('1'); + }); + + it('should render parent folder name', () => { + expect(removeBreakLine(removeWhitespace(wrapper.find('.js-folder-name').text()))).toContain( + 'Environments / review', + ); + }); + + describe('pagination', () => { + it('should render pagination', () => { + expect(wrapper.find(GlPagination).exists()).toBe(true); + }); + + it('should make an API request when changing page', () => { + jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {}); + wrapper.find('.gl-pagination .page-item:nth-last-of-type(2) .page-link').trigger('click'); + expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ + scope: wrapper.vm.scope, + page: '10', + }); + }); + + it('should make an API request when using tabs', () => { + jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {}); + findEnvironmentsTabStopped().trigger('click'); + expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ scope: 'stopped', page: '1' }); + }); + }); + }); + + describe('unsuccessfull request', () => { + beforeEach(() => { + mock.onGet(mockData.endpoint).reply(500, { environments: [] }); + createWrapper(); + return axios.waitForAll(); + }); + + it('should not render a table', () => { + expect(wrapper.find(EnvironmentTable).exists()).toBe(false); + }); + + it('should render available tab with count 0', () => { + const tabTable = findEnvironmentsTabAvailable(); + + expect(tabTable.text()).toContain('Available'); + expect(tabTable.find('.badge').text()).toContain('0'); + }); + + it('should render stopped tab with count 0', () => { + const tabTable = findEnvironmentsTabStopped(); + + expect(tabTable.text()).toContain('Stopped'); + expect(tabTable.find('.badge').text()).toContain('0'); + }); + }); + + describe('methods', () => { + beforeEach(() => { + mockEnvironments([]); + createWrapper(); + jest.spyOn(window.history, 'pushState').mockImplementation(() => {}); + return axios.waitForAll(); + }); + + describe('updateContent', () => { + it('should set given parameters', () => + wrapper.vm.updateContent({ scope: 'stopped', page: '4' }).then(() => { + expect(wrapper.vm.page).toEqual('4'); + expect(wrapper.vm.scope).toEqual('stopped'); + expect(wrapper.vm.requestData.page).toEqual('4'); + })); + }); + + describe('onChangeTab', () => { + it('should set page to 1', () => { + jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {}); + wrapper.vm.onChangeTab('stopped'); + expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ scope: 'stopped', page: '1' }); + }); + }); + + describe('onChangePage', () => { + it('should update page and keep scope', () => { + jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {}); + wrapper.vm.onChangePage(4); + expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ + scope: wrapper.vm.scope, + page: '4', + }); + }); + }); + }); +}); diff --git a/spec/javascripts/environments/folder/environments_folder_view_spec.js b/spec/javascripts/environments/folder/environments_folder_view_spec.js deleted file mode 100644 index 6530201240f..00000000000 --- a/spec/javascripts/environments/folder/environments_folder_view_spec.js +++ /dev/null @@ -1,229 +0,0 @@ -import Vue from 'vue'; -import MockAdapter from 'axios-mock-adapter'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import { removeBreakLine, removeWhitespace } from 'spec/helpers/text_helper'; -import axios from '~/lib/utils/axios_utils'; -import environmentsFolderViewComponent from '~/environments/folder/environments_folder_view.vue'; -import { environmentsList } from '../mock_data'; - -describe('Environments Folder View', () => { - let Component; - let component; - let mock; - - const mockData = { - endpoint: 'environments.json', - folderName: 'review', - canReadEnvironment: true, - cssContainerClass: 'container', - canaryDeploymentFeatureId: 'canary_deployment', - showCanaryDeploymentCallout: true, - userCalloutsPath: '/callouts', - lockPromotionSvgPath: '/assets/illustrations/lock-promotion.svg', - helpCanaryDeploymentsPath: 'help/canary-deployments', - }; - - beforeEach(() => { - mock = new MockAdapter(axios); - - Component = Vue.extend(environmentsFolderViewComponent); - }); - - afterEach(() => { - mock.restore(); - - component.$destroy(); - }); - - describe('successful request', () => { - beforeEach(() => { - mock.onGet(mockData.endpoint).reply( - 200, - { - environments: environmentsList, - stopped_count: 1, - available_count: 0, - }, - { - 'X-nExt-pAge': '2', - 'x-page': '1', - 'X-Per-Page': '2', - 'X-Prev-Page': '', - 'X-TOTAL': '20', - 'X-Total-Pages': '10', - }, - ); - - component = mountComponent(Component, mockData); - }); - - it('should render a table with environments', done => { - setTimeout(() => { - expect(component.$el.querySelectorAll('table')).not.toBeNull(); - expect(component.$el.querySelector('.environment-name').textContent.trim()).toEqual( - environmentsList[0].name, - ); - done(); - }, 0); - }); - - it('should render available tab with count', done => { - setTimeout(() => { - expect(component.$el.querySelector('.js-environments-tab-available').textContent).toContain( - 'Available', - ); - - expect( - component.$el.querySelector('.js-environments-tab-available .badge').textContent, - ).toContain('0'); - done(); - }, 0); - }); - - it('should render stopped tab with count', done => { - setTimeout(() => { - expect(component.$el.querySelector('.js-environments-tab-stopped').textContent).toContain( - 'Stopped', - ); - - expect( - component.$el.querySelector('.js-environments-tab-stopped .badge').textContent, - ).toContain('1'); - done(); - }, 0); - }); - - it('should render parent folder name', done => { - setTimeout(() => { - expect( - removeBreakLine( - removeWhitespace(component.$el.querySelector('.js-folder-name').textContent.trim()), - ), - ).toContain('Environments / review'); - done(); - }, 0); - }); - - describe('pagination', () => { - it('should render pagination', done => { - setTimeout(() => { - expect(component.$el.querySelectorAll('.gl-pagination')).not.toBeNull(); - done(); - }, 0); - }); - - it('should make an API request when changing page', done => { - spyOn(component, 'updateContent'); - setTimeout(() => { - component.$el - .querySelector('.gl-pagination .page-item:nth-last-of-type(2) .page-link') - .click(); - - expect(component.updateContent).toHaveBeenCalledWith({ - scope: component.scope, - page: '10', - }); - done(); - }, 0); - }); - - it('should make an API request when using tabs', done => { - setTimeout(() => { - spyOn(component, 'updateContent'); - component.$el.querySelector('.js-environments-tab-stopped').click(); - - expect(component.updateContent).toHaveBeenCalledWith({ scope: 'stopped', page: '1' }); - done(); - }); - }); - }); - }); - - describe('unsuccessfull request', () => { - beforeEach(() => { - mock.onGet(mockData.endpoint).reply(500, { - environments: [], - }); - - component = mountComponent(Component, mockData); - }); - - it('should not render a table', done => { - setTimeout(() => { - expect(component.$el.querySelector('table')).toBe(null); - done(); - }, 0); - }); - - it('should render available tab with count 0', done => { - setTimeout(() => { - expect(component.$el.querySelector('.js-environments-tab-available').textContent).toContain( - 'Available', - ); - - expect( - component.$el.querySelector('.js-environments-tab-available .badge').textContent, - ).toContain('0'); - done(); - }, 0); - }); - - it('should render stopped tab with count 0', done => { - setTimeout(() => { - expect(component.$el.querySelector('.js-environments-tab-stopped').textContent).toContain( - 'Stopped', - ); - - expect( - component.$el.querySelector('.js-environments-tab-stopped .badge').textContent, - ).toContain('0'); - done(); - }, 0); - }); - }); - - describe('methods', () => { - beforeEach(() => { - mock.onGet(mockData.endpoint).reply(200, { - environments: [], - }); - - component = mountComponent(Component, mockData); - spyOn(window.history, 'pushState').and.stub(); - }); - - describe('updateContent', () => { - it('should set given parameters', done => { - component - .updateContent({ scope: 'stopped', page: '4' }) - .then(() => { - expect(component.page).toEqual('4'); - expect(component.scope).toEqual('stopped'); - expect(component.requestData.scope).toEqual('stopped'); - expect(component.requestData.page).toEqual('4'); - done(); - }) - .catch(done.fail); - }); - }); - - describe('onChangeTab', () => { - it('should set page to 1', () => { - spyOn(component, 'updateContent'); - component.onChangeTab('stopped'); - - expect(component.updateContent).toHaveBeenCalledWith({ scope: 'stopped', page: '1' }); - }); - }); - - describe('onChangePage', () => { - it('should update page and keep scope', () => { - spyOn(component, 'updateContent'); - - component.onChangePage(4); - - expect(component.updateContent).toHaveBeenCalledWith({ scope: component.scope, page: '4' }); - }); - }); - }); -}); |