Commit 10d0e569 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent a19a376b
......@@ -196,6 +196,11 @@ ul.content-list {
display: flex;
align-items: center;
white-space: nowrap;
// Override style that allows the flex-row text to wrap.
&.allow-wrap {
white-space: normal;
}
}
.row-main-content {
......
......@@ -94,6 +94,25 @@ module ApplicationHelper
sanitize(str, tags: %w(a span))
end
def body_data
{
page: body_data_page,
page_type_id: controller.params[:id],
find_file: find_file_path,
group: "#{@group&.path}"
}.merge(project_data)
end
def project_data
return {} unless @project
{
project_id: @project.id,
project: @project.path,
namespace_id: @project.namespace&.id
}
end
def body_data_page
[*controller.controller_path.split('/'), controller.action_name].compact.join(':')
end
......
- managed_namespace_help_text = s_('ClusterIntegration|Choose a prefix to be used for your namespaces. Defaults to your project path.')
- managed_namespace_help_text = s_('ClusterIntegration|Set a prefix for your namespaces. If not set, defaults to your project path. If modified, existing environments will use their current namespaces until the cluster cache is cleared.')
- non_managed_namespace_help_text = s_('ClusterIntegration|The namespace associated with your project. This will be used for deploy boards, pod logs, and Web terminals.')
- managed_namespace_help_link = link_to _('More information'), help_page_path('user/project/clusters/index.md',
anchor: 'gitlab-managed-clusters'), target: '_blank'
......
!!! 5
%html{ lang: I18n.locale, class: page_class }
= render "layouts/head"
%body{ class: "#{user_application_theme} #{@body_class} #{client_class_list}", data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
%body{ class: "#{user_application_theme} #{@body_class} #{client_class_list}", data: body_data }
= render "layouts/init_auto_complete" if @gfm_form
= render "layouts/init_client_detection_flags"
= render 'peek/bar'
......
- commit = @repository.commit(tag.dereferenced_target)
- release = @releases.find { |release| release.tag == tag.name }
%li.flex-row
.row-main-content.str-truncated
%li.flex-row.allow-wrap
.row-main-content
= icon('tag')
= link_to tag.name, project_tag_path(@project, tag.name), class: 'item-title ref-name prepend-left-4'
......@@ -26,7 +26,7 @@
= _("Release")
= link_to release.name, project_releases_path(@project, anchor: release.tag), class: 'tag-release-link'
- if release.description.present?
.description.md.prepend-top-default
.md.prepend-top-default
= markdown_field(release, :description)
.row-fixed-content.controls.flex-row
......
---
title: Allow patch notes on repo tags page to word wrap
merge_request: 20135
author:
type: fixed
---
title: Add body data elements for pageview context
merge_request: 18450
author:
type: added
---
title: Update copy on managed namespace prefixes
merge_request: 20935
author:
type: fixed
......@@ -30,6 +30,23 @@ The source of the documentation exists within the codebase of each GitLab applic
Documentation issues and merge requests are part of their respective repositories and all have the label `Documentation`.
### Branch naming
The [CI pipeline for the main GitLab project](../pipelines.md) is configured to automatically
run only the jobs that match the type of contribution. If your contribution contains
**only** documentation changes, then only documentation-related jobs will be run, and
the pipeline will complete much faster than a code contribution.
If you are submitting documentation-only changes to Runner, Omnibus, or Charts,
the fast pipeline is not determined automatically. Instead, create branches for
docs-only merge requests using the following guide:
| Branch name | Valid example |
|:----------------------|:-----------------------------|
| Starting with `docs/` | `docs/update-api-issues` |
| Starting with `docs-` | `docs-update-api-issues` |
| Ending in `-docs` | `123-update-api-issues-docs` |
## Contributing to docs
[Contributions to GitLab docs](workflow.md) are welcome from the entire GitLab community.
......
......@@ -54,9 +54,9 @@ In summary:
- **Do**: Split tests across separate files, unless the tests share expensive setup.
- **Don't**: Put new tests in an existing file without considering the impact on parallelization.
## Limit the use of `before(:all)` hook
## Limit the use of `before(:all)` and `after` hooks
Limit the use of `before(:all)` to perform setup tasks with only API calls, non UI operations
Limit the use of `before(:all)` hook to perform setup tasks with only API calls, non UI operations
or basic UI operations such as login.
We use [`capybara-screenshot`](https://github.com/mattheworiordan/capybara-screenshot) library to automatically save screenshots on failures.
......@@ -66,6 +66,10 @@ This library [saves the screenshots in the RSpec's `after` hook](https://github.
Given this fact, we should limit the use of `before(:all)` to only those operations where a screenshot is not
necessary in case of failure and QA logs would be enough for debugging.
Similarly, the `after` hook should only be used for non-UI operations. Any UI operations in `after` hook in a test file
would execute before the `after` hook that takes the screenshot. This would result in moving the UI status away from the
point of failure and so the screenshot would not be captured at the right moment.
## Ensure tests do not leave the browser logged in
All QA tests expect to be able to log in at the start of the test.
......@@ -74,7 +78,7 @@ That's not possible if a test leaves the browser logged in when it finishes. Nor
For an example see: <https://gitlab.com/gitlab-org/gitlab/issues/34736>
Ideally, any actions peformed in an `after(:context)` (or [`before(:context)`](#limit-the-use-of-beforeall-hook)) block would be performed via the API. But if it's necessary to do so via the UI (e.g., if API functionality doesn't exist), make sure to log out at the end of the block.
Ideally, any actions peformed in an `after(:context)` (or [`before(:context)`](#limit-the-use-of-beforeall-and-after-hooks)) block would be performed via the API. But if it's necessary to do so via the UI (e.g., if API functionality doesn't exist), make sure to log out at the end of the block.
```ruby
after(:all) do
......
......@@ -14,8 +14,11 @@ To access the visibility and access control options:
## Default branch protection
Branch protection specifies which roles can push to branches and which roles can delete
branches.
This global option defines the branch protection that applies to every repository's default branch. [Branch protection](../../project/protected_branches.md) specifies which roles can push to branches and which roles can delete
branches. In this case _Default_ refers to a repository's default branch, which in most cases is _master_.
branches. "Default" in this case refers to a repository's default branch, which in most cases would be "master".
This setting applies only to each repositories' default branch. To protect other branches, you must configure branch protection in repository. For details, see [Protected Branches](../../project/protected_branches.md).
To change the default branch protection:
......
......@@ -33,6 +33,9 @@ with `repo:status` access granted:
1. Optionally uncheck **Static status check names** checkbox to disable static status check names.
1. Save or optionally click "Test Settings".
Once the integration is configured, see [Pipelines for external pull requests](../../../ci/ci_cd_for_external_repos/#pipelines-for-external-pull-requests)
to configure pipelines to run for open pull requests.
#### Static / dynamic status check names
> - Introduced in GitLab 11.5: using static status check names as opt-in option.
......
......@@ -3595,9 +3595,6 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
msgid "ClusterIntegration|Choose a prefix to be used for your namespaces. Defaults to your project path."
msgstr ""
msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
......@@ -4132,6 +4129,9 @@ msgstr ""
msgid "ClusterIntegration|Service token is required."
msgstr ""
msgid "ClusterIntegration|Set a prefix for your namespaces. If not set, defaults to your project path. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
msgstr ""
msgid "ClusterIntegration|Show"
msgstr ""
......
......@@ -4,8 +4,7 @@ module QA
context 'Configure', :orchestrated, :mattermost do
describe 'Mattermost support' do
it 'user creates a group with a mattermost team' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
Page::Main::Menu.perform(&:go_to_groups)
Page::Dashboard::Groups.perform do |groups|
......
......@@ -4,8 +4,7 @@ module QA
context 'Manage' do
describe 'Project transfer between groups' do
it 'user transfers a project between groups' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
source_group = Resource::Group.fabricate_via_api! do |group|
group.path = 'source-group'
......
......@@ -4,8 +4,7 @@ module QA
context 'Manage', :smoke do
describe 'basic user login' do
it 'user logs in using basic credentials and logs out' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
Page::Main::Menu.perform do |menu|
expect(menu).to have_personal_area
......
......@@ -4,8 +4,7 @@ module QA
context 'Manage', :orchestrated, :ldap_no_tls, :ldap_tls do
describe 'LDAP login' do
it 'user logs into GitLab using LDAP credentials' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
Page::Main::Menu.perform do |menu|
expect(menu).to have_personal_area
......
......@@ -4,8 +4,7 @@ module QA
context 'Manage', :orchestrated, :mattermost do
describe 'Mattermost login' do
it 'user logs into Mattermost using GitLab OAuth' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
Support::Retrier.retry_on_exception do
Runtime::Browser.visit(:mattermost, Page::Mattermost::Login)
......
......@@ -4,8 +4,7 @@ module QA
context 'Manage' do
describe 'Add project member' do
it 'user adds project member' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
user = Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1)
......
......@@ -4,8 +4,7 @@ module QA
context 'Manage', :smoke do
describe 'Project creation' do
it 'user creates a new project' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
created_project = Resource::Project.fabricate_via_browser_ui! do |project|
project.name = 'awesome-project'
......
......@@ -23,8 +23,7 @@ module QA
end
it 'user imports a GitHub repo' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
imported_project # import the project
......
......@@ -4,8 +4,7 @@ module QA
context 'Manage' do
describe 'Project activity' do
it 'user creates an event in the activity page upon Git push' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
project_push = Resource::Repository::ProjectPush.fabricate! do |push|
push.file_name = 'README.md'
......
......@@ -4,8 +4,7 @@ module QA
context 'Create' do
describe 'Create a new merge request' do
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
@project = Resource::Project.fabricate_via_api! do |project|
project.name = 'project'
......
......@@ -4,8 +4,7 @@ module QA
context 'Create' do
describe 'Merge request creation from fork' do
it 'user forks a project, submits a merge request and maintainer merges it' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
merge_request = Resource::MergeRequestFromFork.fabricate! do |merge_request|
merge_request.fork_branch = 'feature-branch'
......
......@@ -5,8 +5,7 @@ module QA
context 'Create', :quarantine do
describe 'Merge request rebasing' do
it 'user rebases source branch of merge request' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
project = Resource::Project.fabricate! do |project|
project.name = "only-fast-forward"
......
......@@ -4,8 +4,7 @@ module QA
context 'Create' do
describe 'Merge request squashing' do
it 'user squashes commits while merging' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
project = Resource::Project.fabricate! do |project|
project.name = "squash-before-merge"
......
......@@ -16,8 +16,7 @@ module QA
commit_message_of_third_branch = "Add #{file_third_branch}"
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
project = Resource::Project.fabricate! do |proj|
proj.name = 'project-qa-test'
......
......@@ -6,8 +6,7 @@ module QA
let(:key_title) { "key for ssh tests #{Time.now.to_f}" }
it 'user adds and then removes an SSH key', :smoke do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
key = Resource::SSHKey.fabricate! do |resource|
resource.title = key_title
......
......@@ -6,8 +6,7 @@ module QA
context 'Create', :quarantine do
describe 'Push over HTTP using Git protocol version 2', :requires_git_protocol_v2 do
it 'user pushes to the repository' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
# Create a project to push to
project = Resource::Project.fabricate! do |project|
......
......@@ -17,20 +17,15 @@ module QA
end
end
def login
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
end
around do |example|
# Create an SSH key to be used with Git
login
Flow::Login.sign_in
ssh_key
example.run
# Remove the SSH key
login
Flow::Login.sign_in
Page::Main::Menu.perform(&:click_settings_link)
Page::Profile::Menu.perform(&:click_ssh_keys)
Page::Profile::SSHKeys.perform do |ssh_keys|
......
......@@ -4,8 +4,7 @@ module QA
context 'Create' do
describe 'Git push over HTTP', :ldap_no_tls do
it 'user using a personal access token pushes code to the repository' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
access_token = Resource::PersonalAccessToken.fabricate!.access_token
......
......@@ -4,8 +4,7 @@ module QA
context 'Create' do
describe 'Git push over HTTP', :ldap_no_tls do
it 'user pushes code to the repository' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
project_push = Resource::Repository::ProjectPush.fabricate! do |push|
push.file_name = 'README.md'
......
......@@ -9,8 +9,7 @@ module QA
let(:key_title) { "key for ssh tests #{Time.now.to_f}" }
it 'user adds an ssh key and pushes code to the repository' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
key = Resource::SSHKey.fabricate! do |resource|
resource.title = key_title
......
......@@ -4,8 +4,7 @@ module QA
context 'Create', :smoke do
describe 'Snippet creation' do
it 'User creates a snippet' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
Page::Main::Menu.perform(&:go_to_snippets)
......
......@@ -4,8 +4,7 @@ module QA
context 'Create' do
describe 'Wiki management' do
it 'user creates, edits, clones, and pushes to the wiki' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
wiki = Resource::Wiki.fabricate! do |resource|
resource.title = 'Home'
......
......@@ -4,8 +4,7 @@ module QA
context 'Release' do
describe 'Deploy key creation' do
it 'user adds a deploy key' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
key = Runtime::Key::RSA.new
deploy_key_title = 'deploy key title'
......
......@@ -10,8 +10,7 @@ module QA
@job_log_json_flag_enabled = Runtime::Feature.enabled?('job_log_json')
Runtime::Feature.disable('job_log_json') if @job_log_json_flag_enabled
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
@runner_name = "qa-runner-#{Time.now.to_i}"
......
......@@ -4,8 +4,7 @@ module QA
context 'Release' do
describe 'Deploy token creation' do
it 'user adds a deploy token' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
deploy_token_name = 'deploy token name'
one_week_from_now = Date.today + 7
......
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import AccessorUtilities from '~/lib/utils/accessor';
describe('AccessorUtilities', () => {
useLocalStorageSpy();
const testError = new Error('test error');
describe('isPropertyAccessSafe', () => {
let base;
it('should return `true` if access is safe', () => {
base = { testProp: 'testProp' };
base = {
testProp: 'testProp',
};
expect(AccessorUtilities.isPropertyAccessSafe(base, 'testProp')).toBe(true);
});
......@@ -54,17 +58,12 @@ describe('AccessorUtilities', () => {
});
describe('isLocalStorageAccessSafe', () => {
beforeEach(() => {
spyOn(window.localStorage, 'setItem');
spyOn(window.localStorage, 'removeItem');
});
it('should return `true` if access is safe', () => {
expect(AccessorUtilities.isLocalStorageAccessSafe()).toBe(true);
});
it('should return `false` if access to .setItem isnt safe', () => {
window.localStorage.setItem.and.callFake(() => {
window.localStorage.setItem.mockImplementation(() => {
throw testError;
});
......
......@@ -25,7 +25,7 @@ describe('DOM Utils', () => {
addClassIfElementExists(childElement, className);
expect(childElement.classList).toContain(className);
expect(childElement.classList).toContainEqual(className);
});
it('does not throw if element does not exist', () => {
......@@ -40,22 +40,44 @@ describe('DOM Utils', () => {
describe('canScrollUp', () => {
[1, 100].forEach(scrollTop => {
it(`is true if scrollTop is > 0 (${scrollTop})`, () => {
expect(canScrollUp({ scrollTop })).toBe(true);
expect(
canScrollUp({
scrollTop,
}),
).toBe(true);
});
});
[0, -10].forEach(scrollTop => {
it(`is false if scrollTop is <= 0 (${scrollTop})`, () => {
expect(canScrollUp({ scrollTop })).toBe(false);
expect(
canScrollUp({
scrollTop,
}),
).toBe(false);
});
});
it('is true if scrollTop is > margin', () => {
expect(canScrollUp({ scrollTop: TEST_MARGIN + 1 }, TEST_MARGIN)).toBe(true);
expect(
canScrollUp(
{
scrollTop: TEST_MARGIN + 1,
},
TEST_MARGIN,
),
).toBe(true);
});
it('is false if scrollTop is <= margin', () => {
expect(canScrollUp({ scrollTop: TEST_MARGIN }, TEST_MARGIN)).toBe(false);
expect(
canScrollUp(
{
scrollTop: TEST_MARGIN,
},
TEST_MARGIN,
),
).toBe(false);
});
});
......@@ -63,7 +85,11 @@ describe('DOM Utils', () => {
let element;
beforeEach(() => {
element = { scrollTop: 7, offsetHeight: 22, scrollHeight: 30 };
element = {
scrollTop: 7,
offsetHeight: 22,
scrollHeight: 30,
};
});
it('is true if element can be scrolled down', () => {
......
......@@ -20,7 +20,7 @@ describe('File upload', () => {
const btn = document.querySelector('.js-button');
const input = document.querySelector('.js-input');
spyOn(input, 'click');
jest.spyOn(input, 'click').mockReturnValue();
btn.click();
......@@ -43,7 +43,7 @@ describe('File upload', () => {
const btn = document.querySelector('.js-button');
fileUpload('.js-not-button', '.js-input');
spyOn(input, 'click');
jest.spyOn(input, 'click').mockReturnValue();
btn.click();
......@@ -55,7 +55,7 @@ describe('File upload', () => {
const btn = document.querySelector('.js-button');
fileUpload('.js-button', '.js-not-input');
spyOn(input, 'click');
jest.spyOn(input, 'click').mockReturnValue();
btn.click();
......
......@@ -17,51 +17,44 @@ describe('Icon utils', () => {
let axiosMock;
let mockEndpoint;
let getIcon;
const mockName = 'mockIconName';
const mockPath = 'mockPath';
const getIcon = () => iconUtils.getSvgIconPathContent(mockName);
beforeEach(() => {
axiosMock = new MockAdapter(axios);
mockEndpoint = axiosMock.onGet(gon.sprite_icons);
getIcon = iconUtils.getSvgIconPathContent(mockName);
});
afterEach(() => {
axiosMock.restore();
});
it('extracts svg icon path content from sprite icons', done => {
it('extracts svg icon path content from sprite icons', () => {
mockEndpoint.replyOnce(
200,
`<svg><symbol id="${mockName}"><path d="${mockPath}"/></symbol></svg>`,
);
getIcon
.then(path => {
expect(path).toBe(mockPath);
done();
})
.catch(done.fail);
return getIcon().then(path => {
expect(path).toBe(mockPath);
});
});
it('returns null if icon path content does not exist', done => {
it('returns null if icon path content does not exist', () => {
mockEndpoint.replyOnce(200, ``);
getIcon
.then(path => {
expect(path).toBe(null);
done();
})
.catch(done.fail);
return getIcon().then(path => {
expect(path).toBe(null);
});
});
it('returns null if an http error occurs', done => {
it('returns null if an http error occurs', () => {
mockEndpoint.replyOnce(500);
getIcon
.then(path => {
expect(path).toBe(null);
done();
})
.catch(done.fail);
return getIcon().then(path => {
expect(path).toBe(null);
});
});
});
});
......@@ -243,7 +243,7 @@ describe('init markdown', () => {
});
it('uses ace editor insert text when editor is passed in', () => {
spyOn(editor, 'insert');
jest.spyOn(editor, 'insert').mockReturnValue();
insertMarkdownText({
text: editor.getValue,
......@@ -258,7 +258,7 @@ describe('init markdown', () => {
});
it('adds block tags on line above and below selection', () => {
spyOn(editor, 'insert');
jest.spyOn(editor, 'insert').mockReturnValue();
const selected = 'this text \n is multiple \n lines';
const text = `before \n ${selected} \n after`;
......@@ -276,7 +276,7 @@ describe('init markdown', () => {
});
it('uses ace editor to navigate back tag length when nothing is selected', () => {
spyOn(editor, 'navigateLeft');
jest.spyOn(editor, 'navigateLeft').mockReturnValue();
insertMarkdownText({
text: editor.getValue,
......@@ -291,7 +291,7 @@ describe('init markdown', () => {
});
it('ace editor does not navigate back when there is selected text', () => {
spyOn(editor, 'navigateLeft');
jest.spyOn(editor, 'navigateLeft').mockReturnValue();
insertMarkdownText({
text: editor.getValue,
......
......@@ -4,7 +4,10 @@ import UsersCache from '~/lib/utils/users_cache';
describe('UsersCache', () => {
const dummyUsername = 'win';
const dummyUserId = 123;
const dummyUser = { name: 'has a farm', username: 'farmer' };
const dummyUser = {
name: 'has a farm',
username: 'farmer',
};
const dummyUserStatus = 'my status';
beforeEach(() => {
......@@ -68,7 +71,6 @@ describe('UsersCache', () => {
it('does nothing if cache contains no matching data', () => {
UsersCache.internalStorage['no body'] = 'no data';
UsersCache.remove(dummyUsername);
expect(UsersCache.internalStorage['no body']).toBe('no data');
......@@ -76,7 +78,6 @@ describe('UsersCache', () => {
it('removes matching data', () => {
UsersCache.internalStorage[dummyUsername] = dummyUser;
UsersCache.remove(dummyUsername);
expect(UsersCache.internalStorage).toEqual({});
......@@ -87,13 +88,16 @@ describe('UsersCache', () => {
let apiSpy;
beforeEach(() => {
spyOn(Api, 'users').and.callFake((query, options) => apiSpy(query, options));
jest.spyOn(Api, 'users').mockImplementation((query, options) => apiSpy(query, options));
});
it('stores and returns data from API call if cache is empty', done => {
apiSpy = (query, options) => {
expect(query).toBe('');
expect(options).toEqual({ username: dummyUsername });
expect(options).toEqual({
username: dummyUsername,
});
return Promise.resolve({
data: [dummyUser],
});
......@@ -110,14 +114,18 @@ describe('UsersCache', () => {
it('returns undefined if Ajax call fails and cache is empty', done => {
const dummyError = new Error('server exploded');
apiSpy = (query, options) => {
expect(query).toBe('');
expect(options).toEqual({ username: dummyUsername });
expect(options).toEqual({
username: dummyUsername,
});
return Promise.reject(dummyError);
};
UsersCache.retrieve(dummyUsername)
.then(user => fail(`Received unexpected user: ${JSON.stringify(user)}`))
.then(user => done.fail(`Received unexpected user: ${JSON.stringify(user)}`))
.catch(error => {
expect(error).toBe(dummyError);
})
......@@ -127,7 +135,8 @@ describe('UsersCache', () => {
it('makes no Ajax call if matching data exists', done => {
UsersCache.internalStorage[dummyUsername] = dummyUser;
apiSpy = () => fail(new Error('expected no Ajax call!'));
apiSpy = () => done.fail(new Error('expected no Ajax call!'));
UsersCache.retrieve(dummyUsername)
.then(user => {
......@@ -142,12 +151,13 @@ describe('UsersCache', () => {
let apiSpy;
beforeEach(() => {
spyOn(Api, 'user').and.callFake(id => apiSpy(id));
jest.spyOn(Api, 'user').mockImplementation(id => apiSpy(id));
});
it('stores and returns data from API call if cache is empty', done => {
apiSpy = id => {
expect(id).toBe(dummyUserId);
return Promise.resolve({
data: dummyUser,
});
......@@ -164,13 +174,15 @@ describe('UsersCache', () => {
it('returns undefined if Ajax call fails and cache is empty', done => {
const dummyError = new Error('server exploded');
apiSpy = id => {
expect(id).toBe(dummyUserId);
return Promise.reject(dummyError);
};
UsersCache.retrieveById(dummyUserId)
.then(user => fail(`Received unexpected user: ${JSON.stringify(user)}`))
.then(user => done.fail(`Received unexpected user: ${JSON.stringify(user)}`))
.catch(error => {
expect(error).toBe(dummyError);
})
......@@ -180,7 +192,8 @@ describe('UsersCache', () => {
it('makes no Ajax call if matching data exists', done => {
UsersCache.internalStorage[dummyUserId] = dummyUser;
apiSpy = () => fail(new Error('expected no Ajax call!'));
apiSpy = () => done.fail(new Error('expected no Ajax call!'));
UsersCache.retrieveById(dummyUserId)
.then(user => {
......@@ -195,12 +208,13 @@ describe('UsersCache', () => {
let apiSpy;
beforeEach(() => {
spyOn(Api, 'userStatus').and.callFake(id => apiSpy(id));
jest.spyOn(Api, 'userStatus').mockImplementation(id => apiSpy(id));
});
it('stores and returns data from API call if cache is empty', done => {
apiSpy = id => {
expect(id).toBe(dummyUserId);
return Promise.resolve({
data: dummyUserStatus,
});
......@@ -217,13 +231,15 @@ describe('UsersCache', () => {
it('returns undefined if Ajax call fails and cache is empty', done => {
const dummyError = new Error('server exploded');
apiSpy = id => {
expect(id).toBe(dummyUserId);
return Promise.reject(dummyError);
};
UsersCache.retrieveStatusById(dummyUserId)
.then(userStatus => fail(`Received unexpected user: ${JSON.stringify(userStatus)}`))
.then(userStatus => done.fail(`Received unexpected user: ${JSON.stringify(userStatus)}`))
.catch(error => {
expect(error).toBe(dummyError);
})
......@@ -232,8 +248,11 @@ describe('UsersCache', () => {
});
it('makes no Ajax call if matching data exists', done => {
UsersCache.internalStorage[dummyUserId] = { status: dummyUserStatus };
apiSpy = () => fail(new Error('expected no Ajax call!'));
UsersCache.internalStorage[dummyUserId] = {
status: dummyUserStatus,
};
apiSpy = () => done.fail(new Error('expected no Ajax call!'));
UsersCache.retrieveStatusById(dummyUserId)
.then(userStatus => {
......
......@@ -235,4 +235,88 @@ describe ApplicationHelper do
end
end
end
describe '#body_data' do
context 'when @project is not set' do
it 'does not include project data in the body data elements' do
expect(helper.body_data).to eq(
{
page: 'application',
page_type_id: nil,
find_file: nil,
group: ''
}
)
end
context 'when @group is set' do
it 'sets group in the body data elements' do
group = create(:group)
assign(:group, group)
expect(helper.body_data).to eq(
{
page: 'application',
page_type_id: nil,
find_file: nil,
group: group.path
}
)
end
end
end
context 'when @project is set' do
it 'includes all possible body data elements and associates the project elements with project' do
project = create(:project)
assign(:project, project)
expect(helper.body_data).to eq(
{
page: 'application',
page_type_id: nil,
find_file: nil,
group: '',
project_id: project.id,
project: project.name,
namespace_id: project.namespace.id
}
)
end
context 'when controller is issues' do
before do
stub_controller_method(:controller_path, 'projects:issues')
end
context 'when params[:id] is present and the issue exsits and action_name is show' do
it 'sets all project and id elements correctly related to the issue' do
issue = create(:issue)
stub_controller_method(:action_name, 'show')
stub_controller_method(:params, { id: issue.id })
assign(:project, issue.project)
expect(helper.body_data).to eq(
{
page: 'projects:issues:show',
page_type_id: issue.id,
find_file: nil,
group: '',
project_id: issue.project.id,
project: issue.project.name,
namespace_id: issue.project.namespace.id
}
)
end
end
end
end
def stub_controller_method(method_name, value)
allow(helper.controller).to receive(method_name).and_return(value)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'layouts/application' do
let(:user) { create(:user) }
before do
allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings)
allow(view).to receive(:experiment_enabled?).and_return(false)
allow(view).to receive(:session).and_return({})
allow(view).to receive(:user_signed_in?).and_return(true)
allow(view).to receive(:current_user).and_return(user)
end
context 'body data elements for pageview context' do
let(:body_data) do
{
body_data_page: 'projects:issues:show',
body_data_page_type_id: '1',
body_data_project_id: '2',
body_data_namespace_id: '3'
}
end
before do
allow(view).to receive(:body_data).and_return(body_data)
render
end
it 'includes the body element page' do
expect(rendered).to include('data-page="projects:issues:show"')
end
it 'includes the body element page_type_id' do
expect(rendered).to include('data-page-type-id="1"')
end
it 'includes the body element project_id' do
expect(rendered).to include('data-project-id="2"')
end
it 'includes the body element namespace_id' do
expect(rendered).to include('data-namespace-id="3"')
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