Commit aaf124b0 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 143f196f
......@@ -411,6 +411,7 @@ group :test do
gem 'concurrent-ruby', '~> 1.1'
gem 'test-prof', '~> 0.10.0'
gem 'rspec_junit_formatter'
gem 'guard-rspec'
end
gem 'octokit', '~> 4.9'
......
......@@ -446,6 +446,20 @@ GEM
googleapis-common-protos-types (~> 1.0)
gssapi (1.2.0)
ffi (>= 1.0.1)
guard (2.15.1)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
lumberjack (>= 1.0.12, < 2.0)
nenv (~> 0.1)
notiffany (~> 0.0)
pry (>= 0.9.12)
shellany (~> 0.0)
thor (>= 0.18.1)
guard-compat (1.2.1)
guard-rspec (4.7.3)
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
haml (5.0.4)
temple (>= 0.8.0)
tilt
......@@ -561,6 +575,10 @@ GEM
xml-simple
licensee (8.9.2)
rugged (~> 0.24)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
locale (2.1.2)
lograge (0.10.0)
actionpack (>= 4)
......@@ -570,6 +588,7 @@ GEM
loofah (2.3.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
lumberjack (1.0.13)
mail (2.7.1)
mini_mime (>= 0.1.1)
mail_room (0.9.1)
......@@ -598,6 +617,7 @@ GEM
mustermann (~> 1.0.0)
nakayoshi_fork (0.0.4)
nap (1.1.0)
nenv (0.3.0)
net-ldap (0.16.0)
net-ntp (2.1.3)
net-ssh (5.2.0)
......@@ -608,6 +628,9 @@ GEM
mini_portile2 (~> 2.4.0)
nokogumbo (1.5.0)
nokogiri
notiffany (0.1.3)
nenv (~> 0.1)
shellany (~> 0.0)
numerizer (0.1.1)
oauth (0.5.4)
oauth2 (1.4.1)
......@@ -898,6 +921,7 @@ GEM
ruby-progressbar (1.10.1)
ruby-saml (1.7.2)
nokogiri (>= 1.5.10)
ruby_dep (1.5.0)
ruby_parser (3.13.1)
sexp_processor (~> 4.9)
rubyntlm (0.6.2)
......@@ -939,6 +963,7 @@ GEM
faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9)
sexp_processor (4.12.0)
shellany (0.0.1)
shoulda-matchers (4.0.1)
activesupport (>= 4.2.0)
sidekiq (5.2.7)
......@@ -1193,6 +1218,7 @@ DEPENDENCIES
graphql-docs (~> 1.6.0)
grpc (~> 1.24.0)
gssapi
guard-rspec
haml_lint (~> 0.31.0)
hamlit (~> 2.8.8)
hangouts-chat (~> 0.0.5)
......
# frozen_string_literal: true
# More info at https://github.com/guard/guard#readme
cmd = ENV['SPRING'] ? 'spring rspec' : 'bundle exec rspec'
guard :rspec, cmd: cmd do
require "guard/rspec/dsl"
dsl = Guard::RSpec::Dsl.new(self)
directories %w(app ee lib spec)
# RSpec files
rspec = dsl.rspec
watch(rspec.spec_helper) { rspec.spec_dir }
watch(rspec.spec_support) { rspec.spec_dir }
watch(rspec.spec_files)
# Ruby files
ruby = dsl.ruby
dsl.watch_spec_files_for(ruby.lib_files)
# Rails files
rails = dsl.rails(view_extensions: %w(erb haml slim))
dsl.watch_spec_files_for(rails.app_files)
dsl.watch_spec_files_for(rails.views)
watch(rails.controllers) do |m|
[
rspec.spec.call("routing/#{m[1]}_routing"),
rspec.spec.call("controllers/#{m[1]}_controller")
]
end
# Rails config changes
watch(rails.spec_helper) { rspec.spec_dir }
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
# Capybara features specs
watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") }
watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") }
end
<script>
/* global ListIssue */
import { urlParamsToObject } from '~/lib/utils/common_utils';
import boardsStore from '~/boards/stores/boards_store';
import ModalHeader from './header.vue';
import ModalList from './list.vue';
import ModalFooter from './footer.vue';
......@@ -109,7 +110,7 @@ export default {
loadIssues(clearIssues = false) {
if (!this.showAddIssuesModal) return false;
return gl.boardService
return boardsStore
.getBacklog({
...urlParamsToObject(this.filter.path),
page: this.page,
......
-# DANGER: Any changes to this file need to be reflected in issuables_list/components/issuable.vue!
%li{ id: dom_id(issue), class: issue_css_classes(issue), url: issue_path(issue), data: { labels: issue.label_ids, id: issue.id } }
%li{ id: dom_id(issue), class: issue_css_classes(issue), url: issue_path(issue), data: { labels: issue.label_ids, id: issue.id, qa_selector: 'issue', qa_issue_title: issue.title } }
.issue-box
- if @can_bulk_update
.issue-check.hidden
......
---
title: Remove all references to BoardsService in index.vue
merge_request: 20152
author: nuwe1
type: other
......@@ -44,6 +44,14 @@ bundle exec rspec
bundle exec rspec spec/[path]/[to]/[spec].rb
```
Use [guard](https://github.com/guard/guard) to continuously monitor for changes and only run matching tests:
```sh
bundle exec guard
```
When using spring and guard together, use `SPRING=1 bundle exec guard` instead to make use of spring.
### General guidelines
- Use a single, top-level `describe ClassName` block.
......
......@@ -167,6 +167,65 @@ There are two supported methods of defining elements within a view.
Any existing `.qa-selector` class should be considered deprecated
and we should prefer the `data-qa-selector` method of definition.
### Dynamic element selection
> Introduced in GitLab 12.5
A common occurrence in automated testing is selecting a single "one-of-many" element.
In a list of several items, how do you differentiate what you are selecting on?
The most common workaround for this is via text matching. Instead, a better practice is
by matching on that specific element by a unique identifier, rather than by text.
We got around this by adding the `data-qa-*` extensible selection mechanism.
#### Examples
**Example 1**
Given the following Rails view (using GitLab Issues as an example):
```haml
%ul.issues-list
- @issues.each do |issue|
%li.issue{data: { qa_selector: 'issue', qa_issue_title: issue.title } }= link_to issue
```
We can select on that specific issue by matching on the Rails model.
```ruby
class Page::Project::Issues::Index < Page::Base
def has_issue?(issue)
has_element? :issue, issue_title: issue
end
end
```
In our test, we can validate that this particular issue exists.
```ruby
describe 'Issue' do
it 'has an issue titled "hello"' do
Page::Project::Issues::Index.perform do |index|
expect(index).to have_issue('hello')
end
end
end
```
**Example 2**
*By an index...*
```haml
%ol
- @some_model.each_with_index do |model, idx|
%li.model{ data: { qa_selector: 'model', qa_index: idx } }
```
```ruby
expect(the_page).to have_element(:model, index: 1) #=> select on the first model that appears in the list
```
### Exceptions
In some cases it might not be possible or worthwhile to add a selector.
......
......@@ -111,12 +111,18 @@ module QA
element.select value
end
def has_element?(name, text: nil, wait: Capybara.default_max_wait_time)
has_css?(element_selector_css(name), wait: wait, text: text)
def has_element?(name, **kwargs)
wait = kwargs[:wait] ? kwargs[:wait] && kwargs.delete(:wait) : Capybara.default_max_wait_time
text = kwargs[:text] ? kwargs[:text] && kwargs.delete(:text) : nil
has_css?(element_selector_css(name, kwargs), text: text, wait: wait)
end
def has_no_element?(name, text: nil, wait: Capybara.default_max_wait_time)
has_no_css?(element_selector_css(name), wait: wait, text: text)
def has_no_element?(name, **kwargs)
wait = kwargs[:wait] ? kwargs[:wait] && kwargs.delete(:wait) : Capybara.default_max_wait_time
text = kwargs[:text] ? kwargs[:text] && kwargs.delete(:text) : nil
has_no_css?(element_selector_css(name, kwargs), wait: wait, text: text)
end
def has_text?(text)
......@@ -199,8 +205,8 @@ module QA
scroll_to(element_selector_css(name), *args)
end
def element_selector_css(name)
Page::Element.new(name).selector_css
def element_selector_css(name, *attributes)
Page::Element.new(name, *attributes).selector_css
end
def click_link_with_text(text)
......
......@@ -28,7 +28,7 @@ module QA
end
def selector_css
%Q([data-qa-selector="#{@name}"],.#{selector})
%Q([data-qa-selector="#{@name}"]#{additional_selectors},.#{selector})
end
def expression
......@@ -42,6 +42,14 @@ module QA
def matches?(line)
!!(line =~ /["']#{name}['"]|#{expression}/)
end
private
def additional_selectors
@attributes.dup.delete_if { |attr| attr == :pattern || attr == :required }.map do |key, value|
%Q([data-qa-#{key.to_s.tr('_', '-')}="#{value}"])
end.join
end
end
end
end
......@@ -36,6 +36,10 @@ module QA
def click_closed_issues_link
click_element :closed_issues_link
end
def has_issue?(issue)
has_element? :issue, issue_title: issue.to_s
end
end
end
end
......
......@@ -38,6 +38,10 @@ module QA
end
end
def to_s
@title
end
def api_get_path
"/projects/#{project.id}/issues/#{id}"
end
......
......@@ -7,8 +7,7 @@ module QA
QA::Runtime::Env.personal_access_token = QA::Runtime::Env.admin_personal_access_token
unless QA::Runtime::Env.personal_access_token
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_admin_credentials)
Flow::Login.sign_in_as_admin
end
user = Resource::User.fabricate_via_api! do |user|
......@@ -20,9 +19,7 @@ module QA
Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
project = Resource::Project.fabricate_via_api! do |resource|
resource.name = 'xss-test-for-mentions-project'
......
......@@ -7,8 +7,7 @@ module QA
let(:commit_message) { 'Closes' }
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
issue = Resource::Issue.fabricate_via_api! do |issue|
issue.title = issue_title
......
......@@ -6,8 +6,7 @@ module QA
let(:my_first_reply) { 'My first reply' }
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
issue = Resource::Issue.fabricate_via_api! do |issue|
issue.title = 'issue title'
......
......@@ -4,8 +4,7 @@ module QA
context 'Plan' do
describe 'Issue comments' do
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
issue = Resource::Issue.fabricate_via_api! do |issue|
issue.title = 'issue title'
......
......@@ -6,18 +6,19 @@ module QA
let(:issue_title) { 'issue title' }
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
end
it 'user creates an issue' do
Resource::Issue.fabricate_via_browser_ui! do |issue|
issue = Resource::Issue.fabricate_via_browser_ui! do |issue|
issue.title = issue_title
end
Page::Project::Menu.perform(&:click_issues)
expect(page).to have_content(issue_title)
Page::Project::Issue::Index.perform do |index|
expect(index).to have_issue(issue)
end
end
context 'when using attachments in comments', :object_storage do
......
......@@ -6,8 +6,7 @@ module QA
let(:issue_title) { 'issue title' }
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
issue = Resource::Issue.fabricate_via_api! do |issue|
issue.title = issue_title
......
......@@ -6,8 +6,7 @@ module QA
let(:issue_title) { 'Issue Lists are awesome' }
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
project = Resource::Project.fabricate_via_api! do |resource|
resource.name = 'project-for-issue-suggestions'
......
......@@ -4,8 +4,7 @@ module QA
context 'Plan', :smoke do
describe 'mention' do
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Flow::Login.sign_in
@user = Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1)
......
......@@ -117,5 +117,23 @@ describe QA::Page::Element do
it 'properly translates to a data-qa-selector' do
expect(subject.selector_css).to include(%q([data-qa-selector="my_element"]))
end
context 'additional selectors' do
let(:element) { described_class.new(:my_element, index: 3, another_match: 'something') }
let(:required_element) { described_class.new(:my_element, required: true, index: 3) }
it 'matches on additional data-qa properties' do
expect(element.selector_css).to include(%q([data-qa-selector="my_element"][data-qa-index="3"]))
end
it 'doesnt conflict with element requirement' do
expect(required_element).to be_required
expect(required_element.selector_css).not_to include(%q(data-qa-required))
end
it 'translates snake_case to kebab-case' do
expect(element.selector_css).to include(%q(data-qa-another-match))
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