Commit 7dfae341 authored by Neil McCorrison's avatar Neil McCorrison Committed by Vitaly Slobodin

Update secure License end to end tests

Given that the buttons for accepting or denying
licenses are being removed from the modals from
Merge Requests and Pipelines, this commit
updates the tests such that Licence Compliance
dashboard is used, but the licenses are updated
within Merge Requests and Pipelines.
parent 0e8c176d
...@@ -37,10 +37,7 @@ compliance report will be shown properly. ...@@ -37,10 +37,7 @@ compliance report will be shown properly.
![License Compliance Widget](img/license_compliance_v13_0.png) ![License Compliance Widget](img/license_compliance_v13_0.png)
If you are a project or group Maintainer, you can click on a license to be given You can click on a license to see more information.
the choice to allow it or deny it.
![License approval decision](img/license_compliance_decision_v13_0.png)
When GitLab detects a **Denied** license, you can view it in the [license list](#license-list). When GitLab detects a **Denied** license, you can view it in the [license list](#license-list).
......
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import { GlLink } from '@gitlab/ui';
import { LICENSE_MANAGEMENT } from 'ee/vue_shared/license_compliance/store/constants'; import { LICENSE_MANAGEMENT } from 'ee/vue_shared/license_compliance/store/constants';
import LicensePackages from './license_packages.vue'; import LicensePackages from './license_packages.vue';
export default { export default {
name: 'LicenseIssueBody', name: 'LicenseIssueBody',
components: { LicensePackages }, components: { LicensePackages, GlLink },
props: { props: {
issue: { issue: {
type: Object, type: Object,
...@@ -19,15 +20,7 @@ export default { ...@@ -19,15 +20,7 @@ export default {
<template> <template>
<div class="report-block-info license-item"> <div class="report-block-info license-item">
<button <gl-link :href="issue.url" target="_blank">{{ issue.name }}</gl-link>
class="btn-blank btn-link gl-mr-2"
type="button"
data-toggle="modal"
data-target="#modal-set-license-approval"
@click="setLicenseInModal(issue)"
>
{{ issue.name }}
</button>
<license-packages :packages="issue.packages" class="text-secondary" /> <license-packages :packages="issue.packages" class="text-secondary" />
</div> </div>
</template> </template>
<script>
import { mapActions, mapState } from 'vuex';
import { GlLink } from '@gitlab/ui';
import { LICENSE_MANAGEMENT } from 'ee/vue_shared/license_compliance/store/constants';
import { s__ } from '~/locale';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import LicensePackages from './license_packages.vue';
import { LICENSE_APPROVAL_STATUS } from '../constants';
export default {
name: 'LicenseSetApprovalStatusModal',
components: { GlLink, LicensePackages, GlModal: DeprecatedModal2 },
computed: {
...mapState(LICENSE_MANAGEMENT, ['currentLicenseInModal', 'canManageLicenses']),
headerTitleText() {
if (!this.canManageLicenses) {
return s__('LicenseCompliance|License details');
}
return s__('LicenseCompliance|License review');
},
canApprove() {
return (
this.canManageLicenses &&
this.currentLicenseInModal &&
this.currentLicenseInModal.approvalStatus !== LICENSE_APPROVAL_STATUS.ALLOWED
);
},
canBlacklist() {
return (
this.canManageLicenses &&
this.currentLicenseInModal &&
this.currentLicenseInModal.approvalStatus !== LICENSE_APPROVAL_STATUS.DENIED
);
},
},
methods: {
...mapActions(LICENSE_MANAGEMENT, ['resetLicenseInModal', 'allowLicense', 'denyLicense']),
},
};
</script>
<template>
<gl-modal
id="modal-set-license-approval"
:header-title-text="headerTitleText"
modal-size="lg"
data-qa-selector="license_management_modal"
@cancel="resetLicenseInModal"
>
<slot v-if="currentLicenseInModal">
<div class="row gl-mt-3 gl-mb-3 js-license-name">
<label class="col-sm-3 text-right font-weight-bold">
{{ s__('LicenseCompliance|License') }}:
</label>
<div class="col-sm-9 text-secondary">{{ currentLicenseInModal.name }}</div>
</div>
<div v-if="currentLicenseInModal.url" class="row gl-mt-3 gl-mb-3 js-license-url">
<label class="col-sm-3 text-right font-weight-bold">
{{ s__('LicenseCompliance|URL') }}:
</label>
<div class="col-sm-9 text-secondary">
<gl-link :href="currentLicenseInModal.url" target="_blank" rel="nofollow">{{
currentLicenseInModal.url
}}</gl-link>
</div>
</div>
<div class="row gl-mt-3 gl-mb-3 js-license-packages">
<label class="col-sm-3 text-right font-weight-bold">
{{ s__('LicenseCompliance|Packages') }}:
</label>
<license-packages
:packages="currentLicenseInModal.packages"
class="col-sm-9 text-secondary"
/>
</div>
</slot>
<template slot="footer">
<button
type="button"
class="btn js-modal-cancel-action"
data-dismiss="modal"
@click="resetLicenseInModal"
>
{{ s__('Modal|Cancel') }}
</button>
<button
v-if="canBlacklist"
class="btn btn-remove btn-inverted js-modal-secondary-action"
data-dismiss="modal"
data-qa-selector="deny_license_button"
@click="denyLicense(currentLicenseInModal)"
>
{{ s__('LicenseCompliance|Deny') }}
</button>
<button
v-if="canApprove"
type="button"
class="btn btn-success js-modal-primary-action"
data-dismiss="modal"
data-qa-selector="approve_license_button"
@click="allowLicense(currentLicenseInModal)"
>
{{ s__('LicenseCompliance|Allow') }}
</button>
</template>
</gl-modal>
</template>
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import { GlLink, GlIcon } from '@gitlab/ui'; import { GlLink, GlIcon } from '@gitlab/ui';
import reportsMixin from 'ee/vue_shared/security_reports/mixins/reports_mixin'; import reportsMixin from 'ee/vue_shared/security_reports/mixins/reports_mixin';
import SetLicenseApprovalModal from 'ee/vue_shared/license_compliance/components/set_approval_status_modal.vue';
import { componentNames } from 'ee/reports/components/issue_body'; import { componentNames } from 'ee/reports/components/issue_body';
import { LICENSE_MANAGEMENT } from 'ee/vue_shared/license_compliance/store/constants'; import { LICENSE_MANAGEMENT } from 'ee/vue_shared/license_compliance/store/constants';
import ReportItem from '~/reports/components/report_item.vue'; import ReportItem from '~/reports/components/report_item.vue';
...@@ -20,7 +19,6 @@ export default { ...@@ -20,7 +19,6 @@ export default {
GlLink, GlLink,
ReportItem, ReportItem,
ReportSection, ReportSection,
SetLicenseApprovalModal,
SmartVirtualList, SmartVirtualList,
GlIcon, GlIcon,
}, },
...@@ -121,7 +119,6 @@ export default { ...@@ -121,7 +119,6 @@ export default {
</script> </script>
<template> <template>
<div> <div>
<set-license-approval-modal />
<report-section <report-section
:status="licenseReportStatus" :status="licenseReportStatus"
:loading-text="licenseSummaryText" :loading-text="licenseSummaryText"
...@@ -185,6 +182,7 @@ export default { ...@@ -185,6 +182,7 @@ export default {
:class="{ 'gl-mr-3': fullReportPath }" :class="{ 'gl-mr-3': fullReportPath }"
:href="licenseManagementSettingsPath" :href="licenseManagementSettingsPath"
class="btn btn-default btn-sm js-manage-licenses" class="btn btn-default btn-sm js-manage-licenses"
data-qa-selector="manage_licenses_button"
> >
{{ s__('ciReport|Manage licenses') }} {{ s__('ciReport|Manage licenses') }}
</a> </a>
......
---
title: Removes ability to change license status through MR and Pipeline pages
merge_request: 43470
author:
type: changed
...@@ -51,6 +51,7 @@ exports[`License Report MR Widget report section should render correctly 1`] = ` ...@@ -51,6 +51,7 @@ exports[`License Report MR Widget report section should render correctly 1`] = `
> >
<a <a
class="btn btn-default btn-sm js-manage-licenses gl-mr-3" class="btn btn-default btn-sm js-manage-licenses gl-mr-3"
data-qa-selector="manage_licenses_button"
href="http://test.host/lm_settings" href="http://test.host/lm_settings"
> >
......
...@@ -21,25 +21,13 @@ describe('LicenseIssueBody', () => { ...@@ -21,25 +21,13 @@ describe('LicenseIssueBody', () => {
vm.$destroy(); vm.$destroy();
}); });
describe('interaction', () => {
it('clicking the button triggers openModal with the current license', () => {
const linkEl = vm.$el.querySelector('.license-item > .btn-link');
expect(store.state.licenseManagement.currentLicenseInModal).toBe(null);
linkEl.click();
expect(store.state.licenseManagement.currentLicenseInModal).toBe(issue);
});
});
describe('template', () => { describe('template', () => {
it('renders component container element with class `license-item`', () => { it('renders component container element with class `license-item`', () => {
expect(vm.$el.classList.contains('license-item')).toBe(true); expect(vm.$el.classList.contains('license-item')).toBe(true);
}); });
it('renders button to open modal', () => { it('renders link to view license', () => {
const linkEl = vm.$el.querySelector('.license-item > .btn-link'); const linkEl = vm.$el.querySelector('.license-item > a');
expect(linkEl).not.toBeNull(); expect(linkEl).not.toBeNull();
expect(linkEl.innerText.trim()).toBe(issue.name); expect(linkEl.innerText.trim()).toBe(issue.name);
......
import Vue from 'vue';
import Vuex from 'vuex';
import SetApprovalModal from 'ee/vue_shared/license_compliance/components/set_approval_status_modal.vue';
import { LICENSE_APPROVAL_STATUS } from 'ee/vue_shared/license_compliance/constants';
import { trimText } from 'helpers/text_helper';
import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import { licenseReport } from '../mock_data';
Vue.use(Vuex);
describe('SetApprovalModal', () => {
const Component = Vue.extend(SetApprovalModal);
let vm;
let store;
let actions;
beforeEach(() => {
actions = {
resetLicenseInModal: jest.fn(),
allowLicense: jest.fn(),
denyLicense: jest.fn(),
};
store = new Vuex.Store({
modules: {
licenseManagement: {
namespaced: true,
state: {
currentLicenseInModal: licenseReport[0],
canManageLicenses: true,
},
actions,
},
},
});
vm = mountComponentWithStore(Component, { store });
});
afterEach(() => {
vm.$destroy();
});
describe('for approved license', () => {
beforeEach(done => {
store.replaceState({
licenseManagement: {
currentLicenseInModal: {
...licenseReport[0],
approvalStatus: LICENSE_APPROVAL_STATUS.ALLOWED,
},
canManageLicenses: true,
},
});
Vue.nextTick(done);
});
describe('computed', () => {
it('headerTitleText returns `License review', () => {
expect(vm.headerTitleText).toBe('License review');
});
it('canApprove is false', () => {
expect(vm.canApprove).toBe(false);
});
it('canBlacklist is true', () => {
expect(vm.canBlacklist).toBe(true);
});
});
describe('template correctly', () => {
it('renders modal title', () => {
const headerEl = vm.$el.querySelector('.modal-title');
expect(headerEl).not.toBeNull();
expect(headerEl.innerText.trim()).toBe('License review');
});
it('renders no Allow button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-primary-action');
expect(footerButton).toBeNull();
});
it('renders Deny button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-secondary-action');
expect(footerButton).not.toBeNull();
expect(footerButton.innerText.trim()).toBe('Deny');
});
});
});
describe('for unapproved license', () => {
beforeEach(done => {
store.replaceState({
licenseManagement: {
currentLicenseInModal: {
...licenseReport[0],
approvalStatus: undefined,
},
canManageLicenses: true,
},
});
Vue.nextTick(done);
});
describe('computed', () => {
it('headerTitleText returns `License review`', () => {
expect(vm.headerTitleText).toBe('License review');
});
it('canApprove is true', () => {
expect(vm.canApprove).toBe(true);
});
it('canBlacklist is true', () => {
expect(vm.canBlacklist).toBe(true);
});
});
describe('template', () => {
it('renders modal title', () => {
const headerEl = vm.$el.querySelector('.modal-title');
expect(headerEl).not.toBeNull();
expect(headerEl.innerText.trim()).toBe('License review');
});
it('renders Allow button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-primary-action');
expect(footerButton).not.toBeNull();
expect(footerButton.innerText.trim()).toBe('Allow');
});
it('renders Deny button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-secondary-action');
expect(footerButton).not.toBeNull();
expect(footerButton.innerText.trim()).toBe('Deny');
});
});
});
describe('for blacklisted license', () => {
beforeEach(done => {
store.replaceState({
licenseManagement: {
currentLicenseInModal: {
...licenseReport[0],
approvalStatus: LICENSE_APPROVAL_STATUS.DENIED,
},
canManageLicenses: true,
},
});
Vue.nextTick(done);
});
describe('computed', () => {
it('headerTitleText returns `License review`', () => {
expect(vm.headerTitleText).toBe('License review');
});
it('canApprove is true', () => {
expect(vm.canApprove).toBe(true);
});
it('canBlacklist is false', () => {
expect(vm.canBlacklist).toBe(false);
});
});
describe('template', () => {
it('renders modal title', () => {
const headerEl = vm.$el.querySelector('.modal-title');
expect(headerEl).not.toBeNull();
expect(headerEl.innerText.trim()).toBe('License review');
});
it('renders Allow button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-primary-action');
expect(footerButton).not.toBeNull();
expect(footerButton.innerText.trim()).toBe('Allow');
});
it('renders no Deny button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-secondary-action');
expect(footerButton).toBeNull();
});
});
});
describe('for user without the rights to manage licenses', () => {
beforeEach(done => {
store.replaceState({
licenseManagement: {
currentLicenseInModal: {
...licenseReport[0],
approvalStatus: undefined,
},
canManageLicenses: false,
},
});
Vue.nextTick(done);
});
describe('computed', () => {
it('headerTitleText returns `License details`', () => {
expect(vm.headerTitleText).toBe('License details');
});
it('canApprove is false', () => {
expect(vm.canApprove).toBe(false);
});
it('canBlacklist is false', () => {
expect(vm.canBlacklist).toBe(false);
});
});
describe('template', () => {
it('renders modal title', () => {
const headerEl = vm.$el.querySelector('.modal-title');
expect(headerEl).not.toBeNull();
expect(headerEl.innerText.trim()).toBe('License details');
});
it('renders no Approve button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-primary-action');
expect(footerButton).toBeNull();
});
it('renders no Blacklist button in modal footer', () => {
const footerButton = vm.$el.querySelector('.js-modal-secondary-action');
expect(footerButton).toBeNull();
});
});
});
describe('Modal Body', () => {
it('renders the license name', () => {
const licenseName = vm.$el.querySelector('.js-license-name');
expect(licenseName).not.toBeNull();
expect(trimText(licenseName.innerText)).toBe(`License: ${licenseReport[0].name}`);
});
it('renders the license url with link', () => {
const licenseName = vm.$el.querySelector('.js-license-url');
expect(licenseName).not.toBeNull();
expect(trimText(licenseName.innerText)).toBe(`URL: ${licenseReport[0].url}`);
const licenseLink = licenseName.querySelector('a');
expect(licenseLink.getAttribute('href')).toBe(licenseReport[0].url);
expect(trimText(licenseLink.innerText)).toBe(licenseReport[0].url);
});
it('renders the license url', () => {
const licenseName = vm.$el.querySelector('.js-license-packages');
expect(licenseName).not.toBeNull();
expect(trimText(licenseName.innerText)).toBe('Packages: Used by pg, puma, foo, and 2 more');
});
});
describe('interaction', () => {
describe('triggering resetLicenseInModal on canceling', () => {
it('by clicking the cancel button', () => {
const linkEl = vm.$el.querySelector('.js-modal-cancel-action');
linkEl.click();
expect(actions.resetLicenseInModal).toHaveBeenCalled();
});
it('triggering resetLicenseInModal by clicking the X button', () => {
const linkEl = vm.$el.querySelector('.js-modal-close-action');
linkEl.click();
expect(actions.resetLicenseInModal).toHaveBeenCalled();
});
});
describe('triggering allowLicense on approving', () => {
it('by clicking the confirmation button', () => {
const linkEl = vm.$el.querySelector('.js-modal-primary-action');
linkEl.click();
expect(actions.allowLicense).toHaveBeenCalledWith(
expect.any(Object),
store.state.licenseManagement.currentLicenseInModal,
);
});
});
describe('triggering denyLicense on blacklisting', () => {
it('by clicking the confirmation button', () => {
const linkEl = vm.$el.querySelector('.js-modal-secondary-action');
linkEl.click();
expect(actions.denyLicense).toHaveBeenCalledWith(
expect.any(Object),
store.state.licenseManagement.currentLicenseInModal,
);
});
});
});
it('does not render a XSS link', done => {
// eslint-disable-next-line no-script-url
const badURL = 'javascript:alert("")';
store.replaceState({
licenseManagement: {
currentLicenseInModal: {
...licenseReport[0],
url: badURL,
approvalStatus: LICENSE_APPROVAL_STATUS.ALLOWED,
},
},
});
Vue.nextTick()
.then(() => {
const licenseName = vm.$el.querySelector('.js-license-url');
expect(licenseName).not.toBeNull();
expect(trimText(licenseName.innerText)).toBe(`URL: ${badURL}`);
expect(licenseName.querySelector('a').getAttribute('href')).toBe('about:blank');
expect(licenseName.querySelector('a').innerText).toBe(badURL);
})
.then(done)
.catch(done.fail);
});
});
...@@ -333,12 +333,6 @@ describe('License Report MR Widget', () => { ...@@ -333,12 +333,6 @@ describe('License Report MR Widget', () => {
}); });
}); });
it('should render set approval modal', () => {
mountComponent();
expect(wrapper.find('#modal-set-license-approval')).not.toBeNull();
});
it('should init store after mount', () => { it('should init store after mount', () => {
const actions = { const actions = {
setAPISettings: jest.fn(), setAPISettings: jest.fn(),
......
...@@ -15946,9 +15946,6 @@ msgstr "" ...@@ -15946,9 +15946,6 @@ msgstr ""
msgid "LicenseCompliance|Learn more about %{linkStart}License Approvals%{linkEnd}" msgid "LicenseCompliance|Learn more about %{linkStart}License Approvals%{linkEnd}"
msgstr "" msgstr ""
msgid "LicenseCompliance|License"
msgstr ""
msgid "LicenseCompliance|License Approvals" msgid "LicenseCompliance|License Approvals"
msgstr "" msgstr ""
...@@ -15988,18 +15985,9 @@ msgstr "" ...@@ -15988,18 +15985,9 @@ msgstr ""
msgid "LicenseCompliance|License Compliance detected no new licenses" msgid "LicenseCompliance|License Compliance detected no new licenses"
msgstr "" msgstr ""
msgid "LicenseCompliance|License details"
msgstr ""
msgid "LicenseCompliance|License name" msgid "LicenseCompliance|License name"
msgstr "" msgstr ""
msgid "LicenseCompliance|License review"
msgstr ""
msgid "LicenseCompliance|Packages"
msgstr ""
msgid "LicenseCompliance|Remove license" msgid "LicenseCompliance|Remove license"
msgstr "" msgstr ""
...@@ -16015,9 +16003,6 @@ msgstr "" ...@@ -16015,9 +16003,6 @@ msgstr ""
msgid "LicenseCompliance|This license already exists in this project." msgid "LicenseCompliance|This license already exists in this project."
msgstr "" msgstr ""
msgid "LicenseCompliance|URL"
msgstr ""
msgid "LicenseCompliance|You are about to remove the license, %{name}, from this project." msgid "LicenseCompliance|You are about to remove the license, %{name}, from this project."
msgstr "" msgstr ""
......
...@@ -9,23 +9,25 @@ ...@@ -9,23 +9,25 @@
{ {
"id": "MIT", "id": "MIT",
"name": "MIT License", "name": "MIT License",
"url": "https://opensource.org/licenses/MIT" "url": "http://opensource.org/licenses/mit-license"
} }
], ],
"dependencies": [ "dependencies": [
{ {
"name": "actioncable", "name": "test_dependency",
"version": "6.0.3.3", "version": "0.1.0",
"package_manager": "bundler", "package_manager": "bundler",
"path": "Gemfile.lock", "path": "Gemfile.lock",
"licenses": ["MIT"] "licenses": ["Apache-2.0"]
}, },
{ {
"name": "test_package", "name": "actioncable",
"version": "0.1.0", "version": "1.2",
"url": "http://rubyonrails.org",
"package_manager": "bundler", "package_manager": "bundler",
"path": "Gemfile.lock", "description": "WebSocket framework for Rails.",
"licenses": ["Apache-2.0"] "path": ".",
"licenses": ["MIT"]
} }
] ]
} }
...@@ -19,14 +19,9 @@ module QA ...@@ -19,14 +19,9 @@ module QA
element :icon_status, ':data-qa-selector="`status_${status}_icon`" ' # rubocop:disable QA/ElementWithPattern element :icon_status, ':data-qa-selector="`status_${status}_icon`" ' # rubocop:disable QA/ElementWithPattern
end end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/components/set_approval_status_modal.vue' do
element :license_management_modal
element :approve_license_button
element :deny_license_button
end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/mr_widget_license_report.vue' do view 'ee/app/assets/javascripts/vue_shared/license_compliance/mr_widget_license_report.vue' do
element :license_report_widget element :license_report_widget
element :manage_licenses_button
end end
end end
end end
...@@ -50,20 +45,14 @@ module QA ...@@ -50,20 +45,14 @@ module QA
wait_for_animated_element(:license_management_modal) wait_for_animated_element(:license_management_modal)
end end
def approve_license(name) def click_manage_licenses_button
wait_until(reload: true) do previous_page = page.current_url
click_license(name) within_element(:license_report_widget) do
has_element?(:approve_license_button, wait: 1) click_element :manage_licenses_button
end end
click_element(:approve_license_button) wait_until(max_duration: 15, reload: false) do
end page.current_url != previous_page
def deny_license(name)
wait_until(reload: true) do
click_license(name)
has_element?(:deny_license_button, wait: 1)
end end
click_element(:deny_license_button)
end end
end end
end end
......
...@@ -114,16 +114,6 @@ module QA ...@@ -114,16 +114,6 @@ module QA
end end
end end
def approve_license_with_mr(name)
expand_license_report unless license_report_expanded?
approve_license(name)
end
def deny_license_with_mr(name)
expand_license_report unless license_report_expanded?
deny_license(name)
end
def expand_vulnerability_report def expand_vulnerability_report
within_element :vulnerability_report_grouped do within_element :vulnerability_report_grouped do
click_element :expand_report_button unless has_content? 'Collapse' click_element :expand_report_button unless has_content? 'Collapse'
......
...@@ -28,7 +28,7 @@ module QA ...@@ -28,7 +28,7 @@ module QA
def approve_license(license) def approve_license(license)
click_element :license_add_button click_element :license_add_button
expand_select_list expand_select_list
search_and_select license search_and_select_exact license
click_element :approved_license_radio click_element :approved_license_radio
click_element :add_license_submit_button click_element :add_license_submit_button
...@@ -36,6 +36,7 @@ module QA ...@@ -36,6 +36,7 @@ module QA
end end
def has_approved_license?(name) def has_approved_license?(name)
has_element?(:admin_license_compliance_row, text: name)
within_element(:admin_license_compliance_row, text: name) do within_element(:admin_license_compliance_row, text: name) do
has_element?(:status_success_icon) has_element?(:status_success_icon)
end end
...@@ -44,7 +45,7 @@ module QA ...@@ -44,7 +45,7 @@ module QA
def deny_license(license) def deny_license(license)
click_element :license_add_button click_element :license_add_button
expand_select_list expand_select_list
search_and_select license search_and_select_exact license
click_element :blacklisted_license_radio click_element :blacklisted_license_radio
click_element :add_license_submit_button click_element :add_license_submit_button
...@@ -52,6 +53,7 @@ module QA ...@@ -52,6 +53,7 @@ module QA
end end
def has_denied_license?(name) def has_denied_license?(name)
has_element?(:admin_license_compliance_row, text: name)
within_element(:admin_license_compliance_row, text: name) do within_element(:admin_license_compliance_row, text: name) do
has_element?(:status_failed_icon) has_element?(:status_failed_icon)
end end
......
...@@ -38,6 +38,16 @@ module QA ...@@ -38,6 +38,16 @@ module QA
select_item(item_text) select_item(item_text)
end end
def search_and_select_exact(item_text)
QA::Runtime::Logger.info "Searching and selecting: #{item_text}"
search_item(item_text)
raise QA::Page::Base::ElementNotFound, %Q(Couldn't find option named "#{item_text}") unless has_item?(item_text)
find('.select2-result-label', text: item_text, exact_text: true).click
end
def expand_select_list def expand_select_list
find('span.select2-arrow').click find('span.select2-arrow').click
end end
......
...@@ -26,6 +26,10 @@ module QA ...@@ -26,6 +26,10 @@ module QA
element :child_pipeline element :child_pipeline
end end
view 'app/assets/javascripts/reports/components/report_section.vue' do
element :expand_report_button
end
view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
end end
...@@ -78,6 +82,12 @@ module QA ...@@ -78,6 +82,12 @@ module QA
end end
end end
def expand_license_report
within_element(:license_report_widget) do
click_element(:expand_report_button)
end
end
def click_on_first_job def click_on_first_job
first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click
end end
......
...@@ -71,7 +71,6 @@ module QA ...@@ -71,7 +71,6 @@ module QA
end end
describe 'License Compliance pipeline reports' do describe 'License Compliance pipeline reports' do
let(:number_of_licenses_in_fixture) { 2 }
let(:executor) {"qa-runner-#{Time.now.to_i}"} let(:executor) {"qa-runner-#{Time.now.to_i}"}
after do after do
...@@ -101,29 +100,29 @@ module QA ...@@ -101,29 +100,29 @@ module QA
.new(__dir__) .new(__dir__)
.join('../../../../../ee/fixtures/secure_premade_reports') .join('../../../../../ee/fixtures/secure_premade_reports')
project_push.commit_message = 'Create Secure compatible application to serve premade reports' project_push.commit_message = 'Create Secure compatible application to serve premade reports'
end.project.visit! end
@project.visit!
Page::Project::Menu.perform(&:click_ci_cd_pipelines) Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:wait_for_latest_pipeline_success) Page::Project::Pipeline::Index.perform(&:wait_for_latest_pipeline_success)
Page::Project::Menu.perform(&:click_on_license_compliance)
end end
it 'can approve and deny licenses in the pipeline', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/965' do it 'can approve and deny licenses in the pipeline', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/965' do
Flow::Pipeline.visit_latest_pipeline EE::Page::Project::Secure::LicenseCompliance.perform do |license_compliance|
license_compliance.open_tab
license_compliance.approve_license approved_license_name
license_compliance.deny_license denied_license_name
end
@project.visit!
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
Page::Project::Pipeline::Show.perform do |pipeline| Page::Project::Pipeline::Show.perform do |pipeline|
pipeline.click_on_licenses pipeline.click_on_licenses
expect(pipeline).to have_approved_license approved_license_name
expect(pipeline).to have_license_count_of number_of_licenses_in_fixture expect(pipeline).to have_denied_license denied_license_name
pipeline.approve_license(approved_license_name)
pipeline.deny_license(denied_license_name)
end
Page::Project::Menu.perform(&:click_on_license_compliance)
EE::Page::Project::Secure::LicenseCompliance.perform do |license_compliance|
license_compliance.open_tab
expect(license_compliance).to have_approved_license approved_license_name
expect(license_compliance).to have_denied_license denied_license_name
end end
end end
end end
......
...@@ -103,11 +103,21 @@ module QA ...@@ -103,11 +103,21 @@ module QA
@merge_request.visit! @merge_request.visit!
Page::MergeRequest::Show.perform do |show| Page::MergeRequest::Show.perform do |show|
show.approve_license_with_mr(approved_license_name)
show.deny_license_with_mr(denied_license_name)
show.wait_for_license_compliance_report show.wait_for_license_compliance_report
show.click_manage_licenses_button
end
EE::Page::Project::Secure::LicenseCompliance.perform do |license_compliance|
license_compliance.open_tab
license_compliance.approve_license approved_license_name
license_compliance.deny_license denied_license_name
end
@merge_request.visit!
Page::MergeRequest::Show.perform do |show|
show.wait_for_license_compliance_report
show.expand_license_report
expect(show).to have_approved_license approved_license_name expect(show).to have_approved_license approved_license_name
expect(show).to have_denied_license denied_license_name expect(show).to have_denied_license denied_license_name
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