Update Composer, update everything

This commit is contained in:
Oliver Davies 2018-11-23 12:29:20 +00:00
parent ea3e94409f
commit dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html lang="de">
<head>
<link rel="alternate" href="photo_flickr.json"
type="application/json+oembed" title="Druplicon FTW!">
</head>
<body></body>
</html>

View file

@ -0,0 +1,12 @@
{
"type": "photo",
"title": "Druplicon FTW!",
"width": "88",
"height": "100",
"url": "internal:\/core\/misc\/druplicon.png",
"thumbnail_url": "internal:\/core\/misc\/druplicon.png",
"thumbnail_width": 88,
"thumbnail_height": 100,
"provider_name": "Flickr",
"version": "1.0"
}

View file

@ -0,0 +1,61 @@
[
{
"provider_name": "Vimeo",
"provider_url": "https:\/\/vimeo.com\/",
"endpoints": [
{
"schemes": [
"https:\/\/vimeo.com\/*",
"https:\/\/vimeo.com\/album\/*\/video\/*",
"https:\/\/vimeo.com\/channels\/*\/*",
"https:\/\/vimeo.com\/groups\/*\/videos\/*",
"https:\/\/vimeo.com\/ondemand\/*\/*",
"https:\/\/player.vimeo.com\/video\/*"
],
"url": "https:\/\/vimeo.com\/api\/oembed.{format}",
"discovery": true
}
]
},
{
"provider_name": "Twitter",
"provider_url": "http:\/\/www.twitter.com\/",
"endpoints": [
{
"schemes": [
"https:\/\/twitter.com\/*\/status\/*",
"https:\/\/*.twitter.com\/*\/status\/*"
],
"url": "https:\/\/publish.twitter.com\/oembed"
}
]
},
{
"provider_name": "CollegeHumor",
"provider_url": "http:\/\/www.collegehumor.com\/",
"endpoints": [
{
"schemes": [
"http:\/\/www.collegehumor.com\/video\/*"
],
"url": "http:\/\/www.collegehumor.com\/oembed.{format}",
"discovery": true
}
]
},
{
"provider_name": "Flickr",
"provider_url": "http:\/\/www.flickr.com\/",
"endpoints": [
{
"schemes": [
"http:\/\/*.flickr.com\/photos\/*",
"http:\/\/flic.kr\/p\/*"
],
"url": "http:\/\/www.flickr.com\/services\/oembed\/",
"discovery": true
}
]
}
]

View file

@ -0,0 +1,13 @@
{
"url": "https:\/\/twitter.com\/drupaldevdays\/status\/935643039741202432",
"author_name": "Drupal Dev Days",
"author_url": "https:\/\/twitter.com\/drupaldevdays",
"html": "<h1>By the power of Greyskull, Twitter works!</h1>",
"width": 550,
"height": 360,
"type": "rich",
"cache_age": "3153600000",
"provider_name": "Twitter",
"provider_url": "https:\/\/twitter.com",
"version": "1.0"
}

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html lang="de">
<head>
<link rel="alternate" href="video_collegehumor.xml"
type="application/xml+oembed" title="Let&#039;s Not Get a Drink Sometime">
</head>
<body></body>
</html>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<oembed>
<type>video</type>
<version>1.0</version>
<title>Let's Not Get a Drink Sometime</title>
<https/>
<author_name>CollegeHumor</author_name>
<author_url>http://www.collegehumor.com</author_url>
<provider_name>CollegeHumor</provider_name>
<provider_url>http://www.collegehumor.com</provider_url>
<width>610</width>
<height>343</height>
<html><h1>By the power of Greyskull, CollegeHumor works!</h1>
</html>
<thumbnail_url>internal:/core/misc/druplicon.png</thumbnail_url>
<thumbnail_width>88</thumbnail_width>
<thumbnail_height>100</thumbnail_height>
</oembed>

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html lang="de">
<head>
<link rel="alternate" href="video_vimeo.json"
type="application/json+oembed" title="Drupal Rap Video - Schipulcon09">
</head>
<body></body>
</html>

View file

@ -0,0 +1,16 @@
{
"type": "video",
"version": "1.0",
"provider_name": "Vimeo",
"provider_url": "https:\/\/vimeo.com\/",
"title": "Drupal Rap Video - Schipulcon09",
"author_name": "Tendenci - The Open Source AMS",
"author_url": "https:\/\/vimeo.com\/schipul",
"html": "<h1>By the power of Greyskull, Vimeo works!</h1>",
"width": 480,
"height": 360,
"description": "Special thanks to Tendenci, formerly Schipul for sponsoring this video with training, equipment and time. The open source way. All creative however was self directed by the individuals - A. Hughes (www.schipul.com\/ahughes) featuring QCait (www.schipul.com\/qcait) - Hands On Drupal\n\nDrupal is a free software package that allows an individual or a community of users to easily publish, manage and organize a wide variety of content on a website.\n\nNeed a little Drupal help or just want to geek out with us? Visit our www.schipul.com\/drupal for more info - we'd love to connect!\n\nGo here for Drupal Common Terms and Suggested Modules : http:\/\/schipul.com\/en\/helpfiles\/v\/229",
"thumbnail_url": "internal:\/core\/misc\/druplicon.png",
"thumbnail_width": 295,
"thumbnail_height": 221
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,36 @@
<?php
// @codingStandardsIgnoreFile
/**
* @file
* Contains database additions to drupal-8.4.0.bare.standard.php.gz for testing
* the upgrade path of https://www.drupal.org/node/2862422.
*/
use Drupal\Core\Database\Database;
$connection = Database::getConnection();
$role = $connection->select('config')
->fields('config', ['data'])
->condition('collection', '')
->condition('name', 'user.role.authenticated')
->execute()
->fetchField();
$role = unserialize($role);
$role['permissions'][] = 'update media';
$role['permissions'][] = 'update any media';
$role['permissions'][] = 'delete media';
$role['permissions'][] = 'delete any media';
$role['permissions'][] = 'create media';
$connection->update('config')
->fields([
'data' => serialize($role),
'collection' => '',
'name' => 'user.role.authenticated',
])
->condition('collection', '')
->condition('name', 'user.role.authenticated')
->execute();

View file

@ -0,0 +1,8 @@
name: Media oEmbed test
description: 'Provides functionality to mimic an oEmbed provider.'
type: module
package: Testing
version: VERSION
core: 8.x
dependencies:
- drupal:media

View file

@ -0,0 +1,17 @@
<?php
/**
* @file
* Helper module for the Media oEmbed tests.
*/
use Drupal\media\OEmbed\Provider;
/**
* Implements hook_oembed_resource_url_alter().
*/
function media_test_oembed_oembed_resource_url_alter(array &$parsed_url, Provider $provider) {
if ($provider->getName() === 'Vimeo') {
$parsed_url['query']['altered'] = 1;
}
}

View file

@ -0,0 +1,6 @@
media_test_oembed.resource.get:
path: '/media_test_oembed/resource'
defaults:
_controller: '\Drupal\media_test_oembed\Controller\ResourceController::get'
requirements:
_access: 'TRUE'

View file

@ -0,0 +1,48 @@
<?php
namespace Drupal\media_test_oembed\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Test controller returning oEmbed resources from Media's test fixtures.
*/
class ResourceController {
/**
* Returns the contents of an oEmbed resource fixture.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request.
*
* @return \Symfony\Component\HttpFoundation\Response
* The JSON response.
*/
public function get(Request $request) {
$asset_url = $request->query->get('url');
$resources = \Drupal::state()->get(static::class, []);
$content = file_get_contents($resources[$asset_url]);
$response = new Response($content);
$response->headers->set('Content-Type', 'application/json');
return $response;
}
/**
* Maps an asset URL to a local fixture representing its oEmbed resource.
*
* @param string $asset_url
* The asset URL.
* @param string $resource_path
* The path of the oEmbed resource representing the asset.
*/
public static function setResourceUrl($asset_url, $resource_path) {
$resources = \Drupal::state()->get(static::class, []);
$resources[$asset_url] = $resource_path;
\Drupal::state()->set(static::class, $resources);
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Drupal\media_test_oembed;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
/**
* Replaces oEmbed-related media services with testing versions.
*/
class MediaTestOembedServiceProvider extends ServiceProviderBase {
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
parent::alter($container);
$container->getDefinition('media.oembed.provider_repository')
->setClass(ProviderRepository::class);
$container->getDefinition('media.oembed.url_resolver')
->setClass(UrlResolver::class);
}
}

View file

@ -0,0 +1,55 @@
<?php
namespace Drupal\media_test_oembed;
use Drupal\media\OEmbed\Provider;
use Drupal\media\OEmbed\ProviderRepository as BaseProviderRepository;
/**
* Overrides the oEmbed provider repository service for testing purposes.
*
* This service does not use caching at all, and will always try to retrieve
* provider data from state before calling the parent methods.
*/
class ProviderRepository extends BaseProviderRepository {
/**
* {@inheritdoc}
*/
protected function cacheGet($cid) {
return FALSE;
}
/**
* {@inheritdoc}
*/
public function getAll() {
return \Drupal::state()->get(static::class) ?: parent::getAll();
}
/**
* {@inheritdoc}
*/
public function get($provider_name) {
$providers = \Drupal::state()->get(static::class, []);
if (isset($providers[$provider_name])) {
return $providers[$provider_name];
}
return parent::get($provider_name);
}
/**
* Stores an oEmbed provider value object in state.
*
* @param \Drupal\media\OEmbed\Provider $provider
* The provider to store.
*/
public function setProvider(Provider $provider) {
$providers = \Drupal::state()->get(static::class, []);
$name = $provider->getName();
$providers[$name] = $provider;
\Drupal::state()->set(static::class, $providers);
}
}

View file

@ -0,0 +1,38 @@
<?php
namespace Drupal\media_test_oembed;
use Drupal\media\OEmbed\UrlResolver as BaseUrlResolver;
/**
* Overrides the oEmbed URL resolver service for testing purposes.
*/
class UrlResolver extends BaseUrlResolver {
/**
* Sets the endpoint URL for an oEmbed resource URL.
*
* @param string $url
* The resource URL.
* @param string $endpoint_url
* The endpoint URL.
*/
public static function setEndpointUrl($url, $endpoint_url) {
$urls = \Drupal::state()->get(static::class, []);
$urls[$url] = $endpoint_url;
\Drupal::state()->set(static::class, $urls);
}
/**
* {@inheritdoc}
*/
public function getResourceUrl($url, $max_width = NULL, $max_height = NULL) {
$urls = \Drupal::state()->get(static::class, []);
if (isset($urls[$url])) {
return $urls[$url];
}
return parent::getResourceUrl($url, $max_width, $max_height);
}
}

View file

@ -0,0 +1,23 @@
media.source.test:
type: media.source.field_aware
label: 'Test media source configuration'
mapping:
test_config_value:
type: string
label: 'Test config value'
media.source.test_translation:
type: media.source.test
label: 'Test media source with translations'
media.source.test_constraints:
type: media.source.test
label: 'Test media source with constraints configuration'
media.source.test_hidden_source_field:
type: media.source.test
label: 'Test media source with hidden source field'
media.source.test_different_displays:
type: media.source.test
label: 'Test media source with different source field displays'

View file

@ -0,0 +1,6 @@
name: 'Test media source'
type: module
description: 'Provides test media source to test configuration forms.'
core: 8.x
package: Testing
version: VERSION

View file

@ -0,0 +1,25 @@
<?php
namespace Drupal\media_test_source\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* A media test constraint.
*
* @Constraint(
* id = "MediaTestConstraint",
* label = @Translation("Media constraint for test purposes.", context = "Validation"),
* type = { "entity", "string" }
* )
*/
class MediaTestConstraint extends Constraint {
/**
* The default violation message.
*
* @var string
*/
public $message = 'Inappropriate text.';
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\media_test_source\Plugin\Validation\Constraint;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Validates the MediaTestConstraint.
*/
class MediaTestConstraintValidator extends ConstraintValidator {
/**
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint) {
if ($value instanceof EntityInterface) {
$string_to_test = $value->label();
}
elseif ($value instanceof FieldItemListInterface) {
$string_to_test = $value->value;
}
else {
return;
}
if (strpos($string_to_test, 'love Drupal') === FALSE) {
$this->context->addViolation($constraint->message);
}
}
}

View file

@ -0,0 +1,88 @@
<?php
namespace Drupal\media_test_source\Plugin\media\Source;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Form\FormStateInterface;
use Drupal\media\MediaInterface;
use Drupal\media\MediaSourceBase;
/**
* Provides test media source.
*
* @MediaSource(
* id = "test",
* label = @Translation("Test source"),
* description = @Translation("Test media source."),
* allowed_field_types = {"string"},
* )
*/
class Test extends MediaSourceBase {
/**
* {@inheritdoc}
*/
public function getMetadataAttributes() {
// The metadata attributes are kept in state storage. This allows tests to
// change the metadata attributes and makes it easier to test different
// variations.
$attributes = \Drupal::state()->get('media_source_test_attributes', [
'attribute_1' => ['label' => $this->t('Attribute 1'), 'value' => 'Value 1'],
'attribute_2' => ['label' => $this->t('Attribute 2'), 'value' => 'Value 1'],
]);
return array_map(function ($item) {
return $item['label'];
}, $attributes);
}
/**
* {@inheritdoc}
*/
public function getMetadata(MediaInterface $media, $attribute_name) {
$attributes = \Drupal::state()->get('media_source_test_attributes', [
'attribute_1' => ['label' => $this->t('Attribute 1'), 'value' => 'Value 1'],
'attribute_2' => ['label' => $this->t('Attribute 2'), 'value' => 'Value 1'],
]);
if (in_array($attribute_name, array_keys($attributes))) {
return $attributes[$attribute_name]['value'];
}
return parent::getMetadata($media, $attribute_name);
}
/**
* {@inheritdoc}
*/
public function getPluginDefinition() {
return NestedArray::mergeDeep(
parent::getPluginDefinition(),
\Drupal::state()->get('media_source_test_definition', [])
);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return parent::defaultConfiguration() + [
'test_config_value' => 'This is default value.',
];
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$form['test_config_value'] = [
'#type' => 'textfield',
'#title' => $this->t('Test config value'),
'#default_value' => $this->configuration['test_config_value'],
];
return $form;
}
}

View file

@ -0,0 +1,50 @@
<?php
namespace Drupal\media_test_source\Plugin\media\Source;
use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\media\MediaTypeInterface;
/**
* Provides test media source.
*
* @MediaSource(
* id = "test_different_displays",
* label = @Translation("Test source with different displays"),
* description = @Translation("Test source with different displays."),
* allowed_field_types = {"entity_reference"},
* )
*/
class TestDifferentDisplays extends Test {
/**
* {@inheritdoc}
*/
public function prepareViewDisplay(MediaTypeInterface $type, EntityViewDisplayInterface $display) {
parent::prepareViewDisplay($type, $display);
$source_name = $this->getSourceFieldDefinition($type)->getName();
$source_component = $display->getComponent($source_name) ?: [];
$source_component['type'] = 'entity_reference_entity_id';
$display->setComponent($source_name, $source_component);
}
/**
* {@inheritdoc}
*/
public function prepareFormDisplay(MediaTypeInterface $type, EntityFormDisplayInterface $display) {
parent::prepareFormDisplay($type, $display);
$source_name = $this->getSourceFieldDefinition($type)->getName();
$source_component = $display->getComponent($source_name) ?: [];
$source_component['type'] = 'entity_reference_autocomplete_tags';
$display->setComponent($source_name, $source_component);
}
/**
* {@inheritdoc}
*/
protected function getSourceFieldName() {
return 'field_media_different_display';
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\media_test_source\Plugin\media\Source;
use Drupal\media\MediaInterface;
/**
* Provides test media source.
*
* @MediaSource(
* id = "test_translation",
* label = @Translation("Test source with translations"),
* description = @Translation("Test media source with translations."),
* allowed_field_types = {"string"},
* thumbnail_alt_metadata_attribute = "test_thumbnail_alt",
* )
*/
class TestTranslation extends Test {
/**
* {@inheritdoc}
*/
public function getMetadata(MediaInterface $media, $attribute_name) {
if ($attribute_name == 'thumbnail_uri') {
return 'public://' . $media->language()->getId() . '.png';
}
if ($attribute_name == 'test_thumbnail_alt') {
$langcode = $media->language()->getId();
return $this->t('Test Thumbnail @language', ['@language' => $langcode], ['langcode' => $langcode]);
}
return parent::getMetadata($media, $attribute_name);
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\media_test_source\Plugin\media\Source;
use Drupal\media\MediaSourceEntityConstraintsInterface;
use Drupal\media\MediaSourceFieldConstraintsInterface;
/**
* Provides generic media type.
*
* @MediaSource(
* id = "test_constraints",
* label = @Translation("Test source with constraints"),
* description = @Translation("Test media source that provides constraints."),
* allowed_field_types = {"string_long"},
* )
*/
class TestWithConstraints extends Test implements MediaSourceEntityConstraintsInterface, MediaSourceFieldConstraintsInterface {
/**
* {@inheritdoc}
*/
public function getEntityConstraints() {
return \Drupal::state()->get('media_source_test_entity_constraints', []);
}
/**
* {@inheritdoc}
*/
public function getSourceFieldConstraints() {
return \Drupal::state()->get('media_source_test_field_constraints', []);
}
}

View file

@ -0,0 +1,42 @@
<?php
namespace Drupal\media_test_source\Plugin\media\Source;
use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\media\MediaTypeInterface;
/**
* Provides test media source.
*
* @MediaSource(
* id = "test_hidden_source_field",
* label = @Translation("Test source with hidden source field"),
* description = @Translation("Test media source with hidden source field."),
* allowed_field_types = {"string"},
* )
*/
class TestWithHiddenSourceField extends Test {
/**
* {@inheritdoc}
*/
public function prepareViewDisplay(MediaTypeInterface $type, EntityViewDisplayInterface $display) {
$display->removeComponent($this->getSourceFieldDefinition($type)->getName());
}
/**
* {@inheritdoc}
*/
public function prepareFormDisplay(MediaTypeInterface $type, EntityFormDisplayInterface $display) {
$display->removeComponent($this->getSourceFieldDefinition($type)->getName());
}
/**
* {@inheritdoc}
*/
protected function getSourceFieldName() {
return 'field_media_hidden';
}
}

View file

@ -0,0 +1,11 @@
id: test
label: 'Test type'
description: 'Test type.'
source: test
source_configuration:
test_config_value: 'Kakec'
status: true
langcode: en
dependencies: { }
field_map:
metadata_attribute: 'field_attribute_config_test'

View file

@ -0,0 +1,9 @@
name: 'Media test type'
type: module
description: 'Provides test type for a media item.'
core: 8.x
package: Testing
version: VERSION
dependencies:
- drupal:media
- drupal:media_test_source

View file

@ -0,0 +1,154 @@
langcode: en
status: true
dependencies:
module:
- media
- user
id: test_media_bulk_form
label: ''
module: views
description: ''
tag: ''
base_table: media_field_data
base_field: mid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
style:
type: table
row:
type: fields
fields:
media_bulk_form:
id: media_bulk_form
table: media
field: media_bulk_form
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
action_title: 'With selection'
include_exclude: exclude
selected_actions: { }
entity_type: media
plugin_id: bulk_form
name:
id: name
table: media_field_data
field: name
entity_type: media
entity_field: media
hide_empty: false
empty_zero: false
settings:
link_to_entity: false
plugin_id: field
relationship: none
group_type: group
admin_label: ''
label: 'Media name'
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
status:
id: status
table: media_field_data
field: status
relationship: none
group_type: group
admin_label: ''
label: Status
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_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: value
type: boolean
settings:
format: custom
format_custom_true: Published
format_custom_false: Unpublished
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
entity_type: media
entity_field: status
plugin_id: field
sorts:
mid:
id: mid
table: media_field_data
field: mid
relationship: none
group_type: group
admin_label: ''
order: ASC
exposed: false
expose:
label: ''
entity_type: media
entity_field: mid
plugin_id: standard
title: 'Entity bulk form test view'
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
page_1:
display_plugin: page
id: page_1
display_title: Page
position: 1
display_options:
path: test-media-bulk-form

View file

@ -0,0 +1,9 @@
name: 'Media test views'
type: module
description: 'Provides default views for views media tests.'
package: Testing
version: VERSION
core: 8.x
dependencies:
- drupal:media
- drupal:views

View file

@ -0,0 +1,173 @@
<?php
namespace Drupal\Tests\media\Functional\FieldFormatter;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\media\Entity\Media;
use Drupal\media_test_oembed\Controller\ResourceController;
use Drupal\media_test_oembed\UrlResolver;
use Drupal\Tests\media\Functional\MediaFunctionalTestBase;
use Drupal\Tests\media\Traits\OEmbedTestTrait;
/**
* @covers \Drupal\media\Plugin\Field\FieldFormatter\OEmbedFormatter
*
* @group media
*/
class OEmbedFormatterTest extends MediaFunctionalTestBase {
use OEmbedTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = [
'field_ui',
'link',
'media_test_oembed',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->lockHttpClientToFixtures();
}
/**
* Data provider for testRender().
*
* @see ::testRender()
*
* @return array
*/
public function providerRender() {
return [
'Vimeo video' => [
'https://vimeo.com/7073899',
'video_vimeo.json',
[],
[
'iframe' => [
'src' => '/media/oembed?url=https%3A//vimeo.com/7073899',
'width' => 480,
'height' => 360,
],
],
],
'Vimeo video, resized' => [
'https://vimeo.com/7073899',
'video_vimeo.json?maxwidth=100&maxheight=100',
['max_width' => 100, 'max_height' => 100],
[
'iframe' => [
'src' => '/media/oembed?url=https%3A//vimeo.com/7073899',
'width' => 100,
'height' => 100,
],
],
],
'tweet' => [
'https://twitter.com/drupaldevdays/status/935643039741202432',
'rich_twitter.json',
[],
[
'iframe' => [
'src' => '/media/oembed?url=https%3A//twitter.com/drupaldevdays/status/935643039741202432',
'width' => 550,
'height' => 360,
],
],
],
'Flickr photo' => [
'https://www.flickr.com/photos/amazeelabs/26497866357',
'photo_flickr.json',
[],
[
'img' => [
'src' => '/core/misc/druplicon.png',
'width' => 88,
'height' => 100,
],
],
],
];
}
/**
* Tests that oEmbed media types' display can be configured correctly.
*/
public function testDisplayConfiguration() {
$account = $this->drupalCreateUser(['administer media display']);
$this->drupalLogin($account);
$media_type = $this->createMediaType('oembed:video');
$this->drupalGet('/admin/structure/media/manage/' . $media_type->id() . '/display');
$assert = $this->assertSession();
$assert->statusCodeEquals(200);
// Test that the formatter doesn't try to check applicability for fields
// which do not have a specific target bundle.
// @see https://www.drupal.org/project/drupal/issues/2976795.
$assert->pageTextNotContains('Can only flip STRING and INTEGER values!');
}
/**
* Tests the oEmbed field formatter.
*
* @param string $url
* The canonical URL of the media asset to test.
* @param string $resource_url
* The oEmebd resource URL of the media asset to test.
* @param mixed $formatter_settings
* Settings for the oEmbed field formatter.
* @param array $selectors
* An array of arrays. Each key is a CSS selector targeting an element in
* the rendered output, and each value is an array of attributes, keyed by
* name, that the element is expected to have.
*
* @dataProvider providerRender
*/
public function testRender($url, $resource_url, array $formatter_settings, array $selectors) {
$account = $this->drupalCreateUser(['view media']);
$this->drupalLogin($account);
$media_type = $this->createMediaType('oembed:video');
$source = $media_type->getSource();
$source_field = $source->getSourceFieldDefinition($media_type);
EntityViewDisplay::create([
'targetEntityType' => 'media',
'bundle' => $media_type->id(),
'mode' => 'full',
'status' => TRUE,
])->removeComponent('thumbnail')
->setComponent($source_field->getName(), [
'type' => 'oembed',
'settings' => $formatter_settings,
])
->save();
$this->hijackProviderEndpoints();
ResourceController::setResourceUrl($url, $this->getFixturesDirectory() . '/' . $resource_url);
UrlResolver::setEndpointUrl($url, $resource_url);
$entity = Media::create([
'bundle' => $media_type->id(),
$source_field->getName() => $url,
]);
$entity->save();
$this->drupalGet($entity->toUrl());
$assert = $this->assertSession();
$assert->statusCodeEquals(200);
foreach ($selectors as $selector => $attributes) {
foreach ($attributes as $attribute => $value) {
$assert->elementAttributeContains('css', $selector, $attribute, $value);
}
}
}
}

View file

@ -0,0 +1,228 @@
<?php
namespace Drupal\Tests\media\Functional\Hal;
use Drupal\Core\Cache\Cache;
use Drupal\file\Entity\File;
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
use Drupal\Tests\media\Functional\Rest\MediaResourceTestBase;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\user\Entity\User;
/**
* @group hal
*/
class MediaHalJsonAnonTest extends MediaResourceTestBase {
use HalEntityNormalizationTrait;
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
$default_normalization = parent::getExpectedNormalizedEntity();
$normalization = $this->applyHalFieldNormalization($default_normalization);
$file = File::load(1);
$thumbnail = File::load(2);
$author = User::load($this->entity->getOwnerId());
return $normalization + [
'_links' => [
'self' => [
'href' => $this->baseUrl . '/media/1?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/media/camelids',
],
$this->baseUrl . '/rest/relation/media/camelids/field_media_file' => [
[
'href' => $file->url(),
'lang' => 'en',
],
],
$this->baseUrl . '/rest/relation/media/camelids/revision_user' => [
[
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
],
],
$this->baseUrl . '/rest/relation/media/camelids/thumbnail' => [
[
'href' => $thumbnail->url(),
'lang' => 'en',
],
],
$this->baseUrl . '/rest/relation/media/camelids/uid' => [
[
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
'lang' => 'en',
],
],
],
'_embedded' => [
$this->baseUrl . '/rest/relation/media/camelids/field_media_file' => [
[
'_links' => [
'self' => [
'href' => $file->url(),
],
'type' => [
'href' => $this->baseUrl . '/rest/type/file/file',
],
],
'lang' => 'en',
'uuid' => [
[
'value' => $file->uuid(),
],
],
],
],
$this->baseUrl . '/rest/relation/media/camelids/revision_user' => [
[
'_links' => [
'self' => [
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/user/user',
],
],
'uuid' => [
[
'value' => $author->uuid(),
],
],
],
],
$this->baseUrl . '/rest/relation/media/camelids/thumbnail' => [
[
'_links' => [
'self' => [
'href' => $thumbnail->url(),
],
'type' => [
'href' => $this->baseUrl . '/rest/type/file/file',
],
],
'lang' => 'en',
'uuid' => [
[
'value' => $thumbnail->uuid(),
],
],
],
],
$this->baseUrl . '/rest/relation/media/camelids/uid' => [
[
'_links' => [
'self' => [
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/user/user',
],
],
'uuid' => [
[
'value' => $author->uuid(),
],
],
'lang' => 'en',
],
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedFileEntity() {
$normalization = parent::getExpectedNormalizedFileEntity();
$owner = static::$auth ? $this->account : User::load(0);
// Cannot use applyHalFieldNormalization() as it uses the $entity property
// from the test class, which in the case of file upload tests, is the
// parent entity test entity for the file that's created.
// The HAL normalization adds entity reference fields to '_links' and
// '_embedded'.
unset($normalization['uid']);
return $normalization + [
'_links' => [
'self' => [
// @todo This can use a proper link once
// https://www.drupal.org/project/drupal/issues/2907402 is complete.
// This link matches what is generated from from File::url(), a
// resource URL is currently not available.
'href' => file_create_url($normalization['uri'][0]['value']),
],
'type' => [
'href' => $this->baseUrl . '/rest/type/file/file',
],
$this->baseUrl . '/rest/relation/file/file/uid' => [
['href' => $this->baseUrl . '/user/' . $owner->id() . '?_format=hal_json'],
],
],
'_embedded' => [
$this->baseUrl . '/rest/relation/file/file/uid' => [
[
'_links' => [
'self' => [
'href' => $this->baseUrl . '/user/' . $owner->id() . '?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/user/user',
],
],
'uuid' => [
[
'value' => $owner->uuid(),
],
],
],
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return parent::getNormalizedPostEntity() + [
'_links' => [
'type' => [
'href' => $this->baseUrl . '/rest/type/media/camelids',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedCacheTags() {
return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:hal.settings']);
}
}

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\media\Functional\Hal;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group hal
*/
class MediaHalJsonBasicAuthTest extends MediaHalJsonAnonTest {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,19 @@
<?php
namespace Drupal\Tests\media\Functional\Hal;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group hal
*/
class MediaHalJsonCookieTest extends MediaHalJsonAnonTest {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,30 @@
<?php
namespace Drupal\Tests\media\Functional\Hal;
use Drupal\Tests\media\Functional\Rest\MediaTypeResourceTestBase;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group hal
*/
class MediaTypeHalJsonAnonTest extends MediaTypeResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
}

View file

@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\media\Functional\Hal;
use Drupal\Tests\media\Functional\Rest\MediaTypeResourceTestBase;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group hal
*/
class MediaTypeHalJsonBasicAuthTest extends MediaTypeResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal', 'basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\media\Functional\Hal;
use Drupal\Tests\media\Functional\Rest\MediaTypeResourceTestBase;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group hal
*/
class MediaTypeHalJsonCookieTest extends MediaTypeResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,174 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\media\Entity\Media;
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
/**
* Basic access tests for Media.
*
* @group media
*/
class MediaAccessTest extends MediaFunctionalTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* {@inheritdoc}
*/
public static $modules = [
'block',
'media_test_source',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// This is needed to provide the user cache context for a below assertion.
$this->drupalPlaceBlock('local_tasks_block');
}
/**
* Test some access control functionality.
*/
public function testMediaAccess() {
$assert_session = $this->assertSession();
$media_type = $this->createMediaType('test');
// Create media.
$media = Media::create([
'bundle' => $media_type->id(),
'name' => 'Unnamed',
]);
$media->save();
$user_media = Media::create([
'bundle' => $media_type->id(),
'name' => 'Unnamed',
'uid' => $this->nonAdminUser->id(),
]);
$user_media->save();
// We are logged in as admin, so test 'administer media' permission.
$this->drupalGet('media/add/' . $media_type->id());
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(200);
$this->drupalGet('media/' . $user_media->id());
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(200);
$this->drupalGet('media/' . $user_media->id() . '/edit');
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(200);
$this->drupalGet('media/' . $user_media->id() . '/delete');
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(200);
$this->drupalLogin($this->nonAdminUser);
/** @var \Drupal\user\RoleInterface $role */
$role = Role::load(RoleInterface::AUTHENTICATED_ID);
// Test 'view media' permission.
user_role_revoke_permissions($role->id(), ['view media']);
$this->drupalGet('media/' . $media->id());
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(403);
$access_result = $media->access('view', NULL, TRUE);
$this->assertSame("The 'view media' permission is required and the media item must be published.", $access_result->getReason());
$this->grantPermissions($role, ['view media']);
$this->drupalGet('media/' . $media->id());
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(200);
// Test 'create BUNDLE media' permission.
$this->drupalGet('media/add/' . $media_type->id());
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(403);
$permissions = ['create ' . $media_type->id() . ' media'];
$this->grantPermissions($role, $permissions);
$this->drupalGet('media/add/' . $media_type->id());
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(200);
user_role_revoke_permissions($role->id(), $permissions);
$role = Role::load(RoleInterface::AUTHENTICATED_ID);
// Test 'create media' permission.
$this->drupalGet('media/add/' . $media_type->id());
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(403);
$permissions = ['create media'];
$this->grantPermissions($role, $permissions);
$this->drupalGet('media/add/' . $media_type->id());
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(200);
user_role_revoke_permissions($role->id(), $permissions);
$role = Role::load(RoleInterface::AUTHENTICATED_ID);
// Test 'edit own BUNDLE media' and 'delete own BUNDLE media' permissions.
$this->drupalGet('media/' . $user_media->id() . '/edit');
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(403);
$this->drupalGet('media/' . $user_media->id() . '/delete');
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(403);
$permissions = [
'edit own ' . $user_media->bundle() . ' media',
'delete own ' . $user_media->bundle() . ' media',
];
$this->grantPermissions($role, $permissions);
$this->drupalGet('media/' . $user_media->id() . '/edit');
$this->assertCacheContext('user');
$assert_session->statusCodeEquals(200);
$this->drupalGet('media/' . $user_media->id() . '/delete');
$this->assertCacheContext('user');
$assert_session->statusCodeEquals(200);
user_role_revoke_permissions($role->id(), $permissions);
$role = Role::load(RoleInterface::AUTHENTICATED_ID);
// Test 'edit any BUNDLE media' and 'delete any BUNDLE media' permissions.
$this->drupalGet('media/' . $media->id() . '/edit');
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(403);
$this->drupalGet('media/' . $media->id() . '/delete');
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(403);
$permissions = [
'edit any ' . $media->bundle() . ' media',
'delete any ' . $media->bundle() . ' media',
];
$this->grantPermissions($role, $permissions);
$this->drupalGet('media/' . $media->id() . '/edit');
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(200);
$this->drupalGet('media/' . $media->id() . '/delete');
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(200);
// Test the 'access media overview' permission.
$this->grantPermissions($role, ['access content overview']);
$this->drupalGet('admin/content');
$assert_session->linkByHrefNotExists('/admin/content/media');
$this->assertCacheContext('user');
// Create a new role, which implicitly checks if the permission exists.
$mediaOverviewRole = $this->createRole(['access content overview', 'access media overview']);
$this->nonAdminUser->addRole($mediaOverviewRole);
$this->nonAdminUser->save();
$this->drupalGet('admin/content');
$assert_session->linkByHrefExists('/admin/content/media');
$this->clickLink('Media');
$this->assertCacheContext('user.permissions');
$assert_session->statusCodeEquals(200);
$assert_session->elementExists('css', '.view-media');
$assert_session->pageTextContains($this->loggedInUser->getDisplayName());
$assert_session->pageTextContains($this->nonAdminUser->getDisplayName());
$assert_session->linkByHrefExists('/media/' . $media->id());
$assert_session->linkByHrefExists('/media/' . $user_media->id());
}
}

View file

@ -0,0 +1,113 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\media\Entity\Media;
use Drupal\views\Views;
/**
* Tests a media bulk form.
*
* @group media
*/
class MediaBulkFormTest extends MediaFunctionalTestBase {
/**
* Modules to be enabled.
*
* @var array
*/
public static $modules = ['media_test_views'];
/**
* The test media type.
*
* @var \Drupal\media\MediaTypeInterface
*/
protected $testMediaType;
/**
* The test media items.
*
* @var \Drupal\media\MediaInterface[]
*/
protected $mediaItems;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->testMediaType = $this->createMediaType('test');
// Create some test media items.
$this->mediaItems = [];
for ($i = 1; $i <= 5; $i++) {
$media = Media::create([
'bundle' => $this->testMediaType->id(),
]);
$media->save();
$this->mediaItems[] = $media;
}
}
/**
* Tests the media bulk form.
*/
public function testBulkForm() {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
// Check that all created items are present in the test view.
$view = Views::getView('test_media_bulk_form');
$view->execute();
$this->assertSame($view->total_rows, 5);
// Check the operations are accessible to the logged in user.
$this->drupalGet('test-media-bulk-form');
// Current available actions: Delete, Save, Publish, Unpublish.
$available_actions = [
'media_delete_action',
'media_publish_action',
'media_save_action',
'media_unpublish_action',
];
foreach ($available_actions as $action_name) {
$assert_session->optionExists('action', $action_name);
}
// Test unpublishing in bulk.
$page->checkField('media_bulk_form[0]');
$page->checkField('media_bulk_form[1]');
$page->checkField('media_bulk_form[2]');
$page->selectFieldOption('action', 'media_unpublish_action');
$page->pressButton('Apply to selected items');
$assert_session->pageTextContains('Unpublish media was applied to 3 items');
$this->assertFalse($this->storage->loadUnchanged(1)->isPublished(), 'The unpublish action failed in some of the media items.');
$this->assertFalse($this->storage->loadUnchanged(2)->isPublished(), 'The unpublish action failed in some of the media items.');
$this->assertFalse($this->storage->loadUnchanged(3)->isPublished(), 'The unpublish action failed in some of the media items.');
// Test publishing in bulk.
$page->checkField('media_bulk_form[0]');
$page->checkField('media_bulk_form[1]');
$page->selectFieldOption('action', 'media_publish_action');
$page->pressButton('Apply to selected items');
$assert_session->pageTextContains('Publish media was applied to 2 items');
$this->assertTrue($this->storage->loadUnchanged(1)->isPublished(), 'The publish action failed in some of the media items.');
$this->assertTrue($this->storage->loadUnchanged(2)->isPublished(), 'The publish action failed in some of the media items.');
// Test deletion in bulk.
$page->checkField('media_bulk_form[0]');
$page->checkField('media_bulk_form[1]');
$page->selectFieldOption('action', 'media_delete_action');
$page->pressButton('Apply to selected items');
$assert_session->pageTextContains('Are you sure you want to delete these media items?');
$page->pressButton('Delete');
$assert_session->pageTextContains('Deleted 2 items.');
$this->assertNull($this->storage->loadUnchanged(1), 'Could not delete some of the media items.');
$this->assertNull($this->storage->loadUnchanged(2), 'Could not delete some of the media items.');
}
}

View file

@ -0,0 +1,63 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\Core\Entity\EntityInterface;
use Drupal\media\Entity\Media;
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
use Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase;
/**
* Tests the media items cache tags.
*
* @group media
*/
class MediaCacheTagsTest extends EntityWithUriCacheTagsTestBase {
use MediaTypeCreationTrait;
/**
* {@inheritdoc}
*/
public static $modules = [
'media',
'media_test_source',
];
/**
* {@inheritdoc}
*/
protected function createEntity() {
// Create a media type.
$mediaType = $this->createMediaType('test');
// Create a media item.
$media = Media::create([
'bundle' => $mediaType->id(),
'name' => 'Unnamed',
]);
$media->save();
return $media;
}
/**
* {@inheritdoc}
*/
protected function getAdditionalCacheContextsForEntity(EntityInterface $media) {
return ['timezone'];
}
/**
* {@inheritdoc}
*/
protected function getAdditionalCacheTagsForEntity(EntityInterface $media) {
// Each media item must have an author and a thumbnail.
return [
'user:' . $media->getOwnerId(),
'config:image.style.thumbnail',
'file:' . $media->get('thumbnail')->entity->id(),
];
}
}

View file

@ -0,0 +1,45 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\media\Entity\Media;
/**
* Tests views contextual links on media items.
*
* @group media
*/
class MediaContextualLinksTest extends MediaFunctionalTestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'contextual',
];
/**
* Tests contextual links.
*/
public function testMediaContextualLinks() {
// Create a media type.
$mediaType = $this->createMediaType('test');
// Create a media item.
$media = Media::create([
'bundle' => $mediaType->id(),
'name' => 'Unnamed',
]);
$media->save();
$user = $this->drupalCreateUser([
'administer media',
'access contextual links',
]);
$this->drupalLogin($user);
$this->drupalGet('media/' . $media->id());
$this->assertSession()->elementAttributeContains('css', 'div[data-contextual-id]', 'data-contextual-id', 'media:media=' . $media->id() . ':');
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
/**
* Base class for Media functional tests.
*/
abstract class MediaFunctionalTestBase extends BrowserTestBase {
use MediaFunctionalTestTrait;
use MediaTypeCreationTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'system',
'node',
'field_ui',
'views_ui',
'media',
'media_test_source',
];
}

View file

@ -0,0 +1,39 @@
<?php
namespace Drupal\Tests\media\Functional;
@trigger_error(__NAMESPACE__ . '\MediaFunctionalTestCreateMediaTypeTrait is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use \Drupal\Tests\media\Traits\MediaTypeCreationTrait instead. See https://www.drupal.org/node/2981614.', E_USER_DEPRECATED);
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
/**
* Trait with helpers for Media functional tests.
*
* @deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use
* \Drupal\Tests\media\Traits\MediaTypeCreationTrait instead.
*
* @see https://www.drupal.org/node/2981614
*/
trait MediaFunctionalTestCreateMediaTypeTrait {
use MediaTypeCreationTrait {
createMediaType as traitCreateMediaType;
}
/**
* Creates a media type.
*
* @param array $values
* The media type values.
* @param string $source
* (optional) The media source plugin that is responsible for additional
* logic related to this media type. Defaults to 'test'.
*
* @return \Drupal\media\MediaTypeInterface
* A newly created media type.
*/
protected function createMediaType(array $values = [], $source = 'test') {
return $this->traitCreateMediaType($source, $values);
}
}

View file

@ -0,0 +1,71 @@
<?php
namespace Drupal\Tests\media\Functional;
/**
* Trait with helpers for Media functional tests.
*/
trait MediaFunctionalTestTrait {
/**
* Permissions for the admin user that will be logged-in for test.
*
* @var array
*/
protected static $adminUserPermissions = [
// Media module permissions.
'access media overview',
'administer media',
'administer media fields',
'administer media form display',
'administer media display',
'administer media types',
'view media',
// Other permissions.
'administer views',
'access content overview',
'view all revisions',
'administer content types',
'administer node fields',
'administer node form display',
'administer node display',
'bypass node access',
];
/**
* An admin test user account.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $adminUser;
/**
* A non-admin test user account.
*
* @var \Drupal\user\UserInterface
*/
protected $nonAdminUser;
/**
* The storage service.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $storage;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Have two users ready to be used in tests.
$this->adminUser = $this->drupalCreateUser(static::$adminUserPermissions);
$this->nonAdminUser = $this->drupalCreateUser([]);
// Start off logged in as admin.
$this->drupalLogin($this->adminUser);
$this->storage = $this->container->get('entity_type.manager')->getStorage('media');
}
}

View file

@ -0,0 +1,44 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests media Install / Uninstall logic.
*
* @group media
*/
class MediaInstallTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['media'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalLogin($this->drupalCreateUser(['administer modules']));
}
/**
* Tests reinstalling after being uninstalled.
*/
public function testReinstallAfterUninstall() {
$page = $this->getSession()->getPage();
$assert_session = $this->assertSession();
// Uninstall the media module.
$this->container->get('module_installer')->uninstall(['media'], FALSE);
$this->drupalGet('/admin/modules');
$page->checkField('modules[media][enable]');
$page->pressButton('Install');
$assert_session->pageTextNotContains('could not be moved/copied because a file by that name already exists in the destination directory');
$assert_session->pageTextContains('Module Media has been enabled');
}
}

View file

@ -0,0 +1,147 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\media\Entity\Media;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
/**
* Tests the Media overview page.
*
* @group media
*/
class MediaOverviewPageTest extends MediaFunctionalTestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalLogin($this->nonAdminUser);
}
/**
* Test that the Media overview page (/admin/content/media).
*/
public function testMediaOverviewPage() {
$assert_session = $this->assertSession();
// Check the view exists, is access-restricted, and some defaults are there.
$this->drupalGet('/admin/content/media');
$assert_session->statusCodeEquals(403);
$role = Role::load(RoleInterface::AUTHENTICATED_ID);
$this->grantPermissions($role, ['access media overview']);
$this->drupalGet('/admin/content/media');
$assert_session->statusCodeEquals(200);
$assert_session->titleEquals('Media | Drupal');
$assert_session->fieldExists('Media name');
$assert_session->selectExists('type');
$assert_session->selectExists('status');
$assert_session->selectExists('langcode');
$assert_session->buttonExists('Filter');
$header = $assert_session->elementExists('css', 'th#view-thumbnail-target-id-table-column');
$this->assertSame('Thumbnail', $header->getText());
$header = $assert_session->elementExists('css', 'th#view-name-table-column');
$this->assertSame('Media name', $header->getText());
$header = $assert_session->elementExists('css', 'th#view-bundle-table-column');
$this->assertSame('Type', $header->getText());
$header = $assert_session->elementExists('css', 'th#view-uid-table-column');
$this->assertSame('Author', $header->getText());
$header = $assert_session->elementExists('css', 'th#view-status-table-column');
$this->assertSame('Status', $header->getText());
$header = $assert_session->elementExists('css', 'th#view-changed-table-column');
$this->assertSame('Updated Sort ascending', $header->getText());
$header = $assert_session->elementExists('css', 'th#view-operations-table-column');
$this->assertSame('Operations', $header->getText());
$assert_session->pageTextContains('No media available.');
// Create some content for the view.
$media_type1 = $this->createMediaType('test');
$media_type2 = $this->createMediaType('test');
$media1 = Media::create([
'bundle' => $media_type1->id(),
'name' => 'Media 1',
'uid' => $this->adminUser->id(),
]);
$media1->save();
$media2 = Media::create([
'bundle' => $media_type2->id(),
'name' => 'Media 2',
'uid' => $this->adminUser->id(),
'status' => FALSE,
]);
$media2->save();
$media3 = Media::create([
'bundle' => $media_type1->id(),
'name' => 'Media 3',
'uid' => $this->nonAdminUser->id(),
]);
$media3->save();
// Verify the view is now correctly populated.
$this->grantPermissions($role, [
'view media',
'update any media',
'delete any media',
]);
$this->drupalGet('/admin/content/media');
$row1 = $assert_session->elementExists('css', 'table tbody tr:nth-child(1)');
$row2 = $assert_session->elementExists('css', 'table tbody tr:nth-child(2)');
$row3 = $assert_session->elementExists('css', 'table tbody tr:nth-child(3)');
// Media thumbnails.
$assert_session->elementExists('css', 'td.views-field-thumbnail__target-id img', $row1);
$assert_session->elementExists('css', 'td.views-field-thumbnail__target-id img', $row2);
$assert_session->elementExists('css', 'td.views-field-thumbnail__target-id img', $row3);
// Media names.
$name1 = $assert_session->elementExists('css', 'td.views-field-name a', $row1);
$this->assertSame($media1->label(), $name1->getText());
$name2 = $assert_session->elementExists('css', 'td.views-field-name a', $row2);
$this->assertSame($media2->label(), $name2->getText());
$name3 = $assert_session->elementExists('css', 'td.views-field-name a', $row3);
$this->assertSame($media3->label(), $name3->getText());
$assert_session->linkByHrefExists('/media/' . $media1->id());
$assert_session->linkByHrefExists('/media/' . $media2->id());
$assert_session->linkByHrefExists('/media/' . $media3->id());
// Media types.
$type_element1 = $assert_session->elementExists('css', 'td.views-field-bundle', $row1);
$this->assertSame($media_type1->label(), $type_element1->getText());
$type_element2 = $assert_session->elementExists('css', 'td.views-field-bundle', $row2);
$this->assertSame($media_type2->label(), $type_element2->getText());
$type_element3 = $assert_session->elementExists('css', 'td.views-field-bundle', $row3);
$this->assertSame($media_type1->label(), $type_element3->getText());
// Media authors.
$author_element1 = $assert_session->elementExists('css', 'td.views-field-uid', $row1);
$this->assertSame($this->adminUser->getDisplayName(), $author_element1->getText());
$author_element2 = $assert_session->elementExists('css', 'td.views-field-uid', $row2);
$this->assertSame($this->adminUser->getDisplayName(), $author_element2->getText());
$author_element3 = $assert_session->elementExists('css', 'td.views-field-uid', $row3);
$this->assertSame($this->nonAdminUser->getDisplayName(), $author_element3->getText());
// Media publishing status.
$status_element1 = $assert_session->elementExists('css', 'td.views-field-status', $row1);
$this->assertSame('Published', $status_element1->getText());
$status_element2 = $assert_session->elementExists('css', 'td.views-field-status', $row2);
$this->assertSame('Unpublished', $status_element2->getText());
$status_element3 = $assert_session->elementExists('css', 'td.views-field-status', $row3);
$this->assertSame('Published', $status_element3->getText());
// Timestamp.
$expected = \Drupal::service('date.formatter')->format($media1->getChangedTime(), 'short');
$changed_element1 = $assert_session->elementExists('css', 'td.views-field-changed', $row1);
$this->assertSame($expected, $changed_element1->getText());
// Operations.
$edit_link1 = $assert_session->elementExists('css', 'td.views-field-operations li.edit a', $row1);
$this->assertSame('Edit', $edit_link1->getText());
$assert_session->linkByHrefExists('/media/' . $media1->id() . '/edit');
$delete_link1 = $assert_session->elementExists('css', 'td.views-field-operations li.delete a', $row1);
$this->assertSame('Delete', $delete_link1->getText());
$assert_session->linkByHrefExists('/media/' . $media1->id() . '/delete');
}
}

View file

@ -0,0 +1,204 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\Core\Entity\EntityInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\media\MediaInterface;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
/**
* Tests the revisionability of media entities.
*
* @group media
*/
class MediaRevisionTest extends MediaFunctionalTestBase {
/**
* Checks media revision operations.
*/
public function testRevisions() {
$assert = $this->assertSession();
/** @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage $media_storage */
$media_storage = $this->container->get('entity.manager')->getStorage('media');
// Create a media type and media item.
$media_type = $this->createMediaType('test');
$media = $media_storage->create([
'bundle' => $media_type->id(),
'name' => 'Unnamed',
]);
$media->save();
// You can't access the revision page when there is only 1 revision.
$this->drupalGet('media/' . $media->id() . '/revisions/' . $media->getRevisionId() . '/view');
$assert->statusCodeEquals(403);
// Create some revisions.
$media_revisions = [];
$media_revisions[] = clone $media;
$revision_count = 3;
for ($i = 0; $i < $revision_count; $i++) {
$media->revision_log = $this->randomMachineName(32);
$media = $this->createMediaRevision($media);
$media_revisions[] = clone $media;
}
// Get the last revision for simple checks.
/** @var \Drupal\media\MediaInterface $media */
$media = end($media_revisions);
// Test permissions.
$this->drupalLogin($this->nonAdminUser);
/** @var \Drupal\user\RoleInterface $role */
$role = Role::load(RoleInterface::AUTHENTICATED_ID);
// Test 'view all media revisions' permission ('view media' permission is
// needed as well).
user_role_revoke_permissions($role->id(), ['view media', 'view all media revisions']);
$this->drupalGet('media/' . $media->id() . '/revisions/' . $media->getRevisionId() . '/view');
$assert->statusCodeEquals(403);
$this->grantPermissions($role, ['view media', 'view all media revisions']);
$this->drupalGet('media/' . $media->id() . '/revisions/' . $media->getRevisionId() . '/view');
$assert->statusCodeEquals(200);
// Confirm the revision page shows the correct title.
$assert->pageTextContains($media->getName());
// Confirm that the last revision is the default revision.
$this->assertTrue($media->isDefaultRevision(), 'Last revision is the default.');
}
/**
* Tests creating revisions of a File media item.
*/
public function testFileMediaRevision() {
$assert = $this->assertSession();
$uri = 'temporary://foo.txt';
file_put_contents($uri, $this->randomString(128));
$this->createMediaType('file', ['id' => 'file', 'new_revision' => TRUE]);
// Create a media item.
$this->drupalGet('/media/add/file');
$page = $this->getSession()->getPage();
$page->fillField('Name', 'Foobar');
$page->attachFileToField('File', $this->container->get('file_system')->realpath($uri));
$page->pressButton('Save');
$assert->addressEquals('admin/content/media');
// The media item was just created, so it should only have one revision.
$media = $this->container
->get('entity_type.manager')
->getStorage('media')
->load(1);
$this->assertRevisionCount($media, 1);
// If we edit the item, we should get a new revision.
$this->drupalGet('/media/1/edit');
$assert->checkboxChecked('Create new revision');
$page = $this->getSession()->getPage();
$page->fillField('Name', 'Foobaz');
$page->pressButton('Save');
$this->assertRevisionCount($media, 2);
// Confirm the correct revision title appears on "view revisions" page.
$media = $this->container->get('entity_type.manager')
->getStorage('media')
->loadUnchanged(1);
$this->drupalGet("media/" . $media->id() . "/revisions/" . $media->getRevisionId() . "/view");
$assert->pageTextContains('Foobaz');
}
/**
* Tests creating revisions of a Image media item.
*/
public function testImageMediaRevision() {
$assert = $this->assertSession();
$this->createMediaType('image', ['id' => 'image', 'new_revision' => TRUE]);
/** @var \Drupal\field\FieldConfigInterface $field */
// Disable the alt text field, because this is not a JavaScript test and
// the alt text field will therefore not appear without a full page refresh.
$field = FieldConfig::load('media.image.field_media_image');
$settings = $field->getSettings();
$settings['alt_field'] = FALSE;
$settings['alt_field_required'] = FALSE;
$field->set('settings', $settings);
$field->save();
// Create a media item.
$this->drupalGet('/media/add/image');
$page = $this->getSession()->getPage();
$page->fillField('Name', 'Foobar');
$page->attachFileToField('Image', $this->root . '/core/modules/media/tests/fixtures/example_1.jpeg');
$page->pressButton('Save');
$assert->addressEquals('admin/content/media');
// The media item was just created, so it should only have one revision.
$media = $this->container
->get('entity_type.manager')
->getStorage('media')
->load(1);
$this->assertRevisionCount($media, 1);
// If we edit the item, we should get a new revision.
$this->drupalGet('/media/1/edit');
$assert->checkboxChecked('Create new revision');
$page = $this->getSession()->getPage();
$page->fillField('Name', 'Foobaz');
$page->pressButton('Save');
$this->assertRevisionCount($media, 2);
// Confirm the correct revision title appears on "view revisions" page.
$media = $this->container->get('entity_type.manager')
->getStorage('media')
->loadUnchanged(1);
$this->drupalGet("media/" . $media->id() . "/revisions/" . $media->getRevisionId() . "/view");
$assert->pageTextContains('Foobaz');
}
/**
* Creates a new revision for a given media item.
*
* @param \Drupal\media\MediaInterface $media
* A media object.
*
* @return \Drupal\media\MediaInterface
* A media object with up to date revision information.
*/
protected function createMediaRevision(MediaInterface $media) {
$media->setName($this->randomMachineName());
$media->setNewRevision();
$media->save();
return $media;
}
/**
* Asserts that an entity has a certain number of revisions.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity in question.
* @param int $expected_revisions
* The expected number of revisions.
*/
protected function assertRevisionCount(EntityInterface $entity, $expected_revisions) {
$entity_type = $entity->getEntityType();
$count = $this->container
->get('entity_type.manager')
->getStorage($entity_type->id())
->getQuery()
->count()
->allRevisions()
->condition($entity_type->getKey('id'), $entity->id())
->execute();
$this->assertSame($expected_revisions, (int) $count);
}
}

View file

@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\media\Functional;
/**
* Testing the media settings.
*
* @group media
*/
class MediaSettingsTest extends MediaFunctionalTestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalLogin($this->createUser(['administer site configuration']));
}
/**
* Test that media warning appears if oEmbed media types exists.
*/
public function testStatusPage() {
$assert_session = $this->assertSession();
$this->drupalGet('admin/reports/status');
$assert_session->pageTextNotContains('It is potentially insecure to display oEmbed content in a frame');
$this->createMediaType('oembed:video');
$this->drupalGet('admin/reports/status');
$assert_session->pageTextContains('It is potentially insecure to display oEmbed content in a frame');
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\field\Entity\FieldConfig;
/**
* Tests the file media source.
*
* @group media
*/
class MediaSourceFileTest extends MediaFunctionalTestBase {
/**
* Test that it's possible to change the allowed file extensions.
*/
public function testSourceFieldSettingsEditing() {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$media_type = $this->createMediaType('file');
$media_type_id = $media_type->id();
$this->assertSame('txt doc docx pdf', FieldConfig::load("media.$media_type_id.field_media_file")->get('settings')['file_extensions']);
$this->drupalGet("admin/structure/media/manage/$media_type_id/fields/media.$media_type_id.field_media_file");
// File extension field exists.
$assert_session->fieldExists('Allowed file extensions');
// Add another extension.
$page->fillField('settings[file_extensions]', 'txt, doc, docx, pdf, odt');
$page->pressButton('Save settings');
$this->drupalGet("admin/structure/media/manage/$media_type_id/fields/media.$media_type_id.field_media_file");
// Verify that new extension is present.
$assert_session->fieldValueEquals('settings[file_extensions]', 'txt, doc, docx, pdf, odt');
$this->assertSame('txt doc docx pdf odt', FieldConfig::load("media.$media_type_id.field_media_file")->get('settings')['file_extensions']);
}
/**
* Ensure source field deletion is not possible.
*/
public function testPreventSourceFieldDeletion() {
$media_type = $this->createMediaType('file');
$media_type_id = $media_type->id();
$this->drupalGet("admin/structure/media/manage/$media_type_id/fields/media.$media_type_id.field_media_file/delete");
$this->assertSession()->statusCodeEquals(403);
}
}

View file

@ -0,0 +1,45 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\media\Entity\Media;
/**
* Tests media template suggestions.
*
* @group media
*/
class MediaTemplateSuggestionsTest extends MediaFunctionalTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['media'];
/**
* Tests template suggestions from media_theme_suggestions_media().
*/
public function testMediaThemeHookSuggestions() {
$media_type = $this->createMediaType('test', [
'queue_thumbnail_downloads' => FALSE,
]);
// Create media item to be rendered.
$media = Media::create([
'bundle' => $media_type->id(),
'name' => 'Unnamed',
]);
$media->save();
$view_mode = 'full';
// Simulate theming of the media item.
$build = \Drupal::entityTypeManager()->getViewBuilder('media')->view($media, $view_mode);
$variables['elements'] = $build;
$suggestions = \Drupal::moduleHandler()->invokeAll('theme_suggestions_media', [$variables]);
$this->assertSame($suggestions, ['media__full', 'media__' . $media_type->id(), 'media__' . $media_type->id() . '__full', 'media__source_' . $media_type->getSource()->getPluginId()], 'Found expected media suggestions.');
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\Tests\content_translation\Functional\ContentTranslationUITestBase;
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
/**
* Tests the Media Translation UI.
*
* @group media
*/
class MediaTranslationUITest extends ContentTranslationUITestBase {
use MediaTypeCreationTrait;
/**
* {inheritdoc}
*/
protected $defaultCacheContexts = [
'languages:language_interface',
'theme',
'timezone',
'url.query_args:_wrapper_format',
'user.permissions',
];
/**
* {inheritdoc}
*/
public static $modules = [
'language',
'content_translation',
'media',
'media_test_source',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->entityTypeId = 'media';
$this->bundle = 'test';
parent::setUp();
}
/**
* {@inheritdoc}
*/
public function setupBundle() {
$this->createMediaType('test', [
'id' => $this->bundle,
'queue_thumbnail_downloads' => FALSE,
]);
}
/**
* {@inheritdoc}
*/
protected function getTranslatorPermissions() {
return array_merge(parent::getTranslatorPermissions(), [
'administer media',
'edit any test media',
]);
}
/**
* {@inheritdoc}
*/
protected function getEditorPermissions() {
return ['administer media', 'create test media'];
}
/**
* {@inheritdoc}
*/
protected function getAdministratorPermissions() {
return array_merge(parent::getAdministratorPermissions(), [
'access administration pages',
'administer media types',
'access media overview',
'administer languages',
]);
}
/**
* {@inheritdoc}
*/
protected function getNewEntityValues($langcode) {
return [
'name' => [['value' => $this->randomMachineName()]],
'field_media_test' => [['value' => $this->randomMachineName()]],
] + parent::getNewEntityValues($langcode);
}
}

View file

@ -0,0 +1,583 @@
<?php
namespace Drupal\Tests\media\Functional;
use Behat\Mink\Element\NodeElement;
use Drupal\media\Entity\Media;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Ensures that media UI works correctly.
*
* @group media
*/
class MediaUiFunctionalTest extends MediaFunctionalTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'block',
'media_test_source',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('local_actions_block');
$this->drupalPlaceBlock('local_tasks_block');
}
/**
* Tests the media actions (add/edit/delete).
*/
public function testMediaWithOnlyOneMediaType() {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$media_type = $this->createMediaType('test', [
'queue_thumbnail_downloads' => FALSE,
]);
$this->drupalGet('media/add');
$assert_session->statusCodeEquals(200);
$assert_session->addressEquals('media/add/' . $media_type->id());
$assert_session->elementNotExists('css', '#edit-revision');
// Tests media add form.
$media_name = $this->randomMachineName();
$page->fillField('name[0][value]', $media_name);
$revision_log_message = $this->randomString();
$page->fillField('revision_log_message[0][value]', $revision_log_message);
$source_field = $this->randomString();
$page->fillField('field_media_test[0][value]', $source_field);
$page->pressButton('Save');
$media_id = $this->container->get('entity_type.manager')
->getStorage('media')
->getQuery()
->execute();
$media_id = reset($media_id);
/** @var \Drupal\media\MediaInterface $media */
$media = $this->container->get('entity_type.manager')
->getStorage('media')
->loadUnchanged($media_id);
$this->assertSame($media->getRevisionLogMessage(), $revision_log_message);
$this->assertSame($media->getName(), $media_name);
$this->drupalGet('media/' . $media_id);
$assert_session->titleEquals($media_name . ' | Drupal');
// Tests media edit form.
$media_type->setNewRevision(FALSE);
$media_type->save();
$media_name2 = $this->randomMachineName();
$this->drupalGet('media/' . $media_id . '/edit');
$assert_session->checkboxNotChecked('edit-revision');
$media_name = $this->randomMachineName();
$page->fillField('name[0][value]', $media_name2);
$page->pressButton('Save');
/** @var \Drupal\media\MediaInterface $media */
$media = $this->container->get('entity_type.manager')
->getStorage('media')
->loadUnchanged($media_id);
$this->assertSame($media->getName(), $media_name2);
$this->drupalGet('media/' . $media_id);
$assert_session->titleEquals($media_name2 . ' | Drupal');
// Test that there is no empty vertical tabs element, if the container is
// empty (see #2750697).
// Make the "Publisher ID" and "Created" fields hidden.
$this->drupalGet('/admin/structure/media/manage/' . $media_type->id() . '/form-display');
$page->selectFieldOption('fields[created][parent]', 'hidden');
$page->selectFieldOption('fields[uid][parent]', 'hidden');
$page->pressButton('Save');
// Assure we are testing with a user without permission to manage revisions.
$this->drupalLogin($this->nonAdminUser);
// Check the container is not present.
$this->drupalGet('media/' . $media_id . '/edit');
$assert_session->elementNotExists('css', 'input.vertical-tabs__active-tab');
// Continue testing as admin.
$this->drupalLogin($this->adminUser);
// Enable revisions by default.
$previous_revision_id = $media->getRevisionId();
$media_type->setNewRevision(TRUE);
$media_type->save();
$this->drupalGet('media/' . $media_id . '/edit');
$assert_session->checkboxChecked('edit-revision');
$page->fillField('name[0][value]', $media_name);
$page->fillField('revision_log_message[0][value]', $revision_log_message);
$page->pressButton('Save');
$this->drupalGet('media/' . $media_id);
$assert_session->titleEquals($media_name . ' | Drupal');
/** @var \Drupal\media\MediaInterface $media */
$media = $this->container->get('entity_type.manager')
->getStorage('media')
->loadUnchanged($media_id);
$this->assertSame($media->getRevisionLogMessage(), $revision_log_message);
$this->assertNotEquals($previous_revision_id, $media->getRevisionId());
// Test the status checkbox.
$this->drupalGet('media/' . $media_id . '/edit');
$page->uncheckField('status[value]');
$page->pressButton('Save');
/** @var \Drupal\media\MediaInterface $media */
$media = $this->container->get('entity_type.manager')
->getStorage('media')
->loadUnchanged($media_id);
$this->assertFalse($media->isPublished());
// Tests media delete form.
$this->drupalGet('media/' . $media_id . '/edit');
$page->clickLink('Delete');
$assert_session->pageTextContains('This action cannot be undone');
$page->pressButton('Delete');
$media_id = \Drupal::entityQuery('media')->execute();
$this->assertFalse($media_id);
}
/**
* Tests the "media/add" and "media/mid" pages.
*
* Tests if the "media/add" page gives you a selecting option if there are
* multiple media types available.
*/
public function testMediaWithMultipleMediaTypes() {
$assert_session = $this->assertSession();
// Tests and creates the first media type.
$first_media_type = $this->createMediaType('test', ['description' => $this->randomMachineName()]);
// Test and create a second media type.
$second_media_type = $this->createMediaType('test', ['description' => $this->randomMachineName()]);
// Test if media/add displays two media type options.
$this->drupalGet('media/add');
// Checks for the first media type.
$assert_session->pageTextContains($first_media_type->label());
$assert_session->pageTextContains($first_media_type->getDescription());
// Checks for the second media type.
$assert_session->pageTextContains($second_media_type->label());
$assert_session->pageTextContains($second_media_type->getDescription());
// Continue testing media type filter.
$first_media_item = Media::create(['bundle' => $first_media_type->id()]);
$first_media_item->save();
$second_media_item = Media::create(['bundle' => $second_media_type->id()]);
$second_media_item->save();
// Go to first media item.
$this->drupalGet('media/' . $first_media_item->id());
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains($first_media_item->getName());
$assert_session->elementsCount('css', '.media--view-mode-full', 1);
// Go to second media item.
$this->drupalGet('media/' . $second_media_item->id());
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains($second_media_item->getName());
}
/**
* Test that media in ER fields use the Rendered Entity formatter by default.
*/
public function testRenderedEntityReferencedMedia() {
$page = $this->getSession()->getPage();
$assert_session = $this->assertSession();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Page']);
$this->drupalGet('/admin/structure/types/manage/page/fields/add-field');
$page->selectFieldOption('new_storage_type', 'field_ui:entity_reference:media');
$page->fillField('label', 'Foo field');
$page->fillField('field_name', 'foo_field');
$page->pressButton('Save and continue');
$this->drupalGet('/admin/structure/types/manage/page/display');
$assert_session->fieldValueEquals('fields[field_foo_field][type]', 'entity_reference_entity_view');
}
/**
* Data provider for testMediaReferenceWidget().
*
* @return array[]
* Test data. See testMediaReferenceWidget() for the child array structure.
*/
public function providerTestMediaReferenceWidget() {
return [
// Single-value fields with a single media type and the default widget:
// - The user can create and list the media.
'single_value:single_type:create_list' => [1, [TRUE], TRUE],
// - The user can list but not create the media.
'single_value:single_type:list' => [1, [FALSE], TRUE],
// - The user can create but not list the media.
'single_value:single_type:create' => [1, [TRUE], FALSE],
// - The user can neither create nor list the media.
'single_value:single_type' => [1, [FALSE], FALSE],
// Single-value fields with the tags-style widget:
// - The user can create and list the media.
'single_value:single_type:create_list:tags' => [1, [TRUE], TRUE, 'entity_reference_autocomplete_tags'],
// - The user can list but not create the media.
'single_value:single_type:list:tags' => [1, [FALSE], TRUE, 'entity_reference_autocomplete_tags'],
// - The user can create but not list the media.
'single_value:single_type:create:tags' => [1, [TRUE], FALSE, 'entity_reference_autocomplete_tags'],
// - The user can neither create nor list the media.
'single_value:single_type:tags' => [1, [FALSE], FALSE, 'entity_reference_autocomplete_tags'],
// Single-value fields with two media types:
// - The user can create both types.
'single_value:two_type:create2_list' => [1, [TRUE, TRUE], TRUE],
// - The user can create only one type.
'single_value:two_type:create1_list' => [1, [TRUE, FALSE], TRUE],
// - The user cannot create either type.
'single_value:two_type:list' => [1, [FALSE, FALSE], TRUE],
// Multiple-value field with a cardinality of 3, with media the user can
// create and list.
'multi_value:single_type:create_list' => [3, [TRUE], TRUE],
// The same, with the tags field.
'multi-value:single_type:create_list:tags' => [3, [TRUE], TRUE, 'entity_reference_autocomplete_tags'],
// Unlimited value field.
'unlimited_value:single_type:create_list' => [FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, [TRUE], TRUE],
// Unlimited value field with the tags widget.
'unlimited_value:single_type:create_list' => [FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, [TRUE], TRUE, 'entity_reference_autocomplete_tags'],
];
}
/**
* Tests the default autocomplete widgets for media reference fields.
*
* @param int $cardinality
* The field cardinality.
* @param bool[] $media_type_create_access
* An array of booleans indicating whether to grant the test user create
* access for each media type. A media type is created automatically for
* each; for example, an array [TRUE, FALSE] would create two media types,
* one that allows the user to create media and a second that does not.
* @param bool $list_access
* Whether to grant the test user access to list media.
*
* @see media_field_widget_entity_reference_autocomplete_form_alter()
* @see media_field_widget_multiple_entity_reference_autocomplete_form_alter()
*
* @dataProvider providerTestMediaReferenceWidget
*/
public function testMediaReferenceWidget($cardinality, array $media_type_create_access, $list_access, $widget_id = 'entity_reference_autocomplete') {
$assert_session = $this->assertSession();
// Create two content types.
$non_media_content_type = $this->createContentType();
$content_type = $this->createContentType();
// Create some media types.
$media_types = [];
$permissions = [];
$create_media_types = [];
foreach ($media_type_create_access as $id => $access) {
if ($access) {
$create_media_types[] = "media_type_$id";
$permissions[] = "create media_type_$id media";
}
$this->createMediaType('test', [
'id' => "media_type_$id",
'label' => "media_type_$id",
]);
$media_types["media_type_$id"] = "media_type_$id";
}
// Create a user that can create content of the type, with other
// permissions as given by the data provider.
$permissions[] = "create {$content_type->id()} content";
if ($list_access) {
$permissions[] = "access media overview";
}
$test_user = $this->drupalCreateUser($permissions);
// Create a non-media entity reference.
$non_media_storage = FieldStorageConfig::create([
'field_name' => 'field_not_a_media_field',
'entity_type' => 'node',
'type' => 'entity_reference',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
'settings' => [
'target_type' => 'node',
],
]);
$non_media_storage->save();
$non_media_field = FieldConfig::create([
'label' => 'No media here!',
'field_storage' => $non_media_storage,
'entity_type' => 'node',
'bundle' => $non_media_content_type->id(),
'settings' => [
'handler' => 'default',
'handler_settings' => [
'target_bundles' => [
$non_media_content_type->id() => $non_media_content_type->id(),
],
],
],
]);
$non_media_field->save();
\Drupal::entityTypeManager()
->getStorage('entity_form_display')
->load('node.' . $non_media_content_type->id() . '.default')
->setComponent('field_not_a_media_field', [
'type' => $widget_id,
])
->save();
// Create a media field through the user interface to ensure that the
// help text handling does not break the default value entry on the field
// settings form.
// Using drupalPostForm() to avoid dealing with JavaScript on the previous
// page in the field creation.
$edit = [
'new_storage_type' => 'field_ui:entity_reference:media',
'label' => "Media (cardinality $cardinality)",
'field_name' => 'media_reference',
];
$this->drupalPostForm("admin/structure/types/manage/{$content_type->id()}/fields/add-field", $edit, 'Save and continue');
$edit = [];
foreach ($media_types as $type) {
$edit["settings[handler_settings][target_bundles][$type]"] = TRUE;
}
$this->drupalPostForm("admin/structure/types/manage/{$content_type->id()}/fields/node.{$content_type->id()}.field_media_reference", $edit, "Save settings");
\Drupal::entityTypeManager()
->getStorage('entity_form_display')
->load('node.' . $content_type->id() . '.default')
->setComponent('field_media_reference', [
'type' => $widget_id,
])
->save();
// Some of the expected texts.
$create_help = 'Create your media on the media add page (opens a new window), then add it by name to the field below.';
$list_text = 'See the media list (opens a new window) to help locate media.';
$use_help = 'Type part of the media name.';
$create_header = "Create new media";
$use_header = "Use existing media";
// First check that none of the help texts are on the non-media content.
$this->drupalGet("/node/add/{$non_media_content_type->id()}");
$this->assertNoHelpTexts([
$create_header,
$create_help,
$use_header,
$use_help,
$list_text,
'Allowed media types:',
]);
// Now, check that the widget displays the expected help text under the
// given conditions for the test user.
$this->drupalLogin($test_user);
$this->drupalGet("/node/add/{$content_type->id()}");
// Specific expected help texts for the media field.
$create_header = "Create new media";
$use_header = "Use existing media";
$type_list = 'Allowed media types: ' . implode(", ", array_keys($media_types));
$fieldset_selector = '#edit-field-media-reference-wrapper fieldset';
$fieldset = $assert_session->elementExists('css', $fieldset_selector);
$this->assertSame("Media (cardinality $cardinality)", $assert_session->elementExists('css', 'legend', $fieldset)->getText());
// Assert text that should be displayed regardless of other access.
$this->assertHelpTexts([$use_header, $use_help, $type_list], $fieldset_selector);
// The entire section for creating new media should only be displayed if
// the user can create at least one media of the type.
if ($create_media_types) {
if (count($create_media_types) === 1) {
$url = Url::fromRoute('entity.media.add_form')->setRouteParameter('media_type', $create_media_types[0]);
}
else {
$url = Url::fromRoute('entity.media.add_page');
}
$this->assertHelpTexts([$create_header, $create_help], $fieldset_selector);
$this->assertHelpLink(
$fieldset,
'media add page',
[
'target' => '_blank',
'href' => $url->toString(),
]
);
}
else {
$this->assertNoHelpTexts([$create_header, $create_help]);
$this->assertNoHelpLink($fieldset, 'media add page');
}
if ($list_access) {
$this->assertHelpTexts([$list_text], $fieldset_selector);
$this->assertHelpLink(
$fieldset,
'media list',
[
'target' => '_blank',
'href' => Url::fromRoute('entity.media.collection')->toString(),
]
);
}
else {
$this->assertNoHelpTexts([$list_text]);
$this->assertNoHelpLink($fieldset, 'media list');
}
}
/**
* Tests the redirect URL after creating a media item.
*/
public function testMediaCreateRedirect() {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$this->createMediaType('test', [
'queue_thumbnail_downloads' => FALSE,
]);
// Test a redirect to the media canonical URL for a user without the 'access
// media overview' permission.
$this->drupalLogin($this->drupalCreateUser([
'view media',
'create media',
]));
$this->drupalGet('media/add');
$page->fillField('name[0][value]', $this->randomMachineName());
$page->fillField('field_media_test[0][value]', $this->randomString());
$page->pressButton('Save');
$media_id = $this->container->get('entity_type.manager')
->getStorage('media')
->getQuery()
->execute();
$media_id = reset($media_id);
$assert_session->addressEquals('media/' . $media_id);
// Test a redirect to the media overview for a user with the 'access media
// overview' permission.
$this->drupalLogin($this->drupalCreateUser([
'view media',
'create media',
'access media overview',
]));
$this->drupalGet('media/add');
$page->fillField('name[0][value]', $this->randomMachineName());
$page->fillField('field_media_test[0][value]', $this->randomString());
$page->pressButton('Save');
$assert_session->addressEquals('admin/content/media');
}
/**
* Asserts that the given texts are present exactly once.
*
* @param string[] $texts
* A list of the help texts to check.
* @param string $selector
* (optional) The selector to search.
*/
public function assertHelpTexts(array $texts, $selector = '') {
$assert_session = $this->assertSession();
foreach ($texts as $text) {
// We only want to escape single quotes, so use str_replace() rather than
// addslashes().
$text = str_replace("'", "\'", $text);
if ($selector) {
$assert_session->elementsCount('css', $selector . ":contains('$text')", 1);
}
else {
$assert_session->pageTextContains($text);
}
}
}
/**
* Asserts that none of the given texts are present.
*
* @param string[] $texts
* A list of the help texts to check.
*/
public function assertNoHelpTexts(array $texts) {
$assert_session = $this->assertSession();
foreach ($texts as $text) {
$assert_session->pageTextNotContains($text);
}
}
/**
* Asserts whether a given link is present.
*
* @param \Behat\Mink\Element\NodeElement $element
* The element to search.
* @param string $text
* The link text.
* @param string[] $attributes
* An associative array of any expected attributes, keyed by the
* attribute name.
*/
protected function assertHelpLink(NodeElement $element, $text, array $attributes = []) {
// Find all the links inside the element.
$link = $element->findLink($text);
$this->assertNotEmpty($link);
foreach ($attributes as $attribute => $value) {
$this->assertSame($link->getAttribute($attribute), $value);
}
}
/**
* Asserts that a given link is not present.
*
* @param \Behat\Mink\Element\NodeElement $element
* The element to search.
* @param string $text
* The link text.
*/
protected function assertNoHelpLink(NodeElement $element, $text) {
$assert_session = $this->assertSession();
// Assert that the link and its text are not present anywhere on the page.
$assert_session->elementNotExists('named', ['link', $text], $element);
$assert_session->pageTextNotContains($text);
}
/**
* Test the media collection route.
*/
public function testMediaCollectionRoute() {
/** @var \Drupal\Core\Entity\EntityStorageInterface $media_storage */
$media_storage = $this->container->get('entity_type.manager')->getStorage('media');
$this->container->get('module_installer')->uninstall(['views']);
// Create a media type and media item.
$media_type = $this->createMediaType('test');
$media = $media_storage->create([
'bundle' => $media_type->id(),
'name' => 'Unnamed',
]);
$media->save();
$this->drupalGet($media->toUrl('collection'));
$assert_session = $this->assertSession();
// Media list table exists.
$assert_session->elementExists('css', 'th:contains("Media Name")');
$assert_session->elementExists('css', 'th:contains("Type")');
$assert_session->elementExists('css', 'th:contains("Operations")');
// Media item is present.
$assert_session->elementExists('css', 'td:contains("Unnamed")');
}
}

View file

@ -0,0 +1,89 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\media\OEmbed\ProviderException;
/**
* Tests the oEmbed provider repository.
*
* @covers \Drupal\media\OEmbed\ProviderRepository
*
* @group media
*/
class ProviderRepositoryTest extends MediaFunctionalTestBase {
/**
* Tests that provider discovery fails if the provider database is empty.
*
* @param string $content
* The expected JSON content of the provider database.
*
* @dataProvider providerEmptyProviderList
*/
public function testEmptyProviderList($content) {
$response = $this->prophesize('\GuzzleHttp\Psr7\Response');
$response->getBody()->willReturn($content);
$client = $this->createMock('\GuzzleHttp\Client');
$client->method('request')->withAnyParameters()->willReturn($response->reveal());
$this->container->set('http_client', $client);
$this->setExpectedException(ProviderException::class, 'Remote oEmbed providers database returned invalid or empty list.');
$this->container->get('media.oembed.provider_repository')->getAll();
}
/**
* Data provider for testEmptyProviderList().
*
* @see ::testEmptyProviderList()
*
* @return array
*/
public function providerEmptyProviderList() {
return [
'empty array' => ['[]'],
'empty string' => [''],
];
}
/**
* Tests that provider discovery fails with a non-existent provider database.
*
* @param string $providers_url
* The URL of the provider database.
* @param string $exception_message
* The expected exception message.
*
* @dataProvider providerNonExistingProviderDatabase
*/
public function testNonExistingProviderDatabase($providers_url, $exception_message) {
$this->config('media.settings')
->set('oembed_providers_url', $providers_url)
->save();
$this->setExpectedException(ProviderException::class, $exception_message);
$this->container->get('media.oembed.provider_repository')->getAll();
}
/**
* Data provider for testEmptyProviderList().
*
* @see ::testEmptyProviderList()
*
* @return array
*/
public function providerNonExistingProviderDatabase() {
return [
[
'http://oembed1.com/providers.json',
'Could not retrieve the oEmbed provider database from http://oembed1.com/providers.json',
],
[
'http://oembed.com/providers1.json',
'Could not retrieve the oEmbed provider database from http://oembed.com/providers1.json',
],
];
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\media\OEmbed\Resource;
use Drupal\Tests\media\Traits\OEmbedTestTrait;
/**
* Tests the oEmbed resource fetcher service.
*
* @coversDefaultClass \Drupal\media\OEmbed\ResourceFetcher
*
* @group media
*/
class ResourceFetcherTest extends MediaFunctionalTestBase {
use OEmbedTestTrait;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->useFixtureProviders();
$this->lockHttpClientToFixtures();
}
/**
* Data provider for testFetchResource().
*
* @return array
*/
public function providerFetchResource() {
return [
'JSON resource' => [
'video_vimeo.json',
'Vimeo',
'Drupal Rap Video - Schipulcon09',
],
'XML resource' => [
'video_collegehumor.xml',
'CollegeHumor',
"Let's Not Get a Drink Sometime",
],
];
}
/**
* Tests resource fetching.
*
* @param string $resource_url
* The URL of the resource to fetch, relative to the base URL.
* @param string $provider_name
* The expected name of the resource provider.
* @param string $title
* The expected title of the resource.
*
* @covers ::fetchResource
*
* @dataProvider providerFetchResource
*/
public function testFetchResource($resource_url, $provider_name, $title) {
/** @var \Drupal\media\OEmbed\Resource $resource */
$resource = $this->container->get('media.oembed.resource_fetcher')
->fetchResource($resource_url);
$this->assertInstanceOf(Resource::class, $resource);
$this->assertSame($provider_name, $resource->getProvider()->getName());
$this->assertSame($title, $resource->getTitle());
}
}

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group rest
*/
class MediaJsonAnonTest extends MediaResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group rest
*/
class MediaJsonBasicAuthTest extends MediaResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,29 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group rest
*/
class MediaJsonCookieTest extends MediaResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,431 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\media\Entity\Media;
use Drupal\media\Entity\MediaType;
use Drupal\rest\RestResourceConfigInterface;
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Drupal\user\RoleInterface;
use GuzzleHttp\RequestOptions;
abstract class MediaResourceTestBase extends EntityResourceTestBase {
use BcTimestampNormalizerUnixTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['media'];
/**
* {@inheritdoc}
*/
protected static $entityTypeId = 'media';
/**
* @var \Drupal\media\MediaInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected static $patchProtectedFieldNames = [
'changed' => NULL,
];
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
switch ($method) {
case 'GET':
$this->grantPermissionsToTestedRole(['view media']);
break;
case 'POST':
$this->grantPermissionsToTestedRole(['create camelids media', 'access content']);
break;
case 'PATCH':
$this->grantPermissionsToTestedRole(['edit any camelids media']);
// @todo Remove this in https://www.drupal.org/node/2824851.
$this->grantPermissionsToTestedRole(['access content']);
break;
case 'DELETE':
$this->grantPermissionsToTestedRole(['delete any camelids media']);
break;
}
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
if (!MediaType::load('camelids')) {
// Create a "Camelids" media type.
$media_type = MediaType::create([
'name' => 'Camelids',
'id' => 'camelids',
'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
'source' => 'file',
]);
$media_type->save();
// Create the source field.
$source_field = $media_type->getSource()->createSourceField($media_type);
$source_field->getFieldStorageDefinition()->save();
$source_field->save();
$media_type
->set('source_configuration', [
'source_field' => $source_field->getName(),
])
->save();
}
// Create a file to upload.
$file = File::create([
'uri' => 'public://llama.txt',
]);
$file->setPermanent();
$file->save();
// Create a "Llama" media item.
$media = Media::create([
'bundle' => 'camelids',
'field_media_file' => [
'target_id' => $file->id(),
],
]);
$media
->setName('Llama')
->setPublished()
->setCreatedTime(123456789)
->setOwnerId(static::$auth ? $this->account->id() : 0)
->setRevisionUserId(static::$auth ? $this->account->id() : 0)
->save();
return $media;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
$file = File::load(1);
$thumbnail = File::load(2);
$author = User::load($this->entity->getOwnerId());
return [
'mid' => [
[
'value' => 1,
],
],
'uuid' => [
[
'value' => $this->entity->uuid(),
],
],
'vid' => [
[
'value' => 1,
],
],
'langcode' => [
[
'value' => 'en',
],
],
'bundle' => [
[
'target_id' => 'camelids',
'target_type' => 'media_type',
'target_uuid' => MediaType::load('camelids')->uuid(),
],
],
'name' => [
[
'value' => 'Llama',
],
],
'field_media_file' => [
[
'description' => NULL,
'display' => NULL,
'target_id' => (int) $file->id(),
'target_type' => 'file',
'target_uuid' => $file->uuid(),
'url' => $file->url(),
],
],
'thumbnail' => [
[
'alt' => 'Thumbnail',
'width' => 180,
'height' => 180,
'target_id' => (int) $thumbnail->id(),
'target_type' => 'file',
'target_uuid' => $thumbnail->uuid(),
'title' => 'Llama',
'url' => $thumbnail->url(),
],
],
'status' => [
[
'value' => TRUE,
],
],
'created' => [
$this->formatExpectedTimestampItemValues(123456789),
],
'changed' => [
$this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
],
'revision_created' => [
$this->formatExpectedTimestampItemValues((int) $this->entity->getRevisionCreationTime()),
],
'default_langcode' => [
[
'value' => TRUE,
],
],
'uid' => [
[
'target_id' => (int) $author->id(),
'target_type' => 'user',
'target_uuid' => $author->uuid(),
'url' => base_path() . 'user/' . $author->id(),
],
],
'revision_user' => [
[
'target_id' => (int) $author->id(),
'target_type' => 'user',
'target_uuid' => $author->uuid(),
'url' => base_path() . 'user/' . $author->id(),
],
],
'revision_log_message' => [],
'revision_translation_affected' => [
[
'value' => TRUE,
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return [
'bundle' => [
[
'target_id' => 'camelids',
],
],
'name' => [
[
'value' => 'Dramallama',
],
],
'field_media_file' => [
[
'description' => NULL,
'display' => NULL,
'target_id' => 3,
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPatchEntity() {
return array_diff_key($this->getNormalizedPostEntity(), ['field_media_file' => TRUE]);
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
return parent::getExpectedUnauthorizedAccessMessage($method);
}
switch ($method) {
case 'GET';
return "The 'view media' permission is required and the media item must be published.";
case 'POST':
return "The following permissions are required: 'administer media' OR 'create media' OR 'create camelids media'.";
case 'PATCH':
return "The following permissions are required: 'update any media' OR 'update own media' OR 'camelids: edit any media' OR 'camelids: edit own media'.";
case 'DELETE':
return "The following permissions are required: 'delete any media' OR 'delete own media' OR 'camelids: delete any media' OR 'camelids: delete own media'.";
default:
return parent::getExpectedUnauthorizedAccessMessage($method);
}
}
/**
* {@inheritdoc}
*/
public function testPost() {
$file_storage = $this->container->get('entity_type.manager')->getStorage('file');
// Step 1: upload file, results in File entity marked temporary.
$this->uploadFile();
$file = $file_storage->loadUnchanged(3);
$this->assertTrue($file->isTemporary());
$this->assertFalse($file->isPermanent());
// Step 2: create Media entity using the File, makes File entity permanent.
parent::testPost();
$file = $file_storage->loadUnchanged(3);
$this->assertFalse($file->isTemporary());
$this->assertTrue($file->isPermanent());
}
/**
* This duplicates some of the 'file_upload' REST resource plugin test
* coverage, to be able to test it on a concrete use case.
*/
protected function uploadFile() {
// Enable the 'file_upload' REST resource for the current format + auth.
$this->resourceConfigStorage->create([
'id' => 'file.upload',
'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY,
'configuration' => [
'methods' => ['POST'],
'formats' => [static::$format],
'authentication' => isset(static::$auth) ? [static::$auth] : [],
],
'status' => TRUE,
])->save();
$this->refreshTestStateAfterRestConfigChange();
$this->initAuthentication();
// POST to create a File entity.
$url = Url::fromUri('base:file/upload/media/camelids/field_media_file');
$url->setOption('query', ['_format' => static::$format]);
$request_options = [];
$request_options[RequestOptions::HEADERS] = [
// Set the required (and only accepted) content type for the request.
'Content-Type' => 'application/octet-stream',
// Set the required Content-Disposition header for the file name.
'Content-Disposition' => 'file; filename="drupal rocks 🤘.txt"',
];
$request_options[RequestOptions::BODY] = 'Drupal is the best!';
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('POST'));
$response = $this->request('POST', $url, $request_options);
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('POST'), $response);
// Grant necessary permission, retry.
$this->grantPermissionsToTestedRole(['create camelids media']);
$response = $this->request('POST', $url, $request_options);
$this->assertSame(201, $response->getStatusCode());
$expected = $this->getExpectedNormalizedFileEntity();
static::recursiveKSort($expected);
$actual = $this->serializer->decode((string) $response->getBody(), static::$format);
static::recursiveKSort($actual);
$this->assertSame($expected, $actual);
// To still run the complete test coverage for POSTing a Media entity, we
// must revoke the additional permissions that we granted.
$role = Role::load(static::$auth ? RoleInterface::AUTHENTICATED_ID : RoleInterface::AUTHENTICATED_ID);
$role->revokePermission('create camelids media');
$role->trustData()->save();
}
/**
* Gets the expected file entity.
*
* @return array
* The expected normalized data array.
*/
protected function getExpectedNormalizedFileEntity() {
$file = File::load(3);
$owner = static::$auth ? $this->account : User::load(0);
return [
'fid' => [
[
'value' => 3,
],
],
'uuid' => [
[
'value' => $file->uuid(),
],
],
'langcode' => [
[
'value' => 'en',
],
],
'uid' => [
[
'target_id' => (int) $owner->id(),
'target_type' => 'user',
'target_uuid' => $owner->uuid(),
'url' => base_path() . 'user/' . $owner->id(),
],
],
'filename' => [
[
'value' => 'drupal rocks 🤘.txt',
],
],
'uri' => [
[
'value' => 'public://' . date('Y-m') . '/drupal rocks 🤘.txt',
'url' => base_path() . $this->siteDirectory . '/files/' . date('Y-m') . '/drupal%20rocks%20%F0%9F%A4%98.txt',
],
],
'filemime' => [
[
'value' => 'text/plain',
],
],
'filesize' => [
[
'value' => 19,
],
],
'status' => [
[
'value' => FALSE,
],
],
'created' => [
$this->formatExpectedTimestampItemValues($file->getCreatedTime()),
],
'changed' => [
$this->formatExpectedTimestampItemValues($file->getChangedTime()),
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessCacheability() {
// @see \Drupal\media\MediaAccessControlHandler::checkAccess()
return parent::getExpectedUnauthorizedAccessCacheability()
->addCacheTags(['media:1']);
}
}

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group rest
*/
class MediaTypeJsonAnonTest extends MediaTypeResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group rest
*/
class MediaTypeJsonBasicAuthTest extends MediaTypeResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,29 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group rest
*/
class MediaTypeJsonCookieTest extends MediaTypeResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,78 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\media\Entity\MediaType;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
abstract class MediaTypeResourceTestBase extends EntityResourceTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['media'];
/**
* {@inheritdoc}
*/
protected static $entityTypeId = 'media_type';
/**
* @var \Drupal\media\MediaTypeInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
$this->grantPermissionsToTestedRole(['administer media types']);
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
// Create a "Camelids" media type.
$camelids = MediaType::create([
'name' => 'Camelids',
'id' => 'camelids',
'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
'source' => 'file',
]);
$camelids->save();
return $camelids;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
return [
'dependencies' => [],
'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
'field_map' => [],
'id' => 'camelids',
'label' => NULL,
'langcode' => 'en',
'new_revision' => FALSE,
'queue_thumbnail_downloads' => FALSE,
'source' => 'file',
'source_configuration' => [
'source_field' => '',
],
'status' => TRUE,
'uuid' => $this->entity->uuid(),
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
// @todo Update in https://www.drupal.org/node/2300677.
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class MediaTypeXmlAnonTest extends MediaTypeResourceTestBase {
use AnonResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class MediaTypeXmlBasicAuthTest extends MediaTypeResourceTestBase {
use BasicAuthResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,31 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class MediaTypeXmlCookieTest extends MediaTypeResourceTestBase {
use CookieResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,26 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class MediaXmlAnonTest extends MediaResourceTestBase {
use AnonResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class MediaXmlBasicAuthTest extends MediaResourceTestBase {
use BasicAuthResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,31 @@
<?php
namespace Drupal\Tests\media\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class MediaXmlCookieTest extends MediaResourceTestBase {
use CookieResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,65 @@
<?php
namespace Drupal\Tests\media\Functional\Update;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
use Drupal\user\Entity\Role;
/**
* Tests that media settings are properly updated during database updates.
*
* @group media
* @group legacy
*/
class MediaUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz',
__DIR__ . '/../../../fixtures/update/drupal-8.4.0-media_installed.php',
__DIR__ . '/../../../fixtures/update/drupal-8.media-add-additional-permissions.php',
];
}
/**
* Tests that media permissions are correctly migrated.
*
* @see media_update_8500()
*/
public function testBundlePermission() {
$this->runUpdates();
/** @var \Drupal\user\RoleInterface $role */
$role = Role::load(Role::AUTHENTICATED_ID);
$media_types = \Drupal::entityQuery('media_type')->execute();
foreach ($media_types as $media_type) {
$this->assertTrue($role->hasPermission("create $media_type media"));
$this->assertTrue($role->hasPermission("edit own $media_type media"));
$this->assertTrue($role->hasPermission("edit any $media_type media"));
$this->assertTrue($role->hasPermission("delete own $media_type media"));
$this->assertTrue($role->hasPermission("delete any $media_type media"));
}
}
/**
* Tests that media.settings config is updated with oEmbed configuration.
*
* @see media_update_8600()
*/
public function testOEmbedConfig() {
$config = $this->config('media.settings');
$this->assertNull($config->get('oembed_providers_url'));
$this->assertNull($config->get('iframe_domain'));
$this->runUpdates();
$config = $this->config('media.settings');
$this->assertSame('https://oembed.com/providers.json', $config->get('oembed_providers_url'));
$this->assertSame('', $config->get('iframe_domain'));
}
}

View file

@ -0,0 +1,133 @@
<?php
namespace Drupal\Tests\media\Functional;
use Drupal\Tests\media\Traits\OEmbedTestTrait;
/**
* Tests the oEmbed URL resolver service.
*
* @coversDefaultClass \Drupal\media\OEmbed\UrlResolver
*
* @group media
*/
class UrlResolverTest extends MediaFunctionalTestBase {
use OEmbedTestTrait;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->lockHttpClientToFixtures();
$this->useFixtureProviders();
}
/**
* Data provider for testEndpointMatching().
*
* @see ::testEndpointMatching()
*
* @return array
*/
public function providerEndpointMatching() {
return [
'match by endpoint: Twitter' => [
'https://twitter.com/Dries/status/999985431595880448',
'https://publish.twitter.com/oembed?url=https%3A//twitter.com/Dries/status/999985431595880448',
],
'match by endpoint: Vimeo' => [
'https://vimeo.com/14782834',
'https://vimeo.com/api/oembed.json?url=https%3A//vimeo.com/14782834',
],
'match by endpoint: CollegeHumor' => [
'http://www.collegehumor.com/video/40002870/lets-not-get-a-drink-sometime',
'http://www.collegehumor.com/oembed.json?url=http%3A//www.collegehumor.com/video/40002870/lets-not-get-a-drink-sometime',
],
];
}
/**
* Tests resource URL resolution when the asset URL can be matched to a
* provider endpoint.
*
* @covers ::getProviderByUrl
* @covers ::getResourceUrl
*
* @param string $url
* The asset URL to resolve.
* @param string $resource_url
* The expected oEmbed resource URL of the asset.
*
* @dataProvider providerEndpointMatching
*/
public function testEndpointMatching($url, $resource_url) {
$this->assertSame(
$resource_url,
$this->container->get('media.oembed.url_resolver')->getResourceUrl($url)
);
}
/**
* Tests that hook_oembed_resource_url_alter() is invoked.
*
* @depends testEndpointMatching
*/
public function testResourceUrlAlterHook() {
$this->container->get('module_installer')->install(['media_test_oembed']);
$resource_url = $this->container->get('media.oembed.url_resolver')
->getResourceUrl('https://vimeo.com/14782834');
$this->assertContains('altered=1', parse_url($resource_url, PHP_URL_QUERY));
}
/**
* Data provider for testUrlDiscovery().
*
* @see ::testUrlDiscovery()
*
* @return array
*/
public function providerUrlDiscovery() {
return [
'JSON resource' => [
'video_vimeo.html',
'https://vimeo.com/api/oembed.json?url=video_vimeo.html',
],
'XML resource' => [
'video_collegehumor.html',
// The endpoint does not explicitly declare that it supports XML, so
// only JSON support is assumed, which is why the discovered URL
// contains '.json'. However, the fetched HTML file contains a
// relationship to an XML representation of the resource, with the
// application/xml+oembed MIME type.
'http://www.collegehumor.com/oembed.json?url=video_collegehumor.html',
],
];
}
/**
* Tests URL resolution when the resource URL must be actively discovered by
* scanning the asset.
*
* @param string $url
* The asset URL to resolve.
* @param string $resource_url
* The expected oEmbed resource URL of the asset.
*
* @covers ::discoverResourceUrl
* @covers ::getProviderByUrl
* @covers ::getResourceUrl
*
* @dataProvider providerUrlDiscovery
*/
public function testUrlDiscovery($url, $resource_url) {
$this->assertSame(
$this->container->get('media.oembed.url_resolver')->getResourceUrl($url),
$resource_url
);
}
}

View file

@ -0,0 +1,184 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\InstallStorage;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\media\Entity\Media;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
/**
* Basic display tests for Media.
*
* @group media
*/
class MediaDisplayTest extends MediaJavascriptTestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Install the optional configs from the standard profile.
$extension_path = drupal_get_path('profile', 'standard');
$optional_install_path = $extension_path . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY;
$storage = new FileStorage($optional_install_path);
$this->container->get('config.installer')->installOptionalConfig($storage, '');
// Reset all the static caches and list caches.
$this->container->get('config.factory')->reset();
}
/**
* Test basic media display.
*/
public function testMediaDisplay() {
$assert_session = $this->assertSession();
$page = $this->getSession()->getPage();
$media_type = $this->createMediaType('test');
// Create a media item.
$media = Media::create([
'bundle' => $media_type->id(),
'name' => 'Fantastic!',
]);
$media->save();
$this->drupalGet('media/' . $media->id());
// Verify the "name" field is really not present.
$assert_session->elementNotExists('css', '.field--name-name');
// Enable the field on the display and verify it becomes visible on the UI.
$this->drupalGet("/admin/structure/media/manage/{$media_type->id()}/display");
$assert_session->buttonExists('Show row weights')->press();
$this->assertSession()->waitForElementVisible('css', '[name="fields[name][region]"]');
$page->selectFieldOption('fields[name][region]', 'content');
$assert_session->waitForElementVisible('css', '#edit-fields-name-settings-edit');
$page->pressButton('Save');
$this->drupalGet('media/' . $media->id());
// Verify the name is present, and its text matches what is expected.
$assert_session->elementExists('css', '.field--name-name');
$name_field = $page->find('css', '.field--name-name .field__item');
$this->assertSame($media->label(), $name_field->getText());
// In the standard profile, there are some pre-cooked types. Make sure the
// elements configured on their displays are the expected ones.
$this->drupalGet('media/add/image');
$image_media_name = 'Fantastic image asset!';
$page->fillField('name[0][value]', $image_media_name);
$page->attachFileToField('files[field_media_image_0]', $this->root . '/core/modules/media/tests/fixtures/example_1.jpeg');
$result = $assert_session->waitForButton('Remove');
$this->assertNotEmpty($result);
$page->fillField('field_media_image[0][alt]', 'Image Alt Text 1');
$page->pressButton('Save');
$image_media_id = $this->container
->get('entity_type.manager')
->getStorage('media')
->getQuery()
->sort('mid', 'DESC')
->execute();
$image_media_id = reset($image_media_id);
// Go to the media entity view.
$this->drupalGet('/media/' . $image_media_id);
// Here we expect to see only the image, nothing else.
// Assert only one element in the content region.
$this->assertSame(1, count($page->findAll('css', '.media--type-image > div')));
// Assert the image is present inside the media element.
$media_item = $assert_session->elementExists('css', '.media--type-image > div');
$assert_session->elementExists('css', 'img', $media_item);
// Assert that the image src is the original image and not an image style.
$media_image = $assert_session->elementExists('css', '.media--type-image img');
$expected_image_src = file_url_transform_relative(file_create_url(\Drupal::token()->replace('public://[date:custom:Y]-[date:custom:m]/example_1.jpeg')));
$this->assertSame($expected_image_src, $media_image->getAttribute('src'));
$test_filename = $this->randomMachineName() . '.txt';
$test_filepath = 'public://' . $test_filename;
file_put_contents($test_filepath, $this->randomMachineName());
$this->drupalGet("media/add/file");
$page->fillField('name[0][value]', 'File media 1');
$page->attachFileToField("files[field_media_file_0]", \Drupal::service('file_system')->realpath($test_filepath));
$result = $assert_session->waitForButton('Remove');
$this->assertNotEmpty($result);
$page->pressButton('Save');
// Go to the media entity view.
$this->drupalGet($this->assertLinkToCreatedMedia());
// Here we expect to see only the linked filename.
// Assert only one element in the content region.
$this->assertSame(1, count($page->findAll('css', 'article.media--type-file > div')));
// Assert the file link is present, and its text matches the filename.
$assert_session->elementExists('css', 'article.media--type-file .field--name-field-media-file a');
$link = $page->find('css', 'article.media--type-file .field--name-field-media-file a');
$this->assertSame($test_filename, $link->getText());
// Create a node type "page" to use as host entity.
$node_type = NodeType::create([
'type' => 'page',
'name' => 'Page',
]);
$node_type->save();
// Reference the created media using an entity_reference field and make sure
// the output is what we expect.
$storage = FieldStorageConfig::create([
'entity_type' => 'node',
'field_name' => 'field_related_media',
'type' => 'entity_reference',
'settings' => [
'target_type' => 'media',
],
]);
$storage->save();
FieldConfig::create([
'field_storage' => $storage,
'entity_type' => 'node',
'bundle' => $node_type->id(),
'label' => 'Related media',
'settings' => [
'handler_settings' => [
'target_bundles' => [
'image' => 'image',
],
],
],
])->save();
entity_get_display('node', $node_type->id(), 'default')
->setComponent('field_related_media', [
'type' => 'entity_reference_entity_view',
'label' => 'hidden',
'settings' => [
'view_mode' => 'full',
],
])->save();
$node = Node::create([
'title' => 'Host node',
'type' => $node_type->id(),
'field_related_media' => [
'target_id' => $image_media_id,
],
]);
$node->save();
$this->drupalGet('/node/' . $node->id());
// Media field is there.
$assert_session->elementExists('css', '.field--name-field-related-media');
// Media name element is not there.
$assert_session->elementNotExists('css', '.field--name-name');
$assert_session->pageTextNotContains($image_media_name);
// Only one element is present inside the media container.
$this->assertSame(1, count($page->findAll('css', '.field--name-field-related-media article.media--type-image > div')));
// Assert the image is present.
$assert_session->elementExists('css', '.field--name-field-related-media article.media--type-image img');
}
}

View file

@ -0,0 +1,63 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\Tests\media\Functional\MediaFunctionalTestTrait;
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
/**
* Base class for Media functional JavaScript tests.
*/
abstract class MediaJavascriptTestBase extends WebDriverTestBase {
use MediaFunctionalTestTrait;
use MediaTypeCreationTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'system',
'node',
'field_ui',
'views_ui',
'media',
'media_test_source',
];
/**
* Waits and asserts that a given element is visible.
*
* @param string $selector
* The CSS selector.
* @param int $timeout
* (Optional) Timeout in milliseconds, defaults to 1000.
* @param string $message
* (Optional) Message to pass to assertJsCondition().
*/
protected function waitUntilVisible($selector, $timeout = 1000, $message = '') {
$condition = "jQuery('" . $selector . ":visible').length > 0";
$this->assertJsCondition($condition, $timeout, $message);
}
/**
* Asserts that a link to a new media item is displayed in the messages area.
*
* @return string
* The link URL.
*/
protected function assertLinkToCreatedMedia() {
$assert_session = $this->assertSession();
$selector = '.messages a';
// Get the canonical media entity URL from the creation message.
$link = $assert_session->elementExists('css', $selector);
$assert_session->elementAttributeExists('css', $selector, 'href');
return $link->getAttribute('href');
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\Component\Utility\Html;
/**
* Tests related to media reference fields.
*
* @group media
*/
class MediaReferenceFieldHelpTest extends MediaJavascriptTestBase {
/**
* Test our custom help texts when creating a field.
*
* @see media_form_field_ui_field_storage_add_form_alter()
*/
public function testFieldCreationHelpText() {
$assert_session = $this->assertSession();
$page = $this->getSession()->getPage();
$type = $this->drupalCreateContentType([
'type' => 'foo',
]);
$this->drupalGet("/admin/structure/types/manage/{$type->id()}/fields/add-field");
$field_types = [
'file',
'image',
'field_ui:entity_reference:media',
];
$description_ids = array_map(function ($item) {
return '#edit-description-' . Html::cleanCssIdentifier($item);
}, $field_types);
// Choose a boolean field, none of the description containers should be
// visible.
$assert_session->optionExists('edit-new-storage-type', 'boolean');
$page->selectFieldOption('edit-new-storage-type', 'boolean');
foreach ($description_ids as $description_id) {
$this->assertFalse($assert_session->elementExists('css', $description_id)->isVisible());
}
// Select each of the file, image, and media fields and verify their
// descriptions are now visible and match the expected text.
$help_text = 'Use Media reference fields for most files, images, audio, videos, and remote media. Use File or Image reference fields when creating your own media types, or for legacy files and images created before enabling the Media module.';
foreach ($field_types as $field_name) {
$assert_session->optionExists('edit-new-storage-type', $field_name);
$page->selectFieldOption('edit-new-storage-type', $field_name);
$field_description_element = $assert_session->elementExists('css', '#edit-description-' . Html::cleanCssIdentifier($field_name));
$this->assertTrue($field_description_element->isVisible());
$this->assertSame($help_text, $field_description_element->getText());
}
}
}

View file

@ -0,0 +1,115 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\file\Entity\File;
/**
* Tests the Audio and Video media sources.
*
* @group media
*/
class MediaSourceAudioVideoTest extends MediaSourceTestBase {
/**
* Check the Audio source functionality.
*/
public function testAudioTypeCreation() {
$assert_session = $this->assertSession();
$page = $this->getSession()->getPage();
$source_id = 'audio_file';
$type_name = 'audio_type';
$field_name = 'field_media_' . $source_id;
$this->doTestCreateMediaType($type_name, $source_id);
// Check that the source field was created with the correct settings.
$storage = FieldStorageConfig::load("media.$field_name");
$this->assertInstanceOf(FieldStorageConfig::class, $storage);
$field = FieldConfig::load("media.$type_name.$field_name");
$this->assertInstanceOf(FieldConfig::class, $field);
$this->assertSame('mp3 wav aac', FieldConfig::load("media.$type_name.$field_name")->get('settings')['file_extensions']);
// Check that the display holds the correct formatter configuration.
$display = EntityViewDisplay::load("media.$type_name.default");
$this->assertInstanceOf(EntityViewDisplay::class, $display);
$formatter = $display->getComponent($field_name)['type'];
$this->assertSame('file_audio', $formatter);
// Create a media asset.
file_put_contents('public://file.mp3', str_repeat('t', 10));
$file = File::create([
'uri' => 'public://file.mp3',
'filename' => 'file.mp3',
]);
$file->save();
$this->drupalGet("media/add/$type_name");
$page->fillField('Name', 'Audio media asset');
$page->attachFileToField("files[{$field_name}_0]", \Drupal::service('file_system')->realpath('public://file.mp3'));
$result = $assert_session->waitForButton('Remove');
$this->assertNotEmpty($result);
$page->pressButton('Save');
// Verify that there is a creation message and that it contains a link to
// the media entity.
$assert_session->pageTextContains("$type_name Audio media asset has been created.");
$this->drupalGet($this->assertLinkToCreatedMedia());
// Verify that the <audio> tag is present on the media entity view.
$assert_session->elementExists('css', "audio > source[type='audio/mpeg']");
}
/**
* Check the Video source functionality.
*/
public function testVideoTypeCreation() {
$assert_session = $this->assertSession();
$page = $this->getSession()->getPage();
$source_id = 'video_file';
$type_name = 'video_type';
$field_name = 'field_media_' . $source_id;
$this->doTestCreateMediaType($type_name, $source_id);
// Check that the source field was created with the correct settings.
$storage = FieldStorageConfig::load("media.$field_name");
$this->assertInstanceOf(FieldStorageConfig::class, $storage);
$field = FieldConfig::load("media.$type_name.$field_name");
$this->assertInstanceOf(FieldConfig::class, $field);
$this->assertSame('mp4', FieldConfig::load("media.$type_name.$field_name")->getSetting('file_extensions'));
// Check that the display holds the correct formatter configuration.
$display = EntityViewDisplay::load("media.$type_name.default");
$this->assertInstanceOf(EntityViewDisplay::class, $display);
$formatter = $display->getComponent($field_name)['type'];
$this->assertSame('file_video', $formatter);
// Create a media asset.
file_put_contents('public://file.mp4', str_repeat('t', 10));
$file = File::create([
'uri' => 'public://file.mp4',
'filename' => 'file.mp4',
]);
$file->save();
$this->drupalGet("media/add/$type_name");
$page->fillField('Name', 'Video media asset');
$page->attachFileToField("files[{$field_name}_0]", \Drupal::service('file_system')->realpath('public://file.mp4'));
$result = $assert_session->waitForButton('Remove');
$this->assertNotEmpty($result);
$page->pressButton('Save');
// Verify that there is a creation message and that it contains a link to
// the media entity.
$assert_session->pageTextContains("$type_name Video media asset has been created.");
$this->drupalGet($this->assertLinkToCreatedMedia());
// Verify that the <video> tag is present on the media entity view.
$assert_session->elementExists('css', "video > source[type='video/mp4']");
}
}

View file

@ -0,0 +1,109 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\media\Entity\Media;
use Drupal\media\Plugin\media\Source\File;
/**
* Tests the file media source.
*
* @group media
*/
class MediaSourceFileTest extends MediaSourceTestBase {
/**
* Tests the file media source.
*/
public function testMediaFileSource() {
$media_type_id = 'test_media_file_type';
$source_field_id = 'field_media_file';
$provided_fields = [
File::METADATA_ATTRIBUTE_NAME,
File::METADATA_ATTRIBUTE_SIZE,
File::METADATA_ATTRIBUTE_MIME,
];
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$this->doTestCreateMediaType($media_type_id, 'file', $provided_fields);
// Create custom fields for the media type to store metadata attributes.
$fields = [
'field_string_file_size' => 'string',
'field_string_mime_type' => 'string',
];
$this->createMediaTypeFields($fields, $media_type_id);
// Hide the name field widget to test default name generation.
$this->hideMediaTypeFieldWidget('name', $media_type_id);
$this->drupalGet("admin/structure/media/manage/{$media_type_id}");
$page->selectFieldOption("field_map[" . File::METADATA_ATTRIBUTE_NAME . "]", 'name');
$page->selectFieldOption("field_map[" . File::METADATA_ATTRIBUTE_SIZE . "]", 'field_string_file_size');
$page->selectFieldOption("field_map[" . File::METADATA_ATTRIBUTE_MIME . "]", 'field_string_mime_type');
$page->pressButton('Save');
$test_filename = $this->randomMachineName() . '.txt';
$test_filepath = 'public://' . $test_filename;
file_put_contents($test_filepath, $this->randomMachineName());
// Create a media item.
$this->drupalGet("media/add/{$media_type_id}");
$page->attachFileToField("files[{$source_field_id}_0]", \Drupal::service('file_system')->realpath($test_filepath));
$result = $assert_session->waitForButton('Remove');
$this->assertNotEmpty($result);
$page->pressButton('Save');
$assert_session->addressEquals('admin/content/media');
// Get the media entity view URL from the creation message.
$this->drupalGet($this->assertLinkToCreatedMedia());
// Make sure the thumbnail is displayed.
$assert_session->elementAttributeContains('css', '.image-style-thumbnail', 'src', 'generic.png');
// Make sure checkbox changes the visibility of log message field.
$this->drupalGet("media/1/edit");
$page->uncheckField('revision');
$assert_session->elementAttributeContains('css', '.field--name-revision-log-message', 'style', 'display: none');
$page->checkField('revision');
$assert_session->elementAttributeNotContains('css', '.field--name-revision-log-message', 'style', 'display');
// Load the media and check that all the fields are properly populated.
$media = Media::load(1);
$this->assertSame($test_filename, $media->getName());
$this->assertSame('8', $media->get('field_string_file_size')->value);
$this->assertSame('text/plain', $media->get('field_string_mime_type')->value);
// Test the MIME type icon.
$icon_base = \Drupal::config('media.settings')->get('icon_base_uri');
file_unmanaged_copy($icon_base . '/generic.png', $icon_base . '/text--plain.png');
$this->drupalGet("media/add/{$media_type_id}");
$page->attachFileToField("files[{$source_field_id}_0]", \Drupal::service('file_system')->realpath($test_filepath));
$result = $assert_session->waitForButton('Remove');
$this->assertNotEmpty($result);
$page->pressButton('Save');
$assert_session->elementAttributeContains('css', '.image-style-thumbnail', 'src', 'text--plain.png');
// Check if the mapped name is automatically updated.
$new_filename = $this->randomMachineName() . '.txt';
$new_filepath = 'public://' . $new_filename;
file_put_contents($new_filepath, $this->randomMachineName());
$this->drupalGet("media/1/edit");
$page->pressButton('Remove');
$result = $assert_session->waitForField("files[{$source_field_id}_0]");
$this->assertNotEmpty($result);
$page->attachFileToField("files[{$source_field_id}_0]", \Drupal::service('file_system')->realpath($new_filepath));
$result = $assert_session->waitForButton('Remove');
$this->assertNotEmpty($result);
$page->pressButton('Save');
/** @var \Drupal\media\MediaInterface $media */
$media = \Drupal::entityTypeManager()->getStorage('media')->loadUnchanged(1);
$this->assertEquals($new_filename, $media->getName());
$assert_session->pageTextContains("$new_filename has been updated.");
}
}

View file

@ -0,0 +1,70 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\media\Entity\Media;
use Drupal\media\Plugin\media\Source\Image;
/**
* Tests the image media source.
*
* @group media
*/
class MediaSourceImageTest extends MediaSourceTestBase {
/**
* Tests the image media source.
*/
public function testMediaImageSource() {
$media_type_id = 'test_media_image_type';
$source_field_id = 'field_media_image';
$provided_fields = [
Image::METADATA_ATTRIBUTE_WIDTH,
Image::METADATA_ATTRIBUTE_HEIGHT,
];
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$this->doTestCreateMediaType($media_type_id, 'image', $provided_fields);
// Create custom fields for the media type to store metadata attributes.
$fields = [
'field_string_width' => 'string',
'field_string_height' => 'string',
];
$this->createMediaTypeFields($fields, $media_type_id);
// Hide the name field widget to test default name generation.
$this->hideMediaTypeFieldWidget('name', $media_type_id);
$this->drupalGet("admin/structure/media/manage/{$media_type_id}");
$page->selectFieldOption("field_map[" . Image::METADATA_ATTRIBUTE_WIDTH . "]", 'field_string_width');
$page->selectFieldOption("field_map[" . Image::METADATA_ATTRIBUTE_HEIGHT . "]", 'field_string_height');
$page->pressButton('Save');
// Create a media item.
$this->drupalGet("media/add/{$media_type_id}");
$page->attachFileToField("files[{$source_field_id}_0]", $this->root . '/core/modules/media/tests/fixtures/example_1.jpeg');
$result = $assert_session->waitForButton('Remove');
$this->assertNotEmpty($result);
$page->fillField("{$source_field_id}[0][alt]", 'Image Alt Text 1');
$page->pressButton('Save');
$assert_session->addressEquals('admin/content/media');
// Get the media entity view URL from the creation message.
$this->drupalGet($this->assertLinkToCreatedMedia());
// Make sure the thumbnail is displayed from uploaded image.
$assert_session->elementAttributeContains('css', '.image-style-thumbnail', 'src', 'example_1.jpeg');
// Load the media and check that all fields are properly populated.
$media = Media::load(1);
$this->assertSame('example_1.jpeg', $media->getName());
$this->assertSame('200', $media->get('field_string_width')->value);
$this->assertSame('89', $media->get('field_string_height')->value);
}
}

View file

@ -0,0 +1,217 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\Core\Session\AccountInterface;
use Drupal\media\Entity\Media;
use Drupal\media_test_oembed\Controller\ResourceController;
use Drupal\Tests\media\Traits\OEmbedTestTrait;
use Drupal\user\Entity\Role;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Tests the oembed:video media source.
*
* @group media
*/
class MediaSourceOEmbedVideoTest extends MediaSourceTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['media_test_oembed'];
use OEmbedTestTrait;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->lockHttpClientToFixtures();
}
/**
* {@inheritdoc}
*/
protected function initConfig(ContainerInterface $container) {
parent::initConfig($container);
// Enable twig debugging to make testing template usage easy.
$parameters = $container->getParameter('twig.config');
$parameters['debug'] = TRUE;
$this->setContainerParameter('twig.config', $parameters);
}
/**
* Tests the oembed media source.
*/
public function testMediaOEmbedVideoSource() {
$media_type_id = 'test_media_oembed_type';
$provided_fields = [
'type',
'title',
'default_name',
'author_name',
'author_url',
'provider_name',
'provider_url',
'cache_age',
'thumbnail_uri',
'thumbnail_width',
'thumbnail_height',
'url',
'width',
'height',
'html',
];
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$this->doTestCreateMediaType($media_type_id, 'oembed:video', $provided_fields);
// Create custom fields for the media type to store metadata attributes.
$fields = [
'field_string_width' => 'string',
'field_string_height' => 'string',
'field_string_author_name' => 'string',
];
$this->createMediaTypeFields($fields, $media_type_id);
// Hide the name field widget to test default name generation.
$this->hideMediaTypeFieldWidget('name', $media_type_id);
$this->drupalGet("admin/structure/media/manage/$media_type_id");
// Only accept Vimeo videos.
$page->checkField("source_configuration[providers][Vimeo]");
$assert_session->selectExists('field_map[width]')->setValue('field_string_width');
$assert_session->selectExists('field_map[height]')->setValue('field_string_height');
$assert_session->selectExists('field_map[author_name]')->setValue('field_string_author_name');
$assert_session->buttonExists('Save')->press();
$this->hijackProviderEndpoints();
$video_url = 'https://vimeo.com/7073899';
ResourceController::setResourceUrl($video_url, $this->getFixturesDirectory() . '/video_vimeo.json');
// Create a media item.
$this->drupalGet("media/add/$media_type_id");
$assert_session->fieldExists('Remote video URL')->setValue($video_url);
$assert_session->buttonExists('Save')->press();
$assert_session->addressEquals('admin/content/media');
// Get the media entity view URL from the creation message.
$this->drupalGet($this->assertLinkToCreatedMedia());
/** @var \Drupal\media\MediaInterface $media */
$media = Media::load(1);
// The thumbnail should have been downloaded.
$thumbnail = $media->getSource()->getMetadata($media, 'thumbnail_uri');
$this->assertFileExists($thumbnail);
// Ensure the iframe exists and that its src attribute contains a coherent
// URL with the query parameters we expect.
$iframe_url = $assert_session->elementExists('css', 'iframe')->getAttribute('src');
$iframe_url = parse_url($iframe_url);
$this->assertStringEndsWith('/media/oembed', $iframe_url['path']);
$this->assertNotEmpty($iframe_url['query']);
$query = [];
parse_str($iframe_url['query'], $query);
$this->assertSame($video_url, $query['url']);
$this->assertNotEmpty($query['hash']);
// Make sure the thumbnail is displayed from uploaded image.
$assert_session->elementAttributeContains('css', '.image-style-thumbnail', 'src', '/oembed_thumbnails/' . basename($thumbnail));
// Load the media and check that all fields are properly populated.
$media = Media::load(1);
$this->assertSame('Drupal Rap Video - Schipulcon09', $media->getName());
$this->assertSame('480', $media->field_string_width->value);
$this->assertSame('360', $media->field_string_height->value);
// Try to create a media asset from a disallowed provider.
$this->drupalGet("media/add/$media_type_id");
$assert_session->fieldExists('Remote video URL')->setValue('http://www.collegehumor.com/video/40003213/grant-and-katie-are-starting-their-own-company');
$page->pressButton('Save');
$assert_session->pageTextContains('The CollegeHumor provider is not allowed.');
// Test anonymous access to media via iframe.
$this->drupalLogout();
// Without a hash should be denied.
$no_hash_query = array_diff_key($query, ['hash' => '']);
$this->drupalGet('media/oembed', ['query' => $no_hash_query]);
$assert_session->pageTextNotContains('By the power of Greyskull, Vimeo works!');
$assert_session->pageTextContains('Access denied');
// A correct query should be allowed because the anonymous role has the
// 'view media' permission.
$this->drupalGet('media/oembed', ['query' => $query]);
$assert_session->pageTextContains('By the power of Greyskull, Vimeo works!');
$this->assertRaw('core/themes/stable/templates/content/media-oembed-iframe.html.twig');
$this->assertNoRaw('core/modules/media/templates/media-oembed-iframe.html.twig');
// Test themes not inheriting from stable.
\Drupal::service('theme_handler')->install(['stark']);
$this->config('system.theme')->set('default', 'stark')->save();
$this->drupalGet('media/oembed', ['query' => $query]);
$assert_session->pageTextContains('By the power of Greyskull, Vimeo works!');
$this->assertNoRaw('core/themes/stable/templates/content/media-oembed-iframe.html.twig');
$this->assertRaw('core/modules/media/templates/media-oembed-iframe.html.twig');
// Remove the 'view media' permission to test that this restricts access.
$role = Role::load(AccountInterface::ANONYMOUS_ROLE);
$role->revokePermission('view media');
$role->save();
$this->drupalGet('media/oembed', ['query' => $query]);
$assert_session->pageTextNotContains('By the power of Greyskull, Vimeo works!');
$assert_session->pageTextContains('Access denied');
}
/**
* Test that a security warning appears if iFrame domain is not set.
*/
public function testOEmbedSecurityWarning() {
$media_type_id = 'test_media_oembed_type';
$source_id = 'oembed:video';
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$this->drupalGet('admin/structure/media/add');
$page->fillField('label', $media_type_id);
$this->getSession()
->wait(5000, "jQuery('.machine-name-value').text() === '{$media_type_id}'");
// Make sure the source is available.
$assert_session->fieldExists('Media source');
$assert_session->optionExists('Media source', $source_id);
$page->selectFieldOption('Media source', $source_id);
$result = $assert_session->waitForElementVisible('css', 'fieldset[data-drupal-selector="edit-source-configuration"]');
$this->assertNotEmpty($result);
$assert_session->pageTextContains('It is potentially insecure to display oEmbed content in a frame');
$this->config('media.settings')->set('iframe_domain', 'http://example.com')->save();
$this->drupalGet('admin/structure/media/add');
$page->fillField('label', $media_type_id);
$this->getSession()
->wait(5000, "jQuery('.machine-name-value').text() === '{$media_type_id}'");
// Make sure the source is available.
$assert_session->fieldExists('Media source');
$assert_session->optionExists('Media source', $source_id);
$page->selectFieldOption('Media source', $source_id);
$result = $assert_session->waitForElementVisible('css', 'fieldset[data-drupal-selector="edit-source-configuration"]');
$this->assertNotEmpty($result);
$assert_session->pageTextNotContains('It is potentially insecure to display oEmbed content in a frame');
}
}

View file

@ -0,0 +1,138 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\media\Entity\MediaType;
/**
* Base class for media source tests.
*/
abstract class MediaSourceTestBase extends MediaJavascriptTestBase {
/**
* Creates storage and field instance, attached to a given media type.
*
* @param string $field_name
* The field name.
* @param string $field_type
* The field type.
* @param string $media_type_id
* The media type config entity ID.
*/
protected function createMediaTypeField($field_name, $field_type, $media_type_id) {
$storage = FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'media',
'type' => $field_type,
]);
$storage->save();
FieldConfig::create([
'field_storage' => $storage,
'bundle' => $media_type_id,
])->save();
// Make the field widget visible in the form display.
$component = \Drupal::service('plugin.manager.field.widget')
->prepareConfiguration($field_type, []);
// @todo Replace entity_get_form_display() when #2367933 is done.
// https://www.drupal.org/node/2872159.
$entity_form_display = entity_get_form_display('media', $media_type_id, 'default');
$entity_form_display->setComponent($field_name, $component)
->save();
// Use the default formatter and settings.
$component = \Drupal::service('plugin.manager.field.formatter')
->prepareConfiguration($field_type, []);
// @todo Replace entity_get_display() when #2367933 is done.
// https://www.drupal.org/node/2872159.
$entity_display = entity_get_display('media', $media_type_id, 'default');
$entity_display->setComponent($field_name, $component)
->save();
}
/**
* Create a set of fields in a media type.
*
* @param array $fields
* An associative array where keys are field names and values field types.
* @param string $media_type_id
* The media type config entity ID.
*/
protected function createMediaTypeFields(array $fields, $media_type_id) {
foreach ($fields as $field_name => $field_type) {
$this->createMediaTypeField($field_name, $field_type, $media_type_id);
}
}
/**
* Hides a widget in the default form display config.
*
* @param string $field_name
* The field name.
* @param string $media_type_id
* The media type config entity ID.
*/
protected function hideMediaTypeFieldWidget($field_name, $media_type_id) {
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $entity_form_display */
$entity_form_display = entity_get_form_display('media', $media_type_id, 'default');
if ($entity_form_display->getComponent($field_name)) {
$entity_form_display->removeComponent($field_name)->save();
}
}
/**
* Test generic media type creation.
*
* @param string $media_type_id
* The media type config entity ID.
* @param string $source_id
* The media source ID.
* @param array $provided_fields
* (optional) An array of field machine names this type provides.
*
* @return \Drupal\media\MediaTypeInterface
* The created media type.
*/
public function doTestCreateMediaType($media_type_id, $source_id, array $provided_fields = []) {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$this->drupalGet('admin/structure/media/add');
$page->fillField('label', $media_type_id);
$this->getSession()
->wait(5000, "jQuery('.machine-name-value').text() === '{$media_type_id}'");
// Make sure the source is available.
$assert_session->fieldExists('Media source');
$assert_session->optionExists('Media source', $source_id);
$page->selectFieldOption('Media source', $source_id);
$result = $assert_session->waitForElementVisible('css', 'fieldset[data-drupal-selector="edit-source-configuration"]');
$this->assertNotEmpty($result);
// Make sure the provided fields are visible on the form.
foreach ($provided_fields as $provided_field) {
$result = $assert_session->waitForElementVisible('css', 'select[name="field_map[' . $provided_field . ']"]');
$this->assertNotEmpty($result);
}
// Save the form to create the type.
$page->pressButton('Save');
$assert_session->pageTextContains('The media type ' . $media_type_id . ' has been added.');
$this->drupalGet('admin/structure/media');
$assert_session->pageTextContains($media_type_id);
// Bundle definitions are statically cached in the context of the test, we
// need to make sure we have updated information before proceeding with the
// actions on the UI.
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
return MediaType::load($media_type_id);
}
}

View file

@ -0,0 +1,181 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\Component\Utility\Html;
/**
* Tests the media type creation.
*
* @group media
*/
class MediaTypeCreationTest extends MediaJavascriptTestBase {
/**
* Tests the source field behavior on the add media type form.
*/
public function testSourceChangeOnMediaTypeCreationForm() {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$label = 'Type with Default Field';
$mediaTypeMachineName = str_replace(' ', '_', strtolower($label));
$this->drupalGet('admin/structure/media/add');
// Fill in a label to the media type.
$page->fillField('label', $label);
$this->assertNotEmpty(
$assert_session->waitForElementVisible('css', '.machine-name-value')
);
// Select the media source used by our media type.
$assert_session->selectExists('Media source')->selectOption('test_different_displays');
$this->assertNotEmpty(
$assert_session->waitForElementVisible('css', 'fieldset[data-drupal-selector="edit-source-configuration"]')
);
// Change the media source.
$assert_session->selectExists('Media source')->selectOption('test');
$this->assertNotEmpty(
$assert_session->waitForElement('css', 'fieldset[data-drupal-selector="edit-source-configuration"] .fieldset-wrapper .placeholder:contains("Text (plain)")')
);
$page->pressButton('Save');
// Check that source can not be changed anymore.
$this->drupalGet("admin/structure/media/manage/{$mediaTypeMachineName}");
$assert_session->pageTextContains('The media source cannot be changed after the media type is created');
$assert_session->fieldDisabled('Media source');
}
/**
* Tests the media type creation form.
*/
public function testMediaTypeCreationFormWithDefaultField() {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$label = 'Type with Default Field';
$mediaTypeMachineName = str_replace(' ', '_', strtolower($label));
$this->drupalGet('admin/structure/media/add');
// Select the media source used by our media type. Do this before setting
// the label or machine name in order to guard against the regression in
// https://www.drupal.org/project/drupal/issues/2557299.
$assert_session->fieldExists('Media source');
$assert_session->optionExists('Media source', 'test');
$page->selectFieldOption('Media source', 'test');
$result = $assert_session->waitForElementVisible('css', 'fieldset[data-drupal-selector="edit-source-configuration"]');
$this->assertNotEmpty($result);
// Fill in a label to the media type.
$page->fillField('label', $label);
// Wait for machine name generation. Default: waitUntilVisible(), does not
// work properly.
$session->wait(5000, "jQuery('.machine-name-value').text() === '{$mediaTypeMachineName}'");
$page->pressButton('Save');
// Check whether the source field was correctly created.
$this->drupalGet("admin/structure/media/manage/{$mediaTypeMachineName}/fields");
// Check 2nd column of first data row, to be machine name for field name.
$assert_session->elementContains('xpath', '(//table[@id="field-overview"]//tr)[2]//td[2]', 'field_media_test');
// Check 3rd column of first data row, to be correct field type.
$assert_session->elementTextContains('xpath', '(//table[@id="field-overview"]//tr)[2]//td[3]', 'Text (plain)');
// Check that the source field is correctly assigned to media type.
$this->drupalGet("admin/structure/media/manage/{$mediaTypeMachineName}");
$assert_session->pageTextContains('Test source field is used to store the essential information about the media item.');
// Check that the plugin cannot be changed after it is set on type creation.
$assert_session->fieldDisabled('Media source');
$assert_session->pageTextContains('The media source cannot be changed after the media type is created.');
// Open up the media add form and verify that the source field is right
// after the name, and before the vertical tabs.
$this->drupalGet("/media/add/$mediaTypeMachineName");
// Get the form element, and its HTML representation.
$form_selector = '#media-' . Html::cleanCssIdentifier($mediaTypeMachineName) . '-add-form';
$form = $assert_session->elementExists('css', $form_selector);
$form_html = $form->getOuterHtml();
// The name field should come before the source field, which should itself
// come before the vertical tabs.
$name_field = $assert_session->fieldExists('Name', $form)->getOuterHtml();
$test_source_field = $assert_session->fieldExists('Test source', $form)->getOuterHtml();
$vertical_tabs = $assert_session->elementExists('css', '.vertical-tabs', $form)->getOuterHtml();
$date_field = $assert_session->fieldExists('Date', $form)->getOuterHtml();
$published_checkbox = $assert_session->fieldExists('Published', $form)->getOuterHtml();
$this->assertTrue(strpos($form_html, $test_source_field) > strpos($form_html, $name_field));
$this->assertTrue(strpos($form_html, $vertical_tabs) > strpos($form_html, $test_source_field));
// The "Published" checkbox should be the last element.
$this->assertTrue(strpos($form_html, $published_checkbox) > strpos($form_html, $date_field));
// Check that a new type with the same machine name cannot be created.
$this->drupalGet('admin/structure/media/add');
$page->fillField('label', $label);
$session->wait(5000, "jQuery('.machine-name-value').text() === '{$mediaTypeMachineName}'");
$page->selectFieldOption('Media source', 'test');
$assert_session->assertWaitOnAjaxRequest();
$page->pressButton('Save');
$assert_session->pageTextContains('The machine-readable name is already in use. It must be unique.');
}
/**
* Test creation of media type, reusing an existing source field.
*/
public function testMediaTypeCreationReuseSourceField() {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
// Create a new media type, which should create a new field we can reuse.
$this->drupalGet('/admin/structure/media/add');
// Choose the source plugin before setting the label and machine name.
$page->selectFieldOption('Media source', 'test');
$result = $assert_session->waitForElementVisible('css', 'fieldset[data-drupal-selector="edit-source-configuration"]');
$this->assertNotEmpty($result);
$page->fillField('label', 'Pastafazoul');
$session->wait(5000, "jQuery('.machine-name-value').text() === 'pastafazoul'");
$page->pressButton('Save');
$label = 'Type reusing Default Field';
$mediaTypeMachineName = str_replace(' ', '_', strtolower($label));
$this->drupalGet('admin/structure/media/add');
// Select the media source used by our media type. Do this before setting
// the label and machine name.
$assert_session->fieldExists('Media source');
$assert_session->optionExists('Media source', 'test');
$page->selectFieldOption('Media source', 'test');
$result = $assert_session->waitForElementVisible('css', 'fieldset[data-drupal-selector="edit-source-configuration"]');
$this->assertNotEmpty($result);
// Select the existing field for re-use.
$page->selectFieldOption('source_configuration[source_field]', 'field_media_test');
// Fill in a label to the media type.
$page->fillField('label', $label);
// Wait for machine name generation. Default: waitUntilVisible(), does not
// work properly.
$session->wait(5000, "jQuery('.machine-name-value').text() === '{$mediaTypeMachineName}'");
$page->pressButton('Save');
// Check that no new fields were created.
$this->drupalGet("admin/structure/media/manage/{$mediaTypeMachineName}/fields");
// The reused field should be present...
$assert_session->pageTextContains('field_media_test');
// ...not a new, unique one.
$assert_session->pageTextNotContains('field_media_test_1');
}
}

View file

@ -0,0 +1,205 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\field\FieldConfigInterface;
use Drupal\media\Entity\Media;
use Drupal\media\Entity\MediaType;
use Drupal\media\MediaSourceInterface;
/**
* Ensures that media UI works correctly.
*
* @group media
*/
class MediaUiJavascriptTest extends MediaJavascriptTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'block',
'media_test_source',
];
/**
* The test media type.
*
* @var \Drupal\media\MediaTypeInterface
*/
protected $testMediaType;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('local_actions_block');
$this->drupalPlaceBlock('local_tasks_block');
}
/**
* Tests a media type administration.
*/
public function testMediaTypes() {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$this->drupalGet('admin/structure/media');
$assert_session->pageTextContains('No media types available. Add media type.');
$assert_session->linkExists('Add media type');
// Test the creation of a media type using the UI.
$name = $this->randomMachineName();
$description = $this->randomMachineName();
$this->drupalGet('admin/structure/media/add');
$page->fillField('label', $name);
$machine_name = strtolower($name);
$this->assertJsCondition("jQuery('.machine-name-value').html() == '$machine_name'");
$page->selectFieldOption('source', 'test');
$this->assertJsCondition("jQuery('.form-item-source-configuration-test-config-value').length > 0;");
$page->fillField('description', $description);
$page->pressButton('Save');
// The wait prevents intermittent test failures.
$result = $assert_session->waitForLink('Add media type');
$this->assertNotEmpty($result);
$assert_session->addressEquals('admin/structure/media');
$assert_session->pageTextContains('The media type ' . $name . ' has been added.');
$this->drupalGet('admin/structure/media');
$assert_session->pageTextContains($name);
$assert_session->pageTextContains($description);
// We need to clear the statically cached field definitions to account for
// fields that have been created by API calls in this test, since they exist
// in a separate memory space from the web server.
$this->container->get('entity_field.manager')->clearCachedFieldDefinitions();
// Assert that the field and field storage were created.
$media_type = MediaType::load($machine_name);
$source = $media_type->getSource();
/** @var \Drupal\field\FieldConfigInterface $source_field */
$source_field = $source->getSourceFieldDefinition($media_type);
$this->assertInstanceOf(FieldConfigInterface::class, $source_field, 'Source field exists.');
$this->assertFalse($source_field->isNew(), 'Source field was saved.');
/** @var \Drupal\field\FieldStorageConfigInterface $storage */
$storage = $source_field->getFieldStorageDefinition();
$this->assertFalse($storage->isNew(), 'Source field storage definition was saved.');
$this->assertFalse($storage->isLocked(), 'Source field storage definition was not locked.');
/** @var \Drupal\media\MediaTypeInterface $media_type_storage */
$media_type_storage = $this->container->get('entity_type.manager')->getStorage('media_type');
$this->testMediaType = $media_type_storage->load(strtolower($name));
// Check if all action links exist.
$assert_session->linkByHrefExists('admin/structure/media/add');
$assert_session->linkByHrefExists('admin/structure/media/manage/' . $this->testMediaType->id());
$assert_session->linkByHrefExists('admin/structure/media/manage/' . $this->testMediaType->id() . '/fields');
$assert_session->linkByHrefExists('admin/structure/media/manage/' . $this->testMediaType->id() . '/form-display');
$assert_session->linkByHrefExists('admin/structure/media/manage/' . $this->testMediaType->id() . '/display');
// Assert that fields have expected values before editing.
$page->clickLink('Edit');
$assert_session->fieldValueEquals('label', $name);
$assert_session->fieldValueEquals('description', $description);
$assert_session->fieldValueEquals('source', 'test');
$assert_session->fieldValueEquals('label', $name);
$assert_session->checkboxNotChecked('edit-options-new-revision');
$assert_session->checkboxChecked('edit-options-status');
$assert_session->checkboxNotChecked('edit-options-queue-thumbnail-downloads');
$assert_session->pageTextContains('Create new revision');
$assert_session->pageTextContains('Automatically create new revisions. Users with the "Administer media" permission will be able to override this option.');
$assert_session->pageTextContains('Download thumbnails via a queue.');
$assert_session->pageTextContains('Media will be automatically published when created.');
$assert_session->pageTextContains('Media sources can provide metadata fields such as title, caption, size information, credits, etc. Media can automatically save this metadata information to entity fields, which can be configured below. Information will only be mapped if the entity field is empty.');
// Try to change media type and check if new configuration sub-form appears.
$page->selectFieldOption('source', 'test');
$result = $assert_session->waitForElementVisible('css', 'fieldset[data-drupal-selector="edit-source-configuration"]');
$this->assertNotEmpty($result);
$assert_session->fieldExists('Test config value');
$assert_session->fieldValueEquals('Test config value', 'This is default value.');
$assert_session->fieldExists('Attribute 1');
$assert_session->fieldExists('Attribute 2');
// Test if the edit machine name is not editable.
$assert_session->fieldDisabled('Machine-readable name');
// Edit and save media type form fields with new values.
$new_name = $this->randomMachineName();
$new_description = $this->randomMachineName();
$page->fillField('label', $new_name);
$page->fillField('description', $new_description);
$page->selectFieldOption('source', 'test');
$page->fillField('Test config value', 'This is new config value.');
$page->selectFieldOption('field_map[attribute_1]', 'name');
$page->checkField('options[new_revision]');
$page->uncheckField('options[status]');
$page->checkField('options[queue_thumbnail_downloads]');
$page->pressButton('Save');
// The wait prevents intermittent test failures.
$result = $assert_session->waitForLink('Add media type');
$this->assertNotEmpty($result);
$assert_session->addressEquals('admin/structure/media');
$assert_session->pageTextContains("The media type $new_name has been updated.");
// Test if edit worked and if new field values have been saved as expected.
$this->drupalGet('admin/structure/media/manage/' . $this->testMediaType->id());
$assert_session->fieldValueEquals('label', $new_name);
$assert_session->fieldValueEquals('description', $new_description);
$assert_session->fieldValueEquals('source', 'test');
$assert_session->checkboxChecked('options[new_revision]');
$assert_session->checkboxNotChecked('options[status]');
$assert_session->checkboxChecked('options[queue_thumbnail_downloads]');
$assert_session->fieldValueEquals('Test config value', 'This is new config value.');
$assert_session->fieldValueEquals('Attribute 1', 'name');
$assert_session->fieldValueEquals('Attribute 2', MediaSourceInterface::METADATA_FIELD_EMPTY);
/** @var \Drupal\media\MediaTypeInterface $loaded_media_type */
$loaded_media_type = $this->container->get('entity_type.manager')
->getStorage('media_type')
->load($this->testMediaType->id());
$this->assertSame($loaded_media_type->id(), $this->testMediaType->id());
$this->assertSame($loaded_media_type->label(), $new_name);
$this->assertSame($loaded_media_type->getDescription(), $new_description);
$this->assertSame($loaded_media_type->getSource()->getPluginId(), 'test');
$this->assertSame($loaded_media_type->getSource()->getConfiguration()['test_config_value'], 'This is new config value.');
$this->assertTrue($loaded_media_type->shouldCreateNewRevision());
$this->assertTrue($loaded_media_type->thumbnailDownloadsAreQueued());
$this->assertFalse($loaded_media_type->getStatus());
$this->assertSame($loaded_media_type->getFieldMap(), ['attribute_1' => 'name']);
// We need to clear the statically cached field definitions to account for
// fields that have been created by API calls in this test, since they exist
// in a separate memory space from the web server.
$this->container->get('entity_field.manager')->clearCachedFieldDefinitions();
// Test that a media item being created with default status to "FALSE",
// will be created unpublished.
/** @var \Drupal\media\MediaInterface $unpublished_media */
$unpublished_media = Media::create(['name' => 'unpublished test media', 'bundle' => $loaded_media_type->id()]);
$this->assertFalse($unpublished_media->isPublished());
$unpublished_media->delete();
// Tests media type delete form.
$page->clickLink('Delete');
$assert_session->addressEquals('admin/structure/media/manage/' . $this->testMediaType->id() . '/delete');
$page->pressButton('Delete');
$assert_session->addressEquals('admin/structure/media');
$assert_session->pageTextContains('The media type ' . $new_name . ' has been deleted.');
// Test that the system for preventing the deletion of media types works
// (they cannot be deleted if there is media content of that type/bundle).
$media_type2 = $this->createMediaType('test');
$label2 = $media_type2->label();
$media = Media::create(['name' => 'lorem ipsum', 'bundle' => $media_type2->id()]);
$media->save();
$this->drupalGet('admin/structure/media/manage/' . $media_type2->id());
$page->clickLink('Delete');
$assert_session->addressEquals('admin/structure/media/manage/' . $media_type2->id() . '/delete');
$assert_session->buttonNotExists('edit-submit');
$assert_session->pageTextContains("$label2 is used by 1 media item on your site. You can not remove this media type until you have removed all of the $label2 media items.");
}
}

View file

@ -0,0 +1,89 @@
<?php
namespace Drupal\Tests\media\FunctionalJavascript;
use Drupal\views\Views;
/**
* Tests the media entity type integration into the wizard.
*
* @group media
*
* @see \Drupal\media\Plugin\views\wizard\Media
* @see \Drupal\media\Plugin\views\wizard\MediaRevision
*/
class MediaViewsWizardTest extends MediaJavascriptTestBase {
/**
* Tests adding a view of media.
*/
public function testMediaWizard() {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$this->createMediaType('test');
$view_id = strtolower($this->randomMachineName(16));
$this->drupalGet('admin/structure/views/add');
$page->fillField('label', $view_id);
$this->waitUntilVisible('.machine-name-value');
$page->selectFieldOption('show[wizard_key]', 'media');
$result = $assert_session->waitForElementVisible('css', 'select[data-drupal-selector="edit-show-type"]');
$this->assertNotEmpty($result);
$page->checkField('page[create]');
$page->fillField('page[path]', $this->randomMachineName(16));
$page->pressButton('Save and edit');
$this->assertSame($session->getCurrentUrl(), $this->baseUrl . '/admin/structure/views/view/' . $view_id);
$view = Views::getView($view_id);
$view->initHandlers();
$row = $view->display_handler->getOption('row');
$this->assertSame($row['type'], 'fields');
// Check for the default filters.
$this->assertSame($view->filter['status']->table, 'media_field_data');
$this->assertSame($view->filter['status']->field, 'status');
$this->assertTrue($view->filter['status']->value);
// Check for the default fields.
$this->assertSame($view->field['name']->table, 'media_field_data');
$this->assertSame($view->field['name']->field, 'name');
}
/**
* Tests adding a view of media revisions.
*/
public function testMediaRevisionWizard() {
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
$view_id = strtolower($this->randomMachineName(16));
$this->drupalGet('admin/structure/views/add');
$page->fillField('label', $view_id);
$this->waitUntilVisible('.machine-name-value');
$page->selectFieldOption('show[wizard_key]', 'media_revision');
$assert_session->assertWaitOnAjaxRequest();
$page->checkField('page[create]');
$page->fillField('page[path]', $this->randomMachineName(16));
$page->pressButton('Save and edit');
$this->assertSame($session->getCurrentUrl(), $this->baseUrl . '/admin/structure/views/view/' . $view_id);
$view = Views::getView($view_id);
$view->initHandlers();
$row = $view->display_handler->getOption('row');
$this->assertSame($row['type'], 'fields');
// Check for the default filters.
$this->assertSame($view->filter['status']->table, 'media_field_revision');
$this->assertSame($view->filter['status']->field, 'status');
$this->assertTrue($view->filter['status']->value);
// Check for the default fields.
$this->assertSame($view->field['name']->table, 'media_field_revision');
$this->assertSame($view->field['name']->field, 'name');
$this->assertSame($view->field['changed']->table, 'media_field_revision');
$this->assertSame($view->field['changed']->field, 'changed');
}
}

View file

@ -0,0 +1,81 @@
<?php
namespace Drupal\Tests\media\Kernel;
use Drupal\media\Entity\Media;
use Drupal\media\Entity\MediaType;
use Drupal\media\MediaInterface;
use Drupal\media\MediaTypeInterface;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
/**
* Tests creation of media types and media items.
*
* @group media
*/
class MediaCreationTest extends MediaKernelTestBase {
/**
* Tests creating a media type programmatically.
*/
public function testMediaTypeCreation() {
$media_type_storage = $this->container->get('entity_type.manager')->getStorage('media_type');
$this->assertInstanceOf(MediaTypeInterface::class, MediaType::load($this->testMediaType->id()), 'The new media type has not been correctly created in the database.');
// Test a media type created from default configuration.
$this->container->get('module_installer')->install(['media_test_type']);
$test_media_type = $media_type_storage->load('test');
$this->assertInstanceOf(MediaTypeInterface::class, $test_media_type, 'The media type from default configuration has not been created in the database.');
$this->assertSame('Test type', $test_media_type->get('label'), 'Could not assure the correct type name.');
$this->assertSame('Test type.', $test_media_type->get('description'), 'Could not assure the correct type description.');
$this->assertSame('test', $test_media_type->get('source'), 'Could not assure the correct media source.');
// Source field is not set on the media source, but it should never
// be created automatically when a config is being imported.
$this->assertSame(['source_field' => '', 'test_config_value' => 'Kakec'], $test_media_type->get('source_configuration'), 'Could not assure the correct media source configuration.');
$this->assertSame(['metadata_attribute' => 'field_attribute_config_test'], $test_media_type->get('field_map'), 'Could not assure the correct field map.');
// Check the Media Type access handler behavior.
// We grant access to the 'view label' operation to all users having
// permission to 'view media'.
$user1 = User::create([
'name' => 'username1',
'status' => 1,
]);
$user1->save();
$user2 = User::create([
'name' => 'username2',
'status' => 1,
]);
$user2->save();
$role = Role::create([
'id' => 'role1',
'label' => 'role1',
]);
$role->grantPermission('view media')->trustData()->save();
$user2->addRole($role->id());
$this->assertFalse($test_media_type->access('view label', $user1));
$this->assertTrue($test_media_type->access('view label', $user2));
}
/**
* Tests creating a media item programmatically.
*/
public function testMediaEntityCreation() {
$media = Media::create([
'bundle' => $this->testMediaType->id(),
'name' => 'Unnamed',
'field_media_test' => 'Nation of sheep, ruled by wolves, owned by pigs.',
]);
$media->save();
$this->assertNotInstanceOf(MediaInterface::class, Media::load(rand(1000, 9999)), 'Failed asserting a non-existent media.');
$this->assertInstanceOf(MediaInterface::class, Media::load($media->id()), 'The new media item has not been created in the database.');
$this->assertSame($this->testMediaType->id(), $media->bundle(), 'The media item was not created with the correct type.');
$this->assertSame('Unnamed', $media->getName(), 'The media item was not created with the correct name.');
$source_field_name = $media->bundle->entity->getSource()->getSourceFieldDefinition($media->bundle->entity)->getName();
$this->assertSame('Nation of sheep, ruled by wolves, owned by pigs.', $media->get($source_field_name)->value, 'Source returns incorrect source field value.');
}
}

View file

@ -0,0 +1,121 @@
<?php
namespace Drupal\Tests\media\Kernel;
use Drupal\file\Entity\File;
use Drupal\KernelTests\KernelTestBase;
use Drupal\media\Entity\Media;
use Drupal\media\MediaTypeInterface;
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
use Drupal\user\Entity\User;
use org\bovigo\vfs\vfsStream;
/**
* Base class for Media kernel tests.
*/
abstract class MediaKernelTestBase extends KernelTestBase {
use MediaTypeCreationTrait;
/**
* Modules to install.
*
* @var array
*/
public static $modules = [
'media',
'media_test_source',
'image',
'user',
'field',
'system',
'file',
];
/**
* The test media type.
*
* @var \Drupal\media\MediaTypeInterface
*/
protected $testMediaType;
/**
* The test media type with constraints.
*
* @var \Drupal\media\MediaTypeInterface
*/
protected $testConstraintsMediaType;
/**
* A user.
*
* @var \Drupal\user\UserInterface
*/
protected $user;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('user');
$this->installEntitySchema('file');
$this->installSchema('file', 'file_usage');
$this->installSchema('system', 'sequences');
$this->installEntitySchema('media');
$this->installConfig(['field', 'system', 'image', 'file', 'media']);
// Create a test media type.
$this->testMediaType = $this->createMediaType('test');
// Create a test media type with constraints.
$this->testConstraintsMediaType = $this->createMediaType('test_constraints');
$this->user = User::create([
'name' => 'username',
'status' => 1,
]);
$this->user->save();
$this->container->get('current_user')->setAccount($this->user);
}
/**
* Helper to generate a media item.
*
* @param string $filename
* String filename with extension.
* @param \Drupal\media\MediaTypeInterface $media_type
* The the media type.
*
* @return \Drupal\media\Entity\Media
* A media item.
*/
protected function generateMedia($filename, MediaTypeInterface $media_type) {
vfsStream::setup('drupal_root');
vfsStream::create([
'sites' => [
'default' => [
'files' => [
$filename => str_repeat('a', 3000),
],
],
],
]);
$file = File::create([
'uri' => 'vfs://drupal_root/sites/default/files/' . $filename,
'uid' => $this->user->id(),
]);
$file->setPermanent();
$file->save();
return Media::create([
'bundle' => $media_type->id(),
'name' => 'Mr. Jones',
'field_media_file' => [
'target_id' => $file->id(),
],
]);
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace Drupal\Tests\media\Kernel;
use Drupal\media\Entity\Media;
/**
* Tests link relationships for media items.
*
* @group media
*/
class MediaLinkRelationsTest extends MediaKernelTestBase {
/**
* Tests that all link relationships for Media exist.
*/
public function testExistLinkRelationships() {
/** @var \Drupal\Core\Http\LinkRelationTypeManager $link_relation_type_manager */
$link_relation_type_manager = $this->container->get('plugin.manager.link_relation_type');
$media = Media::create(['bundle' => $this->testMediaType->id()]);
$media->save();
foreach ($media->uriRelationships() as $relation_name) {
$this->assertTrue($link_relation_type_manager->hasDefinition($relation_name), "Link relationship '{$relation_name}' for a media item");
}
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace Drupal\Tests\media\Kernel;
/**
* Tests the file media source.
*
* @group media
*/
class MediaSourceFileTest extends MediaKernelTestBase {
/**
* Tests the file extension constraint.
*/
public function testFileExtensionConstraint() {
$mediaType = $this->createMediaType('file');
// Create a random file that should fail.
$media = $this->generateMedia('test.patch', $mediaType);
$result = $media->validate();
$this->assertCount(1, $result);
$this->assertSame('field_media_file.0', $result->get(0)->getPropertyPath());
$this->assertContains('Only files with the following extensions are allowed:', (string) $result->get(0)->getMessage());
// Create a random file that should pass.
$media = $this->generateMedia('test.txt', $mediaType);
$result = $media->validate();
$this->assertCount(0, $result);
}
}

View file

@ -0,0 +1,601 @@
<?php
namespace Drupal\Tests\media\Kernel;
use Drupal\Core\Form\FormState;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\media\Entity\Media;
use Drupal\media\Entity\MediaType;
/**
* Tests media source plugins related logic.
*
* @group media
*/
class MediaSourceTest extends MediaKernelTestBase {
/**
* Tests that metadata is correctly mapped irrespective of how media is saved.
*/
public function testSave() {
$field_storage = FieldStorageConfig::create([
'entity_type' => 'media',
'field_name' => 'field_to_map_to',
'type' => 'string',
]);
$field_storage->save();
FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => $this->testMediaType->id(),
'label' => 'Field to map to',
])->save();
// Set an arbitrary metadata value to be mapped.
$this->container->get('state')
->set('media_source_test_attributes', [
'attribute_to_map' => [
'title' => 'Attribute to map',
'value' => 'Snowball',
],
'thumbnail_uri' => [
'title' => 'Thumbnail',
'value' => 'public://TheSisko.png',
],
]);
$this->testMediaType->setFieldMap([
'attribute_to_map' => 'field_to_map_to',
])->save();
/** @var \Drupal\Core\Entity\EntityStorageInterface $storage */
$storage = $this->container->get('entity_type.manager')
->getStorage('media');
/** @var \Drupal\media\MediaInterface $a */
$a = $storage->create([
'bundle' => $this->testMediaType->id(),
]);
/** @var \Drupal\media\MediaInterface $b */
$b = $storage->create([
'bundle' => $this->testMediaType->id(),
]);
// Set a random source value on both items.
$a->set($a->getSource()->getSourceFieldDefinition($a->bundle->entity)->getName(), $this->randomString());
$b->set($b->getSource()->getSourceFieldDefinition($b->bundle->entity)->getName(), $this->randomString());
$a->save();
$storage->save($b);
// Assert that the default name was mapped into the name field for both
// media items.
$this->assertFalse($a->get('name')->isEmpty());
$this->assertFalse($b->get('name')->isEmpty());
// Assert that arbitrary metadata was mapped correctly.
$this->assertFalse($a->get('field_to_map_to')->isEmpty());
$this->assertFalse($b->get('field_to_map_to')->isEmpty());
// Assert that the thumbnail was mapped correctly from the source.
$this->assertSame('public://TheSisko.png', $a->thumbnail->entity->getFileUri());
$this->assertSame('public://TheSisko.png', $b->thumbnail->entity->getFileUri());
}
/**
* Tests default media name functionality.
*/
public function testDefaultName() {
// Make sure that the default name is set if not provided by the user.
/** @var \Drupal\media\MediaInterface $media */
$media = Media::create(['bundle' => $this->testMediaType->id()]);
$media_source = $media->getSource();
$this->assertSame('default_name', $media_source->getPluginDefinition()['default_name_metadata_attribute'], 'Default metadata attribute is not used for the default name.');
$this->assertSame('media:' . $media->bundle() . ':' . $media->uuid(), $media_source->getMetadata($media, 'default_name'), 'Value of the default name metadata attribute does not look correct.');
$this->assertSame('media:' . $media->bundle() . ':' . $media->uuid(), $media->getName(), 'Default name was not used correctly by getName().');
$this->assertSame($media->getName(), $media->label(), 'Default name and label are not the same.');
$media->save();
$this->assertSame('media:' . $media->bundle() . ':' . $media->uuid(), $media->getName(), 'Default name was not saved correctly.');
$this->assertSame($media->getName(), $media->label(), 'The label changed during save.');
// Make sure that the user-supplied name is used.
/** @var \Drupal\media\MediaInterface $media */
$name = 'User-supplied name';
$media = Media::create([
'bundle' => $this->testMediaType->id(),
'name' => $name,
]);
$media_source = $media->getSource();
$this->assertSame('default_name', $media_source->getPluginDefinition()['default_name_metadata_attribute'], 'Default metadata attribute is not used for the default name.');
$this->assertSame('media:' . $media->bundle() . ':' . $media->uuid(), $media_source->getMetadata($media, 'default_name'), 'Value of the default name metadata attribute does not look correct.');
$media->save();
$this->assertSame($name, $media->getName(), 'User-supplied name was not set correctly.');
$this->assertSame($media->getName(), $media->label(), 'The user-supplied name does not match the label.');
// Change the default name attribute and see if it is used to set the name.
$name = 'Old Major';
\Drupal::state()->set('media_source_test_attributes', ['alternative_name' => ['title' => 'Alternative name', 'value' => $name]]);
\Drupal::state()->set('media_source_test_definition', ['default_name_metadata_attribute' => 'alternative_name']);
/** @var \Drupal\media\MediaInterface $media */
$media = Media::create(['bundle' => $this->testMediaType->id()]);
$media_source = $media->getSource();
$this->assertSame('alternative_name', $media_source->getPluginDefinition()['default_name_metadata_attribute'], 'Correct metadata attribute is not used for the default name.');
$this->assertSame($name, $media_source->getMetadata($media, 'alternative_name'), 'Value of the default name metadata attribute does not look correct.');
$media->save();
$this->assertSame($name, $media->getName(), 'Default name was not set correctly.');
$this->assertSame($media->getName(), $media->label(), 'The default name does not match the label.');
}
/**
* Tests metadata mapping functionality.
*/
public function testMetadataMapping() {
$field_name = 'field_to_map_to';
$attribute_name = 'attribute_to_map';
$storage = FieldStorageConfig::create([
'entity_type' => 'media',
'field_name' => $field_name,
'type' => 'string',
]);
$storage->save();
FieldConfig::create([
'field_storage' => $storage,
'bundle' => $this->testMediaType->id(),
'label' => 'Field to map to',
])->save();
// Save the entity without defining the metadata mapping and check that the
// field stays empty.
/** @var \Drupal\media\MediaInterface $media */
$media = Media::create([
'bundle' => $this->testMediaType->id(),
'field_media_test' => 'some_value',
]);
$media->save();
$this->assertEmpty($media->get($field_name)->value, 'Field stayed empty.');
// Make sure that source plugin returns NULL for non-existing fields.
$this->testMediaType->setFieldMap(['not_here_at_all' => $field_name])->save();
$media = Media::create([
'bundle' => $this->testMediaType->id(),
'field_media_test' => 'some_value',
]);
$media_source = $media->getSource();
$this->assertNull($media_source->getMetadata($media, 'not_here_at_all'), 'NULL is not returned if asking for a value of non-existing metadata.');
$media->save();
$this->assertTrue($media->get($field_name)->isEmpty(), 'Non-existing metadata attribute was wrongly mapped to the field.');
// Define mapping and make sure that the value was stored in the field.
\Drupal::state()->set('media_source_test_attributes', [
$attribute_name => ['title' => 'Attribute to map', 'value' => 'Snowball'],
]);
$this->testMediaType->setFieldMap([$attribute_name => $field_name])->save();
$media = Media::create([
'bundle' => $this->testMediaType->id(),
'field_media_test' => 'some_value',
]);
$media_source = $media->getSource();
$this->assertSame('Snowball', $media_source->getMetadata($media, $attribute_name), 'Value of the metadata attribute is not correct.');
$media->save();
$this->assertSame('Snowball', $media->get($field_name)->value, 'Metadata attribute was not mapped to the field.');
// Change the metadata attribute value and re-save the entity. Field value
// should stay the same.
\Drupal::state()->set('media_source_test_attributes', [
$attribute_name => ['title' => 'Attribute to map', 'value' => 'Pinkeye'],
]);
$this->assertSame('Pinkeye', $media_source->getMetadata($media, $attribute_name), 'Value of the metadata attribute is not correct.');
$media->save();
$this->assertSame('Snowball', $media->get($field_name)->value, 'Metadata attribute was not mapped to the field.');
// Now change the value of the source field and make sure that the mapped
// values update too.
$this->assertSame('Pinkeye', $media_source->getMetadata($media, $attribute_name), 'Value of the metadata attribute is not correct.');
$media->set('field_media_test', 'some_new_value');
$media->save();
$this->assertSame('Pinkeye', $media->get($field_name)->value, 'Metadata attribute was not mapped to the field.');
// Remove the value of the mapped field and make sure that it is re-mapped
// on save.
\Drupal::state()->set('media_source_test_attributes', [
$attribute_name => ['title' => 'Attribute to map', 'value' => 'Snowball'],
]);
$media->{$field_name}->value = NULL;
$this->assertSame('Snowball', $media_source->getMetadata($media, $attribute_name), 'Value of the metadata attribute is not correct.');
$media->save();
$this->assertSame('Snowball', $media->get($field_name)->value, 'Metadata attribute was not mapped to the field.');
}
/**
* Tests the getSourceFieldValue() method.
*/
public function testGetSourceFieldValue() {
/** @var \Drupal\media\MediaInterface $media */
$media = Media::create([
'bundle' => $this->testMediaType->id(),
'field_media_test' => 'some_value',
]);
$media->save();
$media_source = $media->getSource();
$this->assertSame('some_value', $media_source->getSourceFieldValue($media));
}
/**
* Tests the thumbnail functionality.
*/
public function testThumbnail() {
file_put_contents('public://thumbnail1.jpg', '');
file_put_contents('public://thumbnail2.jpg', '');
// Save a media item and make sure thumbnail was added.
\Drupal::state()->set('media_source_test_attributes', [
'thumbnail_uri' => ['title' => 'Thumbnail', 'value' => 'public://thumbnail1.jpg'],
]);
/** @var \Drupal\media\MediaInterface $media */
$media = Media::create([
'bundle' => $this->testMediaType->id(),
'name' => 'Mr. Jones',
'field_media_test' => 'some_value',
]);
$media_source = $media->getSource();
$this->assertSame('public://thumbnail1.jpg', $media_source->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is not correct.');
$media->save();
$this->assertSame('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'Thumbnail was not added to the media item.');
$this->assertSame('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.');
$this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.');
// Now change the metadata attribute and make sure that the thumbnail stays
// the same.
\Drupal::state()->set('media_source_test_attributes', [
'thumbnail_uri' => ['title' => 'Thumbnail', 'value' => 'public://thumbnail2.jpg'],
]);
$this->assertSame('public://thumbnail2.jpg', $media_source->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is not correct.');
$media->save();
$this->assertSame('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'Thumbnail was not preserved.');
$this->assertSame('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.');
$this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.');
// Remove the thumbnail and make sure that it is auto-updated on save.
$media->thumbnail->target_id = NULL;
$this->assertSame('public://thumbnail2.jpg', $media_source->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is not correct.');
$media->save();
$this->assertSame('public://thumbnail2.jpg', $media->thumbnail->entity->getFileUri(), 'New thumbnail was not added to the media item.');
$this->assertSame('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.');
$this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.');
// Change the metadata attribute again, change the source field value too
// and make sure that the thumbnail updates.
\Drupal::state()->set('media_source_test_attributes', [
'thumbnail_uri' => ['title' => 'Thumbnail', 'value' => 'public://thumbnail1.jpg'],
]);
$media->field_media_test->value = 'some_new_value';
$this->assertSame('public://thumbnail1.jpg', $media_source->getMetadata($media, 'thumbnail_uri'), 'Value of the thumbnail metadata attribute is not correct.');
$media->save();
$this->assertSame('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'New thumbnail was not added to the media item.');
$this->assertSame('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.');
$this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.');
// Change the thumbnail metadata attribute and make sure that the thumbnail
// is set correctly.
\Drupal::state()->set('media_source_test_attributes', [
'thumbnail_uri' => ['title' => 'Should not be used', 'value' => 'public://thumbnail1.jpg'],
'alternative_thumbnail_uri' => ['title' => 'Should be used', 'value' => 'public://thumbnail2.jpg'],
]);
\Drupal::state()->set('media_source_test_definition', ['thumbnail_uri_metadata_attribute' => 'alternative_thumbnail_uri']);
$media = Media::create([
'bundle' => $this->testMediaType->id(),
'name' => 'Mr. Jones',
'field_media_test' => 'some_value',
]);
$media_source = $media->getSource();
$this->assertSame('public://thumbnail1.jpg', $media_source->getMetadata($media, 'thumbnail_uri'), 'Value of the metadata attribute is not correct.');
$this->assertSame('public://thumbnail2.jpg', $media_source->getMetadata($media, 'alternative_thumbnail_uri'), 'Value of the thumbnail metadata attribute is not correct.');
$media->save();
$this->assertSame('public://thumbnail2.jpg', $media->thumbnail->entity->getFileUri(), 'Correct metadata attribute was not used for the thumbnail.');
$this->assertSame('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.');
$this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.');
// Enable queued thumbnails and make sure that the entity gets the default
// thumbnail initially.
\Drupal::state()->set('media_source_test_definition', []);
\Drupal::state()->set('media_source_test_attributes', [
'thumbnail_uri' => ['title' => 'Should not be used', 'value' => 'public://thumbnail1.jpg'],
]);
$this->testMediaType->setQueueThumbnailDownloadsStatus(TRUE)->save();
$media = Media::create([
'bundle' => $this->testMediaType->id(),
'name' => 'Mr. Jones',
'field_media_test' => 'some_value',
]);
$this->assertSame('public://thumbnail1.jpg', $media->getSource()->getMetadata($media, 'thumbnail_uri'), 'Value of the metadata attribute is not correct.');
$media->save();
$this->assertSame('public://media-icons/generic/generic.png', $media->thumbnail->entity->getFileUri(), 'Default thumbnail was not set initially.');
$this->assertSame('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.');
$this->assertEquals('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.');
// Process the queue item and make sure that the thumbnail was updated too.
$queue_name = 'media_entity_thumbnail';
/** @var \Drupal\Core\Queue\QueueWorkerInterface $queue_worker */
$queue_worker = \Drupal::service('plugin.manager.queue_worker')->createInstance($queue_name);
$queue = \Drupal::queue($queue_name);
$this->assertSame(1, $queue->numberOfItems(), 'Item was not added to the queue.');
$item = $queue->claimItem();
$this->assertSame($media->id(), $item->data['id'], 'Queue item that was created does not belong to the correct entity.');
$queue_worker->processItem($item->data);
$queue->deleteItem($item);
$this->assertSame(0, $queue->numberOfItems(), 'Item was not removed from the queue.');
$media = Media::load($media->id());
$this->assertSame('public://thumbnail1.jpg', $media->thumbnail->entity->getFileUri(), 'Thumbnail was not updated by the queue.');
$this->assertSame('Mr. Jones', $media->thumbnail->title, 'Title text was not set on the thumbnail.');
$this->assertSame('Thumbnail', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.');
// Set alt and title metadata attributes and make sure they are used for the
// thumbnail.
\Drupal::state()->set('media_source_test_definition', [
'thumbnail_alt_metadata_attribute' => 'alt',
'thumbnail_title_metadata_attribute' => 'title',
]);
\Drupal::state()->set('media_source_test_attributes', [
'alt' => ['title' => 'Alt text', 'value' => 'This will be alt.'],
'title' => ['title' => 'Title text', 'value' => 'This will be title.'],
]);
$media = Media::create([
'bundle' => $this->testMediaType->id(),
'name' => 'Boxer',
'field_media_test' => 'some_value',
]);
$media->save();
$this->assertSame('Boxer', $media->getName(), 'Correct name was not set on the media item.');
$this->assertSame('This will be title.', $media->thumbnail->title, 'Title text was not set on the thumbnail.');
$this->assertSame('This will be alt.', $media->thumbnail->alt, 'Alt text was not set on the thumbnail.');
}
/**
* Tests the media item constraints functionality.
*/
public function testConstraints() {
// Test entity constraints.
\Drupal::state()->set('media_source_test_entity_constraints', [
'MediaTestConstraint' => [],
]);
// Create a media item media that uses a source plugin with constraints and
// make sure the constraints works as expected when validating.
/** @var \Drupal\media\MediaInterface $media */
$media = Media::create([
'bundle' => $this->testConstraintsMediaType->id(),
'name' => 'I do not like Drupal',
'field_media_test_constraints' => 'Not checked',
]);
// Validate the entity and make sure violation is reported.
/** @var \Drupal\Core\Entity\EntityConstraintViolationListInterface $violations */
$violations = $media->validate();
$this->assertCount(1, $violations, 'Expected number of validations not found.');
$this->assertEquals('Inappropriate text.', $violations->get(0)->getMessage(), 'Incorrect constraint validation message found.');
// Fix the violation and make sure it is not reported anymore.
$media->setName('I love Drupal!');
$violations = $media->validate();
$this->assertCount(0, $violations, 'Expected number of validations not found.');
// Save and make sure it succeeded.
$this->assertEmpty($media->id(), 'Entity ID was found.');
$media->save();
$this->assertNotEmpty($media->id(), 'Entity ID was not found.');
$this->assertSame($media->getName(), 'I love Drupal!');
// Test source field constraints.
\Drupal::state()->set('media_source_test_field_constraints', [
'MediaTestConstraint' => [],
]);
\Drupal::state()->set('media_source_test_entity_constraints', []);
// Create media that uses source with constraints and make sure it can't
// be saved without validating them.
/** @var \Drupal\media\MediaInterface $media */
$media = Media::create([
'bundle' => $this->testConstraintsMediaType->id(),
'name' => 'Not checked',
'field_media_test_constraints' => 'I do not like Drupal',
]);
// Validate the entity and make sure violation is reported.
/** @var \Drupal\Core\Entity\EntityConstraintViolationListInterface $violations */
$violations = $media->validate();
$this->assertCount(1, $violations, 'Expected number of validations not found.');
$this->assertEquals('Inappropriate text.', $violations->get(0)->getMessage(), 'Incorrect constraint validation message found.');
// Fix the violation and make sure it is not reported anymore.
$media->set('field_media_test_constraints', 'I love Drupal!');
$violations = $media->validate();
$this->assertCount(0, $violations, 'Expected number of validations not found.');
// Save and make sure it succeeded.
$this->assertEmpty($media->id(), 'Entity ID was found.');
$media->save();
$this->assertNotEmpty($media->id(), 'Entity ID was not found.');
}
/**
* Tests logic related to the automated source field creation.
*/
public function testSourceFieldCreation() {
/** @var \Drupal\media\MediaTypeInterface $type */
$type = MediaType::create([
'id' => 'test_type',
'label' => 'Test type',
'source' => 'test',
]);
/** @var \Drupal\field\Entity\FieldConfig $field */
$field = $type->getSource()->createSourceField($type);
/** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */
$field_storage = $field->getFieldStorageDefinition();
// Test field storage.
$this->assertTrue($field_storage->isNew(), 'Field storage is saved automatically.');
$this->assertFalse($field_storage->isLocked(), 'Field storage is not locked.');
$this->assertSame('string', $field_storage->getType(), 'Field is not of correct type.');
$this->assertSame('field_media_test_1', $field_storage->getName(), 'Incorrect field name is used.');
$this->assertSame('media', $field_storage->getTargetEntityTypeId(), 'Field is not targeting media entities.');
// Test field.
$this->assertTrue($field->isNew(), 'Field is saved automatically.');
$this->assertSame('field_media_test_1', $field->getName(), 'Incorrect field name is used.');
$this->assertSame('string', $field->getType(), 'Field is of incorrect type.');
$this->assertTrue($field->isRequired(), 'Field is not required.');
$this->assertEquals('Test source', $field->label(), 'Incorrect label is used.');
$this->assertSame('test_type', $field->getTargetBundle(), 'Field is not targeting correct bundle.');
// Fields should be automatically saved only when creating the media type
// using the media type creation form. Make sure that they are not saved
// when creating a media type programmatically.
// Drupal\Tests\media\FunctionalJavascript\MediaTypeCreationTest is testing
// form part of the functionality.
$type->save();
$storage = FieldStorageConfig::load('media.field_media_test_1');
$this->assertNull($storage, 'Field storage was not saved.');
$field = FieldConfig::load('media.test_type.field_media_test_1');
$this->assertNull($field, 'Field storage was not saved.');
// Test the plugin with a different default source field type.
$type = MediaType::create([
'id' => 'test_constraints_type',
'label' => 'Test type with constraints',
'source' => 'test_constraints',
]);
$field = $type->getSource()->createSourceField($type);
$field_storage = $field->getFieldStorageDefinition();
// Test field storage.
$this->assertTrue($field_storage->isNew(), 'Field storage is saved automatically.');
$this->assertFalse($field_storage->isLocked(), 'Field storage is not locked.');
$this->assertSame('string_long', $field_storage->getType(), 'Field is of incorrect type.');
$this->assertSame('field_media_test_constraints_1', $field_storage->getName(), 'Incorrect field name is used.');
$this->assertSame('media', $field_storage->getTargetEntityTypeId(), 'Field is not targeting media entities.');
// Test field.
$this->assertTrue($field->isNew(), 'Field is saved automatically.');
$this->assertSame('field_media_test_constraints_1', $field->getName(), 'Incorrect field name is used.');
$this->assertSame('string_long', $field->getType(), 'Field is of incorrect type.');
$this->assertTrue($field->isRequired(), 'Field is not required.');
$this->assertEquals('Test source with constraints', $field->label(), 'Incorrect label is used.');
$this->assertSame('test_constraints_type', $field->getTargetBundle(), 'Field is not targeting correct bundle.');
}
/**
* Tests configuration form submit handler on the base media source plugin.
*/
public function testSourceConfigurationSubmit() {
/** @var \Drupal\media\MediaSourceManager $manager */
$manager = $this->container->get('plugin.manager.media.source');
$form = [];
$form_state = new FormState();
$form_state->setValues(['test_config_value' => 'Somewhere over the rainbow.']);
/** @var \Drupal\media\MediaSourceInterface $source */
$source = $manager->createInstance('test', []);
$source->submitConfigurationForm($form, $form_state);
$expected = ['source_field' => 'field_media_test_1', 'test_config_value' => 'Somewhere over the rainbow.'];
$this->assertSame($expected, $source->getConfiguration(), 'Submitted values were saved correctly.');
// Try to save a NULL value.
$form_state->setValue('test_config_value', NULL);
$source->submitConfigurationForm($form, $form_state);
$expected['test_config_value'] = NULL;
$this->assertSame($expected, $source->getConfiguration(), 'Submitted values were saved correctly.');
// Make sure that the config keys are determined correctly even if the
// existing value is NULL.
$form_state->setValue('test_config_value', 'Somewhere over the rainbow.');
$source->submitConfigurationForm($form, $form_state);
$expected['test_config_value'] = 'Somewhere over the rainbow.';
$this->assertSame($expected, $source->getConfiguration(), 'Submitted values were saved correctly.');
// Make sure that a non-relevant value will be skipped.
$form_state->setValue('not_relevant', 'Should not be saved in the plugin.');
$source->submitConfigurationForm($form, $form_state);
$this->assertSame($expected, $source->getConfiguration(), 'Submitted values were saved correctly.');
}
/**
* Tests different display options for the source field.
*/
public function testDifferentSourceFieldDisplays() {
$id = 'test_different_displays';
$field_name = 'field_media_different_display';
$this->createMediaTypeViaForm($id, $field_name);
// Source field not in displays.
$display = entity_get_display('media', $id, 'default');
$components = $display->getComponents();
$this->assertArrayHasKey($field_name, $components);
$this->assertSame('entity_reference_entity_id', $components[$field_name]['type']);
$display = entity_get_form_display('media', $id, 'default');
$components = $display->getComponents();
$this->assertArrayHasKey($field_name, $components);
$this->assertSame('entity_reference_autocomplete_tags', $components[$field_name]['type']);
}
/**
* Tests hidden source field in media type.
*/
public function testHiddenSourceField() {
$id = 'test_hidden_source_field';
$field_name = 'field_media_hidden';
$this->createMediaTypeViaForm($id, $field_name);
// Source field not in displays.
$display = entity_get_display('media', $id, 'default');
$this->assertArrayNotHasKey($field_name, $display->getComponents());
$display = entity_get_form_display('media', $id, 'default');
$this->assertArrayNotHasKey($field_name, $display->getComponents());
}
/**
* Creates a media type via form submit.
*
* @param string $source_plugin_id
* Source plugin ID.
* @param string $field_name
* Source field name.
*/
protected function createMediaTypeViaForm($source_plugin_id, $field_name) {
/** @var \Drupal\media\MediaTypeInterface $type */
$type = MediaType::create(['source' => $source_plugin_id]);
$form = $this->container->get('entity_type.manager')
->getFormObject('media_type', 'add')
->setEntity($type);
$form_state = new FormState();
$form_state->setValues([
'label' => 'Test type',
'id' => $source_plugin_id,
'op' => t('Save'),
]);
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
$field_manager = \Drupal::service('entity_field.manager');
// Source field not created yet.
$fields = $field_manager->getFieldDefinitions('media', $source_plugin_id);
$this->assertArrayNotHasKey($field_name, $fields);
\Drupal::formBuilder()->submitForm($form, $form_state);
// Source field exists now.
$fields = $field_manager->getFieldDefinitions('media', $source_plugin_id);
$this->assertArrayHasKey($field_name, $fields);
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace Drupal\Tests\media\Kernel;
use Drupal\media\Entity\Media;
/**
* Tests Media.
*
* @group media
*/
class MediaTest extends MediaKernelTestBase {
/**
* Tests various aspects of a media item.
*/
public function testEntity() {
$media = Media::create(['bundle' => $this->testMediaType->id()]);
$this->assertSame($media, $media->setOwnerId($this->user->id()), 'setOwnerId() method returns its own entity.');
}
/**
* Tests the Media "name" base field behavior.
*/
public function testNameBaseField() {
/** @var \Drupal\Core\Field\BaseFieldDefinition[] $field_definitions */
$field_definitions = $this->container->get('entity_field.manager')
->getBaseFieldDefinitions('media');
// Ensure media name is configurable on manage display.
$this->assertTrue($field_definitions['name']->isDisplayConfigurable('view'));
// Ensure it is not visible by default.
$this->assertSame($field_definitions['name']->getDisplayOptions('view'), ['region' => 'hidden']);
}
}

View file

@ -0,0 +1,103 @@
<?php
namespace Drupal\Tests\media\Kernel;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\language\Entity\ConfigurableLanguage;
/**
* Tests multilanguage fields logic.
*
* @group media
*/
class MediaTranslationTest extends MediaKernelTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['language'];
/**
* The test media translation type.
*
* @var \Drupal\media\MediaTypeInterface
*/
protected $testTranslationMediaType;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['language']);
// Create a test media type for translations.
$this->testTranslationMediaType = $this->createMediaType('test_translation');
for ($i = 0; $i < 3; ++$i) {
$language_id = 'l' . $i;
ConfigurableLanguage::create([
'id' => $language_id,
'label' => $this->randomString(),
])->save();
file_put_contents('public://' . $language_id . '.png', '');
}
}
/**
* Test translatable fields storage/retrieval.
*/
public function testTranslatableFieldSaveLoad() {
/** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
$entity_type = $this->container->get('entity_type.manager')->getDefinition('media');
$this->assertTrue($entity_type->isTranslatable(), 'Media is translatable.');
// Prepare the field translations.
$source_field_definition = $this->testTranslationMediaType->getSource()->getSourceFieldDefinition($this->testTranslationMediaType);
$source_field_storage = $source_field_definition->getFieldStorageDefinition();
/** @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage $media_storage */
$media_storage = $this->container->get('entity_type.manager')->getStorage('media');
/** @var \Drupal\media\Entity\Media $media */
$media = $media_storage->create([
'bundle' => $this->testTranslationMediaType->id(),
'name' => 'Unnamed',
]);
$field_translations = [];
$available_langcodes = array_keys($this->container->get('language_manager')->getLanguages());
$media->set('langcode', reset($available_langcodes));
foreach ($available_langcodes as $langcode) {
$values = [];
for ($i = 0; $i < $source_field_storage->getCardinality(); $i++) {
$values[$i]['value'] = $this->randomString();
}
$field_translations[$langcode] = $values;
$translation = $media->hasTranslation($langcode) ? $media->getTranslation($langcode) : $media->addTranslation($langcode);
$translation->{$source_field_definition->getName()}->setValue($field_translations[$langcode]);
}
// Save and reload the field translations.
$media->save();
$media_storage->resetCache();
$media = $media_storage->load($media->id());
// Check if the correct source field values were saved/loaded.
foreach ($field_translations as $langcode => $items) {
/** @var \Drupal\media\MediaInterface $media_translation */
$media_translation = $media->getTranslation($langcode);
$result = TRUE;
foreach ($items as $delta => $item) {
$result = $result && $item['value'] == $media_translation->{$source_field_definition->getName()}[$delta]->value;
}
$this->assertTrue($result, new FormattableMarkup('%language translation field value not correct.', ['%language' => $langcode]));
$this->assertSame('public://' . $langcode . '.png', $media_translation->getSource()->getMetadata($media_translation, 'thumbnail_uri'), new FormattableMarkup('%language translation thumbnail metadata attribute is not correct.', ['%language' => $langcode]));
$this->assertSame('public://' . $langcode . '.png', $media_translation->get('thumbnail')->entity->getFileUri(), new FormattableMarkup('%language translation thumbnail value is not correct.', ['%language' => $langcode]));
$this->assertEquals('Test Thumbnail ' . $langcode, $media_translation->getSource()->getMetadata($media_translation, 'test_thumbnail_alt'), new FormattableMarkup('%language translation thumbnail alt metadata attribute is not correct.', ['%language' => $langcode]));
$this->assertSame('Test Thumbnail ' . $langcode, $media_translation->get('thumbnail')->alt, new FormattableMarkup('%language translation thumbnail alt value is not correct.', ['%language' => $langcode]));
}
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace Drupal\Tests\media\Kernel;
use Symfony\Component\HttpFoundation\Request;
/**
* @coversDefaultClass \Drupal\media\Controller\OEmbedIframeController
*
* @group media
*/
class OEmbedIframeControllerTest extends MediaKernelTestBase {
/**
* Data provider for testBadHashParameter().
*
* @return array
*/
public function providerBadHashParameter() {
return [
'no hash' => [
'',
],
'invalid hash' => [
$this->randomString(),
],
];
}
/**
* Tests validation of the 'hash' query string parameter.
*
* @param string $hash
* The 'hash' query string parameter.
*
* @dataProvider providerBadHashParameter
*
* @covers ::render
*/
public function testBadHashParameter($hash) {
/** @var callable $controller */
$controller = $this->container
->get('controller_resolver')
->getControllerFromDefinition('\Drupal\media\Controller\OEmbedIframeController::render');
$this->assertInternalType('callable', $controller);
$this->setExpectedException('\Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException', 'This resource is not available');
$request = new Request([
'url' => 'https://example.com/path/to/resource',
'hash' => $hash,
]);
$controller($request);
}
}

View file

@ -0,0 +1,76 @@
<?php
namespace Drupal\Tests\media\Traits;
use Drupal\media\Entity\MediaType;
/**
* Provides methods to create a media type from given values.
*
* This trait is meant to be used only by test classes.
*/
trait MediaTypeCreationTrait {
/**
* Create a media type for a source plugin.
*
* @param string $source_plugin_id
* The media source plugin ID.
* @param mixed[] $values
* (optional) Additional values for the media type entity:
* - id: The ID of the media type. If none is provided, a random value will
* be used.
* - label: The human-readable label of the media type. If none is provided,
* a random value will be used.
* - bundle: (deprecated) The ID of the media type, for backwards
* compatibility purposes. Use 'id' instead.
* See \Drupal\media\MediaTypeInterface and \Drupal\media\Entity\MediaType
* for full documentation of the media type properties.
*
* @return \Drupal\media\MediaTypeInterface
* A media type.
*
* @see \Drupal\media\MediaTypeInterface
* @see \Drupal\media\Entity\MediaType
*/
protected function createMediaType($source_plugin_id, array $values = []) {
if (isset($values['bundle'])) {
@trigger_error('Setting the "bundle" key when creating a test media type is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Set the "id" key instead. See https://www.drupal.org/node/2981614.', E_USER_DEPRECATED);
$values['id'] = $values['bundle'];
unset($values['bundle']);
}
$values += [
'id' => $this->randomMachineName(),
'label' => $this->randomString(),
'source' => $source_plugin_id,
];
/** @var \Drupal\media\MediaTypeInterface $media_type */
$media_type = MediaType::create($values);
$this->assertSame(SAVED_NEW, $media_type->save());
$source = $media_type->getSource();
$source_field = $source->createSourceField($media_type);
// The media type form creates a source field if it does not exist yet. The
// same must be done in a kernel test, since it does not use that form.
// @see \Drupal\media\MediaTypeForm::save()
$source_field->getFieldStorageDefinition()->save();
// The source field storage has been created, now the field can be saved.
$source_field->save();
$source_configuration = $source->getConfiguration();
$source_configuration['source_field'] = $source_field->getName();
$source->setConfiguration($source_configuration);
$this->assertSame(SAVED_UPDATED, $media_type->save());
// Add the source field to the form display for the media type.
$form_display = entity_get_form_display('media', $media_type->id(), 'default');
$source->prepareFormDisplay($media_type, $form_display);
$form_display->save();
return $media_type;
}
}

View file

@ -0,0 +1,89 @@
<?php
namespace Drupal\Tests\media\Traits;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Url;
use Drupal\media\OEmbed\Provider;
/**
* Contains helper functions for testing oEmbed functionality in isolation.
*/
trait OEmbedTestTrait {
/**
* Returns the relative path to the oEmbed fixtures directory.
*
* @return string
*/
protected function getFixturesDirectory() {
return drupal_get_path('module', 'media') . '/tests/fixtures/oembed';
}
/**
* Returns the absolute URL of the oEmbed fixtures directory.
*
* @return string
*/
protected function getFixturesUrl() {
return $this->baseUrl . '/' . $this->getFixturesDirectory();
}
/**
* Forces Media to use the provider database in the fixtures directory.
*/
protected function useFixtureProviders() {
$this->config('media.settings')
->set('oembed_providers_url', $this->getFixturesUrl() . '/providers.json')
->save();
}
/**
* Configures the http_client service so that all requests are carried out
* relative to the URL of the fixtures directory. For example, after calling
* this method, a request for foobar.html will actually request
* http://test-site/path/to/fuxtures/foobar.html.
*/
protected function lockHttpClientToFixtures() {
$this->writeSettings([
'settings' => [
'http_client_config' => [
'base_uri' => (object) [
'value' => $this->getFixturesUrl() . '/',
'required' => TRUE,
],
],
],
]);
}
/**
* Ensures that all oEmbed provider endpoints defined in the fixture
* providers.json will use the media_test_oembed.resource.get route as their
* URL.
*
* This requires the media_test_oembed module in order to work.
*/
protected function hijackProviderEndpoints() {
$providers = $this->getFixturesDirectory() . '/providers.json';
$providers = file_get_contents($providers);
$providers = Json::decode($providers);
$endpoint_url = Url::fromRoute('media_test_oembed.resource.get')
->setAbsolute()
->toString();
/** @var \Drupal\media_test_oembed\ProviderRepository $provider_repository */
$provider_repository = $this->container->get('media.oembed.provider_repository');
foreach ($providers as &$provider) {
foreach ($provider['endpoints'] as &$endpoint) {
$endpoint['url'] = $endpoint_url;
}
$provider_repository->setProvider(
new Provider($provider['provider_name'], $provider['provider_url'], $provider['endpoints'])
);
}
}
}

View file

@ -0,0 +1,89 @@
<?php
namespace Drupal\Tests\media\Unit;
use Drupal\Core\PrivateKey;
use Drupal\Core\Routing\RequestContext;
use Drupal\media\IFrameUrlHelper;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\media\IFrameUrlHelper
*
* @group media
*/
class IFrameUrlHelperTest extends UnitTestCase {
/**
* Data provider for testIsSecure().
*
* @see ::testIsSecure()
*
* @return array
*/
public function providerIsSecure() {
return [
'no domain' => [
'/path/to/media.php',
'http://www.example.com/',
FALSE,
],
'no base URL domain' => [
'http://www.example.com/media.php',
'/invalid/base/url',
FALSE,
],
'same domain' => [
'http://www.example.com/media.php',
'http://www.example.com/',
FALSE,
],
'different domain' => [
'http://www.example.com/media.php',
'http://www.example-assets.com/',
TRUE,
],
'same subdomain' => [
'http://foo.example.com/media.php',
'http://foo.example.com/',
FALSE,
],
'different subdomain' => [
'http://assets.example.com/media.php',
'http://foo.example.com/',
TRUE,
],
'subdomain and top-level domain' => [
'http://assets.example.com/media.php',
'http://example.com/',
TRUE,
],
];
}
/**
* Tests that isSecure() behaves properly.
*
* @param string $url
* The URL to test for security.
* @param string $base_url
* The base URL to compare $url against.
* @param bool $secure
* The expected result of isSecure().
*
* @covers ::isSecure
*
* @dataProvider providerIsSecure
*/
public function testIsSecure($url, $base_url, $secure) {
$request_context = $this->prophesize(RequestContext::class);
$request_context->getCompleteBaseUrl()->willReturn($base_url);
$url_helper = new IFrameUrlHelper(
$request_context->reveal(),
$this->prophesize(PrivateKey::class)->reveal()
);
$this->assertSame($secure, $url_helper->isSecure($url));
}
}