updated core and modules

This commit is contained in:
Bachir Soussi Chiadmi
2017-09-09 16:27:51 +02:00
parent 027aa99b32
commit 41863f872c
7810 changed files with 318922 additions and 83631 deletions
@@ -5,15 +5,15 @@
* Text fixture.
*/
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();
$connection->insert('config')
->fields(array(
->fields([
'collection' => '',
'name' => 'views.view.test_token_view',
'data' => serialize(Yaml::decode(file_get_contents('core/modules/views/tests/modules/views_test_config/test_views/views.view.test_token_view.yml'))),
))
])
->execute();
@@ -0,0 +1,19 @@
<?php
/**
* @file
* Test fixture.
*/
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();
$connection->insert('config')
->fields([
'collection' => '',
'name' => 'views.view.test_boolean_filter_values',
'data' => serialize(Yaml::decode(file_get_contents('core/modules/views/tests/fixtures/update/views.view.test_boolean_filter_values.yml'))),
])
->execute();
@@ -5,15 +5,15 @@
* Test fixture.
*/
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();
$connection->insert('config')
->fields(array(
->fields([
'collection' => '',
'name' => 'views.view.test_duplicate_field_handlers',
'data' => serialize(Yaml::decode(file_get_contents('core/modules/views/tests/modules/views_test_config/test_views/views.view.test_duplicate_field_handlers.yml'))),
))
])
->execute();
@@ -0,0 +1,604 @@
langcode: en
status: true
dependencies:
module:
- node
- user
id: test_boolean_filter_values
label: Content
module: node
description: 'Find and manage content.'
tag: default
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_options:
access:
type: perm
options:
perm: 'access content overview'
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
options:
submit_button: Filter
reset_button: true
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 50
tags:
previous: ' Previous'
next: 'Next '
first: '« First'
last: 'Last »'
style:
type: table
options:
grouping: { }
row_class: ''
default_row_class: true
override: true
sticky: true
caption: ''
summary: ''
description: ''
columns:
node_bulk_form: node_bulk_form
title: title
type: type
name: name
status: status
changed: changed
edit_node: edit_node
delete_node: delete_node
dropbutton: dropbutton
timestamp: title
info:
node_bulk_form:
align: ''
separator: ''
empty_column: false
responsive: ''
title:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
type:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
name:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: priority-low
status:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
changed:
sortable: true
default_sort_order: desc
align: ''
separator: ''
empty_column: false
responsive: priority-low
edit_node:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
delete_node:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
dropbutton:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
timestamp:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
default: changed
empty_table: true
row:
type: fields
fields:
node_bulk_form:
id: node_bulk_form
table: node
field: node_bulk_form
label: ''
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: node_bulk_form
entity_type: node
title:
id: title
table: node_field_data
field: title
label: Title
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
entity_type: node
entity_field: title
type: string
settings:
link_to_entity: true
plugin_id: field
type:
id: type
table: node_field_data
field: type
relationship: none
group_type: group
admin_label: ''
label: 'Content type'
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: target_id
type: entity_reference_label
settings:
link: false
group_column: target_id
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: node
entity_field: type
plugin_id: field
name:
id: name
table: users_field_data
field: name
relationship: uid
label: Author
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: field
type: user_name
entity_type: user
entity_field: name
status:
id: status
table: node_field_data
field: status
label: Status
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
type: boolean
settings:
format: custom
format_custom_true: Published
format_custom_false: Unpublished
plugin_id: field
entity_type: node
entity_field: status
changed:
id: changed
table: node_field_data
field: changed
label: Updated
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
type: timestamp
settings:
date_format: short
custom_date_format: ''
timezone: ''
plugin_id: field
entity_type: node
entity_field: changed
operations:
id: operations
table: node
field: operations
relationship: none
group_type: group
admin_label: ''
label: Operations
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
destination: true
plugin_id: entity_operations
filters:
status_extra:
id: status_extra
table: node_field_data
field: status_extra
operator: '='
value: false
plugin_id: node_status
group: 1
entity_type: node
status:
id: status
table: node_field_data
field: status
relationship: none
group_type: group
admin_label: ''
operator: '='
value: true
group: 1
exposed: true
expose:
operator_id: ''
label: Status
description: ''
use_operator: false
operator: status_op
identifier: status
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
is_grouped: true
group_info:
label: 'Published status'
description: ''
identifier: status
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items:
1:
title: Published
operator: '='
value: '1'
2:
title: Unpublished
operator: '='
value: '0'
plugin_id: boolean
entity_type: node
entity_field: status
type:
id: type
table: node_field_data
field: type
relationship: none
group_type: group
admin_label: ''
operator: in
value: { }
group: 1
exposed: true
expose:
operator_id: type_op
label: 'Content type'
description: ''
use_operator: false
operator: type_op
identifier: type
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: bundle
entity_type: node
entity_field: type
title:
id: title
table: node_field_data
field: title
relationship: none
group_type: group
admin_label: ''
operator: contains
value: ''
group: 1
exposed: true
expose:
operator_id: title_op
label: Title
description: ''
use_operator: false
operator: title_op
identifier: title
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: string
entity_type: node
entity_field: title
langcode:
id: langcode
table: node_field_data
field: langcode
relationship: none
group_type: group
admin_label: ''
operator: in
value: { }
group: 1
exposed: true
expose:
operator_id: langcode_op
label: Language
description: ''
use_operator: false
operator: langcode_op
identifier: langcode
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: language
entity_type: node
entity_field: langcode
sorts: { }
title: Content
empty:
area_text_custom:
id: area_text_custom
table: views
field: area_text_custom
empty: true
content: 'No content available.'
plugin_id: text_custom
arguments: { }
relationships:
uid:
id: uid
table: node_field_data
field: uid
admin_label: author
required: true
plugin_id: standard
show_admin_links: false
filter_groups:
operator: AND
groups:
1: AND
display_extenders: { }
display_plugin: default
display_title: Master
id: default
position: 0
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }
page_1:
display_options:
path: admin/content/node
menu:
type: 'default tab'
title: Content
description: ''
menu_name: admin
weight: -10
context: ''
tab_options:
type: normal
title: Content
description: 'Find and manage content'
menu_name: admin
weight: -10
display_extenders: { }
display_plugin: page
display_title: Page
id: page_1
position: 1
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }
@@ -8,8 +8,8 @@ dependencies:
- views
- entity_test
# Information added by Drupal.org packaging script on 2016-08-03
version: '8.1.8'
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
core: '8.x'
project: 'drupal'
datestamp: 1470233790
datestamp: 1502903957
@@ -22,10 +22,10 @@ function views_entity_test_entity_base_field_info(EntityTypeInterface $entity_ty
->setLabel(t('Test access'))
->setTranslatable(FALSE)
->setSetting('max_length', 64)
->setDisplayOptions('form', array(
->setDisplayOptions('form', [
'type' => 'string_textfield',
'weight' => 10,
));
]);
return $definitions;
}
}
@@ -119,7 +119,7 @@ display:
field_api_classes: false
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -0,0 +1,216 @@
langcode: en
status: true
dependencies:
config:
- core.entity_view_mode.node.teaser
- user.role.authenticated
module:
- node
- rest
- user
id: rest_export_with_authorization
label: 'Rest Export'
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: role
options:
role:
authenticated: authenticated
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ' Previous'
next: 'Next '
first: '« First'
last: 'Last »'
quantity: 9
style:
type: default
row:
type: 'entity:node'
options:
view_mode: teaser
fields:
title:
id: title
table: node_field_data
field: title
entity_type: node
entity_field: title
label: ''
alter:
alter_text: false
make_link: false
absolute: false
trim: false
word_boundary: false
ellipsis: false
strip_tags: false
html: false
hide_empty: false
empty_zero: false
settings:
link_to_entity: true
plugin_id: field
relationship: none
group_type: group
admin_label: ''
exclude: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_alter_empty: true
click_sort_column: value
type: string
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
filters:
status:
id: status
table: node_field_data
field: status
relationship: none
group_type: group
admin_label: ''
operator: '='
value: '0'
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
use_operator: false
operator: ''
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: boolean
entity_type: node
entity_field: status
sorts:
created:
id: created
table: node_field_data
field: created
order: DESC
entity_type: node
entity_field: created
plugin_id: date
relationship: none
group_type: group
admin_label: ''
exposed: false
expose:
label: ''
granularity: second
title: 'Rest Export'
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url.query_args
- 'user.node_grants:view'
- user.roles
tags: { }
rest_export_1:
display_plugin: rest_export
id: rest_export_1
display_title: 'REST export'
position: 2
display_options:
display_extenders: { }
path: unpublished-content
auth:
basic_auth: basic_auth
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- request_format
- 'user.node_grants:view'
- user.roles
tags: { }
@@ -0,0 +1,79 @@
langcode: en
status: true
dependencies: { }
id: test_area_result
label: ''
module: views
description: ''
tag: ''
base_table: views_test_data
base_field: nid
core: '8'
display:
default:
display_options:
defaults:
fields: false
pager: false
sorts: false
fields:
id:
field: id
id: id
relationship: none
table: views_test_data
plugin_id: numeric
pager:
options:
offset: 0
type: none
sorts:
id:
field: id
id: id
order: ASC
relationship: none
table: views_test_data
plugin_id: numeric
empty:
title:
field: title
id: title
table: views
plugin_id: title
title: test_title_empty
header:
result:
id: result
table: views
field: result
relationship: none
group_type: group
admin_label: ''
empty: true
content: "start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count"
plugin_id: result
display_plugin: default
display_title: Master
id: default
position: 0
page_1:
display_options:
path: test-area-result
defaults:
header: false
header:
result:
id: result
table: views
field: result
relationship: none
group_type: group
admin_label: ''
empty: false
content: "start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count"
plugin_id: result
display_plugin: page
display_title: 'Page 1'
id: page_1
position: 1
@@ -121,7 +121,7 @@ display:
field_api_classes: false
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -0,0 +1,62 @@
langcode: en
status: true
dependencies:
module:
- node
id: test_argument_default_query_param
label: ''
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: '8'
display:
default:
display_options:
arguments:
type:
id: type
table: node_field_data
field: type
default_action: default
default_argument_type: query_parameter
default_argument_options:
query_param: the_node_type
fallback: all
multiple: and
entity_type: node
entity_field: type
plugin_id: node_type
fields:
title:
alter:
alter_text: false
ellipsis: true
html: false
make_link: false
strip_tags: false
trim: false
word_boundary: true
empty_zero: false
field: title
hide_empty: false
id: title
table: node_field_data
plugin_id: field
entity_type: node
entity_field: title
pager:
options:
id: 0
items_per_page: 10
offset: 0
type: full
style:
type: default
row:
type: fields
display_plugin: default
display_title: Master
id: default
position: 0
@@ -115,7 +115,7 @@ display:
hide_alter_empty: true
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -130,7 +130,7 @@ display:
field_api_classes: false
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -110,7 +110,7 @@ display:
hide_alter_empty: true
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -0,0 +1,616 @@
langcode: en
status: true
dependencies:
module:
- node
- user
id: test_content_ajax
label: Content
module: node
description: 'Find and manage content.'
tag: default
base_table: node_field_data
base_field: nid
core: 8.x
display:
default:
display_options:
use_ajax: true
access:
type: perm
options:
perm: 'access content overview'
cache:
type: tag
query:
type: views_query
exposed_form:
type: basic
options:
submit_button: Filter
reset_button: true
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 50
offset: 0
id: 0
tags:
previous: ' Previous'
next: 'Next '
first: '« First'
last: 'Last »'
expose:
items_per_page: true
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
quantity: 9
style:
type: table
options:
grouping: { }
row_class: ''
default_row_class: true
override: true
sticky: true
caption: ''
summary: ''
description: ''
columns:
node_bulk_form: node_bulk_form
title: title
type: type
name: name
status: status
changed: changed
edit_node: edit_node
delete_node: delete_node
dropbutton: dropbutton
timestamp: title
info:
node_bulk_form:
align: ''
separator: ''
empty_column: false
responsive: ''
title:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
type:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
name:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: priority-low
status:
sortable: true
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
changed:
sortable: true
default_sort_order: desc
align: ''
separator: ''
empty_column: false
responsive: priority-low
edit_node:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
delete_node:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
dropbutton:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
timestamp:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
default: changed
empty_table: true
row:
type: fields
fields:
node_bulk_form:
id: node_bulk_form
table: node
field: node_bulk_form
label: ''
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: node_bulk_form
entity_type: node
title:
id: title
table: node_field_data
field: title
label: Title
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
entity_type: node
entity_field: title
type: string
settings:
link_to_entity: true
plugin_id: field
type:
id: type
table: node_field_data
field: type
relationship: none
group_type: group
admin_label: ''
label: 'Content type'
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: target_id
type: entity_reference_label
settings:
link: false
group_column: target_id
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: node
entity_field: type
plugin_id: field
name:
id: name
table: users_field_data
field: name
relationship: uid
label: Author
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: field
type: user_name
entity_type: user
entity_field: name
status:
id: status
table: node_field_data
field: status
label: Status
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
type: boolean
settings:
format: custom
format_custom_true: Published
format_custom_false: Unpublished
plugin_id: field
entity_type: node
entity_field: status
changed:
id: changed
table: node_field_data
field: changed
label: Updated
exclude: false
alter:
alter_text: false
element_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
type: timestamp
settings:
date_format: short
custom_date_format: ''
timezone: ''
plugin_id: field
entity_type: node
entity_field: changed
operations:
id: operations
table: node
field: operations
relationship: none
group_type: group
admin_label: ''
label: Operations
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
destination: true
plugin_id: entity_operations
filters:
status_extra:
id: status_extra
table: node_field_data
field: status_extra
operator: '='
value: false
plugin_id: node_status
group: 1
entity_type: node
status:
id: status
table: node_field_data
field: status
relationship: none
group_type: group
admin_label: ''
operator: '='
value: '1'
group: 1
exposed: true
expose:
operator_id: ''
label: Status
description: ''
use_operator: false
operator: status_op
identifier: status
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
is_grouped: true
group_info:
label: 'Published status'
description: ''
identifier: status
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items:
1:
title: Published
operator: '='
value: '1'
2:
title: Unpublished
operator: '='
value: '0'
plugin_id: boolean
entity_type: node
entity_field: status
type:
id: type
table: node_field_data
field: type
relationship: none
group_type: group
admin_label: ''
operator: in
value: { }
group: 1
exposed: true
expose:
operator_id: type_op
label: 'Content type'
description: ''
use_operator: false
operator: type_op
identifier: type
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: bundle
entity_type: node
entity_field: type
title:
id: title
table: node_field_data
field: title
relationship: none
group_type: group
admin_label: ''
operator: contains
value: ''
group: 1
exposed: true
expose:
operator_id: title_op
label: Title
description: ''
use_operator: false
operator: title_op
identifier: title
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: string
entity_type: node
entity_field: title
langcode:
id: langcode
table: node_field_data
field: langcode
relationship: none
group_type: group
admin_label: ''
operator: in
value: { }
group: 1
exposed: true
expose:
operator_id: langcode_op
label: Language
description: ''
use_operator: false
operator: langcode_op
identifier: langcode
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: language
entity_type: node
entity_field: langcode
sorts: { }
title: Content
empty:
area_text_custom:
id: area_text_custom
table: views
field: area_text_custom
empty: true
content: 'No content available.'
plugin_id: text_custom
arguments: { }
relationships:
uid:
id: uid
table: node_field_data
field: uid
admin_label: author
required: true
plugin_id: standard
show_admin_links: false
filter_groups:
operator: AND
groups:
1: AND
display_extenders: { }
display_plugin: default
display_title: Master
id: default
position: 0
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }
page_1:
display_options:
path: test-content-ajax
menu:
type: 'default tab'
title: Content
description: ''
menu_name: admin
weight: -10
context: ''
tab_options:
type: normal
title: Content
description: 'Find and manage content'
menu_name: admin
weight: -10
display_extenders: { }
display_plugin: page
display_title: Page
id: page_1
position: 1
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- user
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }
@@ -126,7 +126,7 @@ display:
entity_type: node
entity_field: nid
status:
field: status
field: '1'
id: status
table: node_field_data
plugin_id: boolean
@@ -109,7 +109,7 @@ display:
hide_alter_empty: true
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -35,7 +35,7 @@ display:
group: 1
id: status
table: node_field_data
value: true
value: '1'
plugin_id: boolean
entity_type: node
entity_field: status
@@ -115,7 +115,7 @@ display:
group: 1
id: status
table: node_field_data
value: true
value: '1'
plugin_id: boolean
entity_type: node
entity_field: status
@@ -21,6 +21,8 @@ display:
display_options:
access:
type: perm
options:
perm: 'access content overview'
cache:
type: tag
query:
@@ -159,6 +161,108 @@ display:
hide_empty: false
empty_zero: false
hide_alter_empty: false
edit_node:
id: edit_node
table: node
field: edit_node
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: true
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
text: edit
entity_type: node
plugin_id: entity_link_edit
delete_node:
id: delete_node
table: node
field: delete_node
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: true
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
text: delete
entity_type: node
plugin_id: entity_link_delete
dropbutton:
id: dropbutton
table: views
@@ -211,11 +315,13 @@ display:
fields:
title: title
nothing: nothing
edit_node: edit_node
delete_node: delete_node
nid: '0'
destination: true
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status
@@ -123,3 +123,46 @@ display:
position: null
display_options:
path: test-entity-operations
page_2:
display_plugin: page
id: page_2
display_title: 'Page 2'
position: null
display_options:
path: test-entity-operations-table
style:
type: table
options:
grouping: { }
row_class: ''
default_row_class: true
override: true
sticky: false
caption: ''
summary: ''
description: ''
columns:
title: title
operations: operations
info:
title:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
operations:
align: ''
separator: ''
empty_column: false
responsive: ''
default: '-1'
empty_table: false
row:
type: fields
options: { }
display_extenders: { }
defaults:
style: false
row: false
@@ -31,7 +31,7 @@ display:
field: type
id: type
table: node_field_data
plugin_id: node_type
plugin_id: bundle
entity_type: node
entity_field: type
body_value:
@@ -76,6 +76,72 @@ display:
plugin_id: string
entity_type: node
entity_field: body
created:
id: created
table: node_field_data
field: created
relationship: none
group_type: group
admin_label: ''
operator: '='
value:
min: ''
max: ''
value: ''
type: date
group: 1
exposed: true
expose:
operator_id: created_op
label: 'Authored on'
description: null
use_operator: false
operator: created_op
identifier: created
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
is_grouped: true
group_info:
label: 'Authored on'
description: ''
identifier: created
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items:
1:
title: Between
operator: between
value:
type: date
value: ''
min: '2015-01-01'
max: '2016-01-01'
2:
title: 'Not Between'
operator: 'not between'
value:
type: date
value: ''
min: '2015-01-01'
max: '2016-01-01'
3:
title: Equal
operator: '='
value:
type: date
value: '2016-01-01'
min: ''
max: ''
entity_type: node
entity_field: created
plugin_id: date
pager:
type: full
sorts:
@@ -224,7 +224,7 @@ display:
plugin_id: date
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -144,7 +144,7 @@ display:
plugin_id: field
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -41,7 +41,7 @@ display:
group: 1
id: status
table: node_field_data
value: true
value: '1'
plugin_id: boolean
entity_type: node
entity_field: status
@@ -65,7 +65,7 @@ display:
group: 1
id: status
table: node_field_data
value: true
value: '1'
plugin_id: boolean
entity_type: node
entity_field: status
@@ -130,7 +130,7 @@ display:
group: 1
id: status
table: node_field_data
value: true
value: '1'
plugin_id: boolean
entity_type: node
entity_field: status
@@ -59,7 +59,7 @@ display:
entity_field: title
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status
@@ -5,56 +5,450 @@ dependencies:
- node
- user
id: test_glossary
label: test_glossary
module: views
description: ''
label: Test glossary
module: node
description: 'All content, by letter.'
tag: default
base_table: node_field_data
base_field: nid
core: '8'
display:
default:
id: default
display_title: Master
display_plugin: default
position: 0
display_options:
access:
type: perm
arguments:
title:
default_argument_type: fixed
field: title
glossary: true
id: title
limit: 1
summary:
format: default_summary
number_of_records: 0
summary_options:
items_per_page: 25
table: node_field_data
plugin_id: string
entity_type: node
entity_field: title
cache:
type: tag
exposed_form:
type: basic
fields:
title:
field: title
id: title
label: ''
table: node_field_data
plugin_id: field
entity_type: node
entity_field: title
pager:
type: full
query:
type: views_query
options:
query_comment: ''
disable_sql_rewrite: false
distinct: false
replica: false
query_tags: { }
use_ajax: true
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: mini
options:
items_per_page: 36
offset: 0
id: 0
total_pages: 0
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ‹‹
next: ››
fields:
title:
id: title
table: node_field_data
field: title
plugin_id: field
relationship: none
group_type: group
admin_label: ''
label: Title
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
entity_type: node
entity_field: title
name:
id: name
table: users_field_data
field: name
label: Author
relationship: uid
plugin_id: field
type: user_name
group_type: group
admin_label: ''
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
entity_type: user
entity_field: name
changed:
id: changed
table: node_field_data
field: changed
label: 'Last update'
type: timestamp
settings:
date_format: long
custom_date_format: ''
timezone: ''
plugin_id: field
relationship: none
group_type: group
admin_label: ''
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
entity_type: node
entity_field: changed
arguments:
title:
id: title
table: node_field_data
field: title
default_action: default
exception:
title_enable: true
default_argument_type: fixed
default_argument_options:
argument: a
summary:
format: default_summary
specify_validation: true
glossary: true
limit: 1
case: upper
path_case: lower
transform_dash: false
plugin_id: string
relationship: none
group_type: group
admin_label: ''
title_enable: false
title: ''
default_argument_skip_url: false
summary_options: { }
validate:
type: none
fail: 'not found'
validate_options: { }
break_phrase: false
entity_type: node
entity_field: title
relationships:
uid:
id: uid
table: node_field_data
field: uid
plugin_id: standard
relationship: none
group_type: group
admin_label: author
required: false
style:
type: default
type: table
options:
columns:
title: title
name: name
changed: changed
default: title
info:
title:
sortable: true
separator: ''
name:
sortable: true
separator: ''
changed:
sortable: true
separator: ''
override: true
sticky: false
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
order: asc
summary: ''
empty_table: false
row:
type: fields
display_plugin: default
display_title: Master
id: default
position: 0
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
header: { }
footer: { }
empty: { }
sorts: { }
filters:
langcode:
id: langcode
table: node_field_data
field: langcode
relationship: none
group_type: group
admin_label: ''
operator: in
value:
'***LANGUAGE_language_content***': '***LANGUAGE_language_content***'
group: 1
exposed: false
expose:
operator_id: ''
label: ''
description: ''
use_operator: false
operator: ''
identifier: ''
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
reduce: false
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
plugin_id: language
entity_type: node
entity_field: langcode
display_extenders: { }
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }
attachment_1:
id: attachment_1
display_title: Attachment
display_plugin: attachment
position: 2
display_options:
query:
type: views_query
options: { }
pager:
type: none
options:
offset: 0
items_per_page: 0
defaults:
arguments: false
arguments:
title:
id: title
table: node_field_data
field: title
default_action: summary
exception:
title_enable: true
default_argument_type: fixed
default_argument_options:
argument: a
summary:
format: unformatted_summary
summary_options:
items_per_page: 25
inline: true
separator: ' | '
specify_validation: true
glossary: true
limit: 1
case: upper
path_case: lower
transform_dash: false
plugin_id: string
relationship: none
group_type: group
admin_label: ''
title_enable: false
title: ''
default_argument_skip_url: false
validate:
type: none
fail: 'not found'
validate_options: { }
break_phrase: false
entity_type: node
entity_field: title
displays:
default: default
page_1: page_1
inherit_arguments: false
display_extenders: { }
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }
page_1:
id: page_1
display_title: Page
display_plugin: page
position: 1
display_options:
query:
type: views_query
options: { }
path: test-glossary
menu:
type: normal
title: Glossary
weight: 0
menu_name: main
parent: ''
display_extenders: { }
cache_metadata:
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
- 'user.node_grants:view'
- user.permissions
max-age: 0
tags: { }
@@ -107,7 +107,7 @@ display:
comments: false
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -152,7 +152,7 @@ display:
group_type: group
admin_label: ''
operator: '='
value: true
value: '1'
group: 1
exposed: false
expose:
@@ -54,7 +54,7 @@ display:
entity_field: title
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status
@@ -0,0 +1,53 @@
langcode: en
status: true
dependencies: { }
id: test_invalid_tokens
label: 'Test invalid tokens'
module: views
description: 'Test view to invalid token replacement tests.'
tag: ''
base_table: views_test_data
base_field: id
core: 8.x
display:
default:
display_options:
title: 'Test token default'
defaults:
fields: false
pager: false
sorts: false
fields:
age:
field: age
id: age
relationship: none
table: views_test_data
plugin_id: numeric
id:
field: id
id: id
relationship: none
table: views_test_data
plugin_id: numeric
name:
field: name
id: name
relationship: none
table: views_test_data
plugin_id: string
pager:
type: full
options:
items_per_page: 10
display_plugin: default
display_title: Master
id: default
position: 0
block_1:
display_plugin: block
id: block_1
display_title: Block
position: 1
display_options:
display_extenders: { }
@@ -118,3 +118,26 @@ display:
type: mini
options:
items_per_page: 0
page_4:
display_plugin: page
id: page_4
display_title: 'Page 4'
position: 4
display_options:
display_extenders: { }
path: test_mini_pager_total
empty: { }
defaults:
empty: false
header: false
header:
result:
id: result
table: views
field: result
relationship: none
group_type: group
admin_label: ''
empty: false
content: 'Displaying @start - @end of @total'
plugin_id: result
@@ -59,7 +59,7 @@ display:
entity_field: title
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status
@@ -464,7 +464,7 @@ display:
plugin_id: entity_operations
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -464,7 +464,7 @@ display:
plugin_id: entity_operations
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -97,7 +97,7 @@ display:
link_to_entity: true
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status
@@ -135,7 +135,7 @@ display:
display_description: ''
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status
@@ -200,7 +200,7 @@ display:
display_description: ''
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status
@@ -96,7 +96,6 @@ display:
footer: { }
empty: { }
relationships: { }
fields: { }
display_extenders: { }
cache_metadata:
contexts:
@@ -0,0 +1,191 @@
langcode: en
status: true
dependencies:
module:
- taxonomy
id: test_taxonomy_glossary
label: test_taxonomy_glossary
module: views
description: ''
tag: ''
base_table: taxonomy_term_field_data
base_field: tid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: none
options: { }
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: mini
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ‹‹
next: ››
style:
type: default
row:
type: fields
fields:
name:
id: name
table: taxonomy_term_field_data
field: name
entity_type: taxonomy_term
entity_field: name
label: ''
alter:
alter_text: false
make_link: false
absolute: false
trim: false
word_boundary: false
ellipsis: false
strip_tags: false
html: false
hide_empty: false
empty_zero: false
type: string
settings:
link_to_entity: true
plugin_id: term_name
relationship: none
group_type: group
admin_label: ''
exclude: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_alter_empty: true
click_sort_column: value
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
convert_spaces: false
filters: { }
sorts: { }
title: test_taxonomy_glossary
header: { }
footer: { }
empty: { }
relationships: { }
arguments:
name:
id: name
table: taxonomy_term_field_data
field: name
relationship: none
group_type: group
admin_label: ''
default_action: ignore
exception:
value: all
title_enable: false
title: All
title_enable: false
title: ''
default_argument_type: fixed
default_argument_options:
argument: ''
default_argument_skip_url: false
summary_options:
base_path: ''
count: true
items_per_page: 25
override: false
summary:
sort_order: asc
number_of_records: 0
format: default_summary
specify_validation: false
validate:
type: none
fail: 'not found'
validate_options: { }
glossary: true
limit: 1
case: none
path_case: none
transform_dash: false
break_phrase: false
add_table: false
require_value: false
entity_type: taxonomy_term
entity_field: name
plugin_id: string
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
tags: { }
page_1:
display_plugin: page
id: page_1
display_title: Page
position: 1
display_options:
display_extenders: { }
path: test_taxonomy_glossary
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- url.query_args
tags: { }
@@ -151,7 +151,7 @@ display:
plugin_id: field
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
plugin_id: boolean
@@ -77,3 +77,34 @@ display:
operator: '='
value: 'not an existing name'
path: test_tokens_empty
page_3:
display_plugin: page
id: page_3
display_title: Page
position: 1
display_options:
defaults:
title: false
pager: false
header: false
pager:
type: mini
options:
items_per_page: 2
title: 'Test token page with minipager'
path: test_tokens_minipager
display_extenders: { }
header:
area:
id: area
table: views
field: area
relationship: none
group_type: group
admin_label: ''
empty: false
tokenize: false
content:
value: "Total rows: [view:total-rows] - Page count: [view:page-count]"
format: basic_html
plugin_id: text
@@ -7,8 +7,8 @@ package: Testing
dependencies:
- views
# Information added by Drupal.org packaging script on 2016-08-03
version: '8.1.8'
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
core: '8.x'
project: 'drupal'
datestamp: 1470233790
datestamp: 1502903957
@@ -0,0 +1,27 @@
<?php
namespace Drupal\views_test_data\Controller;
/**
* Controller class for views_test_data callbacks.
*/
class ViewsTestDataController {
/**
* Renders an error form page.
*
* This contains a form that will contain an error and an embedded view with
* an exposed form.
*/
public function errorFormPage() {
$build = [];
$build['view'] = [
'#type' => 'view',
'#name' => 'test_exposed_form_buttons',
];
$build['error_form'] = \Drupal::formBuilder()->getForm('Drupal\views_test_data\Form\ViewsTestDataErrorForm');
return $build;
}
}
@@ -21,13 +21,13 @@ class ViewsTestDataElementEmbedForm extends FormBase {
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['view'] = array(
$form['view'] = [
'#type' => 'view',
'#name' => 'test_view_embed',
'#display_id' => 'embed_1',
'#arguments' => array(25),
'#arguments' => [25],
'#embed' => TRUE,
);
];
return $form;
}
@@ -21,13 +21,13 @@ class ViewsTestDataElementForm extends FormBase {
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['view'] = array(
$form['view'] = [
'#type' => 'view',
'#name' => 'test_view_embed',
'#display_id' => 'default',
'#arguments' => array(25),
'#arguments' => [25],
'#embed' => FALSE,
);
];
return $form;
}
@@ -0,0 +1,48 @@
<?php
namespace Drupal\views_test_data\Form;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Implements a test form that has a validation error.
*/
class ViewsTestDataErrorForm implements FormInterface {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'views_test_data_error_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['text'] = [
'#type' => 'textfield',
];
$form['submit'] = [
'#type' => 'submit',
'#value' => t('Submit'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
$form_state->setErrorByName('text', t('Form validation error'));
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
}
}
@@ -19,7 +19,7 @@ class StaticTest extends AccessPluginBase {
protected function defineOptions() {
$options = parent::defineOptions();
$options['access'] = array('default' => FALSE);
$options['access'] = ['default' => FALSE];
return $options;
}
@@ -27,8 +27,8 @@ class TestExample extends AreaPluginBase {
*/
public function defineOptions() {
$options = parent::defineOptions();
$options['string'] = array('default' => '');
$options['custom_access'] = array('default' => TRUE);
$options['string'] = ['default' => ''];
$options['custom_access'] = ['default' => TRUE];
return $options;
}
@@ -46,11 +46,11 @@ class TestExample extends AreaPluginBase {
*/
public function render($empty = FALSE) {
if (!$empty || !empty($this->options['empty'])) {
return array(
return [
'#markup' => $this->globalTokenReplace($this->options['string']),
);
];
}
return array();
return [];
}
}
@@ -19,7 +19,7 @@ class ArgumentDefaultTest extends ArgumentDefaultPluginBase {
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['value'] = array('default' => '');
$options['value'] = ['default' => ''];
return $options;
}
@@ -28,6 +28,7 @@ class ArgumentDefaultTest extends ArgumentDefaultPluginBase {
* {@inheritdoc}
*/
public function getArgument() {
$this->view->element['#cache']['tags'][] = 'example_tag';
return $this->options['value'];
}
@@ -39,7 +39,7 @@ class DisplayTest extends DisplayPluginBase {
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['test_option'] = array('default' => '');
$options['test_option'] = ['default' => ''];
return $options;
}
@@ -50,21 +50,21 @@ class DisplayTest extends DisplayPluginBase {
public function optionsSummary(&$categories, &$options) {
parent::optionsSummary($categories, $options);
$categories['display_test'] = array(
$categories['display_test'] = [
'title' => $this->t('Display test settings'),
'column' => 'second',
'build' => array(
'build' => [
'#weight' => -100,
),
);
],
];
$test_option = $this->getOption('test_option') ?: $this->t('Empty');
$options['test_option'] = array(
$options['test_option'] = [
'category' => 'display_test',
'title' => $this->t('Test option'),
'value' => views_ui_truncate($test_option, 24),
);
];
}
/**
@@ -76,12 +76,12 @@ class DisplayTest extends DisplayPluginBase {
switch ($form_state->get('section')) {
case 'test_option':
$form['#title'] .= $this->t('Test option');
$form['test_option'] = array(
$form['test_option'] = [
'#title' => $this->t('Test option'),
'#type' => 'textfield',
'#description' => $this->t('This is a textfield for test_option.'),
'#default_value' => $this->getOption('test_option'),
);
];
break;
}
}
@@ -39,19 +39,19 @@ class DisplayExtenderTest extends DisplayExtenderPluginBase {
public function optionsSummary(&$categories, &$options) {
parent::optionsSummary($categories, $options);
$categories['display_extender_test'] = array(
$categories['display_extender_test'] = [
'title' => $this->t('Display extender test settings'),
'column' => 'second',
'build' => array(
'build' => [
'#weight' => -100,
),
);
],
];
$options['test_extender_test_option'] = array(
$options['test_extender_test_option'] = [
'category' => 'display_extender_test',
'title' => $this->t('Test option'),
'value' => views_ui_truncate($this->options['test_extender_test_option'], 24),
);
];
}
/**
@@ -61,12 +61,12 @@ class DisplayExtenderTest extends DisplayExtenderPluginBase {
switch ($form_state->get('section')) {
case 'test_extender_test_option':
$form['#title'] .= $this->t('Test option');
$form['test_extender_test_option'] = array(
$form['test_extender_test_option'] = [
'#title' => $this->t('Test option'),
'#type' => 'textfield',
'#description' => $this->t('This is a textfield for test_option.'),
'#default_value' => $this->options['test_extender_test_option'],
);
];
}
}
@@ -86,7 +86,7 @@ class DisplayExtenderTest extends DisplayExtenderPluginBase {
* {@inheritdoc}
*/
public function defaultableSections(&$sections, $section = NULL) {
$sections['test_extender_test_option'] = array('test_extender_test_option');
$sections['test_extender_test_option'] = ['test_extender_test_option'];
}
/**
@@ -0,0 +1,25 @@
<?php
namespace Drupal\views_test_data\Plugin\views\filter;
use Drupal\views\Plugin\views\filter\BooleanOperator;
/**
* Filter to test queryOpBoolean() with default operator.
*
* @ingroup views_filter_handlers
*
* @ViewsFilter("boolean_default")
*/
class FilterBooleanOperatorDefaultTest extends BooleanOperator {
/**
* {@inheritdoc}
*/
public function query() {
$this->ensureMyTable();
$field = "$this->tableAlias.$this->realField";
$this->queryOpBoolean($field);
}
}
@@ -18,7 +18,7 @@ class FilterTest extends FilterPluginBase {
protected function defineOptions() {
$options = parent::defineOptions();
$options['test_enable'] = array('default' => TRUE);
$options['test_enable'] = ['default' => TRUE];
return $options;
}
@@ -30,11 +30,11 @@ class FilterTest extends FilterPluginBase {
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['test_enable'] = array(
$form['test_enable'] = [
'#type' => 'checkbox',
'#title' => $this->t('Controls whether the filter plugin should be active'),
'#default_value' => $this->options['test_enable'],
);
];
}
/**
@@ -18,17 +18,17 @@ use Drupal\views\ViewExecutable;
* )
*/
class QueryTest extends QueryPluginBase {
protected $conditions = array();
protected $fields = array();
protected $allItems = array();
protected $orderBy = array();
protected $conditions = [];
protected $fields = [];
protected $allItems = [];
protected $orderBy = [];
/**
* {@inheritdoc}
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['test_setting'] = array('default' => '');
$options['test_setting'] = ['default' => ''];
return $options;
}
@@ -39,11 +39,11 @@ class QueryTest extends QueryPluginBase {
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['test_setting'] = array(
$form['test_setting'] = [
'#title' => $this->t('Test setting'),
'#type' => 'textfield',
'#default_value' => $this->options['test_setting'],
);
];
}
/**
@@ -57,21 +57,21 @@ class QueryTest extends QueryPluginBase {
}
public function addWhere($group, $field, $value = NULL, $operator = NULL) {
$this->conditions[] = array(
$this->conditions[] = [
'field' => $field,
'value' => $value,
'operator' => $operator
);
];
}
public function addField($table, $field, $alias = '', $params = array()) {
public function addField($table, $field, $alias = '', $params = []) {
$this->fields[$field] = $field;
return $field;
}
public function addOrderBy($table, $field = NULL, $order = 'ASC', $alias = '', $params = array()) {
$this->orderBy = array('field' => $field, 'order' => $order);
public function addOrderBy($table, $field = NULL, $order = 'ASC', $alias = '', $params = []) {
$this->orderBy = ['field' => $field, 'order' => $order];
}
@@ -90,13 +90,13 @@ class QueryTest extends QueryPluginBase {
// @todo You could add a string representation of the query.
$this->view->build_info['query'] = "";
$this->view->build_info['count_query'] = "";
}
}
/**
* {@inheritdoc}
*/
public function execute(ViewExecutable $view) {
$result = array();
$result = [];
foreach ($this->allItems as $element) {
// Run all conditions on the element, and add it to the result if they
// match.
@@ -32,7 +32,7 @@ class RowTest extends RowPluginBase {
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['test_option'] = array('default' => '');
$options['test_option'] = ['default' => ''];
return $options;
}
@@ -43,12 +43,12 @@ class RowTest extends RowPluginBase {
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['test_option'] = array(
$form['test_option'] = [
'#title' => $this->t('Test option'),
'#type' => 'textfield',
'#description' => $this->t('This is a textfield for test_option.'),
'#default_value' => $this->options['test_option'],
);
];
}
/**
@@ -24,26 +24,26 @@ class MappingTest extends Mapping {
* {@inheritdoc}
*/
protected function defineMapping() {
return array(
'title_field' => array(
return [
'title_field' => [
'#title' => $this->t('Title field'),
'#description' => $this->t('Choose the field with the custom title.'),
'#toggle' => TRUE,
'#required' => TRUE,
),
'name_field' => array(
],
'name_field' => [
'#title' => $this->t('Name field'),
'#description' => $this->t('Choose the field with the custom name.'),
),
'numeric_field' => array(
],
'numeric_field' => [
'#title' => $this->t('Numeric field'),
'#description' => $this->t('Select one or more numeric fields.'),
'#multiple' => TRUE,
'#toggle' => TRUE,
'#filter' => 'filterNumericFields',
'#required' => TRUE,
),
);
],
];
}
/**
@@ -20,9 +20,7 @@ use Drupal\views\Plugin\views\style\StylePluginBase;
class StyleTemplateTest extends StylePluginBase {
/**
* Can the style plugin use row plugins.
*
* @var bool
* {@inheritdoc}
*/
protected $usesRowPlugin = TRUE;
@@ -29,9 +29,7 @@ class StyleTest extends StylePluginBase {
public $output;
/**
* Can the style plugin use row plugins.
*
* @var bool
* {@inheritdoc}
*/
protected $usesRowPlugin = TRUE;
@@ -40,7 +38,7 @@ class StyleTest extends StylePluginBase {
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['test_option'] = array('default' => '');
$options['test_option'] = ['default' => ''];
return $options;
}
@@ -51,12 +49,12 @@ class StyleTest extends StylePluginBase {
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['test_option'] = array(
$form['test_option'] = [
'#title' => $this->t('Test option'),
'#type' => 'textfield',
'#description' => $this->t('This is a textfield for test_option.'),
'#default_value' => $this->options['test_option'],
);
];
}
/**
@@ -7,8 +7,8 @@ package: Testing
dependencies:
- views
# Information added by Drupal.org packaging script on 2016-08-03
version: '8.1.8'
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
core: '8.x'
project: 'drupal'
datestamp: 1470233790
datestamp: 1502903957
@@ -17,7 +17,7 @@ function views_test_data_schema() {
*/
function views_test_data_install() {
// Add the marquee tag to possible html elements to test the field handler.
$values = array(
$values = [
'div' => 'DIV',
'span' => 'SPAN',
'h1' => 'H1',
@@ -30,6 +30,6 @@ function views_test_data_install() {
'strong' => 'STRONG',
'em' => 'EM',
'marquee' => 'MARQUEE'
);
];
\Drupal::configFactory()->getEditable('views.settings')->set('field_rewrite_elements', $values)->save();
}
@@ -66,13 +66,13 @@ function views_test_data_preprocess_views_view_table(&$variables) {
* - view: The view object.
*/
function template_preprocess_views_view_mapping_test(&$variables) {
$variables['element'] = array();
$variables['element'] = [];
foreach ($variables['rows'] as $delta => $row) {
$fields = array();
$fields = [];
foreach ($variables['options']['mapping'] as $type => $field_names) {
if (!is_array($field_names)) {
$field_names = array($field_names);
$field_names = [$field_names];
}
foreach ($field_names as $field_name) {
if ($value = $variables['view']->style_plugin->getField($delta, $field_name)) {
@@ -87,26 +87,26 @@ function template_preprocess_views_view_mapping_test(&$variables) {
}
// Build a container for the row.
$variables['element'][$delta] = array(
$variables['element'][$delta] = [
'#type' => 'container',
'#attributes' => array(
'class' => array(
'#attributes' => [
'class' => [
'views-row-mapping-test',
),
),
);
],
],
];
// Add each field to the row.
foreach ($fields as $key => $render) {
$variables['element'][$delta][$key] = array(
$variables['element'][$delta][$key] = [
'#children' => $render,
'#type' => 'container',
'#attributes' => array(
'class' => array(
'#attributes' => [
'class' => [
$key,
),
),
);
],
],
];
}
}
}
@@ -19,3 +19,11 @@ views_test_data.form_multiple:
_controller: '\Drupal\views_test_data\Controller\ViewsTestFormMultipleController::testPage'
requirements:
_access: 'TRUE'
views_test_data.error_form_page:
path: '/views_test_data_error_form_page'
defaults:
_title: 'Test Views Form Exposed Errors'
_controller: '\Drupal\views_test_data\Controller\ViewsTestDataController::errorFormPage'
requirements:
_access: 'TRUE'
@@ -39,7 +39,7 @@ function views_test_data_views_data_alter() {
function views_test_data_views_analyze(ViewExecutable $view) {
\Drupal::state()->set('views_hook_test_views_analyze', TRUE);
$ret = array();
$ret = [];
$ret[] = Analyzer::formatMessage(t('Test ok message'), 'ok');
$ret[] = Analyzer::formatMessage(t('Test warning message'), 'warning');
@@ -22,10 +22,10 @@ function views_test_data_views_query_substitutions(ViewExecutable $view) {
function views_test_data_views_form_substitutions() {
\Drupal::state()->set('views_hook_test_views_form_substitutions', TRUE);
$render = ['#markup' => '<em>unescaped</em>'];
return array(
return [
'<!--will-be-escaped-->' => '<em>escaped</em>',
'<!--will-be-not-escaped-->' => \Drupal::service('renderer')->renderPlain($render),
);
];
}
/**
@@ -7,8 +7,8 @@ package: Testing
dependencies:
- views
# Information added by Drupal.org packaging script on 2016-08-03
version: '8.1.8'
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
core: '8.x'
project: 'drupal'
datestamp: 1470233790
datestamp: 1502903957
@@ -8,8 +8,8 @@ dependencies:
- views
- language
# Information added by Drupal.org packaging script on 2016-08-03
version: '8.1.8'
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
core: '8.x'
project: 'drupal'
datestamp: 1470233790
datestamp: 1502903957
@@ -0,0 +1,220 @@
<?php
namespace Drupal\Tests\views\Functional;
use Drupal\comment\CommentInterface;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\views\Views;
use Drupal\comment\Entity\Comment;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\taxonomy\Entity\Term;
/**
* Tests the default views provided by views.
*
* @group views
*/
class DefaultViewsTest extends ViewTestBase {
use CommentTestTrait;
use EntityReferenceTestTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['views', 'node', 'search', 'comment', 'taxonomy', 'block', 'user'];
/**
* An array of argument arrays to use for default views.
*
* @var array
*/
protected $viewArgMap = [
'backlinks' => [1],
'taxonomy_term' => [1],
'glossary' => ['all'],
];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->drupalPlaceBlock('page_title_block');
// Create Basic page node type.
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
$vocabulary = Vocabulary::create([
'name' => $this->randomMachineName(),
'description' => $this->randomMachineName(),
'vid' => Unicode::strtolower($this->randomMachineName()),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
'help' => '',
'nodes' => ['page' => 'page'],
'weight' => mt_rand(0, 10),
]);
$vocabulary->save();
// Create a field.
$field_name = Unicode::strtolower($this->randomMachineName());
$handler_settings = [
'target_bundles' => [
$vocabulary->id() => $vocabulary->id(),
],
'auto_create' => TRUE,
];
$this->createEntityReferenceField('node', 'page', $field_name, NULL, 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
// Create a time in the past for the archive.
$time = REQUEST_TIME - 3600;
$this->addDefaultCommentField('node', 'page');
for ($i = 0; $i <= 10; $i++) {
$user = $this->drupalCreateUser();
$term = $this->createTerm($vocabulary);
$values = ['created' => $time, 'type' => 'page'];
$values[$field_name][]['target_id'] = $term->id();
// Make every other node promoted.
if ($i % 2) {
$values['promote'] = TRUE;
}
$values['body'][]['value'] = \Drupal::l('Node ' . 1, new Url('entity.node.canonical', ['node' => 1]));
$node = $this->drupalCreateNode($values);
$comment = [
'uid' => $user->id(),
'status' => CommentInterface::PUBLISHED,
'entity_id' => $node->id(),
'entity_type' => 'node',
'field_name' => 'comment'
];
Comment::create($comment)->save();
}
// Some views, such as the "Who's Online" view, only return results if at
// least one user is logged in.
$account = $this->drupalCreateUser([]);
$this->drupalLogin($account);
}
/**
* Test that all Default views work as expected.
*/
public function testDefaultViews() {
// Get all default views.
$controller = $this->container->get('entity.manager')->getStorage('view');
$views = $controller->loadMultiple();
foreach ($views as $name => $view_storage) {
$view = $view_storage->getExecutable();
$view->initDisplay();
foreach ($view->storage->get('display') as $display_id => $display) {
$view->setDisplay($display_id);
// Add any args if needed.
if (array_key_exists($name, $this->viewArgMap)) {
$view->preExecute($this->viewArgMap[$name]);
}
$this->assert(TRUE, format_string('View @view will be executed.', ['@view' => $view->storage->id()]));
$view->execute();
$tokens = ['@name' => $name, '@display_id' => $display_id];
$this->assertTrue($view->executed, format_string('@name:@display_id has been executed.', $tokens));
$count = count($view->result);
$this->assertTrue($count > 0, format_string('@count results returned', ['@count' => $count]));
$view->destroy();
}
}
}
/**
* Returns a new term with random properties in vocabulary $vid.
*/
public function createTerm($vocabulary) {
$filter_formats = filter_formats();
$format = array_pop($filter_formats);
$term = Term::create([
'name' => $this->randomMachineName(),
'description' => $this->randomMachineName(),
// Use the first available text format.
'format' => $format->id(),
'vid' => $vocabulary->id(),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
]);
$term->save();
return $term;
}
/**
* Tests the archive view.
*/
public function testArchiveView() {
// Create additional nodes compared to the one in the setup method.
// Create two nodes in the same month, and one in each following month.
$node = [
'created' => 280299600, // Sun, 19 Nov 1978 05:00:00 GMT
];
$this->drupalCreateNode($node);
$this->drupalCreateNode($node);
$node = [
'created' => 282891600, // Tue, 19 Dec 1978 05:00:00 GMT
];
$this->drupalCreateNode($node);
$node = [
'created' => 285570000, // Fri, 19 Jan 1979 05:00:00 GMT
];
$this->drupalCreateNode($node);
$view = Views::getView('archive');
$view->setDisplay('page_1');
$this->executeView($view);
$columns = ['nid', 'created_year_month', 'num_records'];
$column_map = array_combine($columns, $columns);
// Create time of additional nodes created in the setup method.
$created_year_month = date('Ym', REQUEST_TIME - 3600);
$expected_result = [
[
'nid' => 1,
'created_year_month' => $created_year_month,
'num_records' => 11,
],
[
'nid' => 15,
'created_year_month' => 197901,
'num_records' => 1,
],
[
'nid' => 14,
'created_year_month' => 197812,
'num_records' => 1,
],
[
'nid' => 12,
'created_year_month' => 197811,
'num_records' => 2,
],
];
$this->assertIdenticalResultset($view, $expected_result, $column_map);
$view->storage->setStatus(TRUE);
$view->save();
\Drupal::service('router.builder')->rebuild();
$this->drupalGet('archive');
$this->assertResponse(200);
}
}
@@ -0,0 +1,71 @@
<?php
namespace Drupal\Tests\views\Functional\Entity;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
/**
* Tests views base field access.
*
* @group views
*/
class BaseFieldAccessTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_entity_test_protected_access'];
/**
* Modules to enable
*
* @var array
*/
public static $modules = [
'views', 'views_test_config', 'entity_test', 'node', 'views_entity_test',
];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
/** @var \Drupal\Core\Entity\EntityDefinitionUpdateManager $update_manager */
$update_manager = $this->container->get('entity.definition_update_manager');
\Drupal::entityManager()->clearCachedDefinitions();
$update_manager->applyUpdates();
ViewTestData::createTestViews(get_class($this), ['comment_test_views']);
\Drupal::state()->set('entity_test.views_data', [
'entity_test' => [
'test_text_access' => [
'field' => [
'id' => 'standard',
],
],
],
]);
$entity_1 = EntityTest::create([
'test_text_access' => 'no access value',
]);
$entity_1->save();
$entity_2 = EntityTest::create([
'test_text_access' => 'ok to see this one',
]);
$entity_2->save();
$this->drupalLogin($this->drupalCreateUser(['access content']));
}
/**
* Test access to protected base fields.
*/
public function testProtectedField() {
$this->drupalGet('test-entity-protected-access');
$this->assertText('ok to see this one');
$this->assertNoText('no access value');
}
}
@@ -0,0 +1,90 @@
<?php
namespace Drupal\Tests\views\Functional\Entity;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\node\Entity\Node;
use Drupal\user\Entity\User;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
use Drupal\views\Views;
use Drupal\comment\Entity\Comment;
/**
* Tests the field plugin base integration with the entity system.
*
* @group views
*/
class FieldEntityTest extends ViewTestBase {
use CommentTestTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_field_get_entity'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'comment'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp(FALSE);
$this->drupalCreateContentType(['type' => 'page']);
$this->addDefaultCommentField('node', 'page');
ViewTestData::createTestViews(get_class($this), ['views_test_config']);
}
/**
* Tests the getEntity method.
*/
public function testGetEntity() {
// The view is a view of comments, their nodes and their authors, so there
// are three layers of entities.
$account = User::create(['name' => $this->randomMachineName(), 'bundle' => 'user']);
$account->save();
$node = Node::create([
'uid' => $account->id(),
'type' => 'page',
'title' => $this->randomString(),
]);
$node->save();
$comment = Comment::create([
'uid' => $account->id(),
'entity_id' => $node->id(),
'entity_type' => 'node',
'field_name' => 'comment'
]);
$comment->save();
$user = $this->drupalCreateUser(['access comments']);
$this->drupalLogin($user);
$view = Views::getView('test_field_get_entity');
$this->executeView($view);
$row = $view->result[0];
// Tests entities on the base level.
$entity = $view->field['cid']->getEntity($row);
$this->assertEqual($entity->id(), $comment->id(), 'Make sure the right comment entity got loaded.');
// Tests entities as relationship on first level.
$entity = $view->field['nid']->getEntity($row);
$this->assertEqual($entity->id(), $node->id(), 'Make sure the right node entity got loaded.');
// Tests entities as relationships on second level.
$entity = $view->field['uid']->getEntity($row);
$this->assertEqual($entity->id(), $account->id(), 'Make sure the right user entity got loaded.');
}
}
@@ -0,0 +1,174 @@
<?php
namespace Drupal\Tests\views\Functional\Entity;
use Drupal\Core\Language\Language;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\views\Functional\ViewTestBase;
use Symfony\Component\CssSelector\CssSelectorConverter;
/**
* Tests the rendering of fields (base fields) and their translations.
*
* @group views
*/
class FieldEntityTranslationTest extends ViewTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['language', 'locale', 'content_translation', 'node'];
/**
* {@inheritdoc}
*/
public static $testViews = ['test_entity_field_renderers'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$node_type = NodeType::create([
'type' => 'article',
'label' => 'Article',
]);
$node_type->save();
/** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
$content_translation_manager = \Drupal::service('content_translation.manager');
$content_translation_manager->setEnabled('node', 'article', TRUE);
$language = ConfigurableLanguage::create([
'id' => 'es',
'label' => 'Spanish',
]);
$language->save();
// Rebuild the container to setup the language path processors.
$this->rebuildContainer();
}
/**
* Tests that different translation mechanisms can be used for base fields.
*/
public function testTranslationRows() {
$node = Node::create([
'type' => 'article',
'title' => 'example EN',
'sticky' => FALSE,
]);
$node->save();
$translation = $node->addTranslation('es');
$translation->title->value = 'example ES';
$translation->sticky->value = TRUE;
$translation->save();
$this->drupalGet('test_entity_field_renderers/entity_translation');
$this->assertRows([
[
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example ES',
'sticky' => 'On',
],
]);
$this->drupalGet('test_entity_field_renderers/entity_default');
$this->assertRows([
[
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
$this->drupalGet('test_entity_field_renderers/site_default');
$this->assertRows([
[
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
$this->drupalGet('test_entity_field_renderers/language_interface');
$this->assertRows([
[
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
$this->drupalGet('test_entity_field_renderers/language_interface', ['language' => new Language(['id' => 'es'])]);
$this->assertRows([
[
'title' => 'example ES',
'sticky' => 'On',
],
[
'title' => 'example ES',
'sticky' => 'On',
],
]);
$this->drupalGet('test_entity_field_renderers/en');
$this->assertRows([
[
'title' => 'example EN',
'sticky' => 'Off',
],
[
'title' => 'example EN',
'sticky' => 'Off',
],
]);
$this->drupalGet('test_entity_field_renderers/es');
$this->assertRows([
[
'title' => 'example ES',
'sticky' => 'On',
],
[
'title' => 'example ES',
'sticky' => 'On',
],
]);
}
/**
* Ensures that the rendered results are working as expected.
*
* @param array $expected
* The expected rows of the result.
*/
protected function assertRows($expected = []) {
$actual = [];
$rows = $this->cssSelect('div.views-row');
foreach ($rows as $row) {
$actual[] = [
'title' => $row->find('xpath', (new CssSelectorConverter())->toXPath('.views-field-title span.field-content a'))->getText(),
'sticky' => $row->find('xpath', (new CssSelectorConverter())->toXPath('.views-field-sticky span.field-content'))->getText(),
];
}
$this->assertEqual($actual, $expected);
}
}
@@ -0,0 +1,128 @@
<?php
namespace Drupal\Tests\views\Functional\Entity;
use Drupal\node\Entity\Node;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
use Drupal\views\Views;
/**
* Tests the generic entity bundle filter.
*
* @group views
*/
class FilterEntityBundleTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_entity_type_filter'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node'];
/**
* Entity bundle data.
*
* @var array
*/
protected $entityBundles;
/**
* An array of entities.
*
* @var array
*/
protected $entities = [];
protected function setUp($import_test_views = TRUE) {
parent::setUp(FALSE);
$this->drupalCreateContentType(['type' => 'test_bundle']);
$this->drupalCreateContentType(['type' => 'test_bundle_2']);
ViewTestData::createTestViews(get_class($this), ['views_test_config']);
$this->entityBundles = $this->container->get('entity_type.bundle.info')->getBundleInfo('node');
$this->entities['count'] = 0;
foreach ($this->entityBundles as $key => $info) {
for ($i = 0; $i < 5; $i++) {
$entity = Node::create([
'title' => $this->randomString(),
'uid' => 1,
'type' => $key,
]);
$entity->save();
$this->entities[$key][$entity->id()] = $entity;
$this->entities['count']++;
}
}
}
/**
* Tests the generic bundle filter.
*/
public function testFilterEntity() {
$view = Views::getView('test_entity_type_filter');
// Tests \Drupal\views\Plugin\views\filter\Bundle::calculateDependencies().
$expected = [
'config' => [
'node.type.test_bundle',
'node.type.test_bundle_2',
],
'module' => [
'node'
],
];
$this->assertIdentical($expected, $view->getDependencies());
$this->executeView($view);
// Test we have all the results, with all types selected.
$this->assertEqual(count($view->result), $this->entities['count']);
// Test the valueOptions of the filter handler.
$expected = [];
foreach ($this->entityBundles as $key => $info) {
$expected[$key] = $info['label'];
}
$this->assertIdentical($view->filter['type']->getValueOptions(), $expected);
$view->destroy();
// Test each bundle type.
foreach ($this->entityBundles as $key => $info) {
// Test each bundle type.
$view->initDisplay();
$filters = $view->display_handler->getOption('filters');
$filters['type']['value'] = [$key => $key];
$view->display_handler->setOption('filters', $filters);
$this->executeView($view);
$this->assertEqual(count($view->result), count($this->entities[$key]));
$view->destroy();
}
// Test an invalid bundle type to make sure we have no results.
$view->initDisplay();
$filters = $view->display_handler->getOption('filters');
$filters['type']['value'] = ['type_3' => 'type_3'];
$view->display_handler->setOption('filters', $filters);
$this->executeView($view);
$this->assertEqual(count($view->result), 0);
}
}
@@ -0,0 +1,46 @@
<?php
namespace Drupal\Tests\views\Functional\Entity;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\language_test\Entity\NoLanguageEntityTest;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the view creation of non-translatable entities.
*
* @group views
*/
class ViewNonTranslatableEntityTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'entity_test',
'content_translation',
'language_test',
'views_ui',
];
/**
* Tests displaying a view of non-translatable entities.
*/
public function testViewNoTranslatableEntity() {
// Add a new language.
ConfigurableLanguage::createFromLangcode('sr')->save();
// Create a non-translatable entity.
$no_language_entity = NoLanguageEntityTest::create();
$no_language_entity->save();
// Visit the view page and assert it is displayed properly.
$this->drupalGet('no-entity-translation-view');
$this->assertResponse(200);
$this->assertText('No Entity Translation View');
$this->assertText($no_language_entity->uuid());
}
}
@@ -0,0 +1,124 @@
<?php
namespace Drupal\Tests\views\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
use Drupal\views\Tests\AssertViewsCacheTagsTrait;
use Drupal\views\Views;
/**
* Tests glossary functionality of views.
*
* @group views
*/
class GlossaryTest extends ViewTestBase {
use AssertViewsCacheTagsTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node'];
/**
* Tests the default glossary view.
*/
public function testGlossaryView() {
// Create a content type and add some nodes, with a non-random title.
$type = $this->drupalCreateContentType();
$nodes_per_char = [
'd' => 1,
'r' => 4,
'u' => 10,
'p' => 2,
'a' => 3,
'l' => 6,
];
$nodes_by_char = [];
foreach ($nodes_per_char as $char => $count) {
$setting = [
'type' => $type->id()
];
for ($i = 0; $i < $count; $i++) {
$node = $setting;
$node['title'] = $char . $this->randomString(3);
$node = $this->drupalCreateNode($node);
$nodes_by_char[$char][] = $node;
}
}
// Execute glossary view
$view = Views::getView('glossary');
$view->setDisplay('attachment_1');
$view->executeDisplay('attachment_1');
// Check that the amount of nodes per char.
foreach ($view->result as $item) {
$this->assertEqual($nodes_per_char[$item->title_truncated], $item->num_records);
}
// Enable the glossary to be displayed.
$view->storage->enable()->save();
$this->container->get('router.builder')->rebuildIfNeeded();
$url = Url::fromRoute('view.glossary.page_1');
// Verify cache tags.
$this->assertPageCacheContextsAndTags(
$url,
[
'timezone',
'languages:' . LanguageInterface::TYPE_CONTENT,
'languages:' . LanguageInterface::TYPE_INTERFACE,
'theme',
'url',
'user.node_grants:view',
'user.permissions',
'route',
],
[
'config:views.view.glossary',
// Listed for letter 'a'
'node:' . $nodes_by_char['a'][0]->id(), 'node:' . $nodes_by_char['a'][1]->id(), 'node:' . $nodes_by_char['a'][2]->id(),
// Link for letter 'd'.
'node:1',
// Link for letter 'p'.
'node:16',
// Link for letter 'r'.
'node:2',
// Link for letter 'l'.
'node:21',
// Link for letter 'u'.
'node:6',
'node_list',
'user:0',
'user_list',
'http_response',
'rendered',
// FinishResponseSubscriber adds this cache tag to responses that have
// the 'user.permissions' cache context for anonymous users.
'config:user.role.anonymous',
]
);
// Check the actual page response.
$this->drupalGet($url);
$this->assertResponse(200);
foreach ($nodes_per_char as $char => $count) {
$href = Url::fromRoute('view.glossary.page_1', ['arg_0' => $char])->toString();
$label = Unicode::strtoupper($char);
// Get the summary link for a certain character. Filter by label and href
// to ensure that both of them are correct.
$result = $this->xpath('//a[contains(@href, :href) and normalize-space(text())=:label]/..', [':href' => $href, ':label' => $label]);
$this->assertTrue(count($result));
// The rendered output looks like "<a href=''>X</a> | (count)" so let's
// figure out the int.
$result_count = explode(' ', trim(str_replace(['|', '(', ')'], '', $result[0]->getText())))[1];
$this->assertEqual($result_count, $count, 'The expected number got rendered.');
}
}
}
@@ -0,0 +1,48 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
/**
* Tests the http_status_code area handler.
*
* @group views
* @see \Drupal\views\Plugin\views\area\HTTPStatusCode
*/
class AreaHTTPStatusCodeTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_http_status_code'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node'];
/**
* Tests the area handler.
*/
public function testHTTPStatusCodeHandler() {
$this->drupalGet('test-http-status-code');
$this->assertResponse(200);
// Change the HTTP status code to 418.
$view = Views::getView('test_http_status_code');
$display = &$view->storage->getDisplay('default');
$display['display_options']['empty']['http_status_code']['status_code'] = 418;
$view->save();
// Test that the HTTP response is "I'm a teapot".
$this->drupalGet('test-http-status-code');
$this->assertResponse(418);
}
}
@@ -0,0 +1,217 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\Component\Utility\Xss;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
/**
* Tests the plugin base of the area handler.
*
* @group views
* @see \Drupal\views\Plugin\views\area\AreaPluginBase
* @see \Drupal\views_test\Plugin\views\area\TestExample
*/
class AreaTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_example_area', 'test_example_area_access'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'views_ui'];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
}
protected function viewsData() {
$data = parent::viewsData();
$data['views']['test_example'] = [
'title' => 'Test Example area',
'help' => 'A area handler which just exists for tests.',
'area' => [
'id' => 'test_example'
]
];
return $data;
}
/**
* Tests the generic UI of a area handler.
*/
public function testUI() {
$admin_user = $this->drupalCreateUser(['administer views', 'administer site configuration']);
$this->drupalLogin($admin_user);
$types = ['header', 'footer', 'empty'];
$labels = [];
foreach ($types as $type) {
$edit_path = 'admin/structure/views/nojs/handler/test_example_area/default/' . $type . '/test_example';
// First setup an empty label.
$this->drupalPostForm($edit_path, [], t('Apply'));
$this->assertText('Test Example area');
// Then setup a no empty label.
$labels[$type] = $this->randomMachineName();
$this->drupalPostForm($edit_path, ['options[admin_label]' => $labels[$type]], t('Apply'));
// Make sure that the new label appears on the site.
$this->assertText($labels[$type]);
// Test that the settings (empty/admin_label) are accessible.
$this->drupalGet($edit_path);
$this->assertField('options[admin_label]');
if ($type !== 'empty') {
$this->assertField('options[empty]');
}
}
}
/**
* Tests the rendering of an area.
*/
public function testRenderArea() {
$view = Views::getView('test_example_area');
$view->initHandlers();
// Insert a random string with XSS injection in the test area plugin.
// Ensure that the string is rendered for the header, footer, and empty
// text with the markup properly escaped.
$header_string = '<script type="text/javascript">alert("boo");</script><p>' . $this->randomMachineName() . '</p>';
$footer_string = '<script type="text/javascript">alert("boo");</script><p>' . $this->randomMachineName() . '</p>';
$empty_string = '<script type="text/javascript">alert("boo");</script><p>' . $this->randomMachineName() . '</p>';
$view->header['test_example']->options['string'] = $header_string;
$view->header['test_example']->options['empty'] = TRUE;
$view->footer['test_example']->options['string'] = $footer_string;
$view->footer['test_example']->options['empty'] = TRUE;
$view->empty['test_example']->options['string'] = $empty_string;
// Check whether the strings exist in the output and are sanitized.
$output = $view->preview();
$output = $this->container->get('renderer')->renderRoot($output);
$this->assertTrue(strpos($output, Xss::filterAdmin($header_string)) !== FALSE, 'Views header exists in the output and is sanitized');
$this->assertTrue(strpos($output, Xss::filterAdmin($footer_string)) !== FALSE, 'Views footer exists in the output and is sanitized');
$this->assertTrue(strpos($output, Xss::filterAdmin($empty_string)) !== FALSE, 'Views empty exists in the output and is sanitized');
$this->assertTrue(strpos($output, '<script') === FALSE, 'Script tags were escaped');
}
/**
* Tests the access for an area.
*/
public function testAreaAccess() {
// Test with access denied for the area handler.
$view = Views::getView('test_example_area_access');
$view->initDisplay();
$view->initHandlers();
$handlers = $view->display_handler->getHandlers('empty');
$this->assertEqual(0, count($handlers));
$output = $view->preview();
$output = \Drupal::service('renderer')->renderRoot($output);
// The area output should not be present since access was denied.
$this->assertFalse(strpos($output, 'a custom string') !== FALSE);
$view->destroy();
// Test with access granted for the area handler.
$view = Views::getView('test_example_area_access');
$view->initDisplay();
$view->display_handler->overrideOption('empty', [
'test_example' => [
'field' => 'test_example',
'id' => 'test_example',
'table' => 'views',
'plugin_id' => 'test_example',
'string' => 'a custom string',
'custom_access' => TRUE,
],
]);
$view->initHandlers();
$handlers = $view->display_handler->getHandlers('empty');
$output = $view->preview();
$output = \Drupal::service('renderer')->renderRoot($output);
$this->assertTrue(strpos($output, 'a custom string') !== FALSE);
$this->assertEqual(1, count($handlers));
}
/**
* Tests global tokens.
*/
public function testRenderAreaToken() {
$admin_user = $this->drupalCreateUser(['administer views', 'administer site configuration']);
$this->drupalLogin($admin_user);
$view = Views::getView('test_example_area');
$view->initHandlers();
$this->drupalGet('admin/structure/views/nojs/handler/test_example_area/default/empty/test_example');
// Test that the list is token present.
$element = $this->xpath('//ul[@class="global-tokens"]');
$this->assertTrue($element, 'Token list found on the options form.');
$empty_handler = &$view->empty['test_example'];
// Test the list of available tokens.
$available = $empty_handler->getAvailableGlobalTokens();
foreach (['site', 'view'] as $type) {
$this->assertTrue(!empty($available[$type]) && is_array($available[$type]));
// Test that each item exists in the list.
foreach ($available[$type] as $token => $info) {
$this->assertText("[$type:$token]");
}
}
// Test the rendered output of a token.
$empty_handler->options['string'] = '[site:name]';
// Test we have the site:name token in the output.
$output = $view->preview();
$output = $this->container->get('renderer')->renderRoot($output);
$expected = \Drupal::token()->replace('[site:name]');
$this->assertTrue(strpos($output, $expected) !== FALSE);
}
/**
* Tests overriding the view title using the area title handler.
*/
public function testTitleArea() {
$view = Views::getView('frontpage');
$view->initDisplay('page_1');
// Add the title area handler to the empty area.
$view->displayHandlers->get('page_1')->overrideOption('empty', [
'title' => [
'id' => 'title',
'table' => 'views',
'field' => 'title',
'admin_label' => '',
'empty' => '0',
'title' => 'Overridden title',
'plugin_id' => 'title',
],
]);
$view->storage->enable()->save();
$this->drupalGet('node');
$this->assertText('Overridden title', 'Overridden title found.');
}
}
@@ -0,0 +1,80 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Entity\View;
/**
* Tests the title area handler with a web test.
*
* @group views
* @see \Drupal\views\Plugin\views\area\Title
*/
class AreaTitleWebTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_area_title'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
}
/**
* Tests the title area handler.
*/
public function testTitleText() {
// Confirm that the view has the normal title before making the view return
// no result.
$this->drupalGet('test-area-title');
$this->assertTitle('test_title_header | Drupal');
// Change the view to return no result.
/** @var \Drupal\views\Entity\View $view */
$view = View::load('test_area_title');
$display =& $view->getDisplay('default');
$display['display_options']['filters']['name'] = [
'field' => 'name',
'id' => 'name',
'table' => 'views_test_data',
'relationship' => 'none',
'plugin_id' => 'string',
// Add a value which does not exist. The dataset is defined in
// \Drupal\views\Tests\ViewTestData::dataSet().
'value' => 'Euler',
];
$view->save();
$this->drupalGet('test-area-title');
$this->assertTitle('test_title_empty | Drupal');
// Change the view to return a result instead.
/** @var \Drupal\views\Entity\View $view */
$view = View::load('test_area_title');
$display =& $view->getDisplay('default');
$display['display_options']['filters']['name'] = [
'field' => 'name',
'id' => 'name',
'table' => 'views_test_data',
'relationship' => 'none',
'plugin_id' => 'string',
// Change to a value which does exist. The dataset is defined in
// \Drupal\views\Tests\ViewTestData::dataSet().
'value' => 'Ringo',
];
$view->save();
$this->drupalGet('test-area-title');
$this->assertTitle('test_title_header | Drupal');
}
}
@@ -0,0 +1,61 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\argument\StringArgument handler.
*
* @group views
*/
class ArgumentStringTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_glossary'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node'];
/**
* Tests the glossary feature.
*/
public function testGlossary() {
// Setup some nodes, one with a, two with b and three with c.
$counter = 1;
foreach (['a', 'b', 'c'] as $char) {
for ($i = 0; $i < $counter; $i++) {
$edit = [
'title' => $char . $this->randomMachineName(),
];
$this->drupalCreateNode($edit);
}
}
$view = Views::getView('test_glossary');
$this->executeView($view);
$count_field = 'nid';
foreach ($view->result as &$row) {
if (strpos($view->field['title']->getValue($row), 'a') === 0) {
$this->assertEqual(1, $row->{$count_field});
}
if (strpos($view->field['title']->getValue($row), 'b') === 0) {
$this->assertEqual(2, $row->{$count_field});
}
if (strpos($view->field['title']->getValue($row), 'c') === 0) {
$this->assertEqual(3, $row->{$count_field});
}
}
}
}
@@ -0,0 +1,66 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\Tests\views\Functional\ViewTestBase;
/**
* Tests the dropbutton field handler.
*
* @group views
* @see \Drupal\system\Plugin\views\field\Dropbutton
*/
class FieldDropButtonTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_dropbutton'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$admin_user = $this->drupalCreateUser(['access content overview', 'administer nodes', 'bypass node access']);
$this->drupalLogin($admin_user);
}
/**
* Tests dropbutton field.
*/
public function testDropbutton() {
// Create some test nodes.
$nodes = [];
for ($i = 0; $i < 5; $i++) {
$nodes[] = $this->drupalCreateNode();
}
$this->drupalGet('test-dropbutton');
foreach ($nodes as $node) {
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[contains(@href, :path) and text()=:title]', [':path' => '/node/' . $node->id(), ':title' => $node->label()]);
$this->assertEqual(count($result), 1, 'Just one node title link was found.');
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[contains(@href, :path) and text()=:title]', [':path' => '/node/' . $node->id(), ':title' => 'Custom Text']);
$this->assertEqual(count($result), 1, 'Just one custom link was found.');
}
// Check if the dropbutton.js library is available.
$this->drupalGet('admin/content');
$this->assertRaw('dropbutton.js');
// Check if the dropbutton.js library is available on a cached page to
// ensure that bubbleable metadata is not lost in the views render workflow.
$this->drupalGet('admin/content');
$this->assertRaw('dropbutton.js');
}
}
@@ -0,0 +1,94 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\Core\Url;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\Node;
use Drupal\Tests\views\Functional\ViewTestBase;
/**
* Tests the core Drupal\views\Plugin\views\field\EntityOperations handler.
*
* @group views
*/
class FieldEntityOperationsTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_entity_operations'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'language', 'views_ui'];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
// Create Article content type.
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
}
/**
* Tests entity operations field.
*/
public function testEntityOperations() {
// Add languages and refresh the container so the entity manager will have
// fresh data.
ConfigurableLanguage::createFromLangcode('hu')->save();
ConfigurableLanguage::createFromLangcode('es')->save();
$this->rebuildContainer();
// Create some test entities. Every other entity is Hungarian while all
// have a Spanish translation.
$entities = [];
for ($i = 0; $i < 5; $i++) {
$entity = Node::create([
'title' => $this->randomString(),
'type' => 'article',
'langcode' => $i % 2 === 0 ? 'hu' : 'en',
]);
$entity->save();
$translation = $entity->addTranslation('es');
$translation->set('title', $entity->getTitle() . ' in Spanish');
$translation->save();
$entities[$i] = $entity;
}
$admin_user = $this->drupalCreateUser(['access administration pages', 'administer nodes', 'bypass node access']);
$this->drupalLogin($this->rootUser);
$this->drupalGet('test-entity-operations');
/** @var $entity \Drupal\entity_test\Entity\EntityTest */
foreach ($entities as $entity) {
/** @var \Drupal\Core\Language\LanguageInterface $language */
foreach ($entity->getTranslationLanguages() as $language) {
$entity = $entity->getTranslation($language->getId());
$operations = \Drupal::entityManager()->getListBuilder('node')->getOperations($entity);
$this->assertTrue(count($operations) > 0, 'There are operations.');
foreach ($operations as $operation) {
$expected_destination = Url::fromUri('internal:/test-entity-operations')->toString();
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[@href=:path and text()=:title]', [':path' => $operation['url']->toString() . '?destination=' . $expected_destination, ':title' => (string) $operation['title']]);
$this->assertEqual(count($result), 1, t('Found entity @operation link with destination parameter.', ['@operation' => $operation['title']]));
// Entities which were created in Hungarian should link to the Hungarian
// edit form, others to the English one (which has no path prefix here).
$base_path = \Drupal::request()->getBasePath();
$parts = explode('/', str_replace($base_path, '', $operation['url']->toString()));
$expected_prefix = ($language->getId() != 'en' ? $language->getId() : 'node');
$this->assertEqual($parts[1], $expected_prefix, 'Entity operation links to the correct language for the entity.');
}
}
}
// Test that we can't enable click sorting on the operation field.
$this->drupalGet('admin/structure/views/nojs/display/test_entity_operations/page_2/style_options');
$this->assertField('style_options[info][title][sortable]');
$this->assertNoField('style_options[info][operations][sortable]');
}
}
@@ -0,0 +1,112 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Render\RenderContext;
use Drupal\field\Entity\FieldConfig;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests the "Display all values in the same row" setting.
*
* @see \Drupal\views\Plugin\views\field\EntityField
*
* @group views
*/
class FieldGroupRowsTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_group_rows', 'test_ungroup_rows'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'field_test'];
/**
* Field that will be created to test the group/ungroup rows functionality
*
* @var string
*/
private $fieldName = 'field_group_rows';
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
// Create content type with unlimited text field.
$node_type = $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create the unlimited text field.
$field_storage = FieldStorageConfig::create([
'field_name' => $this->fieldName,
'entity_type' => 'node',
'type' => 'text',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
]);
$field_storage->save();
// Create an instance of the text field on the content type.
$field = [
'field_storage' => $field_storage,
'bundle' => $node_type->id(),
];
FieldConfig::create($field)->save();
}
/**
* Testing the "Grouped rows" functionality.
*/
public function testGroupRows() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$edit = [
'title' => $this->randomMachineName(),
$this->fieldName => ['a', 'b', 'c'],
];
$this->drupalCreateNode($edit);
$view = Views::getView('test_group_rows');
// Test grouped rows.
$this->executeView($view);
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field[$this->fieldName]->advancedRender($view->result[0]);
});
$this->assertEqual($output, 'a, b, c');
// Change the group_rows checkbox to false.
$view = Views::getView('test_group_rows');
$view->setHandlerOption('default', 'field', $this->fieldName, 'group_rows', FALSE);
// Test ungrouped rows.
$this->executeView($view);
$view->render();
$view->row_index = 0;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field[$this->fieldName]->advancedRender($view->result[0]);
});
$this->assertEqual($output, 'a');
$view->row_index = 1;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field[$this->fieldName]->advancedRender($view->result[1]);
});
$this->assertEqual($output, 'b');
$view->row_index = 2;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field[$this->fieldName]->advancedRender($view->result[2]);
});
$this->assertEqual($output, 'c');
}
}
@@ -0,0 +1,119 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Tests\views\Functional\ViewTestBase;
/**
* Tests the "Display all values in the same row" setting.
*
* @group views
*/
class FieldGroupRowsWebTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_group_rows', 'test_ungroup_rows'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node'];
/**
* The page node type.
*
* @var \Drupal\node\NodeTypeInterface
*/
protected $nodeType;
/**
* The used field name in the test.
*
* @var string
*/
protected $fieldName;
/**
* The field storage.
*
* @var \Drupal\field\Entity\FieldStorageConfig
*/
protected $fieldStorage;
/**
* The field config.
*
* @var \Drupal\field\Entity\FieldConfig
*/
protected $field;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
// Create content type with unlimited text field.
$this->nodeType = $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
// Create the unlimited text field.
$this->fieldName = 'field_views_testing_group_rows';
$this->fieldStorage = FieldStorageConfig::create([
'field_name' => $this->fieldName,
'entity_type' => 'node',
'type' => 'text',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
]);
$this->fieldStorage->save();
// Create an instance of the text field on the content type.
$this->field = FieldConfig::create([
'field_storage' => $this->fieldStorage,
'bundle' => $this->nodeType->id(),
]);
$this->field->save();
$edit = [
'title' => $this->randomMachineName(),
$this->fieldName => ['a', 'b', 'c'],
];
$this->drupalCreateNode($edit);
}
/**
* Testing when "Display all values in the same row" is checked.
*/
public function testGroupRows() {
$this->drupalGet('test-group-rows');
$result = $this->cssSelect('div.views-field-field-views-testing-group- div');
$rendered_value = [];
foreach ($result as $row) {
$rendered_value[] = $row->getText();
}
$this->assertEqual(['a, b, c'], $rendered_value);
}
/**
* Testing when "Display all values in the same row" is unchecked.
*/
public function testUngroupedRows() {
$this->drupalGet('test-ungroup-rows');
$result = $this->cssSelect('div.views-field-field-views-testing-group- div');
$rendered_value = [];
foreach ($result as $row) {
$rendered_value[] = $row->getText();
}
$this->assertEqual(['a', 'b', 'c'], $rendered_value);
}
}
@@ -0,0 +1,656 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Url;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
/**
* Tests fields from within a UI.
*
* @group views
* @see \Drupal\views\Plugin\views\field\FieldPluginBase
*/
class FieldWebTest extends ViewTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_view', 'test_field_classes', 'test_field_output', 'test_click_sort'];
/**
* {@inheritdoc}
*/
public static $modules = ['node'];
/**
* Maps between the key in the expected result and the query result.
*
* @var array
*/
protected $columnMap = [
'views_test_data_name' => 'name',
];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
}
/**
* {@inheritdoc}
*/
protected function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['job']['field']['id'] = 'test_field';
return $data;
}
/**
* Tests the click sorting functionality.
*/
public function testClickSorting() {
$this->drupalGet('test_click_sort');
$this->assertResponse(200);
// Only the id and name should be click sortable, but not the name.
$this->assertLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'id', 'sort' => 'asc']]));
$this->assertLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'name', 'sort' => 'desc']]));
$this->assertNoLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'created']]));
// Check that the view returns the click sorting cache contexts.
$expected_contexts = [
'languages:language_interface',
'theme',
'url.query_args',
];
$this->assertCacheContexts($expected_contexts);
// Clicking a click sort should change the order.
$this->clickLink(t('ID'));
$this->assertLinkByHref(\Drupal::url('<none>', [], ['query' => ['order' => 'id', 'sort' => 'desc']]));
// Check that the output has the expected order (asc).
$ids = $this->clickSortLoadIdsFromOutput();
$this->assertEqual($ids, range(1, 5));
$this->clickLink(t('ID Sort descending'));
// Check that the output has the expected order (desc).
$ids = $this->clickSortLoadIdsFromOutput();
$this->assertEqual($ids, range(5, 1, -1));
}
/**
* Small helper function to get all ids in the output.
*
* @return array
* A list of beatle ids.
*/
protected function clickSortLoadIdsFromOutput() {
$fields = $this->xpath("//td[contains(@class, 'views-field-id')]");
$ids = [];
foreach ($fields as $field) {
$ids[] = (int) $field->getText();
}
return $ids;
}
/**
* Assertion helper which checks whether a string is part of another string.
*
* @param string $haystack
* The value to search in.
* @param string $needle
* The value to search for.
* @param string $message
* The message to display along with the assertion.
* @param string $group
* The type of assertion - examples are "Browser", "PHP".
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertSubString($haystack, $needle, $message = '', $group = 'Other') {
return $this->assertTrue(strpos($haystack, $needle) !== FALSE, $message, $group);
}
/**
* Assertion helper which checks whether a string is not part of another string.
*
* @param string $haystack
* The value to search in.
* @param string $needle
* The value to search for.
* @param string $message
* The message to display along with the assertion.
* @param string $group
* The type of assertion - examples are "Browser", "PHP".
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertNotSubString($haystack, $needle, $message = '', $group = 'Other') {
return $this->assertTrue(strpos($haystack, $needle) === FALSE, $message, $group);
}
/**
* Parse a content and return the html element.
*
* @param string $content
* The html to parse.
*
* @return array
* An array containing simplexml objects.
*/
protected function parseContent($content) {
$htmlDom = new \DOMDocument();
@$htmlDom->loadHTML('<?xml encoding="UTF-8">' . $content);
$elements = simplexml_import_dom($htmlDom);
return $elements;
}
/**
* Performs an xpath search on a certain content.
*
* The search is relative to the root element of the $content variable.
*
* @param string $content
* The html to parse.
* @param string $xpath
* The xpath string to use in the search.
* @param array $arguments
* Some arguments for the xpath.
*
* @return array|false
* The return value of the xpath search. For details on the xpath string
* format and return values see the SimpleXML documentation,
* http://php.net/manual/function.simplexml-element-xpath.php.
*/
protected function xpathContent($content, $xpath, array $arguments = []) {
if ($elements = $this->parseContent($content)) {
$xpath = $this->buildXPathQuery($xpath, $arguments);
$result = $elements->xpath($xpath);
// Some combinations of PHP / libxml versions return an empty array
// instead of the documented FALSE. Forcefully convert any falsish values
// to an empty array to allow foreach(...) constructions.
return $result ? $result : [];
}
else {
return FALSE;
}
}
/**
* Tests rewriting the output to a link.
*/
public function testAlterUrl() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_view');
$view->setDisplay();
$view->initHandlers();
$this->executeView($view);
$row = $view->result[0];
$id_field = $view->field['id'];
// Setup the general settings required to build a link.
$id_field->options['alter']['make_link'] = TRUE;
$id_field->options['alter']['path'] = $path = $this->randomMachineName();
// Tests that the suffix/prefix appears on the output.
$id_field->options['alter']['prefix'] = $prefix = $this->randomMachineName();
$id_field->options['alter']['suffix'] = $suffix = $this->randomMachineName();
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($output, $prefix);
$this->assertSubString($output, $suffix);
unset($id_field->options['alter']['prefix']);
unset($id_field->options['alter']['suffix']);
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($output, $path, 'Make sure that the path is part of the output');
// Some generic test code adapted from the UrlTest class, which tests
// mostly the different options for the path.
foreach ([FALSE, TRUE] as $absolute) {
$alter = &$id_field->options['alter'];
$alter['path'] = 'node/123';
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['absolute' => $absolute]);
$alter['absolute'] = $absolute;
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($result, $expected_result);
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['fragment' => 'foo', 'absolute' => $absolute]);
$alter['path'] = 'node/123#foo';
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($result, $expected_result);
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => NULL], 'absolute' => $absolute]);
$alter['path'] = 'node/123?foo';
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($result, $expected_result);
$expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => 'bar', 'bar' => 'baz'], 'absolute' => $absolute]);
$alter['path'] = 'node/123?foo=bar&bar=baz';
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString(Html::decodeEntities($result), Html::decodeEntities($expected_result));
// @todo The route-based URL generator strips out NULL attributes.
// $expected_result = \Drupal::url('entity.node.canonical', ['node' => '123'], ['query' => ['foo' => NULL], 'fragment' => 'bar', 'absolute' => $absolute]);
$expected_result = Url::fromUserInput('/node/123', ['query' => ['foo' => NULL], 'fragment' => 'bar', 'absolute' => $absolute])->toString();
$alter['path'] = 'node/123?foo#bar';
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString(Html::decodeEntities($result), Html::decodeEntities($expected_result));
$expected_result = \Drupal::url('<front>', [], ['absolute' => $absolute]);
$alter['path'] = '<front>';
$result = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($result, $expected_result);
}
// Tests the replace spaces with dashes feature.
$id_field->options['alter']['replace_spaces'] = TRUE;
$id_field->options['alter']['path'] = $path = $this->randomMachineName() . ' ' . $this->randomMachineName();
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($output, str_replace(' ', '-', $path));
$id_field->options['alter']['replace_spaces'] = FALSE;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
// The url has a space in it, so to check we have to decode the url output.
$this->assertSubString(urldecode($output), $path);
// Tests the external flag.
// Switch on the external flag should output an external url as well.
$id_field->options['alter']['external'] = TRUE;
$id_field->options['alter']['path'] = $path = 'www.drupal.org';
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($output, 'http://www.drupal.org');
// Setup a not external url, which shouldn't lead to an external url.
$id_field->options['alter']['external'] = FALSE;
$id_field->options['alter']['path'] = $path = 'www.drupal.org';
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertNotSubString($output, 'http://www.drupal.org');
// Tests the transforming of the case setting.
$id_field->options['alter']['path'] = $path = $this->randomMachineName();
$id_field->options['alter']['path_case'] = 'none';
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($output, $path);
// Switch to uppercase and lowercase.
$id_field->options['alter']['path_case'] = 'upper';
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($output, strtoupper($path));
$id_field->options['alter']['path_case'] = 'lower';
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($output, strtolower($path));
// Switch to ucfirst and ucwords.
$id_field->options['alter']['path_case'] = 'ucfirst';
$id_field->options['alter']['path'] = 'drupal has a great community';
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($output, UrlHelper::encodePath('Drupal has a great community'));
$id_field->options['alter']['path_case'] = 'ucwords';
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($output, UrlHelper::encodePath('Drupal Has A Great Community'));
unset($id_field->options['alter']['path_case']);
// Tests the linkclass setting and see whether it actually exists in the
// output.
$id_field->options['alter']['link_class'] = $class = $this->randomMachineName();
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$elements = $this->xpathContent($output, '//a[contains(@class, :class)]', [':class' => $class]);
$this->assertTrue($elements);
// @fixme link_class, alt, rel cannot be unset, which should be fixed.
$id_field->options['alter']['link_class'] = '';
// Tests the alt setting.
$id_field->options['alter']['alt'] = $rel = $this->randomMachineName();
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$elements = $this->xpathContent($output, '//a[contains(@title, :alt)]', [':alt' => $rel]);
$this->assertTrue($elements);
$id_field->options['alter']['alt'] = '';
// Tests the rel setting.
$id_field->options['alter']['rel'] = $rel = $this->randomMachineName();
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$elements = $this->xpathContent($output, '//a[contains(@rel, :rel)]', [':rel' => $rel]);
$this->assertTrue($elements);
$id_field->options['alter']['rel'] = '';
// Tests the target setting.
$id_field->options['alter']['target'] = $target = $this->randomMachineName();
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$elements = $this->xpathContent($output, '//a[contains(@target, :target)]', [':target' => $target]);
$this->assertTrue($elements);
unset($id_field->options['alter']['target']);
}
/**
* Tests the field/label/wrapper classes.
*/
public function testFieldClasses() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$view = Views::getView('test_field_classes');
$view->initHandlers();
// Tests whether the default field classes are added.
$id_field = $view->field['id'];
$id_field->options['element_default_classes'] = FALSE;
// Setup some kind of label by default.
$id_field->options['label'] = $this->randomMachineName();
$output = $view->preview();
$output = $renderer->renderRoot($output);
$this->assertFalse($this->xpathContent($output, '//div[contains(@class, :class)]', [':class' => 'field-content']));
$this->assertFalse($this->xpathContent($output, '//div[contains(@class, :class)]', [':class' => 'field__label']));
$id_field->options['element_default_classes'] = TRUE;
$output = $view->preview();
$output = $renderer->renderRoot($output);
// Per default the label and the element of the field are spans.
$this->assertTrue($this->xpathContent($output, '//span[contains(@class, :class)]', [':class' => 'field-content']));
$this->assertTrue($this->xpathContent($output, '//span[contains(@class, :class)]', [':class' => 'views-label']));
$this->assertTrue($this->xpathContent($output, '//div[contains(@class, :class)]', [':class' => 'views-field']));
// Tests the element wrapper classes/element.
$random_class = $this->randomMachineName();
// Set some common wrapper element types and see whether they appear with and without a custom class set.
foreach (['h1', 'span', 'p', 'div'] as $element_type) {
$id_field->options['element_wrapper_type'] = $element_type;
// Set a custom wrapper element css class.
$id_field->options['element_wrapper_class'] = $random_class;
$output = $view->preview();
$output = $renderer->renderRoot($output);
$this->assertTrue($this->xpathContent($output, "//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
// Set no custom css class.
$id_field->options['element_wrapper_class'] = '';
$output = $view->preview();
$output = $renderer->renderRoot($output);
$this->assertFalse($this->xpathContent($output, "//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
$this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]/{$element_type}"));
}
// Tests the label class/element.
// Set some common label element types and see whether they appear with and without a custom class set.
foreach (['h1', 'span', 'p', 'div'] as $element_type) {
$id_field->options['element_label_type'] = $element_type;
// Set a custom label element css class.
$id_field->options['element_label_class'] = $random_class;
$output = $view->preview();
$output = $renderer->renderRoot($output);
$this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
// Set no custom css class.
$id_field->options['element_label_class'] = '';
$output = $view->preview();
$output = $renderer->renderRoot($output);
$this->assertFalse($this->xpathContent($output, "//li[contains(@class, views-row)]//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
$this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//{$element_type}"));
}
// Tests the element classes/element.
// Set some common element element types and see whether they appear with and without a custom class set.
foreach (['h1', 'span', 'p', 'div'] as $element_type) {
$id_field->options['element_type'] = $element_type;
// Set a custom label element css class.
$id_field->options['element_class'] = $random_class;
$output = $view->preview();
$output = $renderer->renderRoot($output);
$this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//div[contains(@class, views-field)]//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
// Set no custom css class.
$id_field->options['element_class'] = '';
$output = $view->preview();
$output = $renderer->renderRoot($output);
$this->assertFalse($this->xpathContent($output, "//li[contains(@class, views-row)]//div[contains(@class, views-field)]//{$element_type}[contains(@class, :class)]", [':class' => $random_class]));
$this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//div[contains(@class, views-field)]//{$element_type}"));
}
// Tests the available html elements.
$element_types = $id_field->getElements();
$expected_elements = [
'',
0,
'div',
'span',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'p',
'strong',
'em',
'marquee'
];
$this->assertEqual(array_keys($element_types), $expected_elements);
}
/**
* Tests trimming/read-more/ellipses.
*/
public function testTextRendering() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_field_output');
$view->initHandlers();
$name_field = $view->field['name'];
// Tests stripping of html elements.
$this->executeView($view);
$random_text = $this->randomMachineName();
$name_field->options['alter']['alter_text'] = TRUE;
$name_field->options['alter']['text'] = $html_text = '<div class="views-test">' . $random_text . '</div>';
$row = $view->result[0];
$name_field->options['alter']['strip_tags'] = TRUE;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is enabled.');
$this->assertNotSubString($output, $html_text, 'Find no text with the html if stripping of views field output is enabled.');
// Tests preserving of html tags.
$name_field->options['alter']['preserve_tags'] = '<div>';
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is enabled but a div is allowed.');
$this->assertSubString($output, $html_text, 'Find text with the html if stripping of views field output is enabled but a div is allowed.');
$name_field->options['alter']['strip_tags'] = FALSE;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is disabled.');
$this->assertSubString($output, $html_text, 'Find text with the html if stripping of views field output is disabled.');
// Tests for removing whitespace and the beginning and the end.
$name_field->options['alter']['alter_text'] = FALSE;
$views_test_data_name = $row->views_test_data_name;
$row->views_test_data_name = ' ' . $views_test_data_name . ' ';
$name_field->options['alter']['trim_whitespace'] = TRUE;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertSubString($output, $views_test_data_name, 'Make sure the trimmed text can be found if trimming is enabled.');
$this->assertNotSubString($output, $row->views_test_data_name, 'Make sure the untrimmed text can be found if trimming is enabled.');
$name_field->options['alter']['trim_whitespace'] = FALSE;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertSubString($output, $views_test_data_name, 'Make sure the trimmed text can be found if trimming is disabled.');
$this->assertSubString($output, $row->views_test_data_name, 'Make sure the untrimmed text can be found if trimming is disabled.');
// Tests for trimming to a maximum length.
$name_field->options['alter']['trim'] = TRUE;
$name_field->options['alter']['word_boundary'] = FALSE;
// Tests for simple trimming by string length.
$row->views_test_data_name = $this->randomMachineName(8);
$name_field->options['alter']['max_length'] = 5;
$trimmed_name = Unicode::substr($row->views_test_data_name, 0, 5);
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertSubString($output, $trimmed_name, format_string('Make sure the trimmed output (@trimmed) appears in the rendered output (@output).', ['@trimmed' => $trimmed_name, '@output' => $output]));
$this->assertNotSubString($output, $row->views_test_data_name, format_string("Make sure the untrimmed value (@untrimmed) shouldn't appear in the rendered output (@output).", ['@untrimmed' => $row->views_test_data_name, '@output' => $output]));
$name_field->options['alter']['max_length'] = 9;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertSubString($output, $trimmed_name, format_string('Make sure the untrimmed (@untrimmed) output appears in the rendered output (@output).', ['@trimmed' => $trimmed_name, '@output' => $output]));
// Take word_boundary into account for the tests.
$name_field->options['alter']['max_length'] = 5;
$name_field->options['alter']['word_boundary'] = TRUE;
$random_text_2 = $this->randomMachineName(2);
$random_text_4 = $this->randomMachineName(4);
$random_text_8 = $this->randomMachineName(8);
$tuples = [
// Create one string which doesn't fit at all into the limit.
[
'value' => $random_text_8,
'trimmed_value' => '',
'trimmed' => TRUE
],
// Create one string with two words which doesn't fit both into the limit.
[
'value' => $random_text_8 . ' ' . $random_text_8,
'trimmed_value' => '',
'trimmed' => TRUE
],
// Create one string which contains of two words, of which only the first
// fits into the limit.
[
'value' => $random_text_4 . ' ' . $random_text_8,
'trimmed_value' => $random_text_4,
'trimmed' => TRUE
],
// Create one string which contains of two words, of which both fits into
// the limit.
[
'value' => $random_text_2 . ' ' . $random_text_2,
'trimmed_value' => $random_text_2 . ' ' . $random_text_2,
'trimmed' => FALSE
]
];
foreach ($tuples as $tuple) {
$row->views_test_data_name = $tuple['value'];
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
if ($tuple['trimmed']) {
$this->assertNotSubString($output, $tuple['value'], format_string('The untrimmed value (@untrimmed) should not appear in the trimmed output (@output).', ['@untrimmed' => $tuple['value'], '@output' => $output]));
}
if (!empty($tuple['trimmed_value'])) {
$this->assertSubString($output, $tuple['trimmed_value'], format_string('The trimmed value (@trimmed) should appear in the trimmed output (@output).', ['@trimmed' => $tuple['trimmed_value'], '@output' => $output]));
}
}
// Tests for displaying a readmore link when the output got trimmed.
$row->views_test_data_name = $this->randomMachineName(8);
$name_field->options['alter']['max_length'] = 5;
$name_field->options['alter']['more_link'] = TRUE;
$name_field->options['alter']['more_link_text'] = $more_text = $this->randomMachineName();
$name_field->options['alter']['more_link_path'] = $more_path = $this->randomMachineName();
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertSubString($output, $more_text, 'Make sure a read more text is displayed if the output got trimmed');
$this->assertTrue($this->xpathContent($output, '//a[contains(@href, :path)]', [':path' => $more_path]), 'Make sure the read more link points to the right destination.');
$name_field->options['alter']['more_link'] = FALSE;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertNotSubString($output, $more_text, 'Make sure no read more text appears.');
$this->assertFalse($this->xpathContent($output, '//a[contains(@href, :path)]', [':path' => $more_path]), 'Make sure no read more link appears.');
// Check for the ellipses.
$row->views_test_data_name = $this->randomMachineName(8);
$name_field->options['alter']['max_length'] = 5;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertSubString($output, '…', 'An ellipsis should appear if the output is trimmed');
$name_field->options['alter']['max_length'] = 10;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field, $row) {
return $name_field->advancedRender($row);
});
$this->assertNotSubString($output, '…', 'No ellipsis should appear if the output is not trimmed');
}
}
@@ -0,0 +1,319 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\config\Tests\SchemaCheckTestTrait;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\filter\Date handler.
*
* @group views
*/
class FilterDateTest extends ViewTestBase {
use SchemaCheckTestTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_filter_date_between'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'views_ui', 'datetime'];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
// Add a date field so we can test datetime handling.
NodeType::create([
'type' => 'page',
'name' => 'Page',
])->save();
// Setup a field storage and field, but also change the views data for the
// entity_test entity type.
$field_storage = FieldStorageConfig::create([
'field_name' => 'field_date',
'type' => 'datetime',
'entity_type' => 'node',
]);
$field_storage->save();
$field = FieldConfig::create([
'field_name' => 'field_date',
'entity_type' => 'node',
'bundle' => 'page',
]);
$field->save();
// Add some basic test nodes.
$this->nodes = [];
$this->nodes[] = $this->drupalCreateNode(['created' => 100000, 'field_date' => 10000]);
$this->nodes[] = $this->drupalCreateNode(['created' => 200000, 'field_date' => 20000]);
$this->nodes[] = $this->drupalCreateNode(['created' => 300000, 'field_date' => 30000]);
$this->nodes[] = $this->drupalCreateNode(['created' => time() + 86400, 'field_date' => time() + 86400]);
$this->map = [
'nid' => 'nid',
];
}
/**
* Runs other test methods.
*/
public function testDateFilter() {
$this->_testOffset();
$this->_testBetween();
$this->_testUiValidation();
$this->_testFilterDateUI();
$this->_testFilterDatetimeUI();
}
/**
* Test the general offset functionality.
*/
protected function _testOffset() {
$view = Views::getView('test_filter_date_between');
// Test offset for simple operator.
$view->initHandlers();
$view->filter['created']->operator = '>';
$view->filter['created']->value['type'] = 'offset';
$view->filter['created']->value['value'] = '+1 hour';
$view->executeDisplay('default');
$expected_result = [
['nid' => $this->nodes[3]->id()],
];
$this->assertIdenticalResultset($view, $expected_result, $this->map);
$view->destroy();
// Test offset for between operator.
$view->initHandlers();
$view->filter['created']->operator = 'between';
$view->filter['created']->value['type'] = 'offset';
$view->filter['created']->value['max'] = '+2 days';
$view->filter['created']->value['min'] = '+1 hour';
$view->executeDisplay('default');
$expected_result = [
['nid' => $this->nodes[3]->id()],
];
$this->assertIdenticalResultset($view, $expected_result, $this->map);
}
/**
* Tests the filter operator between/not between.
*/
protected function _testBetween() {
$view = Views::getView('test_filter_date_between');
// Test between with min and max.
$view->initHandlers();
$view->filter['created']->operator = 'between';
$view->filter['created']->value['min'] = format_date(150000, 'custom', 'Y-m-d H:i:s');
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
$view->executeDisplay('default');
$expected_result = [
['nid' => $this->nodes[1]->id()],
];
$this->assertIdenticalResultset($view, $expected_result, $this->map);
$view->destroy();
// Test between with just max.
$view->initHandlers();
$view->filter['created']->operator = 'between';
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
$view->executeDisplay('default');
$expected_result = [
['nid' => $this->nodes[0]->id()],
['nid' => $this->nodes[1]->id()],
];
$this->assertIdenticalResultset($view, $expected_result, $this->map);
$view->destroy();
// Test not between with min and max.
$view->initHandlers();
$view->filter['created']->operator = 'not between';
$view->filter['created']->value['min'] = format_date(100000, 'custom', 'Y-m-d H:i:s');
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
$view->executeDisplay('default');
$expected_result = [
['nid' => $this->nodes[2]->id()],
['nid' => $this->nodes[3]->id()],
];
$this->assertIdenticalResultset($view, $expected_result, $this->map);
$view->destroy();
// Test not between with just max.
$view->initHandlers();
$view->filter['created']->operator = 'not between';
$view->filter['created']->value['max'] = format_date(200000, 'custom', 'Y-m-d H:i:s');
$view->executeDisplay('default');
$expected_result = [
['nid' => $this->nodes[2]->id()],
['nid' => $this->nodes[3]->id()],
];
$this->assertIdenticalResultset($view, $expected_result, $this->map);
}
/**
* Make sure the validation callbacks works.
*/
protected function _testUiValidation() {
$this->drupalLogin($this->drupalCreateUser(['administer views', 'administer site configuration']));
$this->drupalGet('admin/structure/views/view/test_filter_date_between/edit');
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created');
$edit = [];
// Generate a definitive wrong value, which should be checked by validation.
$edit['options[value][value]'] = $this->randomString() . '-------';
$this->drupalPostForm(NULL, $edit, t('Apply'));
$this->assertText(t('Invalid date format.'), 'Make sure that validation is run and the invalidate date format is identified.');
}
/**
* Test date filter UI.
*/
protected function _testFilterDateUI() {
$this->drupalLogin($this->drupalCreateUser(['administer views']));
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created');
$this->drupalPostForm(NULL, [], t('Expose filter'));
$this->drupalPostForm(NULL, [], t('Grouped filters'));
$edit = [];
$edit['options[group_info][group_items][1][title]'] = 'simple-offset';
$edit['options[group_info][group_items][1][operator]'] = '>';
$edit['options[group_info][group_items][1][value][type]'] = 'offset';
$edit['options[group_info][group_items][1][value][value]'] = '+1 hour';
$edit['options[group_info][group_items][2][title]'] = 'between-offset';
$edit['options[group_info][group_items][2][operator]'] = 'between';
$edit['options[group_info][group_items][2][value][type]'] = 'offset';
$edit['options[group_info][group_items][2][value][min]'] = '+1 hour';
$edit['options[group_info][group_items][2][value][max]'] = '+2 days';
$edit['options[group_info][group_items][3][title]'] = 'between-date';
$edit['options[group_info][group_items][3][operator]'] = 'between';
$edit['options[group_info][group_items][3][value][min]'] = format_date(150000, 'custom', 'Y-m-d H:i:s');
$edit['options[group_info][group_items][3][value][max]'] = format_date(250000, 'custom', 'Y-m-d H:i:s');
$this->drupalPostForm(NULL, $edit, t('Apply'));
$this->drupalGet('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created');
foreach ($edit as $name => $value) {
$this->assertFieldByName($name, $value);
if (strpos($name, '[value][type]')) {
$radio = $this->cssSelect('input[name="' . $name . '"][checked="checked"][type="radio"]');
$this->assertEqual($radio[0]->getAttribute('value'), $value);
}
}
$this->drupalPostForm('admin/structure/views/view/test_filter_date_between', [], t('Save'));
$this->assertConfigSchemaByName('views.view.test_filter_date_between');
// Test that the exposed filter works as expected.
$path = 'test_filter_date_between-path';
$this->drupalPostForm('admin/structure/views/view/test_filter_date_between/edit', [], 'Add Page');
$this->drupalPostForm('admin/structure/views/nojs/display/test_filter_date_between/page_1/path', ['path' => $path], 'Apply');
$this->drupalPostForm(NULL, [], t('Save'));
$this->drupalGet($path);
$this->drupalPostForm(NULL, [], 'Apply');
$results = $this->cssSelect('.view-content .field-content');
$this->assertEqual(count($results), 4);
$this->drupalPostForm(NULL, ['created' => '1'], 'Apply');
$results = $this->cssSelect('.view-content .field-content');
$this->assertEqual(count($results), 1);
$this->assertEqual($results[0]->getText(), $this->nodes[3]->id());
$this->drupalPostForm(NULL, ['created' => '2'], 'Apply');
$results = $this->cssSelect('.view-content .field-content');
$this->assertEqual(count($results), 1);
$this->assertEqual($results[0]->getText(), $this->nodes[3]->id());
$this->drupalPostForm(NULL, ['created' => '3'], 'Apply');
$results = $this->cssSelect('.view-content .field-content');
$this->assertEqual(count($results), 1);
$this->assertEqual($results[0]->getText(), $this->nodes[1]->id());
// Change the filter to a single filter to test the schema when the operator
// is not exposed.
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created', [], t('Single filter'));
$edit = [];
$edit['options[operator]'] = '>';
$edit['options[value][type]'] = 'date';
$edit['options[value][value]'] = format_date(350000, 'custom', 'Y-m-d H:i:s');
$this->drupalPostForm(NULL, $edit, t('Apply'));
$this->drupalPostForm('admin/structure/views/view/test_filter_date_between', [], t('Save'));
$this->assertConfigSchemaByName('views.view.test_filter_date_between');
// Test that the filter works as expected.
$this->drupalGet($path);
$results = $this->cssSelect('.view-content .field-content');
$this->assertEqual(count($results), 1);
$this->assertEqual($results[0]->getText(), $this->nodes[3]->id());
$this->drupalPostForm(NULL, ['created' => format_date(250000, 'custom', 'Y-m-d H:i:s')], 'Apply');
$results = $this->cssSelect('.view-content .field-content');
$this->assertEqual(count($results), 2);
$this->assertEqual($results[0]->getText(), $this->nodes[2]->id());
$this->assertEqual($results[1]->getText(), $this->nodes[3]->id());
}
/**
* Test datetime grouped filter UI.
*/
protected function _testFilterDatetimeUI() {
$this->drupalLogin($this->drupalCreateUser(['administer views']));
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_filter_date_between/default/filter', ['name[node__field_date.field_date_value]' => 'node__field_date.field_date_value'], t('Add and configure filter criteria'));
$this->drupalPostForm(NULL, [], t('Expose filter'));
$this->drupalPostForm(NULL, [], t('Grouped filters'));
$edit = [];
$edit['options[group_info][group_items][1][title]'] = 'simple-offset';
$edit['options[group_info][group_items][1][operator]'] = '>';
$edit['options[group_info][group_items][1][value][type]'] = 'offset';
$edit['options[group_info][group_items][1][value][value]'] = '+1 hour';
$edit['options[group_info][group_items][2][title]'] = 'between-offset';
$edit['options[group_info][group_items][2][operator]'] = 'between';
$edit['options[group_info][group_items][2][value][type]'] = 'offset';
$edit['options[group_info][group_items][2][value][min]'] = '+1 hour';
$edit['options[group_info][group_items][2][value][max]'] = '+2 days';
$edit['options[group_info][group_items][3][title]'] = 'between-date';
$edit['options[group_info][group_items][3][operator]'] = 'between';
$edit['options[group_info][group_items][3][value][min]'] = format_date(150000, 'custom', 'Y-m-d H:i:s');
$edit['options[group_info][group_items][3][value][max]'] = format_date(250000, 'custom', 'Y-m-d H:i:s');
$this->drupalPostForm(NULL, $edit, t('Apply'));
$this->drupalPostForm('admin/structure/views/view/test_filter_date_between', [], t('Save'));
$this->assertConfigSchemaByName('views.view.test_filter_date_between');
}
/**
* Tests that the exposed date filter is displayed without errors.
*/
public function testExposedFilter() {
$this->drupalLogin($this->drupalCreateUser(['administer views']));
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created', [], t('Expose filter'));
$this->drupalPostForm('admin/structure/views/view/test_filter_date_between/edit', [], t('Add Page'));
$edit = [
'path' => 'exposed-date-filter',
];
$this->drupalPostForm('admin/structure/views/nojs/display/test_filter_date_between/page_1/path', $edit, t('Apply'));
$this->drupalPostForm(NULL, [], t('Save'));
$this->drupalGet('exposed-date-filter');
$this->assertField('created');
}
}
@@ -0,0 +1,116 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\HandlerBase;
use Drupal\views\Plugin\views\filter\InOperator;
use Drupal\views\Entity\View;
/**
* Tests instances of all handlers.
*
* @group views
*/
class HandlerAllTest extends ViewTestBase {
use CommentTestTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'aggregator',
'book',
'block',
'comment',
'contact',
'field',
'filter',
'file',
'forum',
'history',
'language',
'locale',
'node',
'search',
'statistics',
'taxonomy',
'user',
];
/**
* Tests most of the handlers.
*/
public function testHandlers() {
$this->drupalCreateContentType(['type' => 'article']);
$this->addDefaultCommentField('node', 'article');
$object_types = array_keys(ViewExecutable::getHandlerTypes());
foreach ($this->container->get('views.views_data')->get() as $base_table => $info) {
if (!isset($info['table']['base'])) {
continue;
}
$view = View::create(['base_table' => $base_table]);
$view = $view->getExecutable();
// @todo The groupwise relationship is currently broken.
$exclude[] = 'taxonomy_term_field_data:tid_representative';
$exclude[] = 'users_field_data:uid_representative';
// Go through all fields and there through all handler types.
foreach ($info as $field => $field_info) {
// Table is a reserved key for the metainformation.
if ($field != 'table' && !in_array("$base_table:$field", $exclude)) {
$item = [
'table' => $base_table,
'field' => $field,
];
foreach ($object_types as $type) {
if (isset($field_info[$type]['id'])) {
$options = [];
if ($type == 'filter') {
$handler = $this->container->get("plugin.manager.views.$type")->getHandler($item);
// Set the value to use for the filter based on the filter type.
if ($handler instanceof InOperator) {
$options['value'] = [1];
}
else {
$options['value'] = 1;
}
}
$view->addHandler('default', $type, $base_table, $field, $options);
}
}
}
}
// Go through each step individually to see whether some parts are
// failing.
$view->build();
$view->preExecute();
$view->execute();
$view->render();
// Make sure all handlers extend the HandlerBase.
foreach ($object_types as $type) {
if (isset($view->{$type})) {
foreach ($view->{$type} as $handler) {
$this->assertTrue($handler instanceof HandlerBase, format_string(
'@type handler of class %class is an instance of HandlerBase',
[
'@type' => $type,
'%class' => get_class($handler),
]));
}
}
}
}
}
}
@@ -0,0 +1,400 @@
<?php
namespace Drupal\Tests\views\Functional\Handler;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Entity\View;
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\HandlerBase;
use Drupal\views\Views;
/**
* Tests abstract handler definitions.
*
* @group views
*/
class HandlerTest extends ViewTestBase {
use CommentTestTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_view', 'test_view_handler_weight', 'test_handler_relationships', 'test_handler_test_access', 'test_filter_in_operator_ui'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['views_ui', 'comment', 'node'];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->drupalCreateContentType(['type' => 'page']);
$this->addDefaultCommentField('node', 'page');
$this->enableViewsTestModule();
}
/**
* {@inheritdoc}
*/
protected function viewsData() {
$data = parent::viewsData();
// Override the name handler to be able to call placeholder() from outside.
$data['views_test_data']['name']['field']['id'] = 'test_field';
// Setup one field with an access callback and one with an access callback
// and arguments.
$data['views_test_data']['access_callback'] = $data['views_test_data']['id'];
$data['views_test_data']['access_callback_arguments'] = $data['views_test_data']['id'];
foreach (ViewExecutable::getHandlerTypes() as $type => $info) {
if (isset($data['views_test_data']['access_callback'][$type]['id'])) {
$data['views_test_data']['access_callback'][$type]['access callback'] = 'views_test_data_handler_test_access_callback';
$data['views_test_data']['access_callback_arguments'][$type]['access callback'] = 'views_test_data_handler_test_access_callback_argument';
$data['views_test_data']['access_callback_arguments'][$type]['access arguments'] = [TRUE];
}
}
return $data;
}
/**
* Tests the breakString method.
*/
public function testBreakString() {
// Check defaults.
$this->assertEqual((object) ['value' => [], 'operator' => NULL], HandlerBase::breakString(''));
// Test ors
$handler = HandlerBase::breakString('word1 word2+word');
$this->assertEqualValue(['word1', 'word2', 'word'], $handler);
$this->assertEqual('or', $handler->operator);
$handler = HandlerBase::breakString('word1+word2+word');
$this->assertEqualValue(['word1', 'word2', 'word'], $handler);
$this->assertEqual('or', $handler->operator);
$handler = HandlerBase::breakString('word1 word2 word');
$this->assertEqualValue(['word1', 'word2', 'word'], $handler);
$this->assertEqual('or', $handler->operator);
$handler = HandlerBase::breakString('word-1+word-2+word');
$this->assertEqualValue(['word-1', 'word-2', 'word'], $handler);
$this->assertEqual('or', $handler->operator);
$handler = HandlerBase::breakString('wõrd1+wõrd2+wõrd');
$this->assertEqualValue(['wõrd1', 'wõrd2', 'wõrd'], $handler);
$this->assertEqual('or', $handler->operator);
// Test ands.
$handler = HandlerBase::breakString('word1,word2,word');
$this->assertEqualValue(['word1', 'word2', 'word'], $handler);
$this->assertEqual('and', $handler->operator);
$handler = HandlerBase::breakString('word1 word2,word');
$this->assertEqualValue(['word1 word2', 'word'], $handler);
$this->assertEqual('and', $handler->operator);
$handler = HandlerBase::breakString('word1,word2 word');
$this->assertEqualValue(['word1', 'word2 word'], $handler);
$this->assertEqual('and', $handler->operator);
$handler = HandlerBase::breakString('word-1,word-2,word');
$this->assertEqualValue(['word-1', 'word-2', 'word'], $handler);
$this->assertEqual('and', $handler->operator);
$handler = HandlerBase::breakString('wõrd1,wõrd2,wõrd');
$this->assertEqualValue(['wõrd1', 'wõrd2', 'wõrd'], $handler);
$this->assertEqual('and', $handler->operator);
// Test a single word
$handler = HandlerBase::breakString('word');
$this->assertEqualValue(['word'], $handler);
$this->assertEqual('and', $handler->operator);
$s1 = $this->randomMachineName();
// Generate three random numbers which can be used below;
$n1 = rand(0, 100);
$n2 = rand(0, 100);
$n3 = rand(0, 100);
// Test "or"s.
$handlerBase = HandlerBase::breakString("$s1 $n2+$n3");
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
$this->assertEqual('or', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$s1+$n2+$n3");
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
$this->assertEqual('or', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$s1 $n2 $n3");
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
$this->assertEqual('or', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$s1 $n2++$n3");
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
$this->assertEqual('or', $handlerBase->operator);
// Test "and"s.
$handlerBase = HandlerBase::breakString("$s1,$n2,$n3");
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
$this->assertEqual('and', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$s1,,$n2,$n3");
$this->assertEqualValue([$s1, $n2, $n3], $handlerBase);
$this->assertEqual('and', $handlerBase->operator);
// Enforce int values.
$handlerBase = HandlerBase::breakString("$n1,$n2,$n3", TRUE);
$this->assertEqualValue([$n1, $n2, $n3], $handlerBase);
$this->assertEqual('and', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$n1+$n2+$n3", TRUE);
$this->assertEqualValue([$n1, $n2, $n3], $handlerBase);
$this->assertEqual('or', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$s1,$n2,$n3", TRUE);
$this->assertEqualValue([(int) $s1, $n2, $n3], $handlerBase);
$this->assertEqual('and', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$s1+$n2+$n3", TRUE);
$this->assertEqualValue([(int) $s1, $n2, $n3], $handlerBase);
$this->assertEqual('or', $handlerBase->operator);
// Generate three random decimals which can be used below;
$d1 = rand(0, 10) / 10;
$d2 = rand(0, 10) / 10;
$d3 = rand(0, 10) / 10;
// Test "or"s.
$handlerBase = HandlerBase::breakString("$s1 $d1+$d2");
$this->assertEqualValue([$s1, $d1, $d2], $handlerBase);
$this->assertEqual('or', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$s1+$d1+$d3");
$this->assertEqualValue([$s1, $d1, $d3], $handlerBase);
$this->assertEqual('or', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$s1 $d2 $d3");
$this->assertEqualValue([$s1, $d2, $d3], $handlerBase);
$this->assertEqual('or', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$s1 $d2++$d3");
$this->assertEqualValue([$s1, $d2, $d3], $handlerBase);
$this->assertEqual('or', $handlerBase->operator);
// Test "and"s.
$handlerBase = HandlerBase::breakString("$s1,$d2,$d3");
$this->assertEqualValue([$s1, $d2, $d3], $handlerBase);
$this->assertEqual('and', $handlerBase->operator);
$handlerBase = HandlerBase::breakString("$s1,,$d2,$d3");
$this->assertEqualValue([$s1, $d2, $d3], $handlerBase);
$this->assertEqual('and', $handlerBase->operator);
}
/**
* Tests the order of handlers is the same before and after saving.
*/
public function testHandlerWeights() {
$handler_types = ['fields', 'filters', 'sorts'];
$view = Views::getView('test_view_handler_weight');
$view->initDisplay();
// Store the order of handlers before saving the view.
$original_order = [];
foreach ($handler_types as $type) {
$original_order[$type] = array_keys($view->display_handler->getOption($type));
}
// Save the view and see if our filters are in the same order.
$view->save();
$view = views::getView('test_view_handler_weight');
$view->initDisplay();
foreach ($handler_types as $type) {
$loaded_order = array_keys($view->display_handler->getOption($type));
$this->assertIdentical($original_order[$type], $loaded_order);
}
}
/**
* Check to see if a value is the same as the value on a certain handler.
*
* @param $expected
* The expected value to check.
* @param \Drupal\views\Plugin\views\ViewsHandlerInterface $handler
* The handler that has the $handler->value property to compare with first.
* @param string $message
* The message to display along with the assertion.
* @param string $group
* The type of assertion - examples are "Browser", "PHP".
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertEqualValue($expected, $handler, $message = '', $group = 'Other') {
if (empty($message)) {
$message = t('Comparing @first and @second', ['@first' => implode(',', $expected), '@second' => implode(',', $handler->value)]);
}
return $this->assert($expected == $handler->value, $message, $group);
}
/**
* Tests the relationship ui for field/filter/argument/relationship.
*/
public function testRelationshipUI() {
$views_admin = $this->drupalCreateUser(['administer views']);
$this->drupalLogin($views_admin);
// Make sure the link to the field options exists.
$handler_options_path = 'admin/structure/views/nojs/handler/test_handler_relationships/default/field/title';
$view_edit_path = 'admin/structure/views/view/test_handler_relationships/edit';
$this->drupalGet($view_edit_path);
$this->assertLinkByHref($handler_options_path);
// The test view has a relationship to node_revision so the field should
// show a relationship selection.
$this->drupalGet($handler_options_path);
$relationship_name = 'options[relationship]';
$this->assertFieldByName($relationship_name);
// Check for available options.
$fields = $this->getSession()->getPage()->findAll('named_exact', ['field', $relationship_name]);
$options = [];
foreach ($fields as $field) {
$items = $field->findAll('css', 'option');
foreach ($items as $item) {
$options[] = $item->getAttribute('value');
}
}
$expected_options = ['none', 'nid'];
$this->assertEqual($options, $expected_options);
// Remove the relationship and make sure no relationship option appears.
$this->drupalPostForm('admin/structure/views/nojs/handler/test_handler_relationships/default/relationship/nid', [], t('Remove'));
$this->drupalGet($handler_options_path);
$this->assertNoFieldByName($relationship_name, NULL, 'Make sure that no relationship option is available');
// Create a view of comments with node relationship.
View::create(['base_table' => 'comment_field_data', 'id' => 'test_get_entity_type'])->save();
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_get_entity_type/default/relationship', ['name[comment_field_data.node]' => 'comment_field_data.node'], t('Add and configure relationships'));
$this->drupalPostForm(NULL, [], t('Apply'));
// Add a content type filter.
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_get_entity_type/default/filter', ['name[node_field_data.type]' => 'node_field_data.type'], t('Add and configure filter criteria'));
$this->assertOptionSelected('edit-options-relationship', 'node');
$this->drupalPostForm(NULL, ['options[value][page]' => 'page'], t('Apply'));
// Check content type filter options.
$this->drupalGet('admin/structure/views/nojs/handler/test_get_entity_type/default/filter/type');
$this->assertOptionSelected('edit-options-relationship', 'node');
$this->assertFieldChecked('edit-options-value-page');
}
/**
* Tests the relationship method on the base class.
*/
public function testSetRelationship() {
$view = Views::getView('test_handler_relationships');
$view->setDisplay();
// Setup a broken relationship.
$view->addHandler('default', 'relationship', $this->randomMachineName(), $this->randomMachineName(), [], 'broken_relationship');
// Setup a valid relationship.
$view->addHandler('default', 'relationship', 'comment_field_data', 'node', ['relationship' => 'cid'], 'valid_relationship');
$view->initHandlers();
$field = $view->field['title'];
$field->options['relationship'] = NULL;
$field->setRelationship();
$this->assertFalse($field->relationship, 'Make sure that an empty relationship does not create a relationship on the field.');
$field->options['relationship'] = $this->randomMachineName();
$field->setRelationship();
$this->assertFalse($field->relationship, 'Make sure that a random relationship does not create a relationship on the field.');
$field->options['relationship'] = 'broken_relationship';
$field->setRelationship();
$this->assertFalse($field->relationship, 'Make sure that a broken relationship does not create a relationship on the field.');
$field->options['relationship'] = 'valid_relationship';
$field->setRelationship();
$this->assertFalse(!empty($field->relationship), 'Make sure that the relationship alias was not set without building a views query before.');
// Remove the invalid relationship.
unset($view->relationship['broken_relationship']);
$view->build();
$field->setRelationship();
$this->assertEqual($field->relationship, $view->relationship['valid_relationship']->alias, 'Make sure that a valid relationship does create the right relationship query alias.');
}
/**
* Tests the placeholder function.
*
* @see \Drupal\views\Plugin\views\HandlerBase::placeholder()
*/
public function testPlaceholder() {
$view = Views::getView('test_view');
$view->initHandlers();
$view->initQuery();
$handler = $view->field['name'];
$table = $handler->table;
$field = $handler->field;
$string = ':' . $table . '_' . $field;
// Make sure the placeholder variables are like expected.
$this->assertEqual($handler->getPlaceholder(), $string);
$this->assertEqual($handler->getPlaceholder(), $string . 1);
$this->assertEqual($handler->getPlaceholder(), $string . 2);
// Set another table/field combination and make sure there are new
// placeholders.
$table = $handler->table = $this->randomMachineName();
$field = $handler->field = $this->randomMachineName();
$string = ':' . $table . '_' . $field;
// Make sure the placeholder variables are like expected.
$this->assertEqual($handler->getPlaceholder(), $string);
$this->assertEqual($handler->getPlaceholder(), $string . 1);
$this->assertEqual($handler->getPlaceholder(), $string . 2);
}
/**
* Tests access to a handler.
*
* @see views_test_data_handler_test_access_callback
*/
public function testAccess() {
$view = Views::getView('test_handler_test_access');
$views_data = $this->viewsData();
$views_data = $views_data['views_test_data'];
// Enable access to callback only field and deny for callback + arguments.
$this->config('views_test_data.tests')->set('handler_access_callback', TRUE)->save();
$this->config('views_test_data.tests')->set('handler_access_callback_argument', FALSE)->save();
$view->initDisplay();
$view->initHandlers();
foreach ($views_data['access_callback'] as $type => $info) {
if (!in_array($type, ['title', 'help'])) {
$this->assertTrue($view->field['access_callback'] instanceof HandlerBase, 'Make sure the user got access to the access_callback field ');
$this->assertFalse(isset($view->field['access_callback_arguments']), 'Make sure the user got no access to the access_callback_arguments field ');
}
}
// Enable access to the callback + argument handlers and deny for callback.
$this->config('views_test_data.tests')->set('handler_access_callback', FALSE)->save();
$this->config('views_test_data.tests')->set('handler_access_callback_argument', TRUE)->save();
$view->destroy();
$view->initDisplay();
$view->initHandlers();
foreach ($views_data['access_callback'] as $type => $info) {
if (!in_array($type, ['title', 'help'])) {
$this->assertFalse(isset($view->field['access_callback']), 'Make sure the user got no access to the access_callback field ');
$this->assertTrue($view->field['access_callback_arguments'] instanceof HandlerBase, 'Make sure the user got access to the access_callback_arguments field ');
}
}
}
}
@@ -0,0 +1,106 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
use Drupal\views\Views;
/**
* Tests pluggable access for views.
*
* @group views
* @todo It probably make sense to split the test up by one for role/perm/none
* and the two generic ones.
*/
class AccessTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_access_none', 'test_access_static', 'test_access_dynamic'];
/**
* Modules to enable.
*
* @return array
*/
public static $modules = ['node'];
/**
* Web user for testing.
*
* @var \Drupal\user\UserInterface
*/
protected $webUser;
/**
* Normal user for testing.
*
* @var \Drupal\user\UserInterface
*/
protected $normalUser;
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
ViewTestData::createTestViews(get_class($this), ['views_test_data']);
$this->webUser = $this->drupalCreateUser();
$normal_role = $this->drupalCreateRole([]);
$this->normalUser = $this->drupalCreateUser(['views_test_data test permission']);
$this->normalUser->addRole($normal_role);
// @todo when all the plugin information is cached make a reset function and
// call it here.
}
/**
* Tests none access plugin.
*/
public function testAccessNone() {
$view = Views::getView('test_access_none');
$view->setDisplay();
$this->assertTrue($view->display_handler->access($this->webUser));
$this->assertTrue($view->display_handler->access($this->normalUser));
}
/**
* @todo Test abstract access plugin.
*/
/**
* Tests static access check.
*
* @see \Drupal\views_test\Plugin\views\access\StaticTest
*/
public function testStaticAccessPlugin() {
$view = Views::getView('test_access_static');
$view->setDisplay();
$access_plugin = $view->display_handler->getPlugin('access');
$this->assertFalse($access_plugin->access($this->normalUser));
$this->drupalGet('test_access_static');
$this->assertResponse(403);
$display = &$view->storage->getDisplay('default');
$display['display_options']['access']['options']['access'] = TRUE;
$access_plugin->options['access'] = TRUE;
$view->save();
// Saving a view will cause the router to be rebuilt when the kernel
// termination event fires. Simulate that here.
$this->container->get('router.builder')->rebuildIfNeeded();
$this->assertTrue($access_plugin->access($this->normalUser));
$this->drupalGet('test_access_static');
$this->assertResponse(200);
}
}
@@ -0,0 +1,190 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\Core\Url;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
use Drupal\views_test_data\Plugin\views\argument_default\ArgumentDefaultTest as ArgumentDefaultTestPlugin;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests pluggable argument_default for views.
*
* @group views
*/
class ArgumentDefaultTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = [
'test_view',
'test_argument_default_fixed',
'test_argument_default_current_user',
'test_argument_default_node',
'test_argument_default_query_param',
];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'views_ui', 'block'];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
}
/**
* Tests the argument default test plugin.
*
* @see \Drupal\views_test_data\Plugin\views\argument_default\ArgumentDefaultTest
*/
public function testArgumentDefaultPlugin() {
$view = Views::getView('test_view');
// Add a new argument and set the test plugin for the argument_default.
$options = [
'default_argument_type' => 'argument_default_test',
'default_argument_options' => [
'value' => 'John'
],
'default_action' => 'default'
];
$id = $view->addHandler('default', 'argument', 'views_test_data', 'name', $options);
$view->initHandlers();
$plugin = $view->argument[$id]->getPlugin('argument_default');
$this->assertTrue($plugin instanceof ArgumentDefaultTestPlugin, 'The correct argument default plugin is used.');
// Check that the value of the default argument is as expected.
$this->assertEqual($view->argument[$id]->getDefaultArgument(), 'John', 'The correct argument default value is returned.');
// Don't pass in a value for the default argument and make sure the query
// just returns John.
$this->executeView($view);
$this->assertEqual($view->argument[$id]->getValue(), 'John', 'The correct argument value is used.');
$expected_result = [['name' => 'John']];
$this->assertIdenticalResultset($view, $expected_result, ['views_test_data_name' => 'name']);
// Pass in value as argument to be sure that not the default value is used.
$view->destroy();
$this->executeView($view, ['George']);
$this->assertEqual($view->argument[$id]->getValue(), 'George', 'The correct argument value is used.');
$expected_result = [['name' => 'George']];
$this->assertIdenticalResultset($view, $expected_result, ['views_test_data_name' => 'name']);
}
/**
* Tests the use of a default argument plugin that provides no options.
*/
public function testArgumentDefaultNoOptions() {
$admin_user = $this->drupalCreateUser(['administer views', 'administer site configuration']);
$this->drupalLogin($admin_user);
// The current_user plugin has no options form, and should pass validation.
$argument_type = 'current_user';
$edit = [
'options[default_argument_type]' => $argument_type,
];
$this->drupalPostForm('admin/structure/views/nojs/handler/test_argument_default_current_user/default/argument/uid', $edit, t('Apply'));
// Note, the undefined index error has two spaces after it.
$error = [
'%type' => 'Notice',
'@message' => 'Undefined index: ' . $argument_type,
'%function' => 'views_handler_argument->validateOptionsForm()',
];
$message = t('%type: @message in %function', $error);
$this->assertNoRaw($message, format_string('Did not find error message: @message.', ['@message' => $message]));
}
/**
* Tests fixed default argument.
*/
public function testArgumentDefaultFixed() {
$random = $this->randomMachineName();
$view = Views::getView('test_argument_default_fixed');
$view->setDisplay();
$options = $view->display_handler->getOption('arguments');
$options['null']['default_argument_options']['argument'] = $random;
$view->display_handler->overrideOption('arguments', $options);
$view->initHandlers();
$this->assertEqual($view->argument['null']->getDefaultArgument(), $random, 'Fixed argument should be used by default.');
// Make sure that a normal argument provided is used
$random_string = $this->randomMachineName();
$view->executeDisplay('default', [$random_string]);
$this->assertEqual($view->args[0], $random_string, 'Provided argument should be used.');
}
/**
* @todo Test php default argument.
*/
//function testArgumentDefaultPhp() {}
/**
* Test node default argument.
*/
public function testArgumentDefaultNode() {
// Create a user that has permission to place a view block.
$permissions = [
'administer views',
'administer blocks',
'bypass node access',
'access user profiles',
'view all revisions',
];
$views_admin = $this->drupalCreateUser($permissions);
$this->drupalLogin($views_admin);
// Create nodes where should show themselves again as view block.
$node_type = NodeType::create(['type' => 'page', 'label' => 'Page']);
$node_type->save();
$node1 = Node::create(['title' => 'Test node 1', 'type' => 'page']);
$node1->save();
$node2 = Node::create(['title' => 'Test node 2', 'type' => 'page']);
$node2->save();
// Place the block, visit the pages that display the block, and check that
// the nodes we expect appear in the respective pages.
$id = 'view-block-id';
$this->drupalPlaceBlock("views_block:test_argument_default_node-block_1", ['id' => $id]);
$xpath = '//*[@id="block-' . $id . '"]';
$this->drupalGet('node/' . $node1->id());
$this->assertTrue(strpos($this->xpath($xpath)[0]->getText(), $node1->getTitle()));
$this->drupalGet('node/' . $node2->id());
$this->assertTrue(strpos($this->xpath($xpath)[0]->getText(), $node2->getTitle()));
}
/**
* Tests the query parameter default argument.
*/
public function testArgumentDefaultQueryParameter() {
$view = Views::getView('test_argument_default_query_param');
$request = Request::create(Url::fromUri('internal:/whatever', ['absolute' => TRUE])->toString());
// Check the query parameter default argument fallback value.
$view->setRequest($request);
$view->initHandlers();
$this->assertEqual($view->argument['type']->getDefaultArgument(), 'all');
// Check the query parameter default argument with a value.
$request->query->add(['the_node_type' => 'page']);
$view->setRequest($request);
$view->initHandlers();
$this->assertEqual($view->argument['type']->getDefaultArgument(), 'page');
}
}
@@ -0,0 +1,212 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\Core\Cache\Cache;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\ViewExecutable;
use Drupal\views\Views;
/**
* Tests tag cache plugin.
*
* @group views
* @see \Drupal\views\Plugin\views\cache\Tag
*/
class CacheTagTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_tag_cache'];
/**
* Views used by this test.
*
* @var array
*/
public static $modules = ['node'];
/**
* The node storage.
*
* @var \Drupal\node\NodeStorage
*/
protected $nodeStorage;
/**
* The node view builder.
*
* @var \Drupal\node\NodeViewBuilder
*/
protected $nodeViewBuilder;
/**
* The user view builder.
*
* @var \Drupal\Core\Entity\EntityViewBuilder
*/
protected $userViewBuilder;
/**
* An array of page nodes.
*
* @var \Drupal\node\NodeInterface[]
*/
protected $pages;
/**
* An article node.
*
* @var \Drupal\node\NodeInterface
*/
protected $article;
/**
* A test user.
*
* @var \Drupal\user\UserInterface
*/
protected $user;
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
$this->nodeStorage = $this->container->get('entity.manager')->getStorage('node');
$this->nodeViewBuilder = $this->container->get('entity.manager')->getViewBuilder('node');
$this->userViewBuilder = $this->container->get('entity.manager')->getViewBuilder('user');
for ($i = 1; $i <= 5; $i++) {
$this->pages[] = $this->drupalCreateNode(['title' => "Test $i", 'type' => 'page']);
}
$this->article = $this->drupalCreateNode(['title' => "Test article", 'type' => 'article']);
$this->user = $this->drupalCreateUser();
// Mark the current request safe, in order to make render cache working, see
// \Drupal\Core\Render\RenderCache::get.
\Drupal::request()->setMethod('GET');
}
/**
* Gets the render cache for a given view.
*
* @param \Drupal\views\ViewExecutable $view
* The view.
*
* @return array|false
* The render cache result or FALSE if not existent.
*/
protected function getRenderCache(ViewExecutable $view) {
/** @var \Drupal\Core\Render\RenderCacheInterface $render_cache */
$render_cache = \Drupal::service('render_cache');
$view->element = ['#cache' => []];
$build = $view->buildRenderable();
$build['#cache']['contexts'] = Cache::mergeContexts($build['#cache']['contexts'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
return $render_cache->get($build);
}
/**
* Tests the tag cache plugin.
*/
public function testTagCaching() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_tag_cache');
$build = $view->buildRenderable();
$renderer->renderPlain($build);
// Saving the view should invalidate the tags.
$cache_plugin = $view->display_handler->getPlugin('cache');
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
$view->storage->save();
$this->assertFalse($cache_plugin->cacheGet('results'), 'Results cache empty after the view is saved.');
$this->assertFalse($this->getRenderCache($view), 'Output cache empty after the view is saved.');
$view->destroy();
$build = $view->buildRenderable();
$renderer->renderPlain($build);
// Test invalidating the nodes in this view invalidates the cache.
$cache_plugin = $view->display_handler->getPlugin('cache');
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
$this->nodeViewBuilder->resetCache($this->pages);
$this->assertFalse($cache_plugin->cacheGet('results'), 'Results cache empty after resetCache is called with pages.');
$this->assertFalse($this->getRenderCache($view), 'Output cache empty after resetCache is called with pages.');
$view->destroy();
$build = $view->buildRenderable();
$renderer->renderPlain($build);
// Test saving a node in this view invalidates the cache.
$cache_plugin = $view->display_handler->getPlugin('cache');
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
$node = reset($this->pages);
$node->save();
$this->assertFalse($cache_plugin->cacheGet('results'), 'Results cache empty after a page node is saved.');
$this->assertFalse($this->getRenderCache($view), 'Output cache empty after a page node is saved.');
$view->destroy();
$build = $view->buildRenderable();
$renderer->renderPlain($build);
// Test saving a node not in this view invalidates the cache too.
$cache_plugin = $view->display_handler->getPlugin('cache');
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
$this->article->save();
$this->assertFalse($cache_plugin->cacheGet('results'), 'Results cache empty after an article node is saved.');
$this->assertFalse($this->getRenderCache($view), 'Output cache empty after an article node is saved.');
$view->destroy();
$build = $view->buildRenderable();
$renderer->renderPlain($build);
// Test that invalidating a tag for a user, does not invalidate the cache,
// as the user entity type will not be contained in the views cache tags.
$cache_plugin = $view->display_handler->getPlugin('cache');
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
$this->userViewBuilder->resetCache([$this->user]);
$cache_plugin = $view->display_handler->getPlugin('cache');
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found after a user is invalidated.');
$this->assertTrue($this->getRenderCache($view), 'Output cache found after a user is invalidated.');
$view->destroy();
// Invalidate the views cache tags in order to invalidate the render
// caching.
\Drupal::service('cache_tags.invalidator')->invalidateTags($view->storage->getCacheTagsToInvalidate());
$build = $view->buildRenderable();
$renderer->renderPlain($build);
// Test the cacheFlush method invalidates the cache.
$cache_plugin = $view->display_handler->getPlugin('cache');
$this->assertTrue($cache_plugin->cacheGet('results'), 'Results cache found.');
$this->assertTrue($this->getRenderCache($view), 'Output cache found.');
$cache_plugin->cacheFlush();
$cache_plugin = $view->display_handler->getPlugin('cache');
$this->assertFalse($cache_plugin->cacheGet('results'), 'Results cache empty after the cacheFlush() method is called.');
$this->assertFalse($this->getRenderCache($view), 'Output cache empty after the cacheFlush() method is called.');
}
}
@@ -0,0 +1,94 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Views;
/**
* Tests pluggable caching for views via a web test.
*
* @group views
* @see views_plugin_cache
*/
class CacheWebTest extends ViewTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_display'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['taxonomy'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
}
/**
* Tests the output caching on an actual page.
*/
public function testCacheOutputOnPage() {
$view = Views::getView('test_display');
$view->storage->setStatus(TRUE);
$view->setDisplay('page_1');
$view->display_handler->overrideOption('cache', [
'type' => 'time',
'options' => [
'results_lifespan' => '3600',
'output_lifespan' => '3600'
]
]);
$view->save();
$this->container->get('router.builder')->rebuildIfNeeded();
/** @var \Drupal\Core\Render\RenderCacheInterface $render_cache */
$render_cache = \Drupal::service('render_cache');
$cache_element = DisplayPluginBase::buildBasicRenderable('test_display', 'page_1');
$cache_element['#cache'] += ['contexts' => $this->container->getParameter('renderer.config')['required_cache_contexts']];
$this->assertFalse($render_cache->get($cache_element));
$this->drupalGet('test-display');
$this->assertResponse(200);
$this->assertTrue($render_cache->get($cache_element));
$cache_tags = [
'config:user.role.anonymous',
'config:views.view.test_display',
'node_list',
'rendered'
];
$this->assertCacheTags($cache_tags);
$this->drupalGet('test-display');
$this->assertResponse(200);
$this->assertTrue($render_cache->get($cache_element));
$this->assertCacheTags($cache_tags);
}
/**
* Tests that a display without caching still contains the cache metadata.
*/
public function testDisplayWithoutCacheStillBubblesMetadata() {
$view = Views::getView('test_display');
$uncached_block = $view->buildRenderable('block_1', [], FALSE);
$cached_block = $view->buildRenderable('block_1', [], TRUE);
$this->assertEqual($uncached_block['#cache']['contexts'], $cached_block['#cache']['contexts'], 'Cache contexts are the same when you render the view cached and uncached.');
}
}
@@ -0,0 +1,153 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\Core\Plugin\Context\ContextDefinitionInterface;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* A test for contextual filters exposed as block context.
*
* @group views
*/
class ContextualFiltersBlockContextTest extends ViewTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['block', 'block_test_views', 'views_ui', 'node'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_view_block_with_context'];
/**
* Test node type.
*
* @var \Drupal\node\NodeTypeInterface
*/
protected $nodeType;
/**
* Test nodes.
*
* @var \Drupal\node\NodeInterface[]
*/
protected $nodes;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
ViewTestData::createTestViews(get_class($this), ['block_test_views']);
$this->enableViewsTestModule();
$this->nodeType = $this->container->get('entity_type.manager')
->getStorage('node_type')
->create([
'name' => 'Test node type',
'type' => 'test',
]);
$this->nodeType->save();
$this->nodes[0] = $this->container->get('entity_type.manager')
->getStorage('node')
->create(['type' => $this->nodeType->id(), 'title' => 'First test node']);
$this->nodes[0]->save();
$this->nodes[1] = $this->container->get('entity_type.manager')
->getStorage('node')
->create(['type' => $this->nodeType->id(), 'title' => 'Second test node']);
$this->nodes[1]->save();
}
/**
* Tests exposed context.
*/
public function testBlockContext() {
$this->drupalLogin($this->drupalCreateUser(['administer views', 'administer blocks']));
// Check if context was correctly propagated to the block.
$definition = $this->container->get('plugin.manager.block')
->getDefinition('views_block:test_view_block_with_context-block_1');
$this->assertTrue($definition['context']['nid'] instanceof ContextDefinitionInterface);
/** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */
$context = $definition['context']['nid'];
$this->assertEqual($context->getDataType(), 'entity:node', 'Context definition data type is correct.');
$this->assertEqual($context->getLabel(), 'Content: ID', 'Context definition label is correct.');
$this->assertFalse($context->isRequired(), 'Context is not required.');
// Place test block via block UI to check if contexts are correctly exposed.
$this->drupalGet(
'admin/structure/block/add/views_block:test_view_block_with_context-block_1/classy',
['query' => ['region' => 'content']]
);
$edit = [
'settings[context_mapping][nid]' => '@node.node_route_context:node',
];
$this->drupalPostForm(NULL, $edit, 'Save block');
// Check if mapping saved correctly.
/** @var \Drupal\block\BlockInterface $block */
$block = $this->container->get('entity_type.manager')
->getStorage('block')
->load('views_block__test_view_block_with_context_block_1');
$expected_settings = [
'id' => 'views_block:test_view_block_with_context-block_1',
'label' => '',
'provider' => 'views',
'label_display' => 'visible',
'views_label' => '',
'items_per_page' => 'none',
'context_mapping' => ['nid' => '@node.node_route_context:node']
];
$this->assertEqual($block->getPlugin()->getConfiguration(), $expected_settings, 'Block settings are correct.');
// Make sure view behaves as expected.
$this->drupalGet('<front>');
$this->assertText('Test view: No results found.');
$this->drupalGet($this->nodes[0]->toUrl());
$this->assertText('Test view row: First test node');
$this->drupalGet($this->nodes[1]->toUrl());
$this->assertText('Test view row: Second test node');
// Check the second block which should expose two integer contexts, one
// based on the numeric plugin and the other based on numeric validation.
$definition = $this->container->get('plugin.manager.block')
->getDefinition('views_block:test_view_block_with_context-block_2');
$this->assertTrue($definition['context']['created'] instanceof ContextDefinitionInterface);
/** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */
$context = $definition['context']['created'];
$this->assertEqual($context->getDataType(), 'integer', 'Context definition data type is correct.');
$this->assertEqual($context->getLabel(), 'Content: Authored on', 'Context definition label is correct.');
$this->assertFalse($context->isRequired(), 'Context is not required.');
$this->assertTrue($definition['context']['vid'] instanceof ContextDefinitionInterface);
/** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */
$context = $definition['context']['vid'];
$this->assertEqual($context->getDataType(), 'integer', 'Context definition data type is correct.');
$this->assertEqual($context->getLabel(), 'Content: Revision ID', 'Context definition label is correct.');
$this->assertFalse($context->isRequired(), 'Context is not required.');
$this->assertTrue($definition['context']['title'] instanceof ContextDefinitionInterface);
/** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */
$context = $definition['context']['title'];
$this->assertEqual($context->getDataType(), 'string', 'Context definition data type is correct.');
$this->assertEqual($context->getLabel(), 'Content: Title', 'Context definition label is correct.');
$this->assertFalse($context->isRequired(), 'Context is not required.');
}
}
@@ -0,0 +1,101 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\Tests\views\Functional\ViewTestBase;
/**
* Tests the ability to disable and enable view displays.
*
* @group views
* @see \Drupal\views\Plugin\views\display\Feed
*/
class DisabledDisplayTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_disabled_display'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['block', 'node', 'views'];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
$this->drupalPlaceBlock('page_title_block');
$admin_user = $this->drupalCreateUser(['administer site configuration']);
$this->drupalLogin($admin_user);
}
/**
* Tests that views displays can be disabled.
*
* This method only checks the page displays via a HTTP request, but should
* the .enabled property disappear from the schema both the load and save
* calls will start failing.
*/
public function testDisabledDisplays() {
// The displays defined in this view.
$display_ids = ['attachment_1', 'block_1', 'embed_1', 'feed_1', 'page_2'];
$this->drupalCreateContentType(['type' => 'page']);
$this->drupalCreateNode();
// Load the test view and initialize its displays.
$view = $this->container->get('entity.manager')->getStorage('view')->load('test_disabled_display');
$view->getExecutable()->setDisplay();
// Enabled page display should return content.
$this->drupalGet('test-disabled-display');
$result = $this->xpath('//h1[@class="page-title"]');
$this->assertEqual($result[0]->getText(), 'test_disabled_display', 'The enabled page_1 display is accessible.');
// Disabled page view should 404.
$this->drupalGet('test-disabled-display-2');
$this->assertResponse(404);
// Enable each disabled display and save the view.
foreach ($display_ids as $display_id) {
$view->getExecutable()->displayHandlers->get($display_id)->setOption('enabled', TRUE);
$view->save();
$enabled = $view->getExecutable()->displayHandlers->get($display_id)->isEnabled();
$this->assertTrue($enabled, 'Display ' . $display_id . ' is now enabled');
}
\Drupal::service('router.builder')->rebuildIfNeeded();
// Check that the originally disabled page_2 display is now enabled.
$this->drupalGet('test-disabled-display-2');
$result = $this->xpath('//h1[@class="page-title"]');
$this->assertEqual($result[0]->getText(), 'test_disabled_display', 'The enabled page_2 display is accessible.');
// Disable each disabled display and save the view.
foreach ($display_ids as $display_id) {
$view->getExecutable()->displayHandlers->get($display_id)->setOption('enabled', FALSE);
$view->save();
$enabled = $view->getExecutable()->displayHandlers->get($display_id)->isEnabled();
$this->assertFalse($enabled, 'Display ' . $display_id . ' is now disabled');
}
\Drupal::service('router.builder')->rebuild();
// Check that the page_1 display still works.
$this->drupalGet('test-disabled-display');
$this->assertResponse(200);
// Check that the page_2 display is now disabled again.
$this->drupalGet('test-disabled-display-2');
$this->assertResponse(404);
}
}
@@ -0,0 +1,107 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
/**
* Tests the attachment display plugin.
*
* @group views
* @see \Drupal\views\Plugin\views\display\Attachment
*/
class DisplayAttachmentTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_display_attachment', 'test_attached_disabled'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'views'];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
$admin_user = $this->drupalCreateUser(['administer site configuration']);
$this->drupalLogin($admin_user);
}
/**
* Tests the attachment plugin.
*/
public function testAttachment() {
$this->drupalGet('test-display-attachment');
$result = $this->xpath('//div[contains(@class, "view-content")]');
$this->assertEqual(count($result), 2, 'Both actual view and the attachment is rendered.');
$result = $this->xpath('//div[contains(@class, "attachment-after")]');
$this->assertEqual(count($result), 0, 'The attachment is not rendered after the actual view.');
$result = $this->xpath('//div[contains(@class, "attachment-before")]');
$this->assertEqual(count($result), 1, 'The attachment is rendered before the actual view.');
}
/**
* Tests that nothing is output when the attachment displays are disabled.
*/
public function testDisabledAttachments() {
$this->drupalCreateContentType(['type' => 'page']);
$this->drupalCreateNode();
// Ensure that the feed_1 display is attached to the page_1 display.
$view = Views::getView('test_attached_disabled');
$view->setDisplay('page_1');
$attached_displays = $view->display_handler->getAttachedDisplays();
$this->assertTrue(in_array('attachment_1', $attached_displays), 'The attachment_1 display is attached to the page display.');
$this->assertTrue(in_array('attachment_2', $attached_displays), 'The attachment_2 display is attached to the page display.');
// Check that the attachments are output on the page display.
$this->drupalGet('test-attached-disabled');
$result = $this->xpath('//div[contains(@class, "view-content")]');
$this->assertEqual(count($result), 3, 'The page view and the attachments are rendered.');
$result = $this->xpath('//div[contains(@class, "attachment-before")]');
$this->assertEqual(count($result), 1, 'The attachment is rendered before the page view.');
$result = $this->xpath('//div[contains(@class, "attachment-after")]');
$this->assertEqual(count($result), 1, 'The attachment is rendered after the page view.');
// Disable the attachment_1 display.
$view->displayHandlers->get('attachment_1')->setOption('enabled', FALSE);
$view->save();
// Test that the before attachment is not displayed.
$this->drupalGet('/test-attached-disabled');
$result = $this->xpath('//div[contains(@class, "view-content")]');
$this->assertEqual(count($result), 2, 'The page view and only one attachment are rendered.');
$result = $this->xpath('//div[contains(@class, "attachment-before")]');
$this->assertEqual(count($result), 0, 'The attachment_1 is not rendered.');
// Disable the attachment_2 display.
$view->displayHandlers->get('attachment_2')->setOption('enabled', FALSE);
$view->save();
// Test that the after attachment is not displayed.
$this->drupalGet('/test-attached-disabled');
$result = $this->xpath('//div[contains(@class, "view-content")]');
$this->assertEqual(count($result), 1, 'The page view is rendered without attachments.');
$result = $this->xpath('//div[contains(@class, "attachment-after")]');
$this->assertEqual(count($result), 0, 'The attachment_2 is not rendered.');
}
}
@@ -0,0 +1,254 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
/**
* Tests the entity reference display plugin.
*
* @group views
*
* @see \Drupal\views\Plugin\views\display\EntityReference
*/
class DisplayEntityReferenceTest extends ViewTestBase {
use EntityReferenceTestTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_display_entity_reference'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['entity_test', 'field', 'views_ui'];
/**
* The used field name in the test.
*
* @var string
*/
protected $fieldName;
/**
* The used entity reference field name in the test.
*
* @var string
*/
protected $entityRefFieldName;
/**
* The field storage.
*
* @var \Drupal\field\Entity\FieldStorageConfig
*/
protected $fieldStorage;
/**
* The field config.
*
* @var \Drupal\field\Entity\FieldConfig
*/
protected $field;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->drupalLogin($this->drupalCreateUser(['administer views']));
// Create the text field.
$this->fieldName = 'field_test_entity_ref_display';
$this->fieldStorage = FieldStorageConfig::create([
'field_name' => $this->fieldName,
'entity_type' => 'entity_test',
'type' => 'text',
]);
$this->fieldStorage->save();
// Create an instance of the text field on the content type.
$this->field = FieldConfig::create([
'field_storage' => $this->fieldStorage,
'bundle' => 'entity_test',
]);
$this->field->save();
// Add an entity reference field to reference the same base table.
$this->entityRefFieldName = 'field_test_entity_ref_entity_ref';
$this->createEntityReferenceField('entity_test', 'entity_test', $this->entityRefFieldName, NULL, 'entity_test');
// Create some entities to search. Add a common string to the name and
// the text field in two entities so we can test that we can search in both.
for ($i = 0; $i < 5; $i++) {
EntityTest::create([
'bundle' => 'entity_test',
'name' => 'name' . $i,
$this->fieldName => 'text',
])->save();
EntityTest::create([
'bundle' => 'entity_test',
'name' => 'name',
$this->fieldName => 'text' . $i,
])->save();
}
EntityTest::create([
'bundle' => 'entity_test',
'name' => 'name',
$this->fieldName => 'tex',
])->save();
EntityTest::create([
'bundle' => 'entity_test',
'name' => 'name',
$this->fieldName => 'TEX',
])->save();
EntityTest::create([
'bundle' => 'entity_test',
'name' => 'name',
$this->fieldName => 'sometext',
])->save();
}
/**
* Tests the entity reference display plugin.
*/
public function testEntityReferenceDisplay() {
// Add the new field to the fields.
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_display_entity_reference/default/field', ['name[entity_test__' . $this->fieldName . '.' . $this->fieldName . ']' => TRUE], t('Add and configure fields'));
$this->drupalPostForm(NULL, [], t('Apply'));
// Test that the right fields are shown on the display settings form.
$this->drupalGet('admin/structure/views/nojs/display/test_display_entity_reference/entity_reference_1/style_options');
$this->assertText('Test entity: Name');
$this->assertText('Test entity: ' . $this->field->label());
// Add the new field to the search fields.
$this->drupalPostForm(NULL, ['style_options[search_fields][' . $this->fieldName . ']' => $this->fieldName], t('Apply'));
$this->drupalPostForm(NULL, [], t('Save'));
$view = Views::getView('test_display_entity_reference');
$view->setDisplay('entity_reference_1');
// Add the required settings to test a search operation.
$options = [
'match' => '1',
'match_operator' => 'CONTAINS',
'limit' => 0,
'ids' => NULL,
];
$view->display_handler->setOption('entity_reference_options', $options);
$this->executeView($view);
// Test that we have searched in both fields.
$this->assertEqual(count($view->result), 2, 'Search returned two rows');
$view->destroy();
// Test the 'CONTAINS' match_operator.
$view = Views::getView('test_display_entity_reference');
$view->setDisplay('entity_reference_1');
$options = [
'match' => 'tex',
'match_operator' => 'CONTAINS',
'limit' => 0,
'ids' => NULL,
];
$view->display_handler->setOption('entity_reference_options', $options);
$this->executeView($view);
$this->assertEqual(count($view->result), 13, 'Search returned thirteen rows');
$view->destroy();
// Test the 'STARTS_WITH' match_operator.
$view = Views::getView('test_display_entity_reference');
$view->setDisplay('entity_reference_1');
$options = [
'match' => 'tex',
'match_operator' => 'STARTS_WITH',
'limit' => 0,
'ids' => NULL,
];
$view->display_handler->setOption('entity_reference_options', $options);
$this->executeView($view);
$this->assertEqual(count($view->result), 12, 'Search returned twelve rows');
$view->destroy();
// Test the '=' match_operator.
$view = Views::getView('test_display_entity_reference');
$view->setDisplay('entity_reference_1');
$options = [
'match' => 'tex',
'match_operator' => '=',
'limit' => 0,
'ids' => NULL,
];
$view->display_handler->setOption('entity_reference_options', $options);
$this->executeView($view);
$this->assertEqual(count($view->result), 2, 'Search returned two rows');
$view->destroy();
// Add a relationship and a field using that relationship.
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_display_entity_reference/default/relationship', ['name[entity_test.user_id]' => TRUE], t('Add and configure relationships'));
$this->drupalPostForm(NULL, [], t('Apply'));
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_display_entity_reference/default/field', ['name[users_field_data.uid]' => TRUE], t('Add and configure fields'));
$this->drupalPostForm(NULL, [], t('Apply'));
// Add the new field to the search fields.
$this->drupalPostForm('admin/structure/views/nojs/display/test_display_entity_reference/entity_reference_1/style_options', ['style_options[search_fields][uid]' => 'uid'], t('Apply'));
$this->drupalPostForm(NULL, [], t('Save'));
// Test that the search still works with the ralated field.
$view = Views::getView('test_display_entity_reference');
$view->setDisplay('entity_reference_1');
// Add the required settings to test a search operation.
$options = [
'match' => '2',
'match_operator' => 'CONTAINS',
'limit' => 0,
'ids' => NULL,
];
$view->display_handler->setOption('entity_reference_options', $options);
$this->executeView($view);
// Run validation when using a relationship to the same base table.
$this->assertEqual(count($view->result), 2, 'Search returned two rows');
$view->destroy();
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_display_entity_reference/default/relationship', ['name[entity_test__field_test_entity_ref_entity_ref.field_test_entity_ref_entity_ref]' => TRUE], t('Add and configure relationships'));
$this->drupalPostForm(NULL, [], t('Apply'));
$this->drupalPostForm(NULL, [], t('Save'));
// Test that the search still works with the related field.
$view = Views::getView('test_display_entity_reference');
$view->setDisplay('entity_reference_1');
// Add IDs to trigger validation.
$options = [
'match' => '1',
'match_operator' => 'CONTAINS',
'limit' => 0,
'ids' => [1, 2],
];
$view->display_handler->setOption('entity_reference_options', $options);
$this->executeView($view);
$this->assertEqual(count($view->result), 2, 'Search returned two rows');
}
}
@@ -0,0 +1,173 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
/**
* Tests the views page display plugin as webtest.
*
* @group views
*/
class DisplayPageWebTest extends ViewTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_page_display', 'test_page_display_arguments', 'test_page_display_menu', 'test_page_display_path'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['menu_ui', 'block', 'views_ui'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
$this->drupalPlaceBlock('local_tasks_block');
}
/**
* Tests arguments.
*/
public function testArguments() {
$this->drupalGet('test_route_without_arguments');
$this->assertResponse(200);
$result = $this->xpath('//span[@class="field-content"]');
$this->assertEqual(count($result), 5, 'All entries was returned');
$this->drupalGet('test_route_without_arguments/1');
$this->assertResponse(404);
$this->drupalGet('test_route_with_argument/1');
$this->assertResponse(200);
$this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url']);
$result = $this->xpath('//span[@class="field-content"]');
$this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.');
$this->assertEqual($result[0]->getText(), 1, 'The passed ID was returned.');
$this->drupalGet('test_route_with_suffix/1/suffix');
$this->assertResponse(200);
$result = $this->xpath('//span[@class="field-content"]');
$this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.');
$this->assertEqual($result[0]->getText(), 1, 'The passed ID was returned.');
$this->drupalGet('test_route_with_suffix_and_argument/1/suffix/2');
$this->assertResponse(200);
$result = $this->xpath('//span[@class="field-content"]');
$this->assertEqual(count($result), 0, 'No result was returned.');
$this->drupalGet('test_route_with_suffix_and_argument/1/suffix/1');
$this->assertResponse(200);
$result = $this->xpath('//span[@class="field-content"]');
$this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.');
$this->assertEqual($result[0]->getText(), 1, 'The passed ID was returned.');
$this->drupalGet('test_route_with_long_argument/1');
$this->assertResponse(200);
$result = $this->xpath('//span[@class="field-content"]');
$this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.');
$this->assertEqual($result[0]->getText(), 1, 'The passed ID was returned.');
}
/**
* Tests menu settings of page displays.
*/
public function testPageDisplayMenu() {
// Check local tasks.
$this->drupalGet('test_page_display_menu');
$this->assertResponse(200);
$element = $this->xpath('//ul[contains(@class, :ul_class)]//a[contains(@class, :a_class)]/child::text()', [
':ul_class' => 'tabs primary',
':a_class' => 'is-active',
]);
$this->assertEqual($element[0]->getText(), t('Test default tab'));
$this->assertTitle(t('Test default page | Drupal'));
$this->drupalGet('test_page_display_menu/default');
$this->assertResponse(404);
$this->drupalGet('test_page_display_menu/local');
$this->assertResponse(200);
$element = $this->xpath('//ul[contains(@class, :ul_class)]//a[contains(@class, :a_class)]/child::text()', [
':ul_class' => 'tabs primary',
':a_class' => 'is-active',
]);
$this->assertEqual($element[0]->getText(), t('Test local tab'));
$this->assertTitle(t('Test local page | Drupal'));
// Check an ordinary menu link.
$admin_user = $this->drupalCreateUser(['administer menu']);
$this->drupalLogin($admin_user);
$this->drupalPlaceBlock('system_menu_block:tools');
$this->drupalGet('<front>');
$menu_link = $this->cssSelect('nav.block-menu ul.menu a');
$this->assertEqual($menu_link[0]->getText(), 'Test menu link');
// Update the menu link.
$this->drupalPostForm("admin/structure/menu/link/views_view:views.test_page_display_menu.page_3/edit", [
'title' => 'New title',
], t('Save'));
$this->drupalGet('<front>');
$menu_link = $this->cssSelect('nav.block-menu ul.menu a');
$this->assertEqual($menu_link[0]->getText(), 'New title');
}
/**
* Tests the title is not displayed in the output.
*/
public function testTitleOutput() {
$this->drupalGet('test_page_display_200');
$view = Views::getView('test_page_display');
$xpath = $this->cssSelect('div.view:contains("' . $view->getTitle() . '")');
$this->assertFalse($xpath, 'The view title was not displayed in the view markup.');
}
/**
* Tests the views page path functionality.
*/
public function testPagePaths() {
$this->drupalLogin($this->rootUser);
$this->assertPagePath('0');
$this->assertPagePath('9999');
}
/**
* Tests that we can successfully change a view page display path.
*
* @param string $path
* Path that will be set as the view page display path.
*
* @return bool
* Assertion result.
*/
public function assertPagePath($path) {
$view = Views::getView('test_page_display_path');
$view->initDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('path', $path);
$view->save();
$this->container->get('router.builder')->rebuild();
// Check if we successfully changed the path.
$this->drupalGet($path);
$success = $this->assertResponse(200);
// Check if we don't get any error on the view edit page.
$this->drupalGet('admin/structure/views/view/test_page_display_path');
return $success && $this->assertResponse(200);
}
}
@@ -0,0 +1,364 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
use Drupal\views_test_data\Plugin\views\display\DisplayTest as DisplayTestPlugin;
/**
* Tests the basic display plugin.
*
* @group views
*/
class DisplayTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_filter_groups', 'test_get_attach_displays', 'test_view', 'test_display_more', 'test_display_invalid', 'test_display_empty', 'test_exposed_relationship_admin_ui'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['views_ui', 'node', 'block'];
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->enableViewsTestModule();
$this->adminUser = $this->drupalCreateUser(['administer views']);
$this->drupalLogin($this->adminUser);
// Create 10 nodes.
for ($i = 0; $i <= 10; $i++) {
$this->drupalCreateNode(['promote' => TRUE]);
}
}
/**
* Tests the display test plugin.
*
* @see \Drupal\views_test_data\Plugin\views\display\DisplayTest
*/
public function testDisplayPlugin() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$view = Views::getView('test_view');
// Add a new 'display_test' display and test it's there.
$view->storage->addDisplay('display_test');
$displays = $view->storage->get('display');
$this->assertTrue(isset($displays['display_test_1']), 'Added display has been assigned to "display_test_1"');
// Check the display options are like expected.
$options = [
'display_options' => [],
'display_plugin' => 'display_test',
'id' => 'display_test_1',
'display_title' => 'Display test',
'position' => 1,
];
$this->assertEqual($displays['display_test_1'], $options);
// Add another one to ensure that position is counted up.
$view->storage->addDisplay('display_test');
$displays = $view->storage->get('display');
$options = [
'display_options' => [],
'display_plugin' => 'display_test',
'id' => 'display_test_2',
'display_title' => 'Display test 2',
'position' => 2,
];
$this->assertEqual($displays['display_test_2'], $options);
// Move the second display before the first one in order to test custom
// sorting.
$displays['display_test_1']['position'] = 2;
$displays['display_test_2']['position'] = 1;
$view->storage->set('display', $displays);
$view->save();
$view->setDisplay('display_test_1');
$this->assertTrue($view->display_handler instanceof DisplayTestPlugin, 'The correct display handler instance is on the view object.');
// Check the test option.
$this->assertIdentical($view->display_handler->getOption('test_option'), '');
$style = $view->display_handler->getOption('style');
$style['type'] = 'test_style';
$view->display_handler->setOption('style', $style);
$view->initDisplay();
$view->initStyle();
$view->style_plugin->setUsesRowPlugin(FALSE);
$output = $view->preview();
$output = $renderer->renderRoot($output);
$this->assertTrue(strpos($output, '<h1></h1>') !== FALSE, 'An empty value for test_option found in output.');
// Change this option and check the title of out output.
$view->display_handler->overrideOption('test_option', 'Test option title');
$view->save();
$output = $view->preview();
$output = $renderer->renderRoot($output);
// Test we have our custom <h1> tag in the output of the view.
$this->assertTrue(strpos($output, '<h1>Test option title</h1>') !== FALSE, 'The test_option value found in display output title.');
// Test that the display category/summary is in the UI.
$this->drupalGet('admin/structure/views/view/test_view/edit/display_test_1');
$this->assertText('Display test settings');
// Ensure that the order is as expected.
$result = $this->xpath('//ul[@id="views-display-menu-tabs"]/li/a/child::text()');
$this->assertEqual($result[0]->getText(), 'Display test 2');
$this->assertEqual($result[1]->getText(), 'Display test');
$this->clickLink('Test option title');
$test_option = $this->randomString();
$this->drupalPostForm(NULL, ['test_option' => $test_option], t('Apply'));
// Check the new value has been saved by checking the UI summary text.
$this->drupalGet('admin/structure/views/view/test_view/edit/display_test_1');
$this->assertLink($test_option);
// Test the enable/disable status of a display.
$view->display_handler->setOption('enabled', FALSE);
$this->assertFalse($view->display_handler->isEnabled(), 'Make sure that isEnabled returns FALSE on a disabled display.');
$view->display_handler->setOption('enabled', TRUE);
$this->assertTrue($view->display_handler->isEnabled(), 'Make sure that isEnabled returns TRUE on a disabled display.');
}
/**
* Tests the overriding of filter_groups.
*/
public function testFilterGroupsOverriding() {
$view = Views::getView('test_filter_groups');
$view->initDisplay();
// mark is as overridden, yes FALSE, means overridden.
$view->displayHandlers->get('page')->setOverride('filter_groups', FALSE);
$this->assertFalse($view->displayHandlers->get('page')->isDefaulted('filter_groups'), "Make sure that 'filter_groups' is marked as overridden.");
$this->assertFalse($view->displayHandlers->get('page')->isDefaulted('filters'), "Make sure that 'filters'' is marked as overridden.");
}
/**
* Tests the getAttachedDisplays method.
*/
public function testGetAttachedDisplays() {
$view = Views::getView('test_get_attach_displays');
// Both the feed_1 and the feed_2 display are attached to the page display.
$view->setDisplay('page_1');
$this->assertEqual($view->display_handler->getAttachedDisplays(), ['feed_1', 'feed_2']);
$view->setDisplay('feed_1');
$this->assertEqual($view->display_handler->getAttachedDisplays(), []);
}
/**
* Tests the readmore validation.
*/
public function testReadMoreNoDisplay() {
$view = Views::getView('test_display_more');
// Confirm that the view validates when there is a page display.
$errors = $view->validate();
$this->assertTrue(empty($errors), 'More link validation has no errors.');
// Confirm that the view does not validate when the page display is disabled.
$view->setDisplay('page_1');
$view->display_handler->setOption('enabled', FALSE);
$view->setDisplay('default');
$errors = $view->validate();
$this->assertTrue(!empty($errors), 'More link validation has some errors.');
$this->assertEqual($errors['default'][0], 'Display "Master" uses a "more" link but there are no displays it can link to. You need to specify a custom URL.', 'More link validation has the right error.');
// Confirm that the view does not validate when the page display does not exist.
$view = Views::getView('test_view');
$view->setDisplay('default');
$view->display_handler->setOption('use_more', 1);
$errors = $view->validate();
$this->assertTrue(!empty($errors), 'More link validation has some errors.');
$this->assertEqual($errors['default'][0], 'Display "Master" uses a "more" link but there are no displays it can link to. You need to specify a custom URL.', 'More link validation has the right error.');
}
/**
* Tests invalid display plugins.
*/
public function testInvalidDisplayPlugins() {
$this->drupalGet('test_display_invalid');
$this->assertResponse(200);
// Change the page plugin id to an invalid one. Bypass the entity system
// so no menu rebuild was executed (so the path is still available).
$config = $this->config('views.view.test_display_invalid');
$config->set('display.page_1.display_plugin', 'invalid');
$config->save();
$this->drupalGet('test_display_invalid');
$this->assertResponse(200);
$this->assertText('The &quot;invalid&quot; plugin does not exist.');
// Rebuild the router, and ensure that the path is not accessible anymore.
views_invalidate_cache();
\Drupal::service('router.builder')->rebuildIfNeeded();
$this->drupalGet('test_display_invalid');
$this->assertResponse(404);
// Change the display plugin ID back to the correct ID.
$config = $this->config('views.view.test_display_invalid');
$config->set('display.page_1.display_plugin', 'page');
$config->save();
// Place the block display.
$block = $this->drupalPlaceBlock('views_block:test_display_invalid-block_1', ['label' => 'Invalid display']);
$this->drupalGet('<front>');
$this->assertResponse(200);
$result = $this->xpath('//div[@id = :id]', [':id' => 'block-' . $block->id()]);
$this->assertEquals(1, count($result));
// Change the block plugin ID to an invalid one.
$config = $this->config('views.view.test_display_invalid');
$config->set('display.block_1.display_plugin', 'invalid');
$config->save();
// Test the page is still displayed, the block not present, and has the
// plugin warning message.
$this->drupalGet('<front>');
$this->assertResponse(200);
$this->assertText('The &quot;invalid&quot; plugin does not exist.');
$result = $this->xpath('//div[@id = :id]', [':id' => 'block-' . $block->id()]);
$this->assertEquals(0, count($result));
}
/**
* Tests display validation when a required relationship is missing.
*/
public function testMissingRelationship() {
$view = Views::getView('test_exposed_relationship_admin_ui');
// Remove the relationship that is not used by other handlers.
$view->removeHandler('default', 'relationship', 'uid_1');
$errors = $view->validate();
// Check that no error message is shown.
$this->assertTrue(empty($errors['default']), 'No errors found when removing unused relationship.');
// Unset cached relationships (see DisplayPluginBase::getHandlers())
unset($view->display_handler->handlers['relationship']);
// Remove the relationship used by other handlers.
$view->removeHandler('default', 'relationship', 'uid');
// Validate display
$errors = $view->validate();
// Check that the error messages are shown.
$this->assertTrue(count($errors['default']) == 2, 'Error messages found for required relationship');
$this->assertEqual($errors['default'][0], t('The %handler_type %handler uses a relationship that has been removed.', ['%handler_type' => 'field', '%handler' => 'User: Last login']));
$this->assertEqual($errors['default'][1], t('The %handler_type %handler uses a relationship that has been removed.', ['%handler_type' => 'field', '%handler' => 'User: Created']));
}
/**
* Tests the outputIsEmpty method on the display.
*/
public function testOutputIsEmpty() {
$view = Views::getView('test_display_empty');
$this->executeView($view);
$this->assertTrue(count($view->result) > 0, 'Ensure the result of the view is not empty.');
$this->assertFalse($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as not empty.');
$view->destroy();
// Add a filter, so the view result is empty.
$view->setDisplay('default');
$item = [
'table' => 'views_test_data',
'field' => 'id',
'id' => 'id',
'value' => ['value' => 7297]
];
$view->setHandler('default', 'filter', 'id', $item);
$this->executeView($view);
$this->assertFalse(count($view->result), 'Ensure the result of the view is empty.');
$this->assertFalse($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as not empty, because the empty text still appears.');
$view->destroy();
// Remove the empty area, but mark the header area to still appear.
$view->removeHandler('default', 'empty', 'area');
$item = $view->getHandler('default', 'header', 'area');
$item['empty'] = TRUE;
$view->setHandler('default', 'header', 'area', $item);
$this->executeView($view);
$this->assertFalse(count($view->result), 'Ensure the result of the view is empty.');
$this->assertFalse($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as not empty, because the header text still appears.');
$view->destroy();
// Hide the header on empty results.
$item = $view->getHandler('default', 'header', 'area');
$item['empty'] = FALSE;
$view->setHandler('default', 'header', 'area', $item);
$this->executeView($view);
$this->assertFalse(count($view->result), 'Ensure the result of the view is empty.');
$this->assertTrue($view->display_handler->outputIsEmpty(), 'Ensure the view output is marked as empty.');
}
/**
* Test translation rendering settings based on entity translatability.
*/
public function testTranslationSetting() {
\Drupal::service('module_installer')->install(['file']);
\Drupal::service('router.builder')->rebuild();
// By default there should be no language settings.
$this->checkTranslationSetting();
\Drupal::service('module_installer')->install(['language']);
// Enabling the language module should not make a difference.
$this->checkTranslationSetting();
// Making the site multilingual should let translatable entity types support
// translation rendering.
ConfigurableLanguage::createFromLangcode('it')->save();
$this->checkTranslationSetting(TRUE);
}
/**
* Asserts a node and a file based view for the translation setting.
*
* The file based view should never expose that setting. The node based view
* should if the site is multilingual.
*
* @param bool $expected_node_translatability
* Whether the node based view should be expected to support translation
* settings.
*/
protected function checkTranslationSetting($expected_node_translatability = FALSE) {
$not_supported_text = 'The view is not based on a translatable entity type or the site is not multilingual.';
$supported_text = 'All content that supports translations will be displayed in the selected language.';
$this->drupalGet('admin/structure/views/nojs/display/content/page_1/rendering_language');
if ($expected_node_translatability) {
$this->assertNoText($not_supported_text);
$this->assertText($supported_text);
}
else {
$this->assertText($not_supported_text);
$this->assertNoText($supported_text);
}
$this->drupalGet('admin/structure/views/nojs/display/files/page_1/rendering_language');
$this->assertText($not_supported_text);
$this->assertNoText($supported_text);
}
}
@@ -0,0 +1,403 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\Component\Utility\Html;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\ViewExecutable;
use Drupal\views\Views;
use Drupal\views\Entity\View;
/**
* Tests exposed forms functionality.
*
* @group views
*/
class ExposedFormTest extends ViewTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_exposed_form_buttons', 'test_exposed_block', 'test_exposed_form_sort_items_per_page'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'views_ui', 'block', 'entity_test'];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
$this->drupalCreateContentType(['type' => 'article']);
// Create some random nodes.
for ($i = 0; $i < 5; $i++) {
$this->drupalCreateNode(['type' => 'article']);
}
}
/**
* Tests the submit button.
*/
public function testSubmitButton() {
// Test the submit button value defaults to 'Apply'.
$this->drupalGet('test_exposed_form_buttons');
$this->assertResponse(200);
$this->helperButtonHasLabel('edit-submit-test-exposed-form-buttons', t('Apply'));
// Rename the label of the submit button.
$view = Views::getView('test_exposed_form_buttons');
$view->setDisplay();
$exposed_form = $view->display_handler->getOption('exposed_form');
$exposed_form['options']['submit_button'] = $expected_label = $this->randomMachineName();
$view->display_handler->setOption('exposed_form', $exposed_form);
$view->save();
// Make sure the submit button label changed.
$this->drupalGet('test_exposed_form_buttons');
$this->helperButtonHasLabel('edit-submit-test-exposed-form-buttons', $expected_label);
// Make sure an empty label uses the default 'Apply' button value too.
$view = Views::getView('test_exposed_form_buttons');
$view->setDisplay();
$exposed_form = $view->display_handler->getOption('exposed_form');
$exposed_form['options']['submit_button'] = '';
$view->display_handler->setOption('exposed_form', $exposed_form);
$view->save();
// Make sure the submit button label shows 'Apply'.
$this->drupalGet('test_exposed_form_buttons');
$this->helperButtonHasLabel('edit-submit-test-exposed-form-buttons', t('Apply'));
}
/**
* Tests the exposed form with a non-standard identifier.
*/
public function testExposedIdentifier() {
// Alter the identifier of the filter to a random string.
$view = Views::getView('test_exposed_form_buttons');
$view->setDisplay();
$identifier = 'new_identifier';
$view->displayHandlers->get('default')->overrideOption('filters', [
'type' => [
'exposed' => TRUE,
'field' => 'type',
'id' => 'type',
'table' => 'node_field_data',
'plugin_id' => 'in_operator',
'entity_type' => 'node',
'entity_field' => 'type',
'expose' => [
'identifier' => $identifier,
'label' => 'Content: Type',
'operator_id' => 'type_op',
'reduce' => FALSE,
'description' => 'Exposed overridden description'
],
]
]);
$view->save();
$this->drupalGet('test_exposed_form_buttons', ['query' => [$identifier => 'article']]);
$this->assertFieldById(Html::getId('edit-' . $identifier), 'article', "Article type filter set with new identifier.");
// Alter the identifier of the filter to a random string containing
// restricted characters.
$view = Views::getView('test_exposed_form_buttons');
$view->setDisplay();
$identifier = 'bad identifier';
$view->displayHandlers->get('default')->overrideOption('filters', [
'type' => [
'exposed' => TRUE,
'field' => 'type',
'id' => 'type',
'table' => 'node_field_data',
'plugin_id' => 'in_operator',
'entity_type' => 'node',
'entity_field' => 'type',
'expose' => [
'identifier' => $identifier,
'label' => 'Content: Type',
'operator_id' => 'type_op',
'reduce' => FALSE,
'description' => 'Exposed overridden description'
],
]
]);
$this->executeView($view);
$errors = $view->validate();
$expected = [
'default' => ['This identifier has illegal characters.'],
'page_1' => ['This identifier has illegal characters.'],
];
$this->assertEqual($errors, $expected);
}
/**
* Tests whether the reset button works on an exposed form.
*/
public function testResetButton() {
// Test the button is hidden when there is no exposed input.
$this->drupalGet('test_exposed_form_buttons');
$this->assertNoField('edit-reset');
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article']]);
// Test that the type has been set.
$this->assertFieldById('edit-type', 'article', 'Article type filter set.');
// Test the reset works.
$this->drupalGet('test_exposed_form_buttons', ['query' => ['op' => 'Reset']]);
$this->assertResponse(200);
// Test the type has been reset.
$this->assertFieldById('edit-type', 'All', 'Article type filter has been reset.');
// Test the button is hidden after reset.
$this->assertNoField('edit-reset');
// Test the reset works with type set.
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article', 'op' => 'Reset']]);
$this->assertResponse(200);
$this->assertFieldById('edit-type', 'All', 'Article type filter has been reset.');
// Test the button is hidden after reset.
$this->assertNoField('edit-reset');
// Rename the label of the reset button.
$view = Views::getView('test_exposed_form_buttons');
$view->setDisplay();
$exposed_form = $view->display_handler->getOption('exposed_form');
$exposed_form['options']['reset_button_label'] = $expected_label = $this->randomMachineName();
$exposed_form['options']['reset_button'] = TRUE;
$view->display_handler->setOption('exposed_form', $exposed_form);
$view->save();
// Look whether the reset button label changed.
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article']]);
$this->assertResponse(200);
$this->helperButtonHasLabel('edit-reset', $expected_label);
}
/**
* Tests overriding the default render option with checkboxes.
*/
public function testExposedFormRenderCheckboxes() {
// Make sure we have at least two options for node type.
$this->drupalCreateContentType(['type' => 'page']);
$this->drupalCreateNode(['type' => 'page']);
// Use a test theme to convert multi-select elements into checkboxes.
\Drupal::service('theme_handler')->install(['views_test_checkboxes_theme']);
$this->config('system.theme')
->set('default', 'views_test_checkboxes_theme')
->save();
// Set the "type" filter to multi-select.
$view = Views::getView('test_exposed_form_buttons');
$filter = $view->getHandler('page_1', 'filter', 'type');
$filter['expose']['multiple'] = TRUE;
$view->setHandler('page_1', 'filter', 'type', $filter);
// Only display 5 items per page so we can test that paging works.
$display = &$view->storage->getDisplay('default');
$display['display_options']['pager']['options']['items_per_page'] = 5;
$view->save();
$this->drupalGet('test_exposed_form_buttons');
$actual = $this->xpath('//form//input[@type="checkbox" and @name="type[article]"]');
$this->assertEqual(count($actual), 1, 'Article option renders as a checkbox.');
$actual = $this->xpath('//form//input[@type="checkbox" and @name="type[page]"]');
$this->assertEqual(count($actual), 1, 'Page option renders as a checkbox');
// Ensure that all results are displayed.
$rows = $this->xpath("//div[contains(@class, 'views-row')]");
$this->assertEqual(count($rows), 5, '5 rows are displayed by default on the first page when no options are checked.');
$this->clickLink('Page 2');
$rows = $this->xpath("//div[contains(@class, 'views-row')]");
$this->assertEqual(count($rows), 1, '1 row is displayed by default on the second page when no options are checked.');
$this->assertNoText('An illegal choice has been detected. Please contact the site administrator.');
}
/**
* Tests the exposed block functionality.
*/
public function testExposedBlock() {
$this->drupalCreateContentType(['type' => 'page']);
$view = Views::getView('test_exposed_block');
$view->setDisplay('page_1');
$block = $this->drupalPlaceBlock('views_exposed_filter_block:test_exposed_block-page_1');
$this->drupalGet('test_exposed_block');
// Test there is an exposed form in a block.
$xpath = $this->buildXPathQuery('//div[@id=:id]/form/@id', [':id' => Html::getUniqueId('block-' . $block->id())]);
$result = $this->xpath($xpath);
$this->assertEquals(1, count($result));
// Test there is not an exposed form in the view page content area.
$xpath = $this->buildXPathQuery('//div[@class="view-content"]/form/@id', [':id' => Html::getUniqueId('block-' . $block->id())]);
$this->assertNoFieldByXpath($xpath, $this->getExpectedExposedFormId($view), 'No exposed form found in views content region.');
// Test there is only one views exposed form on the page.
$elements = $this->xpath('//form[@id=:id]', [':id' => $this->getExpectedExposedFormId($view)]);
$this->assertEqual(count($elements), 1, 'One exposed form block found.');
// Test that the correct option is selected after form submission.
$this->assertCacheContext('url');
$this->assertOptionSelected('edit-type', 'All');
foreach (['All', 'article', 'page'] as $argument) {
$this->drupalGet('test_exposed_block', ['query' => ['type' => $argument]]);
$this->assertCacheContext('url');
$this->assertOptionSelected('edit-type', $argument);
}
}
/**
* Test the input required exposed form type.
*/
public function testInputRequired() {
$view = View::load('test_exposed_form_buttons');
$display = &$view->getDisplay('default');
$display['display_options']['exposed_form']['type'] = 'input_required';
$view->save();
$this->drupalGet('test_exposed_form_buttons');
$this->assertResponse(200);
$this->helperButtonHasLabel('edit-submit-test-exposed-form-buttons', t('Apply'));
// Ensure that no results are displayed.
$rows = $this->xpath("//div[contains(@class, 'views-row')]");
$this->assertEqual(count($rows), 0, 'No rows are displayed by default when no input is provided.');
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article']]);
// Ensure that results are displayed.
$rows = $this->xpath("//div[contains(@class, 'views-row')]");
$this->assertEqual(count($rows), 5, 'All rows are displayed by default when input is provided.');
}
/**
* Test the "on demand text" for the input required exposed form type.
*/
public function testTextInputRequired() {
$view = Views::getView('test_exposed_form_buttons');
$display = &$view->storage->getDisplay('default');
$display['display_options']['exposed_form']['type'] = 'input_required';
// Set up the "on demand text".
// @see https://www.drupal.org/node/535868
$on_demand_text = 'Select any filter and click Apply to see results.';
$display['display_options']['exposed_form']['options']['text_input_required'] = $on_demand_text;
$display['display_options']['exposed_form']['options']['text_input_required_format'] = filter_default_format();
$view->save();
// Ensure that the "on demand text" is displayed when no exposed filters are
// applied.
$this->drupalGet('test_exposed_form_buttons');
$this->assertText('Select any filter and click Apply to see results.');
// Ensure that the "on demand text" is not displayed when an exposed filter
// is applied.
$this->drupalGet('test_exposed_form_buttons', ['query' => ['type' => 'article']]);
$this->assertNoText($on_demand_text);
}
/**
* Tests exposed forms with exposed sort and items per page.
*/
public function testExposedSortAndItemsPerPage() {
for ($i = 0; $i < 50; $i++) {
$entity = EntityTest::create([
]);
$entity->save();
}
$contexts = [
'languages:language_interface',
'entity_test_view_grants',
'theme',
'url.query_args',
'languages:language_content'
];
$this->drupalGet('test_exposed_form_sort_items_per_page');
$this->assertCacheContexts($contexts);
$this->assertIds(range(1, 10, 1));
$this->drupalGet('test_exposed_form_sort_items_per_page', ['query' => ['sort_order' => 'DESC']]);
$this->assertCacheContexts($contexts);
$this->assertIds(range(50, 41, 1));
$this->drupalGet('test_exposed_form_sort_items_per_page', ['query' => ['sort_order' => 'DESC', 'items_per_page' => 25]]);
$this->assertCacheContexts($contexts);
$this->assertIds(range(50, 26, 1));
$this->drupalGet('test_exposed_form_sort_items_per_page', ['query' => ['sort_order' => 'DESC', 'items_per_page' => 25, 'offset' => 10]]);
$this->assertCacheContexts($contexts);
$this->assertIds(range(40, 16, 1));
}
/**
* Checks whether the specified ids are the ones displayed in the view output.
*
* @param int[] $ids
* The ids to check.
*
* @return bool
* TRUE if ids match, FALSE otherwise.
*/
protected function assertIds(array $ids) {
$elements = $this->cssSelect('div.view-test-exposed-form-sort-items-per-page div.views-row span.field-content');
$actual_ids = [];
foreach ($elements as $element) {
$actual_ids[] = (int) $element->getText();
}
return $this->assertIdentical($ids, $actual_ids);
}
/**
* Returns a views exposed form ID.
*
* @param \Drupal\views\ViewExecutable $view
* The view to create an ID for.
*
* @return string
* The form ID.
*/
protected function getExpectedExposedFormId(ViewExecutable $view) {
return Html::cleanCssIdentifier('views-exposed-form-' . $view->storage->id() . '-' . $view->current_display);
}
/**
* Tests a view which is rendered after a form with a validation error.
*/
public function testFormErrorWithExposedForm() {
$this->drupalGet('views_test_data_error_form_page');
$this->assertResponse(200);
$form = $this->cssSelect('form.views-exposed-form');
$this->assertTrue($form, 'The exposed form element was found.');
$this->assertRaw(t('Apply'), 'Ensure the exposed form is rendered before submitting the normal form.');
$this->assertRaw('<div class="views-row">', 'Views result shown.');
$this->drupalPostForm(NULL, [], t('Submit'));
$this->assertResponse(200);
$form = $this->cssSelect('form.views-exposed-form');
$this->assertTrue($form, 'The exposed form element was found.');
$this->assertRaw(t('Apply'), 'Ensure the exposed form is rendered after submitting the normal form.');
$this->assertRaw('<div class="views-row">', 'Views result shown.');
}
}
@@ -0,0 +1,167 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
use Drupal\views_test_data\Plugin\views\filter\FilterTest as FilterPlugin;
/**
* Tests general filter plugin functionality.
*
* @group views
* @see \Drupal\views\Plugin\views\filter\FilterPluginBase
*/
class FilterTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_filter', 'test_filter_in_operator_ui'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['views_ui', 'node'];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
$this->adminUser = $this->drupalCreateUser(['administer views']);
$this->drupalLogin($this->adminUser);
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Page']);
}
/**
* {@inheritdoc}
*/
protected function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['name']['filter']['id'] = 'test_filter';
return $data;
}
/**
* Test query of the row plugin.
*/
public function testFilterQuery() {
// Check that we can find the test filter plugin.
$plugin = $this->container->get('plugin.manager.views.filter')->createInstance('test_filter');
$this->assertTrue($plugin instanceof FilterPlugin, 'Test filter plugin found.');
$view = Views::getView('test_filter');
$view->initDisplay();
// Change the filtering.
$view->displayHandlers->get('default')->overrideOption('filters', [
'test_filter' => [
'id' => 'test_filter',
'table' => 'views_test_data',
'field' => 'name',
'operator' => '=',
'value' => 'John',
'group' => 0,
],
]);
$this->executeView($view);
// Make sure the query have where data.
$this->assertTrue(!empty($view->query->where));
// Check the data added.
$where = $view->query->where;
$this->assertIdentical($where[0]['conditions'][0]['field'], 'views_test_data.name', 'Where condition field matches');
$this->assertIdentical($where[0]['conditions'][0]['value'], 'John', 'Where condition value matches');
$this->assertIdentical($where[0]['conditions'][0]['operator'], '=', 'Where condition operator matches');
$this->executeView($view);
// Check that our operator and value match on the filter.
$this->assertIdentical($view->filter['test_filter']->operator, '=');
$this->assertIdentical($view->filter['test_filter']->value, 'John');
// Check that we have a single element, as a result of applying the '= John'
// filter.
$this->assertEqual(count($view->result), 1, format_string('Results were returned. @count results.', ['@count' => count($view->result)]));
$view->destroy();
$view->initDisplay();
// Change the filtering.
$view->displayHandlers->get('default')->overrideOption('filters', [
'test_filter' => [
'id' => 'test_filter',
'table' => 'views_test_data',
'field' => 'name',
'operator' => '<>',
'value' => 'John',
'group' => 0,
],
]);
$this->executeView($view);
// Check that our operator and value match on the filter.
$this->assertIdentical($view->filter['test_filter']->operator, '<>');
$this->assertIdentical($view->filter['test_filter']->value, 'John');
// Check if we have the other elements in the dataset, as a result of
// applying the '<> John' filter.
$this->assertEqual(count($view->result), 4, format_string('Results were returned. @count results.', ['@count' => count($view->result)]));
$view->destroy();
$view->initDisplay();
// Set the test_enable option to FALSE. The 'where' clause should not be
// added to the query.
$view->displayHandlers->get('default')->overrideOption('filters', [
'test_filter' => [
'id' => 'test_filter',
'table' => 'views_test_data',
'field' => 'name',
'operator' => '<>',
'value' => 'John',
'group' => 0,
// Disable this option, so nothing should be added to the query.
'test_enable' => FALSE,
],
]);
// Execute the view again.
$this->executeView($view);
// Check if we have all 5 results.
$this->assertEqual(count($view->result), 5, format_string('All @count results returned', ['@count' => count($view->displayHandlers)]));
}
/**
* Test no error message is displayed when all options are selected in an
* exposed filter.
*/
public function testInOperatorSelectAllOptions() {
$view = Views::getView('test_filter_in_operator_ui');
$row['row[type]'] = 'fields';
$this->drupalPostForm('admin/structure/views/nojs/display/test_filter_in_operator_ui/default/row', $row, t('Apply'));
$field['name[node_field_data.nid]'] = TRUE;
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_filter_in_operator_ui/default/field', $field, t('Add and configure fields'));
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_in_operator_ui/default/field/nid', [], t('Apply'));
$edit['options[value][all]'] = TRUE;
$edit['options[value][article]'] = TRUE;
$edit['options[value][page]'] = TRUE;
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_in_operator_ui/default/filter/type', $edit, t('Apply'));
$this->drupalPostForm('admin/structure/views/view/test_filter_in_operator_ui/edit/default', [], t('Save'));
$this->drupalPostForm(NULL, [], t('Update preview'));
$this->assertNoText('An illegal choice has been detected.');
}
}
@@ -0,0 +1,98 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\Tests\views\Functional\ViewTestBase;
/**
* Tests the menu links created in views.
*
* @group views
*/
class MenuLinkTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_menu_link'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['views', 'views_ui', 'user', 'node', 'menu_ui', 'block'];
/**
* A user with permission to administer views, menus and view content.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->enableViewsTestModule();
$this->adminUser = $this->drupalCreateUser(['administer views', 'administer menu']);
$this->drupalPlaceBlock('system_menu_block:main');
$this->drupalCreateContentType(['type' => 'page']);
}
/**
* Test that menu links using menu_link_content as parent are visible.
*/
public function testHierarchicalMenuLinkVisibility() {
$this->drupalLogin($this->adminUser);
$node = $this->drupalCreateNode(['type' => 'page']);
// Create a primary level menu link to the node.
$link = MenuLinkContent::create([
'title' => 'Primary level node',
'menu_name' => 'main',
'bundle' => 'menu_link_content',
'parent' => '',
'link' => [['uri' => 'entity:node/' . $node->id()]],
]);
$link->save();
$parent_menu_value = 'main:menu_link_content:' . $link->uuid();
// Alter the view's menu link in view page to use the menu link from the
// node as parent.
$this->drupalPostForm("admin/structure/views/nojs/display/test_menu_link/page_1/menu", [
'menu[type]' => 'normal',
'menu[title]' => 'Secondary level view page',
'menu[parent]' => $parent_menu_value,
], 'Apply');
// Save view which has pending changes.
$this->drupalPostForm(NULL, [], 'Save');
// Test if the node as parent menu item is selected in our views settings.
$this->drupalGet('admin/structure/views/nojs/display/test_menu_link/page_1/menu');
$this->assertOptionSelected('edit-menu-parent', $parent_menu_value);
$this->drupalGet('');
// Test if the primary menu item (node) is visible, and the secondary menu
// item (view) is hidden.
$this->assertText('Primary level node');
$this->assertNoText('Secondary level view page');
// Go to the node page and ensure that both the first and second level items
// are visible.
$this->drupalGet($node->urlInfo());
$this->assertText('Primary level node');
$this->assertText('Secondary level view page');
}
}
@@ -0,0 +1,135 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
/**
* Tests the mini pager plugin.
*
* @group views
* @see \Drupal\views\Plugin\views\pager\Mini
*/
class MiniPagerTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_mini_pager'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node'];
/**
* Nodes used by the test.
*
* @var array
*/
protected $nodes;
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->drupalCreateContentType(['type' => 'page']);
// Create a bunch of test nodes.
for ($i = 0; $i < 20; $i++) {
$this->nodes[] = $this->drupalCreateNode();
}
}
/**
* Tests the rendering of mini pagers.
*/
public function testMiniPagerRender() {
$this->drupalGet('test_mini_pager');
$this->assertText('›› test', 'The next link appears on the first page.');
$this->assertText('Page 1', 'The current page info shows the first page.');
$this->assertNoText('‹‹ test', 'The previous link does not appear on the first page.');
$this->assertText($this->nodes[0]->label());
$this->assertText($this->nodes[1]->label());
$this->assertText($this->nodes[2]->label());
$this->drupalGet('test_mini_pager', ['query' => ['page' => 1]]);
$this->assertText('‹‹ test', 'The previous link appears.');
$this->assertText('Page 2', 'The current page info shows the second page.');
$this->assertText('›› test', 'The next link appears.');
$this->assertText($this->nodes[3]->label());
$this->assertText($this->nodes[4]->label());
$this->assertText($this->nodes[5]->label());
$this->drupalGet('test_mini_pager', ['query' => ['page' => 6]]);
$this->assertNoText('›› test', 'The next link appears on the last page.');
$this->assertText('Page 7', 'The current page info shows the last page.');
$this->assertText('‹‹ test', 'The previous link does not appear on the last page.');
$this->assertText($this->nodes[18]->label());
$this->assertText($this->nodes[19]->label());
// Test @total value in result summary
$view = Views::getView('test_mini_pager');
$view->setDisplay('page_4');
$this->executeView($view);
$this->assertIdentical($view->get_total_rows, TRUE, 'The query was set to calculate the total number of rows.');
$this->assertEqual(count($this->nodes), $view->total_rows, 'The total row count is equal to the number of nodes.');
$this->drupalGet('test_mini_pager_total', ['query' => ['page' => 1]]);
$this->assertText('of ' . count($this->nodes), 'The first page shows the total row count.');
$this->drupalGet('test_mini_pager_total', ['query' => ['page' => 6]]);
$this->assertText('of ' . count($this->nodes), 'The last page shows the total row count.');
// Test a mini pager with just one item per page.
$this->drupalGet('test_mini_pager_one');
$this->assertText('››');
$this->assertText('Page 1');
$this->assertText($this->nodes[0]->label());
$this->drupalGet('test_mini_pager_one', ['query' => ['page' => 1]]);
$this->assertText('‹‹');
$this->assertText('Page 2');
$this->assertText('››');
$this->assertText($this->nodes[1]->label());
$this->drupalGet('test_mini_pager_one', ['query' => ['page' => 19]]);
$this->assertNoText('››');
$this->assertText('Page 20');
$this->assertText('‹‹');
$this->assertText($this->nodes[19]->label());
$this->drupalGet('test_mini_pager_all');
$this->assertNoText('‹‹ test', 'The previous link does not appear on the page.');
$this->assertNoText('Page 1', 'The current page info shows the only page.');
$this->assertNoText('test ››', 'The next link does not appear on the page.');
$result = $this->xpath('//div[contains(@class, "views-row")]');
$this->assertEqual(count($result), count($this->nodes), 'All rows appear on the page.');
// Remove all items beside 1, so there should be no links shown.
for ($i = 0; $i < 19; $i++) {
$this->nodes[$i]->delete();
}
$this->drupalGet('test_mini_pager');
$this->assertNoText('‹‹ test', 'The previous link does not appear on the page.');
$this->assertNoText('Page 1', 'The current page info shows the only page.');
$this->assertNoText('‹‹ test', 'The previous link does not appear on the page.');
$this->assertText($this->nodes[19]->label());
$view = Views::getView('test_mini_pager');
$this->executeView($view);
$this->assertIdentical($view->get_total_rows, NULL, 'The query was not forced to calculate the total number of results.');
$this->assertIdentical($view->total_rows, 1, 'The pager calculated the total number of rows.');
// Remove the last node as well and ensure that no "Page 1" is shown.
$this->nodes[19]->delete();
$this->drupalGet('test_mini_pager');
$this->assertNoText('‹‹ test', 'The previous link does not appear on the page.');
$this->assertNoText('Page 1', 'The current page info shows the only page.');
$this->assertNoText('‹‹ test', 'The previous link does not appear on the page.');
}
}
@@ -0,0 +1,160 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\Component\Gettext\PoHeader;
use Drupal\file\Entity\File;
use Drupal\Tests\views\Functional\ViewTestBase;
/**
* Tests the creation of numeric fields.
*
* @group field
*/
class NumericFormatPluralTest extends ViewTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['views_ui', 'file', 'language', 'locale'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['numeric_test'];
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$web_user = $this->drupalCreateUser(['administer views', 'administer languages']);
$this->drupalLogin($web_user);
}
/**
* Test plural formatting setting on a numeric views handler.
*/
public function testNumericFormatPlural() {
// Create a file.
$file = $this->createFile();
// Assert that the starting configuration is correct.
$config = $this->config('views.view.numeric_test');
$field_config_prefix = 'display.default.display_options.fields.count.';
$this->assertEqual($config->get($field_config_prefix . 'format_plural'), TRUE);
$this->assertEqual($config->get($field_config_prefix . 'format_plural_string'), '1' . LOCALE_PLURAL_DELIMITER . '@count');
// Assert that the value is displayed.
$this->drupalGet('numeric-test');
$this->assertRaw('<span class="field-content">0</span>');
// Assert that the user interface has controls to change it.
$this->drupalGet('admin/structure/views/nojs/handler/numeric_test/page_1/field/count');
$this->assertFieldByName('options[format_plural_values][0]', '1');
$this->assertFieldByName('options[format_plural_values][1]', '@count');
// Assert that changing the settings will change configuration properly.
$edit = ['options[format_plural_values][0]' => '1 time', 'options[format_plural_values][1]' => '@count times'];
$this->drupalPostForm(NULL, $edit, t('Apply'));
$this->drupalPostForm(NULL, [], t('Save'));
$config = $this->config('views.view.numeric_test');
$field_config_prefix = 'display.default.display_options.fields.count.';
$this->assertEqual($config->get($field_config_prefix . 'format_plural'), TRUE);
$this->assertEqual($config->get($field_config_prefix . 'format_plural_string'), '1 time' . LOCALE_PLURAL_DELIMITER . '@count times');
// Assert that the value is displayed with some sample values.
$numbers = [0, 1, 2, 3, 4, 42];
foreach ($numbers as $i => $number) {
\Drupal::service('file.usage')->add($file, 'views_ui', 'dummy', $i, $number);
}
$this->drupalGet('numeric-test');
foreach ($numbers as $i => $number) {
$this->assertRaw('<span class="field-content">' . $number . ($number == 1 ? ' time' : ' times') . '</span>');
}
// Add Slovenian and set its plural formula to test multiple plural forms.
$edit = ['predefined_langcode' => 'sl'];
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
$formula = 'nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);';
$header = new PoHeader();
list($nplurals, $formula) = $header->parsePluralForms($formula);
\Drupal::service('locale.plural.formula')->setPluralFormula('sl', $nplurals, $formula);
// Change the view to Slovenian.
$config = $this->config('views.view.numeric_test');
$config->set('langcode', 'sl')->save();
// Assert that the user interface has controls with more inputs now.
$this->drupalGet('admin/structure/views/nojs/handler/numeric_test/page_1/field/count');
$this->assertFieldByName('options[format_plural_values][0]', '1 time');
$this->assertFieldByName('options[format_plural_values][1]', '@count times');
$this->assertFieldByName('options[format_plural_values][2]', '');
$this->assertFieldByName('options[format_plural_values][3]', '');
// Assert that changing the settings will change configuration properly.
$edit = [
'options[format_plural_values][0]' => '@count time0',
'options[format_plural_values][1]' => '@count time1',
'options[format_plural_values][2]' => '@count time2',
'options[format_plural_values][3]' => '@count time3',
];
$this->drupalPostForm(NULL, $edit, t('Apply'));
$this->drupalPostForm(NULL, [], t('Save'));
$config = $this->config('views.view.numeric_test');
$field_config_prefix = 'display.default.display_options.fields.count.';
$this->assertEqual($config->get($field_config_prefix . 'format_plural'), TRUE);
$this->assertEqual($config->get($field_config_prefix . 'format_plural_string'), implode(LOCALE_PLURAL_DELIMITER, array_values($edit)));
// The view should now use the new plural configuration.
$this->drupalGet('sl/numeric-test');
$this->assertRaw('<span class="field-content">0 time3</span>');
$this->assertRaw('<span class="field-content">1 time0</span>');
$this->assertRaw('<span class="field-content">2 time1</span>');
$this->assertRaw('<span class="field-content">3 time2</span>');
$this->assertRaw('<span class="field-content">4 time2</span>');
$this->assertRaw('<span class="field-content">42 time3</span>');
// Add an English configuration translation with English plurals.
$english = \Drupal::languageManager()->getLanguageConfigOverride('en', 'views.view.numeric_test');
$english->set('display.default.display_options.fields.count.format_plural_string', '1 time' . LOCALE_PLURAL_DELIMITER . '@count times')->save();
// The view displayed in English should use the English translation.
$this->drupalGet('numeric-test');
$this->assertRaw('<span class="field-content">0 times</span>');
$this->assertRaw('<span class="field-content">1 time</span>');
$this->assertRaw('<span class="field-content">2 times</span>');
$this->assertRaw('<span class="field-content">3 times</span>');
$this->assertRaw('<span class="field-content">4 times</span>');
$this->assertRaw('<span class="field-content">42 times</span>');
}
/**
* Creates and saves a test file.
*
* @return \Drupal\Core\Entity\EntityInterface
* A file entity.
*/
protected function createFile() {
// Create a new file entity.
$file = File::create([
'uid' => 1,
'filename' => 'druplicon.txt',
'uri' => 'public://druplicon.txt',
'filemime' => 'text/plain',
'created' => 1,
'changed' => 1,
'status' => FILE_STATUS_PERMANENT,
]);
file_put_contents($file->getFileUri(), 'hello world');
// Save it, inserting a new record.
$file->save();
return $file;
}
}
@@ -0,0 +1,454 @@
<?php
namespace Drupal\Tests\views\Functional\Plugin;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\Tests\views\Functional\ViewTestBase;
use Drupal\views\Views;
use Drupal\language\Entity\ConfigurableLanguage;
/**
* Tests the pluggable pager system.
*
* @group views
*/
class PagerTest extends ViewTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_store_pager_settings', 'test_pager_none', 'test_pager_some', 'test_pager_full', 'test_view_pager_full_zero_items_per_page', 'test_view', 'content'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'views_ui'];
/**
* String translation storage object.
*
* @var \Drupal\locale\StringStorageInterface
*/
protected $localeStorage;
/**
* Pagers was sometimes not stored.
*
* @see https://www.drupal.org/node/652712
*/
public function testStorePagerSettings() {
// Show the master display so the override selection is shown.
\Drupal::configFactory()->getEditable('views.settings')->set('ui.show.master_display', TRUE)->save();
$admin_user = $this->drupalCreateUser(['administer views', 'administer site configuration']);
$this->drupalLogin($admin_user);
// Test behavior described in
// https://www.drupal.org/node/652712#comment-2354918.
$this->drupalGet('admin/structure/views/view/test_view/edit');
$edit = [
'pager[type]' => 'full',
];
$this->drupalPostForm('admin/structure/views/nojs/display/test_view/default/pager', $edit, t('Apply'));
$edit = [
'pager_options[items_per_page]' => 20,
];
$this->drupalPostForm('admin/structure/views/nojs/display/test_view/default/pager_options', $edit, t('Apply'));
$this->assertText('20 items');
// Change type and check whether the type is new type is stored.
$edit = [
'pager[type]' => 'mini',
];
$this->drupalPostForm('admin/structure/views/nojs/display/test_view/default/pager', $edit, t('Apply'));
$this->drupalGet('admin/structure/views/view/test_view/edit');
$this->assertText('Mini', 'Changed pager plugin, should change some text');
// Test behavior described in
// https://www.drupal.org/node/652712#comment-2354400.
$view = Views::getView('test_store_pager_settings');
// Make it editable in the admin interface.
$view->save();
$this->drupalGet('admin/structure/views/view/test_store_pager_settings/edit');
$edit = [
'pager[type]' => 'full',
];
$this->drupalPostForm('admin/structure/views/nojs/display/test_store_pager_settings/default/pager', $edit, t('Apply'));
$this->drupalGet('admin/structure/views/view/test_store_pager_settings/edit');
$this->assertText('Full');
$edit = [
'pager_options[items_per_page]' => 20,
];
$this->drupalPostForm('admin/structure/views/nojs/display/test_store_pager_settings/default/pager_options', $edit, t('Apply'));
$this->assertText('20 items');
// add new display and test the settings again, by override it.
$edit = [ ];
// Add a display and override the pager settings.
$this->drupalPostForm('admin/structure/views/view/test_store_pager_settings/edit', $edit, t('Add Page'));
$edit = [
'override[dropdown]' => 'page_1',
];
$this->drupalPostForm('admin/structure/views/nojs/display/test_store_pager_settings/page_1/pager', $edit, t('Apply'));
$edit = [
'pager[type]' => 'mini',
];
$this->drupalPostForm('admin/structure/views/nojs/display/test_store_pager_settings/page_1/pager', $edit, t('Apply'));
$this->drupalGet('admin/structure/views/view/test_store_pager_settings/edit/page_1');
$this->assertText('Mini', 'Changed pager plugin, should change some text');
$edit = [
'pager_options[items_per_page]' => 10,
];
$this->drupalPostForm('admin/structure/views/nojs/display/test_store_pager_settings/default/pager_options', $edit, t('Apply'));
$this->assertText('10 items', 'The default value has been changed.');
$this->drupalGet('admin/structure/views/view/test_store_pager_settings/edit/page_1');
$this->assertText('20 items', 'The original value remains unchanged.');
// Test that the override element is only displayed on pager plugin selection form.
$this->drupalGet('admin/structure/views/nojs/display/test_store_pager_settings/page_1/pager');
$this->assertFieldByName('override[dropdown]', 'page_1', 'The override element is displayed on plugin selection form.');
$this->drupalGet('admin/structure/views/nojs/display/test_store_pager_settings/page_1/pager_options');
$this->assertNoFieldByName('override[dropdown]', NULL, 'The override element is not displayed on plugin settings form.');
}
/**
* Tests the none-pager-query.
*/
public function testNoLimit() {
// Create 11 nodes and make sure that everyone is returned.
// We create 11 nodes, because the default pager plugin had 10 items per page.
$this->drupalCreateContentType(['type' => 'page']);
for ($i = 0; $i < 11; $i++) {
$this->drupalCreateNode();
}
$view = Views::getView('test_pager_none');
$this->executeView($view);
$this->assertEqual(count($view->result), 11, 'Make sure that every item is returned in the result');
// Setup and test a offset.
$view = Views::getView('test_pager_none');
$view->setDisplay();
$pager = [
'type' => 'none',
'options' => [
'offset' => 3,
],
];
$view->display_handler->setOption('pager', $pager);
$this->executeView($view);
$this->assertEqual(count($view->result), 8, 'Make sure that every item beside the first three is returned in the result');
// Check some public functions.
$this->assertFalse($view->pager->usePager());
$this->assertFalse($view->pager->useCountQuery());
$this->assertEqual($view->pager->getItemsPerPage(), 0);
}
public function testViewTotalRowsWithoutPager() {
$this->drupalCreateContentType(['type' => 'page']);
for ($i = 0; $i < 23; $i++) {
$this->drupalCreateNode();
}
$view = Views::getView('test_pager_none');
$view->get_total_rows = TRUE;
$this->executeView($view);
$this->assertEqual($view->total_rows, 23, "'total_rows' is calculated when pager type is 'none' and 'get_total_rows' is TRUE.");
}
/**
* Tests the some pager plugin.
*/
public function testLimit() {
// Create 11 nodes and make sure that everyone is returned.
// We create 11 nodes, because the default pager plugin had 10 items per page.
$this->drupalCreateContentType(['type' => 'page']);
for ($i = 0; $i < 11; $i++) {
$this->drupalCreateNode();
}
$view = Views::getView('test_pager_some');
$this->executeView($view);
$this->assertEqual(count($view->result), 5, 'Make sure that only a certain count of items is returned');
// Setup and test a offset.
$view = Views::getView('test_pager_some');
$view->setDisplay();
$pager = [
'type' => 'none',
'options' => [
'offset' => 8,
'items_per_page' => 5,
],
];
$view->display_handler->setOption('pager', $pager);
$this->executeView($view);
$this->assertEqual(count($view->result), 3, 'Make sure that only a certain count of items is returned');
// Check some public functions.
$this->assertFalse($view->pager->usePager());
$this->assertFalse($view->pager->useCountQuery());
}
/**
* Tests the normal pager.
*/
public function testNormalPager() {
// Create 11 nodes and make sure that everyone is returned.
// We create 11 nodes, because the default pager plugin had 10 items per page.
$this->drupalCreateContentType(['type' => 'page']);
for ($i = 0; $i < 11; $i++) {
$this->drupalCreateNode();
}
$view = Views::getView('test_pager_full');
$this->executeView($view);
$this->assertEqual(count($view->result), 5, 'Make sure that only a certain count of items is returned');
// Setup and test a offset.
$view = Views::getView('test_pager_full');
$view->setDisplay();
$pager = [
'type' => 'full',
'options' => [
'offset' => 8,
'items_per_page' => 5,
],
];
$view->display_handler->setOption('pager', $pager);
$this->executeView($view);
$this->assertEqual(count($view->result), 3, 'Make sure that only a certain count of items is returned');
// Test items per page = 0
$view = Views::getView('test_view_pager_full_zero_items_per_page');
$this->executeView($view);
$this->assertEqual(count($view->result), 11, 'All items are return');
// TODO test number of pages.
// Test items per page = 0.
// Setup and test a offset.
$view = Views::getView('test_pager_full');
$view->setDisplay();
$pager = [
'type' => 'full',
'options' => [
'offset' => 0,
'items_per_page' => 0,
],
];
$view->display_handler->setOption('pager', $pager);
$this->executeView($view);
$this->assertEqual($view->pager->getItemsPerPage(), 0);
$this->assertEqual(count($view->result), 11);
// Test pager cache contexts.
$this->drupalGet('test_pager_full');
$this->assertCacheContexts(['languages:language_interface', 'theme', 'timezone', 'url.query_args', 'user.node_grants:view']);
}
/**
* Tests rendering with NULL pager.
*/
public function testRenderNullPager() {
// Create 11 nodes and make sure that everyone is returned.
// We create 11 nodes, because the default pager plugin had 10 items per page.
$this->drupalCreateContentType(['type' => 'page']);
for ($i = 0; $i < 11; $i++) {
$this->drupalCreateNode();
}
$view = Views::getView('test_pager_full');
$this->executeView($view);
// Force the value again here.
$view->setAjaxEnabled(TRUE);
$view->pager = NULL;
$output = $view->render();
$output = \Drupal::service('renderer')->renderRoot($output);
$this->assertEqual(preg_match('/<ul class="pager">/', $output), 0, 'The pager is not rendered.');
}
/**
* Test the api functions on the view object.
*/
public function testPagerApi() {
$view = Views::getView('test_pager_full');
$view->setDisplay();
// On the first round don't initialize the pager.
$this->assertEqual($view->getItemsPerPage(), NULL, 'If the pager is not initialized and no manual override there is no items per page.');
$rand_number = rand(1, 5);
$view->setItemsPerPage($rand_number);
$this->assertEqual($view->getItemsPerPage(), $rand_number, 'Make sure getItemsPerPage uses the settings of setItemsPerPage.');
$this->assertEqual($view->getOffset(), NULL, 'If the pager is not initialized and no manual override there is no offset.');
$rand_number = rand(1, 5);
$view->setOffset($rand_number);
$this->assertEqual($view->getOffset(), $rand_number, 'Make sure getOffset uses the settings of setOffset.');
$this->assertEqual($view->getCurrentPage(), NULL, 'If the pager is not initialized and no manual override there is no current page.');
$rand_number = rand(1, 5);
$view->setCurrentPage($rand_number);
$this->assertEqual($view->getCurrentPage(), $rand_number, 'Make sure getCurrentPage uses the settings of set_current_page.');
$view->destroy();
// On this round enable the pager.
$view->initDisplay();
$view->initQuery();
$view->initPager();
$this->assertEqual($view->getItemsPerPage(), 5, 'Per default the view has 5 items per page.');
$rand_number = rand(1, 5);
$view->setItemsPerPage($rand_number);
$rand_number = rand(6, 11);
$view->pager->setItemsPerPage($rand_number);
$this->assertEqual($view->getItemsPerPage(), $rand_number, 'Make sure getItemsPerPage uses the settings of setItemsPerPage.');
$this->assertEqual($view->getOffset(), 0, 'Per default a view has a 0 offset.');
$rand_number = rand(1, 5);
$view->setOffset($rand_number);
$rand_number = rand(6, 11);
$view->pager->setOffset($rand_number);
$this->assertEqual($view->getOffset(), $rand_number, 'Make sure getOffset uses the settings of setOffset.');
$this->assertEqual($view->getCurrentPage(), 0, 'Per default the current page is 0.');
$rand_number = rand(1, 5);
$view->setCurrentPage($rand_number);
$rand_number = rand(6, 11);
$view->pager->setCurrentPage($rand_number);
$this->assertEqual($view->getCurrentPage(), $rand_number, 'Make sure getCurrentPage uses the settings of set_current_page.');
// Set an invalid page and make sure the method takes care about it.
$view->setCurrentPage(-1);
$this->assertEqual($view->getCurrentPage(), 0, 'Make sure setCurrentPage always sets a valid page number.');
}
/**
* Tests translating the pager using config_translation.
*/
public function testPagerConfigTranslation() {
$view = Views::getView('content');
$display = &$view->storage->getDisplay('default');
$display['display_options']['pager']['options']['items_per_page'] = 5;
$view->save();
// Enable locale, config_translation and language module.
$this->container->get('module_installer')->install(['locale', 'language', 'config_translation']);
$this->resetAll();
$admin_user = $this->drupalCreateUser(['access content overview', 'administer nodes', 'bypass node access', 'translate configuration']);
$this->drupalLogin($admin_user);
$langcode = 'nl';
// Add a default locale storage for this test.
$this->localeStorage = $this->container->get('locale.storage');
// Add Dutch language programmatically.
ConfigurableLanguage::createFromLangcode($langcode)->save();
$edit = [
'translation[config_names][views.view.content][display][default][display_options][pager][options][tags][first]' => '« Eerste',
'translation[config_names][views.view.content][display][default][display_options][pager][options][tags][previous]' => ' Vorige',
'translation[config_names][views.view.content][display][default][display_options][pager][options][tags][next]' => 'Volgende ',
'translation[config_names][views.view.content][display][default][display_options][pager][options][tags][last]' => 'Laatste »',
];
$this->drupalPostForm('admin/structure/views/view/content/translate/nl/edit', $edit, t('Save translation'));
// We create 11 nodes, this will give us 3 pages.
$this->drupalCreateContentType(['type' => 'page']);
for ($i = 0; $i < 11; $i++) {
$this->drupalCreateNode();
}
// Go to the second page so we see both previous and next buttons.
$this->drupalGet('nl/admin/content', ['query' => ['page' => 1]]);
// Translation mapping..
$labels = [
'« First' => '« Eerste',
' Previous' => ' Vorige',
'Next ' => 'Volgende ',
'Last »' => 'Laatste »',
];
foreach ($labels as $label => $translation) {
// Check if we can find the translation.
$this->assertRaw($translation);
}
}
/**
* Tests translating the pager using locale.
*/
public function testPagerLocale() {
// Enable locale and language module.
$this->container->get('module_installer')->install(['locale', 'language']);
$this->resetAll();
$langcode = 'nl';
// Add a default locale storage for this test.
$this->localeStorage = $this->container->get('locale.storage');
// Add Dutch language programmatically.
ConfigurableLanguage::createFromLangcode($langcode)->save();
// Labels that need translations.
$labels = [
'« First' => '« Eerste',
' Previous' => ' Vorige',
'Next ' => 'Volgende ',
'Last »' => 'Laatste »',
];
foreach ($labels as $label => $translation) {
// Create source string.
$source = $this->localeStorage->createString(
[
'source' => $label
]
);
$source->save();
$this->createTranslation($source, $translation, $langcode);
}
// We create 11 nodes, this will give us 3 pages.
$this->drupalCreateContentType(['type' => 'page']);
for ($i = 0; $i < 11; $i++) {
$this->drupalCreateNode();
}
// Go to the second page so we see both previous and next buttons.
$this->drupalGet('nl/test_pager_full', ['query' => ['page' => 1]]);
foreach ($labels as $label => $translation) {
// Check if we can find the translation.
$this->assertRaw($translation);
}
}
/**
* Creates single translation for source string.
*/
protected function createTranslation($source, $translation, $langcode) {
$values = [
'lid' => $source->lid,
'language' => $langcode,
'translation' => $translation,
];
return $this->localeStorage->createTranslation($values)->save();
}
}

Some files were not shown because too many files have changed in this diff Show More