Skip to content
Snippets Groups Projects
Commit 2c156e3c authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 8e129497
No related branches found
No related tags found
No related merge requests found
Showing
with 809 additions and 47 deletions
Loading
Loading
@@ -67,6 +67,14 @@ FactoryBot.define do
end
end
 
trait :with_coverage_reports do
status { :success }
after(:build) do |pipeline, evaluator|
pipeline.builds << build(:ci_build, :coverage_reports, pipeline: pipeline, project: pipeline.project)
end
end
trait :with_exposed_artifacts do
status { :success }
 
Loading
Loading
Loading
Loading
@@ -121,6 +121,18 @@ FactoryBot.define do
end
end
 
trait :with_coverage_reports do
after(:build) do |merge_request|
merge_request.head_pipeline = build(
:ci_pipeline,
:success,
:with_coverage_reports,
project: merge_request.source_project,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha)
end
end
trait :with_exposed_artifacts do
after(:build) do |merge_request|
merge_request.head_pipeline = build(
Loading
Loading
Loading
Loading
@@ -190,7 +190,7 @@ describe 'Merge request > User sees avatars on diff notes', :js do
 
def find_line(line_code)
line = find("[id='#{line_code}']")
line = line.find(:xpath, 'preceding-sibling::*[1][self::td]') if line.tag_name == 'td'
line = line.find(:xpath, 'preceding-sibling::*[1][self::td]/preceding-sibling::*[1][self::td]') if line.tag_name == 'td'
line
end
end
Loading
Loading
@@ -17,7 +17,8 @@
"path": { "type": "string" },
"name": { "type": "string" },
"username": { "type": "string" },
"status_tooltip_html": { "$ref": "../types/nullable_string.json" }
"status_tooltip_html": { "$ref": "../types/nullable_string.json" },
"is_gitlab_employee": { "type": "boolean" }
},
"additionalProperties": false
}
<?xml version='1.0'?>
<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">
<!-- cobertura example file - generated by simplecov-cobertura - subset of gitlab-org/gitlab - manually modified -->
<!-- Generated by simplecov-cobertura version 1.3.1 (https://github.com/dashingrocket/simplecov-cobertura) -->
<coverage line-rate="0.5" branch-rate="0" lines-covered="73865" lines-valid="147397" branches-covered="0" branches-valid="0" complexity="0" version="0" timestamp="1577128350">
<sources>
<source>/tmp/projects/gitlab-ce/gitlab</source>
</sources>
<packages>
<package name="Controllers" line-rate="0.43" branch-rate="0" complexity="0">
<classes>
<class name="abuse_reports_controller" filename="app/controllers/abuse_reports_controller.rb" line-rate="0.3" branch-rate="0" complexity="0">
<methods/>
<lines>
<line number="3" branch="false" hits="1"/>
<line number="4" branch="false" hits="1"/>
<line number="6" branch="false" hits="1"/>
<line number="7" branch="false" hits="0"/>
<line number="8" branch="false" hits="0"/>
<line number="9" branch="false" hits="0"/>
<line number="12" branch="false" hits="1"/>
<line number="13" branch="false" hits="0"/>
<line number="14" branch="false" hits="0"/>
<line number="16" branch="false" hits="0"/>
<line number="17" branch="false" hits="0"/>
<line number="19" branch="false" hits="0"/>
<line number="20" branch="false" hits="0"/>
<line number="22" branch="false" hits="0"/>
<line number="26" branch="false" hits="1"/>
<line number="28" branch="false" hits="1"/>
<line number="29" branch="false" hits="0"/>
<line number="36" branch="false" hits="1"/>
<line number="37" branch="false" hits="0"/>
<line number="39" branch="false" hits="0"/>
<line number="40" branch="false" hits="0"/>
<line number="41" branch="false" hits="0"/>
<line number="42" branch="false" hits="0"/>
</lines>
</class>
</classes>
</package>
</packages>
</coverage>
\ No newline at end of file
File added
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">
<!-- cobertura example file - generated by gocov-xml - subset of gitlab-org/gitaly -->
<coverage line-rate="0.7966102" branch-rate="0" lines-covered="47" lines-valid="59" branches-covered="0" branches-valid="0" complexity="0" version="" timestamp="1577127162320">
<packages>
<package name="gitlab.com/gitlab-org/gitaly/auth" line-rate="0.7966102" branch-rate="0" complexity="0" line-count="59" line-hits="47">
<classes>
<class name="-" filename="auth/rpccredentials.go" line-rate="0.2" branch-rate="0" complexity="0" line-count="5" line-hits="1">
<methods>
<method name="RPCCredentials" signature="" line-rate="1" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="17" hits="1"></line>
</lines>
</method>
<method name="RPCCredentialsV2" signature="" line-rate="0" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="34" hits="0"></line>
</lines>
</method>
<method name="hmacToken" signature="" line-rate="0" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="52" hits="0"></line>
<line number="53" hits="0"></line>
<line number="55" hits="0"></line>
</lines>
</method>
</methods>
<lines>
<line number="17" hits="1"></line>
<line number="34" hits="0"></line>
<line number="52" hits="0"></line>
<line number="53" hits="0"></line>
<line number="55" hits="0"></line>
</lines>
</class>
<class name="rpcCredentials" filename="auth/rpccredentials.go" line-rate="0.5" branch-rate="0" complexity="0" line-count="2" line-hits="1">
<methods>
<method name="RequireTransportSecurity" signature="" line-rate="0" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="24" hits="0"></line>
</lines>
</method>
<method name="GetRequestMetadata" signature="" line-rate="1" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="27" hits="1"></line>
</lines>
</method>
</methods>
<lines>
<line number="24" hits="0"></line>
<line number="27" hits="1"></line>
</lines>
</class>
<class name="rpcCredentialsV2" filename="auth/rpccredentials.go" line-rate="0" branch-rate="0" complexity="0" line-count="3" line-hits="0">
<methods>
<method name="RequireTransportSecurity" signature="" line-rate="0" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="41" hits="0"></line>
</lines>
</method>
<method name="GetRequestMetadata" signature="" line-rate="0" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="44" hits="0"></line>
</lines>
</method>
<method name="hmacToken" signature="" line-rate="0" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="48" hits="0"></line>
</lines>
</method>
</methods>
<lines>
<line number="41" hits="0"></line>
<line number="44" hits="0"></line>
<line number="48" hits="0"></line>
</lines>
</class>
<class name="-" filename="auth/token.go" line-rate="0.9183673" branch-rate="0" complexity="0" line-count="49" line-hits="45">
<methods>
<method name="init" signature="" line-rate="1" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="38" hits="1"></line>
</lines>
</method>
<method name="CheckToken" signature="" line-rate="0.9285714" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="52" hits="1"></line>
<line number="53" hits="0"></line>
<line number="56" hits="1"></line>
<line number="57" hits="1"></line>
<line number="58" hits="1"></line>
<line number="61" hits="1"></line>
<line number="63" hits="1"></line>
<line number="64" hits="1"></line>
<line number="65" hits="1"></line>
<line number="68" hits="1"></line>
<line number="69" hits="1"></line>
<line number="72" hits="1"></line>
<line number="73" hits="1"></line>
<line number="77" hits="1"></line>
</lines>
</method>
<method name="tokensEqual" signature="" line-rate="1" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="81" hits="1"></line>
</lines>
</method>
<method name="ExtractAuthInfo" signature="" line-rate="0.90909094" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="86" hits="1"></line>
<line number="88" hits="1"></line>
<line number="89" hits="1"></line>
<line number="92" hits="1"></line>
<line number="96" hits="1"></line>
<line number="97" hits="1"></line>
<line number="100" hits="1"></line>
<line number="101" hits="1"></line>
<line number="102" hits="1"></line>
<line number="103" hits="0"></line>
<line number="106" hits="1"></line>
</lines>
</method>
<method name="countV2Error" signature="" line-rate="1" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="109" hits="1"></line>
</lines>
</method>
<method name="v2HmacInfoValid" signature="" line-rate="0.8888889" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="112" hits="1"></line>
<line number="113" hits="1"></line>
<line number="114" hits="1"></line>
<line number="115" hits="1"></line>
<line number="118" hits="1"></line>
<line number="119" hits="1"></line>
<line number="120" hits="0"></line>
<line number="121" hits="0"></line>
<line number="124" hits="1"></line>
<line number="125" hits="1"></line>
<line number="126" hits="1"></line>
<line number="128" hits="1"></line>
<line number="129" hits="1"></line>
<line number="130" hits="1"></line>
<line number="133" hits="1"></line>
<line number="134" hits="1"></line>
<line number="135" hits="1"></line>
<line number="138" hits="1"></line>
</lines>
</method>
<method name="hmacSign" signature="" line-rate="1" branch-rate="0" complexity="0" line-count="0" line-hits="0">
<lines>
<line number="142" hits="1"></line>
<line number="143" hits="1"></line>
<line number="145" hits="1"></line>
</lines>
</method>
</methods>
<lines>
<line number="38" hits="1"></line>
<line number="52" hits="1"></line>
<line number="53" hits="0"></line>
<line number="56" hits="1"></line>
<line number="57" hits="1"></line>
<line number="58" hits="1"></line>
<line number="61" hits="1"></line>
<line number="63" hits="1"></line>
<line number="64" hits="1"></line>
<line number="65" hits="1"></line>
<line number="68" hits="1"></line>
<line number="69" hits="1"></line>
<line number="72" hits="1"></line>
<line number="73" hits="1"></line>
<line number="77" hits="1"></line>
<line number="81" hits="1"></line>
<line number="86" hits="1"></line>
<line number="88" hits="1"></line>
<line number="89" hits="1"></line>
<line number="92" hits="1"></line>
<line number="96" hits="1"></line>
<line number="97" hits="1"></line>
<line number="100" hits="1"></line>
<line number="101" hits="1"></line>
<line number="102" hits="1"></line>
<line number="103" hits="0"></line>
<line number="106" hits="1"></line>
<line number="109" hits="1"></line>
<line number="112" hits="1"></line>
<line number="113" hits="1"></line>
<line number="114" hits="1"></line>
<line number="115" hits="1"></line>
<line number="118" hits="1"></line>
<line number="119" hits="1"></line>
<line number="120" hits="0"></line>
<line number="121" hits="0"></line>
<line number="124" hits="1"></line>
<line number="125" hits="1"></line>
<line number="126" hits="1"></line>
<line number="128" hits="1"></line>
<line number="129" hits="1"></line>
<line number="130" hits="1"></line>
<line number="133" hits="1"></line>
<line number="134" hits="1"></line>
<line number="135" hits="1"></line>
<line number="138" hits="1"></line>
<line number="142" hits="1"></line>
<line number="143" hits="1"></line>
<line number="145" hits="1"></line>
</lines>
</class>
</classes>
</package>
</packages>
<sources>
<source>/tmp/projects/gitlab-ce/gitaly/src/gitlab.com/gitlab-org/gitaly</source>
</sources>
</coverage>
File added
<?xml version="1.0" ?>
<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">
<!-- cobertura example file - generated by NYC - manually modified -->
<coverage lines-valid="22" lines-covered="16" line-rate="0.7273000000000001" branches-valid="4" branches-covered="2" branch-rate="0.5" timestamp="1576756029756" complexity="0" version="0.1">
<sources>
<source>/tmp/projects/coverage-test</source>
</sources>
<packages>
<package name="coverage-test" line-rate="0.6842" branch-rate="0.5">
<classes>
<class name="index.js" filename="index.js" line-rate="0.6842" branch-rate="0.5">
<methods>
<method name="(anonymous_3)" hits="0" signature="()V">
<lines>
<line number="21" hits="0"/>
</lines>
</method>
</methods>
<lines>
<line number="21" hits="1" branch="false"/>
<line number="22" hits="0" branch="false"/>
<line number="25" hits="1" branch="true" condition-coverage="50% (1/2)"/>
<line number="26" hits="0" branch="false"/>
<line number="27" hits="0" branch="false"/>
<line number="28" hits="0" branch="false"/>
<line number="29" hits="0" branch="false"/>
</lines>
</class>
</classes>
</package>
<package name="coverage-test.lib.math" line-rate="1" branch-rate="1">
<classes>
<class name="add.js" filename="lib/math/add.js" line-rate="1" branch-rate="1">
<methods>
<method name="(anonymous_0)" hits="1" signature="()V">
<lines>
<line number="1" hits="1"/>
</lines>
</method>
</methods>
<lines>
<line null="test" hits="1" branch="false"/>
<line number="2" hits="1" branch="false"/>
<line number="3" hits="1" branch="false"/>
</lines>
</class>
</classes>
</package>
</packages>
</coverage>
File added
Loading
Loading
@@ -13,6 +13,7 @@ localVue.use(Vuex);
describe('EksClusterConfigurationForm', () => {
let store;
let actions;
let getters;
let state;
let rolesState;
let regionsState;
Loading
Loading
@@ -29,8 +30,7 @@ describe('EksClusterConfigurationForm', () => {
let securityGroupsActions;
let vm;
 
beforeEach(() => {
state = eksClusterFormState();
const createStore = (config = {}) => {
actions = {
createCluster: jest.fn(),
setClusterName: jest.fn(),
Loading
Loading
@@ -64,29 +64,44 @@ describe('EksClusterConfigurationForm', () => {
securityGroupsActions = {
fetchItems: jest.fn(),
};
state = {
...eksClusterFormState(),
...config.initialState,
};
rolesState = {
...clusterDropdownStoreState(),
...config.rolesState,
};
regionsState = {
...clusterDropdownStoreState(),
...config.regionsState,
};
vpcsState = {
...clusterDropdownStoreState(),
...config.vpcsState,
};
subnetsState = {
...clusterDropdownStoreState(),
...config.subnetsState,
};
keyPairsState = {
...clusterDropdownStoreState(),
...config.keyPairsState,
};
securityGroupsState = {
...clusterDropdownStoreState(),
...config.securityGroupsState,
};
instanceTypesState = {
...clusterDropdownStoreState(),
...config.instanceTypesState,
};
getters = {
subnetValid: config?.getters?.subnetValid || (() => false),
};
store = new Vuex.Store({
state,
getters,
actions,
modules: {
vpcs: {
Loading
Loading
@@ -125,9 +140,29 @@ describe('EksClusterConfigurationForm', () => {
},
},
});
});
};
 
beforeEach(() => {
const createValidStateStore = initialState => {
createStore({
initialState: {
clusterName: 'cluster name',
environmentScope: '*',
selectedRegion: 'region',
selectedRole: 'role',
selectedKeyPair: 'key pair',
selectedVpc: 'vpc',
selectedSubnet: ['subnet 1', 'subnet 2'],
selectedSecurityGroup: 'group',
selectedInstanceType: 'small-1',
...initialState,
},
getters: {
subnetValid: () => true,
},
});
};
const buildWrapper = () => {
vm = shallowMount(EksClusterConfigurationForm, {
localVue,
store,
Loading
Loading
@@ -137,27 +172,17 @@ describe('EksClusterConfigurationForm', () => {
externalLinkIcon: '',
},
});
};
beforeEach(() => {
createStore();
buildWrapper();
});
 
afterEach(() => {
vm.destroy();
});
 
const setAllConfigurationFields = () => {
store.replaceState({
...state,
clusterName: 'cluster name',
environmentScope: '*',
selectedRegion: 'region',
selectedRole: 'role',
selectedKeyPair: 'key pair',
selectedVpc: 'vpc',
selectedSubnet: 'subnet',
selectedSecurityGroup: 'group',
selectedInstanceType: 'small-1',
});
};
const findCreateClusterButton = () => vm.find('.js-create-cluster');
const findClusterNameInput = () => vm.find('[id=eks-cluster-name]');
const findEnvironmentScopeInput = () => vm.find('[id=eks-environment-scope]');
Loading
Loading
@@ -310,12 +335,29 @@ describe('EksClusterConfigurationForm', () => {
expect(findSubnetDropdown().props('items')).toBe(subnetsState.items);
});
 
it('sets SubnetDropdown hasErrors to true when loading subnets fails', () => {
subnetsState.loadingItemsError = new Error();
it('displays a validation error in the subnet dropdown when loading subnets fails', () => {
createStore({
subnetsState: {
loadingItemsError: new Error(),
},
});
buildWrapper();
 
return Vue.nextTick().then(() => {
expect(findSubnetDropdown().props('hasErrors')).toEqual(true);
expect(findSubnetDropdown().props('hasErrors')).toEqual(true);
});
it('displays a validation error in the subnet dropdown when a single subnet is selected', () => {
createStore({
initialState: {
selectedSubnet: ['subnet 1'],
},
});
buildWrapper();
expect(findSubnetDropdown().props('hasErrors')).toEqual(true);
expect(findSubnetDropdown().props('errorMessage')).toEqual(
'You should select at least two subnets',
);
});
 
it('disables SecurityGroupDropdown when no vpc is selected', () => {
Loading
Loading
@@ -386,11 +428,7 @@ describe('EksClusterConfigurationForm', () => {
});
 
it('cleans selected subnet', () => {
expect(actions.setSubnet).toHaveBeenCalledWith(
expect.anything(),
{ subnet: null },
undefined,
);
expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet: [] }, undefined);
});
 
it('cleans selected security group', () => {
Loading
Loading
@@ -464,11 +502,7 @@ describe('EksClusterConfigurationForm', () => {
});
 
it('cleans selected subnet', () => {
expect(actions.setSubnet).toHaveBeenCalledWith(
expect.anything(),
{ subnet: null },
undefined,
);
expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet: [] }, undefined);
});
 
it('cleans selected security group', () => {
Loading
Loading
@@ -573,22 +607,19 @@ describe('EksClusterConfigurationForm', () => {
});
 
describe('when all cluster configuration fields are set', () => {
beforeEach(() => {
setAllConfigurationFields();
});
it('enables create cluster button', () => {
createValidStateStore();
buildWrapper();
expect(findCreateClusterButton().props('disabled')).toBe(false);
});
});
 
describe('when at least one cluster configuration field is not set', () => {
beforeEach(() => {
setAllConfigurationFields();
store.replaceState({
...state,
clusterName: '',
createValidStateStore({
clusterName: null,
});
buildWrapper();
});
 
it('disables create cluster button', () => {
Loading
Loading
@@ -596,13 +627,12 @@ describe('EksClusterConfigurationForm', () => {
});
});
 
describe('when isCreatingCluster', () => {
describe('when is creating cluster', () => {
beforeEach(() => {
setAllConfigurationFields();
store.replaceState({
...state,
createValidStateStore({
isCreatingCluster: true,
});
buildWrapper();
});
 
it('sets create cluster button as loading', () => {
Loading
Loading
import { subnetValid } from '~/create_cluster/eks_cluster/store/getters';
describe('EKS Cluster Store Getters', () => {
describe('subnetValid', () => {
it('returns true if there are 2 or more selected subnets', () => {
expect(subnetValid({ selectedSubnet: [1, 2] })).toBe(true);
});
it.each([[[], [1]]])('returns false if there are 1 or less selected subnets', subnets => {
expect(subnetValid({ selectedSubnet: subnets })).toBe(false);
});
});
});
Loading
Loading
@@ -41,6 +41,7 @@ describe('diffs/components/app', () => {
endpoint: TEST_ENDPOINT,
endpointMetadata: `${TEST_HOST}/diff/endpointMetadata`,
endpointBatch: `${TEST_HOST}/diff/endpointBatch`,
endpointCoverage: `${TEST_HOST}/diff/endpointCoverage`,
projectPath: 'namespace/project',
currentUser: {},
changesEmptyStateIllustration: '',
Loading
Loading
@@ -95,6 +96,7 @@ describe('diffs/components/app', () => {
jest.spyOn(wrapper.vm, 'fetchDiffFiles').mockImplementation(fetchResolver);
jest.spyOn(wrapper.vm, 'fetchDiffFilesMeta').mockImplementation(fetchResolver);
jest.spyOn(wrapper.vm, 'fetchDiffFilesBatch').mockImplementation(fetchResolver);
jest.spyOn(wrapper.vm, 'fetchCoverageFiles').mockImplementation(fetchResolver);
jest.spyOn(wrapper.vm, 'setDiscussions').mockImplementation(() => {});
jest.spyOn(wrapper.vm, 'startRenderDiffsQueue').mockImplementation(() => {});
jest.spyOn(wrapper.vm, 'unwatchDiscussions').mockImplementation(() => {});
Loading
Loading
@@ -250,6 +252,7 @@ describe('diffs/components/app', () => {
expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesMeta).not.toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesBatch).not.toHaveBeenCalled();
expect(wrapper.vm.fetchCoverageFiles).toHaveBeenCalled();
expect(wrapper.vm.unwatchDiscussions).toHaveBeenCalled();
expect(wrapper.vm.diffFilesLength).toEqual(100);
expect(wrapper.vm.unwatchRetrievingBatches).toHaveBeenCalled();
Loading
Loading
@@ -269,6 +272,7 @@ describe('diffs/components/app', () => {
expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesMeta).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesBatch).toHaveBeenCalled();
expect(wrapper.vm.fetchCoverageFiles).toHaveBeenCalled();
expect(wrapper.vm.unwatchDiscussions).toHaveBeenCalled();
expect(wrapper.vm.diffFilesLength).toEqual(100);
expect(wrapper.vm.unwatchRetrievingBatches).toHaveBeenCalled();
Loading
Loading
@@ -286,6 +290,7 @@ describe('diffs/components/app', () => {
expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesMeta).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesBatch).toHaveBeenCalled();
expect(wrapper.vm.fetchCoverageFiles).toHaveBeenCalled();
expect(wrapper.vm.unwatchDiscussions).toHaveBeenCalled();
expect(wrapper.vm.diffFilesLength).toEqual(100);
expect(wrapper.vm.unwatchRetrievingBatches).toHaveBeenCalled();
Loading
Loading
Loading
Loading
@@ -12,6 +12,7 @@ describe('InlineDiffTableRow', () => {
vm = createComponentWithStore(Vue.extend(InlineDiffTableRow), createStore(), {
line: thisLine,
fileHash: diffFileMockData.file_hash,
filePath: diffFileMockData.file_path,
contextLinesPath: 'contextLinesPath',
isHighlighted: false,
}).$mount();
Loading
Loading
@@ -39,4 +40,64 @@ describe('InlineDiffTableRow', () => {
.then(done)
.catch(done.fail);
});
describe('sets coverage title and class', () => {
it('for lines with coverage', done => {
vm.$nextTick()
.then(() => {
const name = diffFileMockData.file_path;
const line = thisLine.new_line;
vm.$store.state.diffs.coverageFiles = { files: { [name]: { [line]: 5 } } };
return vm.$nextTick();
})
.then(() => {
const coverage = vm.$el.querySelector('.line-coverage');
expect(coverage.title).toContain('Test coverage: 5 hits');
expect(coverage.classList).toContain('coverage');
})
.then(done)
.catch(done.fail);
});
it('for lines without coverage', done => {
vm.$nextTick()
.then(() => {
const name = diffFileMockData.file_path;
const line = thisLine.new_line;
vm.$store.state.diffs.coverageFiles = { files: { [name]: { [line]: 0 } } };
return vm.$nextTick();
})
.then(() => {
const coverage = vm.$el.querySelector('.line-coverage');
expect(coverage.title).toContain('No test coverage');
expect(coverage.classList).toContain('no-coverage');
})
.then(done)
.catch(done.fail);
});
it('for unknown lines', done => {
vm.$nextTick()
.then(() => {
vm.$store.state.diffs.coverageFiles = {};
return vm.$nextTick();
})
.then(() => {
const coverage = vm.$el.querySelector('.line-coverage');
expect(coverage.title).not.toContain('Coverage');
expect(coverage.classList).not.toContain('coverage');
expect(coverage.classList).not.toContain('no-coverage');
})
.then(done)
.catch(done.fail);
});
});
});
Loading
Loading
@@ -14,6 +14,7 @@ describe('ParallelDiffTableRow', () => {
vm = createComponentWithStore(Vue.extend(ParallelDiffTableRow), createStore(), {
line: thisLine,
fileHash: diffFileMockData.file_hash,
filePath: diffFileMockData.file_path,
contextLinesPath: 'contextLinesPath',
isHighlighted: false,
}).$mount();
Loading
Loading
@@ -52,6 +53,7 @@ describe('ParallelDiffTableRow', () => {
vm = createComponentWithStore(Vue.extend(ParallelDiffTableRow), createStore(), {
line: thisLine,
fileHash: diffFileMockData.file_hash,
filePath: diffFileMockData.file_path,
contextLinesPath: 'contextLinesPath',
isHighlighted: false,
}).$mount();
Loading
Loading
@@ -81,5 +83,65 @@ describe('ParallelDiffTableRow', () => {
.then(done)
.catch(done.fail);
});
describe('sets coverage title and class', () => {
it('for lines with coverage', done => {
vm.$nextTick()
.then(() => {
const name = diffFileMockData.file_path;
const line = rightLine.new_line;
vm.$store.state.diffs.coverageFiles = { files: { [name]: { [line]: 5 } } };
return vm.$nextTick();
})
.then(() => {
const coverage = vm.$el.querySelector('.line-coverage.right-side');
expect(coverage.title).toContain('Test coverage: 5 hits');
expect(coverage.classList).toContain('coverage');
})
.then(done)
.catch(done.fail);
});
it('for lines without coverage', done => {
vm.$nextTick()
.then(() => {
const name = diffFileMockData.file_path;
const line = rightLine.new_line;
vm.$store.state.diffs.coverageFiles = { files: { [name]: { [line]: 0 } } };
return vm.$nextTick();
})
.then(() => {
const coverage = vm.$el.querySelector('.line-coverage.right-side');
expect(coverage.title).toContain('No test coverage');
expect(coverage.classList).toContain('no-coverage');
})
.then(done)
.catch(done.fail);
});
it('for unknown lines', done => {
vm.$nextTick()
.then(() => {
vm.$store.state.diffs.coverageFiles = {};
return vm.$nextTick();
})
.then(() => {
const coverage = vm.$el.querySelector('.line-coverage.right-side');
expect(coverage.title).not.toContain('Coverage');
expect(coverage.classList).not.toContain('coverage');
expect(coverage.classList).not.toContain('no-coverage');
})
.then(done)
.catch(done.fail);
});
});
});
});
Loading
Loading
@@ -12,6 +12,7 @@ import actions, {
fetchDiffFiles,
fetchDiffFilesBatch,
fetchDiffFilesMeta,
fetchCoverageFiles,
assignDiscussionsToDiff,
removeDiscussionsFromDiff,
startRenderDiffsQueue,
Loading
Loading
@@ -73,6 +74,7 @@ describe('DiffsStoreActions', () => {
const endpoint = '/diffs/set/endpoint';
const endpointMetadata = '/diffs/set/endpoint/metadata';
const endpointBatch = '/diffs/set/endpoint/batch';
const endpointCoverage = '/diffs/set/coverage_reports';
const projectPath = '/root/project';
const dismissEndpoint = '/-/user_callouts';
const showSuggestPopover = false;
Loading
Loading
@@ -84,6 +86,7 @@ describe('DiffsStoreActions', () => {
endpoint,
endpointBatch,
endpointMetadata,
endpointCoverage,
projectPath,
dismissEndpoint,
showSuggestPopover,
Loading
Loading
@@ -93,6 +96,7 @@ describe('DiffsStoreActions', () => {
endpoint: '',
endpointBatch: '',
endpointMetadata: '',
endpointCoverage: '',
projectPath: '',
dismissEndpoint: '',
showSuggestPopover: true,
Loading
Loading
@@ -105,6 +109,7 @@ describe('DiffsStoreActions', () => {
endpoint,
endpointMetadata,
endpointBatch,
endpointCoverage,
projectPath,
dismissEndpoint,
showSuggestPopover,
Loading
Loading
@@ -318,6 +323,44 @@ describe('DiffsStoreActions', () => {
});
});
 
describe('fetchCoverageFiles', () => {
let mock;
const endpointCoverage = '/fetch';
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => mock.restore());
it('should commit SET_COVERAGE_DATA with received response', done => {
const data = { files: { 'app.js': { '1': 0, '2': 1 } } };
mock.onGet(endpointCoverage).reply(200, { data });
testAction(
fetchCoverageFiles,
{},
{ endpointCoverage },
[{ type: types.SET_COVERAGE_DATA, payload: { data } }],
[],
done,
);
});
it('should show flash on API error', done => {
const flashSpy = spyOnDependency(actions, 'createFlash');
mock.onGet(endpointCoverage).reply(400);
testAction(fetchCoverageFiles, {}, { endpointCoverage }, [], [], () => {
expect(flashSpy).toHaveBeenCalledTimes(1);
expect(flashSpy).toHaveBeenCalledWith(jasmine.stringMatching('Something went wrong'));
done();
});
});
});
describe('setHighlightedRow', () => {
it('should mark currently selected diff and set lineHash and fileHash of highlightedRow', () => {
testAction(setHighlightedRow, 'ABC_123', {}, [
Loading
Loading
Loading
Loading
@@ -282,4 +282,34 @@ describe('Diffs Module Getters', () => {
expect(getters.currentDiffIndex(localState)).toEqual(0);
});
});
describe('fileLineCoverage', () => {
beforeEach(() => {
Object.assign(localState.coverageFiles, { files: { 'app.js': { '1': 0, '2': 5 } } });
});
it('returns empty object when no coverage data is available', () => {
Object.assign(localState.coverageFiles, {});
expect(getters.fileLineCoverage(localState)('test.js', 2)).toEqual({});
});
it('returns empty object when unknown filename is passed', () => {
expect(getters.fileLineCoverage(localState)('test.js', 2)).toEqual({});
});
it('returns no-coverage info when correct filename and line is passed', () => {
expect(getters.fileLineCoverage(localState)('app.js', 1)).toEqual({
text: 'No test coverage',
class: 'no-coverage',
});
});
it('returns coverage info when correct filename and line is passed', () => {
expect(getters.fileLineCoverage(localState)('app.js', 2)).toEqual({
text: 'Test coverage: 5 hits',
class: 'coverage',
});
});
});
});
Loading
Loading
@@ -123,6 +123,17 @@ describe('DiffsStoreMutations', () => {
});
});
 
describe('SET_COVERAGE_DATA', () => {
it('should set coverage data properly', () => {
const state = { coverageFiles: {} };
const coverage = { 'app.js': { '1': 0, '2': 1 } };
mutations[types.SET_COVERAGE_DATA](state, coverage);
expect(state.coverageFiles).toEqual(coverage);
});
});
describe('SET_DIFF_VIEW_TYPE', () => {
it('should set diff view type properly', () => {
const state = {};
Loading
Loading
Loading
Loading
@@ -45,6 +45,7 @@ describe Gitlab::Ci::Config::Entry::Reports do
:performance | 'performance.json'
:lsif | 'lsif.json'
:dotenv | 'build.dotenv'
:cobertura | 'cobertura-coverage.xml'
end
 
with_them do
Loading
Loading
# frozen_string_literal: true
require 'fast_spec_helper'
describe Gitlab::Ci::Parsers::Coverage::Cobertura do
describe '#parse!' do
subject { described_class.new.parse!(cobertura, coverage_report) }
let(:coverage_report) { Gitlab::Ci::Reports::CoverageReports.new }
context 'when data is Cobertura style XML' do
context 'when there is no <class>' do
let(:cobertura) { '' }
it 'parses XML and returns empty coverage' do
expect { subject }.not_to raise_error
expect(coverage_report.files).to eq({})
end
end
context 'when there is a single <class>' do
context 'with no lines' do
let(:cobertura) do
<<-EOF.strip_heredoc
<classes><class filename="app.rb"></class></classes>
EOF
end
it 'parses XML and returns empty coverage' do
expect { subject }.not_to raise_error
expect(coverage_report.files).to eq({})
end
end
context 'with a single line' do
let(:cobertura) do
<<-EOF.strip_heredoc
<classes>
<class filename="app.rb"><lines>
<line number="1" hits="2"/>
</lines></class>
</classes>
EOF
end
it 'parses XML and returns a single file with coverage' do
expect { subject }.not_to raise_error
expect(coverage_report.files).to eq({ 'app.rb' => { 1 => 2 } })
end
end
context 'with multipe lines and methods info' do
let(:cobertura) do
<<-EOF.strip_heredoc
<classes>
<class filename="app.rb"><methods/><lines>
<line number="1" hits="2"/>
<line number="2" hits="0"/>
</lines></class>
</classes>
EOF
end
it 'parses XML and returns a single file with coverage' do
expect { subject }.not_to raise_error
expect(coverage_report.files).to eq({ 'app.rb' => { 1 => 2, 2 => 0 } })
end
end
end
context 'when there are multipe <class>' do
context 'with the same filename and different lines' do
let(:cobertura) do
<<-EOF.strip_heredoc
<classes>
<class filename="app.rb"><methods/><lines>
<line number="1" hits="2"/>
<line number="2" hits="0"/>
</lines></class>
<class filename="app.rb"><methods/><lines>
<line number="6" hits="1"/>
<line number="7" hits="1"/>
</lines></class>
</classes>
EOF
end
it 'parses XML and returns a single file with merged coverage' do
expect { subject }.not_to raise_error
expect(coverage_report.files).to eq({ 'app.rb' => { 1 => 2, 2 => 0, 6 => 1, 7 => 1 } })
end
end
context 'with the same filename and lines' do
let(:cobertura) do
<<-EOF.strip_heredoc
<packages><package><classes>
<class filename="app.rb"><methods/><lines>
<line number="1" hits="2"/>
<line number="2" hits="0"/>
</lines></class>
<class filename="app.rb"><methods/><lines>
<line number="1" hits="1"/>
<line number="2" hits="1"/>
</lines></class>
</classes></package></packages>
EOF
end
it 'parses XML and returns a single file with summed-up coverage' do
expect { subject }.not_to raise_error
expect(coverage_report.files).to eq({ 'app.rb' => { 1 => 3, 2 => 1 } })
end
end
context 'with missing filename' do
let(:cobertura) do
<<-EOF.strip_heredoc
<classes>
<class filename="app.rb"><methods/><lines>
<line number="1" hits="2"/>
<line number="2" hits="0"/>
</lines></class>
<class><methods/><lines>
<line number="6" hits="1"/>
<line number="7" hits="1"/>
</lines></class>
</classes>
EOF
end
it 'parses XML and ignores class with missing name' do
expect { subject }.not_to raise_error
expect(coverage_report.files).to eq({ 'app.rb' => { 1 => 2, 2 => 0 } })
end
end
context 'with invalid line information' do
let(:cobertura) do
<<-EOF.strip_heredoc
<classes>
<class filename="app.rb"><methods/><lines>
<line number="1" hits="2"/>
<line number="2" hits="0"/>
</lines></class>
<class filename="app.rb"><methods/><lines>
<line null="test" hits="1"/>
<line number="7" hits="1"/>
</lines></class>
</classes>
EOF
end
it 'raises an error' do
expect { subject }.to raise_error(described_class::CoberturaParserError)
end
end
end
end
context 'when data is not Cobertura style XML' do
let(:cobertura) { { coverage: '12%' }.to_json }
it 'raises an error' do
expect { subject }.to raise_error(described_class::CoberturaParserError)
end
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment