- select and deselect and select all - navigating with carets and breadcrumbs - check for disabled statepull/11571/head
parent
caeabef057
commit
af13efe36d
@ -0,0 +1,180 @@ |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2022 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See COPYRIGHT and LICENSE files for more details. |
||||
#++ |
||||
|
||||
FactoryBot.define do |
||||
factory :webdav_data, class: 'String' do |
||||
skip_create |
||||
|
||||
initialize_with do |
||||
Nokogiri::XML::Builder.new do |xml| |
||||
xml['d'].multistatus( |
||||
'xmlns:d' => 'DAV:', |
||||
'xmlns:s' => 'http://sabredav.org/ns', |
||||
'xmlns:oc' => 'http://owncloud.org/ns', |
||||
'xmlns:nc' => 'http://nextcloud.org/ns' |
||||
) do |
||||
xml['d'].response do |
||||
xml['d'].href('/remote.php/dav/files/admin/') |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['oc'].fileid('6') |
||||
xml['oc'].size('20028269') |
||||
xml['d'].getlastmodified('Fri, 28 Oct 2022 14:27:36 GMT') |
||||
xml['oc'].send('owner-display-name', 'admin') |
||||
end |
||||
xml['d'].status('HTTP/1.1 200 OK') |
||||
end |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['d'].getcontenttype |
||||
end |
||||
xml['d'].status('HTTP/1.1 404 Not Found') |
||||
end |
||||
end |
||||
xml['d'].response do |
||||
xml['d'].href('/remote.php/dav/files/admin/Folder1/') |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['oc'].fileid('11') |
||||
xml['oc'].size('6592') |
||||
xml['d'].getlastmodified('Fri, 28 Oct 2022 14:31:26 GMT') |
||||
xml['oc'].send('owner-display-name', 'admin') |
||||
end |
||||
xml['d'].status('HTTP/1.1 200 OK') |
||||
end |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['d'].getcontenttype |
||||
end |
||||
xml['d'].status('HTTP/1.1 404 Not Found') |
||||
end |
||||
end |
||||
xml['d'].response do |
||||
xml['d'].href('/remote.php/dav/files/admin/README.md') |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['oc'].fileid('12') |
||||
xml['oc'].size('1024') |
||||
xml['d'].getcontenttype('text/markdown') |
||||
xml['d'].getlastmodified('Thu, 14 Jul 2022 08:42:15 GMT') |
||||
xml['oc'].send('owner-display-name', 'admin') |
||||
end |
||||
xml['d'].status('HTTP/1.1 200 OK') |
||||
end |
||||
end |
||||
xml['d'].response do |
||||
xml['d'].href('/remote.php/dav/files/admin/Manual.pdf') |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['oc'].fileid('13') |
||||
xml['oc'].size('12706214') |
||||
xml['d'].getcontenttype('application/pdf') |
||||
xml['d'].getlastmodified('Thu, 14 Jul 2022 08:42:15 GMT') |
||||
xml['oc'].send('owner-display-name', 'admin') |
||||
end |
||||
xml['d'].status('HTTP/1.1 200 OK') |
||||
end |
||||
end |
||||
end |
||||
end.to_xml |
||||
end |
||||
end |
||||
|
||||
factory :webdav_data_folder, class: 'String' do |
||||
skip_create |
||||
|
||||
initialize_with do |
||||
Nokogiri::XML::Builder.new do |xml| |
||||
xml['d'].multistatus( |
||||
'xmlns:d' => 'DAV:', |
||||
'xmlns:s' => 'http://sabredav.org/ns', |
||||
'xmlns:oc' => 'http://owncloud.org/ns', |
||||
'xmlns:nc' => 'http://nextcloud.org/ns' |
||||
) do |
||||
xml['d'].response do |
||||
xml['d'].href('/remote.php/dav/files/admin/Folder1') |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['oc'].fileid('11') |
||||
xml['oc'].size('6592') |
||||
xml['d'].getlastmodified('Fri, 28 Oct 2022 14:31:26 GMT') |
||||
xml['oc'].send('owner-display-name', 'admin') |
||||
end |
||||
xml['d'].status('HTTP/1.1 200 OK') |
||||
end |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['d'].getcontenttype |
||||
end |
||||
xml['d'].status('HTTP/1.1 404 Not Found') |
||||
end |
||||
end |
||||
xml['d'].response do |
||||
xml['d'].href('/remote.php/dav/files/admin/Folder1/logo.png') |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['oc'].fileid('21') |
||||
xml['oc'].size('2048') |
||||
xml['d'].getcontenttype('image/png') |
||||
xml['d'].getlastmodified('Fri, 28 Oct 2022 14:31:26 GMT') |
||||
xml['oc'].send('owner-display-name', 'admin') |
||||
end |
||||
xml['d'].status('HTTP/1.1 200 OK') |
||||
end |
||||
end |
||||
xml['d'].response do |
||||
xml['d'].href('/remote.php/dav/files/admin/Folder1/jingle.ogg') |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['oc'].fileid('22') |
||||
xml['oc'].size('22736218') |
||||
xml['d'].getcontenttype('audio/ogg') |
||||
xml['d'].getlastmodified('Fri, 28 Oct 2022 14:31:26 GMT') |
||||
xml['oc'].send('owner-display-name', 'admin') |
||||
end |
||||
xml['d'].status('HTTP/1.1 200 OK') |
||||
end |
||||
end |
||||
xml['d'].response do |
||||
xml['d'].href('/remote.php/dav/files/admin/Folder1/notes.txt') |
||||
xml['d'].propstat do |
||||
xml['d'].prop do |
||||
xml['oc'].fileid('23') |
||||
xml['oc'].size('128') |
||||
xml['d'].getcontenttype('text/plain') |
||||
xml['d'].getlastmodified('Fri, 28 Oct 2022 14:31:26 GMT') |
||||
xml['oc'].send('owner-display-name', 'admin') |
||||
end |
||||
xml['d'].status('HTTP/1.1 200 OK') |
||||
end |
||||
end |
||||
end |
||||
end.to_xml |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,109 @@ |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2022 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See COPYRIGHT and LICENSE files for more details. |
||||
#++ |
||||
|
||||
require_relative '../spec_helper' |
||||
|
||||
describe 'Creating file links in work package', webmock: true, type: :feature, js: true do |
||||
let(:permissions) { %i(view_work_packages edit_work_packages view_file_links manage_file_links) } |
||||
let(:project) { create(:project) } |
||||
let(:current_user) { create(:user, member_in_project: project, member_with_permissions: permissions) } |
||||
let(:work_package) { create(:work_package, project:, description: 'Initial description') } |
||||
|
||||
let(:storage) { create(:storage) } |
||||
let(:oauth_client) { create(:oauth_client, integration: storage) } |
||||
let(:oauth_client_token) { create(:oauth_client_token, oauth_client:, user: current_user) } |
||||
let(:project_storage) { create(:project_storage, project:, storage:) } |
||||
let(:file_link) { create(:file_link, container: work_package, storage:, origin_id: '22', origin_name: 'jingle.ogg') } |
||||
|
||||
let(:connection_manager) do |
||||
connection_manager = instance_double(::OAuthClients::ConnectionManager) |
||||
allow(connection_manager).to receive(:refresh_token).and_return(ServiceResult.success(result: oauth_client_token)) |
||||
allow(connection_manager).to receive(:get_access_token).and_return(ServiceResult.success(result: oauth_client_token)) |
||||
allow(connection_manager).to receive(:authorization_state).and_return(:connected) |
||||
allow(connection_manager).to receive(:with_refreshed_token).and_yield |
||||
connection_manager |
||||
end |
||||
|
||||
let(:root_xml_response) { create(:webdav_data) } |
||||
let(:folder1_xml_response) { create(:webdav_data_folder) } |
||||
|
||||
let(:sync_service) do |
||||
sync_service = instance_double(::Storages::FileLinkSyncService) |
||||
allow(sync_service).to receive(:call) do |file_links| |
||||
ServiceResult.success(result: file_links.each { |file_link| file_link.origin_permission = :view }) |
||||
end |
||||
sync_service |
||||
end |
||||
|
||||
let(:wp_page) { ::Pages::FullWorkPackage.new(work_package, project) } |
||||
let(:dialog) { ::Components::FilePickerDialog.new } |
||||
|
||||
before do |
||||
allow(::OAuthClients::ConnectionManager).to receive(:new).and_return(connection_manager) |
||||
allow(::Storages::FileLinkSyncService).to receive(:new).and_return(sync_service) |
||||
|
||||
stub_request(:propfind, "#{storage.host}/remote.php/dav/files/#{oauth_client_token.origin_user_id}").to_return(status: 207, body: root_xml_response, headers: {}) |
||||
stub_request(:propfind, "#{storage.host}/remote.php/dav/files/#{oauth_client_token.origin_user_id}/Folder1").to_return(status: 207, body: folder1_xml_response, headers: {}) |
||||
|
||||
project_storage |
||||
file_link |
||||
|
||||
login_as current_user |
||||
wp_page.visit_tab! :files |
||||
end |
||||
|
||||
describe 'with the file picker' do |
||||
it 'must enable the user to link existing files on the storage' do |
||||
expect(wp_page.all('[data-qa-selector="file-list--item"]').size).to eq 1 |
||||
|
||||
wp_page.find('[data-qa-selector="op-file-list--link-existing-file-button"]').click |
||||
|
||||
dialog.expect_open |
||||
dialog.confirm_button_state(selection_count: 0) |
||||
|
||||
dialog.select_file('Manual.pdf') |
||||
dialog.confirm_button_state(selection_count: 1) |
||||
|
||||
dialog.enter_folder('Folder1') |
||||
dialog.has_list_item(text: 'jingle.ogg', checked: true, disabled: true) |
||||
dialog.select_all |
||||
dialog.confirm_button_state(selection_count: 3) |
||||
|
||||
dialog.select_file('notes.txt') |
||||
dialog.confirm_button_state(selection_count: 2) |
||||
|
||||
dialog.use_breadcrumb(position: 'root') |
||||
dialog.has_list_item(text: 'Manual.pdf', checked: true, disabled: false) |
||||
|
||||
dialog.confirm |
||||
|
||||
sleep 15 |
||||
expect(wp_page.all('[data-qa-selector="file-list--item"]').size).to eq 3 |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,104 @@ |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2022 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See COPYRIGHT and LICENSE files for more details. |
||||
#++ |
||||
|
||||
module Components |
||||
class FilePickerDialog |
||||
include Capybara::DSL |
||||
include RSpec::Matchers |
||||
|
||||
def container |
||||
'[data-qa-selector="op-files-picker-modal"]' |
||||
end |
||||
|
||||
def expect_open |
||||
expect(page).to have_selector(container) |
||||
end |
||||
|
||||
def confirm_button_state(selection_count:) |
||||
page.within(container) do |
||||
if selection_count > 0 |
||||
expect(page).to have_button(disabled: false, |
||||
exact_text: I18n.t('js.storages.file_links.selection_any', number: selection_count)) |
||||
else |
||||
expect(page).to have_button(disabled: true, |
||||
exact_text: I18n.t('js.storages.file_links.selection_none')) |
||||
end |
||||
end |
||||
end |
||||
|
||||
def confirm |
||||
page.within(container) do |
||||
page.find('[data-qa-selector="op-files-picker-modal--confirm"]').click |
||||
end |
||||
end |
||||
|
||||
def select_file(text) |
||||
page.within(container) do |
||||
page.find('[data-qa-selector="op-files-picker-modal--list-item"]', text: text).click |
||||
end |
||||
end |
||||
|
||||
def has_list_item(text:, checked:, disabled:) |
||||
page.within(container) do |
||||
expect(page.find('[data-qa-selector="op-files-picker-modal--list-item"]', text:)) |
||||
.to have_field(type: 'checkbox', checked:, disabled:) |
||||
end |
||||
end |
||||
|
||||
def enter_folder(text) |
||||
page.within(container) do |
||||
page.within('[data-qa-selector="op-files-picker-modal--list-item"]', text: text) do |
||||
page.find('[data-qa-selector="op-files-picker-modal--list-item-caret"]').click |
||||
end |
||||
end |
||||
end |
||||
|
||||
def select_all |
||||
page.within(container) do |
||||
page.find('[data-qa-selector="op-files-picker-modal--select-all"]').click |
||||
end |
||||
end |
||||
|
||||
def use_breadcrumb(position: 'root' | 'grandparent' | 'parent') |
||||
page.within(container) do |
||||
crumbs = page.all('[data-qa-selector="op-breadcrumb"]') |
||||
case position |
||||
when 'root' |
||||
expect(crumbs.size).to be > 1 |
||||
crumbs[0].click |
||||
when 'parent' |
||||
expect(crumbs.size).to be > 2 |
||||
crumbs[-2].click |
||||
when 'grandparent' |
||||
expect(crumbs.size).to be > 3 |
||||
crumbs[-3].click |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue