diff --git a/core/modules/image/src/Tests/ImageAdminStylesTest.php b/core/modules/image/src/Tests/ImageAdminStylesTest.php
index 1f6f411054f6a28c9cf6393474ccfd17d8e64862..e4f775be4f6a08c5c0a3c60f676131adbe77f98a 100644
--- a/core/modules/image/src/Tests/ImageAdminStylesTest.php
+++ b/core/modules/image/src/Tests/ImageAdminStylesTest.php
@@ -2,12 +2,7 @@
 
 namespace Drupal\image\Tests;
 
-use Drupal\Component\Utility\SafeMarkup;
-use Drupal\Core\Entity\Entity\EntityViewDisplay;
 use Drupal\image\Entity\ImageStyle;
-use Drupal\image\ImageStyleInterface;
-use Drupal\node\Entity\Node;
-use Drupal\file\Entity\File;
 
 /**
  * Tests creation, deletion, and editing of image styles and effects.
@@ -16,280 +11,6 @@
  */
 class ImageAdminStylesTest extends ImageFieldTestBase {
 
-  /**
-   * Given an image style, generate an image.
-   */
-  public function createSampleImage(ImageStyleInterface $style) {
-    static $file_path;
-
-    // First, we need to make sure we have an image in our testing
-    // file directory. Copy over an image on the first run.
-    if (!isset($file_path)) {
-      $files = $this->drupalGetTestFiles('image');
-      $file = reset($files);
-      $file_path = file_unmanaged_copy($file->uri);
-    }
-
-    return $style->buildUrl($file_path) ? $file_path : FALSE;
-  }
-
-  /**
-   * Count the number of images currently create for a style.
-   */
-  public function getImageCount(ImageStyleInterface $style) {
-    return count(file_scan_directory('public://styles/' . $style->id(), '/.*/'));
-  }
-
-  /**
-   * Test creating an image style with a numeric name and ensuring it can be
-   * applied to an image.
-   */
-  public function testNumericStyleName() {
-    $style_name = rand();
-    $style_label = $this->randomString();
-    $edit = [
-      'name' => $style_name,
-      'label' => $style_label,
-    ];
-    $this->drupalPostForm('admin/config/media/image-styles/add', $edit, t('Create new style'));
-    $this->assertRaw(t('Style %name was created.', ['%name' => $style_label]));
-    $options = image_style_options();
-    $this->assertTrue(array_key_exists($style_name, $options), format_string('Array key %key exists.', ['%key' => $style_name]));
-  }
-
-  /**
-   * General test to add a style, add/remove/edit effects to it, then delete it.
-   */
-  public function testStyle() {
-    $admin_path = 'admin/config/media/image-styles';
-
-    // Setup a style to be created and effects to add to it.
-    $style_name = strtolower($this->randomMachineName(10));
-    $style_label = $this->randomString();
-    $style_path = $admin_path . '/manage/' . $style_name;
-    $effect_edits = [
-      'image_resize' => [
-        'width' => 100,
-        'height' => 101,
-      ],
-      'image_scale' => [
-        'width' => 110,
-        'height' => 111,
-        'upscale' => 1,
-      ],
-      'image_scale_and_crop' => [
-        'width' => 120,
-        'height' => 121,
-      ],
-      'image_crop' => [
-        'width' => 130,
-        'height' => 131,
-        'anchor' => 'left-top',
-      ],
-      'image_desaturate' => [
-        // No options for desaturate.
-      ],
-      'image_rotate' => [
-        'degrees' => 5,
-        'random' => 1,
-        'bgcolor' => '#FFFF00',
-      ],
-    ];
-
-    // Add style form.
-
-    $edit = [
-      'name' => $style_name,
-      'label' => $style_label,
-    ];
-    $this->drupalPostForm($admin_path . '/add', $edit, t('Create new style'));
-    $this->assertRaw(t('Style %name was created.', ['%name' => $style_label]));
-
-    // Ensure that the expected entity operations are there.
-    $this->drupalGet($admin_path);
-    $this->assertLinkByHref($style_path);
-    $this->assertLinkByHref($style_path . '/flush');
-    $this->assertLinkByHref($style_path . '/delete');
-
-    // Add effect form.
-
-    // Add each sample effect to the style.
-    foreach ($effect_edits as $effect => $edit) {
-      $edit_data = [];
-      foreach ($edit as $field => $value) {
-        $edit_data['data[' . $field . ']'] = $value;
-      }
-      // Add the effect.
-      $this->drupalPostForm($style_path, ['new' => $effect], t('Add'));
-      if (!empty($edit)) {
-        $this->drupalPostForm(NULL, $edit_data, t('Add effect'));
-      }
-    }
-
-    // Load the saved image style.
-    $style = ImageStyle::load($style_name);
-
-    // Ensure that third party settings were added to the config entity.
-    // These are added by a hook_image_style_presave() implemented in
-    // image_module_test module.
-    $this->assertEqual('bar', $style->getThirdPartySetting('image_module_test', 'foo'), 'Third party settings were added to the image style.');
-
-    // Ensure that the image style URI matches our expected path.
-    $style_uri_path = $style->url();
-    $this->assertTrue(strpos($style_uri_path, $style_path) !== FALSE, 'The image style URI is correct.');
-
-    // Confirm that all effects on the image style have settings that match
-    // what was saved.
-    $uuids = [];
-    foreach ($style->getEffects() as $uuid => $effect) {
-      // Store the uuid for later use.
-      $uuids[$effect->getPluginId()] = $uuid;
-      $effect_configuration = $effect->getConfiguration();
-      foreach ($effect_edits[$effect->getPluginId()] as $field => $value) {
-        $this->assertEqual($value, $effect_configuration['data'][$field], SafeMarkup::format('The %field field in the %effect effect has the correct value of %value.', ['%field' => $field, '%effect' => $effect->getPluginId(), '%value' => $value]));
-      }
-    }
-
-    // Assert that every effect was saved.
-    foreach (array_keys($effect_edits) as $effect_name) {
-      $this->assertTrue(isset($uuids[$effect_name]), format_string(
-        'A %effect_name effect was saved with ID %uuid',
-        [
-          '%effect_name' => $effect_name,
-          '%uuid' => $uuids[$effect_name],
-        ]));
-    }
-
-    // Image style overview form (ordering and renaming).
-
-    // Confirm the order of effects is maintained according to the order we
-    // added the fields.
-    $effect_edits_order = array_keys($effect_edits);
-    $order_correct = TRUE;
-    $index = 0;
-    foreach ($style->getEffects() as $effect) {
-      if ($effect_edits_order[$index] != $effect->getPluginId()) {
-        $order_correct = FALSE;
-      }
-      $index++;
-    }
-    $this->assertTrue($order_correct, 'The order of the effects is correctly set by default.');
-
-    // Test the style overview form.
-    // Change the name of the style and adjust the weights of effects.
-    $style_name = strtolower($this->randomMachineName(10));
-    $style_label = $this->randomMachineName();
-    $weight = count($effect_edits);
-    $edit = [
-      'name' => $style_name,
-      'label' => $style_label,
-    ];
-    foreach ($style->getEffects() as $uuid => $effect) {
-      $edit['effects[' . $uuid . '][weight]'] = $weight;
-      $weight--;
-    }
-
-    // Create an image to make sure it gets flushed after saving.
-    $image_path = $this->createSampleImage($style);
-    $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', ['%style' => $style->label(), '%file' => $image_path]));
-
-    $this->drupalPostForm($style_path, $edit, t('Update style'));
-
-    // Note that after changing the style name, the style path is changed.
-    $style_path = 'admin/config/media/image-styles/manage/' . $style_name;
-
-    // Check that the URL was updated.
-    $this->drupalGet($style_path);
-    $this->assertTitle(t('Edit style @name | Drupal', ['@name' => $style_label]));
-    $this->assertResponse(200, format_string('Image style %original renamed to %new', ['%original' => $style->id(), '%new' => $style_name]));
-
-    // Check that the available image effects are properly sorted.
-    $option = $this->xpath('//select[@id=:id]//option', [':id' => 'edit-new--2']);
-    $this->assertTrue($option[1] == 'Ajax test', '"Ajax test" is the first selectable effect.');
-
-    // Check that the image was flushed after updating the style.
-    // This is especially important when renaming the style. Make sure that
-    // the old image directory has been deleted.
-    $this->assertEqual($this->getImageCount($style), 0, format_string('Image style %style was flushed after renaming the style and updating the order of effects.', ['%style' => $style->label()]));
-
-    // Load the style by the new name with the new weights.
-    $style = ImageStyle::load($style_name);
-
-    // Confirm the new style order was saved.
-    $effect_edits_order = array_reverse($effect_edits_order);
-    $order_correct = TRUE;
-    $index = 0;
-    foreach ($style->getEffects() as $effect) {
-      if ($effect_edits_order[$index] != $effect->getPluginId()) {
-        $order_correct = FALSE;
-      }
-      $index++;
-    }
-    $this->assertTrue($order_correct, 'The order of the effects is correctly set by default.');
-
-    // Image effect deletion form.
-
-    // Create an image to make sure it gets flushed after deleting an effect.
-    $image_path = $this->createSampleImage($style);
-    $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', ['%style' => $style->label(), '%file' => $image_path]));
-
-    // Delete the 'image_crop' effect from the style.
-    $this->drupalPostForm($style_path . '/effects/' . $uuids['image_crop'] . '/delete', [], t('Delete'));
-    // Confirm that the form submission was successful.
-    $this->assertResponse(200);
-    $image_crop_effect = $style->getEffect($uuids['image_crop']);
-    $this->assertRaw(t('The image effect %name has been deleted.', ['%name' => $image_crop_effect->label()]));
-    // Confirm that there is no longer a link to the effect.
-    $this->assertNoLinkByHref($style_path . '/effects/' . $uuids['image_crop'] . '/delete');
-    // Refresh the image style information and verify that the effect was
-    // actually deleted.
-    $entity_type_manager = $this->container->get('entity_type.manager');
-    $style = $entity_type_manager->getStorage('image_style')->loadUnchanged($style->id());
-    $this->assertFalse($style->getEffects()->has($uuids['image_crop']), format_string(
-      'Effect with ID %uuid no longer found on image style %style',
-      [
-        '%uuid' => $uuids['image_crop'],
-        '%style' => $style->label(),
-      ]));
-
-    // Additional test on Rotate effect, for transparent background.
-    $edit = [
-      'data[degrees]' => 5,
-      'data[random]' => 0,
-      'data[bgcolor]' => '',
-    ];
-    $this->drupalPostForm($style_path, ['new' => 'image_rotate'], t('Add'));
-    $this->drupalPostForm(NULL, $edit, t('Add effect'));
-    $entity_type_manager = $this->container->get('entity_type.manager');
-    $style = $entity_type_manager->getStorage('image_style')->loadUnchanged($style_name);
-    $this->assertEqual(count($style->getEffects()), 6, 'Rotate effect with transparent background was added.');
-
-    // Style deletion form.
-
-    // Delete the style.
-    $this->drupalPostForm($style_path . '/delete', [], t('Delete'));
-
-    // Confirm the style directory has been removed.
-    $directory = file_default_scheme() . '://styles/' . $style_name;
-    $this->assertFalse(is_dir($directory), format_string('Image style %style directory removed on style deletion.', ['%style' => $style->label()]));
-
-    $this->assertFalse(ImageStyle::load($style_name), format_string('Image style %style successfully deleted.', ['%style' => $style->label()]));
-
-    // Test empty text when there are no image styles.
-
-    // Delete all image styles.
-    foreach (ImageStyle::loadMultiple() as $image_style) {
-      $image_style->delete();
-    }
-
-    // Confirm that the empty text is correct on the image styles page.
-    $this->drupalGet($admin_path);
-    $this->assertRaw(t('There are currently no styles. <a href=":url">Add a new one</a>.', [
-      ':url' => \Drupal::url('image.style_add'),
-    ]));
-
-  }
-
   /**
    * Tests editing Ajax-enabled image effect forms.
    */
@@ -328,214 +49,6 @@ public function testAjaxEnabledEffectForm() {
       $this->drupalPostAjaxForm(NULL, $effect_edit, ['op' => t('Ajax refresh')]);
       $this->drupalPostForm(NULL, $effect_edit, t('Update effect'));
     }
-
-  }
-
-  /**
-   * Test deleting a style and choosing a replacement style.
-   */
-  public function testStyleReplacement() {
-    // Create a new style.
-    $style_name = strtolower($this->randomMachineName(10));
-    $style_label = $this->randomString();
-    $style = ImageStyle::create(['name' => $style_name, 'label' => $style_label]);
-    $style->save();
-    $style_path = 'admin/config/media/image-styles/manage/';
-
-    // Create an image field that uses the new style.
-    $field_name = strtolower($this->randomMachineName(10));
-    $this->createImageField($field_name, 'article');
-    entity_get_display('node', 'article', 'default')
-      ->setComponent($field_name, [
-        'type' => 'image',
-        'settings' => ['image_style' => $style_name],
-      ])
-      ->save();
-
-    // Create a new node with an image attached.
-    $test_image = current($this->drupalGetTestFiles('image'));
-    $nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
-    $node = Node::load($nid);
-
-    // Get node field original image URI.
-    $fid = $node->get($field_name)->target_id;
-    $original_uri = File::load($fid)->getFileUri();
-
-    // Test that image is displayed using newly created style.
-    $this->drupalGet('node/' . $nid);
-    $this->assertRaw(file_url_transform_relative($style->buildUrl($original_uri)), format_string('Image displayed using style @style.', ['@style' => $style_name]));
-
-    // Rename the style and make sure the image field is updated.
-    $new_style_name = strtolower($this->randomMachineName(10));
-    $new_style_label = $this->randomString();
-    $edit = [
-      'name' => $new_style_name,
-      'label' => $new_style_label,
-    ];
-    $this->drupalPostForm($style_path . $style_name, $edit, t('Update style'));
-    $this->assertText(t('Changes to the style have been saved.'), format_string('Style %name was renamed to %new_name.', ['%name' => $style_name, '%new_name' => $new_style_name]));
-    $this->drupalGet('node/' . $nid);
-
-    // Reload the image style using the new name.
-    $style = ImageStyle::load($new_style_name);
-    $this->assertRaw(file_url_transform_relative($style->buildUrl($original_uri)), 'Image displayed using style replacement style.');
-
-    // Delete the style and choose a replacement style.
-    $edit = [
-      'replacement' => 'thumbnail',
-    ];
-    $this->drupalPostForm($style_path . $new_style_name . '/delete', $edit, t('Delete'));
-    $message = t('The image style %name has been deleted.', ['%name' => $new_style_label]);
-    $this->assertRaw($message);
-
-    $replacement_style = ImageStyle::load('thumbnail');
-    $this->drupalGet('node/' . $nid);
-    $this->assertRaw(file_url_transform_relative($replacement_style->buildUrl($original_uri)), 'Image displayed using style replacement style.');
-  }
-
-  /**
-   * Verifies that editing an image effect does not cause it to be duplicated.
-   */
-  public function testEditEffect() {
-    // Add a scale effect.
-    $style_name = 'test_style_effect_edit';
-    $this->drupalGet('admin/config/media/image-styles/add');
-    $this->drupalPostForm(NULL, ['label' => 'Test style effect edit', 'name' => $style_name], t('Create new style'));
-    $this->drupalPostForm(NULL, ['new' => 'image_scale_and_crop'], t('Add'));
-    $this->drupalPostForm(NULL, ['data[width]' => '300', 'data[height]' => '200'], t('Add effect'));
-    $this->assertText(t('Scale and crop 300×200'));
-
-    // There should normally be only one edit link on this page initially.
-    $this->clickLink(t('Edit'));
-    $this->drupalPostForm(NULL, ['data[width]' => '360', 'data[height]' => '240'], t('Update effect'));
-    $this->assertText(t('Scale and crop 360×240'));
-
-    // Check that the previous effect is replaced.
-    $this->assertNoText(t('Scale and crop 300×200'));
-
-    // Add another scale effect.
-    $this->drupalGet('admin/config/media/image-styles/add');
-    $this->drupalPostForm(NULL, ['label' => 'Test style scale edit scale', 'name' => 'test_style_scale_edit_scale'], t('Create new style'));
-    $this->drupalPostForm(NULL, ['new' => 'image_scale'], t('Add'));
-    $this->drupalPostForm(NULL, ['data[width]' => '12', 'data[height]' => '19'], t('Add effect'));
-
-    // Edit the scale effect that was just added.
-    $this->clickLink(t('Edit'));
-    $this->drupalPostForm(NULL, ['data[width]' => '24', 'data[height]' => '19'], t('Update effect'));
-
-    // Add another scale effect and make sure both exist. Click through from
-    // the overview to make sure that it is possible to add new effect then.
-    $this->drupalGet('admin/config/media/image-styles');
-    $rows = $this->xpath('//table/tbody/tr');
-    $i = 0;
-    foreach ($rows as $row) {
-      if (((string) $row->td[0]) === 'Test style scale edit scale') {
-        $this->clickLink('Edit', $i);
-        break;
-      }
-      $i++;
-    }
-    $this->drupalPostForm(NULL, ['new' => 'image_scale'], t('Add'));
-    $this->drupalPostForm(NULL, ['data[width]' => '12', 'data[height]' => '19'], t('Add effect'));
-    $this->assertText(t('Scale 24×19'));
-    $this->assertText(t('Scale 12×19'));
-
-    // Try to edit a nonexistent effect.
-    $uuid = $this->container->get('uuid');
-    $this->drupalGet('admin/config/media/image-styles/manage/' . $style_name . '/effects/' . $uuid->generate());
-    $this->assertResponse(404);
-  }
-
-  /**
-   * Test flush user interface.
-   */
-  public function testFlushUserInterface() {
-    $admin_path = 'admin/config/media/image-styles';
-
-    // Create a new style.
-    $style_name = strtolower($this->randomMachineName(10));
-    $style = ImageStyle::create(['name' => $style_name, 'label' => $this->randomString()]);
-    $style->save();
-
-    // Create an image to make sure it gets flushed.
-    $files = $this->drupalGetTestFiles('image');
-    $image_uri = $files[0]->uri;
-    $derivative_uri = $style->buildUri($image_uri);
-    $this->assertTrue($style->createDerivative($image_uri, $derivative_uri));
-    $this->assertEqual($this->getImageCount($style), 1);
-
-    // Go to image styles list page and check if the flush operation link
-    // exists.
-    $this->drupalGet($admin_path);
-    $flush_path = $admin_path . '/manage/' . $style_name . '/flush';
-    $this->assertLinkByHref($flush_path);
-
-    // Flush the image style derivatives using the user interface.
-    $this->drupalPostForm($flush_path, [], t('Flush'));
-
-    // The derivative image file should have been deleted.
-    $this->assertEqual($this->getImageCount($style), 0);
-  }
-
-  /**
-   * Tests image style configuration import that does a delete.
-   */
-  public function testConfigImport() {
-    // Create a new style.
-    $style_name = strtolower($this->randomMachineName(10));
-    $style_label = $this->randomString();
-    $style = ImageStyle::create(['name' => $style_name, 'label' => $style_label]);
-    $style->save();
-
-    // Create an image field that uses the new style.
-    $field_name = strtolower($this->randomMachineName(10));
-    $this->createImageField($field_name, 'article');
-    entity_get_display('node', 'article', 'default')
-      ->setComponent($field_name, [
-        'type' => 'image',
-        'settings' => ['image_style' => $style_name],
-      ])
-      ->save();
-
-    // Create a new node with an image attached.
-    $test_image = current($this->drupalGetTestFiles('image'));
-    $nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
-    $node = Node::load($nid);
-
-    // Get node field original image URI.
-    $fid = $node->get($field_name)->target_id;
-    $original_uri = File::load($fid)->getFileUri();
-
-    // Test that image is displayed using newly created style.
-    $this->drupalGet('node/' . $nid);
-    $this->assertRaw(file_url_transform_relative($style->buildUrl($original_uri)), format_string('Image displayed using style @style.', ['@style' => $style_name]));
-
-    // Copy config to sync, and delete the image style.
-    $sync = $this->container->get('config.storage.sync');
-    $active = $this->container->get('config.storage');
-    // Remove the image field from the display, to avoid a dependency error
-    // during import.
-    EntityViewDisplay::load('node.article.default')
-      ->removeComponent($field_name)
-      ->save();
-    $this->copyConfig($active, $sync);
-    $sync->delete('image.style.' . $style_name);
-    $this->configImporter()->import();
-
-    $this->assertFalse(ImageStyle::load($style_name), 'Style deleted after config import.');
-    $this->assertEqual($this->getImageCount($style), 0, 'Image style was flushed after being deleted by config import.');
-  }
-
-  /**
-   * Tests access for the image style listing.
-   */
-  public function testImageStyleAccess() {
-    $style = ImageStyle::create(['name' => 'style_foo', 'label' => $this->randomString()]);
-    $style->save();
-
-    $this->drupalGet('admin/config/media/image-styles');
-    $this->clickLink(t('Edit'));
-    $this->assertRaw(t('Select a new effect'));
   }
 
 }
diff --git a/core/modules/image/src/Tests/ImageFieldTestBase.php b/core/modules/image/src/Tests/ImageFieldTestBase.php
index 0623b6e92f6c0db039bf335cf99c0807cacc6088..2e21739abd4092938646911f6ca69959d353f03d 100644
--- a/core/modules/image/src/Tests/ImageFieldTestBase.php
+++ b/core/modules/image/src/Tests/ImageFieldTestBase.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\image\Tests;
 
+@trigger_error('The ' . __NAMESPACE__ . '\ImageFieldTestBase class is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. Use \Drupal\Tests\image\Functional\ImageFieldTestBase instead. See https://www.drupal.org/node/2863626.', E_USER_DEPRECATED);
+
 use Drupal\Tests\image\Kernel\ImageFieldCreationTrait;
 use Drupal\simpletest\WebTestBase;
 
diff --git a/core/modules/image/src/Tests/ImageFieldValidateTest.php b/core/modules/image/src/Tests/ImageFieldValidateTest.php
index 87c042bf98772ef8b47b4cea1ff2f4999899acae..39750d809a86f8911c1ba112a71e16674f68b187 100644
--- a/core/modules/image/src/Tests/ImageFieldValidateTest.php
+++ b/core/modules/image/src/Tests/ImageFieldValidateTest.php
@@ -12,213 +12,6 @@
  */
 class ImageFieldValidateTest extends ImageFieldTestBase {
 
-  /**
-   * Test image validity.
-   */
-  public function testValid() {
-    $file_system = $this->container->get('file_system');
-    $image_files = $this->drupalGetTestFiles('image');
-
-    $field_name = strtolower($this->randomMachineName());
-    $this->createImageField($field_name, 'article', [], ['file_directory' => 'test-upload']);
-    $expected_path = 'public://test-upload';
-
-    // Create alt text for the image.
-    $alt = $this->randomMachineName();
-
-    // Create a node with a valid image.
-    $node = $this->uploadNodeImage($image_files[0], $field_name, 'article', $alt);
-    $this->assertTrue(file_exists($expected_path . '/' . $image_files[0]->filename));
-
-    // Remove the image.
-    $this->drupalPostForm('node/' . $node . '/edit', [], t('Remove'));
-    $this->drupalPostForm(NULL, [], t('Save'));
-
-    // Get invalid image test files from simpletest.
-    $files = file_scan_directory(drupal_get_path('module', 'simpletest') . '/files', '/invalid-img-.*/');
-    $invalid_image_files = [];
-    foreach ($files as $file) {
-      $invalid_image_files[$file->filename] = $file;
-    }
-
-    // Try uploading a zero-byte image.
-    $zero_size_image = $invalid_image_files['invalid-img-zero-size.png'];
-    $edit = [
-      'files[' . $field_name . '_0]' => $file_system->realpath($zero_size_image->uri),
-    ];
-    $this->drupalPostForm('node/' . $node . '/edit', $edit, t('Upload'));
-    $this->assertFalse(file_exists($expected_path . '/' . $zero_size_image->filename));
-
-    // Try uploading an invalid image.
-    $invalid_image = $invalid_image_files['invalid-img-test.png'];
-    $edit = [
-      'files[' . $field_name . '_0]' => $file_system->realpath($invalid_image->uri),
-    ];
-    $this->drupalPostForm('node/' . $node . '/edit', $edit, t('Upload'));
-    $this->assertFalse(file_exists($expected_path . '/' . $invalid_image->filename));
-
-    // Upload a valid image again.
-    $valid_image = $image_files[0];
-    $edit = [
-      'files[' . $field_name . '_0]' => $file_system->realpath($valid_image->uri),
-    ];
-    $this->drupalPostForm('node/' . $node . '/edit', $edit, t('Upload'));
-    $this->assertTrue(file_exists($expected_path . '/' . $valid_image->filename));
-  }
-
-  /**
-   * Test min/max resolution settings.
-   */
-  public function testResolution() {
-    $field_names = [
-      0 => strtolower($this->randomMachineName()),
-      1 => strtolower($this->randomMachineName()),
-      2 => strtolower($this->randomMachineName()),
-    ];
-    $min_resolution = [
-      'width' => 50,
-      'height' => 50
-    ];
-    $max_resolution = [
-      'width' => 100,
-      'height' => 100
-    ];
-    $no_height_min_resolution = [
-      'width' => 50,
-      'height' => NULL
-    ];
-    $no_height_max_resolution = [
-      'width' => 100,
-      'height' => NULL
-    ];
-    $no_width_min_resolution = [
-      'width' => NULL,
-      'height' => 50
-    ];
-    $no_width_max_resolution = [
-      'width' => NULL,
-      'height' => 100
-    ];
-    $field_settings = [
-      0 => $this->getFieldSettings($min_resolution, $max_resolution),
-      1 => $this->getFieldSettings($no_height_min_resolution, $no_height_max_resolution),
-      2 => $this->getFieldSettings($no_width_min_resolution, $no_width_max_resolution),
-    ];
-    $this->createImageField($field_names[0], 'article', [], $field_settings[0]);
-    $this->createImageField($field_names[1], 'article', [], $field_settings[1]);
-    $this->createImageField($field_names[2], 'article', [], $field_settings[2]);
-
-    // We want a test image that is too small, and a test image that is too
-    // big, so cycle through test image files until we have what we need.
-    $image_that_is_too_big = FALSE;
-    $image_that_is_too_small = FALSE;
-    $image_factory = $this->container->get('image.factory');
-    foreach ($this->drupalGetTestFiles('image') as $image) {
-      $image_file = $image_factory->get($image->uri);
-      if ($image_file->getWidth() > $max_resolution['width']) {
-        $image_that_is_too_big = $image;
-      }
-      if ($image_file->getWidth() < $min_resolution['width']) {
-        $image_that_is_too_small = $image;
-        $image_that_is_too_small_file = $image_file;
-      }
-      if ($image_that_is_too_small && $image_that_is_too_big) {
-        break;
-      }
-    }
-    $this->uploadNodeImage($image_that_is_too_small, $field_names[0], 'article');
-    $this->assertRaw(t('The specified file %name could not be uploaded.', ['%name' => $image_that_is_too_small->filename]));
-    $this->assertRaw(t('The image is too small. The minimum dimensions are %dimensions pixels and the image size is %widthx%height pixels.', [
-      '%dimensions' => '50x50',
-      '%width' => $image_that_is_too_small_file->getWidth(),
-      '%height' => $image_that_is_too_small_file->getHeight(),
-      ]));
-    $this->uploadNodeImage($image_that_is_too_big, $field_names[0], 'article');
-    $this->assertText(t('The image was resized to fit within the maximum allowed dimensions of 100x100 pixels.'));
-    $this->uploadNodeImage($image_that_is_too_small, $field_names[1], 'article');
-    $this->assertRaw(t('The specified file %name could not be uploaded.', ['%name' => $image_that_is_too_small->filename]));
-    $this->uploadNodeImage($image_that_is_too_big, $field_names[1], 'article');
-    $this->assertText(t('The image was resized to fit within the maximum allowed width of 100 pixels.'));
-    $this->uploadNodeImage($image_that_is_too_small, $field_names[2], 'article');
-    $this->assertRaw(t('The specified file %name could not be uploaded.', ['%name' => $image_that_is_too_small->filename]));
-    $this->uploadNodeImage($image_that_is_too_big, $field_names[2], 'article');
-    $this->assertText(t('The image was resized to fit within the maximum allowed height of 100 pixels.'));
-  }
-
-  /**
-   * Test that required alt/title fields gets validated right.
-   */
-  public function testRequiredAttributes() {
-    $field_name = strtolower($this->randomMachineName());
-    $field_settings = [
-      'alt_field' => 1,
-      'alt_field_required' => 1,
-      'title_field' => 1,
-      'title_field_required' => 1,
-      'required' => 1,
-    ];
-    $instance = $this->createImageField($field_name, 'article', [], $field_settings);
-    $images = $this->drupalGetTestFiles('image');
-    // Let's just use the first image.
-    $image = $images[0];
-    $this->uploadNodeImage($image, $field_name, 'article');
-
-    // Look for form-required for the alt text.
-    $elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-alt" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-alt"]');
-
-    $this->assertTrue(isset($elements[0]), 'Required marker is shown for the required alt text.');
-
-    $elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-title" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-title"]');
-
-    $this->assertTrue(isset($elements[0]), 'Required marker is shown for the required title text.');
-
-    $this->assertText(t('Alternative text field is required.'));
-    $this->assertText(t('Title field is required.'));
-
-    $instance->setSetting('alt_field_required', 0);
-    $instance->setSetting('title_field_required', 0);
-    $instance->save();
-
-    $edit = [
-      'title[0][value]' => $this->randomMachineName(),
-    ];
-    $this->drupalPostForm('node/add/article', $edit, t('Save'));
-
-    $this->assertNoText(t('Alternative text field is required.'));
-    $this->assertNoText(t('Title field is required.'));
-
-    $instance->setSetting('required', 0);
-    $instance->setSetting('alt_field_required', 1);
-    $instance->setSetting('title_field_required', 1);
-    $instance->save();
-
-    $edit = [
-      'title[0][value]' => $this->randomMachineName(),
-    ];
-    $this->drupalPostForm('node/add/article', $edit, t('Save'));
-
-    $this->assertNoText(t('Alternative text field is required.'));
-    $this->assertNoText(t('Title field is required.'));
-  }
-
-  /**
-   * Returns field settings.
-   *
-   * @param int[] $min_resolution
-   *   The minimum width and height resolution setting.
-   * @param int[] $max_resolution
-   *   The maximum width and height resolution setting.
-   *
-   * @return array
-   */
-  protected function getFieldSettings($min_resolution, $max_resolution) {
-    return [
-      'max_resolution' => $max_resolution['width'] . 'x' . $max_resolution['height'],
-      'min_resolution' => $min_resolution['width'] . 'x' . $min_resolution['height'],
-      'alt_field' => 0,
-    ];
-  }
-
   /**
    * Test the validation message is displayed only once for ajax uploads.
    */
diff --git a/core/modules/image/src/Tests/FileMoveTest.php b/core/modules/image/tests/src/Functional/FileMoveTest.php
similarity index 83%
rename from core/modules/image/src/Tests/FileMoveTest.php
rename to core/modules/image/tests/src/Functional/FileMoveTest.php
index d9ce27f75d3049b1a61d2dcaf6706311eac9f9ba..3cf3be71b8046a2e4444efcdf7cd8fce7a732263 100644
--- a/core/modules/image/src/Tests/FileMoveTest.php
+++ b/core/modules/image/tests/src/Functional/FileMoveTest.php
@@ -1,17 +1,23 @@
 <?php
 
-namespace Drupal\image\Tests;
+namespace Drupal\Tests\image\Functional;
 
 use Drupal\file\Entity\File;
-use Drupal\simpletest\WebTestBase;
 use Drupal\image\Entity\ImageStyle;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\TestFileCreationTrait;
 
 /**
  * Tests the file move function for images and image styles.
  *
  * @group image
  */
-class FileMoveTest extends WebTestBase {
+class FileMoveTest extends BrowserTestBase {
+
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+    compareFiles as drupalCompareFiles;
+  }
 
   /**
    * Modules to enable.
diff --git a/core/modules/image/tests/src/Functional/ImageAdminStylesTest.php b/core/modules/image/tests/src/Functional/ImageAdminStylesTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c37d04bc4a94cfd35d2e49d8f12b33da4e04edf6
--- /dev/null
+++ b/core/modules/image/tests/src/Functional/ImageAdminStylesTest.php
@@ -0,0 +1,506 @@
+<?php
+
+namespace Drupal\Tests\image\Functional;
+
+use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\image\Entity\ImageStyle;
+use Drupal\image\ImageStyleInterface;
+use Drupal\node\Entity\Node;
+use Drupal\file\Entity\File;
+use Drupal\Tests\TestFileCreationTrait;
+
+/**
+ * Tests creation, deletion, and editing of image styles and effects.
+ *
+ * @group image
+ */
+class ImageAdminStylesTest extends ImageFieldTestBase {
+
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+    compareFiles as drupalCompareFiles;
+  }
+
+  /**
+   * Given an image style, generate an image.
+   */
+  public function createSampleImage(ImageStyleInterface $style) {
+    static $file_path;
+
+    // First, we need to make sure we have an image in our testing
+    // file directory. Copy over an image on the first run.
+    if (!isset($file_path)) {
+      $files = $this->drupalGetTestFiles('image');
+      $file = reset($files);
+      $file_path = file_unmanaged_copy($file->uri);
+    }
+
+    return $style->buildUrl($file_path) ? $file_path : FALSE;
+  }
+
+  /**
+   * Count the number of images currently create for a style.
+   */
+  public function getImageCount(ImageStyleInterface $style) {
+    return count(file_scan_directory('public://styles/' . $style->id(), '/.*/'));
+  }
+
+  /**
+   * Test creating an image style with a numeric name and ensuring it can be
+   * applied to an image.
+   */
+  public function testNumericStyleName() {
+    $style_name = rand();
+    $style_label = $this->randomString();
+    $edit = [
+      'name' => $style_name,
+      'label' => $style_label,
+    ];
+    $this->drupalPostForm('admin/config/media/image-styles/add', $edit, t('Create new style'));
+    $this->assertRaw(t('Style %name was created.', ['%name' => $style_label]));
+    $options = image_style_options();
+    $this->assertTrue(array_key_exists($style_name, $options), format_string('Array key %key exists.', ['%key' => $style_name]));
+  }
+
+  /**
+   * General test to add a style, add/remove/edit effects to it, then delete it.
+   */
+  public function testStyle() {
+    $admin_path = 'admin/config/media/image-styles';
+
+    // Setup a style to be created and effects to add to it.
+    $style_name = strtolower($this->randomMachineName(10));
+    $style_label = $this->randomString();
+    $style_path = $admin_path . '/manage/' . $style_name;
+    $effect_edits = [
+      'image_resize' => [
+        'width' => 100,
+        'height' => 101,
+      ],
+      'image_scale' => [
+        'width' => 110,
+        'height' => 111,
+        'upscale' => 1,
+      ],
+      'image_scale_and_crop' => [
+        'width' => 120,
+        'height' => 121,
+      ],
+      'image_crop' => [
+        'width' => 130,
+        'height' => 131,
+        'anchor' => 'left-top',
+      ],
+      'image_desaturate' => [
+        // No options for desaturate.
+      ],
+      'image_rotate' => [
+        'degrees' => 5,
+        'random' => 1,
+        'bgcolor' => '#FFFF00',
+      ],
+    ];
+
+    // Add style form.
+
+    $edit = [
+      'name' => $style_name,
+      'label' => $style_label,
+    ];
+    $this->drupalPostForm($admin_path . '/add', $edit, t('Create new style'));
+    $this->assertRaw(t('Style %name was created.', ['%name' => $style_label]));
+
+    // Ensure that the expected entity operations are there.
+    $this->drupalGet($admin_path);
+    $this->assertLinkByHref($style_path);
+    $this->assertLinkByHref($style_path . '/flush');
+    $this->assertLinkByHref($style_path . '/delete');
+
+    // Add effect form.
+
+    // Add each sample effect to the style.
+    foreach ($effect_edits as $effect => $edit) {
+      $edit_data = [];
+      foreach ($edit as $field => $value) {
+        $edit_data['data[' . $field . ']'] = $value;
+      }
+      // Add the effect.
+      $this->drupalPostForm($style_path, ['new' => $effect], t('Add'));
+      if (!empty($edit)) {
+        $this->drupalPostForm(NULL, $edit_data, t('Add effect'));
+      }
+    }
+
+    // Load the saved image style.
+    $style = ImageStyle::load($style_name);
+
+    // Ensure that third party settings were added to the config entity.
+    // These are added by a hook_image_style_presave() implemented in
+    // image_module_test module.
+    $this->assertEqual('bar', $style->getThirdPartySetting('image_module_test', 'foo'), 'Third party settings were added to the image style.');
+
+    // Ensure that the image style URI matches our expected path.
+    $style_uri_path = $style->url();
+    $this->assertTrue(strpos($style_uri_path, $style_path) !== FALSE, 'The image style URI is correct.');
+
+    // Confirm that all effects on the image style have settings that match
+    // what was saved.
+    $uuids = [];
+    foreach ($style->getEffects() as $uuid => $effect) {
+      // Store the uuid for later use.
+      $uuids[$effect->getPluginId()] = $uuid;
+      $effect_configuration = $effect->getConfiguration();
+      foreach ($effect_edits[$effect->getPluginId()] as $field => $value) {
+        $this->assertEqual($value, $effect_configuration['data'][$field], SafeMarkup::format('The %field field in the %effect effect has the correct value of %value.', ['%field' => $field, '%effect' => $effect->getPluginId(), '%value' => $value]));
+      }
+    }
+
+    // Assert that every effect was saved.
+    foreach (array_keys($effect_edits) as $effect_name) {
+      $this->assertTrue(isset($uuids[$effect_name]), format_string(
+        'A %effect_name effect was saved with ID %uuid',
+        [
+          '%effect_name' => $effect_name,
+          '%uuid' => $uuids[$effect_name],
+        ]));
+    }
+
+    // Image style overview form (ordering and renaming).
+
+    // Confirm the order of effects is maintained according to the order we
+    // added the fields.
+    $effect_edits_order = array_keys($effect_edits);
+    $order_correct = TRUE;
+    $index = 0;
+    foreach ($style->getEffects() as $effect) {
+      if ($effect_edits_order[$index] != $effect->getPluginId()) {
+        $order_correct = FALSE;
+      }
+      $index++;
+    }
+    $this->assertTrue($order_correct, 'The order of the effects is correctly set by default.');
+
+    // Test the style overview form.
+    // Change the name of the style and adjust the weights of effects.
+    $style_name = strtolower($this->randomMachineName(10));
+    $style_label = $this->randomMachineName();
+    $weight = count($effect_edits);
+    $edit = [
+      'name' => $style_name,
+      'label' => $style_label,
+    ];
+    foreach ($style->getEffects() as $uuid => $effect) {
+      $edit['effects[' . $uuid . '][weight]'] = $weight;
+      $weight--;
+    }
+
+    // Create an image to make sure it gets flushed after saving.
+    $image_path = $this->createSampleImage($style);
+    $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', ['%style' => $style->label(), '%file' => $image_path]));
+
+    $this->drupalPostForm($style_path, $edit, t('Update style'));
+
+    // Note that after changing the style name, the style path is changed.
+    $style_path = 'admin/config/media/image-styles/manage/' . $style_name;
+
+    // Check that the URL was updated.
+    $this->drupalGet($style_path);
+    $this->assertTitle(t('Edit style @name | Drupal', ['@name' => $style_label]));
+    $this->assertResponse(200, format_string('Image style %original renamed to %new', ['%original' => $style->id(), '%new' => $style_name]));
+
+    // Check that the available image effects are properly sorted.
+    $option = $this->xpath('//select[@id=:id]//option', [':id' => 'edit-new--2']);
+    $this->assertEquals('Ajax test', $option[1]->getText(), '"Ajax test" is the first selectable effect.');
+
+    // Check that the image was flushed after updating the style.
+    // This is especially important when renaming the style. Make sure that
+    // the old image directory has been deleted.
+    $this->assertEqual($this->getImageCount($style), 0, format_string('Image style %style was flushed after renaming the style and updating the order of effects.', ['%style' => $style->label()]));
+
+    // Load the style by the new name with the new weights.
+    $style = ImageStyle::load($style_name);
+
+    // Confirm the new style order was saved.
+    $effect_edits_order = array_reverse($effect_edits_order);
+    $order_correct = TRUE;
+    $index = 0;
+    foreach ($style->getEffects() as $effect) {
+      if ($effect_edits_order[$index] != $effect->getPluginId()) {
+        $order_correct = FALSE;
+      }
+      $index++;
+    }
+    $this->assertTrue($order_correct, 'The order of the effects is correctly set by default.');
+
+    // Image effect deletion form.
+
+    // Create an image to make sure it gets flushed after deleting an effect.
+    $image_path = $this->createSampleImage($style);
+    $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', ['%style' => $style->label(), '%file' => $image_path]));
+
+    // Delete the 'image_crop' effect from the style.
+    $this->drupalPostForm($style_path . '/effects/' . $uuids['image_crop'] . '/delete', [], t('Delete'));
+    // Confirm that the form submission was successful.
+    $this->assertResponse(200);
+    $image_crop_effect = $style->getEffect($uuids['image_crop']);
+    $this->assertRaw(t('The image effect %name has been deleted.', ['%name' => $image_crop_effect->label()]));
+    // Confirm that there is no longer a link to the effect.
+    $this->assertNoLinkByHref($style_path . '/effects/' . $uuids['image_crop'] . '/delete');
+    // Refresh the image style information and verify that the effect was
+    // actually deleted.
+    $entity_type_manager = $this->container->get('entity_type.manager');
+    $style = $entity_type_manager->getStorage('image_style')->loadUnchanged($style->id());
+    $this->assertFalse($style->getEffects()->has($uuids['image_crop']), format_string(
+      'Effect with ID %uuid no longer found on image style %style',
+      [
+        '%uuid' => $uuids['image_crop'],
+        '%style' => $style->label(),
+      ]));
+
+    // Additional test on Rotate effect, for transparent background.
+    $edit = [
+      'data[degrees]' => 5,
+      'data[random]' => 0,
+      'data[bgcolor]' => '',
+    ];
+    $this->drupalPostForm($style_path, ['new' => 'image_rotate'], t('Add'));
+    $this->drupalPostForm(NULL, $edit, t('Add effect'));
+    $entity_type_manager = $this->container->get('entity_type.manager');
+    $style = $entity_type_manager->getStorage('image_style')->loadUnchanged($style_name);
+    $this->assertEqual(count($style->getEffects()), 6, 'Rotate effect with transparent background was added.');
+
+    // Style deletion form.
+
+    // Delete the style.
+    $this->drupalPostForm($style_path . '/delete', [], t('Delete'));
+
+    // Confirm the style directory has been removed.
+    $directory = file_default_scheme() . '://styles/' . $style_name;
+    $this->assertFalse(is_dir($directory), format_string('Image style %style directory removed on style deletion.', ['%style' => $style->label()]));
+
+    $this->assertFalse(ImageStyle::load($style_name), format_string('Image style %style successfully deleted.', ['%style' => $style->label()]));
+
+    // Test empty text when there are no image styles.
+
+    // Delete all image styles.
+    foreach (ImageStyle::loadMultiple() as $image_style) {
+      $image_style->delete();
+    }
+
+    // Confirm that the empty text is correct on the image styles page.
+    $this->drupalGet($admin_path);
+    $this->assertRaw(t('There are currently no styles. <a href=":url">Add a new one</a>.', [
+      ':url' => \Drupal::url('image.style_add'),
+    ]));
+
+  }
+
+  /**
+   * Test deleting a style and choosing a replacement style.
+   */
+  public function testStyleReplacement() {
+    // Create a new style.
+    $style_name = strtolower($this->randomMachineName(10));
+    $style_label = $this->randomString();
+    $style = ImageStyle::create(['name' => $style_name, 'label' => $style_label]);
+    $style->save();
+    $style_path = 'admin/config/media/image-styles/manage/';
+
+    // Create an image field that uses the new style.
+    $field_name = strtolower($this->randomMachineName(10));
+    $this->createImageField($field_name, 'article');
+    entity_get_display('node', 'article', 'default')
+      ->setComponent($field_name, [
+        'type' => 'image',
+        'settings' => ['image_style' => $style_name],
+      ])
+      ->save();
+
+    // Create a new node with an image attached.
+    $test_image = current($this->drupalGetTestFiles('image'));
+    $nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
+    $node = Node::load($nid);
+
+    // Get node field original image URI.
+    $fid = $node->get($field_name)->target_id;
+    $original_uri = File::load($fid)->getFileUri();
+
+    // Test that image is displayed using newly created style.
+    $this->drupalGet('node/' . $nid);
+    $this->assertRaw(file_url_transform_relative($style->buildUrl($original_uri)), format_string('Image displayed using style @style.', ['@style' => $style_name]));
+
+    // Rename the style and make sure the image field is updated.
+    $new_style_name = strtolower($this->randomMachineName(10));
+    $new_style_label = $this->randomString();
+    $edit = [
+      'name' => $new_style_name,
+      'label' => $new_style_label,
+    ];
+    $this->drupalPostForm($style_path . $style_name, $edit, t('Update style'));
+    $this->assertText(t('Changes to the style have been saved.'), format_string('Style %name was renamed to %new_name.', ['%name' => $style_name, '%new_name' => $new_style_name]));
+    $this->drupalGet('node/' . $nid);
+
+    // Reload the image style using the new name.
+    $style = ImageStyle::load($new_style_name);
+    $this->assertRaw(file_url_transform_relative($style->buildUrl($original_uri)), 'Image displayed using style replacement style.');
+
+    // Delete the style and choose a replacement style.
+    $edit = [
+      'replacement' => 'thumbnail',
+    ];
+    $this->drupalPostForm($style_path . $new_style_name . '/delete', $edit, t('Delete'));
+    $message = t('The image style %name has been deleted.', ['%name' => $new_style_label]);
+    $this->assertRaw($message);
+
+    $replacement_style = ImageStyle::load('thumbnail');
+    $this->drupalGet('node/' . $nid);
+    $this->assertRaw(file_url_transform_relative($replacement_style->buildUrl($original_uri)), 'Image displayed using style replacement style.');
+  }
+
+  /**
+   * Verifies that editing an image effect does not cause it to be duplicated.
+   */
+  public function testEditEffect() {
+    // Add a scale effect.
+    $style_name = 'test_style_effect_edit';
+    $this->drupalGet('admin/config/media/image-styles/add');
+    $this->drupalPostForm(NULL, ['label' => 'Test style effect edit', 'name' => $style_name], t('Create new style'));
+    $this->drupalPostForm(NULL, ['new' => 'image_scale_and_crop'], t('Add'));
+    $this->drupalPostForm(NULL, ['data[width]' => '300', 'data[height]' => '200'], t('Add effect'));
+    $this->assertText(t('Scale and crop 300×200'));
+
+    // There should normally be only one edit link on this page initially.
+    $this->clickLink(t('Edit'));
+    $this->drupalPostForm(NULL, ['data[width]' => '360', 'data[height]' => '240'], t('Update effect'));
+    $this->assertText(t('Scale and crop 360×240'));
+
+    // Check that the previous effect is replaced.
+    $this->assertNoText(t('Scale and crop 300×200'));
+
+    // Add another scale effect.
+    $this->drupalGet('admin/config/media/image-styles/add');
+    $this->drupalPostForm(NULL, ['label' => 'Test style scale edit scale', 'name' => 'test_style_scale_edit_scale'], t('Create new style'));
+    $this->drupalPostForm(NULL, ['new' => 'image_scale'], t('Add'));
+    $this->drupalPostForm(NULL, ['data[width]' => '12', 'data[height]' => '19'], t('Add effect'));
+
+    // Edit the scale effect that was just added.
+    $this->clickLink(t('Edit'));
+    $this->drupalPostForm(NULL, ['data[width]' => '24', 'data[height]' => '19'], t('Update effect'));
+
+    // Add another scale effect and make sure both exist. Click through from
+    // the overview to make sure that it is possible to add new effect then.
+    $this->drupalGet('admin/config/media/image-styles');
+    $rows = $this->xpath('//table/tbody/tr');
+    $i = 0;
+    foreach ($rows as $row) {
+      if ($row->find('css', 'td')->getText() === 'Test style scale edit scale') {
+        $this->clickLink('Edit', $i);
+        break;
+      }
+      $i++;
+    }
+    $this->drupalPostForm(NULL, ['new' => 'image_scale'], t('Add'));
+    $this->drupalPostForm(NULL, ['data[width]' => '12', 'data[height]' => '19'], t('Add effect'));
+    $this->assertText(t('Scale 24×19'));
+    $this->assertText(t('Scale 12×19'));
+
+    // Try to edit a nonexistent effect.
+    $uuid = $this->container->get('uuid');
+    $this->drupalGet('admin/config/media/image-styles/manage/' . $style_name . '/effects/' . $uuid->generate());
+    $this->assertResponse(404);
+  }
+
+  /**
+   * Test flush user interface.
+   */
+  public function testFlushUserInterface() {
+    $admin_path = 'admin/config/media/image-styles';
+
+    // Create a new style.
+    $style_name = strtolower($this->randomMachineName(10));
+    $style = ImageStyle::create(['name' => $style_name, 'label' => $this->randomString()]);
+    $style->save();
+
+    // Create an image to make sure it gets flushed.
+    $files = $this->drupalGetTestFiles('image');
+    $image_uri = $files[0]->uri;
+    $derivative_uri = $style->buildUri($image_uri);
+    $this->assertTrue($style->createDerivative($image_uri, $derivative_uri));
+    $this->assertEqual($this->getImageCount($style), 1);
+
+    // Go to image styles list page and check if the flush operation link
+    // exists.
+    $this->drupalGet($admin_path);
+    $flush_path = $admin_path . '/manage/' . $style_name . '/flush';
+    $this->assertLinkByHref($flush_path);
+
+    // Flush the image style derivatives using the user interface.
+    $this->drupalPostForm($flush_path, [], t('Flush'));
+
+    // The derivative image file should have been deleted.
+    $this->assertEqual($this->getImageCount($style), 0);
+  }
+
+  /**
+   * Tests image style configuration import that does a delete.
+   */
+  public function testConfigImport() {
+    // Create a new style.
+    $style_name = strtolower($this->randomMachineName(10));
+    $style_label = $this->randomString();
+    $style = ImageStyle::create(['name' => $style_name, 'label' => $style_label]);
+    $style->save();
+
+    // Create an image field that uses the new style.
+    $field_name = strtolower($this->randomMachineName(10));
+    $this->createImageField($field_name, 'article');
+    entity_get_display('node', 'article', 'default')
+      ->setComponent($field_name, [
+        'type' => 'image',
+        'settings' => ['image_style' => $style_name],
+      ])
+      ->save();
+
+    // Create a new node with an image attached.
+    $test_image = current($this->drupalGetTestFiles('image'));
+    $nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
+    $node = Node::load($nid);
+
+    // Get node field original image URI.
+    $fid = $node->get($field_name)->target_id;
+    $original_uri = File::load($fid)->getFileUri();
+
+    // Test that image is displayed using newly created style.
+    $this->drupalGet('node/' . $nid);
+    $this->assertRaw(file_url_transform_relative($style->buildUrl($original_uri)), format_string('Image displayed using style @style.', ['@style' => $style_name]));
+
+    // Copy config to sync, and delete the image style.
+    $sync = $this->container->get('config.storage.sync');
+    $active = $this->container->get('config.storage');
+    // Remove the image field from the display, to avoid a dependency error
+    // during import.
+    EntityViewDisplay::load('node.article.default')
+      ->removeComponent($field_name)
+      ->save();
+    $this->copyConfig($active, $sync);
+    $sync->delete('image.style.' . $style_name);
+    $this->configImporter()->import();
+
+    $this->assertFalse(ImageStyle::load($style_name), 'Style deleted after config import.');
+    $this->assertEqual($this->getImageCount($style), 0, 'Image style was flushed after being deleted by config import.');
+  }
+
+  /**
+   * Tests access for the image style listing.
+   */
+  public function testImageStyleAccess() {
+    $style = ImageStyle::create(['name' => 'style_foo', 'label' => $this->randomString()]);
+    $style->save();
+
+    $this->drupalGet('admin/config/media/image-styles');
+    $this->clickLink(t('Edit'));
+    $this->assertRaw(t('Select a new effect'));
+  }
+
+}
diff --git a/core/modules/image/src/Tests/ImageDimensionsTest.php b/core/modules/image/tests/src/Functional/ImageDimensionsTest.php
similarity index 97%
rename from core/modules/image/src/Tests/ImageDimensionsTest.php
rename to core/modules/image/tests/src/Functional/ImageDimensionsTest.php
index 136b0f1f15d672e9982f30ae46878f92ccf900e5..46eef05d9b021982d60781444c12c35e783d310f 100644
--- a/core/modules/image/src/Tests/ImageDimensionsTest.php
+++ b/core/modules/image/tests/src/Functional/ImageDimensionsTest.php
@@ -1,16 +1,22 @@
 <?php
 
-namespace Drupal\image\Tests;
+namespace Drupal\Tests\image\Functional;
 
 use Drupal\image\Entity\ImageStyle;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\TestFileCreationTrait;
 
 /**
  * Tests that images have correct dimensions when styled.
  *
  * @group image
  */
-class ImageDimensionsTest extends WebTestBase {
+class ImageDimensionsTest extends BrowserTestBase {
+
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+    compareFiles as drupalCompareFiles;
+  }
 
   /**
    * Modules to enable.
diff --git a/core/modules/image/src/Tests/ImageFieldDefaultImagesTest.php b/core/modules/image/tests/src/Functional/ImageFieldDefaultImagesTest.php
similarity index 98%
rename from core/modules/image/src/Tests/ImageFieldDefaultImagesTest.php
rename to core/modules/image/tests/src/Functional/ImageFieldDefaultImagesTest.php
index b82348ec70454587f136cf11201e028e7e368a06..c4b989a75902f9d648219c91c62f98251cd12eea 100644
--- a/core/modules/image/src/Tests/ImageFieldDefaultImagesTest.php
+++ b/core/modules/image/tests/src/Functional/ImageFieldDefaultImagesTest.php
@@ -1,12 +1,14 @@
 <?php
 
-namespace Drupal\image\Tests;
+namespace Drupal\Tests\image\Functional;
 
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Entity\Entity\EntityViewDisplay;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\file\Entity\File;
 use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Tests\EntityViewTrait;
+use Drupal\Tests\TestFileCreationTrait;
 
 /**
  * Tests setting up default images both to the field and field storage.
@@ -15,6 +17,14 @@
  */
 class ImageFieldDefaultImagesTest extends ImageFieldTestBase {
 
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+    compareFiles as drupalCompareFiles;
+  }
+  use EntityViewTrait {
+    buildEntityView as drupalBuildEntityView;
+  }
+
   /**
    * Modules to enable.
    *
diff --git a/core/modules/image/src/Tests/ImageFieldDisplayTest.php b/core/modules/image/tests/src/Functional/ImageFieldDisplayTest.php
similarity index 94%
rename from core/modules/image/src/Tests/ImageFieldDisplayTest.php
rename to core/modules/image/tests/src/Functional/ImageFieldDisplayTest.php
index 05d716c367899100256e2d9278a8806a293a19e2..ce924f426aabe634eb53a6ff20d788d3cd5770f0 100644
--- a/core/modules/image/src/Tests/ImageFieldDisplayTest.php
+++ b/core/modules/image/tests/src/Functional/ImageFieldDisplayTest.php
@@ -1,9 +1,11 @@
 <?php
 
-namespace Drupal\image\Tests;
+namespace Drupal\Tests\image\Functional;
 
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Tests\TestFileCreationTrait;
+use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
 use Drupal\user\RoleInterface;
 use Drupal\image\Entity\ImageStyle;
 
@@ -14,6 +16,12 @@
  */
 class ImageFieldDisplayTest extends ImageFieldTestBase {
 
+  use AssertPageCacheContextsAndTagsTrait;
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+    compareFiles as drupalCompareFiles;
+  }
+
   protected $dumpHeaders = TRUE;
 
   /**
@@ -54,7 +62,7 @@ public function _testImageFieldFormatters($scheme) {
     $this->drupalGet("admin/structure/types/manage/article/display");
 
     // Test for existence of link to image styles configuration.
-    $this->drupalPostAjaxForm(NULL, [], "{$field_name}_settings_edit");
+    $this->drupalPostForm(NULL, [], "{$field_name}_settings_edit");
     $this->assertLinkByHref(\Drupal::url('entity.image_style.collection'), 0, 'Link to image styles configuration is found');
 
     // Remove 'administer image styles' permission from testing admin user.
@@ -65,7 +73,7 @@ public function _testImageFieldFormatters($scheme) {
     $this->drupalGet("admin/structure/types/manage/article/display");
 
     // Test for absence of link to image styles configuration.
-    $this->drupalPostAjaxForm(NULL, [], "{$field_name}_settings_edit");
+    $this->drupalPostForm(NULL, [], "{$field_name}_settings_edit");
     $this->assertNoLinkByHref(\Drupal::url('entity.image_style.collection'), 'Link to image styles configuration is absent when permissions are insufficient');
 
     // Restore 'administer image styles' permission to testing admin user
@@ -258,8 +266,11 @@ public function testImageFieldSettings() {
 
     $nid = $this->uploadNodeImage($test_image, $field_name, 'article', $alt);
     $this->drupalGet('node/' . $nid . '/edit');
-    $this->assertFieldByName($field_name . '[0][alt]', '', 'Alt field displayed on article form.');
+
+    // Verify that the optional fields alt & title are saved & filled.
+    $this->assertFieldByName($field_name . '[0][alt]', $alt, 'Alt field displayed on article form.');
     $this->assertFieldByName($field_name . '[0][title]', '', 'Title field displayed on article form.');
+
     // Verify that the attached image is being previewed using the 'medium'
     // style.
     $node_storage->resetCache([$nid]);
@@ -324,9 +335,9 @@ public function testImageFieldSettings() {
     $edit = [
       'files[' . $field_name . '_2][]' => \Drupal::service('file_system')->realpath($test_image->uri),
     ];
-    $this->drupalPostAjaxForm(NULL, $edit, $field_name . '_2_upload_button');
-    $this->assertNoRaw('<input multiple type="file" id="edit-' . strtr($field_name, '_', '-') . '-2-upload" name="files[' . $field_name . '_2][]" size="22" class="js-form-file form-file">');
-    $this->assertRaw('<input multiple type="file" id="edit-' . strtr($field_name, '_', '-') . '-3-upload" name="files[' . $field_name . '_3][]" size="22" class="js-form-file form-file">');
+    $this->drupalPostForm(NULL, $edit, $field_name . '_2_upload_button');
+    $this->assertSession()->elementNotExists('css', 'input[name="files[' . $field_name . '_2][]"]');
+    $this->assertSession()->elementExists('css', 'input[name="files[' . $field_name . '_3][]"]');
   }
 
   /**
@@ -410,10 +421,11 @@ public function testImageFieldDefaultImage() {
     $this->assertRaw($image_output, 'User supplied image is displayed.');
 
     // Remove default image from the field and make sure it is no longer used.
-    $edit = [
-      'settings[default_image][uuid][fids]' => 0,
-    ];
-    $this->drupalPostForm("admin/structure/types/manage/article/fields/node.article.$field_name/storage", $edit, t('Save field settings'));
+    // Can't use fillField cause Mink can't fill hidden fields.
+    $this->drupalGet("admin/structure/types/manage/article/fields/node.article.$field_name/storage");
+    $this->getSession()->getPage()->find('css', 'input[name="settings[default_image][uuid][fids]"]')->setValue(0);
+    $this->getSession()->getPage()->pressButton(t('Save field settings'));
+
     // Clear field definition cache so the new default image is detected.
     \Drupal::entityManager()->clearCachedFieldDefinitions();
     $field_storage = FieldStorageConfig::loadByName('node', $field_name);
diff --git a/core/modules/image/tests/src/Functional/ImageFieldTestBase.php b/core/modules/image/tests/src/Functional/ImageFieldTestBase.php
index b9d659a16dbd460c045a388be696d17874b132aa..b6484a84e90d519b79c1e15340a04b73f5d12c49 100644
--- a/core/modules/image/tests/src/Functional/ImageFieldTestBase.php
+++ b/core/modules/image/tests/src/Functional/ImageFieldTestBase.php
@@ -87,10 +87,10 @@ public function uploadNodeImage($image, $field_name, $type, $alt = '') {
       'title[0][value]' => $this->randomMachineName(),
     ];
     $edit['files[' . $field_name . '_0]'] = \Drupal::service('file_system')->realpath($image->uri);
-    $this->drupalPostForm('node/add/' . $type, $edit, t('Save and publish'));
+    $this->drupalPostForm('node/add/' . $type, $edit, t('Save'));
     if ($alt) {
       // Add alt text.
-      $this->drupalPostForm(NULL, [$field_name . '[0][alt]' => $alt], t('Save and publish'));
+      $this->drupalPostForm(NULL, [$field_name . '[0][alt]' => $alt], t('Save'));
     }
 
     // Retrieve ID of the newly created node from the current URL.
diff --git a/core/modules/image/tests/src/Functional/ImageFieldValidateTest.php b/core/modules/image/tests/src/Functional/ImageFieldValidateTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c69a7136f12daa5d41d77a57eeee2439a6da91b6
--- /dev/null
+++ b/core/modules/image/tests/src/Functional/ImageFieldValidateTest.php
@@ -0,0 +1,226 @@
+<?php
+
+namespace Drupal\Tests\image\Functional;
+
+use Drupal\Tests\TestFileCreationTrait;
+
+/**
+ * Tests validation functions such as min/max resolution.
+ *
+ * @group image
+ */
+class ImageFieldValidateTest extends ImageFieldTestBase {
+
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+    compareFiles as drupalCompareFiles;
+  }
+
+  /**
+   * Test image validity.
+   */
+  public function testValid() {
+    $file_system = $this->container->get('file_system');
+    $image_files = $this->drupalGetTestFiles('image');
+
+    $field_name = strtolower($this->randomMachineName());
+    $this->createImageField($field_name, 'article', [], ['file_directory' => 'test-upload']);
+    $expected_path = 'public://test-upload';
+
+    // Create alt text for the image.
+    $alt = $this->randomMachineName();
+
+    // Create a node with a valid image.
+    $node = $this->uploadNodeImage($image_files[0], $field_name, 'article', $alt);
+    $this->assertTrue(file_exists($expected_path . '/' . $image_files[0]->filename));
+
+    // Remove the image.
+    $this->drupalPostForm('node/' . $node . '/edit', [], t('Remove'));
+    $this->drupalPostForm(NULL, [], t('Save'));
+
+    // Get invalid image test files from simpletest.
+    $files = file_scan_directory(drupal_get_path('module', 'simpletest') . '/files', '/invalid-img-.*/');
+    $invalid_image_files = [];
+    foreach ($files as $file) {
+      $invalid_image_files[$file->filename] = $file;
+    }
+
+    // Try uploading a zero-byte image.
+    $zero_size_image = $invalid_image_files['invalid-img-zero-size.png'];
+    $edit = [
+      'files[' . $field_name . '_0]' => $file_system->realpath($zero_size_image->uri),
+    ];
+    $this->drupalPostForm('node/' . $node . '/edit', $edit, t('Upload'));
+    $this->assertFalse(file_exists($expected_path . '/' . $zero_size_image->filename));
+
+    // Try uploading an invalid image.
+    $invalid_image = $invalid_image_files['invalid-img-test.png'];
+    $edit = [
+      'files[' . $field_name . '_0]' => $file_system->realpath($invalid_image->uri),
+    ];
+    $this->drupalPostForm('node/' . $node . '/edit', $edit, t('Upload'));
+    $this->assertFalse(file_exists($expected_path . '/' . $invalid_image->filename));
+
+    // Upload a valid image again.
+    $valid_image = $image_files[0];
+    $edit = [
+      'files[' . $field_name . '_0]' => $file_system->realpath($valid_image->uri),
+    ];
+    $this->drupalPostForm('node/' . $node . '/edit', $edit, t('Upload'));
+    $this->assertTrue(file_exists($expected_path . '/' . $valid_image->filename));
+  }
+
+  /**
+   * Test min/max resolution settings.
+   */
+  public function testResolution() {
+    $field_names = [
+      0 => strtolower($this->randomMachineName()),
+      1 => strtolower($this->randomMachineName()),
+      2 => strtolower($this->randomMachineName()),
+    ];
+    $min_resolution = [
+      'width' => 50,
+      'height' => 50
+    ];
+    $max_resolution = [
+      'width' => 100,
+      'height' => 100
+    ];
+    $no_height_min_resolution = [
+      'width' => 50,
+      'height' => NULL
+    ];
+    $no_height_max_resolution = [
+      'width' => 100,
+      'height' => NULL
+    ];
+    $no_width_min_resolution = [
+      'width' => NULL,
+      'height' => 50
+    ];
+    $no_width_max_resolution = [
+      'width' => NULL,
+      'height' => 100
+    ];
+    $field_settings = [
+      0 => $this->getFieldSettings($min_resolution, $max_resolution),
+      1 => $this->getFieldSettings($no_height_min_resolution, $no_height_max_resolution),
+      2 => $this->getFieldSettings($no_width_min_resolution, $no_width_max_resolution),
+    ];
+    $this->createImageField($field_names[0], 'article', [], $field_settings[0]);
+    $this->createImageField($field_names[1], 'article', [], $field_settings[1]);
+    $this->createImageField($field_names[2], 'article', [], $field_settings[2]);
+
+    // We want a test image that is too small, and a test image that is too
+    // big, so cycle through test image files until we have what we need.
+    $image_that_is_too_big = FALSE;
+    $image_that_is_too_small = FALSE;
+    $image_factory = $this->container->get('image.factory');
+    foreach ($this->drupalGetTestFiles('image') as $image) {
+      $image_file = $image_factory->get($image->uri);
+      if ($image_file->getWidth() > $max_resolution['width']) {
+        $image_that_is_too_big = $image;
+      }
+      if ($image_file->getWidth() < $min_resolution['width']) {
+        $image_that_is_too_small = $image;
+        $image_that_is_too_small_file = $image_file;
+      }
+      if ($image_that_is_too_small && $image_that_is_too_big) {
+        break;
+      }
+    }
+    $this->uploadNodeImage($image_that_is_too_small, $field_names[0], 'article');
+    $this->assertRaw(t('The specified file %name could not be uploaded.', ['%name' => $image_that_is_too_small->filename]));
+    $this->assertRaw(t('The image is too small. The minimum dimensions are %dimensions pixels and the image size is %widthx%height pixels.', [
+      '%dimensions' => '50x50',
+      '%width' => $image_that_is_too_small_file->getWidth(),
+      '%height' => $image_that_is_too_small_file->getHeight(),
+      ]));
+    $this->uploadNodeImage($image_that_is_too_big, $field_names[0], 'article');
+    $this->assertText(t('The image was resized to fit within the maximum allowed dimensions of 100x100 pixels.'));
+    $this->uploadNodeImage($image_that_is_too_small, $field_names[1], 'article');
+    $this->assertRaw(t('The specified file %name could not be uploaded.', ['%name' => $image_that_is_too_small->filename]));
+    $this->uploadNodeImage($image_that_is_too_big, $field_names[1], 'article');
+    $this->assertText(t('The image was resized to fit within the maximum allowed width of 100 pixels.'));
+    $this->uploadNodeImage($image_that_is_too_small, $field_names[2], 'article');
+    $this->assertRaw(t('The specified file %name could not be uploaded.', ['%name' => $image_that_is_too_small->filename]));
+    $this->uploadNodeImage($image_that_is_too_big, $field_names[2], 'article');
+    $this->assertText(t('The image was resized to fit within the maximum allowed height of 100 pixels.'));
+  }
+
+  /**
+   * Test that required alt/title fields gets validated right.
+   */
+  public function testRequiredAttributes() {
+    $field_name = strtolower($this->randomMachineName());
+    $field_settings = [
+      'alt_field' => 1,
+      'alt_field_required' => 1,
+      'title_field' => 1,
+      'title_field_required' => 1,
+      'required' => 1,
+    ];
+    $instance = $this->createImageField($field_name, 'article', [], $field_settings);
+    $images = $this->drupalGetTestFiles('image');
+    // Let's just use the first image.
+    $image = $images[0];
+    $this->uploadNodeImage($image, $field_name, 'article');
+
+    // Look for form-required for the alt text.
+    $elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-alt" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-alt"]');
+
+    $this->assertTrue(isset($elements[0]), 'Required marker is shown for the required alt text.');
+
+    $elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-title" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-title"]');
+
+    $this->assertTrue(isset($elements[0]), 'Required marker is shown for the required title text.');
+
+    $this->assertText(t('Alternative text field is required.'));
+    $this->assertText(t('Title field is required.'));
+
+    $instance->setSetting('alt_field_required', 0);
+    $instance->setSetting('title_field_required', 0);
+    $instance->save();
+
+    $edit = [
+      'title[0][value]' => $this->randomMachineName(),
+    ];
+    $this->drupalPostForm('node/add/article', $edit, t('Save'));
+
+    $this->assertNoText(t('Alternative text field is required.'));
+    $this->assertNoText(t('Title field is required.'));
+
+    $instance->setSetting('required', 0);
+    $instance->setSetting('alt_field_required', 1);
+    $instance->setSetting('title_field_required', 1);
+    $instance->save();
+
+    $edit = [
+      'title[0][value]' => $this->randomMachineName(),
+    ];
+    $this->drupalPostForm('node/add/article', $edit, t('Save'));
+
+    $this->assertNoText(t('Alternative text field is required.'));
+    $this->assertNoText(t('Title field is required.'));
+  }
+
+  /**
+   * Returns field settings.
+   *
+   * @param int[] $min_resolution
+   *   The minimum width and height resolution setting.
+   * @param int[] $max_resolution
+   *   The maximum width and height resolution setting.
+   *
+   * @return array
+   */
+  protected function getFieldSettings($min_resolution, $max_resolution) {
+    return [
+      'max_resolution' => $max_resolution['width'] . 'x' . $max_resolution['height'],
+      'min_resolution' => $min_resolution['width'] . 'x' . $min_resolution['height'],
+      'alt_field' => 0,
+    ];
+  }
+
+}
diff --git a/core/modules/image/src/Tests/ImageOnTranslatedEntityTest.php b/core/modules/image/tests/src/Functional/ImageOnTranslatedEntityTest.php
similarity index 97%
rename from core/modules/image/src/Tests/ImageOnTranslatedEntityTest.php
rename to core/modules/image/tests/src/Functional/ImageOnTranslatedEntityTest.php
index 1ae555289f88a3319027aef010b7ed670e26b0ad..15ca7582880dc605779758892cd26e2551b0187e 100644
--- a/core/modules/image/src/Tests/ImageOnTranslatedEntityTest.php
+++ b/core/modules/image/tests/src/Functional/ImageOnTranslatedEntityTest.php
@@ -1,8 +1,9 @@
 <?php
 
-namespace Drupal\image\Tests;
+namespace Drupal\Tests\image\Functional;
 
 use Drupal\file\Entity\File;
+use Drupal\Tests\TestFileCreationTrait;
 
 /**
  * Uploads images to translated nodes.
@@ -11,6 +12,11 @@
  */
 class ImageOnTranslatedEntityTest extends ImageFieldTestBase {
 
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+    compareFiles as drupalCompareFiles;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/image/src/Tests/ImageStyleFlushTest.php b/core/modules/image/tests/src/Functional/ImageStyleFlushTest.php
similarity index 95%
rename from core/modules/image/src/Tests/ImageStyleFlushTest.php
rename to core/modules/image/tests/src/Functional/ImageStyleFlushTest.php
index 4e8cd2c779e23cfba70b94d9472d93231263420a..070f199982f8d6f7bd927740b26deb8dc10bc787 100644
--- a/core/modules/image/src/Tests/ImageStyleFlushTest.php
+++ b/core/modules/image/tests/src/Functional/ImageStyleFlushTest.php
@@ -1,8 +1,9 @@
 <?php
 
-namespace Drupal\image\Tests;
+namespace Drupal\Tests\image\Functional;
 
 use Drupal\image\Entity\ImageStyle;
+use Drupal\Tests\TestFileCreationTrait;
 
 /**
  * Tests flushing of image styles.
@@ -11,6 +12,11 @@
  */
 class ImageStyleFlushTest extends ImageFieldTestBase {
 
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+    compareFiles as drupalCompareFiles;
+  }
+
   /**
    * Given an image style and a wrapper, generate an image.
    */
diff --git a/core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php b/core/modules/image/tests/src/Functional/ImageStylesPathAndUrlTest.php
similarity index 95%
rename from core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php
rename to core/modules/image/tests/src/Functional/ImageStylesPathAndUrlTest.php
index eef166c95169e04d1927eb40713549959d2e7c61..a0c7b1935928f09e02ea4f1d54b37cad4c093438 100644
--- a/core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php
+++ b/core/modules/image/tests/src/Functional/ImageStylesPathAndUrlTest.php
@@ -1,17 +1,23 @@
 <?php
 
-namespace Drupal\image\Tests;
+namespace Drupal\Tests\image\Functional;
 
 use Drupal\image\Entity\ImageStyle;
 use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\TestFileCreationTrait;
 
 /**
  * Tests the functions for generating paths and URLs for image styles.
  *
  * @group image
  */
-class ImageStylesPathAndUrlTest extends WebTestBase {
+class ImageStylesPathAndUrlTest extends BrowserTestBase {
+
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+    compareFiles as drupalCompareFiles;
+  }
 
   /**
    * Modules to enable.
@@ -189,7 +195,8 @@ public function doImageStyleUrlAndPathTests($scheme, $clean_url = TRUE, $extra_s
     $this->drupalGet($generate_url);
     $this->assertResponse(200, 'Image was generated at the URL.');
     $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
-    $this->assertRaw(file_get_contents($generated_uri), 'URL returns expected file.');
+    // assertRaw can't be used with string containing non UTF-8 chars.
+    $this->assertNotEmpty(file_get_contents($generated_uri), 'URL returns expected file.');
     $image = $this->container->get('image.factory')->get($generated_uri);
     $this->assertEqual($this->drupalGetHeader('Content-Type'), $image->getMimeType(), 'Expected Content-Type was reported.');
     $this->assertEqual($this->drupalGetHeader('Content-Length'), $image->getFileSize(), 'Expected Content-Length was reported.');
@@ -240,7 +247,8 @@ public function doImageStyleUrlAndPathTests($scheme, $clean_url = TRUE, $extra_s
         // Check for PNG-Signature
         // (cf. http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.2)
         // in the response body.
-        $this->assertNoRaw(chr(137) . chr(80) . chr(78) . chr(71) . chr(13) . chr(10) . chr(26) . chr(10), 'No PNG signature found in the response body.');
+        $raw = $this->getSession()->getPage()->getContent();
+        $this->assertFalse(strpos($raw, chr(137) . chr(80) . chr(78) . chr(71) . chr(13) . chr(10) . chr(26) . chr(10)));
       }
     }
     else {
diff --git a/core/modules/image/src/Tests/QuickEditImageControllerTest.php b/core/modules/image/tests/src/Functional/QuickEditImageControllerTest.php
similarity index 76%
rename from core/modules/image/src/Tests/QuickEditImageControllerTest.php
rename to core/modules/image/tests/src/Functional/QuickEditImageControllerTest.php
index cfe4ccbfb14394781742bcc657b37f02522dde51..a037d4808d66d725c746c9896bc6802bea80b71d 100644
--- a/core/modules/image/src/Tests/QuickEditImageControllerTest.php
+++ b/core/modules/image/tests/src/Functional/QuickEditImageControllerTest.php
@@ -1,18 +1,23 @@
 <?php
 
-namespace Drupal\image\Tests;
+namespace Drupal\Tests\image\Functional;
 
+use Drupal\Component\Serialization\Json;
+use Drupal\Tests\BrowserTestBase;
 use Drupal\Tests\image\Kernel\ImageFieldCreationTrait;
-use Drupal\simpletest\WebTestBase;
+use Drupal\Tests\TestFileCreationTrait;
 
 /**
  * Tests the endpoints used by the "image" in-place editor.
  *
  * @group image
  */
-class QuickEditImageControllerTest extends WebTestBase {
+class QuickEditImageControllerTest extends BrowserTestBase {
 
   use ImageFieldCreationTrait;
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+  }
 
   /**
    * {@inheritdoc}
@@ -77,8 +82,11 @@ public function testAccess() {
     ]);
     $this->drupalGet('quickedit/image/info/node/' . $node->id() . '/' . $this->fieldName . '/' . $node->language()->getId() . '/default');
     $this->assertResponse('403');
-    $this->drupalPost('quickedit/image/upload/node/' . $node->id() . '/' . $this->fieldName . '/' . $node->language()->getId() . '/default', 'application/json', []);
-    $this->assertResponse('403');
+
+    /** @var \Symfony\Component\BrowserKit\Client $client */
+    $client = $this->getSession()->getDriver()->getClient();
+    $client->request('POST', '/quickedit/image/upload/node/' . $node->id() . '/' . $this->fieldName . '/' . $node->language()->getId() . '/default');
+    $this->assertEquals('403', $client->getResponse()->getStatus());
   }
 
   /**
@@ -90,7 +98,8 @@ public function testFieldInfo() {
       'type' => 'article',
       'title' => t('Test Node'),
     ]);
-    $info = $this->drupalGetJSON('quickedit/image/info/node/' . $node->id() . '/' . $this->fieldName . '/' . $node->language()->getId() . '/default');
+    $json = $this->drupalGet('quickedit/image/info/node/' . $node->id() . '/' . $this->fieldName . '/' . $node->language()->getId() . '/default', ['query' => ['_format' => 'json']]);
+    $info = Json::decode($json);
     // Assert that the default settings for our field are respected by our JSON
     // endpoint.
     $this->assertTrue($info['alt_field']);
@@ -118,8 +127,10 @@ public function testValidImageUpload() {
       }
     }
     $this->assertTrue($valid_image);
+
+    $this->drupalLogin($this->contentAuthorUser);
     $this->uploadImage($valid_image, $node->id(), $this->fieldName, $node->language()->getId());
-    $this->assertText('fid', t('Valid upload completed successfully.'));
+    $this->assertContains('"fid":"1"', $this->getSession()->getPage()->getContent(), 'Valid upload completed successfully.');
   }
 
   /**
@@ -145,8 +156,10 @@ public function testInvalidUpload() {
       }
     }
     $this->assertTrue($invalid_image);
+
+    $this->drupalLogin($this->contentAuthorUser);
     $this->uploadImage($invalid_image, $node->id(), $this->fieldName, $node->language()->getId());
-    $this->assertText('main_error', t('Invalid upload returned errors.'));
+    $this->assertContains('"main_error":"The image failed validation."', $this->getSession()->getPage()->getContent(), 'Invalid upload returned errors.');
   }
 
   /**
@@ -160,27 +173,14 @@ public function testInvalidUpload() {
    *   The target field machine name.
    * @param string $langcode
    *   The langcode to use when setting the field's value.
-   *
-   * @return mixed
-   *   The content returned from the call to $this->curlExec().
    */
   public function uploadImage($image, $nid, $field_name, $langcode) {
     $filepath = $this->container->get('file_system')->realpath($image->uri);
-    $data = [
-      'files[image]' => curl_file_create($filepath),
-    ];
     $path = 'quickedit/image/upload/node/' . $nid . '/' . $field_name . '/' . $langcode . '/default';
-    // We assemble the curl request ourselves as drupalPost cannot process file
-    // uploads, and drupalPostForm only works with typical Drupal forms.
-    return $this->curlExec([
-      CURLOPT_URL => $this->buildUrl($path, []),
-      CURLOPT_POST => TRUE,
-      CURLOPT_POSTFIELDS => $data,
-      CURLOPT_HTTPHEADER => [
-        'Accept: application/json',
-        'Content-Type: multipart/form-data',
-      ],
-    ]);
+
+    $this->prepareRequest();
+    $client = $this->getSession()->getDriver()->getClient();
+    $client->request('POST', $this->buildUrl($path, []), [], ['files[image]' => $filepath]);
   }
 
 }
diff --git a/core/modules/image/src/Tests/ImageThemeFunctionTest.php b/core/modules/image/tests/src/Kernel/ImageThemeFunctionTest.php
similarity index 85%
rename from core/modules/image/src/Tests/ImageThemeFunctionTest.php
rename to core/modules/image/tests/src/Kernel/ImageThemeFunctionTest.php
index 54c5c64a19fdbaa9e21eb183ca18e6236d76dfe8..7abe47e47a7abbd0b1349ce987de86f31984dd66 100644
--- a/core/modules/image/src/Tests/ImageThemeFunctionTest.php
+++ b/core/modules/image/tests/src/Kernel/ImageThemeFunctionTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\image\Tests;
+namespace Drupal\Tests\image\Kernel;
 
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Url;
@@ -8,22 +8,28 @@
 use Drupal\field\Entity\FieldConfig;
 use Drupal\file\Entity\File;
 use Drupal\image\Entity\ImageStyle;
-use Drupal\simpletest\WebTestBase;
+use Drupal\KernelTests\KernelTestBase;
 use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Tests\TestFileCreationTrait;
 
 /**
  * Tests image theme functions.
  *
  * @group image
  */
-class ImageThemeFunctionTest extends WebTestBase {
+class ImageThemeFunctionTest extends KernelTestBase {
+
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+    compareFiles as drupalCompareFiles;
+  }
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = ['image', 'entity_test'];
+  public static $modules = ['entity_test', 'field', 'file', 'image', 'system', 'simpletest', 'user'];
 
   /**
    * Created file entity.
@@ -40,6 +46,11 @@ class ImageThemeFunctionTest extends WebTestBase {
   protected function setUp() {
     parent::setUp();
 
+    $this->installEntitySchema('entity_test');
+    $this->installEntitySchema('file');
+    $this->installSchema('file', ['file_usage']);
+    $this->installEntitySchema('user');
+
     FieldStorageConfig::create([
       'entity_type' => 'entity_test',
       'field_name' => 'image_test',
@@ -96,7 +107,7 @@ public function testImageFormatterTheme() {
     // Test using theme_image_formatter() with a NULL value for the alt option.
     $element = $base_element;
     $this->setRawContent($renderer->renderRoot($element));
-    $elements = $this->xpath('//a[@href=:path]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height]', [':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight()]);
+    $elements = $this->xpath('//a[@href=:path]/img[@src=:url and @width=:width and @height=:height]', [':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight()]);
     $this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders with a NULL value for the alt option.');
 
     // Test using theme_image_formatter() without an image title, alt text, or
@@ -104,7 +115,7 @@ public function testImageFormatterTheme() {
     $element = $base_element;
     $element['#item']->alt = '';
     $this->setRawContent($renderer->renderRoot($element));
-    $elements = $this->xpath('//a[@href=:path]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height and @alt=""]', [':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight()]);
+    $elements = $this->xpath('//a[@href=:path]/img[@src=:url and @width=:width and @height=:height and @alt=""]', [':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight()]);
     $this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders without title, alt, or path options.');
 
     // Link the image to a fragment on the page, and not a full URL.
@@ -112,7 +123,7 @@ public function testImageFormatterTheme() {
     $element = $base_element;
     $element['#url'] = Url::fromRoute('<none>', [], ['fragment' => $fragment]);
     $this->setRawContent($renderer->renderRoot($element));
-    $elements = $this->xpath('//a[@href=:fragment]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height and @alt=""]', [
+    $elements = $this->xpath('//a[@href=:fragment]/img[@src=:url and @width=:width and @height=:height and @alt=""]', [
       ':fragment' => '#' . $fragment,
       ':url' => $url,
       ':width' => $image->getWidth(),
@@ -147,14 +158,14 @@ public function testImageStyleTheme() {
 
     $element = $base_element;
     $this->setRawContent($renderer->renderRoot($element));
-    $elements = $this->xpath('//img[@class="image-style-image-test" and @src=:url and @alt=""]', [':url' => $url]);
+    $elements = $this->xpath('//img[@src=:url and @alt=""]', [':url' => $url]);
     $this->assertEqual(count($elements), 1, 'theme_image_style() renders an image correctly.');
 
     // Test using theme_image_style() with a NULL value for the alt option.
     $element = $base_element;
     $element['#alt'] = NULL;
     $this->setRawContent($renderer->renderRoot($element));
-    $elements = $this->xpath('//img[@class="image-style-image-test" and @src=:url]', [':url' => $url]);
+    $elements = $this->xpath('//img[@src=:url]', [':url' => $url]);
     $this->assertEqual(count($elements), 1, 'theme_image_style() renders an image correctly with a NULL value for the alt option.');
   }
 
diff --git a/core/modules/image/src/Tests/Views/RelationshipUserImageDataTest.php b/core/modules/image/tests/src/Kernel/Views/RelationshipUserImageDataTest.php
similarity index 82%
rename from core/modules/image/src/Tests/Views/RelationshipUserImageDataTest.php
rename to core/modules/image/tests/src/Kernel/Views/RelationshipUserImageDataTest.php
index 374981f63aa092c5b4bd1b7487859393db27af64..e0f605e92ddedfd92eee50876a4b2987c2b87e4e 100644
--- a/core/modules/image/src/Tests/Views/RelationshipUserImageDataTest.php
+++ b/core/modules/image/tests/src/Kernel/Views/RelationshipUserImageDataTest.php
@@ -1,10 +1,11 @@
 <?php
 
-namespace Drupal\image\Tests\Views;
+namespace Drupal\Tests\image\Kernel\Views;
 
 use Drupal\field\Entity\FieldConfig;
 use Drupal\file\Entity\File;
-use Drupal\views\Tests\ViewTestBase;
+use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
+use Drupal\user\Entity\User;
 use Drupal\views\Views;
 use Drupal\views\Tests\ViewTestData;
 use Drupal\field\Entity\FieldStorageConfig;
@@ -14,14 +15,14 @@
  *
  * @group image
  */
-class RelationshipUserImageDataTest extends ViewTestBase {
+class RelationshipUserImageDataTest extends ViewsKernelTestBase {
 
   /**
    * Modules to install.
    *
    * @var array
    */
-  public static $modules = ['image', 'image_test_views', 'user'];
+  public static $modules = ['file', 'field', 'image', 'image_test_views', 'system', 'user'];
 
   /**
    * Views used by this test.
@@ -33,6 +34,10 @@ class RelationshipUserImageDataTest extends ViewTestBase {
   protected function setUp($import_test_views = TRUE) {
     parent::setUp($import_test_views);
 
+    $this->installEntitySchema('file');
+    $this->installSchema('file', ['file_usage']);
+    $this->installEntitySchema('user');
+
     // Create the user profile field and instance.
     FieldStorageConfig::create([
       'entity_type' => 'user',
@@ -70,7 +75,9 @@ public function testViewsHandlerRelationshipUserImageData() {
     file_put_contents($file->getFileUri(), file_get_contents('core/modules/simpletest/files/image-1.png'));
     $file->save();
 
-    $account = $this->drupalCreateUser();
+    $account = User::create([
+      'name' => 'foo',
+    ]);
     $account->user_picture->target_id = 2;
     $account->save();