Commit 0e68afab authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 33aa02e7
...@@ -410,13 +410,10 @@ RSpec/RepeatedExample: ...@@ -410,13 +410,10 @@ RSpec/RepeatedExample:
- 'spec/models/ability_spec.rb' - 'spec/models/ability_spec.rb'
- 'spec/models/ci/build_spec.rb' - 'spec/models/ci/build_spec.rb'
- 'spec/models/concerns/issuable_spec.rb' - 'spec/models/concerns/issuable_spec.rb'
- 'spec/models/member_spec.rb'
- 'spec/models/project_services/chat_message/pipeline_message_spec.rb' - 'spec/models/project_services/chat_message/pipeline_message_spec.rb'
- 'spec/models/wiki_page_spec.rb'
- 'spec/routing/admin_routing_spec.rb' - 'spec/routing/admin_routing_spec.rb'
- 'spec/rubocop/cop/migration/update_large_table_spec.rb' - 'spec/rubocop/cop/migration/update_large_table_spec.rb'
- 'spec/services/notification_service_spec.rb' - 'spec/services/notification_service_spec.rb'
- 'spec/services/web_hook_service_spec.rb' - 'spec/services/web_hook_service_spec.rb'
- 'ee/spec/models/group_spec.rb'
- 'ee/spec/services/boards/lists/update_service_spec.rb' - 'ee/spec/services/boards/lists/update_service_spec.rb'
- 'ee/spec/services/geo/repository_verification_primary_service_spec.rb' - 'ee/spec/services/geo/repository_verification_primary_service_spec.rb'
...@@ -250,7 +250,7 @@ export default { ...@@ -250,7 +250,7 @@ export default {
}, },
}, },
created() { created() {
this.setEndpoints({ this.setInitialState({
metricsEndpoint: this.metricsEndpoint, metricsEndpoint: this.metricsEndpoint,
deploymentsEndpoint: this.deploymentsEndpoint, deploymentsEndpoint: this.deploymentsEndpoint,
dashboardEndpoint: this.dashboardEndpoint, dashboardEndpoint: this.dashboardEndpoint,
...@@ -258,6 +258,7 @@ export default { ...@@ -258,6 +258,7 @@ export default {
currentDashboard: this.currentDashboard, currentDashboard: this.currentDashboard,
projectPath: this.projectPath, projectPath: this.projectPath,
logsPath: this.logsPath, logsPath: this.logsPath,
currentEnvironmentName: this.currentEnvironmentName,
}); });
}, },
mounted() { mounted() {
...@@ -273,7 +274,7 @@ export default { ...@@ -273,7 +274,7 @@ export default {
'setTimeRange', 'setTimeRange',
'fetchData', 'fetchData',
'setGettingStartedEmptyState', 'setGettingStartedEmptyState',
'setEndpoints', 'setInitialState',
'setPanelGroupMetrics', 'setPanelGroupMetrics',
'filterEnvironments', 'filterEnvironments',
]), ]),
......
...@@ -64,7 +64,10 @@ export default { ...@@ -64,7 +64,10 @@ export default {
}, },
}, },
mounted() { mounted() {
this.setInitialState(); this.setInitialState({
dashboardEndpoint: removeTimeRangeParams(this.dashboardUrl),
});
this.setShowErrorBanner(false);
this.setTimeRange(this.timeRange); this.setTimeRange(this.timeRange);
this.fetchDashboard(); this.fetchDashboard();
...@@ -90,11 +93,8 @@ export default { ...@@ -90,11 +93,8 @@ export default {
fetchDashboard(dispatch, payload) { fetchDashboard(dispatch, payload) {
return dispatch(`${this.namespace}/fetchDashboard`, payload); return dispatch(`${this.namespace}/fetchDashboard`, payload);
}, },
setEndpoints(dispatch, payload) { setInitialState(dispatch, payload) {
return dispatch(`${this.namespace}/setEndpoints`, payload); return dispatch(`${this.namespace}/setInitialState`, payload);
},
setFeatureFlags(dispatch, payload) {
return dispatch(`${this.namespace}/setFeatureFlags`, payload);
}, },
setShowErrorBanner(dispatch, payload) { setShowErrorBanner(dispatch, payload) {
return dispatch(`${this.namespace}/setShowErrorBanner`, payload); return dispatch(`${this.namespace}/setShowErrorBanner`, payload);
...@@ -108,12 +108,6 @@ export default { ...@@ -108,12 +108,6 @@ export default {
this.elWidth = this.$el.clientWidth; this.elWidth = this.$el.clientWidth;
}, sidebarAnimationDuration); }, sidebarAnimationDuration);
}, },
setInitialState() {
this.setEndpoints({
dashboardEndpoint: removeTimeRangeParams(this.dashboardUrl),
});
this.setShowErrorBanner(false);
},
}, },
}; };
</script> </script>
......
...@@ -79,3 +79,28 @@ export const dateFormats = { ...@@ -79,3 +79,28 @@ export const dateFormats = {
timeOfDay: 'h:MM TT', timeOfDay: 'h:MM TT',
default: 'dd mmm yyyy, h:MMTT', default: 'dd mmm yyyy, h:MMTT',
}; };
/**
* These Vuex store properties are allowed to be
* replaced dynamically after component has been created
* and initial state has been set.
*
* Currently used in `receiveMetricsDashboardSuccess` action.
*/
export const endpointKeys = [
'metricsEndpoint',
'deploymentsEndpoint',
'dashboardEndpoint',
'dashboardsEndpoint',
'currentDashboard',
'projectPath',
'logsPath',
];
/**
* These Vuex store properties are set as soon as the
* dashboard component has been created. The values are
* passed as data-* attributes and received by dashboard
* as Vue props.
*/
export const initialStateKeys = [...endpointKeys, 'currentEnvironmentName'];
...@@ -30,8 +30,8 @@ export const setGettingStartedEmptyState = ({ commit }) => { ...@@ -30,8 +30,8 @@ export const setGettingStartedEmptyState = ({ commit }) => {
commit(types.SET_GETTING_STARTED_EMPTY_STATE); commit(types.SET_GETTING_STARTED_EMPTY_STATE);
}; };
export const setEndpoints = ({ commit }, endpoints) => { export const setInitialState = ({ commit }, initialState) => {
commit(types.SET_ENDPOINTS, endpoints); commit(types.SET_INITIAL_STATE, initialState);
}; };
export const setTimeRange = ({ commit }, timeRange) => { export const setTimeRange = ({ commit }, timeRange) => {
......
...@@ -17,6 +17,7 @@ export const RECEIVE_METRIC_RESULT_FAILURE = 'RECEIVE_METRIC_RESULT_FAILURE'; ...@@ -17,6 +17,7 @@ export const RECEIVE_METRIC_RESULT_FAILURE = 'RECEIVE_METRIC_RESULT_FAILURE';
export const SET_TIME_RANGE = 'SET_TIME_RANGE'; export const SET_TIME_RANGE = 'SET_TIME_RANGE';
export const SET_ALL_DASHBOARDS = 'SET_ALL_DASHBOARDS'; export const SET_ALL_DASHBOARDS = 'SET_ALL_DASHBOARDS';
export const SET_ENDPOINTS = 'SET_ENDPOINTS'; export const SET_ENDPOINTS = 'SET_ENDPOINTS';
export const SET_INITIAL_STATE = 'SET_INITIAL_STATE';
export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE'; export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE';
export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE'; export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE';
export const SET_SHOW_ERROR_BANNER = 'SET_SHOW_ERROR_BANNER'; export const SET_SHOW_ERROR_BANNER = 'SET_SHOW_ERROR_BANNER';
......
...@@ -3,7 +3,7 @@ import pick from 'lodash/pick'; ...@@ -3,7 +3,7 @@ import pick from 'lodash/pick';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { mapToDashboardViewModel, normalizeQueryResult } from './utils'; import { mapToDashboardViewModel, normalizeQueryResult } from './utils';
import { BACKOFF_TIMEOUT } from '../../lib/utils/common_utils'; import { BACKOFF_TIMEOUT } from '../../lib/utils/common_utils';
import { metricStates } from '../constants'; import { endpointKeys, initialStateKeys, metricStates } from '../constants';
import httpStatusCodes from '~/lib/utils/http_status'; import httpStatusCodes from '~/lib/utils/http_status';
/** /**
...@@ -150,19 +150,11 @@ export default { ...@@ -150,19 +150,11 @@ export default {
state: emptyStateFromError(error), state: emptyStateFromError(error),
}); });
}, },
[types.SET_INITIAL_STATE](state, initialState = {}) {
Object.assign(state, pick(initialState, initialStateKeys));
},
[types.SET_ENDPOINTS](state, endpoints = {}) { [types.SET_ENDPOINTS](state, endpoints = {}) {
const endpointKeys = [ Object.assign(state, pick(endpoints, endpointKeys));
'metricsEndpoint',
'deploymentsEndpoint',
'dashboardEndpoint',
'dashboardsEndpoint',
'currentDashboard',
'projectPath',
'logsPath',
];
Object.entries(pick(endpoints, endpointKeys)).forEach(([key, value]) => {
state[key] = value;
});
}, },
[types.SET_TIME_RANGE](state, timeRange) { [types.SET_TIME_RANGE](state, timeRange) {
state.timeRange = timeRange; state.timeRange = timeRange;
......
...@@ -103,7 +103,7 @@ export default { ...@@ -103,7 +103,7 @@ export default {
<div v-else-if="shouldRenderSuccessState" class="js-success-state"> <div v-else-if="shouldRenderSuccessState" class="js-success-state">
<release-block <release-block
v-for="(release, index) in releases" v-for="(release, index) in releases"
:key="release.tagName" :key="index"
:release="release" :release="release"
:class="{ 'linked-card': releases.length > 1 && index !== releases.length - 1 }" :class="{ 'linked-card': releases.length > 1 && index !== releases.length - 1 }"
/> />
......
...@@ -37,7 +37,11 @@ export default { ...@@ -37,7 +37,11 @@ export default {
}; };
}, },
computed: { computed: {
id() { htmlId() {
if (!this.release.tagName) {
return null;
}
return slugify(this.release.tagName); return slugify(this.release.tagName);
}, },
assets() { assets() {
...@@ -72,7 +76,7 @@ export default { ...@@ -72,7 +76,7 @@ export default {
this.renderGFM(); this.renderGFM();
const hash = getLocationHash(); const hash = getLocationHash();
if (hash && slugify(hash) === this.id) { if (hash && slugify(hash) === this.htmlId) {
this.isHighlighted = true; this.isHighlighted = true;
setTimeout(() => { setTimeout(() => {
this.isHighlighted = false; this.isHighlighted = false;
...@@ -89,7 +93,7 @@ export default { ...@@ -89,7 +93,7 @@ export default {
}; };
</script> </script>
<template> <template>
<div :id="id" :class="{ 'bg-line-target-blue': isHighlighted }" class="card release-block"> <div :id="htmlId" :class="{ 'bg-line-target-blue': isHighlighted }" class="card release-block">
<release-block-header :release="release" /> <release-block-header :release="release" />
<div class="card-body"> <div class="card-body">
<div v-if="shouldRenderMilestoneInfo"> <div v-if="shouldRenderMilestoneInfo">
......
...@@ -15,7 +15,7 @@ class ReactiveCachingWorker # rubocop:disable Scalability/IdempotentWorker ...@@ -15,7 +15,7 @@ class ReactiveCachingWorker # rubocop:disable Scalability/IdempotentWorker
def self.context_for_arguments(arguments) def self.context_for_arguments(arguments)
class_name, *_other_args = arguments class_name, *_other_args = arguments
Gitlab::ApplicationContext.new(related_class: class_name) Gitlab::ApplicationContext.new(related_class: class_name.to_s)
end end
def perform(class_name, id, *args) def perform(class_name, id, *args)
......
---
title: Fix Releases page for Guest users of private projects
merge_request: 28447
author:
type: fixed
---
title: Refactor duplicate member specs
merge_request: 28574
author: Rajendra Kadam
type: added
---
title: Refactor duplicate specs in wiki page specs
merge_request: 28551
author: Rajendra Kadam
type: added
...@@ -1460,6 +1460,15 @@ Example response: ...@@ -1460,6 +1460,15 @@ Example response:
``` ```
```` ````
### Fake user information
You may need to demonstrate an API call or a cURL command that includes the name
and email address of a user. Don't use real user information in API calls:
- **Email addresses**: Use an email address ending in `example.com`.
- **Names**: Use strings like `Example Username`. Alternatively, use diverse or non-gendered names with
common surnames, such as `Sidney Jones`, `Zhang Wei`. or `Maria Garcia`.
### Fake tokens ### Fake tokens
There may be times where a token is needed to demonstrate an API call using There may be times where a token is needed to demonstrate an API call using
......
...@@ -170,6 +170,7 @@ using environment variables. ...@@ -170,6 +170,7 @@ using environment variables.
| Environment Variable | Description | Default | | Environment Variable | Description | Default |
| ------ | ------ | ------ | | ------ | ------ | ------ |
| `KLAR_TRACE` | Set to true to enable more verbose output from klar. | `"false"` | | `KLAR_TRACE` | Set to true to enable more verbose output from klar. | `"false"` |
| `CLAIR_TRACE` | Set to true to enable more verbose output from the clair server process. | `"false"` |
| `DOCKER_USER` | Username for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_USER` | | `DOCKER_USER` | Username for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_USER` |
| `DOCKER_PASSWORD` | Password for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_PASSWORD` | | `DOCKER_PASSWORD` | Password for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_PASSWORD` |
| `CLAIR_OUTPUT` | Severity level threshold. Vulnerabilities with severity level higher than or equal to this threshold will be outputted. Supported levels are `Unknown`, `Negligible`, `Low`, `Medium`, `High`, `Critical` and `Defcon1`. | `Unknown` | | `CLAIR_OUTPUT` | Severity level threshold. Vulnerabilities with severity level higher than or equal to this threshold will be outputted. Supported levels are `Unknown`, `Negligible`, `Low`, `Medium`, `High`, `Critical` and `Defcon1`. | `Unknown` |
......
...@@ -168,15 +168,15 @@ requires [GraphQL](../../../api/graphql/index.md) to be enabled. ...@@ -168,15 +168,15 @@ requires [GraphQL](../../../api/graphql/index.md) to be enabled.
### Status **(ULTIMATE)** ### Status **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/36427) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.9. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/36427) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.10.
To help you track the status of your issues, you can assign a status to each issue to flag work that's progressing as planned or needs attention to keep on schedule: To help you track the status of your issues, you can assign a status to each issue to flag work that's progressing as planned or needs attention to keep on schedule:
- `On track` (green) - **On track** (green)
- `Needs attention` (amber) - **Needs attention** (amber)
- `At risk` (red) - **At risk** (red)
!["On track" health status on an issue](img/issue_health_status_v12_9.png) !["On track" health status on an issue](img/issue_health_status_v12_10.png)
--- ---
......
...@@ -24701,6 +24701,9 @@ msgstr "" ...@@ -24701,6 +24701,9 @@ msgstr ""
msgid "remove due date" msgid "remove due date"
msgstr "" msgstr ""
msgid "remove status"
msgstr ""
msgid "remove weight" msgid "remove weight"
msgstr "" msgstr ""
......
...@@ -51,9 +51,7 @@ module QA ...@@ -51,9 +51,7 @@ module QA
metadata[:type] = :feature metadata[:type] = :feature
end end
config.around(:each) do |example| config.append_after(:each) do |example|
example.run
if example.metadata[:screenshot] if example.metadata[:screenshot]
screenshot = example.metadata[:screenshot][:image] || example.metadata[:screenshot][:html] screenshot = example.metadata[:screenshot][:image] || example.metadata[:screenshot][:html]
example.metadata[:stdout] = %{[[ATTACHMENT|#{screenshot}]]} example.metadata[:stdout] = %{[[ATTACHMENT|#{screenshot}]]}
......
...@@ -3,41 +3,33 @@ ...@@ -3,41 +3,33 @@
require 'spec_helper' require 'spec_helper'
describe 'User views releases', :js do describe 'User views releases', :js do
let!(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository, :private) }
let!(:release) { create(:release, project: project ) } let_it_be(:release) { create(:release, project: project, name: 'The first release' ) }
let!(:user) { create(:user) } let_it_be(:maintainer) { create(:user) }
let_it_be(:guest) { create(:user) }
before do before do
project.add_maintainer(user) project.add_maintainer(maintainer)
project.add_guest(guest)
gitlab_sign_in(user)
end end
it 'sees the release' do context('when the user is a maintainer') do
visit project_releases_path(project) before do
gitlab_sign_in(maintainer)
expect(page).to have_content(release.name) end
expect(page).to have_content(release.tag)
expect(page).not_to have_content('Upcoming Release')
end
context 'when there is a link as an asset' do
let!(:release_link) { create(:release_link, release: release, url: url ) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath }
it 'sees the link' do it 'sees the release' do
visit project_releases_path(project) visit project_releases_path(project)
page.within('.js-assets-list') do expect(page).to have_content(release.name)
expect(page).to have_link release_link.name, href: direct_asset_link expect(page).to have_content(release.tag)
expect(page).not_to have_content('(external source)') expect(page).not_to have_content('Upcoming Release')
end
end end
context 'when there is a link redirect' do context 'when there is a link as an asset' do
let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) } let!(:release_link) { create(:release_link, release: release, url: url ) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath }
it 'sees the link' do it 'sees the link' do
visit project_releases_path(project) visit project_releases_path(project)
...@@ -47,39 +39,73 @@ describe 'User views releases', :js do ...@@ -47,39 +39,73 @@ describe 'User views releases', :js do
expect(page).not_to have_content('(external source)') expect(page).not_to have_content('(external source)')
end end
end end
end
context 'when url points to external resource' do context 'when there is a link redirect' do
let(:url) { 'http://google.com/download' } let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
it 'sees that the link is external resource' do it 'sees the link' do
visit project_releases_path(project) visit project_releases_path(project)
page.within('.js-assets-list') do page.within('.js-assets-list') do
expect(page).to have_content('(external source)') expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_content('(external source)')
end
end
end
context 'when url points to external resource' do
let(:url) { 'http://google.com/download' }
it 'sees that the link is external resource' do
visit project_releases_path(project)
page.within('.js-assets-list') do
expect(page).to have_content('(external source)')
end
end end
end end
end end
end
context 'with an upcoming release' do context 'with an upcoming release' do
let(:tomorrow) { Time.zone.now + 1.day } let(:tomorrow) { Time.zone.now + 1.day }
let!(:release) { create(:release, project: project, released_at: tomorrow ) } let!(:release) { create(:release, project: project, released_at: tomorrow ) }
it 'sees the upcoming tag' do it 'sees the upcoming tag' do
visit project_releases_path(project) visit project_releases_path(project)
expect(page).to have_content('Upcoming Release')
end
end
context 'with a tag containing a slash' do
it 'sees the release' do
release = create :release, :with_evidence, project: project, tag: 'debian/2.4.0-1'
visit project_releases_path(project)
expect(page).to have_content('Upcoming Release') expect(page).to have_content(release.name)
expect(page).to have_content(release.tag)
end
end end
end end
context 'with a tag containing a slash' do context('when the user is a guest') do
it 'sees the release' do before do
release = create :release, :with_evidence, project: project, tag: 'debian/2.4.0-1' gitlab_sign_in(guest)
end
it 'renders release info except for Git-related data' do
visit project_releases_path(project) visit project_releases_path(project)
expect(page).to have_content(release.name) within('.release-block') do
expect(page).to have_content(release.tag) expect(page).to have_content(release.description)
# The following properties (sometimes) include Git info,
# so they are not rendered for Guest users
expect(page).not_to have_content(release.name)
expect(page).not_to have_content(release.tag)
expect(page).not_to have_content(release.commit.short_id)
end
end end
end end
end end
...@@ -88,11 +88,17 @@ describe('Dashboard', () => { ...@@ -88,11 +88,17 @@ describe('Dashboard', () => {
expect(findEnvironmentsDropdown().exists()).toBe(true); expect(findEnvironmentsDropdown().exists()).toBe(true);
}); });
it('sets endpoints: logs path', () => { it('sets initial state', () => {
expect(store.dispatch).toHaveBeenCalledWith( expect(store.dispatch).toHaveBeenCalledWith('monitoringDashboard/setInitialState', {
'monitoringDashboard/setEndpoints', currentDashboard: '',
expect.objectContaining({ logsPath: propsData.logsPath }), currentEnvironmentName: 'production',
); dashboardEndpoint: 'https://invalid',
dashboardsEndpoint: 'https://invalid',
deploymentsEndpoint: null,
logsPath: '/path/to/logs',
metricsEndpoint: 'http://test.host/monitoring/mock',
projectPath: '/path/to/project',
});
}); });
}); });
......
...@@ -26,9 +26,8 @@ describe('MetricEmbed', () => { ...@@ -26,9 +26,8 @@ describe('MetricEmbed', () => {
beforeEach(() => { beforeEach(() => {
actions = { actions = {
setFeatureFlags: jest.fn(), setInitialState: jest.fn(),
setShowErrorBanner: jest.fn(), setShowErrorBanner: jest.fn(),
setEndpoints: jest.fn(),
setTimeRange: jest.fn(), setTimeRange: jest.fn(),
fetchDashboard: jest.fn(), fetchDashboard: jest.fn(),
}; };
......
...@@ -16,7 +16,7 @@ import { ...@@ -16,7 +16,7 @@ import {
fetchEnvironmentsData, fetchEnvironmentsData,
fetchPrometheusMetrics, fetchPrometheusMetrics,
fetchPrometheusMetric, fetchPrometheusMetric,
setEndpoints, setInitialState,
filterEnvironments, filterEnvironments,
setGettingStartedEmptyState, setGettingStartedEmptyState,
duplicateSystemDashboard, duplicateSystemDashboard,
...@@ -208,14 +208,14 @@ describe('Monitoring store actions', () => { ...@@ -208,14 +208,14 @@ describe('Monitoring store actions', () => {
}); });
}); });
describe('Set endpoints', () => { describe('Set initial state', () => {
let mockedState; let mockedState;
beforeEach(() => { beforeEach(() => {
mockedState = storeState(); mockedState = storeState();
}); });
it('should commit SET_ENDPOINTS mutation', done => { it('should commit SET_INITIAL_STATE mutation', done => {
testAction( testAction(
setEndpoints, setInitialState,
{ {
metricsEndpoint: 'additional_metrics.json', metricsEndpoint: 'additional_metrics.json',
deploymentsEndpoint: 'deployments.json', deploymentsEndpoint: 'deployments.json',
...@@ -223,7 +223,7 @@ describe('Monitoring store actions', () => { ...@@ -223,7 +223,7 @@ describe('Monitoring store actions', () => {
mockedState, mockedState,
[ [
{ {
type: types.SET_ENDPOINTS, type: types.SET_INITIAL_STATE,
payload: { payload: {
metricsEndpoint: 'additional_metrics.json', metricsEndpoint: 'additional_metrics.json',
deploymentsEndpoint: 'deployments.json', deploymentsEndpoint: 'deployments.json',
......
...@@ -86,6 +86,58 @@ describe('Monitoring mutations', () => { ...@@ -86,6 +86,58 @@ describe('Monitoring mutations', () => {
expect(typeof stateCopy.deploymentData[0]).toEqual('object'); expect(typeof stateCopy.deploymentData[0]).toEqual('object');
}); });
}); });
describe('SET_INITIAL_STATE', () => {
it('should set all the endpoints', () => {
mutations[types.SET_INITIAL_STATE](stateCopy, {
metricsEndpoint: 'additional_metrics.json',
deploymentsEndpoint: 'deployments.json',
dashboardEndpoint: 'dashboard.json',
projectPath: '/gitlab-org/gitlab-foss',
currentEnvironmentName: 'production',
});
expect(stateCopy.metricsEndpoint).toEqual('additional_metrics.json');
expect(stateCopy.deploymentsEndpoint).toEqual('deployments.json');
expect(stateCopy.dashboardEndpoint).toEqual('dashboard.json');
expect(stateCopy.projectPath).toEqual('/gitlab-org/gitlab-foss');
expect(stateCopy.currentEnvironmentName).toEqual('production');
});
it('should not remove previously set properties', () => {
const defaultLogsPath = stateCopy.logsPath;
mutations[types.SET_INITIAL_STATE](stateCopy, {
logsPath: defaultLogsPath,
});
mutations[types.SET_INITIAL_STATE](stateCopy, {
dashboardEndpoint: 'dashboard.json',
});
mutations[types.SET_INITIAL_STATE](stateCopy, {
projectPath: '/gitlab-org/gitlab-foss',
});
mutations[types.SET_INITIAL_STATE](stateCopy, {
currentEnvironmentName: 'canary',
});
expect(stateCopy).toMatchObject({
logsPath: defaultLogsPath,
dashboardEndpoint: 'dashboard.json',
projectPath: '/gitlab-org/gitlab-foss',
currentEnvironmentName: 'canary',
});
});
it('should not update unknown properties', () => {
mutations[types.SET_INITIAL_STATE](stateCopy, {
dashboardEndpoint: 'dashboard.json',
someOtherProperty: 'some invalid value', // someOtherProperty is not allowed
});
expect(stateCopy.dashboardEndpoint).toBe('dashboard.json');
expect(stateCopy.someOtherProperty).toBeUndefined();
});
});
describe('SET_ENDPOINTS', () => { describe('SET_ENDPOINTS', () => {
it('should set all the endpoints', () => { it('should set all the endpoints', () => {
mutations[types.SET_ENDPOINTS](stateCopy, { mutations[types.SET_ENDPOINTS](stateCopy, {
......
...@@ -165,6 +165,14 @@ describe('Release block', () => { ...@@ -165,6 +165,14 @@ describe('Release block', () => {
}); });
}); });
it('does not set the ID if tagName is missing', () => {
release.tagName = undefined;
return factory(release).then(() => {
expect(wrapper.attributes().id).toBeUndefined();
});
});
describe('evidence block', () => { describe('evidence block', () => {
it('renders the evidence block when the evidence is available and the feature flag is true', () => it('renders the evidence block when the evidence is available and the feature flag is true', () =>
factory(release, { releaseEvidenceCollection: true }).then(() => factory(release, { releaseEvidenceCollection: true }).then(() =>
......
...@@ -38,10 +38,6 @@ describe Member do ...@@ -38,10 +38,6 @@ describe Member do
expect(member).not_to be_valid expect(member).not_to be_valid
end end
it "is valid otherwise" do
expect(member).to be_valid
end
end end
context "when an invite email is not provided" do context "when an invite email is not provided" do
......
...@@ -577,6 +577,8 @@ describe WikiPage do ...@@ -577,6 +577,8 @@ describe WikiPage do
end end
it 'returns false when version is nil' do it 'returns false when version is nil' do
expect(latest_page).to receive(:version) { nil }
expect(latest_page.historical?).to be_falsy expect(latest_page.historical?).to be_falsy
end end
......
...@@ -37,5 +37,13 @@ describe ReactiveCachingWorker do ...@@ -37,5 +37,13 @@ describe ReactiveCachingWorker do
expect(scheduled_job).to include('meta.related_class' => 'Environment') expect(scheduled_job).to include('meta.related_class' => 'Environment')
end end
it 'sets the related class on the job when it was passed as a class' do
described_class.perform_async(Project, 1, 'other', 'argument')
scheduled_job = described_class.jobs.first
expect(scheduled_job).to include('meta.related_class' => 'Project')
end
end 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